$OpenBSD: patch-binutils_rdcoff_c,v 1.3 2010/06/27 20:58:10 ckuethe Exp $
--- binutils/rdcoff.c.orig	Sat Jun 26 11:22:44 2010
+++ binutils/rdcoff.c	Sat Jun 26 11:31:17 2010
@@ -82,6 +82,9 @@ struct coff_types
   struct coff_slots *slots;
   /* Basic types.  */
   debug_type basic[T_MAX + 1];
+  /* Some general information, kept here for convenience. */
+  size_t intsize;		/* sizeof (int) */
+  size_t doublesize;		/* sizeof (double) */
 };
 
 static debug_type *coff_get_slot (struct coff_types *, int);
@@ -101,6 +104,7 @@ static bfd_boolean parse_coff_symbol
   (bfd *, struct coff_types *, asymbol *, long, struct internal_syment *,
    void *, debug_type, bfd_boolean);
 static bfd_boolean external_coff_symbol_p (int sym_class);
+static bfd_vma coff_convert_register (bfd *, bfd_vma);
 
 /* Return the slot for a type.  */
 
@@ -271,8 +275,7 @@ parse_coff_base_type (bfd *abfd, struct coff_symbols *
       break;
 
     case T_INT:
-      /* FIXME: Perhaps the size should depend upon the architecture.  */
-      ret = debug_make_int_type (dhandle, 4, FALSE);
+      ret = debug_make_int_type (dhandle, types->intsize, FALSE);
       name = "int";
       break;
 
@@ -287,7 +290,7 @@ parse_coff_base_type (bfd *abfd, struct coff_symbols *
       break;
 
     case T_DOUBLE:
-      ret = debug_make_float_type (dhandle, 8);
+      ret = debug_make_float_type (dhandle, types->doublesize);
       name = "double";
       break;
 
@@ -307,7 +310,7 @@ parse_coff_base_type (bfd *abfd, struct coff_symbols *
       break;
 
     case T_UINT:
-      ret = debug_make_int_type (dhandle, 4, TRUE);
+      ret = debug_make_int_type (dhandle, types->intsize, TRUE);
       name = "unsigned int";
       break;
 
@@ -565,6 +568,8 @@ parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct 
 
     case C_WEAKEXT:
     case C_EXT:
+      /* AVR COFF abuses C_EXTDEF */
+    case C_EXTDEF:
       if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
 				   DEBUG_GLOBAL, bfd_asymbol_value (sym)))
 	return FALSE;
@@ -580,9 +585,9 @@ parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct 
       break;
 
     case C_REG:
-      /* FIXME: We may need to convert the register number.  */
       if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
-				   DEBUG_REGISTER, bfd_asymbol_value (sym)))
+				   DEBUG_REGISTER,
+				   coff_convert_register (abfd, bfd_asymbol_value (sym))))
 	return FALSE;
       break;
 
@@ -596,9 +601,9 @@ parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct 
       break;
 
     case C_REGPARM:
-      /* FIXME: We may need to convert the register number.  */
       if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type,
-				    DEBUG_PARM_REG, bfd_asymbol_value (sym)))
+				    DEBUG_PARM_REG,
+				    coff_convert_register (abfd, bfd_asymbol_value (sym))))
 	return FALSE;
       break;
 
@@ -648,6 +653,28 @@ external_coff_symbol_p (int sym_class)
   return FALSE;
 }
 
+static bfd_vma
+coff_convert_register (abfd, val)
+     bfd *abfd;
+     bfd_vma val;
+{
+
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_avr:
+      /* AVR COFF wants to describe up to four registers by the four
+	 bytes of the 32-bit value.  Unused bytes are filled with
+	 0xff.  In theory, this would allow for non-contiguous
+	 register usage to hold a single value, but hopefully, no
+	 compiler is going to use that feature.  We could not handle
+	 it anyway. */
+      return val & 0xff;
+
+    default:
+      return val;
+    }
+}
+
 /* This is the main routine.  It looks through all the symbols and
    handles them.  */
 
@@ -674,7 +701,18 @@ parse_coff (bfd *abfd, asymbol **syms, long symcount, 
   types.slots = NULL;
   for (i = 0; i <= T_MAX; i++)
     types.basic[i] = DEBUG_TYPE_NULL;
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_avr:
+      types.intsize = 2;
+      types.doublesize = 4;
+      break;
 
+    default:
+      types.intsize = 4;
+      types.doublesize = 8;
+    }
+
   next_c_file = -1;
   fnname = NULL;
   fnclass = 0;
@@ -734,7 +772,6 @@ parse_coff (bfd *abfd, asymbol **syms, long symcount, 
       switch (syment.n_sclass)
 	{
 	case C_EFCN:
-	case C_EXTDEF:
 	case C_ULABEL:
 	case C_USTATIC:
 	case C_LINE:
@@ -757,6 +794,8 @@ parse_coff (bfd *abfd, asymbol **syms, long symcount, 
 	  /* Fall through.  */
 	case C_WEAKEXT:
 	case C_EXT:
+	  /* AVR COFF abuses C_EXTDEF for C_EXT */
+	case C_EXTDEF:
 	  if (ISFCN (syment.n_type))
 	    {
 	      fnname = name;
