OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [gas/] [dw2gencfi.c] - Blame information for rev 862

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.