2003-05-07 Eric Christopher <echristo@redhat.com>
[deliverable/binutils-gdb.git] / gas / dw2gencfi.c
CommitLineData
54cfded0
AM
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
39b82151
ML
26struct cie_entry
27{
28 unsigned long offset;
29 size_t size;
30 void *data;
31 struct cie_entry *next;
32};
33
34struct cfi_data
35{
36 enum cfi_insn insn;
37 long param[2];
38 struct cfi_data *next;
39};
40
41struct 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. */
52static struct cfi_info *cfi_info;
53
54/* List of CIEs so that they could be reused. */
55static struct cie_entry *cie_root;
56
54cfded0
AM
57/* Current target config. */
58static struct cfi_config current_config;
59
60/* This is the main entry point to the CFI machinery. */
61static void dot_cfi (int arg);
62
63const 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 },
39b82151 73 { "cfi_register", dot_cfi, CFA_register },
54cfded0
AM
74 { NULL, NULL, 0 }
75 };
76
77static const char *
78cfi_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
54cfded0
AM
125static struct cfi_data *
126alloc_cfi_data (void)
127{
128 return (struct cfi_data *) xcalloc (sizeof (struct cfi_info), 1);
129}
130
131static struct cfi_info *
132alloc_cfi_info (void)
133{
134 return (struct cfi_info *) xcalloc (sizeof (struct cfi_info), 1);
135}
136
137/* Parse arguments. */
138static int
139cfi_parse_arg (long *param, int resolvereg)
140{
54cfded0
AM
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 }
7c0295b1 153#ifdef tc_regname_to_dw2regnum
39b82151
ML
154 else if (resolvereg && ((is_name_beginner (*input_line_pointer))
155 || (*input_line_pointer == '%'
156 && is_name_beginner (*(++input_line_pointer)))))
54cfded0 157 {
7c0295b1
AM
158 char *name, c, *p;
159
54cfded0
AM
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 }
7c0295b1 169#endif
54cfded0
AM
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
188static int
189cfi_parse_reg (long *param)
190{
191 return cfi_parse_arg (param, 1);
192}
193
194static int
195cfi_parse_const (long *param)
196{
197 return cfi_parse_arg (param, 0);
198}
199
200void
201cfi_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
227static void
228cfi_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
238static long
239get_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
257static void
258cfi_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
39b82151
ML
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
54cfded0
AM
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
341static symbolS *
342cfi_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))
7ed2c8b0
NC
354 return symbolP;
355
54cfded0
AM
356 snprintf (symname, sizeof (symname), "%s_0x%lx_%u",
357 symbase, (long) frag_now_fix (), i++);
358 }
7ed2c8b0 359#ifdef BFD_ASSEMBLER
54cfded0
AM
360 symbolP = (symbolS *) local_symbol_make (symname, now_seg,
361 (valueT) frag_now_fix (),
362 frag_now);
7ed2c8b0
NC
363#else
364 symbolP = symbol_make (symname);
365#endif
54cfded0
AM
366 return symbolP;
367}
368
369static void
370dot_cfi_startproc (void)
371{
7ed2c8b0 372#ifdef tc_cfi_frame_initial_instructions
39b82151 373 const char *simple = "simple";
7ed2c8b0 374#endif
39b82151 375
54cfded0
AM
376 if (cfi_info)
377 {
378 as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
379 return;
380 }
381
39b82151
ML
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
54cfded0
AM
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
39b82151 395 SKIP_WHITESPACE ();
54cfded0 396#ifdef tc_cfi_frame_initial_instructions
39b82151
ML
397 if (strncmp (simple, input_line_pointer, strlen (simple)) != 0)
398 tc_cfi_frame_initial_instructions ();
399 else
400 input_line_pointer += strlen (simple);
54cfded0
AM
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
39b82151
ML
408/* Output CFI instructions to the file. */
409
54cfded0
AM
410enum 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
54cfded0
AM
421static int
422output_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:
39b82151
ML
444 /* This should never happen - throw an internal error. */
445 as_fatal (_("unknown type %d"), type);
54cfded0
AM
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:
39b82151 486 as_fatal (_("unknown type %d"), type);
54cfded0
AM
487 return 0;
488 }
489
490 *size -= ret_size;
491 *p += ret_size;
492
493 return ret_size;
494}
495
496static int
497cfi_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)
39b82151
ML
538 printf ("\t# CFA_def_cfa(%ld,%ld)\n",
539 data->param[0], data->param[1]);
54cfded0
AM
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
39b82151
ML
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
54cfded0
AM
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
596static void
597dot_cfi_endproc (void)
598{
599 struct cfi_data *data_ptr;
39b82151 600 struct cie_entry *cie_ptr;
54cfded0 601 char *cie_buf, *fde_buf, *pbuf, *where;
39b82151
ML
602 unsigned long buf_size, cie_size, fde_size, last_cie_offset;
603 unsigned long fde_initloc_offset, fde_len_offset, fde_offset;
7ed2c8b0 604 segT saved_seg, cfi_seg;
7c0295b1 605 expressionS exp;
54cfded0
AM
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);
7ed2c8b0 617#ifdef BFD_ASSEMBLER
54cfded0
AM
618 bfd_set_section_flags (stdoutput, cfi_seg,
619 SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
7ed2c8b0 620#endif
54cfded0
AM
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 ();
39b82151
ML
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 }
54cfded0
AM
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
39b82151
ML
717 /* Offset of this FDE in current fragment. */
718 fde_offset = frag_now_fix ();
719
54cfded0
AM
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. */
39b82151 734 output_data (&pbuf, &buf_size, t_long, fde_offset - last_cie_offset + 4);
54cfded0
AM
735
736 /* FDE initial location - this must be set relocatable! */
39b82151 737 fde_initloc_offset = pbuf - fde_buf + fde_offset;
54cfded0
AM
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
54cfded0
AM
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;
54cfded0
AM
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
782void
783dot_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:
39b82151 799 case CFA_register:
54cfded0
AM
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
816void
817cfi_set_config (struct cfi_config *cfg)
818{
819 assert (cfg != NULL);
820 assert (cfg->addr_length > 0);
821
822 current_config = *cfg;
823}
824
825void
826cfi_finish (void)
827{
828 if (cfi_info)
829 as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
830}
This page took 0.058289 seconds and 4 git commands to generate.