dw2gencfi.c revision 130561
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 "as.h"
23#include "dw2gencfi.h"
24
25
26/* We re-use DWARF2_LINE_MIN_INSN_LENGTH for the code alignment field
27   of the CIE.  Default to 1 if not otherwise specified.  */
28#ifndef DWARF2_LINE_MIN_INSN_LENGTH
29# define DWARF2_LINE_MIN_INSN_LENGTH 1
30#endif
31
32/* If TARGET_USE_CFIPOP is defined, it is required that the target
33   provide the following definitions.  Otherwise provide them to
34   allow compilation to continue.  */
35#ifndef TARGET_USE_CFIPOP
36# ifndef DWARF2_DEFAULT_RETURN_COLUMN
37#  define DWARF2_DEFAULT_RETURN_COLUMN 0
38# endif
39# ifndef DWARF2_CIE_DATA_ALIGNMENT
40#  define DWARF2_CIE_DATA_ALIGNMENT 1
41# endif
42#endif
43
44#ifndef EH_FRAME_ALIGNMENT
45# ifdef BFD_ASSEMBLER
46#  define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
47# else
48#  define EH_FRAME_ALIGNMENT 2
49# endif
50#endif
51
52#ifndef tc_cfi_frame_initial_instructions
53# define tc_cfi_frame_initial_instructions() ((void)0)
54#endif
55
56
57struct cfi_insn_data
58{
59  struct cfi_insn_data *next;
60  int insn;
61  union {
62    struct {
63      unsigned reg;
64      offsetT offset;
65    } ri;
66
67    struct {
68      unsigned reg1;
69      unsigned reg2;
70    } rr;
71
72    unsigned r;
73    offsetT i;
74
75    struct {
76      symbolS *lab1;
77      symbolS *lab2;
78    } ll;
79
80    struct cfi_escape_data {
81      struct cfi_escape_data *next;
82      expressionS exp;
83    } *esc;
84  } u;
85};
86
87struct fde_entry
88{
89  struct fde_entry *next;
90  symbolS *start_address;
91  symbolS *end_address;
92  struct cfi_insn_data *data;
93  struct cfi_insn_data **last;
94  unsigned int return_column;
95};
96
97struct cie_entry
98{
99  struct cie_entry *next;
100  symbolS *start_address;
101  unsigned int return_column;
102  struct cfi_insn_data *first, *last;
103};
104
105
106/* Current open FDE entry.  */
107static struct fde_entry *cur_fde_data;
108static symbolS *last_address;
109static offsetT cur_cfa_offset;
110
111/* List of FDE entries.  */
112static struct fde_entry *all_fde_data;
113static struct fde_entry **last_fde_data = &all_fde_data;
114
115/* List of CIEs so that they could be reused.  */
116static struct cie_entry *cie_root;
117
118/* Stack of old CFI data, for save/restore.  */
119struct cfa_save_data
120{
121  struct cfa_save_data *next;
122  offsetT cfa_offset;
123};
124
125static struct cfa_save_data *cfa_save_stack;
126
127/* Construct a new FDE structure and add it to the end of the fde list.  */
128
129static struct fde_entry *
130alloc_fde_entry (void)
131{
132  struct fde_entry *fde = xcalloc (1, sizeof (struct fde_entry));
133
134  cur_fde_data = fde;
135  *last_fde_data = fde;
136  last_fde_data = &fde->next;
137
138  fde->last = &fde->data;
139  fde->return_column = DWARF2_DEFAULT_RETURN_COLUMN;
140
141  return fde;
142}
143
144/* The following functions are available for a backend to construct its
145   own unwind information, usually from legacy unwind directives.  */
146
147/* Construct a new INSN structure and add it to the end of the insn list
148   for the currently active FDE.  */
149
150static struct cfi_insn_data *
151alloc_cfi_insn_data (void)
152{
153  struct cfi_insn_data *insn = xcalloc (1, sizeof (struct cfi_insn_data));
154
155  *cur_fde_data->last = insn;
156  cur_fde_data->last = &insn->next;
157
158  return insn;
159}
160
161/* Construct a new FDE structure that begins at LABEL.  */
162
163void
164cfi_new_fde (symbolS *label)
165{
166  struct fde_entry *fde = alloc_fde_entry ();
167  fde->start_address = label;
168  last_address = label;
169}
170
171/* End the currently open FDE.  */
172
173void
174cfi_end_fde (symbolS *label)
175{
176  cur_fde_data->end_address = label;
177  cur_fde_data = NULL;
178}
179
180/* Set the return column for the current FDE.  */
181
182void
183cfi_set_return_column (unsigned regno)
184{
185  cur_fde_data->return_column = regno;
186}
187
188/* Universal functions to store new instructions.  */
189
190static void
191cfi_add_CFA_insn(int insn)
192{
193  struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
194
195  insn_ptr->insn = insn;
196}
197
198static void
199cfi_add_CFA_insn_reg (int insn, unsigned regno)
200{
201  struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
202
203  insn_ptr->insn = insn;
204  insn_ptr->u.r = regno;
205}
206
207static void
208cfi_add_CFA_insn_offset (int insn, offsetT offset)
209{
210  struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
211
212  insn_ptr->insn = insn;
213  insn_ptr->u.i = offset;
214}
215
216static void
217cfi_add_CFA_insn_reg_reg (int insn, unsigned reg1, unsigned reg2)
218{
219  struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
220
221  insn_ptr->insn = insn;
222  insn_ptr->u.rr.reg1 = reg1;
223  insn_ptr->u.rr.reg2 = reg2;
224}
225
226static void
227cfi_add_CFA_insn_reg_offset (int insn, unsigned regno, offsetT offset)
228{
229  struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
230
231  insn_ptr->insn = insn;
232  insn_ptr->u.ri.reg = regno;
233  insn_ptr->u.ri.offset = offset;
234}
235
236/* Add a CFI insn to advance the PC from the last address to LABEL.  */
237
238void
239cfi_add_advance_loc (symbolS *label)
240{
241  struct cfi_insn_data *insn = alloc_cfi_insn_data ();
242
243  insn->insn = DW_CFA_advance_loc;
244  insn->u.ll.lab1 = last_address;
245  insn->u.ll.lab2 = label;
246
247  last_address = label;
248}
249
250/* Add a DW_CFA_offset record to the CFI data.  */
251
252void
253cfi_add_CFA_offset (unsigned regno, offsetT offset)
254{
255  unsigned int abs_data_align;
256
257  cfi_add_CFA_insn_reg_offset (DW_CFA_offset, regno, offset);
258
259  abs_data_align = (DWARF2_CIE_DATA_ALIGNMENT < 0
260		    ? -DWARF2_CIE_DATA_ALIGNMENT : DWARF2_CIE_DATA_ALIGNMENT);
261  if (offset % abs_data_align)
262    as_bad (_("register save offset not a multiple of %u"), abs_data_align);
263}
264
265/* Add a DW_CFA_def_cfa record to the CFI data.  */
266
267void
268cfi_add_CFA_def_cfa (unsigned regno, offsetT offset)
269{
270  cfi_add_CFA_insn_reg_offset (DW_CFA_def_cfa, regno, offset);
271  cur_cfa_offset = offset;
272}
273
274/* Add a DW_CFA_register record to the CFI data.  */
275
276void
277cfi_add_CFA_register (unsigned reg1, unsigned reg2)
278{
279  cfi_add_CFA_insn_reg_reg (DW_CFA_register, reg1, reg2);
280}
281
282/* Add a DW_CFA_def_cfa_register record to the CFI data.  */
283
284void
285cfi_add_CFA_def_cfa_register (unsigned regno)
286{
287  cfi_add_CFA_insn_reg (DW_CFA_def_cfa_register, regno);
288}
289
290/* Add a DW_CFA_def_cfa_offset record to the CFI data.  */
291
292void
293cfi_add_CFA_def_cfa_offset (offsetT offset)
294{
295  cfi_add_CFA_insn_offset (DW_CFA_def_cfa_offset, offset);
296  cur_cfa_offset = offset;
297}
298
299void
300cfi_add_CFA_restore (unsigned regno)
301{
302  cfi_add_CFA_insn_reg (DW_CFA_restore, regno);
303}
304
305void
306cfi_add_CFA_undefined (unsigned regno)
307{
308  cfi_add_CFA_insn_reg (DW_CFA_undefined, regno);
309}
310
311void
312cfi_add_CFA_same_value (unsigned regno)
313{
314  cfi_add_CFA_insn_reg (DW_CFA_same_value, regno);
315}
316
317void
318cfi_add_CFA_remember_state (void)
319{
320  struct cfa_save_data *p;
321
322  cfi_add_CFA_insn (DW_CFA_remember_state);
323
324  p = xmalloc (sizeof (*p));
325  p->cfa_offset = cur_cfa_offset;
326  p->next = cfa_save_stack;
327  cfa_save_stack = p;
328}
329
330void
331cfi_add_CFA_restore_state (void)
332{
333  struct cfa_save_data *p;
334
335  cfi_add_CFA_insn (DW_CFA_restore_state);
336
337  p = cfa_save_stack;
338  if (p)
339    {
340      cur_cfa_offset = p->cfa_offset;
341      cfa_save_stack = p->next;
342      free (p);
343    }
344}
345
346
347/* Parse CFI assembler directives.  */
348
349static void dot_cfi (int);
350static void dot_cfi_escape (int);
351static void dot_cfi_startproc (int);
352static void dot_cfi_endproc (int);
353
354/* Fake CFI type; outside the byte range of any real CFI insn.  */
355#define CFI_adjust_cfa_offset	0x100
356#define CFI_return_column	0x101
357#define CFI_rel_offset		0x102
358#define CFI_escape		0x103
359
360const pseudo_typeS cfi_pseudo_table[] =
361  {
362    { "cfi_startproc", dot_cfi_startproc, 0 },
363    { "cfi_endproc", dot_cfi_endproc, 0 },
364    { "cfi_def_cfa", dot_cfi, DW_CFA_def_cfa },
365    { "cfi_def_cfa_register", dot_cfi, DW_CFA_def_cfa_register },
366    { "cfi_def_cfa_offset", dot_cfi, DW_CFA_def_cfa_offset },
367    { "cfi_adjust_cfa_offset", dot_cfi, CFI_adjust_cfa_offset },
368    { "cfi_offset", dot_cfi, DW_CFA_offset },
369    { "cfi_rel_offset", dot_cfi, CFI_rel_offset },
370    { "cfi_register", dot_cfi, DW_CFA_register },
371    { "cfi_return_column", dot_cfi, CFI_return_column },
372    { "cfi_restore", dot_cfi, DW_CFA_restore },
373    { "cfi_undefined", dot_cfi, DW_CFA_undefined },
374    { "cfi_same_value", dot_cfi, DW_CFA_same_value },
375    { "cfi_remember_state", dot_cfi, DW_CFA_remember_state },
376    { "cfi_restore_state", dot_cfi, DW_CFA_restore_state },
377    { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
378    { "cfi_escape", dot_cfi_escape, 0 },
379    { NULL, NULL, 0 }
380  };
381
382static void
383cfi_parse_separator (void)
384{
385  SKIP_WHITESPACE ();
386  if (*input_line_pointer == ',')
387    input_line_pointer++;
388  else
389    as_bad (_("missing separator"));
390}
391
392static unsigned
393cfi_parse_reg (void)
394{
395  int regno;
396  expressionS exp;
397
398#ifdef tc_regname_to_dw2regnum
399  SKIP_WHITESPACE ();
400  if (is_name_beginner (*input_line_pointer)
401      || (*input_line_pointer == '%'
402	  && is_name_beginner (*++input_line_pointer)))
403    {
404      char *name, c;
405
406      name = input_line_pointer;
407      c = get_symbol_end ();
408
409      if ((regno = tc_regname_to_dw2regnum (name)) < 0)
410	{
411	  as_bad (_("bad register expression"));
412	  regno = 0;
413	}
414
415      *input_line_pointer = c;
416      return regno;
417    }
418#endif
419
420  expression (&exp);
421  switch (exp.X_op)
422    {
423    case O_register:
424    case O_constant:
425      regno = exp.X_add_number;
426      break;
427
428    default:
429      as_bad (_("bad register expression"));
430      regno = 0;
431      break;
432    }
433
434  return regno;
435}
436
437static offsetT
438cfi_parse_const (void)
439{
440  return get_absolute_expression ();
441}
442
443static void
444dot_cfi (int arg)
445{
446  offsetT offset;
447  unsigned reg1, reg2;
448
449  if (!cur_fde_data)
450    {
451      as_bad (_("CFI instruction used without previous .cfi_startproc"));
452      return;
453    }
454
455  /* If the last address was not at the current PC, advance to current.  */
456  if (symbol_get_frag (last_address) != frag_now
457      || S_GET_VALUE (last_address) != frag_now_fix ())
458    cfi_add_advance_loc (symbol_temp_new_now ());
459
460  switch (arg)
461    {
462    case DW_CFA_offset:
463      reg1 = cfi_parse_reg ();
464      cfi_parse_separator ();
465      offset = cfi_parse_const ();
466      cfi_add_CFA_offset (reg1, offset);
467      break;
468
469    case CFI_rel_offset:
470      reg1 = cfi_parse_reg ();
471      cfi_parse_separator ();
472      offset = cfi_parse_const ();
473      cfi_add_CFA_offset (reg1, offset - cur_cfa_offset);
474      break;
475
476    case DW_CFA_def_cfa:
477      reg1 = cfi_parse_reg ();
478      cfi_parse_separator ();
479      offset = cfi_parse_const ();
480      cfi_add_CFA_def_cfa (reg1, offset);
481      break;
482
483    case DW_CFA_register:
484      reg1 = cfi_parse_reg ();
485      cfi_parse_separator ();
486      reg2 = cfi_parse_reg ();
487      cfi_add_CFA_register (reg1, reg2);
488      break;
489
490    case DW_CFA_def_cfa_register:
491      reg1 = cfi_parse_reg ();
492      cfi_add_CFA_def_cfa_register (reg1);
493      break;
494
495    case DW_CFA_def_cfa_offset:
496      offset = cfi_parse_const ();
497      cfi_add_CFA_def_cfa_offset (offset);
498      break;
499
500    case CFI_adjust_cfa_offset:
501      offset = cfi_parse_const ();
502      cfi_add_CFA_def_cfa_offset (cur_cfa_offset + offset);
503      break;
504
505    case DW_CFA_restore:
506      reg1 = cfi_parse_reg ();
507      cfi_add_CFA_restore (reg1);
508      break;
509
510    case DW_CFA_undefined:
511      reg1 = cfi_parse_reg ();
512      cfi_add_CFA_undefined (reg1);
513      break;
514
515    case DW_CFA_same_value:
516      reg1 = cfi_parse_reg ();
517      cfi_add_CFA_same_value (reg1);
518      break;
519
520    case CFI_return_column:
521      reg1 = cfi_parse_reg ();
522      cfi_set_return_column (reg1);
523      break;
524
525    case DW_CFA_remember_state:
526      cfi_add_CFA_remember_state ();
527      break;
528
529    case DW_CFA_restore_state:
530      cfi_add_CFA_restore_state ();
531      break;
532
533    case DW_CFA_GNU_window_save:
534      cfi_add_CFA_insn (DW_CFA_GNU_window_save);
535      break;
536
537    default:
538      abort ();
539    }
540
541  demand_empty_rest_of_line ();
542}
543
544static void
545dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
546{
547  struct cfi_escape_data *head, **tail, *e;
548  struct cfi_insn_data *insn;
549
550  if (!cur_fde_data)
551    {
552      as_bad (_("CFI instruction used without previous .cfi_startproc"));
553      return;
554    }
555
556  /* If the last address was not at the current PC, advance to current.  */
557  if (symbol_get_frag (last_address) != frag_now
558      || S_GET_VALUE (last_address) != frag_now_fix ())
559    cfi_add_advance_loc (symbol_temp_new_now ());
560
561  tail = &head;
562  do
563    {
564      e = xmalloc (sizeof (*e));
565      do_parse_cons_expression (&e->exp, 1);
566      *tail = e;
567      tail = &e->next;
568    }
569  while (*input_line_pointer++ == ',');
570  *tail = NULL;
571
572  insn = alloc_cfi_insn_data ();
573  insn->insn = CFI_escape;
574  insn->u.esc = head;
575}
576
577static void
578dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
579{
580  int simple = 0;
581
582  if (cur_fde_data)
583    {
584      as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
585      return;
586    }
587
588  cfi_new_fde (symbol_temp_new_now ());
589
590  SKIP_WHITESPACE ();
591  if (is_name_beginner (*input_line_pointer))
592    {
593      char *name, c;
594
595      name = input_line_pointer;
596      c = get_symbol_end ();
597
598      if (strcmp (name, "simple") == 0)
599	{
600	  simple = 1;
601	  *input_line_pointer = c;
602	}
603      else
604	input_line_pointer = name;
605    }
606  demand_empty_rest_of_line ();
607
608  if (!simple)
609    tc_cfi_frame_initial_instructions ();
610}
611
612static void
613dot_cfi_endproc (int ignored ATTRIBUTE_UNUSED)
614{
615  if (! cur_fde_data)
616    {
617      as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
618      return;
619    }
620
621  cfi_end_fde (symbol_temp_new_now ());
622}
623
624
625/* Emit a single byte into the current segment.  */
626
627static inline void
628out_one (int byte)
629{
630  FRAG_APPEND_1_CHAR (byte);
631}
632
633/* Emit a two-byte word into the current segment.  */
634
635static inline void
636out_two (int data)
637{
638  md_number_to_chars (frag_more (2), data, 2);
639}
640
641/* Emit a four byte word into the current segment.  */
642
643static inline void
644out_four (int data)
645{
646  md_number_to_chars (frag_more (4), data, 4);
647}
648
649/* Emit an unsigned "little-endian base 128" number.  */
650
651static void
652out_uleb128 (addressT value)
653{
654  output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0);
655}
656
657/* Emit an unsigned "little-endian base 128" number.  */
658
659static void
660out_sleb128 (offsetT value)
661{
662  output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1);
663}
664
665static void
666output_cfi_insn (struct cfi_insn_data *insn)
667{
668  offsetT offset;
669  unsigned int regno;
670
671  switch (insn->insn)
672    {
673    case DW_CFA_advance_loc:
674      {
675	symbolS *from = insn->u.ll.lab1;
676	symbolS *to = insn->u.ll.lab2;
677
678	if (symbol_get_frag (to) == symbol_get_frag (from))
679	  {
680	    addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
681	    addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;
682
683	    if (scaled <= 0x3F)
684	      out_one (DW_CFA_advance_loc + scaled);
685	    else if (delta <= 0xFF)
686	      {
687	        out_one (DW_CFA_advance_loc1);
688	        out_one (delta);
689	      }
690	    else if (delta <= 0xFFFF)
691	      {
692	        out_one (DW_CFA_advance_loc2);
693	        out_two (delta);
694	      }
695	    else
696	      {
697	        out_one (DW_CFA_advance_loc4);
698	        out_four (delta);
699	      }
700	  }
701	else
702	  {
703	    expressionS exp;
704
705	    exp.X_op = O_subtract;
706	    exp.X_add_symbol = to;
707	    exp.X_op_symbol = from;
708	    exp.X_add_number = 0;
709
710	    /* The code in ehopt.c expects that one byte of the encoding
711	       is already allocated to the frag.  This comes from the way
712	       that it scans the .eh_frame section looking first for the
713	       .byte DW_CFA_advance_loc4.  */
714	    frag_more (1);
715
716	    frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
717		      make_expr_symbol (&exp), frag_now_fix () - 1,
718		      (char *) frag_now);
719	  }
720      }
721      break;
722
723    case DW_CFA_def_cfa:
724      offset = insn->u.ri.offset;
725      if (offset < 0)
726	{
727	  out_one (DW_CFA_def_cfa_sf);
728	  out_uleb128 (insn->u.ri.reg);
729	  out_uleb128 (offset);
730	}
731      else
732	{
733	  out_one (DW_CFA_def_cfa);
734	  out_uleb128 (insn->u.ri.reg);
735	  out_uleb128 (offset);
736	}
737      break;
738
739    case DW_CFA_def_cfa_register:
740    case DW_CFA_undefined:
741    case DW_CFA_same_value:
742      out_one (insn->insn);
743      out_uleb128 (insn->u.r);
744      break;
745
746    case DW_CFA_def_cfa_offset:
747      offset = insn->u.i;
748      if (offset < 0)
749	{
750	  out_one (DW_CFA_def_cfa_offset_sf);
751	  out_sleb128 (offset);
752	}
753      else
754	{
755	  out_one (DW_CFA_def_cfa_offset);
756	  out_uleb128 (offset);
757	}
758      break;
759
760    case DW_CFA_restore:
761      regno = insn->u.r;
762      if (regno <= 0x3F)
763	{
764	  out_one (DW_CFA_restore + regno);
765	}
766      else
767	{
768	  out_one (DW_CFA_restore_extended);
769	  out_uleb128 (regno);
770	}
771      break;
772
773    case DW_CFA_offset:
774      regno = insn->u.ri.reg;
775      offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
776      if (offset < 0)
777	{
778	  out_one (DW_CFA_offset_extended_sf);
779	  out_uleb128 (regno);
780	  out_sleb128 (offset);
781	}
782      else if (regno <= 0x3F)
783	{
784	  out_one (DW_CFA_offset + regno);
785	  out_uleb128 (offset);
786	}
787      else
788	{
789	  out_one (DW_CFA_offset_extended);
790	  out_uleb128 (regno);
791	  out_uleb128 (offset);
792	}
793      break;
794
795    case DW_CFA_register:
796      out_one (DW_CFA_register);
797      out_uleb128 (insn->u.rr.reg1);
798      out_uleb128 (insn->u.rr.reg2);
799      break;
800
801    case DW_CFA_remember_state:
802    case DW_CFA_restore_state:
803      out_one (insn->insn);
804      break;
805
806    case DW_CFA_GNU_window_save:
807      out_one (DW_CFA_GNU_window_save);
808      break;
809
810    case CFI_escape:
811      {
812	struct cfi_escape_data *e;
813	for (e = insn->u.esc; e ; e = e->next)
814	  emit_expr (&e->exp, 1);
815	break;
816      }
817
818    default:
819      abort ();
820    }
821}
822
823static void
824output_cie (struct cie_entry *cie)
825{
826  symbolS *after_size_address, *end_address;
827  expressionS exp;
828  struct cfi_insn_data *i;
829
830  cie->start_address = symbol_temp_new_now ();
831  after_size_address = symbol_temp_make ();
832  end_address = symbol_temp_make ();
833
834  exp.X_op = O_subtract;
835  exp.X_add_symbol = end_address;
836  exp.X_op_symbol = after_size_address;
837  exp.X_add_number = 0;
838
839  emit_expr (&exp, 4);				/* Length */
840  symbol_set_value_now (after_size_address);
841  out_four (0);					/* CIE id */
842  out_one (DW_CIE_VERSION);			/* Version */
843  out_one ('z');				/* Augmentation */
844  out_one ('R');
845  out_one (0);
846  out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH);	/* Code alignment */
847  out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT);	/* Data alignment */
848  out_one (cie->return_column);			/* Return column */
849  out_uleb128 (1);				/* Augmentation size */
850#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
851  out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
852#else
853  out_one (DW_EH_PE_sdata4);
854#endif
855
856  if (cie->first)
857    for (i = cie->first; i != cie->last; i = i->next)
858      output_cfi_insn (i);
859
860  frag_align (2, 0, 0);
861  symbol_set_value_now (end_address);
862}
863
864static void
865output_fde (struct fde_entry *fde, struct cie_entry *cie,
866	    struct cfi_insn_data *first, int align)
867{
868  symbolS *after_size_address, *end_address;
869  expressionS exp;
870
871  after_size_address = symbol_temp_make ();
872  end_address = symbol_temp_make ();
873
874  exp.X_op = O_subtract;
875  exp.X_add_symbol = end_address;
876  exp.X_op_symbol = after_size_address;
877  exp.X_add_number = 0;
878  emit_expr (&exp, 4);				/* Length */
879  symbol_set_value_now (after_size_address);
880
881  exp.X_add_symbol = after_size_address;
882  exp.X_op_symbol = cie->start_address;
883  emit_expr (&exp, 4);				/* CIE offset */
884
885#ifdef DIFF_EXPR_OK
886  exp.X_add_symbol = fde->start_address;
887  exp.X_op_symbol = symbol_temp_new_now ();
888  emit_expr (&exp, 4);				/* Code offset */
889#else
890  exp.X_op = O_symbol;
891  exp.X_add_symbol = fde->start_address;
892  exp.X_op_symbol = NULL;
893#ifdef tc_cfi_emit_pcrel_expr
894  tc_cfi_emit_pcrel_expr (&exp, 4);		/* Code offset */
895#else
896  emit_expr (&exp, 4);				/* Code offset */
897#endif
898  exp.X_op = O_subtract;
899#endif
900
901  exp.X_add_symbol = fde->end_address;
902  exp.X_op_symbol = fde->start_address;		/* Code length */
903  emit_expr (&exp, 4);
904
905  out_uleb128 (0);				/* Augmentation size */
906
907  for (; first; first = first->next)
908    output_cfi_insn (first);
909
910  frag_align (align, 0, 0);
911  symbol_set_value_now (end_address);
912}
913
914static struct cie_entry *
915select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
916{
917  struct cfi_insn_data *i, *j;
918  struct cie_entry *cie;
919
920  for (cie = cie_root; cie; cie = cie->next)
921    {
922      if (cie->return_column != fde->return_column)
923	continue;
924      for (i = cie->first, j = fde->data;
925	   i != cie->last && j != NULL;
926	   i = i->next, j = j->next)
927	{
928	  if (i->insn != j->insn)
929	    goto fail;
930	  switch (i->insn)
931	    {
932	    case DW_CFA_advance_loc:
933	      /* We reached the first advance in the FDE, but did not
934		 reach the end of the CIE list.  */
935	      goto fail;
936
937	    case DW_CFA_offset:
938	    case DW_CFA_def_cfa:
939	      if (i->u.ri.reg != j->u.ri.reg)
940		goto fail;
941	      if (i->u.ri.offset != j->u.ri.offset)
942		goto fail;
943	      break;
944
945	    case DW_CFA_register:
946	      if (i->u.rr.reg1 != j->u.rr.reg1)
947		goto fail;
948	      if (i->u.rr.reg2 != j->u.rr.reg2)
949		goto fail;
950	      break;
951
952	    case DW_CFA_def_cfa_register:
953	    case DW_CFA_restore:
954	    case DW_CFA_undefined:
955	    case DW_CFA_same_value:
956	      if (i->u.r != j->u.r)
957		goto fail;
958	      break;
959
960	    case DW_CFA_def_cfa_offset:
961	      if (i->u.i != j->u.i)
962		goto fail;
963	      break;
964
965	    case CFI_escape:
966	      /* Don't bother matching these for now.  */
967	      goto fail;
968
969	    default:
970	      abort ();
971	    }
972	}
973
974      /* Success if we reached the end of the CIE list, and we've either
975	 run out of FDE entries or we've encountered an advance.  */
976      if (i == cie->last && (!j || j->insn == DW_CFA_advance_loc))
977	{
978	  *pfirst = j;
979	  return cie;
980	}
981
982    fail:;
983    }
984
985  cie = xmalloc (sizeof (struct cie_entry));
986  cie->next = cie_root;
987  cie_root = cie;
988  cie->return_column = fde->return_column;
989  cie->first = fde->data;
990
991  for (i = cie->first; i ; i = i->next)
992    if (i->insn == DW_CFA_advance_loc)
993      break;
994
995  cie->last = i;
996  *pfirst = i;
997
998  output_cie (cie);
999
1000  return cie;
1001}
1002
1003void
1004cfi_finish (void)
1005{
1006  segT cfi_seg;
1007  struct fde_entry *fde;
1008  int save_flag_traditional_format;
1009
1010  if (cur_fde_data)
1011    {
1012      as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
1013      cur_fde_data->end_address = cur_fde_data->start_address;
1014    }
1015
1016  if (all_fde_data == 0)
1017    return;
1018
1019  /* Open .eh_frame section.  */
1020  cfi_seg = subseg_new (".eh_frame", 0);
1021#ifdef BFD_ASSEMBLER
1022  bfd_set_section_flags (stdoutput, cfi_seg,
1023			 SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY);
1024#endif
1025  subseg_set (cfi_seg, 0);
1026  record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
1027
1028  /* Make sure check_eh_frame doesn't do anything with our output.  */
1029  save_flag_traditional_format = flag_traditional_format;
1030  flag_traditional_format = 1;
1031
1032  for (fde = all_fde_data; fde ; fde = fde->next)
1033    {
1034      struct cfi_insn_data *first;
1035      struct cie_entry *cie;
1036
1037      cie = select_cie_for_fde (fde, &first);
1038      output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
1039    }
1040
1041  flag_traditional_format = save_flag_traditional_format;
1042}
1043