#! /bin/sh -e
## 121_ia64_unwind_fixes.dpatch
##
## DP: Description: Fix unwind handling on ia64
## DP: Author: David Mosberger and James E. Wilson
## DP: Upstream status: Committed to trunk.
## DP: Date: 2004-10-25 / 2004-09-21
## DP: URL: http://sources.redhat.com/ml/binutils-cvs/2004-10/msg00189.html
## DP: URL: http://sources.redhat.com/ml/binutils-cvs/2004-09/msg00111.html
## DP: URL: http://sources.redhat.com/ml/binutils/2004-09/msg00223.html

if [ $# -lt 1 ]; then
    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
    exit 1
fi

[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"

case "$1" in
    -patch) patch -p1 ${patch_opts} < $0;;
    -unpatch) patch -R -p1 ${patch_opts} < $0;;
    *)
        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
        exit 1;;
esac

exit 0

@DPATCH@
diff -urNad /home/james/debian/packages/binutils/binutils-2.15/gas/config/tc-ia64.c binutils-2.15/gas/config/tc-ia64.c
--- /home/james/debian/packages/binutils/binutils-2.15/gas/config/tc-ia64.c	2004-05-17 20:36:10.000000000 +0100
+++ binutils-2.15/gas/config/tc-ia64.c	2004-11-24 22:17:00.543933737 +0000
@@ -698,6 +698,12 @@
   struct label_prologue_count * saved_prologue_counts;
 } unwind;
 
+/* The input value is a negated offset from psp, and specifies an address
+   psp - offset.  The encoded value is psp + 16 - (4 * offset).  Thus we
+   must add 16 and divide by 4 to get the encoded value.  */
+
+#define ENCODED_PSP_OFFSET(OFFSET) (((OFFSET) + 16) / 4)
+
 typedef void (*vbyte_func) PARAMS ((int, char *, char *));
 
 /* Forward declarations:  */
@@ -1839,7 +1845,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (rp_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1873,7 +1879,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (pfs_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1907,7 +1913,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (preds_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1984,7 +1990,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (spill_base);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2009,7 +2015,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (unat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2043,7 +2049,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (lc_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2077,7 +2083,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (fpsr_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2118,7 +2124,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (priunat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2152,7 +2158,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (bsp_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2186,7 +2192,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (bspstore_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2220,7 +2226,7 @@
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (rnat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2277,7 +2283,7 @@
   unw_rec_list *ptr = alloc_record (spill_psprel);
   ptr->r.record.x.ab = ab;
   ptr->r.record.x.reg = reg;
-  ptr->r.record.x.pspoff = offset / 4;
+  ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2304,7 +2310,7 @@
   unw_rec_list *ptr = alloc_record (spill_psprel_p);
   ptr->r.record.x.ab = ab;
   ptr->r.record.x.reg = reg;
-  ptr->r.record.x.pspoff = offset / 4;
+  ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
   ptr->r.record.x.qp = predicate;
   return ptr;
 }
@@ -2770,8 +2776,14 @@
 	    break;
 	  }
 	case epilogue:
-	  ptr->r.record.b.t = rlen - 1 - t;
-	  break;
+          if (t < rlen)
+            ptr->r.record.b.t = rlen - 1 - t;
+          else
+            /* This happens when a memory-stack-less procedure uses a
+               ".restore sp" directive at the end of a region to pop
+               the frame state.  */
+            ptr->r.record.b.t = 0;
+          break;
 
 	case mem_stack_f:
 	case mem_stack_v:
