Squashed 'third_party/elfutils/' content from commit 555e15e

Change-Id: I61cde98949e47e5c8c09c33260de17f30921be79
git-subtree-dir: third_party/elfutils
git-subtree-split: 555e15ebe8bf1eb33d00747173cfc80cc65648a4
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
new file mode 100644
index 0000000..510bd69
--- /dev/null
+++ b/libdwfl/dwfl_module.c
@@ -0,0 +1,242 @@
+/* Maintenance of module list in libdwfl.
+   Copyright (C) 2005, 2006, 2007, 2008, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils 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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwflP.h"
+#include "../libdw/cfi.h"
+#include <search.h>
+#include <unistd.h>
+
+static void
+free_cu (struct dwfl_cu *cu)
+{
+  if (cu->lines != NULL)
+    free (cu->lines);
+  free (cu);
+}
+
+static void
+nofree (void *arg __attribute__ ((unused)))
+{
+}
+
+static void
+free_file (struct dwfl_file *file)
+{
+  free (file->name);
+
+  /* Close the fd only on the last reference.  */
+  if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
+    close (file->fd);
+}
+
+void
+internal_function
+__libdwfl_module_free (Dwfl_Module *mod)
+{
+  if (mod->lazy_cu_root != NULL)
+    tdestroy (mod->lazy_cu_root, nofree);
+
+  if (mod->aranges != NULL)
+    free (mod->aranges);
+
+  if (mod->cu != NULL)
+    {
+      for (size_t i = 0; i < mod->ncu; ++i)
+	free_cu (mod->cu[i]);
+      free (mod->cu);
+    }
+
+  /* We might have primed the Dwarf_CFI ebl cache with our own ebl
+     in __libdwfl_set_cfi. Make sure we don't free it twice.  */
+  if (mod->eh_cfi != NULL)
+    {
+      if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
+	mod->eh_cfi->ebl = NULL;
+      dwarf_cfi_end (mod->eh_cfi);
+    }
+
+  if (mod->dwarf_cfi != NULL)
+    {
+      if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl)
+	mod->dwarf_cfi->ebl = NULL;
+      /* We don't need to explicitly destroy the dwarf_cfi.
+	 That will be done by dwarf_end.  */
+    }
+
+  if (mod->dw != NULL)
+    {
+      INTUSE(dwarf_end) (mod->dw);
+      if (mod->alt != NULL)
+	{
+	  INTUSE(dwarf_end) (mod->alt);
+	  if (mod->alt_elf != NULL)
+	    elf_end (mod->alt_elf);
+	  if (mod->alt_fd != -1)
+	    close (mod->alt_fd);
+	}
+    }
+
+  if (mod->ebl != NULL)
+    ebl_closebackend (mod->ebl);
+
+  if (mod->debug.elf != mod->main.elf)
+    free_file (&mod->debug);
+  free_file (&mod->main);
+  free_file (&mod->aux_sym);
+
+  if (mod->build_id_bits != NULL)
+    free (mod->build_id_bits);
+
+  if (mod->reloc_info != NULL)
+    free (mod->reloc_info);
+
+  free (mod->name);
+  free (mod);
+}
+
+void
+dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
+{
+  /* The lookup table will be cleared on demand, there is nothing we need
+     to do here.  */
+}
+INTDEF (dwfl_report_begin_add)
+
+void
+dwfl_report_begin (Dwfl *dwfl)
+{
+  /* Clear the segment lookup table.  */
+  dwfl->lookup_elts = 0;
+
+  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
+    m->gc = true;
+
+  dwfl->offline_next_address = OFFLINE_REDZONE;
+}
+INTDEF (dwfl_report_begin)
+
+static inline Dwfl_Module *
+use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
+{
+  mod->next = *tailp;
+  *tailp = mod;
+
+  if (unlikely (dwfl->lookup_module != NULL))
+    {
+      free (dwfl->lookup_module);
+      dwfl->lookup_module = NULL;
+    }
+
+  return mod;
+}
+
+/* Report that a module called NAME spans addresses [START, END).
+   Returns the module handle, either existing or newly allocated,
+   or returns a null pointer for an allocation error.  */
+Dwfl_Module *
+dwfl_report_module (Dwfl *dwfl, const char *name,
+		    GElf_Addr start, GElf_Addr end)
+{
+  Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
+
+  for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
+    {
+      if (m->low_addr == start && m->high_addr == end
+	  && !strcmp (m->name, name))
+	{
+	  /* This module is still here.  Move it to the place in the list
+	     after the last module already reported.  */
+	  *prevp = m->next;
+	  m->gc = false;
+	  return use (m, tailp, dwfl);
+	}
+
+      if (! m->gc)
+	tailp = &m->next;
+    }
+
+  Dwfl_Module *mod = calloc (1, sizeof *mod);
+  if (mod == NULL)
+    goto nomem;
+
+  mod->name = strdup (name);
+  if (mod->name == NULL)
+    {
+      free (mod);
+    nomem:
+      __libdwfl_seterrno (DWFL_E_NOMEM);
+      return NULL;
+    }
+
+  mod->low_addr = start;
+  mod->high_addr = end;
+  mod->dwfl = dwfl;
+
+  return use (mod, tailp, dwfl);
+}
+INTDEF (dwfl_report_module)
+
+
+/* Finish reporting the current set of modules to the library.
+   If REMOVED is not null, it's called for each module that
+   existed before but was not included in the current report.
+   Returns a nonzero return value from the callback.
+   DWFL cannot be used until this function has returned zero.  */
+int
+dwfl_report_end (Dwfl *dwfl,
+		 int (*removed) (Dwfl_Module *, void *,
+				 const char *, Dwarf_Addr,
+				 void *arg),
+		 void *arg)
+{
+  Dwfl_Module **tailp = &dwfl->modulelist;
+  while (*tailp != NULL)
+    {
+      Dwfl_Module *m = *tailp;
+      if (m->gc && removed != NULL)
+	{
+	  int result = (*removed) (MODCB_ARGS (m), arg);
+	  if (result != 0)
+	    return result;
+	}
+      if (m->gc)
+	{
+	  *tailp = m->next;
+	  __libdwfl_module_free (m);
+	}
+      else
+	tailp = &m->next;
+    }
+
+  return 0;
+}
+INTDEF (dwfl_report_end)