dwarf2 EH support
authorJason Merrill <jason@gcc.gnu.org>
Wed, 10 Sep 1997 18:00:28 +0000 (14:00 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 10 Sep 1997 18:00:28 +0000 (14:00 -0400)
From-SVN: r15255

23 files changed:
gcc/c-decl.c
gcc/collect2.c
gcc/config/i386/i386.c
gcc/config/mips/iris6.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/sparc/sparc.c
gcc/config/sparc/sunos4.h
gcc/config/sparc/sysv4.h
gcc/cp/decl2.c
gcc/cp/except.c
gcc/cp/gxxint.texi
gcc/crtstuff.c
gcc/defaults.h
gcc/dwarf2.h
gcc/dwarf2out.c
gcc/except.h
gcc/final.c
gcc/frame.c [new file with mode: 0644]
gcc/tm.texi
gcc/toplev.c
gcc/tree.h
gcc/varasm.c

index b556d0825f1fd7e4a25b262165e15e03746f249f..94dc196a6a17b246dcb9775d3edf54387a281ddf 100644 (file)
@@ -2849,7 +2849,7 @@ init_decl_processing ()
   tree traditional_ptr_type_node;
   /* Data types of memcpy and strlen.  */
   tree memcpy_ftype, memset_ftype, strlen_ftype;
-  tree void_ftype_any;
+  tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr;
   int wchar_type_size;
   tree temp;
   tree array_domain_type;
@@ -3165,6 +3165,11 @@ init_decl_processing ()
                                                            sizetype,
                                                            endlink))));
 
+  ptr_ftype_void = build_function_type (ptr_type_node, endlink);
+  ptr_ftype_ptr
+    = build_function_type (ptr_type_node,
+                          tree_cons (NULL_TREE, ptr_type_node, endlink));
+
   builtin_function ("__builtin_constant_p", default_function_type,
                    BUILT_IN_CONSTANT_P, NULL_PTR);
 
@@ -3186,6 +3191,36 @@ init_decl_processing ()
                    build_function_type (ptr_type_node, NULL_TREE),
                    BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR);
 
+  /* Hooks for the DWARF 2 __throw routine.  */
+  builtin_function ("__builtin_unwind_init",
+                   build_function_type (void_type_node, endlink),
+                   BUILT_IN_UNWIND_INIT, NULL_PTR);
+  builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
+  builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
+  builtin_function ("__builtin_dwarf_fp_regnum",
+                   build_function_type (unsigned_type_node, endlink),
+                   BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
+  builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr,
+                   BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
+  builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
+                   BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
+  builtin_function ("__builtin_set_return_addr_reg",
+                   build_function_type (void_type_node, 
+                                        tree_cons (NULL_TREE,
+                                                   ptr_type_node,
+                                                   endlink)),
+                   BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
+  builtin_function ("__builtin_eh_stub", ptr_ftype_void,
+                   BUILT_IN_EH_STUB, NULL_PTR);
+  builtin_function
+    ("__builtin_set_eh_regs",
+     build_function_type (void_type_node,
+                         tree_cons (NULL_TREE, ptr_type_node,
+                                    tree_cons (NULL_TREE,
+                                               type_for_mode (ptr_mode, 0),
+                                               endlink))),
+     BUILT_IN_SET_EH_REGS, NULL_PTR);
+
   builtin_function ("__builtin_alloca",
                    build_function_type (ptr_type_node,
                                         tree_cons (NULL_TREE,
index 7c17824cc01b181d7865820df64a815a3fc31fb2..576bc74669f808627934bc48135bb6e8b2ee9359 100644 (file)
@@ -239,6 +239,7 @@ static char *initname, *fininame;   /* names of init and fini funcs */
 static struct head constructors;       /* list of constructors found */
 static struct head destructors;                /* list of destructors found */
 static struct head exports;            /* list of exported symbols */
+static struct head frame_tables;       /* list of frame unwind info tables */
 
 struct obstack temporary_obstack;
 struct obstack permanent_obstack;
@@ -599,13 +600,16 @@ is_ctor_dtor (s)
 #ifdef NO_DOT_IN_LABEL
     { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 },
     { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 },
+    { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 },
 #else
     { "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
     { "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
+    { "GLOBAL_.F.", sizeof ("GLOBAL_.F.")-1, 5, 0 },
 #endif
 #else
     { "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
     { "GLOBAL_$D$", sizeof ("GLOBAL_$D$")-1, 2, 0 },
+    { "GLOBAL_$F$", sizeof ("GLOBAL_$F$")-1, 5, 0 },
 #endif
     { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 },
     { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 },
@@ -993,6 +997,7 @@ main (argc, argv)
        num_c_args++;
     }
   obstack_free (&temporary_obstack, temporary_firstobj);
+  ++num_c_args;
 
   c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
 
@@ -1288,6 +1293,7 @@ main (argc, argv)
        shared_obj = 1;
     }
   obstack_free (&temporary_obstack, temporary_firstobj);
+  *c_ptr++ = "-fno-exceptions";
 
 #ifdef COLLECT_EXPORT_LIST
   /* The AIX linker will discard static constructors in object files if
@@ -1396,7 +1402,8 @@ main (argc, argv)
     }
 
   if (constructors.number == 0 && destructors.number == 0
-#ifdef LDD_SUFFIX
+      && frame_tables.number == 0
+#ifdef SCAN_LIBRARIES
       /* If we will be running these functions ourselves, we want to emit
         stubs into the shared library so that we don't have to relink
         dependent programs when we add static objects.  */
@@ -1690,6 +1697,7 @@ write_c_file_stat (stream, name)
      char *name;
 {
   char *prefix, *p, *q;
+  int frames = (frame_tables.number > 0);
 
   /* Figure out name of output_file, stripping off .so version.  */
   p = rindex (output_file, '/');
@@ -1743,15 +1751,38 @@ write_c_file_stat (stream, name)
   fprintf (stream, "static int count;\n");
   fprintf (stream, "typedef void entry_pt();\n");
   write_list_with_asm (stream, "extern entry_pt ", constructors.first);
+
+  if (frames)
+    {
+      write_list_with_asm (stream, "extern void *", frame_tables.first);
+
+      fprintf (stream, "\tstatic void *frame_table[] = {\n");
+      write_list (stream, "\t\t&", frame_tables.first);
+      fprintf (stream, "\t0\n};\n");
+
+      fprintf (stream, "extern void __register_frame_table (void *);\n");
+      fprintf (stream, "extern void __deregister_frame (void *);\n");
+
+      fprintf (stream, "static void reg_frame () {\n");
+      fprintf (stream, "\t__register_frame_table (frame_table);\n");
+      fprintf (stream, "\t}\n");
+
+      fprintf (stream, "static void dereg_frame () {\n");
+      fprintf (stream, "\t__deregister_frame (frame_table);\n");
+      fprintf (stream, "\t}\n");
+    }
+
   fprintf (stream, "void %s() {\n", initname);
-  if (constructors.number > 0)
+  if (constructors.number > 0 || frames)
     {
       fprintf (stream, "\tstatic entry_pt *ctors[] = {\n");
       write_list (stream, "\t\t", constructors.first);
+      if (frames)
+       fprintf (stream, "\treg_frame,\n");
       fprintf (stream, "\t};\n");
       fprintf (stream, "\tentry_pt **p;\n");
       fprintf (stream, "\tif (count++ != 0) return;\n");
-      fprintf (stream, "\tp = ctors + %d;\n", constructors.number);
+      fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames);
       fprintf (stream, "\twhile (p > ctors) (*--p)();\n");
     }
   else
@@ -1759,16 +1790,18 @@ write_c_file_stat (stream, name)
   fprintf (stream, "}\n");
   write_list_with_asm (stream, "extern entry_pt ", destructors.first);
   fprintf (stream, "void %s() {\n", fininame);
-  if (destructors.number > 0)
+  if (destructors.number > 0 || frames)
     {
       fprintf (stream, "\tstatic entry_pt *dtors[] = {\n");
       write_list (stream, "\t\t", destructors.first);
+      if (frames)
+       fprintf (stream, "\tdereg_frame,\n");
       fprintf (stream, "\t};\n");
       fprintf (stream, "\tentry_pt **p;\n");
       fprintf (stream, "\tif (--count != 0) return;\n");
       fprintf (stream, "\tp = dtors;\n");
       fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n",
-              destructors.number);
+              destructors.number + frames);
     }
   fprintf (stream, "}\n");
 
@@ -1788,20 +1821,46 @@ write_c_file_glob (stream, name)
 {
   /* Write the tables as C code  */
 
+  int frames = (frame_tables.number > 0);
+
   fprintf (stream, "typedef void entry_pt();\n\n");
     
   write_list_with_asm (stream, "extern entry_pt ", constructors.first);
-    
+
+  if (frames)
+    {
+      write_list_with_asm (stream, "extern void *", frame_tables.first);
+
+      fprintf (stream, "\tstatic void *frame_table[] = {\n");
+      write_list (stream, "\t\t&", frame_tables.first);
+      fprintf (stream, "\t0\n};\n");
+
+      fprintf (stream, "extern void __register_frame_table (void *);\n");
+      fprintf (stream, "extern void __deregister_frame (void *);\n");
+
+      fprintf (stream, "static void reg_frame () {\n");
+      fprintf (stream, "\t__register_frame_table (frame_table);\n");
+      fprintf (stream, "\t}\n");
+
+      fprintf (stream, "static void dereg_frame () {\n");
+      fprintf (stream, "\t__deregister_frame (frame_table);\n");
+      fprintf (stream, "\t}\n");
+    }
+
   fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
-  fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
+  fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames);
   write_list (stream, "\t", constructors.first);
+  if (frames)
+    fprintf (stream, "\treg_frame,\n");
   fprintf (stream, "\t0\n};\n\n");
 
   write_list_with_asm (stream, "extern entry_pt ", destructors.first);
 
   fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
-  fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
+  fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames);
   write_list (stream, "\t", destructors.first);
+  if (frames)
+    fprintf (stream, "\tdereg_frame,\n");
   fprintf (stream, "\t0\n};\n\n");
 
   fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN);
@@ -1985,6 +2044,10 @@ scan_prog_file (prog_name, which_pass)
 #endif
          break;
 
+       case 5:
+         if (which_pass != PASS_LIB)
+           add_to_list (&frame_tables, name);
+
        default:                /* not a constructor or destructor */
          continue;
        }
index d8d9757e759f4b3d723dbe78934adac344de1fb2..fafdabc91b4ef589a02b89dee26b405c96e958d8 100644 (file)
@@ -1866,6 +1866,7 @@ function_prologue (file, size)
   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                                  || current_function_uses_const_pool);
   long tsize = get_frame_size ();
+  int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
 
   /* pic references don't explicitly mention pic_offset_table_rtx */
   if (TARGET_SCHEDULE_PROLOGUE)
@@ -1881,13 +1882,34 @@ function_prologue (file, size)
   if (frame_pointer_needed)
     {
       output_asm_insn ("push%L1 %1", xops); 
+      if (dwarf2out_do_frame ())
+       {
+         char *l = (char *) dwarf2out_cfi_label ();
+         cfa_store_offset += 4;
+         cfa_offset = cfa_store_offset;
+         dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
+         dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_store_offset);
+       }
       output_asm_insn (AS2 (mov%L0,%0,%1), xops); 
+      if (dwarf2out_do_frame ())
+       dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);
     }
 
   if (tsize == 0)
     ;
   else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
-    output_asm_insn (AS2 (sub%L0,%2,%0), xops);
+    {
+      output_asm_insn (AS2 (sub%L0,%2,%0), xops);
+      if (dwarf2out_do_frame ())
+       {
+         cfa_store_offset += tsize;
+         if (! frame_pointer_needed)
+           {
+             cfa_offset = cfa_store_offset;
+             dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
+           }
+       }
+    }
   else 
     {
       xops[3] = gen_rtx (REG, SImode, 0);
@@ -1913,6 +1935,17 @@ function_prologue (file, size)
       {
        xops[0] = gen_rtx (REG, SImode, regno);
        output_asm_insn ("push%L0 %0", xops);
+       if (dwarf2out_do_frame ())
+         {
+           char *l = (char *) dwarf2out_cfi_label ();
+           cfa_store_offset += 4;
+           if (! frame_pointer_needed)
+             {
+               cfa_offset = cfa_store_offset;
+               dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
+             }
+           dwarf2out_reg_save (l, regno, -cfa_store_offset);
+         }
       }
 
   if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
index 3521fdd3b3b9d2b8097f87fbbd0db8d6501f1e89..86746d11e845a57cc1164cca365af7d6119da239 100644 (file)
@@ -249,6 +249,10 @@ Boston, MA 02111-1307, USA.  */
   (TARGET_LONG64 ? ".section\t.dtors,1,2,0,8" : ".section\t.dtors,1,2,0,4")
 #endif /* defined (CRT_BEGIN) || defined (CRT_END) */
 
+/* dwarf2out will handle padding this data properly.  We definitely don't
+   want it 8-byte aligned on n32.  */
+#define EH_FRAME_SECTION_ASM_OP ".section\t.eh_frame,1,2,0,1"
+
 /* A default list of other sections which we might be "in" at any given
    time.  For targets that use additional sections (e.g. .tdesc) you
    should override this definition in the target-specific file which
@@ -538,5 +542,5 @@ do {                                                                         \
 %{!static: \
   %{!shared: %{!non_shared: %{!call_shared: -call_shared -no_unresolved}}}} \
 %{rpath} -init __do_global_ctors -fini __do_global_dtors \
-%{shared:-hidden_symbol __do_global_ctors,__do_global_dtors} \
+%{shared:-hidden_symbol __do_global_ctors,__do_global_dtors,__EH_FRAME_BEGIN__} \
 -_SYSTYPE_SVR4 %{mabi=32: -32}%{mabi=n32: -n32}%{mabi=64: -64} %{!mabi*: -n32}"
index 7ebb50836484311c3a0c6fee22d96aa8fc792646..ffbea137862d9863f0e261951e427b95d487f561 100644 (file)
@@ -5241,6 +5241,9 @@ function_prologue (file, size)
                   sp_str, sp_str, tsize);
          fprintf (file, "\t.cprestore %d\n", current_frame_info.args_size);
        }
+
+      if (dwarf2out_do_frame ())
+       dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, tsize);
     }
 }
 
index 58ed718cad72a42b1823fca408452d7ca88cecb1..fba9d0a1ce8bed4121706745e46e39a6759118c4 100644 (file)
@@ -948,12 +948,11 @@ while (0)
 #define DBX_REGISTER_NUMBER(REGNO) mips_dbx_regno[ (REGNO) ]
 
 /* The mapping from gcc register number to DWARF 2 CFA column number.
-   This mapping does not allow for tracking DBX register 0, since column 0
-   is used for the frame address, but since register 0 is fixed this is
-   not really a problem.  */
+   This mapping does not allow for tracking register 0, since SGI's broken
+   dwarf reader thinks column 0 is used for the frame address, but since
+   register 0 is fixed this is not a problem.  */
 #define DWARF_FRAME_REGNUM(REG)                                \
-  (REG == GP_REG_FIRST + 31 ? DWARF_FRAME_RETURN_COLUMN        \
-   : DBX_REGISTER_NUMBER (REG))
+  (REG == GP_REG_FIRST + 31 ? DWARF_FRAME_RETURN_COLUMN : REG)
 
 /* The DWARF 2 CFA column which tracks the return address.  */
 #define DWARF_FRAME_RETURN_COLUMN (FP_REG_LAST + 1)
index 4235c93580240666e426fb53bfd2d2dca4f577f0..f040aa7608ec5ddc142b8f238157167ff780481a 100644 (file)
@@ -2910,10 +2910,8 @@ save_regs (file, low, high, base, offset, n_regs, real_offset)
            {
              fprintf (file, "\tstx %s,[%s+%d]\n",
                       reg_names[i], base, offset + 4 * n_regs);
-#ifdef DWARF2_DEBUGGING_INFO
-             if (write_symbols == DWARF2_DEBUG)
+             if (dwarf2out_do_frame ())
                dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
-#endif
              n_regs += 2;
            }
        }
@@ -2927,34 +2925,28 @@ save_regs (file, low, high, base, offset, n_regs, real_offset)
              {
                fprintf (file, "\tstd %s,[%s+%d]\n",
                         reg_names[i], base, offset + 4 * n_regs);
-#ifdef DWARF2_DEBUGGING_INFO
-               if (write_symbols == DWARF2_DEBUG)
+               if (dwarf2out_do_frame ())
                  {
                    char *l = (char *) dwarf2out_cfi_label ();
                    dwarf2out_reg_save (l, i, real_offset + 4 * n_regs);
                    dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4);
                  }
-#endif
                n_regs += 2;
              }
            else
              {
                fprintf (file, "\tst %s,[%s+%d]\n",
                         reg_names[i], base, offset + 4 * n_regs);
-#ifdef DWARF2_DEBUGGING_INFO
-               if (write_symbols == DWARF2_DEBUG)
+               if (dwarf2out_do_frame ())
                  dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
-#endif
                n_regs += 2;
              }
          else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
            {
              fprintf (file, "\tst %s,[%s+%d]\n",
                       reg_names[i+1], base, offset + 4 * n_regs + 4);
-#ifdef DWARF2_DEBUGGING_INFO
-             if (write_symbols == DWARF2_DEBUG)
+             if (dwarf2out_do_frame ())
                dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4);
-#endif
              n_regs += 2;
            }
        }
@@ -3196,8 +3188,7 @@ output_function_prologue (file, size, leaf_function)
        }
     }
 
-#ifdef DWARF2_DEBUGGING_INFO
-  if (write_symbols == DWARF2_DEBUG && actual_fsize)
+  if (dwarf2out_do_frame () && actual_fsize)
     {
       char *label = (char *) dwarf2out_cfi_label ();
 
@@ -3217,7 +3208,6 @@ output_function_prologue (file, size, leaf_function)
          dwarf2out_return_reg (label, 31);
        }
     }
-#endif
 
   /* If doing anything with PIC, do it now.  */
   if (! flag_pic)
@@ -4739,15 +4729,13 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, doublewo
                      fprintf (file, "\t%s %s,[%s+%d]\n",
                               doubleword_op, reg_names[regno],
                               base_reg, offset);
-#ifdef DWARF2_DEBUGGING_INFO
-                     if (write_symbols == DWARF2_DEBUG)
+                     if (dwarf2out_do_frame ())
                        {
                          char *l = (char *) dwarf2out_cfi_label ();
                          dwarf2out_reg_save (l, regno, offset + base_offset);
                          dwarf2out_reg_save
                            (l, regno+1, offset+base_offset + UNITS_PER_WORD);
                        }
-#endif
                    }
                  else
                    fprintf (file, "\t%s [%s+%d],%s\n",
@@ -4764,10 +4752,8 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, doublewo
                      fprintf (file, "\t%s %s,[%s+%d]\n",
                               word_op, reg_names[regno],
                               base_reg, offset);
-#ifdef DWARF2_DEBUGGING_INFO
-                     if (write_symbols == DWARF2_DEBUG)
+                     if (dwarf2out_do_frame ())
                        dwarf2out_reg_save ("", regno, offset + base_offset);
-#endif
                    }
                  else
                    fprintf (file, "\t%s [%s+%d],%s\n",
@@ -4790,10 +4776,8 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, doublewo
                  fprintf (file, "\t%s %s,[%s+%d]\n",
                           word_op, reg_names[regno],
                           base_reg, offset);
-#ifdef DWARF2_DEBUGGING_INFO
-                 if (write_symbols == DWARF2_DEBUG)
+                 if (dwarf2out_do_frame ())
                    dwarf2out_reg_save ("", regno, offset + base_offset);
-#endif
                }
              else
                fprintf (file, "\t%s [%s+%d],%s\n",
@@ -4891,8 +4875,7 @@ sparc_flat_output_function_prologue (file, size)
                  reg_offset += 4;
                }
            }
-#ifdef DWARF2_DEBUGGING_INFO
-         if (write_symbols == DWARF2_DEBUG)
+         if (dwarf2out_do_frame ())
            {
              char *l = (char *) dwarf2out_cfi_label ();
              if (gmask & FRAME_POINTER_MASK)
@@ -4904,15 +4887,12 @@ sparc_flat_output_function_prologue (file, size)
              else
                dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size);
            }
-#endif
          if (gmask & RETURN_ADDR_MASK)
            {
              fprintf (file, "\tst %s,[%s+%d]\n",
                       reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset);
-#ifdef DWARF2_DEBUGGING_INFO
-             if (write_symbols == DWARF2_DEBUG)
+             if (dwarf2out_do_frame ())
                dwarf2out_return_save ("", reg_offset - size);
-#endif
              reg_offset += 4;
            }
          sparc_flat_save_restore (file, sp_str, reg_offset,
@@ -4951,8 +4931,7 @@ sparc_flat_output_function_prologue (file, size)
                  offset += 4;
                }
            }
-#ifdef DWARF2_DEBUGGING_INFO
-         if (write_symbols == DWARF2_DEBUG)
+         if (dwarf2out_do_frame ())
            {
              char *l = (char *) dwarf2out_cfi_label ();
              if (gmask & FRAME_POINTER_MASK)
@@ -4964,17 +4943,14 @@ sparc_flat_output_function_prologue (file, size)
              else
                dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1);
            }
-#endif
          if (gmask & RETURN_ADDR_MASK)
            {
              fprintf (file, "\tst %s,[%s+%d]\n",
                       reg_names[RETURN_ADDR_REGNUM], sp_str, offset);
-#ifdef DWARF2_DEBUGGING_INFO
-             if (write_symbols == DWARF2_DEBUG)
+             if (dwarf2out_do_frame ())
                /* offset - size1 == reg_offset - size
                   if reg_offset were updated above like offset.  */
                dwarf2out_return_save ("", offset - size1);
-#endif
              offset += 4;
            }
          sparc_flat_save_restore (file, sp_str, offset,
@@ -4983,11 +4959,9 @@ sparc_flat_output_function_prologue (file, size)
                                   "st", "std", -size1);
          fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n",
                   size - size1, t1_str, sp_str, t1_str, sp_str);
-#ifdef DWARF2_DEBUGGING_INFO
-         if (write_symbols == DWARF2_DEBUG)
+         if (dwarf2out_do_frame ())
            if (! (gmask & FRAME_POINTER_MASK))
              dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
-#endif
        }
     }
 
index 1b58a17d282b08864adb3bfbb007cd7b5bffdd1a..070f41aa3b5e1ff2c757d9ccc7f63e8427b5ba35 100644 (file)
@@ -25,3 +25,6 @@ Boston, MA 02111-1307, USA.  */
 #define DBX_USE_BINCL
 
 #include "sparc/sparc.h"
+
+/* The Sun as doesn't like unaligned data.  */
+#define DWARF2_UNWIND_INFO 0
index 38ddd4815ca05d1a6689b07084869b473982640a..cdb7cd6a2bbe6f81ce683ee7a1ccca2440b0e260 100644 (file)
@@ -91,6 +91,7 @@ Boston, MA 02111-1307, USA.  */
 #define STRING_ASM_OP          ".asciz"
 #define COMMON_ASM_OP          ".common"
 #define SKIP_ASM_OP            ".skip"
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".uaxword"
 #define UNALIGNED_INT_ASM_OP   ".uaword"
 #define UNALIGNED_SHORT_ASM_OP ".uahalf"
 #define PUSHSECTION_ASM_OP     ".pushsection"
@@ -179,6 +180,8 @@ do { ASM_OUTPUT_ALIGN ((FILE), Pmode == SImode ? 2 : 3);            \
 #define CTORS_SECTION_ASM_OP    ".section\t\".ctors\",#alloc,#write"
 #undef DTORS_SECTION_ASM_OP
 #define DTORS_SECTION_ASM_OP    ".section\t\".dtors\",#alloc,#write"
+#undef EH_FRAME_SECTION_ASM_OP
+#define EH_FRAME_SECTION_ASM_OP ".section\t\".eh_frame\",#alloc,#write"
 
 /* A C statement to output something to the assembler file to switch to section
    NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or
index 2de7fcede6e93add4039894841523f823e9ad500..0f313f5e7ec8baece6784f93cdc89f27b14de6fb 100644 (file)
@@ -2934,7 +2934,7 @@ finish_file ()
       rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1);
   vars = static_aggregates;
 
-  if (static_ctors || vars || exception_table_p ())
+  if (static_ctors || vars || register_exception_table_p ())
     needs_messing_up = 1;
   if (static_dtors)
     needs_cleaning = 1;
@@ -3033,7 +3033,7 @@ finish_file ()
       push_momentary ();
       expand_start_bindings (0);
 
-      if (exception_table_p ())
+      if (register_exception_table_p ())
        register_exception_table ();
 
       while (vars)
index 79d8e197da174f11140e518c5307ef20315b64d3..355485af399ca452ba2fdff5e9df565629d662e6 100644 (file)
@@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "except.h"
 #include "function.h"
+#include "defaults.h"
 
 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 
@@ -609,7 +610,8 @@ do_unwind (inner_throw_label)
      rtx inner_throw_label;
 {
 #if defined (SPARC_STACK_ALIGN) /* was sparc */
-  /* This doesn't work for the flat model sparc, I bet.  */
+  /* This doesn't work for the flat model sparc, nor does it need to
+     as the default unwinder is only used to unwind non-flat frames.  */
   tree fcall;
   tree params;
   rtx next_pc;
@@ -704,6 +706,7 @@ do_unwind (inner_throw_label)
 void
 expand_builtin_throw ()
 {
+#ifndef DWARF2_UNWIND_INFO
   tree fcall;
   tree params;
   rtx handler;
@@ -897,6 +900,7 @@ expand_builtin_throw ()
   pop_momentary ();
 
   finish_function (lineno, 0, 0);
+#endif /* DWARF2_UNWIND_INFO */
 }
 
 
@@ -1149,7 +1153,6 @@ expand_throw (exp)
          expand_expr (object, const0_rtx, VOIDmode, 0);
          end_anon_func ();
          mark_addressable (cleanup);
-
        }
 
       if (cleanup == empty_fndecl)
index 5fe34b0a6df513e24fdc829342948b21e41a3f0f..587f0a293ace9dc2182faccca30521978c5ddc0e 100644 (file)
@@ -1185,29 +1185,28 @@ arrays.  Exception specifications are now handled.  Thrown objects are
 now cleaned up all the time.  We can now tell if we have an active
 exception being thrown or not (__eh_type != 0).  We use this to call
 terminate if someone does a throw; without there being an active
-exception object.  uncaught_exception () works.
+exception object.  uncaught_exception () works.  Exception handling
+should work right if you optimize.  Exception handling should work with
+-fpic or -fPIC.
 
 The below points out some flaws in g++'s exception handling, as it now
 stands.
 
 Only exact type matching or reference matching of throw types works when
--fno-rtti is used.  Only works on a SPARC (like Suns), SPARClite, i386,
-arm, rs6000, PowerPC, Alpha, mips, VAX, m68k and z8k machines.  Partial
-support is in for all other machines, but a stack unwinder called
-__unwind_function has to be written, and added to libgcc2 for them.  The
-new EH code doesn't rely upon the __unwind_function for C++ code,
-instead it creates per function unwinders right inside the function,
-unfortunately, on many platforms the definition of RETURN_ADDR_RTX in
-the tm.h file for the machine port is wrong.  The HPPA has a brain dead
-abi that prevents exception handling from just working.  See below for
-details on __unwind_function.  Don't expect exception handling to work
-right if you optimize, in fact the compiler will probably core dump.
-RTL_EXPRs for EH cond variables for && and || exprs should probably be
-wrapped in UNSAVE_EXPRs, and RTL_EXPRs tweaked so that they can be
-unsaved, and the UNSAVE_EXPR code should be in the backend, or
-alternatively, UNSAVE_EXPR should be ripped out and exactly one
-finalization allowed to be expanded by the backend.  I talked with
-kenner about this, and we have to allow multiple expansions.
+-fno-rtti is used.  Only works on a SPARC (like Suns) (both -mflat and
+-mno-flat models work), SPARClite, Hitachi SH, i386, arm, rs6000,
+PowerPC, Alpha, mips, VAX, m68k and z8k machines.  SPARC v9 may not
+work.  HPPA is mostly done, but throwing between a shared library and
+user code doesn't yet work.  Some targets have support for data-driven
+unwinding.  Partial support is in for all other machines, but a stack
+unwinder called __unwind_function has to be written, and added to
+libgcc2 for them.  The new EH code doesn't rely upon the
+__unwind_function for C++ code, instead it creates per function
+unwinders right inside the function, unfortunately, on many platforms
+the definition of RETURN_ADDR_RTX in the tm.h file for the machine port
+is wrong.  See below for details on __unwind_function.  RTL_EXPRs for EH
+cond variables for && and || exprs should probably be wrapped in
+UNSAVE_EXPRs, and RTL_EXPRs tweaked so that they can be unsaved.
 
 We only do pointer conversions on exception matching a la 15.3 p2 case
 3: `A handler with type T, const T, T&, or const T& is a match for a
@@ -1397,6 +1396,33 @@ things: first, a way to figure out where the frame pointer was stored,
 and second, a functional @code{__builtin_return_address} implementation
 for except.c to be able to use it.
 
+Or just support DWARF 2 unwind info.
+
+@subsection New Backend Exception Support
+
+This subsection discusses various aspects of the design of the
+data-driven model being implemented for the exception handling backend.
+
+The goal is to generate enough data during the compilation of user code,
+such that we can dynamically unwind through functions at run time with a
+single routine (@code{__throw}) that lives in libgcc.a, built by the
+compiler, and dispatch into associated exception handlers.
+
+This information is generated by the DWARF 2 debugging backend, and
+includes all of the information __throw needs to unwind an arbitrary
+frame.  It specifies where all of the saved registers and the return
+address can be found at any point in the function.
+
+Major disadvantages when enabling exceptions are:
+
+@itemize @bullet
+@item
+Code that uses caller saved registers, can't, when flow can be
+transfered into that code from an exception handler.  In high performace
+code this should not usually be true, so the effects should be minimal.
+
+@end itemize
+
 @subsection Backend Exception Support
 
 The backend must be extended to fully support exceptions.  Right now
index 2c6824360693751a52b057c333951edfec070bc2..bcb5cc50bf0b820f78a08c1d05891261c3522a3e 100644 (file)
@@ -52,6 +52,7 @@ Boston, MA 02111-1307, USA.  */
    do not apply.  */
 
 #include "tm.h"
+#include "defaults.h"
 
 /* Provide default definitions for the pseudo-ops used to switch to the
    .ctors and .dtors sections.
@@ -75,6 +76,9 @@ Boston, MA 02111-1307, USA.  */
 #ifndef DTORS_SECTION_ASM_OP
 #define DTORS_SECTION_ASM_OP   ".section\t.dtors,\"aw\""
 #endif
+#if !defined (EH_FRAME_SECTION_ASM_OP) && defined (DWARF2_UNWIND_INFO) && defined(ASM_OUTPUT_SECTION_NAME)
+#define EH_FRAME_SECTION_ASM_OP        ".section\t.eh_frame,\"aw\""
+#endif
 
 #ifdef OBJECT_FORMAT_ELF
 
@@ -118,6 +122,7 @@ typedef void (*func_ptr) (void);
    the list we left off processing, and we resume at that point,
    should we be re-invoked.  */
 
+static char __EH_FRAME_BEGIN__[];
 static func_ptr __DTOR_LIST__[];
 static void
 __do_global_dtors_aux ()
@@ -128,6 +133,10 @@ __do_global_dtors_aux ()
       p++;
       (*(p-1)) ();
     }
+
+#ifdef EH_FRAME_SECTION_ASM_OP
+  __deregister_frame (__EH_FRAME_BEGIN__);
+#endif
 }
 
 /* Stick a call to __do_global_dtors_aux into the .fini section.  */
@@ -143,6 +152,29 @@ fini_dummy ()
   asm (TEXT_SECTION_ASM_OP);
 }
 
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Stick a call to __register_frame into the .init section.  For some reason
+   calls with no arguments work more reliably in .init, so stick the call
+   in another function.  */
+
+static void
+frame_dummy ()
+{
+  __register_frame (__EH_FRAME_BEGIN__);
+}
+
+static void
+init_dummy ()
+{
+  asm (INIT_SECTION_ASM_OP);
+  frame_dummy ();
+#ifdef FORCE_INIT_SECTION_ALIGN
+  FORCE_INIT_SECTION_ALIGN;
+#endif
+  asm (TEXT_SECTION_ASM_OP);
+}
+#endif /* EH_FRAME_SECTION_ASM_OP */
+
 #else  /* OBJECT_FORMAT_ELF */
 
 /* The function __do_global_ctors_aux is compiled twice (once in crtbegin.o
@@ -200,7 +232,9 @@ __do_global_ctors_aux ()    /* prologue goes in .init section */
 #ifdef HAS_INIT_SECTION
 /* This case is used by the Irix 6 port, which supports named sections but
    not an SVR4-style .fini section.  __do_global_dtors can be non-static
-   in this case because the -fini switch to ld binds strongly.  */
+   in this case because we protect it with -hidden_symbol.  */
+
+static char __EH_FRAME_BEGIN__[];
 static func_ptr __DTOR_LIST__[];
 void
 __do_global_dtors ()
@@ -208,6 +242,10 @@ __do_global_dtors ()
   func_ptr *p;
   for (p = __DTOR_LIST__ + 1; *p; p++)
     (*p) ();
+
+#ifdef EH_FRAME_SECTION_ASM_OP
+  __deregister_frame (__EH_FRAME_BEGIN__);
+#endif
 }
 #endif
 
@@ -244,6 +282,17 @@ asm (DTORS_SECTION_ASM_OP);        /* cc1 doesn't know that we are switching! */
 STATIC func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) };
 #endif
 
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Stick a label at the beginning of the frame unwind info so we can register
+   and deregister it with the exception handling library code.  */
+
+asm (EH_FRAME_SECTION_ASM_OP);
+#ifdef INIT_SECTION_ASM_OP
+STATIC
+#endif
+char __EH_FRAME_BEGIN__[] = { };
+#endif /* EH_FRAME_SECTION_ASM_OP */
+
 #endif /* defined(CRT_BEGIN) */
 
 #ifdef CRT_END
@@ -327,12 +376,16 @@ __do_global_ctors_aux ()  /* prologue goes in .text section */
 #ifdef HAS_INIT_SECTION
 /* This case is used by the Irix 6 port, which supports named sections but
    not an SVR4-style .init section.  __do_global_ctors can be non-static
-   in this case because the -init switch to ld binds strongly.  */
+   in this case because we protect it with -hidden_symbol.  */
+extern char __EH_FRAME_BEGIN__[];
 static func_ptr __CTOR_END__[];
 void
 __do_global_ctors ()
 {
   func_ptr *p;
+#ifdef EH_FRAME_SECTION_ASM_OP
+  __register_frame (__EH_FRAME_BEGIN__);
+#endif
   for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
     (*p) ();
 }
@@ -363,4 +416,13 @@ asm (DTORS_SECTION_ASM_OP);        /* cc1 doesn't know that we are switching! */
 STATIC func_ptr __DTOR_END__[1] = { (func_ptr) 0 };
 #endif
 
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Terminate the frame unwind info section with a 4byte 0 as a sentinel;
+   this would be the 'length' field in a real FDE.  */
+
+typedef unsigned int ui32 __attribute__ ((mode (SI)));
+asm (EH_FRAME_SECTION_ASM_OP);
+STATIC ui32 __FRAME_END__[] = { 0 };
+#endif /* EH_FRAME_SECTION */
+
 #endif /* defined(CRT_END) */
index 651133898d08e6ad887c69382568d10711d972a7..434d761afed797644f0dbf59f87f7869f350ded5 100644 (file)
@@ -136,6 +136,6 @@ do { fprintf (FILE, "\t%s\t", ASM_LONG);                            \
 
 /* If we have a definition of INCOMING_RETURN_ADDR_RTX, assume that
    the rest of the DWARF 2 frame unwind support is also provided.  */
-#ifdef INCOMING_RETURN_ADDR_RTX
-#define DWARF2_UNWIND_INFO
+#if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX)
+#define DWARF2_UNWIND_INFO 1
 #endif
index 2390e573297dbb3c549d590632275fadf04f00e9..4340344c868c4a8bb0ea593a709f6ce8235e1674 100644 (file)
@@ -496,7 +496,8 @@ enum dwarf_call_frame_info
     DW_CFA_MIPS_advance_loc8 = 0x1d,
 
     /* GNU extensions */
-    DW_CFA_GNU_window_save = 0x2d
+    DW_CFA_GNU_window_save = 0x2d,
+    DW_CFA_GNU_args_size = 0x2e
   };
 
 #define DW_CIE_ID        0xffffffff
index fac5135275006b938cc51bea171608d72b235888..6789f01af84780c71fdfd9bb1fa9839b7c41c22f 100644 (file)
@@ -20,19 +20,15 @@ You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-#include "config.h"
-#include "defaults.h"
-
 /* The first part of this file deals with the DWARF 2 frame unwind
    information, which is also used by the GCC efficient exception handling
    mechanism.  The second part, controlled only by an #ifdef
    DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
    information.  */
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-
+#include "config.h"
+#include "defaults.h"
 #include <stdio.h>
-#include <setjmp.h>
 #include "dwarf2.h"
 #include "tree.h"
 #include "flags.h"
@@ -48,6 +44,21 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /* #define NDEBUG 1 */
 #include "assert.h"
 
+/* Decide whether we want to emit frame unwind information for the current
+   translation unit.  */
+
+int
+dwarf2out_do_frame ()
+{
+  return (write_symbols == DWARF2_DEBUG
+#ifdef DWARF2_UNWIND_INFO
+         || (flag_exceptions && ! exceptions_via_longjmp)
+#endif
+         );
+}
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
 #ifndef __GNUC__
 #define inline
 #endif
@@ -191,6 +202,7 @@ static unsigned reg_number          PROTO((rtx));
    Theses may be overridden in the tm.h file (if necessary) for a particular
    assembler.  */
 
+#ifdef OBJECT_FORMAT_ELF
 #ifndef UNALIGNED_SHORT_ASM_OP
 #define UNALIGNED_SHORT_ASM_OP ".2byte"
 #endif
@@ -200,20 +212,12 @@ static unsigned reg_number                PROTO((rtx));
 #ifndef UNALIGNED_DOUBLE_INT_ASM_OP
 #define UNALIGNED_DOUBLE_INT_ASM_OP    ".8byte"
 #endif
+#endif /* OBJECT_FORMAT_ELF */
+
 #ifndef ASM_BYTE_OP
 #define ASM_BYTE_OP            ".byte"
 #endif
 
-#ifndef UNALIGNED_OFFSET_ASM_OP
-#define UNALIGNED_OFFSET_ASM_OP \
-  (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
-#endif
-
-#ifndef UNALIGNED_WORD_ASM_OP
-#define UNALIGNED_WORD_ASM_OP \
-  (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
-#endif
-
 /* Data and reference forms for relocatable data.  */
 #define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
 #define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
@@ -238,9 +242,6 @@ static unsigned reg_number          PROTO((rtx));
 #ifndef FRAME_SECTION
 #define FRAME_SECTION          ".debug_frame"
 #endif
-#if !defined (EH_FRAME_SECTION) && defined (ASM_OUTPUT_SECTION_NAME)
-#define EH_FRAME_SECTION       ".eh_frame"
-#endif
 
 #ifndef FUNC_BEGIN_LABEL
 #define FUNC_BEGIN_LABEL       "LFB"
@@ -262,6 +263,23 @@ static unsigned reg_number         PROTO((rtx));
   fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
 #endif
 
+#ifndef ASM_OUTPUT_DWARF_DATA1
+#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
+  fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, VALUE)
+#endif
+
+#ifdef UNALIGNED_INT_ASM_OP
+
+#ifndef UNALIGNED_OFFSET_ASM_OP
+#define UNALIGNED_OFFSET_ASM_OP \
+  (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
+#endif
+
+#ifndef UNALIGNED_WORD_ASM_OP
+#define UNALIGNED_WORD_ASM_OP \
+  (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
+#endif
+
 #ifndef ASM_OUTPUT_DWARF_DELTA2
 #define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2)                    \
  do {  fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP);             \
@@ -317,11 +335,6 @@ static unsigned reg_number         PROTO((rtx));
   } while (0)
 #endif
 
-#ifndef ASM_OUTPUT_DWARF_DATA1
-#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, VALUE)
-#endif
-
 #ifndef ASM_OUTPUT_DWARF_DATA2
 #define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
   fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) VALUE)
@@ -360,6 +373,43 @@ static unsigned reg_number         PROTO((rtx));
   } while (0)
 #endif
 
+#else /* UNALIGNED_INT_ASM_OP */
+
+/* We don't have unaligned support, let's hope the normal output works for
+   .debug_frame.  */
+
+#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
+  assemble_integer (gen_rtx (SYMBOL_REF, Pmode, LABEL), PTR_SIZE, 1)
+
+#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
+  assemble_integer (gen_rtx (SYMBOL_REF, SImode, LABEL), 4, 1)
+
+#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2)                    \
+  assemble_integer (gen_rtx (MINUS, HImode,                            \
+                            gen_rtx (SYMBOL_REF, Pmode, LABEL1),       \
+                            gen_rtx (SYMBOL_REF, Pmode, LABEL2)),      \
+                   2, 1)
+  
+#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2)                    \
+  assemble_integer (gen_rtx (MINUS, SImode,                            \
+                            gen_rtx (SYMBOL_REF, Pmode, LABEL1),       \
+                            gen_rtx (SYMBOL_REF, Pmode, LABEL2)),      \
+                   4, 1)
+
+#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2)                        \
+  assemble_integer (gen_rtx (MINUS, Pmode,                             \
+                            gen_rtx (SYMBOL_REF, Pmode, LABEL1),       \
+                            gen_rtx (SYMBOL_REF, Pmode, LABEL2)),      \
+                   PTR_SIZE, 1)
+
+#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
+  ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2)
+
+#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
+  assemble_integer (GEN_INT (VALUE), 4, 1)
+
+#endif /* UNALIGNED_INT_ASM_OP */
+
 /* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
    newline is produced.  When flag_verbose_asm is asserted, we add commnetary
    at the end of the line, so we must avoid output of a newline here.  */
@@ -404,6 +454,14 @@ static unsigned reg_number         PROTO((rtx));
 #define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
 #endif
 
+/* Hook used by __throw.  */
+
+rtx
+expand_builtin_dwarf_fp_regnum ()
+{
+  return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
+}
+
 /* The offset from the incoming value of %sp to the top of the stack frame
    for the current function.  */
 #ifndef INCOMING_FRAME_SP_OFFSET
@@ -497,6 +555,8 @@ dwarf_cfi_name (cfi_opc)
     /* GNU extensions */
     case DW_CFA_GNU_window_save:
       return "DW_CFA_GNU_window_save";
+    case DW_CFA_GNU_args_size:
+      return "DW_CFA_GNU_args_size";
 
     default:
       return "DW_CFA_<unknown>";
@@ -638,6 +698,9 @@ static long cfa_offset;
 static unsigned cfa_store_reg;
 static long cfa_store_offset;
 
+/* The running total of the size of arguments pushed onto the stack.  */
+static long args_size;
+
 /* Entry point to update the canonical frame address (CFA).
    LABEL is passed to add_fde_cfi.  The value of CFA is now to be
    calculated from REG+OFFSET.  */
@@ -743,6 +806,20 @@ dwarf2out_window_save (label)
   add_fde_cfi (label, cfi);
 }
 
+/* Add a CFI to update the running total of the size of arguments
+   pushed onto the stack.  */
+
+void
+dwarf2out_args_size (label, size)
+     char *label;
+     long size;
+{
+  register dw_cfi_ref cfi = new_cfi ();
+  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+  add_fde_cfi (label, cfi);
+}
+
 /* Entry point for saving a register to the stack.  REG is the GCC register
    number.  LABEL and OFFSET are passed to reg_save.  */
 
@@ -828,6 +905,67 @@ initial_return_save (rtl)
   reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset);
 }
 
+/* Check INSN to see if it looks like a push or a stack adjustment, and
+   make a note of it if it does.  EH uses this information to find out how
+   much extra space it needs to pop off the stack.  */
+
+static void
+dwarf2out_stack_adjust (insn)
+     rtx insn;
+{
+  rtx src, dest;
+  enum rtx_code code;
+  long offset;
+  char *label;
+
+  if (GET_CODE (insn) != SET)
+    return;
+
+  src = SET_SRC (insn);
+  dest = SET_DEST (insn);
+  if (dest == stack_pointer_rtx)
+    {
+      /* (set (reg sp) (plus (reg sp) (const_int))) */
+      code = GET_CODE (src);
+      if (! (code == PLUS || code == MINUS)
+         || XEXP (src, 0) != stack_pointer_rtx
+         || GET_CODE (XEXP (src, 1)) != CONST_INT)
+       return;
+
+      offset = INTVAL (XEXP (src, 1));
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      /* (set (mem (pre_dec (reg sp))) (foo)) */
+      src = XEXP (dest, 0);
+      code = GET_CODE (src);
+
+      if (! (code == PRE_DEC || code == PRE_INC)
+         || XEXP (src, 0) != stack_pointer_rtx)
+       return;
+
+      offset = GET_MODE_SIZE (GET_MODE (dest));
+    }
+  else
+    return;
+
+  if (code == PLUS || code == PRE_INC)
+    offset = -offset;
+  if (cfa_reg == STACK_POINTER_REGNUM)
+    cfa_offset += offset;
+
+#ifndef STACK_GROWS_DOWNWARD
+  offset = -offset;
+#endif
+  args_size += offset;
+  if (args_size < 0)
+    args_size = 0;
+
+  label = dwarf2out_cfi_label ();
+  dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
+  dwarf2out_args_size (label, args_size);
+}
+
 /* Record call frame debugging information for INSN, which either
    sets SP or FP (adjusting how we calculate the frame address) or saves a
    register to the stack.  If INSN is NULL_RTX, initialize our state.  */
@@ -857,6 +995,12 @@ dwarf2out_frame_debug (insn)
       return;
     }
 
+  if (! RTX_FRAME_RELATED_P (insn))
+    {
+      dwarf2out_stack_adjust (PATTERN (insn));
+      return;
+    }
+
   label = dwarf2out_cfi_label ();
     
   insn = PATTERN (insn);
@@ -903,13 +1047,21 @@ dwarf2out_frame_debug (insn)
                  abort ();
                }
 
+             if (XEXP (src, 0) == hard_frame_pointer_rtx)
+               {
+                 /* Restoring SP from FP in the epilogue.  */
+                 assert (cfa_reg == HARD_FRAME_POINTER_REGNUM);
+                 cfa_reg = STACK_POINTER_REGNUM;
+               }
+             else
+               assert (XEXP (src, 0) == stack_pointer_rtx);
+
              if (GET_CODE (src) == PLUS)
                offset = -offset;
              if (cfa_reg == STACK_POINTER_REGNUM)
                cfa_offset += offset;
              if (cfa_store_reg == STACK_POINTER_REGNUM)
                cfa_store_offset += offset;
-             assert (XEXP (src, 0) == stack_pointer_rtx);
            }
          else
            {
@@ -953,7 +1105,7 @@ dwarf2out_frame_debug (insn)
        case PRE_INC:
        case PRE_DEC:
          offset = GET_MODE_SIZE (GET_MODE (dest));
-         if (GET_CODE (src) == PRE_INC)
+         if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
            offset = -offset;
 
          assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM);
@@ -1196,12 +1348,29 @@ output_cfi (cfi, fde)
          break;
        case DW_CFA_GNU_window_save:
          break;
+       case DW_CFA_GNU_args_size:
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+          fputc ('\n', asm_out_file);
+         break;
        default:
          break;
        }
      }
 }
 
+#if !defined (EH_FRAME_SECTION)
+#if defined (EH_FRAME_SECTION_ASM_OP)
+#define EH_FRAME_SECTION() eh_frame_section();
+#else
+#if defined (ASM_OUTPUT_SECTION_NAME)
+#define EH_FRAME_SECTION()                             \
+  do {                                                 \
+      named_section (NULL_TREE, ".eh_frame", 0);       \
+  } while (0)
+#endif
+#endif
+#endif
+
 /* Output the call frame information used to used to record information
    that relates to calculating the frame pointer, and records the
    location of saved registers.  */
@@ -1231,9 +1400,13 @@ output_call_frame_info (for_eh)
   if (for_eh)
     {
 #ifdef EH_FRAME_SECTION
-      ASM_OUTPUT_SECTION_NAME (asm_out_file, NULL_TREE, EH_FRAME_SECTION, 0);
+      EH_FRAME_SECTION ();
 #else
+      tree label = (tree) get_file_function_name ('F');
+
       data_section ();
+      ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+      ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
 #endif
       assemble_label ("__FRAME_BEGIN__");
     }
@@ -1272,9 +1445,9 @@ output_call_frame_info (for_eh)
   fputc ('\n', asm_out_file);
   if (eh_ptr)
     {
-      /* The "z" augmentation was defined by SGI; the FDE contains a pointer
+      /* The FDE contains a pointer
         to the exception region info for the frame.  */
-      ASM_OUTPUT_DWARF_STRING (asm_out_file, "z");
+      ASM_OUTPUT_DWARF_STRING (asm_out_file, "e");
       if (flag_verbose_asm)
        fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
     }
@@ -1302,14 +1475,6 @@ output_call_frame_info (for_eh)
     fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
 
   fputc ('\n', asm_out_file);
-  if (eh_ptr)
-    {
-      output_uleb128 (0);
-      if (flag_verbose_asm)
-       fprintf (asm_out_file, "\t%s CIE augmentation fields length",
-                ASM_COMMENT_START);
-      fputc ('\n', asm_out_file);
-    }
 
   for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
     output_cfi (cfi, NULL);
@@ -1355,19 +1520,9 @@ output_call_frame_info (for_eh)
       fputc ('\n', asm_out_file);
       if (eh_ptr)
        {
-         output_uleb128 (PTR_SIZE);
-         if (flag_verbose_asm)
-           fprintf (asm_out_file, "\t%s FDE augmentation fields length",
-                    ASM_COMMENT_START);
-         fputc ('\n', asm_out_file);
-
          /* For now, a pointer to the translation unit's info will do.
             ??? Eventually this should point to the function's info.  */
-         if (exception_table_p ())
-           ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
-         else
-           ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
-
+         ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
          if (flag_verbose_asm)
            fprintf (asm_out_file, "\t%s pointer to exception region info",
                     ASM_COMMENT_START);
@@ -1399,16 +1554,6 @@ output_call_frame_info (for_eh)
 #endif
 }
 
-/* Decide whether we want to emit frame unwind information for the current
-   translation unit.  */
-
-int
-dwarf2out_do_frame ()
-{
-  return (write_symbols == DWARF2_DEBUG
-         || (flag_exceptions && ! exceptions_via_longjmp));
-}
-
 /* Output a marker (i.e. a label) for the beginning of a function, before
    the prologue.  */
 
@@ -1443,6 +1588,8 @@ dwarf2out_begin_prologue ()
   fde->dw_fde_current_label = NULL;
   fde->dw_fde_end = NULL;
   fde->dw_fde_cfi = NULL;
+
+  args_size = 0;
 }
 
 /* Output a marker (i.e. a label) for the absolute end of the generated code
@@ -9142,10 +9289,6 @@ dwarf2out_init (asm_out_file, main_input_filename)
   gen_compile_unit_die (main_input_filename);
 
   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
-
-  /* Initialize the frame unwind information.  Eventually this should be
-     called from compile_file instead.  */
-  dwarf2out_frame_init ();
 }
 
 /* Output stuff that dwarf requires at the end of every file,
@@ -9202,10 +9345,6 @@ dwarf2out_finish ()
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
 #endif
 
-  /* Output the frame unwind information.  Eventually this should be called
-     from compile_file instead.  */
-  dwarf2out_frame_finish ();
-
   /* Output the source line correspondence table.  */
   if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
     {
index 14bb2349fb0213788400ba4eb89fb6dcfd0ceafb..71c49c25a77178c8c5d4e3b0b732aebaf45cdf25 100644 (file)
@@ -281,3 +281,15 @@ extern int protect_cleanup_actions_with_terminate;
 #ifdef TREE_CODE
 extern tree protect_with_terminate             PROTO((tree));
 #endif
+
+/* Various hooks for the DWARF 2 __throw routine.  */
+
+void expand_builtin_unwind_init                PROTO((void));
+rtx expand_builtin_dwarf_fp_regnum     PROTO((void));
+rtx expand_builtin_eh_stub             PROTO((void));
+#ifdef TREE_CODE
+rtx expand_builtin_frob_return_addr    PROTO((tree));
+rtx expand_builtin_extract_return_addr PROTO((tree));
+void expand_builtin_set_return_addr_reg PROTO((tree));
+void expand_builtin_set_eh_regs                PROTO((tree, tree));
+#endif
index a7fe94d38cb2ebb83dcc68bfa2680ac8de895efe..48e1a0878f771de7b0f7b33930ab2d6405618773 100644 (file)
@@ -955,9 +955,9 @@ final_start_function (first, file, optimize)
     last_linenum = high_block_linenum = high_function_linenum
       = NOTE_LINE_NUMBER (first);
 
-#ifdef DWARF2_DEBUGGING_INFO
+#if defined (DWARF2_UNWIND_INFO)
   /* Output DWARF definition of the function.  */
-  if (write_symbols == DWARF2_DEBUG)
+  if (dwarf2out_do_frame ())
     dwarf2out_begin_prologue ();
 #endif
 
@@ -992,6 +992,11 @@ final_start_function (first, file, optimize)
     profile_function (file);
 #endif /* PROFILE_BEFORE_PROLOGUE */
 
+#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
+  if (dwarf2out_do_frame ())
+    dwarf2out_frame_debug (NULL_RTX);
+#endif
+
 #ifdef FUNCTION_PROLOGUE
   /* First output the function prologue: code to set up the stack frame.  */
   FUNCTION_PROLOGUE (file, get_frame_size ());
@@ -1142,8 +1147,8 @@ final_end_function (first, file, optimize)
     dwarfout_end_epilogue ();
 #endif
 
-#ifdef DWARF2_DEBUGGING_INFO
-  if (write_symbols == DWARF2_DEBUG)
+#if defined (DWARF2_UNWIND_INFO)
+  if (dwarf2out_do_frame ())
     dwarf2out_end_epilogue ();
 #endif
 
@@ -1265,11 +1270,6 @@ final (first, file, optimize, prescan)
   last_ignored_compare = 0;
   new_block = 1;
 
-#if defined (DWARF2_DEBUGGING_INFO) && defined (HAVE_prologue)
-  if (write_symbols == DWARF2_DEBUG)
-    dwarf2out_frame_debug (NULL_RTX);
-#endif
-
   check_exception_handler_labels ();
 
   /* Make a map indicating which line numbers appear in this function.
@@ -2171,12 +2171,21 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
        output_asm_insn (template, recog_operand);
 
-#if defined (DWARF2_DEBUGGING_INFO) && defined (HAVE_prologue)
+#if defined (DWARF2_UNWIND_INFO)
+#if !defined (ACCUMULATE_OUTGOING_ARGS)
+       /* If we push arguments, we need to check all insns for stack
+          adjustments.  */
+       if (dwarf2out_do_frame ())
+         dwarf2out_frame_debug (insn);
+#else
+#if defined (HAVE_prologue)
        /* If this insn is part of the prologue, emit DWARF v2
           call frame info.  */
-       if (write_symbols == DWARF2_DEBUG && RTX_FRAME_RELATED_P (insn))
+       if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
          dwarf2out_frame_debug (insn);
 #endif
+#endif
+#endif
 
 #if 0
        /* It's not at all clear why we did this and doing so interferes
diff --git a/gcc/frame.c b/gcc/frame.c
new file mode 100644 (file)
index 0000000..a9e5e23
--- /dev/null
@@ -0,0 +1,607 @@
+/* Subroutines needed for unwinding stack frames for exception handling.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   Contributed by Jason Merrill <jason@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* It is incorrect to include config.h here, because this file is being
+   compiled for the target, and hence definitions concerning only the host
+   do not apply.  */
+
+#include "tconfig.h"
+#include "defaults.h"
+
+#ifdef DWARF2_UNWIND_INFO
+#include "dwarf2.h"
+#include "frame.h"
+#include <stddef.h>
+
+/* Don't use `fancy_abort' here even if config.h says to use it.  */
+#ifdef abort
+#undef abort
+#endif
+
+/* Some types used by the DWARF 2 spec.  */
+
+typedef unsigned int uword __attribute__ ((mode (SI)));
+typedef unsigned int uaddr __attribute__ ((mode (pointer)));
+typedef int saddr __attribute__ ((mode (pointer)));
+typedef unsigned char ubyte;
+
+/* The first few fields of a CIE.  The CIE_id field is 0xffffffff for a CIE,
+   to distinguish it from a valid FDE.  FDEs are aligned to an addressing
+   unit boundary, but the fields within are unaligned.  */
+
+struct dwarf_cie {
+  uword length;
+  uaddr CIE_id;
+  ubyte version;
+  char augmentation[0];
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+/* The first few fields of an FDE.  */
+
+struct dwarf_fde {
+  uword length;
+  struct dwarf_cie* CIE_pointer;
+  void* pc_begin;
+  uaddr pc_range;
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+typedef struct dwarf_fde fde;
+
+/* The representation for an "object" to be searched for frame unwind info.
+   For targets with named sections, one object is an executable or shared
+   library; for other targets, one object is one translation unit.  */
+
+struct object {
+  void *pc_begin;
+  void *pc_end;
+  fde *fde_begin;
+  fde ** fde_array;
+  size_t count;
+  struct object *next;
+};
+
+static struct object *objects;
+
+/* The information we care about from a CIE.  */
+
+struct cie_info {
+  char *augmentation;
+  int code_align;
+  int data_align;
+  unsigned ra_regno;
+};
+
+/* The current unwind state, plus a saved copy for DW_CFA_remember_state.  */
+
+struct frame_state_internal
+{
+  struct frame_state s;
+  struct frame_state_internal *saved_state;
+};
+\f  
+/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
+   by R, and return the new value of BUF.  */
+
+static void *
+decode_uleb128 (unsigned char *buf, unsigned *r)
+{
+  unsigned shift = 0;
+  unsigned result = 0;
+
+  while (1)
+    {
+      unsigned byte = *buf++;
+      result |= (byte & 0x7f) << shift;
+      if ((byte & 0x80) == 0)
+       break;
+      shift += 7;
+    }
+  *r = result;
+  return buf;
+}
+
+/* Decode the signed LEB128 constant at BUF into the variable pointed to
+   by R, and return the new value of BUF.  */
+
+static void *
+decode_sleb128 (unsigned char *buf, int *r)
+{
+  unsigned shift = 0;
+  unsigned result = 0;
+  unsigned byte;
+
+  while (1)
+    {
+      byte = *buf++;
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+       break;
+    }
+  if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
+    result |= - (1 << shift);
+
+  *r = result;
+  return buf;
+}
+
+/* Read unaligned data from the instruction buffer.  */
+
+union unaligned {
+  void *p;
+  unsigned b2 __attribute__ ((mode (HI)));
+  unsigned b4 __attribute__ ((mode (SI)));
+  unsigned b8 __attribute__ ((mode (DI)));
+} __attribute__ ((packed));
+static inline void *
+read_pointer (void *p)
+{ union unaligned *up = p; return up->p; }
+static inline unsigned
+read_1byte (void *p)
+{ return *(unsigned char *)p; }
+static inline unsigned
+read_2byte (void *p)
+{ union unaligned *up = p; return up->b2; }
+static inline unsigned
+read_4byte (void *p)
+{ union unaligned *up = p; return up->b4; }
+static inline unsigned long
+read_8byte (void *p)
+{ union unaligned *up = p; return up->b8; }
+\f
+/* Ordering function for FDEs.  Functions can't overlap, so we just compare
+   their starting addresses.  */
+
+static inline saddr
+fde_compare (fde *x, fde *y)
+{
+  return (saddr)x->pc_begin - (saddr)y->pc_begin;
+}
+
+/* Return the address of the FDE after P.  */
+
+static inline fde *
+next_fde (fde *p)
+{
+  return (fde *)(((char *)p) + p->length + sizeof (p->length));
+}
+
+/* One iteration of an insertion sort, for adding new FDEs to the array.
+   Usually the new FDE will go in at the end, so we can expect close to
+   O(n) performance.  If this turns out to be overly optimistic, we can have
+   the linker sort the FDEs so we don't have to do it at run time.  */
+
+static void
+fde_insert (fde **array, size_t i, fde *this_fde)
+{
+  array[i] = this_fde;
+
+  for (; i > 0 && fde_compare (array[i], array[i-1]) < 0; --i)
+    {
+      this_fde = array[i];
+      array[i] = array[i-1];
+      array[i-1] = this_fde;
+    }
+}
+
+static size_t
+count_fdes (fde *this_fde)
+{
+  size_t count;
+
+  for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs.  */
+      if ((uaddr)(this_fde->CIE_pointer) == (uaddr)-1)
+       continue;
+
+      ++count;
+    }
+
+  return count;
+}
+
+static void
+add_fdes (fde *this_fde, fde **array, size_t *i_ptr,
+         void **beg_ptr, void **end_ptr)
+{
+  size_t i = *i_ptr;
+  void *pc_begin = *beg_ptr;
+  void *pc_end = *end_ptr;
+
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs.  */
+      if ((uaddr)(this_fde->CIE_pointer) == (uaddr)-1)
+       continue;
+
+      fde_insert (array, i++, this_fde);
+
+      if (this_fde->pc_begin < pc_begin)
+       pc_begin = this_fde->pc_begin;
+      if (this_fde->pc_begin + this_fde->pc_range > pc_end)
+       pc_end = this_fde->pc_begin + this_fde->pc_range;
+    }
+
+  *i_ptr = i;
+  *beg_ptr = pc_begin;
+  *end_ptr = pc_end;
+}
+
+/* Set up a sorted array of pointers to FDEs for a loaded object.  We
+   count up the entries before allocating the array because it's likely to
+   be faster.  */
+
+static void
+frame_init (struct object* ob)
+{
+  fde *this_fde;
+  size_t count;
+  fde **array;
+  void *pc_begin, *pc_end;
+
+  if (ob->fde_array)
+    {
+      fde **p = ob->fde_array;
+      for (count = 0; *p; ++p)
+       count += count_fdes (*p);
+    }
+  else
+    count = count_fdes (ob->fde_begin);
+
+  ob->count = count;
+  array = (fde **) malloc (sizeof (fde *) * count);
+
+  pc_begin = (void*)(uaddr)-1;
+  pc_end = 0;
+  count = 0;
+
+  if (ob->fde_array)
+    {
+      fde **p = ob->fde_array;
+      for (; *p; ++p)
+       add_fdes (*p, array, &count, &pc_begin, &pc_end);
+    }
+  else
+    add_fdes (ob->fde_begin, array, &count, &pc_begin, &pc_end);
+
+  ob->fde_array = array;
+  ob->pc_begin = pc_begin;
+  ob->pc_end = pc_end;
+}
+
+/* Return a pointer to the FDE for the function containing PC.  */
+
+static fde *
+find_fde (void *pc)
+{
+  struct object *ob;
+  size_t lo, hi;
+
+  for (ob = objects; ob; ob = ob->next)
+    {
+      if (ob->pc_begin == 0)
+       frame_init (ob);
+      if (pc >= ob->pc_begin && pc < ob->pc_end)
+       break;
+    }
+
+  if (ob == 0)
+    return 0;
+
+  /* Standard binary search algorithm.  */
+  for (lo = 0, hi = ob->count; lo < hi; )
+    {
+      size_t i = (lo + hi) / 2;
+      fde *f = ob->fde_array[i];
+
+      if (pc < f->pc_begin)
+       hi = i;
+      else if (pc > f->pc_begin + f->pc_range)
+       lo = i + 1;
+      else
+       return f;
+    }
+
+  return 0;
+}
+\f
+/* Extract any interesting information from the CIE for the translation
+   unit F belongs to.  */
+
+static void *
+extract_cie_info (fde *f, struct cie_info *c)
+{
+  void *p;
+  int i;
+
+  c->augmentation = f->CIE_pointer->augmentation;
+
+  if (strcmp (c->augmentation, "") != 0
+      && strcmp (c->augmentation, "e") != 0
+      && c->augmentation[0] != 'z')
+    return 0;
+
+  p = c->augmentation + strlen (c->augmentation) + 1;
+
+  p = decode_uleb128 (p, &c->code_align);
+  p = decode_sleb128 (p, &c->data_align);
+  c->ra_regno = *(unsigned char *)p++;
+
+  /* If the augmentation starts with 'z', we now see the length of the
+     augmentation fields.  */
+  if (c->augmentation[0] == 'z')
+    {
+      p = decode_uleb128 (p, &i);
+      p += i;
+    }
+
+  return p;
+}
+
+/* Decode one instruction's worth of of DWARF 2 call frame information.
+   Used by __frame_state_for.  Takes pointers P to the instruction to
+   decode, STATE to the current register unwind information, INFO to the
+   current CIE information, and PC to the current PC value.  Returns a
+   pointer to the next instruction.  */
+
+static void *
+execute_cfa_insn (void *p, struct frame_state_internal *state,
+                 struct cie_info *info, void **pc)
+{
+  unsigned insn = *(unsigned char *)p++;
+  unsigned reg;
+  int offset;
+
+  if (insn & DW_CFA_advance_loc)
+    *pc += ((insn & 0x3f) * info->code_align);
+  else if (insn & DW_CFA_offset)
+    {
+      reg = (insn & 0x3f);
+      p = decode_uleb128 (p, &offset);
+      offset *= info->data_align;
+      state->s.saved[reg] = REG_SAVED_OFFSET;
+      state->s.reg_or_offset[reg] = offset;
+    }
+  else if (insn & DW_CFA_restore)
+    {
+      reg = (insn & 0x3f);
+      state->s.saved[reg] = REG_UNSAVED;
+    }
+  else switch (insn)
+    {
+    case DW_CFA_set_loc:
+      *pc = read_pointer (p);
+      p += sizeof (void *);
+      break;
+    case DW_CFA_advance_loc1:
+      *pc += read_1byte (p);
+      p += 1;
+      break;
+    case DW_CFA_advance_loc2:
+      *pc += read_2byte (p);
+      p += 2;
+      break;
+    case DW_CFA_advance_loc4:
+      *pc += read_4byte (p);
+      p += 4;
+      break;
+
+    case DW_CFA_offset_extended:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      offset *= info->data_align;
+      state->s.saved[reg] = REG_SAVED_OFFSET;
+      state->s.reg_or_offset[reg] = offset;
+      break;
+    case DW_CFA_restore_extended:
+      p = decode_uleb128 (p, &reg);
+      state->s.saved[reg] = REG_UNSAVED;
+      break;
+
+    case DW_CFA_undefined:
+    case DW_CFA_same_value:
+    case DW_CFA_nop:
+      break;
+
+    case DW_CFA_register:
+      {
+       unsigned reg2;
+       p = decode_uleb128 (p, &reg);
+       p = decode_uleb128 (p, &reg2);
+       state->s.saved[reg] = REG_SAVED_REG;
+       state->s.reg_or_offset[reg] = reg2;
+      }
+      break;
+
+    case DW_CFA_def_cfa:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      state->s.cfa_reg = reg;
+      state->s.cfa_offset = offset;
+      break;
+    case DW_CFA_def_cfa_register:
+      p = decode_uleb128 (p, &reg);
+      state->s.cfa_reg = reg;
+      break;
+    case DW_CFA_def_cfa_offset:
+      p = decode_uleb128 (p, &offset);
+      state->s.cfa_offset = offset;
+      break;
+      
+    case DW_CFA_remember_state:
+      {
+       struct frame_state_internal *save =
+         (struct frame_state_internal *)
+         malloc (sizeof (struct frame_state_internal));
+       memcpy (save, state, sizeof (struct frame_state_internal));
+       state->saved_state = save;
+      }
+      break;
+    case DW_CFA_restore_state:
+      {
+       struct frame_state_internal *save = state->saved_state;
+       memcpy (state, save, sizeof (struct frame_state_internal));
+       free (save);
+      }
+      break;
+
+      /* FIXME: Hardcoded for SPARC register window configuration.  */
+    case DW_CFA_GNU_window_save:
+      for (reg = 16; reg < 32; ++reg)
+       {
+         state->s.saved[reg] = REG_SAVED_OFFSET;
+         state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
+       }
+      break;
+
+    case DW_CFA_GNU_args_size:
+      p = decode_uleb128 (p, &offset);
+      state->s.args_size = offset;
+      break;
+
+    default:
+      abort ();
+    }
+  return p;
+}
+\f
+/* Called from crtbegin.o to register the unwind info for an object.  */
+
+void
+__register_frame (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+
+  ob->fde_begin = begin;
+
+  ob->pc_begin = ob->pc_end = 0;
+  ob->fde_array = 0;
+  ob->count = 0;
+
+  ob->next = objects;
+  objects = ob;
+}
+
+/* Similar, but BEGIN is actually a pointer to a table of unwind entries
+   for different translation units.  Called from the file generated by
+   collect2.  */
+
+void
+__register_frame_table (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+
+  ob->fde_begin = begin;
+  ob->fde_array = begin;
+
+  ob->pc_begin = ob->pc_end = 0;
+  ob->count = 0;
+
+  ob->next = objects;
+  objects = ob;
+}
+
+/* Called from crtend.o to deregister the unwind info for an object.  */
+
+void
+__deregister_frame (void *begin)
+{
+  struct object **p = &objects;
+
+  while (*p)
+    {
+      if ((*p)->fde_begin == begin)
+       {
+         struct object *ob = *p;
+         *p = (*p)->next;
+
+         if (ob->fde_array)
+           free (ob->fde_array);
+         free (ob);
+
+         return;
+       }
+      p = &((*p)->next);
+    }
+  abort ();
+}
+
+/* Called from __throw to find the registers to restore for a given
+   PC_TARGET.  The caller should allocate a local variable of `struct
+   frame_state' (declared in frame.h) and pass its address to STATE_IN.  */
+
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in)
+{
+  fde *f;
+  void *insn, *end, *pc;
+  struct cie_info info;
+  struct frame_state_internal state;
+
+  f = find_fde (pc_target);
+  if (f == 0)
+    return 0;
+
+  insn = extract_cie_info (f, &info);
+  if (insn == 0)
+    return 0;
+
+  memset (&state, 0, sizeof (state));
+  state.s.retaddr_column = info.ra_regno;
+
+  /* First decode all the insns in the CIE.  */
+  end = next_fde ((fde*) f->CIE_pointer);
+  while (insn < end)
+    insn = execute_cfa_insn (insn, &state, &info, 0);
+
+  insn = ((fde *)f) + 1;
+
+  if (info.augmentation[0] == 'z')
+    {
+      int i;
+      insn = decode_uleb128 (insn, &i);
+      insn += i;
+    }
+  else if (strcmp (info.augmentation, "e") == 0)
+    {
+      state.s.eh_ptr = read_pointer (insn);
+      insn += sizeof (void *);
+    }
+
+  /* Then the insns in the FDE up to our target PC.  */
+  end = next_fde (f);
+  pc = f->pc_begin;
+  while (insn < end && pc < pc_target)
+    insn = execute_cfa_insn (insn, &state, &info, &pc);
+
+  memcpy (state_in, &state.s, sizeof (state.s));
+  return state_in;
+}
+#endif /* DWARF2_UNWIND_INFO */
index d5e4c9fffa4fe3721b9c4cd1904dc320538b1f93..0b95dbf1850b2ba0963bcd541472ef0b9cbccc6a 100644 (file)
@@ -5987,6 +5987,26 @@ A C expression to output text to mark the end of an exception region.
 
 This macro need not be defined on most platforms.
 
+@findex EXCEPTION_SECTION
+@item EXCEPTION_SECTION ()
+A C expression to switch to the section in which the main
+exception table is to be placed (@pxref{Sections}).  The default is a
+section named @code{.gcc_except_table} on machines that support named
+sections via @code{ASM_OUTPUT_SECTION_NAME}, otherwise if @samp{-fpic}
+or @samp{-fPIC} is in effect, the @code{data_section}, otherwise the
+@code{readonly_data_section}.
+
+@findex EH_FRAME_SECTION_ASM_OP
+@item EH_FRAME_SECTION_ASM_OP
+If defined, a C string constant for the assembler operation to switch to
+the section for exception handling frame unwind information.  If not
+defined, GNU CC will provide a default definition if the target supports
+named sections.  @file{crtstuff.c} uses this macro to switch to the
+appropriate section.
+
+You should define this symbol if your target supports DWARF 2 frame
+unwind information and the default definition does not work.
+
 @findex OMIT_EH_TABLE
 @item OMIT_EH_TABLE ()
 A C expression that is nonzero if the normal exception table output
@@ -6011,6 +6031,23 @@ for details on when to define this, and how.
 @item MASK_RETURN_ADDR
 An rtx used to mask the return address found via RETURN_ADDR_RTX, so
 that it does not contain any extraneous set bits in it.
+
+@findex DWARF2_UNWIND_INFO
+@item DWARF2_UNWIND_INFO
+Define this macro to 0 if your target supports DWARF 2 frame unwind
+information, but it does not yet work with exception handling.
+Otherwise, if your target supports this information (if it defines
+@samp{INCOMING_RETURN_ADDR_RTX} and either @samp{UNALIGNED_INT_ASM_OP}
+or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of
+1.
+
+If this macro is defined to 1, the DWARF 2 unwinder will be the default
+exception handling mechanism; otherwise, setjmp/longjmp will be used by
+default.
+
+If this macro is defined to anything, the DWARF 2 unwinder will be used
+instead of inline unwinders and __unwind_function in the non-setjmp case.
+
 @end table
 
 @node Alignment Output
index d1ddf202fee70907fb62df3dc805b2f16f215f16..2658e5b5ee9121fd4c817e8ec977f50e22a802de 100644 (file)
@@ -2463,6 +2463,10 @@ compile_file (name)
   if (write_symbols == DWARF_DEBUG)
     TIMEVAR (symout_time, dwarfout_init (asm_out_file, main_input_filename));
 #endif
+#ifdef DWARF2_UNWIND_INFO
+  if (dwarf2out_do_frame ())
+    dwarf2out_frame_init ();
+#endif
 #ifdef DWARF2_DEBUGGING_INFO
   if (write_symbols == DWARF2_DEBUG)
     TIMEVAR (symout_time, dwarf2out_init (asm_out_file, main_input_filename));
@@ -2597,8 +2601,7 @@ compile_file (name)
     /* Now that all possible functions have been output, we can dump
        the exception table.  */
 
-    if (exception_table_p ())
-      output_exception_table ();
+    output_exception_table ();
 
     for (i = 0; i < len; i++)
       {
@@ -2713,6 +2716,11 @@ compile_file (name)
             });
 #endif
 
+#ifdef DWARF2_UNWIND_INFO
+  if (dwarf2out_do_frame ())
+    dwarf2out_frame_finish ();
+#endif
+
 #ifdef DWARF2_DEBUGGING_INFO
   if (write_symbols == DWARF2_DEBUG)
     TIMEVAR (symout_time,
index 5e5087fa14ea78672b75e0e8f2613be9d5949401..d594bd92ccda16cab18bc01e24fe529c92077c98 100644 (file)
@@ -101,6 +101,16 @@ enum built_in_function
   BUILT_IN_SETJMP,
   BUILT_IN_LONGJMP,
 
+  /* Various hooks for the DWARF 2 __throw routine.  */
+  BUILT_IN_FP, BUILT_IN_SP,
+  BUILT_IN_UNWIND_INIT,
+  BUILT_IN_DWARF_FP_REGNUM,
+  BUILT_IN_FROB_RETURN_ADDR,
+  BUILT_IN_EXTRACT_RETURN_ADDR,
+  BUILT_IN_SET_RETURN_ADDR_REG,
+  BUILT_IN_EH_STUB,
+  BUILT_IN_SET_EH_REGS,
+
   /* C++ extensions */
   BUILT_IN_NEW,
   BUILT_IN_VEC_NEW,
index 9d245830f44e88cdf35dd4a1092d88082d936f85..351524dec558415367b883b6f680a7cebc0575a1 100644 (file)
@@ -170,6 +170,9 @@ static enum in_section { no_section, in_text, in_data, in_named
 #ifdef BSS_SECTION_ASM_OP
   , in_bss
 #endif
+#ifdef EH_FRAME_SECTION_ASM_OP
+  , in_eh_frame
+#endif
 #ifdef EXTRA_SECTIONS
   , EXTRA_SECTIONS
 #endif
@@ -401,6 +404,18 @@ asm_output_aligned_bss (file, decl, name, size, align)
 
 #endif /* BSS_SECTION_ASM_OP */
 
+#ifdef EH_FRAME_SECTION_ASM_OP
+void
+eh_frame_section ()
+{
+  if (in_section != in_eh_frame)
+    {
+      fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP);
+      in_section = in_eh_frame;
+    }
+} 
+#endif
+
 /* Switch to the section for function DECL.
 
    If DECL is NULL_TREE, switch to the text section.
@@ -461,15 +476,15 @@ variable_section (decl, reloc)
 void
 exception_section ()
 {
+#if defined (EXCEPTION_SECTION)
+  EXCEPTION_SECTION ();
+#else
 #ifdef ASM_OUTPUT_SECTION_NAME
   named_section (NULL_TREE, ".gcc_except_table", 0);
 #else
   if (flag_pic)
     data_section ();
   else
-#if defined (EXCEPTION_SECTION)
-    EXCEPTION_SECTION ();
-#else
     readonly_data_section ();
 #endif
 #endif