2007-10-23  Roland McGrath  <roland@redhat.com>

	* linux-kernel-modules.c (report_kernel_archive): Reorder the kernel
	module to appear first.

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index d21f5d6..b7cd628 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2007-10-17  Roland McGrath  <roland@redhat.com>
+
+	* libdw.h (__deprecated_attribute__): New macro.
+	(dwarf_formref): Mark it deprecated.
+	* dwarf_formref.c (__libdw_formref): New function, broken out of ...
+	(dwarf_formref): ... here.  Call it.  Remove INTDEF.
+	* libdwP.h: Remove INTDECL.
+	Declare __libdw_formref.
+	* dwarf_siblingof.c (dwarf_siblingof): Call __libdw_formref instead.
+	* dwarf_formref_die.c: Likewise.  Handle DW_FORM_ref_addr here.
+
+	* libdw_form.c (__libdw_form_val_len): Fix DW_FORM_ref_addr result,
+	needs to check CU->version.
+
+	* libdwP.h (struct Dwarf_CU): New member `version'.
+	* libdw_findcu.c (__libdw_findcu): Initialize it.
+
+	* dwarf_child.c: Return 1 for null entry as first child.
+
 2007-10-05  Roland McGrath  <roland@redhat.com>
 
 	* dwarf_begin_elf.c (check_section): Punt on SHT_NOBITS sections.
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index 42b3813..b22b010 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -1,5 +1,5 @@
 /* Return vhild of current DIE.
-   Copyright (C) 2003, 2004, 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -177,6 +177,15 @@
   if (addr == NULL)
     return -1;
 
+  /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
+     So if this starts with ULEB128 of 0 (even with silly encoding of 0),
+     it is a kosher null entry and we do not really have any children.  */
+  const unsigned char *code = addr;
+  while (unlikely (*code == 0x80))
+    ++code;
+  if (unlikely (*code == '\0'))
+    return 1;
+
   /* RESULT can be the same as DIE.  So preserve what we need.  */
   struct Dwarf_CU *cu = die->cu;
 
diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c
index ac905c8..7c4fb71 100644
--- a/libdw/dwarf_formref.c
+++ b/libdw/dwarf_formref.c
@@ -1,5 +1,5 @@
 /* Return reference offset represented by attribute.
-   Copyright (C) 2003, 2005 Red Hat, Inc.
+   Copyright (C) 2003, 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -55,15 +55,11 @@
 #include <dwarf.h>
 #include "libdwP.h"
 
-
 int
-dwarf_formref (attr, return_offset)
+__libdw_formref (attr, return_offset)
      Dwarf_Attribute *attr;
      Dwarf_Off *return_offset;
 {
-  if (attr == NULL)
-    return -1;
-
   const unsigned char *datap;
 
   switch (attr->form)
@@ -100,4 +96,16 @@
 
   return 0;
 }
-INTDEF(dwarf_formref)
+
+/* This is the old public entry point.
+   It is now deprecated in favor of dwarf_formref_die.  */
+int
+dwarf_formref (attr, return_offset)
+     Dwarf_Attribute *attr;
+     Dwarf_Off *return_offset;
+{
+  if (attr == NULL)
+    return -1;
+
+  return __libdw_formref (attr, return_offset);
+}
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 18ffe2f..90a4b2d 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -1,5 +1,5 @@
 /* Look up the DIE in a reference-form attribute.
-   Copyright (C) 2005 Red Hat, Inc.
+   Copyright (C) 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -52,13 +52,39 @@
 #endif
 
 #include "libdwP.h"
+#include <dwarf.h>
+
 
 Dwarf_Die *
-dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem)
+dwarf_formref_die (attr, die_mem)
+     Dwarf_Attribute *attr;
+     Dwarf_Die *die_mem;
 {
+  if (attr == NULL)
+    return NULL;
+
   Dwarf_Off offset;
-  return (unlikely (INTUSE(dwarf_formref) (attr, &offset) != 0) ? NULL
-	  : INTUSE(dwarf_offdie) (attr->cu->dbg, attr->cu->start + offset,
-				  die_mem));
+  if (attr->form == DW_FORM_ref_addr)
+    {
+      /* This has an absolute offset.  */
+
+      uint8_t ref_size = (attr->cu->version == 2
+			  ? attr->cu->address_size
+			  : attr->cu->offset_size);
+
+      if (ref_size == 8)
+	offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+      else
+	offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+    }
+  else
+    {
+      /* Other forms produce an offset from the CU.  */
+      if (unlikely (__libdw_formref (attr, &offset) != 0))
+	return NULL;
+      offset += attr->cu->start;
+    }
+
+  return INTUSE(dwarf_offdie) (attr->cu->dbg, offset, die_mem);
 }
 INTDEF (dwarf_formref_die)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
index 00e5a1c..a6cca39 100644
--- a/libdw/dwarf_siblingof.c
+++ b/libdw/dwarf_siblingof.c
@@ -1,5 +1,5 @@
 /* Return sibling of given DIE.
-   Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2003, 2004, 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -92,7 +92,7 @@
 	{
 	  Dwarf_Off offset;
 	  sibattr.valp = addr;
-	  if (INTUSE(dwarf_formref) (&sibattr, &offset) != 0)
+	  if (__libdw_formref (&sibattr, &offset) != 0)
 	    /* Something went wrong.  */
 	    return -1;
 
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 70a35b0..6242d04 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -57,10 +57,13 @@
 
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
 # define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__)))
+# define __deprecated_attribute__ __attribute__ ((__deprecated__))
 #else
 # define __nonnull_attribute__(args...)
+# define __deprecated_attribute__
 #endif
 
+
 #ifdef __GNUC_STDC_INLINE__
 # define __libdw_extern_inline extern __inline __attribute__ ((__gnu_inline__))
 #else
@@ -310,9 +313,10 @@
 extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
      __nonnull_attribute__ (2);
 
-/* Return reference offset represented by attribute.  */
+/* This function is deprecated.  Always use dwarf_formref_die instead.
+   Return reference offset represented by attribute.  */
 extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
-     __nonnull_attribute__ (2);
+     __nonnull_attribute__ (2) __deprecated_attribute__;
 
 /* Look up the DIE in a reference-form attribute.  */
 extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem)
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index f069075..78fd5ce 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -267,6 +267,7 @@
   Dwarf_Off end;
   uint8_t address_size;
   uint8_t offset_size;
+  uint16_t version;
 
   /* Hash table for the abbreviations.  */
   Dwarf_Abbrev_Hash abbrev_hash;
@@ -365,6 +366,11 @@
 				    const unsigned char *valp)
      __nonnull_attribute__ (1, 2, 4) internal_function;
 
+/* Helper function for DW_FORM_ref* handling.  */
+extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
+     __nonnull_attribute__ (1, 2) internal_function;
+
+
 /* Helper function to locate attribute.  */
 extern unsigned char *__libdw_find_attr (Dwarf_Die *die,
 					 unsigned int search_name,
@@ -411,7 +417,6 @@
 INTDECL (dwarf_errmsg)
 INTDECL (dwarf_formaddr)
 INTDECL (dwarf_formblock)
-INTDECL (dwarf_formref)
 INTDECL (dwarf_formref_die)
 INTDECL (dwarf_formsdata)
 INTDECL (dwarf_formstring)
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index e6259d4..afff6d3 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -1,5 +1,5 @@
 /* Find CU for given offset.
-   Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2003, 2004, 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -97,6 +97,7 @@
 
   if (start < dbg->next_cu_offset)
     {
+    invalid:
       __libdw_seterrno (DWARF_E_INVALID_DWARF);
       return NULL;
     }
@@ -115,6 +116,15 @@
 	/* No more entries.  */
 	return NULL;
 
+      /* XXX We need the version number but dwarf_nextcu swallows it.  */
+      const char *bytes = (dbg->sectiondata[IDX_debug_info]->d_buf + oldoff
+			   + (2 * offset_size - 4));
+      uint16_t version = read_2ubyte_unaligned (dbg, bytes);
+
+      /* We only know how to handle the DWARF version 2 and 3 formats.  */
+      if (unlikely (version != 2) && unlikely (version != 3))
+	goto invalid;
+
       /* Create an entry for this CU.  */
       struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
 
@@ -123,6 +133,7 @@
       newp->end = dbg->next_cu_offset;
       newp->address_size = address_size;
       newp->offset_size = offset_size;
+      newp->version = version;
       Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
       newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
       newp->lines = NULL;
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index 779b6c0..ad78f4b 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -1,5 +1,5 @@
 /* Helper functions for form handling.
-   Copyright (C) 2003, 2004, 2006 Red Hat, Inc.
+   Copyright (C) 2003, 2004, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -73,8 +73,11 @@
       result = cu->address_size;
       break;
 
-    case DW_FORM_strp:
     case DW_FORM_ref_addr:
+      result = cu->version == 2 ? cu->address_size : cu->offset_size;
+      break;
+
+    case DW_FORM_strp:
       result = cu->offset_size;
       break;