Back to index

cell-binutils  2.17cvs20070401
dw2gencfi.c
Go to the documentation of this file.
00001 /* dw2gencfi.c - Support for generating Dwarf2 CFI information.
00002    Copyright 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
00003    Contributed by Michal Ludvig <mludvig@suse.cz>
00004 
00005    This file is part of GAS, the GNU Assembler.
00006 
00007    GAS is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    GAS is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with GAS; see the file COPYING.  If not, write to the Free
00019    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00020    02110-1301, USA.  */
00021 
00022 #include "as.h"
00023 #include "dw2gencfi.h"
00024 #include "subsegs.h"
00025 
00026 
00027 /* We re-use DWARF2_LINE_MIN_INSN_LENGTH for the code alignment field
00028    of the CIE.  Default to 1 if not otherwise specified.  */
00029 #ifndef  DWARF2_LINE_MIN_INSN_LENGTH
00030 # define DWARF2_LINE_MIN_INSN_LENGTH 1
00031 #endif
00032 
00033 /* If TARGET_USE_CFIPOP is defined, it is required that the target
00034    provide the following definitions.  Otherwise provide them to 
00035    allow compilation to continue.  */
00036 #ifndef TARGET_USE_CFIPOP
00037 # ifndef  DWARF2_DEFAULT_RETURN_COLUMN
00038 #  define DWARF2_DEFAULT_RETURN_COLUMN 0
00039 # endif
00040 # ifndef  DWARF2_CIE_DATA_ALIGNMENT
00041 #  define DWARF2_CIE_DATA_ALIGNMENT 1
00042 # endif
00043 #endif
00044 
00045 #ifndef EH_FRAME_ALIGNMENT
00046 # define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
00047 #endif
00048 
00049 #ifndef tc_cfi_frame_initial_instructions
00050 # define tc_cfi_frame_initial_instructions() ((void)0)
00051 #endif
00052 
00053 
00054 struct cfi_insn_data
00055 {
00056   struct cfi_insn_data *next;
00057   int insn;
00058   union {
00059     struct {
00060       unsigned reg;
00061       offsetT offset;
00062     } ri;
00063 
00064     struct {
00065       unsigned reg1;
00066       unsigned reg2;
00067     } rr;
00068 
00069     unsigned r;
00070     offsetT i;
00071 
00072     struct {
00073       symbolS *lab1;
00074       symbolS *lab2;
00075     } ll;
00076 
00077     struct cfi_escape_data {
00078       struct cfi_escape_data *next;
00079       expressionS exp;
00080     } *esc;
00081   } u;
00082 };
00083 
00084 struct fde_entry
00085 {
00086   struct fde_entry *next;
00087   symbolS *start_address;
00088   symbolS *end_address;
00089   struct cfi_insn_data *data;
00090   struct cfi_insn_data **last;
00091   unsigned char per_encoding;
00092   unsigned char lsda_encoding;
00093   expressionS personality;
00094   expressionS lsda;
00095   unsigned int return_column;
00096   unsigned int signal_frame;
00097 };
00098 
00099 struct cie_entry
00100 {
00101   struct cie_entry *next;
00102   symbolS *start_address;
00103   unsigned int return_column;
00104   unsigned int signal_frame;
00105   unsigned char per_encoding;
00106   unsigned char lsda_encoding;
00107   expressionS personality;
00108   struct cfi_insn_data *first, *last;
00109 };
00110 
00111 
00112 /* List of FDE entries.  */
00113 static struct fde_entry *all_fde_data;
00114 static struct fde_entry **last_fde_data = &all_fde_data;
00115 
00116 /* List of CIEs so that they could be reused.  */
00117 static struct cie_entry *cie_root;
00118 
00119 /* Stack of old CFI data, for save/restore.  */
00120 struct cfa_save_data
00121 {
00122   struct cfa_save_data *next;
00123   offsetT cfa_offset;
00124 };
00125 
00126 /* Current open FDE entry.  */
00127 struct frch_cfi_data
00128 {
00129   struct fde_entry *cur_fde_data;
00130   symbolS *last_address;
00131   offsetT cur_cfa_offset;
00132   struct cfa_save_data *cfa_save_stack;
00133 };
00134 
00135 /* Construct a new FDE structure and add it to the end of the fde list.  */
00136 
00137 static struct fde_entry *
00138 alloc_fde_entry (void)
00139 {
00140   struct fde_entry *fde = xcalloc (1, sizeof (struct fde_entry));
00141 
00142   frchain_now->frch_cfi_data = xcalloc (1, sizeof (struct frch_cfi_data));
00143   frchain_now->frch_cfi_data->cur_fde_data = fde;
00144   *last_fde_data = fde;
00145   last_fde_data = &fde->next;
00146 
00147   fde->last = &fde->data;
00148   fde->return_column = DWARF2_DEFAULT_RETURN_COLUMN;
00149   fde->per_encoding = DW_EH_PE_omit;
00150   fde->lsda_encoding = DW_EH_PE_omit;
00151 
00152   return fde;
00153 }
00154 
00155 /* The following functions are available for a backend to construct its
00156    own unwind information, usually from legacy unwind directives.  */
00157 
00158 /* Construct a new INSN structure and add it to the end of the insn list
00159    for the currently active FDE.  */
00160 
00161 static struct cfi_insn_data *
00162 alloc_cfi_insn_data (void)
00163 {
00164   struct cfi_insn_data *insn = xcalloc (1, sizeof (struct cfi_insn_data));
00165   struct fde_entry *cur_fde_data = frchain_now->frch_cfi_data->cur_fde_data;
00166 
00167   *cur_fde_data->last = insn;
00168   cur_fde_data->last = &insn->next;
00169 
00170   return insn;
00171 }
00172 
00173 /* Construct a new FDE structure that begins at LABEL.  */
00174 
00175 void 
00176 cfi_new_fde (symbolS *label)
00177 {
00178   struct fde_entry *fde = alloc_fde_entry ();
00179   fde->start_address = label;
00180   frchain_now->frch_cfi_data->last_address = label;
00181 }
00182 
00183 /* End the currently open FDE.  */
00184 
00185 void 
00186 cfi_end_fde (symbolS *label)
00187 {
00188   frchain_now->frch_cfi_data->cur_fde_data->end_address = label;
00189   free (frchain_now->frch_cfi_data);
00190   frchain_now->frch_cfi_data = NULL;
00191 }
00192 
00193 /* Set the return column for the current FDE.  */
00194 
00195 void
00196 cfi_set_return_column (unsigned regno)
00197 {
00198   frchain_now->frch_cfi_data->cur_fde_data->return_column = regno;
00199 }
00200 
00201 /* Universal functions to store new instructions.  */
00202 
00203 static void
00204 cfi_add_CFA_insn(int insn)
00205 {
00206   struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
00207 
00208   insn_ptr->insn = insn;
00209 }
00210 
00211 static void
00212 cfi_add_CFA_insn_reg (int insn, unsigned regno)
00213 {
00214   struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
00215 
00216   insn_ptr->insn = insn;
00217   insn_ptr->u.r = regno;
00218 }
00219 
00220 static void
00221 cfi_add_CFA_insn_offset (int insn, offsetT offset)
00222 {
00223   struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
00224 
00225   insn_ptr->insn = insn;
00226   insn_ptr->u.i = offset;
00227 }
00228 
00229 static void
00230 cfi_add_CFA_insn_reg_reg (int insn, unsigned reg1, unsigned reg2)
00231 {
00232   struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
00233 
00234   insn_ptr->insn = insn;
00235   insn_ptr->u.rr.reg1 = reg1;
00236   insn_ptr->u.rr.reg2 = reg2;
00237 }
00238 
00239 static void
00240 cfi_add_CFA_insn_reg_offset (int insn, unsigned regno, offsetT offset)
00241 {
00242   struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
00243 
00244   insn_ptr->insn = insn;
00245   insn_ptr->u.ri.reg = regno;
00246   insn_ptr->u.ri.offset = offset;
00247 }
00248 
00249 /* Add a CFI insn to advance the PC from the last address to LABEL.  */
00250 
00251 void
00252 cfi_add_advance_loc (symbolS *label)
00253 {
00254   struct cfi_insn_data *insn = alloc_cfi_insn_data ();
00255 
00256   insn->insn = DW_CFA_advance_loc;
00257   insn->u.ll.lab1 = frchain_now->frch_cfi_data->last_address;
00258   insn->u.ll.lab2 = label;
00259 
00260   frchain_now->frch_cfi_data->last_address = label;
00261 }
00262 
00263 /* Add a DW_CFA_offset record to the CFI data.  */
00264 
00265 void
00266 cfi_add_CFA_offset (unsigned regno, offsetT offset)
00267 {
00268   unsigned int abs_data_align;
00269 
00270   assert (DWARF2_CIE_DATA_ALIGNMENT != 0);
00271   cfi_add_CFA_insn_reg_offset (DW_CFA_offset, regno, offset);
00272 
00273   abs_data_align = (DWARF2_CIE_DATA_ALIGNMENT < 0
00274                   ? -DWARF2_CIE_DATA_ALIGNMENT : DWARF2_CIE_DATA_ALIGNMENT);
00275   if (offset % abs_data_align)
00276     as_bad (_("register save offset not a multiple of %u"), abs_data_align);
00277 }
00278 
00279 /* Add a DW_CFA_def_cfa record to the CFI data.  */
00280 
00281 void
00282 cfi_add_CFA_def_cfa (unsigned regno, offsetT offset)
00283 {
00284   cfi_add_CFA_insn_reg_offset (DW_CFA_def_cfa, regno, offset);
00285   frchain_now->frch_cfi_data->cur_cfa_offset = offset;
00286 }
00287 
00288 /* Add a DW_CFA_register record to the CFI data.  */
00289 
00290 void
00291 cfi_add_CFA_register (unsigned reg1, unsigned reg2)
00292 {
00293   cfi_add_CFA_insn_reg_reg (DW_CFA_register, reg1, reg2);
00294 }
00295 
00296 /* Add a DW_CFA_def_cfa_register record to the CFI data.  */
00297 
00298 void
00299 cfi_add_CFA_def_cfa_register (unsigned regno)
00300 {
00301   cfi_add_CFA_insn_reg (DW_CFA_def_cfa_register, regno);
00302 }
00303 
00304 /* Add a DW_CFA_def_cfa_offset record to the CFI data.  */
00305 
00306 void
00307 cfi_add_CFA_def_cfa_offset (offsetT offset)
00308 {
00309   cfi_add_CFA_insn_offset (DW_CFA_def_cfa_offset, offset);
00310   frchain_now->frch_cfi_data->cur_cfa_offset = offset;
00311 }
00312 
00313 void
00314 cfi_add_CFA_restore (unsigned regno)
00315 {
00316   cfi_add_CFA_insn_reg (DW_CFA_restore, regno);
00317 }
00318 
00319 void
00320 cfi_add_CFA_undefined (unsigned regno)
00321 {
00322   cfi_add_CFA_insn_reg (DW_CFA_undefined, regno);
00323 }
00324 
00325 void
00326 cfi_add_CFA_same_value (unsigned regno)
00327 {
00328   cfi_add_CFA_insn_reg (DW_CFA_same_value, regno);
00329 }
00330 
00331 void
00332 cfi_add_CFA_remember_state (void)
00333 {
00334   struct cfa_save_data *p;
00335 
00336   cfi_add_CFA_insn (DW_CFA_remember_state);
00337 
00338   p = xmalloc (sizeof (*p));
00339   p->cfa_offset = frchain_now->frch_cfi_data->cur_cfa_offset;
00340   p->next = frchain_now->frch_cfi_data->cfa_save_stack;
00341   frchain_now->frch_cfi_data->cfa_save_stack = p;
00342 }
00343 
00344 void
00345 cfi_add_CFA_restore_state (void)
00346 {
00347   struct cfa_save_data *p;
00348 
00349   cfi_add_CFA_insn (DW_CFA_restore_state);
00350 
00351   p = frchain_now->frch_cfi_data->cfa_save_stack;
00352   if (p)
00353     {
00354       frchain_now->frch_cfi_data->cur_cfa_offset = p->cfa_offset;
00355       frchain_now->frch_cfi_data->cfa_save_stack = p->next;
00356       free (p);
00357     }
00358   else
00359     as_bad (_("CFI state restore without previous remember"));
00360 }
00361 
00362 
00363 /* Parse CFI assembler directives.  */
00364 
00365 static void dot_cfi (int);
00366 static void dot_cfi_escape (int);
00367 static void dot_cfi_startproc (int);
00368 static void dot_cfi_endproc (int);
00369 static void dot_cfi_personality (int);
00370 static void dot_cfi_lsda (int);
00371 
00372 /* Fake CFI type; outside the byte range of any real CFI insn.  */
00373 #define CFI_adjust_cfa_offset      0x100
00374 #define CFI_return_column   0x101
00375 #define CFI_rel_offset             0x102
00376 #define CFI_escape          0x103
00377 #define CFI_signal_frame    0x104
00378 
00379 const pseudo_typeS cfi_pseudo_table[] =
00380   {
00381     { "cfi_startproc", dot_cfi_startproc, 0 },
00382     { "cfi_endproc", dot_cfi_endproc, 0 },
00383     { "cfi_def_cfa", dot_cfi, DW_CFA_def_cfa },
00384     { "cfi_def_cfa_register", dot_cfi, DW_CFA_def_cfa_register },
00385     { "cfi_def_cfa_offset", dot_cfi, DW_CFA_def_cfa_offset },
00386     { "cfi_adjust_cfa_offset", dot_cfi, CFI_adjust_cfa_offset },
00387     { "cfi_offset", dot_cfi, DW_CFA_offset },
00388     { "cfi_rel_offset", dot_cfi, CFI_rel_offset },
00389     { "cfi_register", dot_cfi, DW_CFA_register },
00390     { "cfi_return_column", dot_cfi, CFI_return_column },
00391     { "cfi_restore", dot_cfi, DW_CFA_restore },
00392     { "cfi_undefined", dot_cfi, DW_CFA_undefined },
00393     { "cfi_same_value", dot_cfi, DW_CFA_same_value },
00394     { "cfi_remember_state", dot_cfi, DW_CFA_remember_state },
00395     { "cfi_restore_state", dot_cfi, DW_CFA_restore_state },
00396     { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
00397     { "cfi_escape", dot_cfi_escape, 0 },
00398     { "cfi_signal_frame", dot_cfi, CFI_signal_frame },
00399     { "cfi_personality", dot_cfi_personality, 0 },
00400     { "cfi_lsda", dot_cfi_lsda, 0 },
00401     { NULL, NULL, 0 }
00402   };
00403 
00404 static void
00405 cfi_parse_separator (void)
00406 {
00407   SKIP_WHITESPACE ();
00408   if (*input_line_pointer == ',')
00409     input_line_pointer++;
00410   else
00411     as_bad (_("missing separator"));
00412 }
00413 
00414 static unsigned
00415 cfi_parse_reg (void)
00416 {
00417   int regno;
00418   expressionS exp;
00419 
00420 #ifdef tc_regname_to_dw2regnum
00421   SKIP_WHITESPACE ();
00422   if (is_name_beginner (*input_line_pointer)
00423       || (*input_line_pointer == '%'
00424          && is_name_beginner (*++input_line_pointer)))
00425     {
00426       char *name, c;
00427 
00428       name = input_line_pointer;
00429       c = get_symbol_end ();
00430 
00431       if ((regno = tc_regname_to_dw2regnum (name)) < 0)
00432        {
00433          as_bad (_("bad register expression"));
00434          regno = 0;
00435        }
00436 
00437       *input_line_pointer = c;
00438       return regno;
00439     }
00440 #endif
00441 
00442   expression_and_evaluate (&exp);
00443   switch (exp.X_op)
00444     {
00445     case O_register:
00446     case O_constant:
00447       regno = exp.X_add_number;
00448       break;
00449 
00450     default:
00451       as_bad (_("bad register expression"));
00452       regno = 0;
00453       break;
00454     }
00455 
00456   return regno;
00457 }
00458 
00459 static offsetT
00460 cfi_parse_const (void)
00461 {
00462   return get_absolute_expression ();
00463 }
00464 
00465 static void
00466 dot_cfi (int arg)
00467 {
00468   offsetT offset;
00469   unsigned reg1, reg2;
00470 
00471   if (frchain_now->frch_cfi_data == NULL)
00472     {
00473       as_bad (_("CFI instruction used without previous .cfi_startproc"));
00474       ignore_rest_of_line ();
00475       return;
00476     }
00477 
00478   /* If the last address was not at the current PC, advance to current.  */
00479   if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
00480       || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
00481         != frag_now_fix ())
00482     cfi_add_advance_loc (symbol_temp_new_now ());
00483 
00484   switch (arg)
00485     {
00486     case DW_CFA_offset:
00487       reg1 = cfi_parse_reg ();
00488       cfi_parse_separator ();
00489       offset = cfi_parse_const ();
00490       cfi_add_CFA_offset (reg1, offset);
00491       break;
00492 
00493     case CFI_rel_offset:
00494       reg1 = cfi_parse_reg ();
00495       cfi_parse_separator ();
00496       offset = cfi_parse_const ();
00497       cfi_add_CFA_offset (reg1,
00498                        offset - frchain_now->frch_cfi_data->cur_cfa_offset);
00499       break;
00500 
00501     case DW_CFA_def_cfa:
00502       reg1 = cfi_parse_reg ();
00503       cfi_parse_separator ();
00504       offset = cfi_parse_const ();
00505       cfi_add_CFA_def_cfa (reg1, offset);
00506       break;
00507 
00508     case DW_CFA_register:
00509       reg1 = cfi_parse_reg ();
00510       cfi_parse_separator ();
00511       reg2 = cfi_parse_reg ();
00512       cfi_add_CFA_register (reg1, reg2);
00513       break;
00514 
00515     case DW_CFA_def_cfa_register:
00516       reg1 = cfi_parse_reg ();
00517       cfi_add_CFA_def_cfa_register (reg1);
00518       break;
00519 
00520     case DW_CFA_def_cfa_offset:
00521       offset = cfi_parse_const ();
00522       cfi_add_CFA_def_cfa_offset (offset);
00523       break;
00524 
00525     case CFI_adjust_cfa_offset:
00526       offset = cfi_parse_const ();
00527       cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset
00528                               + offset);
00529       break;
00530 
00531     case DW_CFA_restore:
00532       for (;;)
00533        {
00534          reg1 = cfi_parse_reg ();
00535          cfi_add_CFA_restore (reg1);
00536          SKIP_WHITESPACE ();
00537          if (*input_line_pointer != ',')
00538            break;
00539          ++input_line_pointer;
00540        }
00541       break;
00542 
00543     case DW_CFA_undefined:
00544       for (;;)
00545        {
00546          reg1 = cfi_parse_reg ();
00547          cfi_add_CFA_undefined (reg1);
00548          SKIP_WHITESPACE ();
00549          if (*input_line_pointer != ',')
00550            break;
00551          ++input_line_pointer;
00552        }
00553       break;
00554 
00555     case DW_CFA_same_value:
00556       reg1 = cfi_parse_reg ();
00557       cfi_add_CFA_same_value (reg1);
00558       break;
00559 
00560     case CFI_return_column:
00561       reg1 = cfi_parse_reg ();
00562       cfi_set_return_column (reg1);
00563       break;
00564 
00565     case DW_CFA_remember_state:
00566       cfi_add_CFA_remember_state ();
00567       break;
00568 
00569     case DW_CFA_restore_state:
00570       cfi_add_CFA_restore_state ();
00571       break;
00572 
00573     case DW_CFA_GNU_window_save:
00574       cfi_add_CFA_insn (DW_CFA_GNU_window_save);
00575       break;
00576 
00577     case CFI_signal_frame:
00578       frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
00579       break;
00580 
00581     default:
00582       abort ();
00583     }
00584 
00585   demand_empty_rest_of_line ();
00586 }
00587 
00588 static void
00589 dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
00590 {
00591   struct cfi_escape_data *head, **tail, *e;
00592   struct cfi_insn_data *insn;
00593 
00594   if (frchain_now->frch_cfi_data == NULL)
00595     {
00596       as_bad (_("CFI instruction used without previous .cfi_startproc"));
00597       ignore_rest_of_line ();
00598       return;
00599     }
00600 
00601   /* If the last address was not at the current PC, advance to current.  */
00602   if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
00603       || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
00604         != frag_now_fix ())
00605     cfi_add_advance_loc (symbol_temp_new_now ());
00606 
00607   tail = &head;
00608   do
00609     {
00610       e = xmalloc (sizeof (*e));
00611       do_parse_cons_expression (&e->exp, 1);
00612       *tail = e;
00613       tail = &e->next;
00614     }
00615   while (*input_line_pointer++ == ',');
00616   *tail = NULL;
00617 
00618   insn = alloc_cfi_insn_data ();
00619   insn->insn = CFI_escape;
00620   insn->u.esc = head;
00621 
00622   --input_line_pointer;
00623   demand_empty_rest_of_line ();
00624 }
00625 
00626 static void
00627 dot_cfi_personality (int ignored ATTRIBUTE_UNUSED)
00628 {
00629   struct fde_entry *fde;
00630   offsetT encoding;
00631 
00632   if (frchain_now->frch_cfi_data == NULL)
00633     {
00634       as_bad (_("CFI instruction used without previous .cfi_startproc"));
00635       ignore_rest_of_line ();
00636       return;
00637     }
00638 
00639   fde = frchain_now->frch_cfi_data->cur_fde_data;
00640   encoding = get_absolute_expression ();
00641   if (encoding == DW_EH_PE_omit)
00642     {
00643       demand_empty_rest_of_line ();
00644       fde->per_encoding = encoding;
00645       return;
00646     }
00647 
00648   if ((encoding & 0xff) != encoding
00649       || ((encoding & 0x70) != 0
00650 #if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
00651          && (encoding & 0x70) != DW_EH_PE_pcrel
00652 #endif
00653          )
00654         /* leb128 can be handled, but does something actually need it?  */
00655       || (encoding & 7) == DW_EH_PE_uleb128
00656       || (encoding & 7) > DW_EH_PE_udata8)
00657     {
00658       as_bad (_("invalid or unsupported encoding in .cfi_personality"));
00659       ignore_rest_of_line ();
00660       return;
00661     }
00662 
00663   if (*input_line_pointer++ != ',')
00664     {
00665       as_bad (_(".cfi_personality requires encoding and symbol arguments"));
00666       ignore_rest_of_line ();
00667       return;
00668     }
00669 
00670   expression_and_evaluate (&fde->personality);
00671   switch (fde->personality.X_op)
00672     {
00673     case O_symbol:
00674       break;
00675     case O_constant:
00676       if ((encoding & 0x70) == DW_EH_PE_pcrel)
00677        encoding = DW_EH_PE_omit;
00678       break;
00679     default:
00680       encoding = DW_EH_PE_omit;
00681       break;
00682     }
00683 
00684   fde->per_encoding = encoding;
00685 
00686   if (encoding == DW_EH_PE_omit)
00687     {
00688       as_bad (_("wrong second argument to .cfi_personality"));
00689       ignore_rest_of_line ();
00690       return;
00691     }
00692 
00693   demand_empty_rest_of_line ();
00694 }
00695 
00696 static void
00697 dot_cfi_lsda (int ignored ATTRIBUTE_UNUSED)
00698 {
00699   struct fde_entry *fde;
00700   offsetT encoding;
00701 
00702   if (frchain_now->frch_cfi_data == NULL)
00703     {
00704       as_bad (_("CFI instruction used without previous .cfi_startproc"));
00705       ignore_rest_of_line ();
00706       return;
00707     }
00708 
00709   fde = frchain_now->frch_cfi_data->cur_fde_data;
00710   encoding = get_absolute_expression ();
00711   if (encoding == DW_EH_PE_omit)
00712     {
00713       demand_empty_rest_of_line ();
00714       fde->lsda_encoding = encoding;
00715       return;
00716     }
00717 
00718   if ((encoding & 0xff) != encoding
00719       || ((encoding & 0x70) != 0
00720 #if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
00721          && (encoding & 0x70) != DW_EH_PE_pcrel
00722 #endif
00723          )
00724         /* leb128 can be handled, but does something actually need it?  */
00725       || (encoding & 7) == DW_EH_PE_uleb128
00726       || (encoding & 7) > DW_EH_PE_udata8)
00727     {
00728       as_bad (_("invalid or unsupported encoding in .cfi_lsda"));
00729       ignore_rest_of_line ();
00730       return;
00731     }
00732 
00733   if (*input_line_pointer++ != ',')
00734     {
00735       as_bad (_(".cfi_lsda requires encoding and symbol arguments"));
00736       ignore_rest_of_line ();
00737       return;
00738     }
00739 
00740   fde->lsda_encoding = encoding;
00741 
00742   expression_and_evaluate (&fde->lsda);
00743   switch (fde->lsda.X_op)
00744     {
00745     case O_symbol:
00746       break;
00747     case O_constant:
00748       if ((encoding & 0x70) == DW_EH_PE_pcrel)
00749        encoding = DW_EH_PE_omit;
00750       break;
00751     default:
00752       encoding = DW_EH_PE_omit;
00753       break;
00754     }
00755 
00756   fde->lsda_encoding = encoding;
00757 
00758   if (encoding == DW_EH_PE_omit)
00759     {
00760       as_bad (_("wrong second argument to .cfi_lsda"));
00761       ignore_rest_of_line ();
00762       return;
00763     }
00764 
00765   demand_empty_rest_of_line ();
00766 }
00767 
00768 static void
00769 dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
00770 {
00771   int simple = 0;
00772 
00773   if (frchain_now->frch_cfi_data != NULL)
00774     {
00775       as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
00776       ignore_rest_of_line ();
00777       return;
00778     }
00779 
00780   cfi_new_fde (symbol_temp_new_now ());
00781 
00782   SKIP_WHITESPACE ();
00783   if (is_name_beginner (*input_line_pointer))
00784     {
00785       char *name, c;
00786 
00787       name = input_line_pointer;
00788       c = get_symbol_end ();
00789 
00790       if (strcmp (name, "simple") == 0)
00791        {
00792          simple = 1;
00793          *input_line_pointer = c;
00794        }
00795       else
00796        input_line_pointer = name;
00797     }
00798   demand_empty_rest_of_line ();
00799 
00800   frchain_now->frch_cfi_data->cur_cfa_offset = 0;
00801   if (!simple)
00802     tc_cfi_frame_initial_instructions ();
00803 }
00804 
00805 static void
00806 dot_cfi_endproc (int ignored ATTRIBUTE_UNUSED)
00807 {
00808   if (frchain_now->frch_cfi_data == NULL)
00809     {
00810       as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
00811       ignore_rest_of_line ();
00812       return;
00813     }
00814 
00815   cfi_end_fde (symbol_temp_new_now ());
00816 
00817   demand_empty_rest_of_line ();
00818 }
00819 
00820 
00821 /* Emit a single byte into the current segment.  */
00822 
00823 static inline void
00824 out_one (int byte)
00825 {
00826   FRAG_APPEND_1_CHAR (byte);
00827 }
00828 
00829 /* Emit a two-byte word into the current segment.  */
00830 
00831 static inline void
00832 out_two (int data)
00833 {
00834   md_number_to_chars (frag_more (2), data, 2);
00835 }
00836 
00837 /* Emit a four byte word into the current segment.  */
00838 
00839 static inline void
00840 out_four (int data)
00841 {
00842   md_number_to_chars (frag_more (4), data, 4);
00843 }
00844 
00845 /* Emit an unsigned "little-endian base 128" number.  */
00846 
00847 static void
00848 out_uleb128 (addressT value)
00849 {
00850   output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0);
00851 }
00852 
00853 /* Emit an unsigned "little-endian base 128" number.  */
00854 
00855 static void
00856 out_sleb128 (offsetT value)
00857 {
00858   output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1);
00859 }
00860 
00861 static void
00862 output_cfi_insn (struct cfi_insn_data *insn)
00863 {
00864   offsetT offset;
00865   unsigned int regno;
00866 
00867   switch (insn->insn)
00868     {
00869     case DW_CFA_advance_loc:
00870       {
00871        symbolS *from = insn->u.ll.lab1;
00872        symbolS *to = insn->u.ll.lab2;
00873 
00874        if (symbol_get_frag (to) == symbol_get_frag (from))
00875          {
00876            addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
00877            addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;
00878 
00879            if (scaled <= 0x3F)
00880              out_one (DW_CFA_advance_loc + scaled);
00881            else if (delta <= 0xFF)
00882              {
00883               out_one (DW_CFA_advance_loc1);
00884               out_one (delta);
00885              }
00886            else if (delta <= 0xFFFF)
00887              {
00888               out_one (DW_CFA_advance_loc2);
00889               out_two (delta);
00890              }
00891            else
00892              {
00893               out_one (DW_CFA_advance_loc4);
00894               out_four (delta);
00895              }
00896          }
00897        else
00898          {
00899            expressionS exp;
00900 
00901            exp.X_op = O_subtract;
00902            exp.X_add_symbol = to;
00903            exp.X_op_symbol = from;
00904            exp.X_add_number = 0;
00905 
00906            /* The code in ehopt.c expects that one byte of the encoding
00907               is already allocated to the frag.  This comes from the way
00908               that it scans the .eh_frame section looking first for the
00909               .byte DW_CFA_advance_loc4.  */
00910            frag_more (1);
00911 
00912            frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
00913                     make_expr_symbol (&exp), frag_now_fix () - 1,
00914                     (char *) frag_now);
00915          }
00916       }
00917       break;
00918 
00919     case DW_CFA_def_cfa:
00920       offset = insn->u.ri.offset;
00921       if (offset < 0)
00922        {
00923          out_one (DW_CFA_def_cfa_sf);
00924          out_uleb128 (insn->u.ri.reg);
00925          out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
00926        }
00927       else
00928        {
00929          out_one (DW_CFA_def_cfa);
00930          out_uleb128 (insn->u.ri.reg);
00931          out_uleb128 (offset);
00932        }
00933       break;
00934 
00935     case DW_CFA_def_cfa_register:
00936     case DW_CFA_undefined:
00937     case DW_CFA_same_value:
00938       out_one (insn->insn);
00939       out_uleb128 (insn->u.r);
00940       break;
00941 
00942     case DW_CFA_def_cfa_offset:
00943       offset = insn->u.i;
00944       if (offset < 0)
00945        {
00946          out_one (DW_CFA_def_cfa_offset_sf);
00947          out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
00948        }
00949       else
00950        {
00951          out_one (DW_CFA_def_cfa_offset);
00952          out_uleb128 (offset);
00953        }
00954       break;
00955 
00956     case DW_CFA_restore:
00957       regno = insn->u.r;
00958       if (regno <= 0x3F)
00959        {
00960          out_one (DW_CFA_restore + regno);
00961        }
00962       else
00963        {
00964          out_one (DW_CFA_restore_extended);
00965          out_uleb128 (regno);
00966        }
00967       break;
00968 
00969     case DW_CFA_offset:
00970       regno = insn->u.ri.reg;
00971       offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
00972       if (offset < 0)
00973        {
00974          out_one (DW_CFA_offset_extended_sf);
00975          out_uleb128 (regno);
00976          out_sleb128 (offset);
00977        }
00978       else if (regno <= 0x3F)
00979        {
00980          out_one (DW_CFA_offset + regno);
00981          out_uleb128 (offset);
00982        }
00983       else
00984        {
00985          out_one (DW_CFA_offset_extended);
00986          out_uleb128 (regno);
00987          out_uleb128 (offset);
00988        }
00989       break;
00990 
00991     case DW_CFA_register:
00992       out_one (DW_CFA_register);
00993       out_uleb128 (insn->u.rr.reg1);
00994       out_uleb128 (insn->u.rr.reg2);
00995       break;
00996 
00997     case DW_CFA_remember_state:
00998     case DW_CFA_restore_state:
00999       out_one (insn->insn);
01000       break;
01001 
01002     case DW_CFA_GNU_window_save:
01003       out_one (DW_CFA_GNU_window_save);
01004       break;
01005 
01006     case CFI_escape:
01007       {
01008        struct cfi_escape_data *e;
01009        for (e = insn->u.esc; e ; e = e->next)
01010          emit_expr (&e->exp, 1);
01011        break;
01012       }
01013 
01014     default:
01015       abort ();
01016     }
01017 }
01018 
01019 static offsetT
01020 encoding_size (unsigned char encoding)
01021 {
01022   if (encoding == DW_EH_PE_omit)
01023     return 0;
01024   switch (encoding & 0x7)
01025     {
01026     case 0:
01027       return bfd_get_arch_size (stdoutput) == 64 ? 8 : 4;
01028     case DW_EH_PE_udata2:
01029       return 2;
01030     case DW_EH_PE_udata4:
01031       return 4;
01032     case DW_EH_PE_udata8:
01033       return 8;
01034     default:
01035       abort ();
01036     }
01037 }
01038 
01039 static void
01040 output_cie (struct cie_entry *cie)
01041 {
01042   symbolS *after_size_address, *end_address;
01043   expressionS exp;
01044   struct cfi_insn_data *i;
01045   offsetT augmentation_size;
01046 
01047   cie->start_address = symbol_temp_new_now ();
01048   after_size_address = symbol_temp_make ();
01049   end_address = symbol_temp_make ();
01050 
01051   exp.X_op = O_subtract;
01052   exp.X_add_symbol = end_address;
01053   exp.X_op_symbol = after_size_address;
01054   exp.X_add_number = 0;
01055 
01056   emit_expr (&exp, 4);                           /* Length.  */
01057   symbol_set_value_now (after_size_address);
01058   out_four (0);                                  /* CIE id.  */
01059   out_one (DW_CIE_VERSION);               /* Version.  */
01060   out_one ('z');                          /* Augmentation.  */
01061   if (cie->per_encoding != DW_EH_PE_omit)
01062     out_one ('P');
01063   if (cie->lsda_encoding != DW_EH_PE_omit)
01064     out_one ('L');
01065   out_one ('R');
01066   if (cie->signal_frame)
01067     out_one ('S');
01068   out_one (0);
01069   out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH);     /* Code alignment.  */
01070   out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT);       /* Data alignment.  */
01071   if (DW_CIE_VERSION == 1)                /* Return column.  */
01072     out_one (cie->return_column);
01073   else
01074     out_uleb128 (cie->return_column);
01075   augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
01076   if (cie->per_encoding != DW_EH_PE_omit)
01077     augmentation_size += 1 + encoding_size (cie->per_encoding);
01078   out_uleb128 (augmentation_size);        /* Augmentation size.  */
01079   if (cie->per_encoding != DW_EH_PE_omit)
01080     {
01081       offsetT size = encoding_size (cie->per_encoding);
01082       out_one (cie->per_encoding);
01083       exp = cie->personality;
01084       if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
01085        {
01086 #ifdef DIFF_EXPR_OK
01087          exp.X_op = O_subtract;
01088          exp.X_op_symbol = symbol_temp_new_now ();
01089          emit_expr (&exp, size);
01090 #elif defined (tc_cfi_emit_pcrel_expr)
01091          tc_cfi_emit_pcrel_expr (&exp, size);
01092 #else
01093          abort ();
01094 #endif
01095        }
01096       else
01097        emit_expr (&exp, size);
01098     }
01099   if (cie->lsda_encoding != DW_EH_PE_omit)
01100     out_one (cie->lsda_encoding);
01101 #if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
01102   out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
01103 #else
01104   out_one (DW_EH_PE_sdata4);
01105 #endif
01106 
01107   if (cie->first)
01108     for (i = cie->first; i != cie->last; i = i->next)
01109       output_cfi_insn (i);
01110 
01111   frag_align (2, DW_CFA_nop, 0);
01112   symbol_set_value_now (end_address);
01113 }
01114 
01115 static void
01116 output_fde (struct fde_entry *fde, struct cie_entry *cie,
01117            struct cfi_insn_data *first, int align)
01118 {
01119   symbolS *after_size_address, *end_address;
01120   expressionS exp;
01121   offsetT augmentation_size;
01122 
01123   after_size_address = symbol_temp_make ();
01124   end_address = symbol_temp_make ();
01125 
01126   exp.X_op = O_subtract;
01127   exp.X_add_symbol = end_address;
01128   exp.X_op_symbol = after_size_address;
01129   exp.X_add_number = 0;
01130   emit_expr (&exp, 4);                           /* Length.  */
01131   symbol_set_value_now (after_size_address);
01132 
01133   exp.X_add_symbol = after_size_address;
01134   exp.X_op_symbol = cie->start_address;
01135   emit_expr (&exp, 4);                           /* CIE offset.  */
01136 
01137 #ifdef DIFF_EXPR_OK
01138   exp.X_add_symbol = fde->start_address;
01139   exp.X_op_symbol = symbol_temp_new_now ();
01140   emit_expr (&exp, 4);                           /* Code offset.  */
01141 #else
01142   exp.X_op = O_symbol;
01143   exp.X_add_symbol = fde->start_address;
01144   exp.X_op_symbol = NULL;
01145 #ifdef tc_cfi_emit_pcrel_expr
01146   tc_cfi_emit_pcrel_expr (&exp, 4);              /* Code offset.  */
01147 #else
01148   emit_expr (&exp, 4);                           /* Code offset.  */
01149 #endif
01150   exp.X_op = O_subtract;
01151 #endif
01152 
01153   exp.X_add_symbol = fde->end_address;
01154   exp.X_op_symbol = fde->start_address;          /* Code length.  */
01155   emit_expr (&exp, 4);
01156 
01157   augmentation_size = encoding_size (fde->lsda_encoding);
01158   out_uleb128 (augmentation_size);        /* Augmentation size.  */
01159 
01160   if (fde->lsda_encoding != DW_EH_PE_omit)
01161     {
01162       exp = fde->lsda;
01163       if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
01164        {
01165 #ifdef DIFF_EXPR_OK
01166          exp.X_op = O_subtract;
01167          exp.X_op_symbol = symbol_temp_new_now ();
01168          emit_expr (&exp, augmentation_size);
01169 #elif defined (tc_cfi_emit_pcrel_expr)
01170          tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
01171 #else
01172          abort ();
01173 #endif
01174        }
01175       else
01176        emit_expr (&exp, augmentation_size);
01177     }
01178 
01179   for (; first; first = first->next)
01180     output_cfi_insn (first);
01181 
01182   frag_align (align, DW_CFA_nop, 0);
01183   symbol_set_value_now (end_address);
01184 }
01185 
01186 static struct cie_entry *
01187 select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
01188 {
01189   struct cfi_insn_data *i, *j;
01190   struct cie_entry *cie;
01191 
01192   for (cie = cie_root; cie; cie = cie->next)
01193     {
01194       if (cie->return_column != fde->return_column
01195          || cie->signal_frame != fde->signal_frame
01196          || cie->per_encoding != fde->per_encoding
01197          || cie->lsda_encoding != fde->lsda_encoding)
01198        continue;
01199       if (cie->per_encoding != DW_EH_PE_omit)
01200        {
01201          if (cie->personality.X_op != fde->personality.X_op
01202              || cie->personality.X_add_number
01203                != fde->personality.X_add_number)
01204            continue;
01205          switch (cie->personality.X_op)
01206            {
01207            case O_constant:
01208              if (cie->personality.X_unsigned != fde->personality.X_unsigned)
01209               continue;
01210              break;
01211            case O_symbol:
01212              if (cie->personality.X_add_symbol
01213                 != fde->personality.X_add_symbol)
01214               continue;
01215              break;
01216            default:
01217              abort ();
01218            }
01219        }
01220       for (i = cie->first, j = fde->data;
01221           i != cie->last && j != NULL;
01222           i = i->next, j = j->next)
01223        {
01224          if (i->insn != j->insn)
01225            goto fail;
01226          switch (i->insn)
01227            {
01228            case DW_CFA_advance_loc:
01229            case DW_CFA_remember_state:
01230              /* We reached the first advance/remember in the FDE,
01231                but did not reach the end of the CIE list.  */
01232              goto fail;
01233 
01234            case DW_CFA_offset:
01235            case DW_CFA_def_cfa:
01236              if (i->u.ri.reg != j->u.ri.reg)
01237               goto fail;
01238              if (i->u.ri.offset != j->u.ri.offset)
01239               goto fail;
01240              break;
01241 
01242            case DW_CFA_register:
01243              if (i->u.rr.reg1 != j->u.rr.reg1)
01244               goto fail;
01245              if (i->u.rr.reg2 != j->u.rr.reg2)
01246               goto fail;
01247              break;
01248 
01249            case DW_CFA_def_cfa_register:
01250            case DW_CFA_restore:
01251            case DW_CFA_undefined:
01252            case DW_CFA_same_value:
01253              if (i->u.r != j->u.r)
01254               goto fail;
01255              break;
01256 
01257            case DW_CFA_def_cfa_offset:
01258              if (i->u.i != j->u.i)
01259               goto fail;
01260              break;
01261 
01262            case CFI_escape:
01263              /* Don't bother matching these for now.  */
01264              goto fail;
01265 
01266            default:
01267              abort ();
01268            }
01269        }
01270 
01271       /* Success if we reached the end of the CIE list, and we've either
01272         run out of FDE entries or we've encountered an advance,
01273         remember, or escape.  */
01274       if (i == cie->last
01275          && (!j
01276              || j->insn == DW_CFA_advance_loc
01277              || j->insn == DW_CFA_remember_state
01278              || j->insn == CFI_escape))
01279        {
01280          *pfirst = j;
01281          return cie;
01282        }
01283 
01284     fail:;
01285     }
01286 
01287   cie = xmalloc (sizeof (struct cie_entry));
01288   cie->next = cie_root;
01289   cie_root = cie;
01290   cie->return_column = fde->return_column;
01291   cie->signal_frame = fde->signal_frame;
01292   cie->per_encoding = fde->per_encoding;
01293   cie->lsda_encoding = fde->lsda_encoding;
01294   cie->personality = fde->personality;
01295   cie->first = fde->data;
01296 
01297   for (i = cie->first; i ; i = i->next)
01298     if (i->insn == DW_CFA_advance_loc
01299        || i->insn == DW_CFA_remember_state
01300        || i->insn == CFI_escape)
01301       break;
01302 
01303   cie->last = i;
01304   *pfirst = i;
01305    
01306   output_cie (cie);
01307 
01308   return cie;
01309 }
01310 
01311 void
01312 cfi_finish (void)
01313 {
01314   segT cfi_seg;
01315   struct fde_entry *fde;
01316   int save_flag_traditional_format;
01317 
01318   if (all_fde_data == 0)
01319     return;
01320 
01321   /* Open .eh_frame section.  */
01322   cfi_seg = subseg_new (".eh_frame", 0);
01323   bfd_set_section_flags (stdoutput, cfi_seg,
01324                       SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY);
01325   subseg_set (cfi_seg, 0);
01326   record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
01327 
01328   /* Make sure check_eh_frame doesn't do anything with our output.  */
01329   save_flag_traditional_format = flag_traditional_format;
01330   flag_traditional_format = 1;
01331 
01332   for (fde = all_fde_data; fde ; fde = fde->next)
01333     {
01334       struct cfi_insn_data *first;
01335       struct cie_entry *cie;
01336 
01337       if (fde->end_address == NULL)
01338        {
01339          as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
01340          fde->end_address = fde->start_address;
01341        }
01342 
01343       cie = select_cie_for_fde (fde, &first);
01344       output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
01345     }
01346 
01347   flag_traditional_format = save_flag_traditional_format;
01348 }