propagate from branch 'com.redhat.elfutils.roland.pending.libelf-threads' (head fc97c9c202b5d7d7699a3b1d5c53007a2ef37bb1)
            to branch 'com.redhat.elfutils' (head 67cccb9bfffc1a7fe3d8d355a2d9b6d0e489ff81)
diff --git a/libasm/ChangeLog b/libasm/ChangeLog
index c98deb6..2894970 100644
--- a/libasm/ChangeLog
+++ b/libasm/ChangeLog
@@ -1,7 +1,3 @@
-2008-12-03  Ulrich Drepper  <drepper@redhat.com>
-
-	* Makefile.am [USE_TLS]: Like libasm.so with libpthread.
-
 2008-01-11  Ulrich Drepper  <drepper@redhat.com>
 
 	* libasm.h (DisasmGetSymCB_t): Change type of fourth and fifth
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
index 62b5ee2..bd5779e 100644
--- a/libasm/Makefile.am
+++ b/libasm/Makefile.am
@@ -65,17 +65,12 @@
 libasm_pic_a_SOURCES =
 am_libasm_pic_a_OBJECTS = $(libasm_a_SOURCES:.c=.os)
 
-libasm_so_LDLIBS =
-if USE_TLS
-libasm_so_LDLIBS += -lpthread
-endif
-
 libasm_so_SOURCES =
 libasm.so: libasm_pic.a libasm.map
 	$(LINK) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \
 		-Wl,--version-script,$(srcdir)/libasm.map,--no-undefined \
 		-Wl,--soname,$@.$(VERSION) \
-		../libebl/libebl.a ../libelf/libelf.so  $(libasm_so_LDLIBS)
+		../libebl/libebl.a ../libelf/libelf.so
 	if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi
 	ln -fs $@ $@.$(VERSION)
 
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index e8069db..f4da129 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,44 @@
+2008-10-22  Petr Machata  <pmachata@redhat.com>
+
+	* elf_rawfile.c (elf_rawfile): Lock around elf-> references.
+
+2008-10-21  Petr Machata  <pmachata@redhat.com>
+
+	* libelfP.h: Rename getehdr_rdlock to getehdr_wrlock.
+	* elf32_getehdr.c (getehdr_rdlock): Move the code to new function
+	getehdr_impl and make it a wrapper.  Rename to getehdr_wrlock.
+	(getehdr_impl): Guard elf->class init with wrlock.
+	(getehdr): Also make it a wrapper of getehdr_impl.
+	* elf32_updatenull.c (updatenull_wrlock): Call getehdr_wrlock.
+
+2008-10-20  Petr Machata  <pmachata@redhat.com>
+
+	* elf_getdata_rawchunk.c (elf_getdata_rawchunk): Lock around the
+	code that reads mutable elf state.  Relock to write lock to chain
+	the new chunk on the elf rawchunks list.
+
+2008-10-20  Petr Machata  <pmachata@redhat.com>
+
+	* elf32_checksum.c (checksum): Place a lock around the code that
+	processes data.  Make it wrlock if the code needs to xlate the
+	data before processing.
+
+2008-10-16  Petr Machata  <pmachata@redhat.com>
+
+	* elf_begin.c
+	(__libelf_next_arhdr): Rename to __libelf_next_arhdr_wrlock.
+	(dup_elf): Adjust the call.
+	(elf_begin): New local function lock_dup_elf.  Relocks the elf if
+	necessary before calling dup.  Call this instead of dup_elf.
+	* elf_getarhdr.c
+	(elf_getarhdr): Lock before calling __libelf_next_arhdr_wrlock.
+	* elf_next.c (elf_next): Likewise.
+	* elf_rand.c (elf_rand): Likewise.
+
+2008-10-14  Petr Machata  <pmachata@redhat.com>
+
+	* elf_getdata.c (__elf_getdata_rdlock): Lock before converting.
+
 2008-11-26  Roland McGrath  <roland@redhat.com>
 
 	* elf.h: Update from glibc.
@@ -46,7 +87,7 @@
 
 	* elf32_getshdr.c
 	(__elfNN_getshdr_internal): Drop.
-	(load_shdr_rwlock, scn_valid): New functions, contain bits of
+	(load_shdr_wrlock, scn_valid): New functions, contain bits of
 	behaviour from __elfNN_getshdr_internal.
 	(__elfNN_getshdr_rdlock, __elfNN_getshdr_wrlock): Replacements for
 	dropped _internal functions above.
diff --git a/libelf/elf32_checksum.c b/libelf/elf32_checksum.c
index 0e4ab9f..32b4a02 100644
--- a/libelf/elf32_checksum.c
+++ b/libelf/elf32_checksum.c
@@ -105,6 +105,14 @@
 		     || (ident[EI_DATA] == ELFDATA2MSB
 			 && __BYTE_ORDER == __BIG_ENDIAN));
 
+  /* If we don't have native byte order, we will likely need to
+     convert the data with xlate functions.  We do it upfront instead
+     of relocking mid-iteration. */
+  if (!likely (same_byte_order))
+    rwlock_wrlock (elf->lock);
+  else
+    rwlock_rdlock (elf->lock);
+
   /* Iterate over all sections to find those which are not strippable.  */
   scn = NULL;
   while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
@@ -118,7 +126,8 @@
       if (shdr == NULL)
 	{
 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
-	  return -1l;
+	  result = -1l;
+	  goto out;
 	}
 
       if (SECTION_STRIP_P (shdr,
@@ -162,17 +171,25 @@
 	    /* Convert the data to file byte order.  */
 	    if (INTUSE(elfw2(LIBELFBITS,xlatetof)) (data, data, ident[EI_DATA])
 		== NULL)
-	      return -1l;
+	      {
+		result = -1l;
+		goto out;
+	      }
 
 	    result = process_block (result, data);
 
 	    /* And convert it back.  */
 	    if (INTUSE(elfw2(LIBELFBITS,xlatetom)) (data, data, ident[EI_DATA])
 		== NULL)
-	      return -1l;
+	      {
+		result = -1l;
+		goto out;
+	      }
 	  }
     }
 
+ out:
+  rwlock_unlock (elf->lock);
   return result;
 }
 INTDEF(elfw2(LIBELFBITS,checksum))
diff --git a/libelf/elf32_getehdr.c b/libelf/elf32_getehdr.c
index d62e255..8009133 100644
--- a/libelf/elf32_getehdr.c
+++ b/libelf/elf32_getehdr.c
@@ -62,12 +62,11 @@
 #endif
 
 
-ElfW2(LIBELFBITS,Ehdr) *
-__elfw2(LIBELFBITS,getehdr_rdlock) (elf)
+static ElfW2(LIBELFBITS,Ehdr) *
+getehdr_impl (elf, wrlock)
      Elf *elf;
+     int wrlock;
 {
-  ElfW2(LIBELFBITS,Ehdr) *result;
-
   if (elf == NULL)
     return NULL;
 
@@ -77,19 +76,32 @@
       return NULL;
     }
 
+ again:
   if (elf->class == 0)
-    elf->class = ELFW(ELFCLASS,LIBELFBITS);
+    {
+      if (!wrlock)
+	{
+	  rwlock_unlock (elf->lock);
+	  rwlock_wrlock (elf->lock);
+	  wrlock = 1;
+	  goto again;
+	}
+      elf->class = ELFW(ELFCLASS,LIBELFBITS);
+    }
   else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS)))
     {
       __libelf_seterrno (ELF_E_INVALID_CLASS);
-      result = NULL;
-      goto out;
+      return NULL;
     }
 
-  result = elf->state.ELFW(elf,LIBELFBITS).ehdr;
+  return elf->state.ELFW(elf,LIBELFBITS).ehdr;
+}
 
- out:
-  return result;
+ElfW2(LIBELFBITS,Ehdr) *
+__elfw2(LIBELFBITS,getehdr_wrlock) (elf)
+     Elf *elf;
+{
+  return getehdr_impl (elf, 1);
 }
 
 ElfW2(LIBELFBITS,Ehdr) *
@@ -101,7 +113,7 @@
     return NULL;
 
   rwlock_rdlock (elf->lock);
-  result = __elfw2(LIBELFBITS,getehdr_rdlock) (elf);
+  result = getehdr_impl (elf, 0);
   rwlock_unlock (elf->lock);
 
   return result;
diff --git a/libelf/elf32_getshdr.c b/libelf/elf32_getshdr.c
index b36e543..91f5b3a 100644
--- a/libelf/elf32_getshdr.c
+++ b/libelf/elf32_getshdr.c
@@ -67,7 +67,7 @@
 
 
 static ElfW2(LIBELFBITS,Shdr) *
-load_shdr_rwlock (Elf_Scn *scn)
+load_shdr_wrlock (Elf_Scn *scn)
 {
   ElfW2(LIBELFBITS,Shdr) *result;
 
@@ -243,7 +243,6 @@
 __elfw2(LIBELFBITS,getshdr_rdlock) (scn)
      Elf_Scn *scn;
 {
-  /* XXX: no read locking here, figure out why is it not necessary. */
   ElfW2(LIBELFBITS,Shdr) *result;
 
   if (!scn_valid (scn))
@@ -256,7 +255,7 @@
       rwlock_wrlock (scn->elf->lock);
       result = scn->shdr.ELFW(e,LIBELFBITS);
       if (result == NULL)
-	result = load_shdr_rwlock (scn);
+	result = load_shdr_wrlock (scn);
     }
 
   return result;
@@ -273,7 +272,7 @@
 
   result = scn->shdr.ELFW(e,LIBELFBITS);
   if (result == NULL)
-    result = load_shdr_rwlock (scn);
+    result = load_shdr_wrlock (scn);
 
   return result;
 }
diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
index ae8696e..a18d0be 100644
--- a/libelf/elf32_updatenull.c
+++ b/libelf/elf32_updatenull.c
@@ -139,7 +139,7 @@
   int changed = 0;
   int ehdr_flags = 0;
 
-  ehdr = __elfw2(LIBELFBITS,getehdr_rdlock) (elf);
+  ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
 
   /* Set the default values.  */
   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c
index bd38530..04670a4 100644
--- a/libelf/elf_begin.c
+++ b/libelf/elf_begin.c
@@ -750,7 +750,7 @@
 /* Read the next archive header.  */
 int
 internal_function
-__libelf_next_arhdr (elf)
+__libelf_next_arhdr_wrlock (elf)
      Elf *elf;
 {
   struct ar_hdr *ar_hdr;
@@ -949,7 +949,7 @@
      pointing to.  First read the header of the next member if this
      has not happened already.  */
   if (ref->state.ar.elf_ar_hdr.ar_name == NULL
-      && __libelf_next_arhdr (ref) != 0)
+      && __libelf_next_arhdr_wrlock (ref) != 0)
     /* Something went wrong.  Maybe there is no member left.  */
     return NULL;
 
@@ -1023,6 +1023,19 @@
       return NULL;
     }
 
+  Elf *lock_dup_elf ()
+  {
+    /* We need wrlock to dup an archive.  */
+    if (ref->kind == ELF_K_AR)
+      {
+	rwlock_unlock (ref->lock);
+	rwlock_wrlock (ref->lock);
+      }
+
+    /* Duplicate the descriptor.  */
+    return dup_elf (fildes, cmd, ref);
+  }
+
   switch (cmd)
     {
     case ELF_C_NULL:
@@ -1043,8 +1056,7 @@
     case ELF_C_READ:
     case ELF_C_READ_MMAP:
       if (ref != NULL)
-	/* Duplicate the descriptor.  */
-	retval = dup_elf (fildes, cmd, ref);
+	retval = lock_dup_elf ();
       else
 	/* Create descriptor for existing file.  */
 	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
@@ -1065,8 +1077,7 @@
 	      retval = NULL;
 	    }
 	  else
-	    /* Duplicate this descriptor.  */
-	    retval = dup_elf (fildes, cmd, ref);
+	    retval = lock_dup_elf ();
 	}
       else
 	/* Create descriptor for existing file.  */
diff --git a/libelf/elf_getarhdr.c b/libelf/elf_getarhdr.c
index 875b2a1..6cc6edd 100644
--- a/libelf/elf_getarhdr.c
+++ b/libelf/elf_getarhdr.c
@@ -78,8 +78,15 @@
   /* Make sure we have read the archive header.  */
   if (parent->state.ar.elf_ar_hdr.ar_name == NULL
       && __libelf_next_arhdr (parent) != 0)
-    /* Something went wrong.  Maybe there is no member left.  */
-    return NULL;
+    {
+      rwlock_wrlock (parent->lock);
+      int st = __libelf_next_arhdr_wrlock (parent);
+      rwlock_unlock (parent->lock);
+
+      if (st != 0)
+	/* Something went wrong.  Maybe there is no member left.  */
+	return NULL;
+    }
 
   /* We can be sure the parent is an archive.  */
   assert (parent->kind == ELF_K_AR);
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
index 216905a..e083b03 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -364,6 +364,7 @@
 {
   Elf_Data *result = NULL;
   Elf *elf;
+  int locked = 0;
 
   if (scn == NULL)
     return NULL;
@@ -431,6 +432,7 @@
          modified, therefore start the tests again.  */
       rwlock_unlock (elf->lock);
       rwlock_wrlock (elf->lock);
+      locked = 1;
 
       /* Read the data from the file.  There is always a file (or
 	 memory region) associated with this descriptor since
@@ -446,14 +448,24 @@
   if (scn->data_list_rear == NULL)
     {
       if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0)
-	/* Convert according to the version and the type.   */
-	convert_data (scn, __libelf_version, elf->class,
-		      (elf->class == ELFCLASS32
-		       || (offsetof (struct Elf, state.elf32.ehdr)
-			   == offsetof (struct Elf, state.elf64.ehdr))
-		       ? elf->state.elf32.ehdr->e_ident[EI_DATA]
-		       : elf->state.elf64.ehdr->e_ident[EI_DATA]),
-		      scn->rawdata.d.d_size, scn->rawdata.d.d_type);
+	{
+	  if (!locked)
+	    {
+	      rwlock_unlock (elf->lock);
+	      rwlock_wrlock (elf->lock);
+	      if (scn->data_list_rear != NULL)
+		goto pass;
+	    }
+
+	  /* Convert according to the version and the type.   */
+	  convert_data (scn, __libelf_version, elf->class,
+			(elf->class == ELFCLASS32
+			 || (offsetof (struct Elf, state.elf32.ehdr)
+			     == offsetof (struct Elf, state.elf64.ehdr))
+			 ? elf->state.elf32.ehdr->e_ident[EI_DATA]
+			 : elf->state.elf64.ehdr->e_ident[EI_DATA]),
+			scn->rawdata.d.d_size, scn->rawdata.d.d_type);
+	}
       else
 	/* This is an empty or NOBITS section.  There is no buffer but
 	   the size information etc is important.  */
@@ -464,6 +476,7 @@
 
   /* If no data is present we cannot return any.  */
   if (scn->data_list_rear != NULL)
+  pass:
     /* Return the first data element in the list.  */
     result = &scn->data_list.data.d;
 
diff --git a/libelf/elf_getdata_rawchunk.c b/libelf/elf_getdata_rawchunk.c
index bea0f3f..5af0f7f 100644
--- a/libelf/elf_getdata_rawchunk.c
+++ b/libelf/elf_getdata_rawchunk.c
@@ -95,6 +95,9 @@
   /* Get the raw bytes from the file.  */
   void *rawchunk;
   int flags = 0;
+  Elf_Data *result = NULL;
+
+  rwlock_rdlock (elf->lock);
 
   /* If the file is mmap'ed we can use it directly.  */
   if (elf->map_address != NULL)
@@ -107,7 +110,7 @@
 	{
 	nomem:
 	  __libelf_seterrno (ELF_E_NOMEM);
-	  return NULL;
+	  goto out;
 	}
 
       /* Read the file content.  */
@@ -118,7 +121,7 @@
 	  /* Something went wrong.  */
 	  free (rawchunk);
 	  __libelf_seterrno (ELF_E_READ_ERROR);
-	  return NULL;
+	  goto out;
 	}
 
       flags = ELF_F_MALLOCED;
@@ -181,8 +184,14 @@
   chunk->data.d.d_align = align;
   chunk->data.d.d_version = __libelf_version;
 
+  rwlock_unlock (elf->lock);
+  rwlock_wrlock (elf->lock);
+
   chunk->next = elf->state.elf.rawchunks;
   elf->state.elf.rawchunks = chunk;
+  result = &chunk->data.d;
 
-  return &chunk->data.d;
+ out:
+  rwlock_unlock (elf->lock);
+  return result;
 }
diff --git a/libelf/elf_next.c b/libelf/elf_next.c
index ec80fad..fbfb272 100644
--- a/libelf/elf_next.c
+++ b/libelf/elf_next.c
@@ -64,6 +64,7 @@
      Elf *elf;
 {
   Elf *parent;
+  Elf_Cmd ret;
 
   /* Be gratious, the specs demand it.  */
   if (elf == NULL || elf->parent == NULL)
@@ -73,14 +74,17 @@
   parent = elf->parent;
   assert (parent->kind == ELF_K_AR);
 
+  rwlock_wrlock (parent->lock);
+
   /* Now advance the offset.  */
   parent->state.ar.offset += (sizeof (struct ar_hdr)
 			      + ((parent->state.ar.elf_ar_hdr.ar_size + 1)
 				 & ~1l));
 
   /* Get the next archive header.  */
-  if (__libelf_next_arhdr (parent) != 0)
-    return ELF_C_NULL;
+  ret = __libelf_next_arhdr_wrlock (parent) != 0 ? ELF_C_NULL : elf->cmd;
 
-  return elf->cmd;
+  rwlock_unlock (parent->lock);
+
+  return ret;
 }
diff --git a/libelf/elf_rand.c b/libelf/elf_rand.c
index 9ba631f..a766d38 100644
--- a/libelf/elf_rand.c
+++ b/libelf/elf_rand.c
@@ -67,16 +67,20 @@
   if (elf == NULL || elf->kind != ELF_K_AR)
     return 0;
 
+  rwlock_wrlock (elf->lock);
+
   /* Save the old offset and set the offset.  */
   elf->state.ar.offset = elf->start_offset + offset;
 
   /* Get the next archive header.  */
-  if (__libelf_next_arhdr (elf) != 0)
+  if (__libelf_next_arhdr_wrlock (elf) != 0)
     {
       /* Mark the archive header as unusable.  */
       elf->state.ar.elf_ar_hdr.ar_name = NULL;
       return 0;
     }
 
+  rwlock_unlock (elf->lock);
+
   return offset;
 }
diff --git a/libelf/elf_rawfile.c b/libelf/elf_rawfile.c
index a1c6a1d..a62a354 100644
--- a/libelf/elf_rawfile.c
+++ b/libelf/elf_rawfile.c
@@ -63,6 +63,8 @@
      Elf *elf;
      size_t *ptr;
 {
+  char *result;
+
   if (elf == NULL)
     {
       /* No valid descriptor.  */
@@ -77,8 +79,12 @@
   if (elf->map_address == NULL && __libelf_readall (elf) == NULL)
     goto error_out;
 
+  rwlock_rdlock (elf->lock);
   if (ptr != NULL)
     *ptr = elf->maximum_size;
 
-  return (char *) elf->map_address + elf->start_offset;
+  result = (char *) elf->map_address + elf->start_offset;
+  rwlock_unlock (elf->lock);
+
+  return result;
 }
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
index 4cab3f3..e810039 100644
--- a/libelf/libelfP.h
+++ b/libelf/libelfP.h
@@ -486,7 +486,7 @@
 extern void __libelf_seterrno (int value) internal_function;
 
 /* Get the next archive header.  */
-extern int __libelf_next_arhdr (Elf *elf) internal_function;
+extern int __libelf_next_arhdr_wrlock (Elf *elf) internal_function;
 
 /* Read all of the file associated with the descriptor.  */
 extern char *__libelf_readall (Elf *elf) internal_function;
@@ -520,8 +520,8 @@
 extern int __elf_end_internal (Elf *__elf) attribute_hidden;
 extern Elf *__elf_begin_internal (int __fildes, Elf_Cmd __cmd, Elf *__ref)
      attribute_hidden;
-extern Elf32_Ehdr *__elf32_getehdr_rdlock (Elf *__elf) internal_function;
-extern Elf64_Ehdr *__elf64_getehdr_rdlock (Elf *__elf) internal_function;
+extern Elf32_Ehdr *__elf32_getehdr_wrlock (Elf *__elf) internal_function;
+extern Elf64_Ehdr *__elf64_getehdr_wrlock (Elf *__elf) internal_function;
 extern Elf32_Ehdr *__elf32_newehdr_internal (Elf *__elf) attribute_hidden;
 extern Elf64_Ehdr *__elf64_newehdr_internal (Elf *__elf) attribute_hidden;
 extern Elf32_Phdr *__elf32_getphdr_internal (Elf *__elf) attribute_hidden;