Put size and endianness in parameters.
[deliverable/binutils-gdb.git] / gas / dw2gencfi.c
CommitLineData
54cfded0 1/* dw2gencfi.c - Support for generating Dwarf2 CFI information.
ec2655a6 2 Copyright 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
54cfded0
AM
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
ec2655a6 9 the Free Software Foundation; either version 3, or (at your option)
54cfded0
AM
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
4b4da160
NC
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20 02110-1301, USA. */
54cfded0 21
54cfded0
AM
22#include "as.h"
23#include "dw2gencfi.h"
ae424f82 24#include "subsegs.h"
54cfded0 25
a4447b93
RH
26
27/* We re-use DWARF2_LINE_MIN_INSN_LENGTH for the code alignment field
28 of the CIE. Default to 1 if not otherwise specified. */
289040ca 29#ifndef DWARF2_LINE_MIN_INSN_LENGTH
a4447b93
RH
30# define DWARF2_LINE_MIN_INSN_LENGTH 1
31#endif
32
33/* If TARGET_USE_CFIPOP is defined, it is required that the target
34 provide the following definitions. Otherwise provide them to
35 allow compilation to continue. */
36#ifndef TARGET_USE_CFIPOP
289040ca 37# ifndef DWARF2_DEFAULT_RETURN_COLUMN
a4447b93
RH
38# define DWARF2_DEFAULT_RETURN_COLUMN 0
39# endif
289040ca 40# ifndef DWARF2_CIE_DATA_ALIGNMENT
a4447b93
RH
41# define DWARF2_CIE_DATA_ALIGNMENT 1
42# endif
43#endif
44
9393cb0d 45#ifndef EH_FRAME_ALIGNMENT
7be1c489 46# define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
9393cb0d
JJ
47#endif
48
a4447b93
RH
49#ifndef tc_cfi_frame_initial_instructions
50# define tc_cfi_frame_initial_instructions() ((void)0)
51#endif
52
53
54struct cfi_insn_data
39b82151 55{
a4447b93
RH
56 struct cfi_insn_data *next;
57 int insn;
58 union {
59 struct {
60 unsigned reg;
61 offsetT offset;
62 } ri;
63
64 struct {
65 unsigned reg1;
66 unsigned reg2;
67 } rr;
68
69 unsigned r;
70 offsetT i;
71
72 struct {
73 symbolS *lab1;
74 symbolS *lab2;
75 } ll;
cdfbf930
RH
76
77 struct cfi_escape_data {
78 struct cfi_escape_data *next;
79 expressionS exp;
80 } *esc;
a4447b93 81 } u;
39b82151
ML
82};
83
a4447b93 84struct fde_entry
39b82151 85{
a4447b93
RH
86 struct fde_entry *next;
87 symbolS *start_address;
88 symbolS *end_address;
89 struct cfi_insn_data *data;
90 struct cfi_insn_data **last;
9b8ae42e
JJ
91 unsigned char per_encoding;
92 unsigned char lsda_encoding;
93 expressionS personality;
94 expressionS lsda;
a4447b93 95 unsigned int return_column;
63752a75 96 unsigned int signal_frame;
39b82151
ML
97};
98
a4447b93 99struct cie_entry
39b82151 100{
a4447b93
RH
101 struct cie_entry *next;
102 symbolS *start_address;
103 unsigned int return_column;
63752a75 104 unsigned int signal_frame;
9b8ae42e
JJ
105 unsigned char per_encoding;
106 unsigned char lsda_encoding;
107 expressionS personality;
a4447b93 108 struct cfi_insn_data *first, *last;
39b82151
ML
109};
110
a4447b93 111
a4447b93
RH
112/* List of FDE entries. */
113static struct fde_entry *all_fde_data;
114static struct fde_entry **last_fde_data = &all_fde_data;
39b82151
ML
115
116/* List of CIEs so that they could be reused. */
117static struct cie_entry *cie_root;
118
fa87b337
RH
119/* Stack of old CFI data, for save/restore. */
120struct cfa_save_data
121{
122 struct cfa_save_data *next;
123 offsetT cfa_offset;
124};
125
ae424f82
JJ
126/* Current open FDE entry. */
127struct frch_cfi_data
128{
129 struct fde_entry *cur_fde_data;
130 symbolS *last_address;
131 offsetT cur_cfa_offset;
132 struct cfa_save_data *cfa_save_stack;
133};
a4447b93
RH
134\f
135/* Construct a new FDE structure and add it to the end of the fde list. */
54cfded0 136
a4447b93
RH
137static struct fde_entry *
138alloc_fde_entry (void)
139{
140 struct fde_entry *fde = xcalloc (1, sizeof (struct fde_entry));
54cfded0 141
ae424f82
JJ
142 frchain_now->frch_cfi_data = xcalloc (1, sizeof (struct frch_cfi_data));
143 frchain_now->frch_cfi_data->cur_fde_data = fde;
a4447b93
RH
144 *last_fde_data = fde;
145 last_fde_data = &fde->next;
54cfded0 146
a4447b93
RH
147 fde->last = &fde->data;
148 fde->return_column = DWARF2_DEFAULT_RETURN_COLUMN;
9b8ae42e
JJ
149 fde->per_encoding = DW_EH_PE_omit;
150 fde->lsda_encoding = DW_EH_PE_omit;
a4447b93
RH
151
152 return fde;
153}
154
155/* The following functions are available for a backend to construct its
156 own unwind information, usually from legacy unwind directives. */
157
158/* Construct a new INSN structure and add it to the end of the insn list
159 for the currently active FDE. */
160
161static struct cfi_insn_data *
162alloc_cfi_insn_data (void)
54cfded0 163{
a4447b93 164 struct cfi_insn_data *insn = xcalloc (1, sizeof (struct cfi_insn_data));
ae424f82 165 struct fde_entry *cur_fde_data = frchain_now->frch_cfi_data->cur_fde_data;
a4447b93
RH
166
167 *cur_fde_data->last = insn;
168 cur_fde_data->last = &insn->next;
54cfded0 169
a4447b93 170 return insn;
54cfded0
AM
171}
172
a4447b93
RH
173/* Construct a new FDE structure that begins at LABEL. */
174
175void
176cfi_new_fde (symbolS *label)
54cfded0 177{
a4447b93
RH
178 struct fde_entry *fde = alloc_fde_entry ();
179 fde->start_address = label;
ae424f82 180 frchain_now->frch_cfi_data->last_address = label;
54cfded0
AM
181}
182
a4447b93
RH
183/* End the currently open FDE. */
184
185void
186cfi_end_fde (symbolS *label)
54cfded0 187{
ae424f82
JJ
188 frchain_now->frch_cfi_data->cur_fde_data->end_address = label;
189 free (frchain_now->frch_cfi_data);
190 frchain_now->frch_cfi_data = NULL;
54cfded0
AM
191}
192
a4447b93
RH
193/* Set the return column for the current FDE. */
194
195void
196cfi_set_return_column (unsigned regno)
54cfded0 197{
ae424f82 198 frchain_now->frch_cfi_data->cur_fde_data->return_column = regno;
a4447b93 199}
54cfded0 200
2be24b54
ML
201/* Universal functions to store new instructions. */
202
203static void
204cfi_add_CFA_insn(int insn)
205{
206 struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
207
208 insn_ptr->insn = insn;
209}
210
211static void
212cfi_add_CFA_insn_reg (int insn, unsigned regno)
213{
214 struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
215
216 insn_ptr->insn = insn;
217 insn_ptr->u.r = regno;
218}
219
220static void
221cfi_add_CFA_insn_offset (int insn, offsetT offset)
222{
223 struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
224
225 insn_ptr->insn = insn;
226 insn_ptr->u.i = offset;
227}
228
229static void
230cfi_add_CFA_insn_reg_reg (int insn, unsigned reg1, unsigned reg2)
231{
232 struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
233
234 insn_ptr->insn = insn;
235 insn_ptr->u.rr.reg1 = reg1;
236 insn_ptr->u.rr.reg2 = reg2;
237}
238
239static void
240cfi_add_CFA_insn_reg_offset (int insn, unsigned regno, offsetT offset)
241{
242 struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
243
244 insn_ptr->insn = insn;
245 insn_ptr->u.ri.reg = regno;
246 insn_ptr->u.ri.offset = offset;
247}
248
a4447b93 249/* Add a CFI insn to advance the PC from the last address to LABEL. */
54cfded0 250
a4447b93
RH
251void
252cfi_add_advance_loc (symbolS *label)
253{
254 struct cfi_insn_data *insn = alloc_cfi_insn_data ();
7c0295b1 255
a4447b93 256 insn->insn = DW_CFA_advance_loc;
ae424f82 257 insn->u.ll.lab1 = frchain_now->frch_cfi_data->last_address;
a4447b93 258 insn->u.ll.lab2 = label;
54cfded0 259
ae424f82 260 frchain_now->frch_cfi_data->last_address = label;
a4447b93 261}
54cfded0 262
a4447b93
RH
263/* Add a DW_CFA_offset record to the CFI data. */
264
265void
266cfi_add_CFA_offset (unsigned regno, offsetT offset)
267{
fa87b337
RH
268 unsigned int abs_data_align;
269
ba5f0fda 270 assert (DWARF2_CIE_DATA_ALIGNMENT != 0);
2be24b54 271 cfi_add_CFA_insn_reg_offset (DW_CFA_offset, regno, offset);
fa87b337
RH
272
273 abs_data_align = (DWARF2_CIE_DATA_ALIGNMENT < 0
274 ? -DWARF2_CIE_DATA_ALIGNMENT : DWARF2_CIE_DATA_ALIGNMENT);
275 if (offset % abs_data_align)
276 as_bad (_("register save offset not a multiple of %u"), abs_data_align);
a4447b93 277}
54cfded0 278
a4447b93 279/* Add a DW_CFA_def_cfa record to the CFI data. */
54cfded0 280
a4447b93
RH
281void
282cfi_add_CFA_def_cfa (unsigned regno, offsetT offset)
283{
2be24b54 284 cfi_add_CFA_insn_reg_offset (DW_CFA_def_cfa, regno, offset);
ae424f82 285 frchain_now->frch_cfi_data->cur_cfa_offset = offset;
54cfded0
AM
286}
287
a4447b93
RH
288/* Add a DW_CFA_register record to the CFI data. */
289
290void
291cfi_add_CFA_register (unsigned reg1, unsigned reg2)
54cfded0 292{
2be24b54 293 cfi_add_CFA_insn_reg_reg (DW_CFA_register, reg1, reg2);
54cfded0
AM
294}
295
a4447b93
RH
296/* Add a DW_CFA_def_cfa_register record to the CFI data. */
297
298void
299cfi_add_CFA_def_cfa_register (unsigned regno)
54cfded0 300{
2be24b54 301 cfi_add_CFA_insn_reg (DW_CFA_def_cfa_register, regno);
54cfded0
AM
302}
303
a4447b93
RH
304/* Add a DW_CFA_def_cfa_offset record to the CFI data. */
305
54cfded0 306void
a4447b93 307cfi_add_CFA_def_cfa_offset (offsetT offset)
54cfded0 308{
2be24b54 309 cfi_add_CFA_insn_offset (DW_CFA_def_cfa_offset, offset);
ae424f82 310 frchain_now->frch_cfi_data->cur_cfa_offset = offset;
a4447b93 311}
54cfded0 312
2be24b54
ML
313void
314cfi_add_CFA_restore (unsigned regno)
315{
316 cfi_add_CFA_insn_reg (DW_CFA_restore, regno);
317}
318
319void
320cfi_add_CFA_undefined (unsigned regno)
321{
322 cfi_add_CFA_insn_reg (DW_CFA_undefined, regno);
323}
324
325void
326cfi_add_CFA_same_value (unsigned regno)
327{
328 cfi_add_CFA_insn_reg (DW_CFA_same_value, regno);
329}
330
331void
332cfi_add_CFA_remember_state (void)
333{
fa87b337
RH
334 struct cfa_save_data *p;
335
2be24b54 336 cfi_add_CFA_insn (DW_CFA_remember_state);
fa87b337
RH
337
338 p = xmalloc (sizeof (*p));
ae424f82
JJ
339 p->cfa_offset = frchain_now->frch_cfi_data->cur_cfa_offset;
340 p->next = frchain_now->frch_cfi_data->cfa_save_stack;
341 frchain_now->frch_cfi_data->cfa_save_stack = p;
2be24b54
ML
342}
343
344void
345cfi_add_CFA_restore_state (void)
346{
fa87b337
RH
347 struct cfa_save_data *p;
348
2be24b54 349 cfi_add_CFA_insn (DW_CFA_restore_state);
fa87b337 350
ae424f82 351 p = frchain_now->frch_cfi_data->cfa_save_stack;
fa87b337
RH
352 if (p)
353 {
ae424f82
JJ
354 frchain_now->frch_cfi_data->cur_cfa_offset = p->cfa_offset;
355 frchain_now->frch_cfi_data->cfa_save_stack = p->next;
fa87b337
RH
356 free (p);
357 }
289040ca
NC
358 else
359 as_bad (_("CFI state restore without previous remember"));
2be24b54
ML
360}
361
a4447b93
RH
362\f
363/* Parse CFI assembler directives. */
54cfded0 364
a4447b93 365static void dot_cfi (int);
cdfbf930 366static void dot_cfi_escape (int);
a4447b93
RH
367static void dot_cfi_startproc (int);
368static void dot_cfi_endproc (int);
9b8ae42e
JJ
369static void dot_cfi_personality (int);
370static void dot_cfi_lsda (int);
54cfded0 371
a4447b93 372/* Fake CFI type; outside the byte range of any real CFI insn. */
2be24b54
ML
373#define CFI_adjust_cfa_offset 0x100
374#define CFI_return_column 0x101
fa87b337 375#define CFI_rel_offset 0x102
cdfbf930 376#define CFI_escape 0x103
63752a75 377#define CFI_signal_frame 0x104
54cfded0 378
a4447b93
RH
379const pseudo_typeS cfi_pseudo_table[] =
380 {
381 { "cfi_startproc", dot_cfi_startproc, 0 },
382 { "cfi_endproc", dot_cfi_endproc, 0 },
383 { "cfi_def_cfa", dot_cfi, DW_CFA_def_cfa },
384 { "cfi_def_cfa_register", dot_cfi, DW_CFA_def_cfa_register },
385 { "cfi_def_cfa_offset", dot_cfi, DW_CFA_def_cfa_offset },
386 { "cfi_adjust_cfa_offset", dot_cfi, CFI_adjust_cfa_offset },
387 { "cfi_offset", dot_cfi, DW_CFA_offset },
fa87b337 388 { "cfi_rel_offset", dot_cfi, CFI_rel_offset },
a4447b93 389 { "cfi_register", dot_cfi, DW_CFA_register },
2be24b54
ML
390 { "cfi_return_column", dot_cfi, CFI_return_column },
391 { "cfi_restore", dot_cfi, DW_CFA_restore },
392 { "cfi_undefined", dot_cfi, DW_CFA_undefined },
393 { "cfi_same_value", dot_cfi, DW_CFA_same_value },
394 { "cfi_remember_state", dot_cfi, DW_CFA_remember_state },
395 { "cfi_restore_state", dot_cfi, DW_CFA_restore_state },
6749011b 396 { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
cdfbf930 397 { "cfi_escape", dot_cfi_escape, 0 },
63752a75 398 { "cfi_signal_frame", dot_cfi, CFI_signal_frame },
9b8ae42e
JJ
399 { "cfi_personality", dot_cfi_personality, 0 },
400 { "cfi_lsda", dot_cfi_lsda, 0 },
a4447b93
RH
401 { NULL, NULL, 0 }
402 };
54cfded0
AM
403
404static void
a4447b93 405cfi_parse_separator (void)
54cfded0 406{
a4447b93
RH
407 SKIP_WHITESPACE ();
408 if (*input_line_pointer == ',')
409 input_line_pointer++;
410 else
411 as_bad (_("missing separator"));
54cfded0
AM
412}
413
a4447b93
RH
414static unsigned
415cfi_parse_reg (void)
54cfded0 416{
a4447b93
RH
417 int regno;
418 expressionS exp;
419
420#ifdef tc_regname_to_dw2regnum
421 SKIP_WHITESPACE ();
422 if (is_name_beginner (*input_line_pointer)
423 || (*input_line_pointer == '%'
424 && is_name_beginner (*++input_line_pointer)))
425 {
426 char *name, c;
427
428 name = input_line_pointer;
429 c = get_symbol_end ();
430
431 if ((regno = tc_regname_to_dw2regnum (name)) < 0)
432 {
433 as_bad (_("bad register expression"));
434 regno = 0;
435 }
54cfded0 436
a4447b93
RH
437 *input_line_pointer = c;
438 return regno;
439 }
440#endif
441
9497f5ac 442 expression_and_evaluate (&exp);
a4447b93 443 switch (exp.X_op)
54cfded0 444 {
a4447b93
RH
445 case O_register:
446 case O_constant:
447 regno = exp.X_add_number;
448 break;
449
450 default:
451 as_bad (_("bad register expression"));
452 regno = 0;
453 break;
54cfded0
AM
454 }
455
a4447b93
RH
456 return regno;
457}
458
459static offsetT
460cfi_parse_const (void)
461{
462 return get_absolute_expression ();
54cfded0
AM
463}
464
465static void
a4447b93 466dot_cfi (int arg)
54cfded0 467{
a4447b93
RH
468 offsetT offset;
469 unsigned reg1, reg2;
54cfded0 470
ae424f82 471 if (frchain_now->frch_cfi_data == NULL)
54cfded0
AM
472 {
473 as_bad (_("CFI instruction used without previous .cfi_startproc"));
7c9c8381 474 ignore_rest_of_line ();
54cfded0
AM
475 return;
476 }
477
a4447b93 478 /* If the last address was not at the current PC, advance to current. */
ae424f82
JJ
479 if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
480 || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
481 != frag_now_fix ())
a4447b93 482 cfi_add_advance_loc (symbol_temp_new_now ());
54cfded0
AM
483
484 switch (arg)
485 {
a4447b93 486 case DW_CFA_offset:
a4447b93
RH
487 reg1 = cfi_parse_reg ();
488 cfi_parse_separator ();
489 offset = cfi_parse_const ();
2be24b54
ML
490 cfi_add_CFA_offset (reg1, offset);
491 break;
a4447b93 492
fa87b337
RH
493 case CFI_rel_offset:
494 reg1 = cfi_parse_reg ();
495 cfi_parse_separator ();
496 offset = cfi_parse_const ();
ae424f82
JJ
497 cfi_add_CFA_offset (reg1,
498 offset - frchain_now->frch_cfi_data->cur_cfa_offset);
fa87b337
RH
499 break;
500
2be24b54
ML
501 case DW_CFA_def_cfa:
502 reg1 = cfi_parse_reg ();
503 cfi_parse_separator ();
504 offset = cfi_parse_const ();
505 cfi_add_CFA_def_cfa (reg1, offset);
54cfded0
AM
506 break;
507
a4447b93
RH
508 case DW_CFA_register:
509 reg1 = cfi_parse_reg ();
510 cfi_parse_separator ();
511 reg2 = cfi_parse_reg ();
a4447b93 512 cfi_add_CFA_register (reg1, reg2);
39b82151
ML
513 break;
514
a4447b93
RH
515 case DW_CFA_def_cfa_register:
516 reg1 = cfi_parse_reg ();
517 cfi_add_CFA_def_cfa_register (reg1);
54cfded0
AM
518 break;
519
a4447b93
RH
520 case DW_CFA_def_cfa_offset:
521 offset = cfi_parse_const ();
522 cfi_add_CFA_def_cfa_offset (offset);
54cfded0
AM
523 break;
524
54cfded0 525 case CFI_adjust_cfa_offset:
a4447b93 526 offset = cfi_parse_const ();
ae424f82
JJ
527 cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset
528 + offset);
54cfded0
AM
529 break;
530
2be24b54 531 case DW_CFA_restore:
b57d375b
JB
532 for (;;)
533 {
534 reg1 = cfi_parse_reg ();
535 cfi_add_CFA_restore (reg1);
536 SKIP_WHITESPACE ();
537 if (*input_line_pointer != ',')
538 break;
539 ++input_line_pointer;
540 }
2be24b54
ML
541 break;
542
543 case DW_CFA_undefined:
b57d375b
JB
544 for (;;)
545 {
546 reg1 = cfi_parse_reg ();
547 cfi_add_CFA_undefined (reg1);
548 SKIP_WHITESPACE ();
549 if (*input_line_pointer != ',')
550 break;
551 ++input_line_pointer;
552 }
2be24b54
ML
553 break;
554
555 case DW_CFA_same_value:
556 reg1 = cfi_parse_reg ();
557 cfi_add_CFA_same_value (reg1);
558 break;
559
560 case CFI_return_column:
561 reg1 = cfi_parse_reg ();
562 cfi_set_return_column (reg1);
563 break;
564
565 case DW_CFA_remember_state:
566 cfi_add_CFA_remember_state ();
567 break;
568
569 case DW_CFA_restore_state:
570 cfi_add_CFA_restore_state ();
571 break;
572
364b6d8b
JJ
573 case DW_CFA_GNU_window_save:
574 cfi_add_CFA_insn (DW_CFA_GNU_window_save);
575 break;
576
63752a75 577 case CFI_signal_frame:
ae424f82 578 frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
63752a75
JJ
579 break;
580
54cfded0 581 default:
a4447b93 582 abort ();
54cfded0 583 }
54cfded0 584
a4447b93 585 demand_empty_rest_of_line ();
54cfded0
AM
586}
587
cdfbf930
RH
588static void
589dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
590{
591 struct cfi_escape_data *head, **tail, *e;
592 struct cfi_insn_data *insn;
593
ae424f82 594 if (frchain_now->frch_cfi_data == NULL)
cdfbf930
RH
595 {
596 as_bad (_("CFI instruction used without previous .cfi_startproc"));
7c9c8381 597 ignore_rest_of_line ();
cdfbf930
RH
598 return;
599 }
600
601 /* If the last address was not at the current PC, advance to current. */
ae424f82
JJ
602 if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
603 || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
604 != frag_now_fix ())
cdfbf930
RH
605 cfi_add_advance_loc (symbol_temp_new_now ());
606
607 tail = &head;
608 do
609 {
610 e = xmalloc (sizeof (*e));
611 do_parse_cons_expression (&e->exp, 1);
612 *tail = e;
613 tail = &e->next;
614 }
615 while (*input_line_pointer++ == ',');
616 *tail = NULL;
617
618 insn = alloc_cfi_insn_data ();
619 insn->insn = CFI_escape;
620 insn->u.esc = head;
7c9c8381
JB
621
622 --input_line_pointer;
623 demand_empty_rest_of_line ();
cdfbf930
RH
624}
625
9b8ae42e
JJ
626static void
627dot_cfi_personality (int ignored ATTRIBUTE_UNUSED)
628{
629 struct fde_entry *fde;
630 offsetT encoding;
631
632 if (frchain_now->frch_cfi_data == NULL)
633 {
634 as_bad (_("CFI instruction used without previous .cfi_startproc"));
635 ignore_rest_of_line ();
636 return;
637 }
638
639 fde = frchain_now->frch_cfi_data->cur_fde_data;
640 encoding = get_absolute_expression ();
641 if (encoding == DW_EH_PE_omit)
642 {
643 demand_empty_rest_of_line ();
644 fde->per_encoding = encoding;
645 return;
646 }
647
648 if ((encoding & 0xff) != encoding
649 || ((encoding & 0x70) != 0
650#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
651 && (encoding & 0x70) != DW_EH_PE_pcrel
652#endif
653 )
654 /* leb128 can be handled, but does something actually need it? */
655 || (encoding & 7) == DW_EH_PE_uleb128
656 || (encoding & 7) > DW_EH_PE_udata8)
657 {
658 as_bad (_("invalid or unsupported encoding in .cfi_personality"));
659 ignore_rest_of_line ();
660 return;
661 }
662
663 if (*input_line_pointer++ != ',')
664 {
665 as_bad (_(".cfi_personality requires encoding and symbol arguments"));
666 ignore_rest_of_line ();
667 return;
668 }
669
670 expression_and_evaluate (&fde->personality);
671 switch (fde->personality.X_op)
672 {
673 case O_symbol:
674 break;
675 case O_constant:
676 if ((encoding & 0x70) == DW_EH_PE_pcrel)
677 encoding = DW_EH_PE_omit;
678 break;
679 default:
680 encoding = DW_EH_PE_omit;
681 break;
682 }
683
684 fde->per_encoding = encoding;
685
686 if (encoding == DW_EH_PE_omit)
687 {
688 as_bad (_("wrong second argument to .cfi_personality"));
689 ignore_rest_of_line ();
690 return;
691 }
692
693 demand_empty_rest_of_line ();
694}
695
696static void
697dot_cfi_lsda (int ignored ATTRIBUTE_UNUSED)
698{
699 struct fde_entry *fde;
700 offsetT encoding;
701
702 if (frchain_now->frch_cfi_data == NULL)
703 {
704 as_bad (_("CFI instruction used without previous .cfi_startproc"));
705 ignore_rest_of_line ();
706 return;
707 }
708
709 fde = frchain_now->frch_cfi_data->cur_fde_data;
710 encoding = get_absolute_expression ();
711 if (encoding == DW_EH_PE_omit)
712 {
713 demand_empty_rest_of_line ();
714 fde->lsda_encoding = encoding;
715 return;
716 }
717
718 if ((encoding & 0xff) != encoding
719 || ((encoding & 0x70) != 0
720#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
721 && (encoding & 0x70) != DW_EH_PE_pcrel
722#endif
723 )
724 /* leb128 can be handled, but does something actually need it? */
725 || (encoding & 7) == DW_EH_PE_uleb128
726 || (encoding & 7) > DW_EH_PE_udata8)
727 {
728 as_bad (_("invalid or unsupported encoding in .cfi_lsda"));
729 ignore_rest_of_line ();
730 return;
731 }
732
733 if (*input_line_pointer++ != ',')
734 {
735 as_bad (_(".cfi_lsda requires encoding and symbol arguments"));
736 ignore_rest_of_line ();
737 return;
738 }
739
740 fde->lsda_encoding = encoding;
741
742 expression_and_evaluate (&fde->lsda);
743 switch (fde->lsda.X_op)
744 {
745 case O_symbol:
746 break;
747 case O_constant:
748 if ((encoding & 0x70) == DW_EH_PE_pcrel)
749 encoding = DW_EH_PE_omit;
750 break;
751 default:
752 encoding = DW_EH_PE_omit;
753 break;
754 }
755
756 fde->lsda_encoding = encoding;
757
758 if (encoding == DW_EH_PE_omit)
759 {
760 as_bad (_("wrong second argument to .cfi_lsda"));
761 ignore_rest_of_line ();
762 return;
763 }
764
765 demand_empty_rest_of_line ();
766}
767
54cfded0 768static void
a4447b93 769dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
54cfded0 770{
a4447b93 771 int simple = 0;
39b82151 772
ae424f82 773 if (frchain_now->frch_cfi_data != NULL)
54cfded0
AM
774 {
775 as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
7c9c8381 776 ignore_rest_of_line ();
54cfded0
AM
777 return;
778 }
779
a4447b93 780 cfi_new_fde (symbol_temp_new_now ());
39b82151 781
a4447b93
RH
782 SKIP_WHITESPACE ();
783 if (is_name_beginner (*input_line_pointer))
784 {
785 char *name, c;
54cfded0 786
a4447b93
RH
787 name = input_line_pointer;
788 c = get_symbol_end ();
54cfded0 789
a4447b93
RH
790 if (strcmp (name, "simple") == 0)
791 {
792 simple = 1;
793 *input_line_pointer = c;
794 }
795 else
796 input_line_pointer = name;
797 }
798 demand_empty_rest_of_line ();
799
ae424f82 800 frchain_now->frch_cfi_data->cur_cfa_offset = 0;
a4447b93 801 if (!simple)
39b82151 802 tc_cfi_frame_initial_instructions ();
54cfded0
AM
803}
804
a4447b93
RH
805static void
806dot_cfi_endproc (int ignored ATTRIBUTE_UNUSED)
807{
ae424f82 808 if (frchain_now->frch_cfi_data == NULL)
a4447b93
RH
809 {
810 as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
7c9c8381 811 ignore_rest_of_line ();
a4447b93
RH
812 return;
813 }
54cfded0 814
a4447b93 815 cfi_end_fde (symbol_temp_new_now ());
7c9c8381
JB
816
817 demand_empty_rest_of_line ();
a4447b93 818}
39b82151 819
a4447b93
RH
820\f
821/* Emit a single byte into the current segment. */
54cfded0 822
a4447b93
RH
823static inline void
824out_one (int byte)
54cfded0 825{
a4447b93
RH
826 FRAG_APPEND_1_CHAR (byte);
827}
54cfded0 828
a4447b93 829/* Emit a two-byte word into the current segment. */
54cfded0 830
a4447b93
RH
831static inline void
832out_two (int data)
833{
834 md_number_to_chars (frag_more (2), data, 2);
835}
54cfded0 836
a4447b93 837/* Emit a four byte word into the current segment. */
54cfded0 838
a4447b93
RH
839static inline void
840out_four (int data)
841{
842 md_number_to_chars (frag_more (4), data, 4);
843}
844
845/* Emit an unsigned "little-endian base 128" number. */
54cfded0 846
a4447b93
RH
847static void
848out_uleb128 (addressT value)
849{
850 output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0);
54cfded0
AM
851}
852
a4447b93
RH
853/* Emit an unsigned "little-endian base 128" number. */
854
855static void
856out_sleb128 (offsetT value)
54cfded0 857{
a4447b93
RH
858 output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1);
859}
54cfded0 860
a4447b93
RH
861static void
862output_cfi_insn (struct cfi_insn_data *insn)
863{
864 offsetT offset;
865 unsigned int regno;
54cfded0 866
a4447b93 867 switch (insn->insn)
54cfded0 868 {
a4447b93
RH
869 case DW_CFA_advance_loc:
870 {
871 symbolS *from = insn->u.ll.lab1;
872 symbolS *to = insn->u.ll.lab2;
873
874 if (symbol_get_frag (to) == symbol_get_frag (from))
875 {
876 addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
877 addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;
878
879 if (scaled <= 0x3F)
880 out_one (DW_CFA_advance_loc + scaled);
881 else if (delta <= 0xFF)
882 {
9b8ae42e
JJ
883 out_one (DW_CFA_advance_loc1);
884 out_one (delta);
a4447b93
RH
885 }
886 else if (delta <= 0xFFFF)
887 {
9b8ae42e
JJ
888 out_one (DW_CFA_advance_loc2);
889 out_two (delta);
a4447b93
RH
890 }
891 else
892 {
9b8ae42e
JJ
893 out_one (DW_CFA_advance_loc4);
894 out_four (delta);
a4447b93
RH
895 }
896 }
897 else
898 {
899 expressionS exp;
900
901 exp.X_op = O_subtract;
902 exp.X_add_symbol = to;
903 exp.X_op_symbol = from;
904 exp.X_add_number = 0;
905
906 /* The code in ehopt.c expects that one byte of the encoding
907 is already allocated to the frag. This comes from the way
908 that it scans the .eh_frame section looking first for the
909 .byte DW_CFA_advance_loc4. */
910 frag_more (1);
911
912 frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
913 make_expr_symbol (&exp), frag_now_fix () - 1,
914 (char *) frag_now);
915 }
916 }
917 break;
918
919 case DW_CFA_def_cfa:
920 offset = insn->u.ri.offset;
921 if (offset < 0)
54cfded0 922 {
a4447b93
RH
923 out_one (DW_CFA_def_cfa_sf);
924 out_uleb128 (insn->u.ri.reg);
dcb45a06 925 out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
54cfded0
AM
926 }
927 else
928 {
a4447b93
RH
929 out_one (DW_CFA_def_cfa);
930 out_uleb128 (insn->u.ri.reg);
931 out_uleb128 (offset);
54cfded0
AM
932 }
933 break;
934
a4447b93 935 case DW_CFA_def_cfa_register:
2be24b54
ML
936 case DW_CFA_undefined:
937 case DW_CFA_same_value:
938 out_one (insn->insn);
939 out_uleb128 (insn->u.r);
54cfded0
AM
940 break;
941
a4447b93
RH
942 case DW_CFA_def_cfa_offset:
943 offset = insn->u.i;
944 if (offset < 0)
945 {
946 out_one (DW_CFA_def_cfa_offset_sf);
dcb45a06 947 out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
a4447b93
RH
948 }
949 else
950 {
951 out_one (DW_CFA_def_cfa_offset);
952 out_uleb128 (offset);
953 }
54cfded0
AM
954 break;
955
2be24b54
ML
956 case DW_CFA_restore:
957 regno = insn->u.r;
958 if (regno <= 0x3F)
959 {
960 out_one (DW_CFA_restore + regno);
961 }
962 else
963 {
964 out_one (DW_CFA_restore_extended);
965 out_uleb128 (regno);
966 }
967 break;
968
a4447b93
RH
969 case DW_CFA_offset:
970 regno = insn->u.ri.reg;
971 offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
972 if (offset < 0)
973 {
1233ae62 974 out_one (DW_CFA_offset_extended_sf);
a4447b93
RH
975 out_uleb128 (regno);
976 out_sleb128 (offset);
977 }
978 else if (regno <= 0x3F)
979 {
980 out_one (DW_CFA_offset + regno);
981 out_uleb128 (offset);
982 }
54cfded0
AM
983 else
984 {
a4447b93
RH
985 out_one (DW_CFA_offset_extended);
986 out_uleb128 (regno);
987 out_uleb128 (offset);
54cfded0 988 }
54cfded0
AM
989 break;
990
a4447b93
RH
991 case DW_CFA_register:
992 out_one (DW_CFA_register);
993 out_uleb128 (insn->u.rr.reg1);
994 out_uleb128 (insn->u.rr.reg2);
39b82151
ML
995 break;
996
2be24b54
ML
997 case DW_CFA_remember_state:
998 case DW_CFA_restore_state:
2be24b54 999 out_one (insn->insn);
54cfded0
AM
1000 break;
1001
364b6d8b
JJ
1002 case DW_CFA_GNU_window_save:
1003 out_one (DW_CFA_GNU_window_save);
1004 break;
1005
cdfbf930
RH
1006 case CFI_escape:
1007 {
1008 struct cfi_escape_data *e;
1009 for (e = insn->u.esc; e ; e = e->next)
1010 emit_expr (&e->exp, 1);
1011 break;
1012 }
1013
54cfded0 1014 default:
a4447b93 1015 abort ();
54cfded0 1016 }
54cfded0
AM
1017}
1018
9b8ae42e
JJ
1019static offsetT
1020encoding_size (unsigned char encoding)
1021{
1022 if (encoding == DW_EH_PE_omit)
1023 return 0;
1024 switch (encoding & 0x7)
1025 {
1026 case 0:
1027 return bfd_get_arch_size (stdoutput) == 64 ? 8 : 4;
1028 case DW_EH_PE_udata2:
1029 return 2;
1030 case DW_EH_PE_udata4:
1031 return 4;
1032 case DW_EH_PE_udata8:
1033 return 8;
1034 default:
1035 abort ();
1036 }
1037}
1038
54cfded0 1039static void
a4447b93 1040output_cie (struct cie_entry *cie)
54cfded0 1041{
a4447b93 1042 symbolS *after_size_address, *end_address;
7c0295b1 1043 expressionS exp;
a4447b93 1044 struct cfi_insn_data *i;
9b8ae42e 1045 offsetT augmentation_size;
a4447b93
RH
1046
1047 cie->start_address = symbol_temp_new_now ();
1048 after_size_address = symbol_temp_make ();
1049 end_address = symbol_temp_make ();
1050
1051 exp.X_op = O_subtract;
1052 exp.X_add_symbol = end_address;
1053 exp.X_op_symbol = after_size_address;
1054 exp.X_add_number = 0;
1055
289040ca 1056 emit_expr (&exp, 4); /* Length. */
a4447b93 1057 symbol_set_value_now (after_size_address);
289040ca
NC
1058 out_four (0); /* CIE id. */
1059 out_one (DW_CIE_VERSION); /* Version. */
1060 out_one ('z'); /* Augmentation. */
9b8ae42e
JJ
1061 if (cie->per_encoding != DW_EH_PE_omit)
1062 out_one ('P');
1063 if (cie->lsda_encoding != DW_EH_PE_omit)
1064 out_one ('L');
a4447b93 1065 out_one ('R');
63752a75
JJ
1066 if (cie->signal_frame)
1067 out_one ('S');
a4447b93 1068 out_one (0);
289040ca
NC
1069 out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH); /* Code alignment. */
1070 out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment. */
0da76f83
NC
1071 if (DW_CIE_VERSION == 1) /* Return column. */
1072 out_one (cie->return_column);
1073 else
1074 out_uleb128 (cie->return_column);
9b8ae42e
JJ
1075 augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
1076 if (cie->per_encoding != DW_EH_PE_omit)
1077 augmentation_size += 1 + encoding_size (cie->per_encoding);
1078 out_uleb128 (augmentation_size); /* Augmentation size. */
1079 if (cie->per_encoding != DW_EH_PE_omit)
1080 {
1081 offsetT size = encoding_size (cie->per_encoding);
1082 out_one (cie->per_encoding);
1083 exp = cie->personality;
1084 if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
1085 {
1086#ifdef DIFF_EXPR_OK
1087 exp.X_op = O_subtract;
1088 exp.X_op_symbol = symbol_temp_new_now ();
1089 emit_expr (&exp, size);
1090#elif defined (tc_cfi_emit_pcrel_expr)
1091 tc_cfi_emit_pcrel_expr (&exp, size);
1092#else
1093 abort ();
1094#endif
1095 }
1096 else
1097 emit_expr (&exp, size);
1098 }
1099 if (cie->lsda_encoding != DW_EH_PE_omit)
1100 out_one (cie->lsda_encoding);
364b6d8b 1101#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
a4447b93 1102 out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
364b6d8b
JJ
1103#else
1104 out_one (DW_EH_PE_sdata4);
1105#endif
a4447b93
RH
1106
1107 if (cie->first)
1108 for (i = cie->first; i != cie->last; i = i->next)
1109 output_cfi_insn (i);
1110
4df6ce47 1111 frag_align (2, DW_CFA_nop, 0);
a4447b93
RH
1112 symbol_set_value_now (end_address);
1113}
54cfded0 1114
a4447b93
RH
1115static void
1116output_fde (struct fde_entry *fde, struct cie_entry *cie,
9393cb0d 1117 struct cfi_insn_data *first, int align)
a4447b93
RH
1118{
1119 symbolS *after_size_address, *end_address;
1120 expressionS exp;
9b8ae42e 1121 offsetT augmentation_size;
54cfded0 1122
a4447b93
RH
1123 after_size_address = symbol_temp_make ();
1124 end_address = symbol_temp_make ();
54cfded0 1125
a4447b93
RH
1126 exp.X_op = O_subtract;
1127 exp.X_add_symbol = end_address;
1128 exp.X_op_symbol = after_size_address;
1129 exp.X_add_number = 0;
289040ca 1130 emit_expr (&exp, 4); /* Length. */
a4447b93 1131 symbol_set_value_now (after_size_address);
54cfded0 1132
a4447b93
RH
1133 exp.X_add_symbol = after_size_address;
1134 exp.X_op_symbol = cie->start_address;
289040ca 1135 emit_expr (&exp, 4); /* CIE offset. */
364b6d8b 1136
9b8ae42e 1137#ifdef DIFF_EXPR_OK
a4447b93
RH
1138 exp.X_add_symbol = fde->start_address;
1139 exp.X_op_symbol = symbol_temp_new_now ();
289040ca 1140 emit_expr (&exp, 4); /* Code offset. */
364b6d8b
JJ
1141#else
1142 exp.X_op = O_symbol;
1143 exp.X_add_symbol = fde->start_address;
1144 exp.X_op_symbol = NULL;
1145#ifdef tc_cfi_emit_pcrel_expr
289040ca 1146 tc_cfi_emit_pcrel_expr (&exp, 4); /* Code offset. */
364b6d8b 1147#else
289040ca 1148 emit_expr (&exp, 4); /* Code offset. */
364b6d8b
JJ
1149#endif
1150 exp.X_op = O_subtract;
1151#endif
54cfded0 1152
a4447b93 1153 exp.X_add_symbol = fde->end_address;
289040ca 1154 exp.X_op_symbol = fde->start_address; /* Code length. */
a4447b93 1155 emit_expr (&exp, 4);
54cfded0 1156
9b8ae42e
JJ
1157 augmentation_size = encoding_size (fde->lsda_encoding);
1158 out_uleb128 (augmentation_size); /* Augmentation size. */
1159
1160 if (fde->lsda_encoding != DW_EH_PE_omit)
1161 {
1162 exp = fde->lsda;
1163 if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
1164 {
1165#ifdef DIFF_EXPR_OK
1166 exp.X_op = O_subtract;
1167 exp.X_op_symbol = symbol_temp_new_now ();
1168 emit_expr (&exp, augmentation_size);
1169#elif defined (tc_cfi_emit_pcrel_expr)
1170 tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
1171#else
1172 abort ();
1173#endif
1174 }
1175 else
1176 emit_expr (&exp, augmentation_size);
1177 }
39b82151 1178
a4447b93
RH
1179 for (; first; first = first->next)
1180 output_cfi_insn (first);
39b82151 1181
4df6ce47 1182 frag_align (align, DW_CFA_nop, 0);
a4447b93
RH
1183 symbol_set_value_now (end_address);
1184}
1185
1186static struct cie_entry *
1187select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
1188{
1189 struct cfi_insn_data *i, *j;
1190 struct cie_entry *cie;
1191
1192 for (cie = cie_root; cie; cie = cie->next)
39b82151 1193 {
63752a75 1194 if (cie->return_column != fde->return_column
9b8ae42e
JJ
1195 || cie->signal_frame != fde->signal_frame
1196 || cie->per_encoding != fde->per_encoding
1197 || cie->lsda_encoding != fde->lsda_encoding)
a4447b93 1198 continue;
9b8ae42e
JJ
1199 if (cie->per_encoding != DW_EH_PE_omit)
1200 {
1201 if (cie->personality.X_op != fde->personality.X_op
1202 || cie->personality.X_add_number
1203 != fde->personality.X_add_number)
1204 continue;
1205 switch (cie->personality.X_op)
1206 {
1207 case O_constant:
1208 if (cie->personality.X_unsigned != fde->personality.X_unsigned)
1209 continue;
1210 break;
1211 case O_symbol:
1212 if (cie->personality.X_add_symbol
1213 != fde->personality.X_add_symbol)
1214 continue;
1215 break;
1216 default:
1217 abort ();
1218 }
1219 }
a4447b93
RH
1220 for (i = cie->first, j = fde->data;
1221 i != cie->last && j != NULL;
1222 i = i->next, j = j->next)
39b82151 1223 {
a4447b93
RH
1224 if (i->insn != j->insn)
1225 goto fail;
1226 switch (i->insn)
1227 {
1228 case DW_CFA_advance_loc:
289040ca
NC
1229 case DW_CFA_remember_state:
1230 /* We reached the first advance/remember in the FDE,
1231 but did not reach the end of the CIE list. */
a4447b93
RH
1232 goto fail;
1233
1234 case DW_CFA_offset:
1235 case DW_CFA_def_cfa:
1236 if (i->u.ri.reg != j->u.ri.reg)
1237 goto fail;
1238 if (i->u.ri.offset != j->u.ri.offset)
1239 goto fail;
1240 break;
1241
1242 case DW_CFA_register:
1243 if (i->u.rr.reg1 != j->u.rr.reg1)
1244 goto fail;
1245 if (i->u.rr.reg2 != j->u.rr.reg2)
1246 goto fail;
1247 break;
1248
1249 case DW_CFA_def_cfa_register:
2be24b54
ML
1250 case DW_CFA_restore:
1251 case DW_CFA_undefined:
1252 case DW_CFA_same_value:
a4447b93
RH
1253 if (i->u.r != j->u.r)
1254 goto fail;
1255 break;
1256
1257 case DW_CFA_def_cfa_offset:
1258 if (i->u.i != j->u.i)
1259 goto fail;
1260 break;
1261
cdfbf930
RH
1262 case CFI_escape:
1263 /* Don't bother matching these for now. */
1264 goto fail;
1265
a4447b93
RH
1266 default:
1267 abort ();
1268 }
39b82151 1269 }
a4447b93
RH
1270
1271 /* Success if we reached the end of the CIE list, and we've either
289040ca
NC
1272 run out of FDE entries or we've encountered an advance,
1273 remember, or escape. */
e9fad691
AM
1274 if (i == cie->last
1275 && (!j
1276 || j->insn == DW_CFA_advance_loc
289040ca 1277 || j->insn == DW_CFA_remember_state
e9fad691 1278 || j->insn == CFI_escape))
39b82151 1279 {
a4447b93
RH
1280 *pfirst = j;
1281 return cie;
39b82151
ML
1282 }
1283
a4447b93 1284 fail:;
54cfded0
AM
1285 }
1286
a4447b93
RH
1287 cie = xmalloc (sizeof (struct cie_entry));
1288 cie->next = cie_root;
1289 cie_root = cie;
1290 cie->return_column = fde->return_column;
63752a75 1291 cie->signal_frame = fde->signal_frame;
9b8ae42e
JJ
1292 cie->per_encoding = fde->per_encoding;
1293 cie->lsda_encoding = fde->lsda_encoding;
1294 cie->personality = fde->personality;
a4447b93 1295 cie->first = fde->data;
54cfded0 1296
a4447b93 1297 for (i = cie->first; i ; i = i->next)
e9fad691 1298 if (i->insn == DW_CFA_advance_loc
289040ca 1299 || i->insn == DW_CFA_remember_state
e9fad691 1300 || i->insn == CFI_escape)
a4447b93 1301 break;
54cfded0 1302
a4447b93
RH
1303 cie->last = i;
1304 *pfirst = i;
1305
1306 output_cie (cie);
54cfded0 1307
a4447b93 1308 return cie;
54cfded0
AM
1309}
1310
1311void
a4447b93 1312cfi_finish (void)
54cfded0 1313{
a4447b93
RH
1314 segT cfi_seg;
1315 struct fde_entry *fde;
eafbc43f 1316 int save_flag_traditional_format;
54cfded0 1317
a4447b93
RH
1318 if (all_fde_data == 0)
1319 return;
54cfded0 1320
a4447b93
RH
1321 /* Open .eh_frame section. */
1322 cfi_seg = subseg_new (".eh_frame", 0);
a4447b93 1323 bfd_set_section_flags (stdoutput, cfi_seg,
757bc393 1324 SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY);
a4447b93 1325 subseg_set (cfi_seg, 0);
9393cb0d 1326 record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
54cfded0 1327
eafbc43f
RH
1328 /* Make sure check_eh_frame doesn't do anything with our output. */
1329 save_flag_traditional_format = flag_traditional_format;
1330 flag_traditional_format = 1;
1331
a4447b93
RH
1332 for (fde = all_fde_data; fde ; fde = fde->next)
1333 {
1334 struct cfi_insn_data *first;
1335 struct cie_entry *cie;
1336
ae424f82
JJ
1337 if (fde->end_address == NULL)
1338 {
1339 as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
1340 fde->end_address = fde->start_address;
1341 }
1342
a4447b93 1343 cie = select_cie_for_fde (fde, &first);
6ec51dba 1344 output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
a4447b93 1345 }
eafbc43f
RH
1346
1347 flag_traditional_format = save_flag_traditional_format;
54cfded0 1348}
This page took 0.235962 seconds and 4 git commands to generate.