Index: libbacktrace/unknown.c
===================================================================
--- libbacktrace/unknown.c	(revision 0)
+++ libbacktrace/unknown.c	(revision 0)
@@ -0,0 +1,64 @@
+/* unknown.c -- used when backtrace configury does not know file format.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* A trivial routine that always fails to find fileline data.  */
+
+static int
+unknown_fileline (void *fileline_data ATTRIBUTE_UNUSED,
+		  uintptr_t pc, backtrace_callback callback,
+		  backtrace_error_callback ATTRIBUTE_UNUSED,
+		  void *data)
+
+{
+  return callback (data, pc, NULL, 0, NULL);
+}
+
+/* Initialize the backtrace data when we don't know how to read the
+   debug info.  */
+
+int
+backtrace_initialize (int descriptor ATTRIBUTE_UNUSED,
+		      backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+		      void *data ATTRIBUTE_UNUSED, fileline *fileline_fn,
+		      void **fileline_data)
+{
+  *fileline_fn = unknown_fileline;
+  *fileline_data = NULL;
+  return 1;
+}
Index: libbacktrace/nounwind.c
===================================================================
--- libbacktrace/nounwind.c	(revision 0)
+++ libbacktrace/nounwind.c	(revision 0)
@@ -0,0 +1,64 @@
+/* backtrace.c -- Entry point for stack backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#include "backtrace.h"
+
+#include "internal.h"
+
+/* This source file is compiled if the unwind library is not
+   available.  */
+
+int
+backtrace (int skip ATTRIBUTE_UNUSED,
+	   backtrace_callback callback ATTRIBUTE_UNUSED,
+	   backtrace_error_callback error_callback, void *data)
+{
+  error_callback (data,
+		  "no stack trace because unwind library not available",
+		  0);
+  return 0;
+}
+
+int
+backtrace_simple (int skip ATTRIBUTE_UNUSED,
+		  backtrace_simple_callback callback ATTRIBUTE_UNUSED,
+		  backtrace_error_callback error_callback, void *data)
+{
+  error_callback (data,
+		  "no stack trace because unwind library not available",
+		  0);
+  return 0;
+}
Index: libbacktrace/posix.c
===================================================================
--- libbacktrace/posix.c	(revision 0)
+++ libbacktrace/posix.c	(revision 0)
@@ -0,0 +1,86 @@
+/* posix.c -- POSIX file I/O routines for the backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Open a file for reading.  */
+
+int
+backtrace_open (const char *filename, backtrace_error_callback error_callback,
+		void *data)
+{
+  int descriptor;
+
+  descriptor = open (filename, O_RDONLY | O_CLOEXEC);
+  if (descriptor < 0)
+    {
+      error_callback (data, filename, errno);
+      return -1;
+    }
+  if (O_CLOEXEC == 0)
+    {
+      /* It doesn't matter if this fails for some reason.  */
+      fcntl (descriptor, F_SETFD, FD_CLOEXEC);
+    }
+  return descriptor;
+}
+
+/* Close DESCRIPTOR.  */
+
+int
+backtrace_close (int descriptor, backtrace_error_callback error_callback,
+		 void *data)
+{
+  if (close (descriptor) < 0)
+    {
+      error_callback (data, "close", errno);
+      return 0;
+    }
+  return 1;
+}
Index: libbacktrace/dwarf.c
===================================================================
--- libbacktrace/dwarf.c	(revision 0)
+++ libbacktrace/dwarf.c	(revision 0)
@@ -0,0 +1,2659 @@
+/* dwarf.c -- Get file/line information from DWARF for backtraces.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "dwarf2.h"
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* A buffer to read DWARF info.  */
+
+struct dwarf_buf
+{
+  /* Buffer name for error messages.  */
+  const char *name;
+  /* Start of the buffer.  */
+  const unsigned char *start;
+  /* Next byte to read.  */
+  const unsigned char *buf;
+  /* The number of bytes remaining.  */
+  size_t left;
+  /* Whether the data is big-endian.  */
+  int is_bigendian;
+  /* Error callback routine.  */
+  backtrace_error_callback error_callback;
+  /* Data for error_callback.  */
+  void *data;
+  /* Non-zero if we've reported an underflow error.  */
+  int reported_underflow;
+};
+
+/* A single attribute in a DWARF abbreviation.  */
+
+struct attr
+{
+  /* The attribute name.  */
+  enum dwarf_attribute name;
+  /* The attribute form.  */
+  enum dwarf_form form;
+};
+
+/* A single DWARF abbreviation.  */
+
+struct abbrev
+{
+  /* The abbrev code--the number used to refer to the abbrev.  */
+  uint64_t code;
+  /* The entry tag.  */
+  enum dwarf_tag tag;
+  /* Non-zero if this abbrev has child entries.  */
+  int has_children;
+  /* The number of attributes.  */
+  size_t num_attrs;
+  /* The attributes.  */
+  struct attr *attrs;
+};
+
+/* The DWARF abbreviations for a compilation unit.  This structure
+   only exists while reading the compilation unit.  Most DWARF readers
+   seem to a hash table to map abbrev ID's to abbrev entries.
+   However, we primarily care about GCC, and GCC simply issues ID's in
+   numerical order starting at 1.  So we simply keep a sorted vector,
+   and try to just look up the code.  */
+
+struct abbrevs
+{
+  /* The number of abbrevs in the vector.  */
+  size_t num_abbrevs;
+  /* The abbrevs, sorted by the code field.  */
+  struct abbrev *abbrevs;
+};
+
+/* The different kinds of attribute values.  */
+
+enum attr_val_encoding
+{
+  /* An address.  */
+  ATTR_VAL_ADDRESS,
+  /* A unsigned integer.  */
+  ATTR_VAL_UINT,
+  /* A sigd integer.  */
+  ATTR_VAL_SINT,
+  /* A string.  */
+  ATTR_VAL_STRING,
+  /* An offset to other data in the containing unit.  */
+  ATTR_VAL_REF_UNIT,
+  /* An offset to other data within the .dwarf_info section.  */
+  ATTR_VAL_REF_INFO,
+  /* An offset to data in some other section.  */
+  ATTR_VAL_REF_SECTION,
+  /* A type signature.  */
+  ATTR_VAL_REF_TYPE,
+  /* A block of data (not represented).  */
+  ATTR_VAL_BLOCK,
+  /* An expression (not represented).  */
+  ATTR_VAL_EXPR,
+};
+
+/* An attribute value.  */
+
+struct attr_val
+{
+  /* How the value is stored in the field u.  */
+  enum attr_val_encoding encoding;
+  union
+  {
+    /* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*.  */
+    uint64_t uint;
+    /* ATTR_VAL_SINT.  */
+    int64_t sint;
+    /* ATTR_VAL_STRING.  */
+    const char *string;
+    /* ATTR_VAL_BLOCK not stored.  */
+  } u;
+};
+
+/* The line number program header.  */
+
+struct line_header
+{
+  /* The version of the line number information.  */
+  int version;
+  /* The minimum instruction length.  */
+  unsigned int min_insn_len;
+  /* The maximum number of ops per instruction.  */
+  unsigned int max_ops_per_insn;
+  /* The line base for special opcodes.  */
+  int line_base;
+  /* The line range for special opcodes.  */
+  unsigned int line_range;
+  /* The opcode base--the first special opcode.  */
+  unsigned int opcode_base;
+  /* Opcode lengths, indexed by opcode - 1.  */
+  const unsigned char *opcode_lengths;
+  /* The number of directory entries.  */
+  size_t dirs_count;
+  /* The directory entries.  */
+  const char **dirs;
+  /* The number of filenames.  */
+  size_t filenames_count;
+  /* The filenames.  */
+  const char **filenames;
+};
+
+/* Map a single PC value to a file/line.  We will keep a vector of
+   these sorted by PC value.  Each file/line will be correct from the
+   PC up to the PC of the next entry if there is one.  We allocate one
+   extra entry at the end so that we can use bsearch.  */
+
+struct line
+{
+  /* PC.  */
+  uintptr_t pc;
+  /* File name.  Many entries in the array are expected to point to
+     the same file name.  */
+  const char *filename;
+  /* Line number.  */
+  int lineno;
+};
+
+/* A growable vector of line number information.  This is used while
+   reading the line numbers.  */
+
+struct line_vector
+{
+  /* Memory.  This is an array of struct line.  */
+  struct backtrace_vector vec;
+  /* Number of valid mappings.  */
+  size_t count;
+};
+
+/* A function described in the debug info.  */
+
+struct function
+{
+  /* The name of the function.  */
+  const char *name;
+  /* If this is an inlined function, the filename of the call
+     site.  */
+  const char *caller_filename;
+  /* If this is an inlined function, the line number of the call
+     site.  */
+  int caller_lineno;
+  /* Map PC ranges to inlined functions.  */
+  struct function_addrs *function_addrs;
+  size_t function_addrs_count;
+};
+
+/* An address range for a function.  This maps a PC value to a
+   specific function.  */
+
+struct function_addrs
+{
+  /* Range is LOW <= PC < HIGH.  */
+  uint64_t low;
+  uint64_t high;
+  /* Function for this address range.  */
+  struct function *function;
+};
+
+/* A growable vector of function address ranges.  */
+
+struct function_vector
+{
+  /* Memory.  This is an array of struct function_addrs.  */
+  struct backtrace_vector vec;
+  /* Number of address ranges present.  */
+  size_t count;
+};
+
+/* A DWARF compilation unit.  This only holds the information we need
+   to map a PC to a file and line.  */
+
+struct unit
+{
+  /* The first entry for this compilation unit.  */
+  const unsigned char *unit_data;
+  /* The length of the data for this compilation unit.  */
+  size_t unit_data_len;
+  /* The offset of UNIT_DATA from the start of the information for
+     this compilation unit.  */
+  size_t unit_data_offset;
+  /* DWARF version.  */
+  int version;
+  /* Whether unit is DWARF64.  */
+  int is_dwarf64;
+  /* Address size.  */
+  int addrsize;
+  /* Offset into line number information.  */
+  off_t lineoff;
+  /* Compilation command working directory.  */
+  const char *comp_dir;
+  /* The abbreviations for this unit.  */
+  struct abbrevs abbrevs;
+  /* PC to line number mapping.  */
+  struct line *lines;
+  /* Number of entries in lines.  This will be set to -1 if there is
+     some problem reading the line number information.  */
+  size_t lines_count;
+  /* PC ranges to function.  */
+  struct function_addrs *function_addrs;
+  size_t function_addrs_count;
+};
+
+/* An address range for a compilation unit.  This maps a PC value to a
+   specific compilation unit.  Note that we invert the representation
+   in DWARF: instead of listing the units and attaching a list of
+   ranges, we list the ranges and have each one point to the unit.
+   This lets us do a binary search to find the unit.  */
+
+struct unit_addrs
+{
+  /* Range is LOW <= PC < HIGH.  */
+  uint64_t low;
+  uint64_t high;
+  /* Compilation unit for this address range.  */
+  struct unit *u;
+};
+
+/* A growable vector of compilation unit address ranges.  */
+
+struct unit_addrs_vector
+{
+  /* Memory.  This is an array of struct unit_addrs.  */
+  struct backtrace_vector vec;
+  /* Number of address ranges present.  */
+  size_t count;
+};
+
+/* The information we need to map a PC to a file and line.  */
+
+struct dwarf_data
+{
+  /* A sorted list of address ranges.  */
+  struct unit_addrs *addrs;
+  /* Number of address ranges in list.  */
+  size_t addrs_count;
+  /* The unparsed .debug_info section.  */
+  const unsigned char *dwarf_info;
+  size_t dwarf_info_size;
+  /* The unparsed .debug_line section.  */
+  const unsigned char *dwarf_line;
+  size_t dwarf_line_size;
+  /* The unparsed .debug_ranges section.  */
+  const unsigned char *dwarf_ranges;
+  size_t dwarf_ranges_size;
+  /* The unparsed .debug_str section.  */
+  const unsigned char *dwarf_str;
+  size_t dwarf_str_size;
+  /* Whether the data is big-endian or not.  */
+  int is_bigendian;
+  /* A vector used for function addresses.  We keep this here so that
+     we can grow the vector as we read more functions.  */
+  struct function_vector fvec;
+};
+
+/* Report an error for a DWARF buffer.  */
+
+static void
+dwarf_buf_error (struct dwarf_buf *buf, const char *msg)
+{
+  char b[200];
+
+  snprintf (b, sizeof b, "%s in %s at %d",
+	    msg, buf->name, (int) (buf->buf - buf->start));
+  buf->error_callback (buf->data, b, 0);
+}
+
+/* Require at least COUNT bytes in BUF.  Return 1 if all is well, 0 on
+   error.  */
+
+static int
+require (struct dwarf_buf *buf, size_t count)
+{
+  if (buf->left >= count)
+    return 1;
+
+  if (!buf->reported_underflow)
+    {
+      dwarf_buf_error (buf, "DWARF underflow");
+      buf->reported_underflow = 1;
+    }
+
+  return 0;
+}
+
+/* Advance COUNT bytes in BUF.  Return 1 if all is well, 0 on
+   error.  */
+
+static int
+advance (struct dwarf_buf *buf, size_t count)
+{
+  if (!require (buf, count))
+    return 0;
+  buf->buf += count;
+  buf->left -= count;
+  return 1;
+}
+
+/* Read one byte from BUF and advance 1 byte.  */
+
+static unsigned char
+read_byte (struct dwarf_buf *buf)
+{
+  const unsigned char *p = buf->buf;
+
+  if (!advance (buf, 1))
+    return 0;
+  return p[0];
+}
+
+/* Read a signed char from BUF and advance 1 byte.  */
+
+static signed char
+read_sbyte (struct dwarf_buf *buf)
+{
+  const unsigned char *p = buf->buf;
+
+  if (!advance (buf, 1))
+    return 0;
+  return (*p ^ 0x80) - 0x80;
+}
+
+/* Read a uint16 from BUF and advance 2 bytes.  */
+
+static uint16_t
+read_uint16 (struct dwarf_buf *buf)
+{
+  const unsigned char *p = buf->buf;
+
+  if (!advance (buf, 2))
+    return 0;
+  if (buf->is_bigendian)
+    return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
+  else
+    return ((uint16_t) p[1] << 8) | (uint16_t) p[0];
+}
+
+/* Read a uint32 from BUF and advance 4 bytes.  */
+
+static uint32_t
+read_uint32 (struct dwarf_buf *buf)
+{
+  const unsigned char *p = buf->buf;
+
+  if (!advance (buf, 4))
+    return 0;
+  if (buf->is_bigendian)
+    return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16)
+	    | ((uint32_t) p[2] << 8) | (uint32_t) p[3]);
+  else
+    return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16)
+	    | ((uint32_t) p[1] << 8) | (uint32_t) p[0]);
+}
+
+/* Read a uint64 from BUF and advance 8 bytes.  */
+
+static uint64_t
+read_uint64 (struct dwarf_buf *buf)
+{
+  const unsigned char *p = buf->buf;
+
+  if (!advance (buf, 8))
+    return 0;
+  if (buf->is_bigendian)
+    return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48)
+	    | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32)
+	    | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16)
+	    | ((uint64_t) p[6] << 8) | (uint64_t) p[7]);
+  else
+    return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48)
+	    | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32)
+	    | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16)
+	    | ((uint64_t) p[1] << 8) | (uint64_t) p[0]);
+}
+
+/* Read an offset from BUF and advance the appropriate number of
+   bytes.  */
+
+static uint64_t
+read_offset (struct dwarf_buf *buf, int is_dwarf64)
+{
+  if (is_dwarf64)
+    return read_uint64 (buf);
+  else
+    return read_uint32 (buf);
+}
+
+/* Read an address from BUF and advance the appropriate number of
+   bytes.  */
+
+static uint64_t
+read_address (struct dwarf_buf *buf, int addrsize)
+{
+  switch (addrsize)
+    {
+    case 1:
+      return read_byte (buf);
+    case 2:
+      return read_uint16 (buf);
+    case 4:
+      return read_uint32 (buf);
+    case 8:
+      return read_uint64 (buf);
+    default:
+      dwarf_buf_error (buf, "unrecognized address size");
+      return 0;
+    }
+}
+
+/* Return whether a value is the highest possible address, given the
+   address size.  */
+
+static int
+is_highest_address (uint64_t address, int addrsize)
+{
+  switch (addrsize)
+    {
+    case 1:
+      return address == (unsigned char) -1;
+    case 2:
+      return address == (uint16_t) -1;
+    case 4:
+      return address == (uint32_t) -1;
+    case 8:
+      return address == (uint64_t) -1;
+    default:
+      return 0;
+    }
+}
+
+/* Read an unsigned LEB128 number.  */
+
+static uint64_t
+read_uleb128 (struct dwarf_buf *buf)
+{
+  uint64_t ret;
+  unsigned int shift;
+  unsigned char b;
+
+  ret = 0;
+  shift = 0;
+  do
+    {
+      const unsigned char *p;
+
+      p = buf->buf;
+      if (!advance (buf, 1))
+	return 0;
+      b = *p;
+      ret |= ((uint64_t) (b & 0x7f)) << shift;
+      shift += 7;
+    }
+  while ((b & 0x80) != 0);
+
+  if (shift > 64)
+    dwarf_buf_error (buf, "LEB128 overflows uint64_5");
+
+  return ret;
+}
+
+/* Read a signed LEB128 number.  */
+
+static int64_t
+read_sleb128 (struct dwarf_buf *buf)
+{
+  uint64_t val;
+  unsigned int shift;
+  unsigned char b;
+
+  val = 0;
+  shift = 0;
+  do
+    {
+      const unsigned char *p;
+
+      p = buf->buf;
+      if (!advance (buf, 1))
+	return 0;
+      b = *p;
+      val |= ((uint64_t) (b & 0x7f)) << shift;
+      shift += 7;
+    }
+  while ((b & 0x80) != 0);
+
+  if (shift > 64)
+    dwarf_buf_error (buf, "signed LEB128 overflows uint64_t");
+
+  if ((b & 0x40) != 0)
+    val |= ((uint64_t) -1) << shift;
+
+  return (int64_t) val;
+}
+
+/* Return the length of an LEB128 number.  */
+
+static size_t
+leb128_len (const unsigned char *p)
+{
+  size_t ret;
+
+  ret = 1;
+  while ((*p & 0x80) != 0)
+    {
+      ++p;
+      ++ret;
+    }
+  return ret;
+}
+
+/* Free an abbreviations structure.  */
+
+static void
+free_abbrevs (struct abbrevs *abbrevs, backtrace_error_callback error_callback,
+	      void *data)
+{
+  size_t i;
+
+  for (i = 0; i < abbrevs->num_abbrevs; ++i)
+    backtrace_free (abbrevs->abbrevs[i].attrs,
+		    abbrevs->abbrevs[i].num_attrs * sizeof (struct attr),
+		    error_callback, data);
+  backtrace_free (abbrevs->abbrevs,
+		  abbrevs->num_abbrevs * sizeof (struct abbrev),
+		  error_callback, data);
+  abbrevs->num_abbrevs = 0;
+  abbrevs->abbrevs = NULL;
+}
+
+/* Read an attribute value.  Returns 1 on success, 0 on failure.  If
+   the value can be represented as a uint64_t, sets *VAL and sets
+   *IS_VALID to 1.  We don't try to store the value of other attribute
+   forms, because we don't care about them.  */
+
+static int
+read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
+		int is_dwarf64, int version, int addrsize,
+		const unsigned char *dwarf_str, size_t dwarf_str_size,
+		struct attr_val *val)
+{
+  switch (form)
+    {
+    case DW_FORM_addr:
+      val->encoding = ATTR_VAL_ADDRESS;
+      val->u.uint = read_address (buf, addrsize);
+      return 1;
+    case DW_FORM_block2:
+      val->encoding = ATTR_VAL_BLOCK;
+      return advance (buf, read_uint16 (buf));
+    case DW_FORM_block4:
+      val->encoding = ATTR_VAL_BLOCK;
+      return advance (buf, read_uint32 (buf));
+    case DW_FORM_data2:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = read_uint16 (buf);
+      return 1;
+    case DW_FORM_data4:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = read_uint32 (buf);
+      return 1;
+    case DW_FORM_data8:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = read_uint64 (buf);
+      return 1;
+    case DW_FORM_string:
+      val->encoding = ATTR_VAL_STRING;
+      val->u.string = (const char *) buf->buf;
+      return advance (buf, strnlen ((const char *) buf->buf, buf->left) + 1);
+    case DW_FORM_block:
+      val->encoding = ATTR_VAL_BLOCK;
+      return advance (buf, read_uleb128 (buf));
+    case DW_FORM_block1:
+      val->encoding = ATTR_VAL_BLOCK;
+      return advance (buf, read_byte (buf));
+    case DW_FORM_data1:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = read_byte (buf);
+      return 1;
+    case DW_FORM_flag:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = read_byte (buf);
+      return 1;
+    case DW_FORM_sdata:
+      val->encoding = ATTR_VAL_SINT;
+      val->u.sint = read_sleb128 (buf);
+      return 1;
+    case DW_FORM_strp:
+      {
+	uint64_t offset;
+
+	offset = read_offset (buf, is_dwarf64);
+	if (offset >= dwarf_str_size)
+	  {
+	    dwarf_buf_error (buf, "DW_FORM_strp out of range");
+	    return 0;
+	  }
+	val->encoding = ATTR_VAL_STRING;
+	val->u.string = (const char *) dwarf_str + offset;
+	return 1;
+      }
+    case DW_FORM_udata:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = read_uleb128 (buf);
+      return 1;
+    case DW_FORM_ref_addr:
+      val->encoding = ATTR_VAL_REF_INFO;
+      if (version == 2)
+	val->u.uint = read_address (buf, addrsize);
+      else
+	val->u.uint = read_offset (buf, is_dwarf64);
+      return 1;
+    case DW_FORM_ref1:
+      val->encoding = ATTR_VAL_REF_UNIT;
+      val->u.uint = read_byte (buf);
+      return 1;
+    case DW_FORM_ref2:
+      val->encoding = ATTR_VAL_REF_UNIT;
+      val->u.uint = read_uint16 (buf);
+      return 1;
+    case DW_FORM_ref4:
+      val->encoding = ATTR_VAL_REF_UNIT;
+      val->u.uint = read_uint32 (buf);
+      return 1;
+    case DW_FORM_ref8:
+      val->encoding = ATTR_VAL_REF_UNIT;
+      val->u.uint = read_uint64 (buf);
+      return 1;
+    case DW_FORM_ref_udata:
+      val->encoding = ATTR_VAL_REF_UNIT;
+      val->u.uint = read_uleb128 (buf);
+      return 1;
+    case DW_FORM_indirect:
+      {
+	uint64_t form;
+
+	form = read_uleb128 (buf);
+	return read_attribute ((enum dwarf_form) form, buf, is_dwarf64,
+			       version, addrsize, dwarf_str, dwarf_str_size,
+			       val);
+      }
+    case DW_FORM_sec_offset:
+      val->encoding = ATTR_VAL_REF_SECTION;
+      val->u.uint = read_offset (buf, is_dwarf64);
+      return 1;
+    case DW_FORM_exprloc:
+      val->encoding = ATTR_VAL_EXPR;
+      return advance (buf, read_uleb128 (buf));
+    case DW_FORM_flag_present:
+      val->encoding = ATTR_VAL_UINT;
+      val->u.uint = 1;
+      return 1;
+    case DW_FORM_ref_sig8:
+      val->encoding = ATTR_VAL_REF_TYPE;
+      val->u.uint = read_uint64 (buf);
+      return 1;
+    case DW_FORM_GNU_addr_index:
+      val->encoding = ATTR_VAL_REF_SECTION;
+      val->u.uint = read_uleb128 (buf);
+      return 1;
+    case DW_FORM_GNU_str_index:
+      val->encoding = ATTR_VAL_REF_SECTION;
+      val->u.uint = read_uleb128 (buf);
+      return 1;
+    case DW_FORM_GNU_ref_alt:
+      val->encoding = ATTR_VAL_REF_SECTION;
+      val->u.uint = read_offset (buf, is_dwarf64);
+      return 1;
+    case DW_FORM_GNU_strp_alt:
+      val->encoding = ATTR_VAL_REF_SECTION;
+      val->u.uint = read_offset (buf, is_dwarf64);
+      return 1;
+    default:
+      dwarf_buf_error (buf, "unrecognized DWARF form");
+      return 0;
+    }
+}
+
+/* Compare function_addrs for qsort.  When ranges are nested, make the
+   smallest one sort last.  */
+
+static int
+function_addrs_compare (const void *v1, const void *v2)
+{
+  const struct function_addrs *a1 = (const struct function_addrs *) v1;
+  const struct function_addrs *a2 = (const struct function_addrs *) v2;
+
+  if (a1->low < a2->low)
+    return -1;
+  if (a1->low > a2->low)
+    return 1;
+  if (a1->high < a2->high)
+    return 1;
+  if (a1->high > a2->high)
+    return -1;
+  return strcmp (a1->function->name, a2->function->name);
+}
+
+/* Compare a PC against a function_addrs for bsearch.  Note that if
+   there are multiple ranges containing PC, which one will be returned
+   is unpredictable.  We compensate for that in dwarf_fileline.  */
+
+static int
+function_addrs_search (const void *vkey, const void *ventry)
+{
+  const uintptr_t *key = (const uintptr_t *) vkey;
+  const struct function_addrs *entry = (const struct function_addrs *) ventry;
+  uintptr_t pc;
+
+  pc = *key;
+  if (pc < entry->low)
+    return -1;
+  else if (pc >= entry->high)
+    return 1;
+  else
+    return 0;
+}
+
+/* Add a new compilation unit address range to a vector.  Returns 1 on
+   success, 0 on failure.  */
+
+static int
+add_unit_addr (struct unit_addrs addrs,
+	       backtrace_error_callback error_callback, void *data,
+	       struct unit_addrs_vector *vec)
+{
+  struct unit_addrs *p;
+
+  /* Try to merge with the last entry.  */
+  if (vec->count > 0)
+    {
+      p = (struct unit_addrs *) vec->vec.base + (vec->count - 1);
+      if ((addrs.low == p->high || addrs.low == p->high + 1)
+	  && addrs.u == p->u)
+	{
+	  if (addrs.high > p->high)
+	    p->high = addrs.high;
+	  return 1;
+	}
+    }
+
+  p = ((struct unit_addrs *)
+       backtrace_vector_grow (sizeof (struct unit_addrs), error_callback,
+			      data, &vec->vec));
+  if (p == NULL)
+    return 0;
+
+  *p = addrs;
+  ++vec->count;
+  return 1;
+}
+
+/* Free a unit address vector.  */
+
+static void
+free_unit_addrs_vector (struct unit_addrs_vector *vec,
+			backtrace_error_callback error_callback, void *data)
+{
+  struct unit_addrs *addrs;
+  size_t i;
+
+  addrs = (struct unit_addrs *) vec->vec.base;
+  for (i = 0; i < vec->count; ++i)
+    free_abbrevs (&addrs[i].u->abbrevs, error_callback, data);
+}
+
+/* Compare unit_addrs for qsort.  When ranges are nested, make the
+   smallest one sort last.  */
+
+static int
+unit_addrs_compare (const void *v1, const void *v2)
+{
+  const struct unit_addrs *a1 = (const struct unit_addrs *) v1;
+  const struct unit_addrs *a2 = (const struct unit_addrs *) v2;
+
+  if (a1->low < a2->low)
+    return -1;
+  if (a1->low > a2->low)
+    return 1;
+  if (a1->high < a2->high)
+    return 1;
+  if (a1->high > a2->high)
+    return -1;
+  if (a1->u->lineoff < a2->u->lineoff)
+    return -1;
+  if (a1->u->lineoff > a2->u->lineoff)
+    return 1;
+  return 0;
+}
+
+/* Compare a PC against a unit_addrs for bsearch.  Note that if there
+   are multiple ranges containing PC, which one will be returned is
+   unpredictable.  We compensate for that in dwarf_fileline.  */
+
+static int
+unit_addrs_search (const void *vkey, const void *ventry)
+{
+  const uintptr_t *key = (const uintptr_t *) vkey;
+  const struct unit_addrs *entry = (const struct unit_addrs *) ventry;
+  uintptr_t pc;
+
+  pc = *key;
+  if (pc < entry->low)
+    return -1;
+  else if (pc >= entry->high)
+    return 1;
+  else
+    return 0;
+}
+
+/* Sort the line vector by PC.  We want a stable sort here.  We know
+   that the pointers are into the same array, so it is safe to compare
+   them directly.  */
+
+static int
+line_compare (const void *v1, const void *v2)
+{
+  const struct line *ln1 = (const struct line *) v1;
+  const struct line *ln2 = (const struct line *) v2;
+
+  if (ln1->pc < ln2->pc)
+    return -1;
+  else if (ln1->pc > ln2->pc)
+    return 1;
+  else if (ln1 < ln2)
+    return -1;
+  else if (ln1 > ln2)
+    return 1;
+  else
+    return 0;
+}
+
+/* Find a PC in a line vector.  We always allocate an extra entry at
+   the end of the lines vector, so that this routine can safely look
+   at the next entry.  Note that when there are multiple mappings for
+   the same PC value, this will return the last one.  */
+
+static int
+line_search (const void *vkey, const void *ventry)
+{
+  const uintptr_t *key = (const uintptr_t *) vkey;
+  const struct line *entry = (const struct line *) ventry;
+  uintptr_t pc;
+
+  pc = *key;
+  if (pc < entry->pc)
+    return -1;
+  else if (pc >= (entry + 1)->pc)
+    return 1;
+  else
+    return 0;
+}
+
+/* Sort the abbrevs by the abbrev code.  This function is passed to
+   both qsort and bsearch.  */
+
+static int
+abbrev_compare (const void *v1, const void *v2)
+{
+  const struct abbrev *a1 = (const struct abbrev *) v1;
+  const struct abbrev *a2 = (const struct abbrev *) v2;
+
+  if (a1->code < a2->code)
+    return -1;
+  else if (a1->code > a2->code)
+    return 1;
+  else
+    {
+      /* This really shouldn't happen.  It means there are two
+	 different abbrevs with the same code, and that means we don't
+	 know which one lookup_abbrev should return.  */
+      return 0;
+    }
+}
+
+/* Read the abbreviation table for a compilation unit.  Returns 1 on
+   success, 0 on failure.  */
+
+static int
+read_abbrevs (uint64_t abbrev_offset, const unsigned char *dwarf_abbrev,
+	      size_t dwarf_abbrev_size, int is_bigendian,
+	      backtrace_error_callback error_callback, void *data,
+	      struct abbrevs *abbrevs)
+{
+  struct dwarf_buf abbrev_buf;
+  struct dwarf_buf count_buf;
+  size_t num_abbrevs;
+
+  abbrevs->num_abbrevs = 0;
+  abbrevs->abbrevs = NULL;
+
+  if (abbrev_offset >= dwarf_abbrev_size)
+    {
+      error_callback (data, "abbrev offset out of range", 0);
+      return 0;
+    }
+
+  abbrev_buf.name = ".debug_abbrev";
+  abbrev_buf.start = dwarf_abbrev;
+  abbrev_buf.buf = dwarf_abbrev + abbrev_offset;
+  abbrev_buf.left = dwarf_abbrev_size - abbrev_offset;
+  abbrev_buf.is_bigendian = is_bigendian;
+  abbrev_buf.error_callback = error_callback;
+  abbrev_buf.data = data;
+  abbrev_buf.reported_underflow = 0;
+
+  /* Count the number of abbrevs in this list.  */
+
+  count_buf = abbrev_buf;
+  num_abbrevs = 0;
+  while (read_uleb128 (&count_buf) != 0)
+    {
+      if (count_buf.reported_underflow)
+	return 0;
+      ++num_abbrevs;
+      // Skip tag.
+      read_uleb128 (&count_buf);
+      // Skip has_children.
+      read_byte (&count_buf);
+      // Skip attributes.
+      while (read_uleb128 (&count_buf) != 0)
+	read_uleb128 (&count_buf);
+      // Skip form of last attribute.
+      read_uleb128 (&count_buf);
+    }
+
+  if (count_buf.reported_underflow)
+    return 0;
+
+  if (num_abbrevs == 0)
+    return 1;
+
+  abbrevs->num_abbrevs = num_abbrevs;
+  abbrevs->abbrevs = ((struct abbrev *)
+		      backtrace_alloc (num_abbrevs * sizeof (struct abbrev),
+				       error_callback, data));
+  if (abbrevs->abbrevs == NULL)
+    return 0;
+  memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev));
+
+  num_abbrevs = 0;
+  while (1)
+    {
+      uint64_t code;
+      struct abbrev a;
+      size_t num_attrs;
+      struct attr *attrs;
+
+      if (abbrev_buf.reported_underflow)
+	goto fail;
+
+      code = read_uleb128 (&abbrev_buf);
+      if (code == 0)
+	break;
+
+      a.code = code;
+      a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf);
+      a.has_children = read_byte (&abbrev_buf);
+
+      count_buf = abbrev_buf;
+      num_attrs = 0;
+      while (read_uleb128 (&count_buf) != 0)
+	{
+	  ++num_attrs;
+	  read_uleb128 (&count_buf);
+	}
+
+      if (num_attrs == 0)
+	{
+	  attrs = NULL;
+	  read_uleb128 (&abbrev_buf);
+	  read_uleb128 (&abbrev_buf);
+	}
+      else
+	{
+	  attrs = ((struct attr *)
+		   backtrace_alloc (num_attrs * sizeof *attrs,
+				    error_callback, data));
+	  if (attrs == NULL)
+	    goto fail;
+	  num_attrs = 0;
+	  while (1)
+	    {
+	      uint64_t name;
+	      uint64_t form;
+
+	      name = read_uleb128 (&abbrev_buf);
+	      form = read_uleb128 (&abbrev_buf);
+	      if (name == 0)
+		break;
+	      attrs[num_attrs].name = (enum dwarf_attribute) name;
+	      attrs[num_attrs].form = (enum dwarf_form) form;
+	      ++num_attrs;
+	    }
+	}
+
+      a.num_attrs = num_attrs;
+      a.attrs = attrs;
+
+      abbrevs->abbrevs[num_abbrevs] = a;
+      ++num_abbrevs;
+    }
+
+  qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, sizeof (struct abbrev),
+	 abbrev_compare);
+
+  return 1;
+
+ fail:
+  free_abbrevs (abbrevs, error_callback, data);
+  return 0;
+}
+
+/* Return the abbrev information for an abbrev code.  */
+
+static const struct abbrev *
+lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
+	       backtrace_error_callback error_callback, void *data)
+{
+  struct abbrev key;
+  void *p;
+
+  /* With GCC, where abbrevs are simply numbered in order, we should
+     be able to just look up the entry.  */
+  if (code - 1 < abbrevs->num_abbrevs
+      && abbrevs->abbrevs[code - 1].code == code)
+    return &abbrevs->abbrevs[code - 1];
+
+  /* Otherwise we have to search.  */
+  memset (&key, 0, sizeof key);
+  key.code = code;
+  p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs,
+	       sizeof (struct abbrev), abbrev_compare);
+  if (p == NULL)
+    {
+      error_callback (data, "invalid abbreviation code", 0);
+      return NULL;
+    }
+  return (const struct abbrev *) p;
+}
+
+/* Add non-contiguous address ranges for a compilation unit.  Returns
+   1 on success, 0 on failure.  */
+
+static int
+add_unit_ranges (struct unit *u, uint64_t ranges, uint64_t base,
+		 int is_bigendian, const unsigned char *dwarf_ranges,
+		 size_t dwarf_ranges_size,
+		 backtrace_error_callback error_callback, void *data,
+		 struct unit_addrs_vector *addrs)
+{
+  struct dwarf_buf ranges_buf;
+
+  if (ranges >= dwarf_ranges_size)
+    {
+      error_callback (data, "ranges offset out of range", 0);
+      return 0;
+    }
+
+  ranges_buf.name = ".debug_ranges";
+  ranges_buf.start = dwarf_ranges;
+  ranges_buf.buf = dwarf_ranges + ranges;
+  ranges_buf.left = dwarf_ranges_size - ranges;
+  ranges_buf.is_bigendian = is_bigendian;
+  ranges_buf.error_callback = error_callback;
+  ranges_buf.data = data;
+  ranges_buf.reported_underflow = 0;
+
+  while (1)
+    {
+      uint64_t low;
+      uint64_t high;
+
+      if (ranges_buf.reported_underflow)
+	return 0;
+
+      low = read_address (&ranges_buf, u->addrsize);
+      high = read_address (&ranges_buf, u->addrsize);
+
+      if (low == 0 && high == 0)
+	break;
+
+      if (is_highest_address (low, u->addrsize))
+	base = high;
+      else
+	{
+	  struct unit_addrs a;
+
+	  a.low = low + base;
+	  a.high = high + base;
+	  a.u = u;
+	  if (!add_unit_addr (a, error_callback, data, addrs))
+	    return 0;
+	}
+    }
+
+  if (ranges_buf.reported_underflow)
+    return 0;
+
+  return 1;
+}
+
+/* Build a mapping from address ranges to the compilation units where
+   the line number information for that range can be found.  Returns 1
+   on success, 0 on failure.  */
+
+static int
+build_address_map (const unsigned char *dwarf_info, size_t dwarf_info_size,
+		   const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
+		   const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
+		   const unsigned char *dwarf_str, size_t dwarf_str_size,
+		   int is_bigendian, backtrace_error_callback error_callback,
+		   void *data, struct unit_addrs_vector *addrs)
+{
+  struct dwarf_buf info;
+  struct abbrevs abbrevs;
+
+  memset (&addrs->vec, 0, sizeof addrs->vec);
+  addrs->count = 0;
+
+  /* Read through the .debug_info section.  FIXME: Should we use the
+     .debug_aranges section?  gdb and addr2line don't use it, but I'm
+     not sure why.  */
+
+  info.name = ".debug_info";
+  info.start = dwarf_info;
+  info.buf = dwarf_info;
+  info.left = dwarf_info_size;
+  info.is_bigendian = is_bigendian;
+  info.error_callback = error_callback;
+  info.data = data;
+  info.reported_underflow = 0;
+
+  memset (&abbrevs, 0, sizeof abbrevs);
+  while (info.left > 0)
+    {
+      const unsigned char *unit_data_start;
+      uint64_t len;
+      int is_dwarf64;
+      struct dwarf_buf unit_buf;
+      int version;
+      uint64_t abbrev_offset;
+      const struct abbrev *abbrev;
+      int addrsize;
+      const unsigned char *unit_data;
+      size_t unit_data_len;
+      size_t unit_data_offset;
+      uint64_t code;
+      size_t i;
+      uint64_t lowpc;
+      int have_lowpc;
+      uint64_t highpc;
+      int have_highpc;
+      int highpc_is_relative;
+      uint64_t ranges;
+      int have_ranges;
+      uint64_t lineoff;
+      int have_lineoff;
+      const char *comp_dir;
+
+      if (info.reported_underflow)
+	goto fail;
+
+      unit_data_start = info.buf;
+
+      is_dwarf64 = 0;
+      len = read_uint32 (&info);
+      if (len == 0xffffffff)
+	{
+	  len = read_uint64 (&info);
+	  is_dwarf64 = 1;
+	}
+
+      unit_buf = info;
+      unit_buf.start = info.buf;
+      unit_buf.left = len;
+
+      if (!advance (&info, len))
+	goto fail;
+
+      version = read_uint16 (&unit_buf);
+      if (version < 2 || version > 4)
+	{
+	  dwarf_buf_error (&unit_buf, "unrecognized DWARF version");
+	  goto fail;
+	}
+
+      abbrev_offset = read_offset (&unit_buf, is_dwarf64);
+      if (!read_abbrevs (abbrev_offset, dwarf_abbrev, dwarf_abbrev_size,
+			 is_bigendian, error_callback, data, &abbrevs))
+	goto fail;
+
+      addrsize = read_byte (&unit_buf);
+
+      unit_data = unit_buf.buf;
+      unit_data_len = unit_buf.left;
+      unit_data_offset = unit_buf.buf - unit_data_start;
+
+      /* We only look at the first attribute in the compilation unit.
+	 In practice this will be a DW_TAG_compile_unit which will
+	 tell us the PC range and where to find the line number
+	 information.  */
+
+      code = read_uleb128 (&unit_buf);
+      abbrev = lookup_abbrev (&abbrevs, code, error_callback, data);
+      if (abbrev == NULL)
+	goto fail;
+
+      lowpc = 0;
+      have_lowpc = 0;
+      highpc = 0;
+      have_highpc = 0;
+      highpc_is_relative = 0;
+      ranges = 0;
+      have_ranges = 0;
+      lineoff = 0;
+      have_lineoff = 0;
+      comp_dir = NULL;
+      for (i = 0; i < abbrev->num_attrs; ++i)
+	{
+	  struct attr_val val;
+
+	  if (!read_attribute (abbrev->attrs[i].form, &unit_buf, is_dwarf64,
+			       version, addrsize, dwarf_str, dwarf_str_size,
+			       &val))
+	    goto fail;
+
+	  switch (abbrev->attrs[i].name)
+	    {
+	    case DW_AT_low_pc:
+	      if (val.encoding == ATTR_VAL_ADDRESS)
+		{
+		  lowpc = val.u.uint;
+		  have_lowpc = 1;
+		}
+	      break;
+	    case DW_AT_high_pc:
+	      if (val.encoding == ATTR_VAL_ADDRESS)
+		{
+		  highpc = val.u.uint;
+		  have_highpc = 1;
+		}
+	      else if (val.encoding == ATTR_VAL_UINT)
+		{
+		  highpc = val.u.uint;
+		  have_highpc = 1;
+		  highpc_is_relative = 1;
+		}
+	      break;
+	    case DW_AT_ranges:
+	      if (val.encoding == ATTR_VAL_UINT
+		  || val.encoding == ATTR_VAL_REF_SECTION)
+		{
+		  ranges = val.u.uint;
+		  have_ranges = 1;
+		}
+	      break;
+	    case DW_AT_stmt_list:
+	      if (val.encoding == ATTR_VAL_UINT
+		  || val.encoding == ATTR_VAL_REF_SECTION)
+		{
+		  lineoff = val.u.uint;
+		  have_lineoff = 1;
+		}
+	      break;
+	    case DW_AT_comp_dir:
+	      if (val.encoding == ATTR_VAL_STRING)
+		comp_dir = val.u.string;
+	      break;
+	    default:
+	      break;
+	    }
+	}
+
+      if (unit_buf.reported_underflow)
+	goto fail;
+
+      if (((have_lowpc && have_highpc) || have_ranges) && have_lineoff)
+	{
+	  struct unit *u;
+	  struct unit_addrs a;
+
+	  u = ((struct unit *)
+	       backtrace_alloc (sizeof *u, error_callback, data));
+	  if (u == NULL)
+	    goto fail;
+	  u->unit_data = unit_data;
+	  u->unit_data_len = unit_data_len;
+	  u->unit_data_offset = unit_data_offset;
+	  u->version = version;
+	  u->is_dwarf64 = is_dwarf64;
+	  u->addrsize = addrsize;
+	  u->comp_dir = comp_dir;
+	  u->lineoff = lineoff;
+	  u->abbrevs = abbrevs;
+	  memset (&abbrevs, 0, sizeof abbrevs);
+
+	  /* The actual line number mappings will be read as
+	     needed.  */
+	  u->lines = NULL;
+	  u->lines_count = 0;
+
+	  if (have_ranges)
+	    {
+	      if (!add_unit_ranges (u, ranges, lowpc, is_bigendian,
+				    dwarf_ranges, dwarf_ranges_size,
+				    error_callback, data, addrs))
+		{
+		  free_abbrevs (&u->abbrevs, error_callback, data);
+		  backtrace_free (u, sizeof *u, error_callback, data);
+		  goto fail;
+		}
+	    }
+	  else
+	    {
+	      if (highpc_is_relative)
+		highpc += lowpc;
+	      a.low = lowpc;
+	      a.high = highpc;
+	      a.u = u;
+
+	      if (!add_unit_addr (a, error_callback, data, addrs))
+		{
+		  free_abbrevs (&u->abbrevs, error_callback, data);
+		  backtrace_free (u, sizeof *u, error_callback, data);
+		  goto fail;
+		}
+	    }
+	}
+      else
+	{
+	  free_abbrevs (&abbrevs, error_callback, data);
+	  memset (&abbrevs, 0, sizeof abbrevs);
+	}
+    }
+  if (info.reported_underflow)
+    goto fail;
+
+  return 1;
+
+ fail:
+  free_abbrevs (&abbrevs, error_callback, data);
+  free_unit_addrs_vector (addrs, error_callback, data);
+  return 0;
+}
+
+/* Add a new mapping to the vector of line mappings that we are
+   building.  Returns 1 on success, 0 on failure.  */
+
+static int
+add_line (uintptr_t pc, const char *filename, int lineno,
+	  backtrace_error_callback error_callback, void *data,
+	  struct line_vector *vec)
+{
+  struct line *ln;
+
+  /* If we are adding the same mapping, ignore it.  This can happen
+     when using discriminators.  */
+  if (vec->count > 0)
+    {
+      ln = (struct line *) vec->vec.base + (vec->count - 1);
+      if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)
+	return 1;
+    }
+
+  ln = ((struct line *)
+	backtrace_vector_grow (sizeof (struct line), error_callback, data,
+			       &vec->vec));
+  if (ln == NULL)
+    return 0;
+
+  ln->pc = pc;
+  ln->filename = filename;
+  ln->lineno = lineno;
+
+  ++vec->count;
+
+  return 1;
+}
+
+/* Free the line header information.  If FREE_FILENAMES is true we
+   free the file names themselves, otherwise we leave them, as there
+   may be line structures pointing to them.  */
+
+static void
+free_line_header (struct line_header *hdr,
+		  backtrace_error_callback error_callback, void *data)
+{
+  backtrace_free (hdr->dirs, hdr->dirs_count * sizeof (const char *),
+		  error_callback, data);
+  backtrace_free (hdr->filenames, hdr->filenames_count * sizeof (char *),
+		  error_callback, data);
+}
+
+/* Read the line header.  Return 1 on success, 0 on failure.  */
+
+static int
+read_line_header (struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf,
+		  struct line_header *hdr)
+{
+  uint64_t hdrlen;
+  struct dwarf_buf hdr_buf;
+  const unsigned char *p;
+  const unsigned char *pend;
+  size_t i;
+
+  hdr->version = read_uint16 (line_buf);
+  if (hdr->version < 2 || hdr->version > 4)
+    {
+      dwarf_buf_error (line_buf, "unsupported line number version");
+      return 0;
+    }
+
+  hdrlen = read_offset (line_buf, is_dwarf64);
+
+  hdr_buf = *line_buf;
+  hdr_buf.left = hdrlen;
+
+  if (!advance (line_buf, hdrlen))
+    return 0;
+  
+  hdr->min_insn_len = read_byte (&hdr_buf);
+  if (hdr->version < 4)
+    hdr->max_ops_per_insn = 1;
+  else
+    hdr->max_ops_per_insn = read_byte (&hdr_buf);
+
+  /* We don't care about default_is_stmt.  */
+  read_byte (&hdr_buf);
+  
+  hdr->line_base = read_sbyte (&hdr_buf);
+  hdr->line_range = read_byte (&hdr_buf);
+
+  hdr->opcode_base = read_byte (&hdr_buf);
+  hdr->opcode_lengths = hdr_buf.buf;
+  if (!advance (&hdr_buf, hdr->opcode_base - 1))
+    return 0;
+
+  /* Count the number of directory entries.  */
+  hdr->dirs_count = 0;
+  p = hdr_buf.buf;
+  pend = p + hdr_buf.left;
+  while (p < pend && *p != '\0')
+    {
+      p += strnlen((const char *) p, pend - p) + 1;
+      ++hdr->dirs_count;
+    }
+
+  hdr->dirs = ((const char **)
+	       backtrace_alloc (hdr->dirs_count * sizeof (const char *),
+				line_buf->error_callback, line_buf->data));
+  if (hdr->dirs == NULL)
+    return 0;
+
+  i = 0;
+  while (*hdr_buf.buf != '\0')
+    {
+      if (hdr_buf.reported_underflow)
+	return 0;
+
+      hdr->dirs[i] = (const char *) hdr_buf.buf;
+      ++i;
+      if (!advance (&hdr_buf,
+		    strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1))
+	return 0;
+    }
+  if (!advance (&hdr_buf, 1))
+    return 0;
+
+  /* Count the number of file entries.  */
+  hdr->filenames_count = 0;
+  p = hdr_buf.buf;
+  pend = p + hdr_buf.left;
+  while (p < pend && *p != '\0')
+    {
+      p += strnlen ((const char *) p, pend - p) + 1;
+      p += leb128_len (p);
+      p += leb128_len (p);
+      p += leb128_len (p);
+      ++hdr->filenames_count;
+    }
+
+  hdr->filenames = ((const char **)
+		    backtrace_alloc (hdr->filenames_count * sizeof (char *),
+				     line_buf->error_callback,
+				     line_buf->data));
+  if (hdr->filenames == NULL)
+    return 0;
+  i = 0;
+  while (*hdr_buf.buf != '\0')
+    {
+      const char *filename;
+      uint64_t dir_index;
+
+      if (hdr_buf.reported_underflow)
+	return 0;
+
+      filename = (const char *) hdr_buf.buf;
+      if (!advance (&hdr_buf,
+		    strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1))
+	return 0;
+      dir_index = read_uleb128 (&hdr_buf);
+      if (IS_ABSOLUTE_PATH (filename))
+	hdr->filenames[i] = filename;
+      else
+	{
+	  const char *dir;
+	  size_t dir_len;
+	  size_t filename_len;
+	  char *s;
+
+	  if (dir_index == 0)
+	    dir = u->comp_dir;
+	  else if (dir_index - 1 < hdr->dirs_count)
+	    dir = hdr->dirs[dir_index - 1];
+	  else
+	    {
+	      dwarf_buf_error (line_buf,
+			       ("invalid directory index in "
+				"line number program header"));
+	      return 0;
+	    }
+	  dir_len = strlen (dir);
+	  filename_len = strlen (filename);
+	  s = ((char *)
+	       backtrace_alloc (dir_len + filename_len + 2,
+				line_buf->error_callback, line_buf->data));
+	  if (s == NULL)
+	    return 0;
+	  memcpy (s, dir, dir_len);
+	  /* FIXME: If we are on a DOS-based file system, and the
+	     directory or the file name use backslashes, then we
+	     should use a backslash here.  */
+	  s[dir_len] = '/';
+	  memcpy (s + dir_len + 1, filename, filename_len + 1);
+	  hdr->filenames[i] = s;
+	}
+
+      /* Ignore the modification time and size.  */
+      read_uleb128 (&hdr_buf);
+      read_uleb128 (&hdr_buf);
+
+      ++i;
+    }
+
+  if (hdr_buf.reported_underflow)
+    return 0;
+
+  return 1;
+}
+
+/* Read the line program, adding line mappings to VEC.  Return 1 on
+   success, 0 on failure.  */
+
+static int
+read_line_program (struct unit *u, const struct line_header *hdr,
+		   struct dwarf_buf *line_buf, struct line_vector *vec)
+{
+  uint64_t address;
+  unsigned int op_index;
+  const char *reset_filename;
+  const char *filename;
+  int lineno;
+
+  address = 0;
+  op_index = 0;
+  if (hdr->filenames_count > 0)
+    reset_filename = hdr->filenames[0];
+  else
+    reset_filename = "";
+  filename = reset_filename;
+  lineno = 1;
+  while (line_buf->left > 0)
+    {
+      unsigned int op;
+
+      op = read_byte (line_buf);
+      if (op >= hdr->opcode_base)
+	{
+	  unsigned int advance;
+
+	  /* Special opcode.  */
+	  op -= hdr->opcode_base;
+	  advance = op / hdr->line_range;
+	  address += (hdr->min_insn_len * (op_index + advance)
+		      / hdr->max_ops_per_insn);
+	  op_index = (op_index + advance) % hdr->max_ops_per_insn;
+	  lineno += hdr->line_base + (int) (op % hdr->line_range);
+	  add_line (address, filename, lineno, line_buf->error_callback,
+		    line_buf->data, vec);
+	}
+      else if (op == DW_LNS_extended_op)
+	{
+	  uint64_t len;
+
+	  len = read_uleb128 (line_buf);
+	  op = read_byte (line_buf);
+	  switch (op)
+	    {
+	    case DW_LNE_end_sequence:
+	      /* FIXME: Should we mark the high PC here?  It seems
+		 that we already have that information from the
+		 compilation unit.  */
+	      address = 0;
+	      op_index = 0;
+	      filename = reset_filename;
+	      lineno = 1;
+	      break;
+	    case DW_LNE_set_address:
+	      address = read_address (line_buf, u->addrsize);
+	      break;
+	    case DW_LNE_define_file:
+	      {
+		const char *f;
+		unsigned int dir_index;
+
+		f = (const char *) line_buf->buf;
+		if (!advance (line_buf, strnlen (f, line_buf->left) + 1))
+		  return 0;
+		dir_index = read_uleb128 (line_buf);
+		/* Ignore that time and length.  */
+		read_uleb128 (line_buf);
+		read_uleb128 (line_buf);
+		if (IS_ABSOLUTE_PATH (f))
+		  filename = f;
+		else
+		  {
+		    const char *dir;
+		    size_t dir_len;
+		    size_t f_len;
+		    char *p;
+
+		    if (dir_index == 0)
+		      dir = u->comp_dir;
+		    else if (dir_index - 1 < hdr->dirs_count)
+		      dir = hdr->dirs[dir_index - 1];
+		    else
+		      {
+			dwarf_buf_error (line_buf,
+					 ("invalid directory index "
+					  "in line number program"));
+			return 0;
+		      }
+		    dir_len = strlen (dir);
+		    f_len = strlen (f);
+		    p = ((char *)
+			 backtrace_alloc (dir_len + f_len + 2,
+					  line_buf->error_callback,
+					  line_buf->data));
+		    if (p == NULL)
+		      return 0;
+		    memcpy (p, dir, dir_len);
+		    /* FIXME: If we are on a DOS-based file system,
+		       and the directory or the file name use
+		       backslashes, then we should use a backslash
+		       here.  */
+		    p[dir_len] = '/';
+		    memcpy (p + dir_len + 1, f, f_len + 1);
+		    filename = p;
+		  }
+	      }
+	      break;
+	    case DW_LNE_set_discriminator:
+	      /* We don't care about discriminators.  */
+	      read_uleb128 (line_buf);
+	      break;
+	    default:
+	      if (!advance (line_buf, len - 1))
+		return 0;
+	      break;
+	    }
+	}
+      else
+	{
+	  switch (op)
+	    {
+	    case DW_LNS_copy:
+	      add_line (address, filename, lineno, line_buf->error_callback,
+			line_buf->data, vec);
+	      break;
+	    case DW_LNS_advance_pc:
+	      {
+		uint64_t advance;
+
+		advance = read_uleb128 (line_buf);
+		address += (hdr->min_insn_len * (op_index + advance)
+			    / hdr->max_ops_per_insn);
+		op_index = (op_index + advance) % hdr->max_ops_per_insn;
+	      }
+	      break;
+	    case DW_LNS_advance_line:
+	      lineno += (int) read_sleb128 (line_buf);
+	      break;
+	    case DW_LNS_set_file:
+	      {
+		uint64_t fileno;
+
+		fileno = read_uleb128 (line_buf);
+		if (fileno == 0)
+		  filename = "";
+		else
+		  {
+		    if (fileno - 1 >= hdr->filenames_count)
+		      {
+			dwarf_buf_error (line_buf,
+					 ("invalid file number in "
+					  "line number program"));
+			return 0;
+		      }
+		    filename = hdr->filenames[fileno - 1];
+		  }
+	      }
+	      break;
+	    case DW_LNS_set_column:
+	      read_uleb128 (line_buf);
+	      break;
+	    case DW_LNS_negate_stmt:
+	      break;
+	    case DW_LNS_set_basic_block:
+	      break;
+	    case DW_LNS_const_add_pc:
+	      {
+		unsigned int advance;
+
+		op = 255 - hdr->opcode_base;
+		advance = op / hdr->line_range;
+		address += (hdr->min_insn_len * (op_index + advance)
+			    / hdr->max_ops_per_insn);
+		op_index = (op_index + advance) % hdr->max_ops_per_insn;
+	      }
+	      break;
+	    case DW_LNS_fixed_advance_pc:
+	      address += read_uint16 (line_buf);
+	      op_index = 0;
+	      break;
+	    case DW_LNS_set_prologue_end:
+	      break;
+	    case DW_LNS_set_epilogue_begin:
+	      break;
+	    case DW_LNS_set_isa:
+	      read_uleb128 (line_buf);
+	      break;
+	    default:
+	      {
+		unsigned int i;
+
+		for (i = hdr->opcode_lengths[op - 1]; i > 0; --i)
+		  read_uleb128 (line_buf);
+	      }
+	      break;
+	    }
+	}
+    }
+
+  return 1;
+}
+
+/* Read the line number information for a compilation unit.  This is
+   called with the backtrace lock held.  This sets U->lines and
+   U->lines_count.  Returns 1 on success, 0 on failure.  */
+
+static int
+read_line_info (struct dwarf_data *ddata,
+		backtrace_error_callback error_callback, void *data,
+		struct unit *u, struct line_header *hdr)
+{
+  struct line_vector vec;
+  struct dwarf_buf line_buf;
+  uint64_t len;
+  int is_dwarf64;
+  struct line *ln;
+
+  memset (&vec.vec, 0, sizeof vec.vec);
+  vec.count = 0;
+
+  memset (hdr, 0, sizeof *hdr);
+
+  if (u->lineoff != (off_t) (size_t) u->lineoff
+      || (size_t) u->lineoff >= ddata->dwarf_line_size)
+    {
+      error_callback (data, "unit line offset out of range", 0);
+      goto fail;
+    }
+
+  line_buf.name = ".debug_line";
+  line_buf.start = ddata->dwarf_line;
+  line_buf.buf = ddata->dwarf_line + u->lineoff;
+  line_buf.left = ddata->dwarf_line_size - u->lineoff;
+  line_buf.is_bigendian = ddata->is_bigendian;
+  line_buf.error_callback = error_callback;
+  line_buf.data = data;
+  line_buf.reported_underflow = 0;
+
+  is_dwarf64 = 0;
+  len = read_uint32 (&line_buf);
+  if (len == 0xffffffff)
+    {
+      len = read_uint64 (&line_buf);
+      is_dwarf64 = 1;
+    }
+  line_buf.left = len;
+
+  if (!read_line_header (u, is_dwarf64, &line_buf, hdr))
+    goto fail;
+
+  if (!read_line_program (u, hdr, &line_buf, &vec))
+    goto fail;
+
+  if (line_buf.reported_underflow)
+    goto fail;
+
+  if (vec.count == 0)
+    {
+      /* This is not a failure in the sense of a generating an error,
+	 but it is a failure in that sense that we have no useful
+	 information.  */
+      goto fail;
+    }
+
+  /* Allocate one extra entry at the end.  */
+  ln = ((struct line *)
+	backtrace_vector_grow (sizeof (struct line), error_callback, data,
+			       &vec.vec));
+  if (ln == NULL)
+    goto fail;
+  ln->pc = (uintptr_t) -1;
+  ln->filename = NULL;
+  ln->lineno = 0;
+
+  if (!backtrace_vector_release (&vec.vec, error_callback, data))
+    goto fail;
+
+  ln = (struct line *) vec.vec.base;
+  qsort (ln, vec.count, sizeof (struct line), line_compare);
+
+  u->lines = ln;
+  u->lines_count = vec.count;
+
+  return 1;
+
+ fail:
+  vec.vec.alc += vec.vec.size;
+  vec.vec.size = 0;
+  backtrace_vector_release (&vec.vec, error_callback, data);
+  free_line_header (hdr, error_callback, data);
+  u->lines = NULL;
+  u->lines_count = (size_t) -1;
+  return 0;
+}
+
+/* Read the name of a function from a DIE referenced by a
+   DW_AT_abstract_origin or DW_AT_specification tag.  OFFSET is within
+   the same compilation unit.  */
+
+static const char *
+read_referenced_name (struct dwarf_data *ddata, struct unit *u,
+		      uint64_t offset, backtrace_error_callback error_callback,
+		      void *data)
+{
+  struct dwarf_buf unit_buf;
+  uint64_t code;
+  const struct abbrev *abbrev;
+  const char *ret;
+  size_t i;
+
+  /* OFFSET is from the start of the data for this compilation unit.
+     U->unit_data is the data, but it starts U->unit_data_offset bytes
+     from the beginning.  */
+
+  if (offset < u->unit_data_offset
+      || offset - u->unit_data_offset >= u->unit_data_len)
+    {
+      error_callback (data,
+		      "abstract origin or specification out of range",
+		      0);
+      return NULL;
+    }
+
+  offset -= u->unit_data_offset;
+
+  unit_buf.name = ".debug_info";
+  unit_buf.start = ddata->dwarf_info;
+  unit_buf.buf = u->unit_data + offset;
+  unit_buf.left = u->unit_data_len - offset;
+  unit_buf.is_bigendian = ddata->is_bigendian;
+  unit_buf.error_callback = error_callback;
+  unit_buf.data = data;
+  unit_buf.reported_underflow = 0;
+
+  code = read_uleb128 (&unit_buf);
+  if (code == 0)
+    {
+      dwarf_buf_error (&unit_buf, "invalid abstract origin or specification");
+      return NULL;
+    }
+
+  abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
+  if (abbrev == NULL)
+    return NULL;
+
+  ret = NULL;
+  for (i = 0; i < abbrev->num_attrs; ++i)
+    {
+      struct attr_val val;
+
+      if (!read_attribute (abbrev->attrs[i].form, &unit_buf,
+			   u->is_dwarf64, u->version, u->addrsize,
+			   ddata->dwarf_str, ddata->dwarf_str_size,
+			   &val))
+	return NULL;
+
+      switch (abbrev->attrs[i].name)
+	{
+	case DW_AT_name:
+	  /* We prefer the linkage name if get one.  */
+	  if (val.encoding == ATTR_VAL_STRING)
+	    ret = val.u.string;
+	  break;
+
+	case DW_AT_linkage_name:
+	case DW_AT_MIPS_linkage_name:
+	  if (val.encoding == ATTR_VAL_STRING)
+	    return val.u.string;
+	  break;
+
+	case DW_AT_specification:
+	  if (abbrev->attrs[i].form == DW_FORM_ref_addr
+	      || abbrev->attrs[i].form == DW_FORM_ref_sig8)
+	    {
+	      /* This refers to a specification defined in some other
+		 compilation unit.  We can handle this case if we
+		 must, but it's harder.  */
+	      break;
+	    }
+	  if (val.encoding == ATTR_VAL_UINT
+	      || val.encoding == ATTR_VAL_REF_UNIT)
+	    {
+	      const char *name;
+
+	      name = read_referenced_name (ddata, u, val.u.uint,
+					   error_callback, data);
+	      if (name != NULL)
+		ret = name;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+    }
+
+  return ret;
+}
+
+/* Add a single range to U that maps to function.  Returns 1 on
+   success, 0 on error.  */
+
+static int
+add_function_range (struct function *function, uint64_t lowpc, uint64_t highpc,
+		    backtrace_error_callback error_callback,
+		    void *data, struct function_vector *vec)
+{
+  struct function_addrs *p;
+
+  if (vec->count > 0)
+    {
+      p = (struct function_addrs *) vec->vec.base + vec->count - 1;
+      if ((lowpc == p->high || lowpc == p->high + 1)
+	  && function == p->function)
+	{
+	  if (highpc > p->high)
+	    p->high = highpc;
+	  return 1;
+	}
+    }
+
+  p = ((struct function_addrs *)
+       backtrace_vector_grow (sizeof (struct function_addrs), error_callback,
+			      data, &vec->vec));
+  if (p == NULL)
+    return 0;
+
+  p->low = lowpc;
+  p->high = highpc;
+  p->function = function;
+  ++vec->count;
+  return 1;
+}
+
+/* Add PC ranges to U that map to FUNCTION.  Returns 1 on success, 0
+   on error.  */
+
+static int
+add_function_ranges (struct dwarf_data *ddata, struct unit *u,
+		     struct function *function, uint64_t ranges,
+		     uint64_t base, backtrace_error_callback error_callback,
+		     void *data, struct function_vector *vec)
+{
+  struct dwarf_buf ranges_buf;
+
+  if (ranges >= ddata->dwarf_ranges_size)
+    {
+      error_callback (data, "function ranges offset out of range", 0);
+      return 0;
+    }
+
+  ranges_buf.name = ".debug_ranges";
+  ranges_buf.start = ddata->dwarf_ranges;
+  ranges_buf.buf = ddata->dwarf_ranges + ranges;
+  ranges_buf.left = ddata->dwarf_ranges_size - ranges;
+  ranges_buf.is_bigendian = ddata->is_bigendian;
+  ranges_buf.error_callback = error_callback;
+  ranges_buf.data = data;
+  ranges_buf.reported_underflow = 0;
+
+  while (1)
+    {
+      uint64_t low;
+      uint64_t high;
+
+      if (ranges_buf.reported_underflow)
+	return 0;
+
+      low = read_address (&ranges_buf, u->addrsize);
+      high = read_address (&ranges_buf, u->addrsize);
+
+      if (low == 0 && high == 0)
+	break;
+
+      if (is_highest_address (low, u->addrsize))
+	base = high;
+      else
+	{
+	  if (!add_function_range (function, low + base, high + base,
+				   error_callback, data, vec))
+	    return 0;
+	}
+    }
+
+  if (ranges_buf.reported_underflow)
+    return 0;
+
+  return 1;
+}
+
+/* Read one entry plus all its children.  Add function addresses to
+   VEC.  Returns 1 on success, 0 on error.  */
+
+static int
+read_function_entry (struct dwarf_data *ddata, struct unit *u,
+		     uint64_t base, struct dwarf_buf *unit_buf,
+		     const struct line_header *lhdr,
+		     backtrace_error_callback error_callback, void *data,
+		     struct function_vector *vec)
+{
+  while (unit_buf->left > 0)
+    {
+      uint64_t code;
+      const struct abbrev *abbrev;
+      int is_function;
+      struct function *function;
+      size_t i;
+      uint64_t lowpc;
+      int have_lowpc;
+      uint64_t highpc;
+      int have_highpc;
+      int highpc_is_relative;
+      uint64_t ranges;
+      int have_ranges;
+
+      code = read_uleb128 (unit_buf);
+      if (code == 0)
+	return 1;
+
+      abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
+      if (abbrev == NULL)
+	return 0;
+
+      is_function = (abbrev->tag == DW_TAG_subprogram
+		     || abbrev->tag == DW_TAG_entry_point
+		     || abbrev->tag == DW_TAG_inlined_subroutine);
+
+      function = NULL;
+      if (is_function)
+	{
+	  function = ((struct function *)
+		      backtrace_alloc (sizeof *function,
+				       error_callback, data));
+	  if (function == NULL)
+	    return 0;
+	  memset (function, 0, sizeof *function);
+	}
+
+      lowpc = 0;
+      have_lowpc = 0;
+      highpc = 0;
+      have_highpc = 0;
+      highpc_is_relative = 0;
+      ranges = 0;
+      have_ranges = 0;
+      for (i = 0; i < abbrev->num_attrs; ++i)
+	{
+	  struct attr_val val;
+
+	  if (!read_attribute (abbrev->attrs[i].form, unit_buf,
+			       u->is_dwarf64, u->version, u->addrsize,
+			       ddata->dwarf_str, ddata->dwarf_str_size,
+			       &val))
+	    return 0;
+
+	  /* The compile unit sets the base address for any address
+	     ranges in the function entries.  */
+	  if (abbrev->tag == DW_TAG_compile_unit
+	      && abbrev->attrs[i].name == DW_AT_low_pc
+	      && val.encoding == ATTR_VAL_ADDRESS)
+	    base = val.u.uint;
+
+	  if (is_function)
+	    {
+	      switch (abbrev->attrs[i].name)
+		{
+		case DW_AT_call_file:
+		  if (val.encoding == ATTR_VAL_UINT)
+		    {
+		      if (val.u.uint == 0)
+			function->caller_filename = "";
+		      else
+			{
+			  if (val.u.uint - 1 >= lhdr->filenames_count)
+			    {
+			      dwarf_buf_error (unit_buf,
+					       ("invalid file number in "
+						"DW_AT_call_file attribute"));
+			      return 0;
+			    }
+			  function->caller_filename =
+			    lhdr->filenames[val.u.uint - 1];
+			}
+		    }
+		  break;
+
+		case DW_AT_call_line:
+		  if (val.encoding == ATTR_VAL_UINT)
+		    function->caller_lineno = val.u.uint;
+		  break;
+
+		case DW_AT_abstract_origin:
+		case DW_AT_specification:
+		  if (abbrev->attrs[i].form == DW_FORM_ref_addr
+		      || abbrev->attrs[i].form == DW_FORM_ref_sig8)
+		    {
+		      /* This refers to an abstract origin defined in
+			 some other compilation unit.  We can handle
+			 this case if we must, but it's harder.  */
+		      break;
+		    }
+		  if (val.encoding == ATTR_VAL_UINT
+		      || val.encoding == ATTR_VAL_REF_UNIT)
+		    {
+		      const char *name;
+
+		      name = read_referenced_name (ddata, u, val.u.uint,
+						   error_callback, data);
+		      if (name != NULL)
+			function->name = name;
+		    }
+		  break;
+
+		case DW_AT_name:
+		  if (val.encoding == ATTR_VAL_STRING)
+		    {
+		      /* Don't override a name we found in some other
+			 way, as it will normally be more
+			 useful--e.g., this name is normally not
+			 mangled.  */
+		      if (function->name == NULL)
+			function->name = val.u.string;
+		    }
+		  break;
+
+		case DW_AT_linkage_name:
+		case DW_AT_MIPS_linkage_name:
+		  if (val.encoding == ATTR_VAL_STRING)
+		    function->name = val.u.string;
+		  break;
+
+		case DW_AT_low_pc:
+		  if (val.encoding == ATTR_VAL_ADDRESS)
+		    {
+		      lowpc = val.u.uint;
+		      have_lowpc = 1;
+		    }
+		  break;
+
+		case DW_AT_high_pc:
+		  if (val.encoding == ATTR_VAL_ADDRESS)
+		    {
+		      highpc = val.u.uint;
+		      have_highpc = 1;
+		    }
+		  else if (val.encoding == ATTR_VAL_UINT)
+		    {
+		      highpc = val.u.uint;
+		      have_highpc = 1;
+		      highpc_is_relative = 1;
+		    }
+		  break;
+
+		case DW_AT_ranges:
+		  if (val.encoding == ATTR_VAL_UINT
+		      || val.encoding == ATTR_VAL_REF_SECTION)
+		    {
+		      ranges = val.u.uint;
+		      have_ranges = 1;
+		    }
+		  break;
+
+		default:
+		  break;
+		}
+	    }
+	}
+
+      /* If we couldn't find a name for the function, we have no use
+	 for it.  */
+      if (is_function && function->name == NULL)
+	{
+	  backtrace_free (function, sizeof *function, error_callback, data);
+	  is_function = 0;
+	}
+
+      if (is_function)
+	{
+	  if (have_ranges)
+	    {
+	      if (!add_function_ranges (ddata, u, function, ranges, base,
+					error_callback, data, vec))
+		return 0;
+	    }
+	  else if (have_lowpc && have_highpc)
+	    {
+	      if (highpc_is_relative)
+		highpc += lowpc;
+	      if (!add_function_range (function, lowpc, highpc, error_callback,
+				       data, vec))
+		return 0;
+	    }
+	  else
+	    {
+	      backtrace_free (function, sizeof *function, error_callback,
+			      data);
+	      is_function = 0;
+	    }
+	}
+
+      if (abbrev->has_children)
+	{
+	  if (!is_function)
+	    {
+	      if (!read_function_entry (ddata, u, base, unit_buf, lhdr,
+					error_callback, data, vec))
+		return 0;
+	    }
+	  else
+	    {
+	      struct function_vector fvec;
+
+	      /* Gather any information for inlined functions in
+		 FVEC.  */
+
+	      memset (&fvec, 0, sizeof fvec);
+
+	      if (!read_function_entry (ddata, u, base, unit_buf, lhdr,
+					error_callback, data, &fvec))
+		return 0;
+
+	      if (fvec.count > 0)
+		{
+		  struct function_addrs *faddrs;
+
+		  if (!backtrace_vector_release (&fvec.vec, error_callback,
+						 data))
+		    return 0;
+
+		  faddrs = (struct function_addrs *) fvec.vec.base;
+		  qsort (faddrs, fvec.count,
+			 sizeof (struct function_addrs),
+			 function_addrs_compare);
+
+		  function->function_addrs = faddrs;
+		  function->function_addrs_count = fvec.count;
+		}
+	    }
+	}
+    }
+
+  return 1;
+}
+
+/* Read function name information for a compilation unit.  We look
+   through the whole unit looking for function tags.  This adds
+   entries to U->function_addrs.  */
+
+static void
+read_function_info (struct dwarf_data *ddata,
+		    const struct line_header *lhdr,
+		    backtrace_error_callback error_callback, void *data,
+		    struct unit *u, struct function_vector *fvec)
+{
+  struct dwarf_buf unit_buf;
+  struct function_addrs *addrs;
+  size_t addrs_count;
+
+  unit_buf.name = ".debug_info";
+  unit_buf.start = ddata->dwarf_info;
+  unit_buf.buf = u->unit_data;
+  unit_buf.left = u->unit_data_len;
+  unit_buf.is_bigendian = ddata->is_bigendian;
+  unit_buf.error_callback = error_callback;
+  unit_buf.data = data;
+  unit_buf.reported_underflow = 0;
+
+  while (unit_buf.left > 0)
+    {
+      if (!read_function_entry (ddata, u, 0, &unit_buf, lhdr, error_callback,
+				data, fvec))
+	return;
+    }
+
+  if (fvec->count == 0)
+    return;
+
+  addrs = (struct function_addrs *) fvec->vec.base;
+  addrs_count = fvec->count;
+
+  /* Finish this list of addresses, but leave the remaining space in
+     the vector available for the next function unit.  */
+  backtrace_vector_finish (&fvec->vec);
+  fvec->count = 0;
+
+  qsort (addrs, addrs_count, sizeof (struct function_addrs),
+	 function_addrs_compare);
+
+  u->function_addrs = addrs;
+  u->function_addrs_count = addrs_count;
+}
+
+/* See if PC is inlined in FUNCTION.  If it is, print out the inlined
+   information, and update FILENAME and LINENO for the caller.
+   Returns whatever CALLBACK returns, or 0 to keep going.  */
+
+static int
+report_inlined_functions (uintptr_t pc, struct function *function,
+			  backtrace_callback callback, void *data,
+			  const char **filename, int *lineno)
+{
+  struct function_addrs *function_addrs;
+  struct function *inlined;
+  int ret;
+
+  if (function->function_addrs_count == 0)
+    return 0;
+
+  function_addrs = ((struct function_addrs *)
+		    bsearch (&pc, function->function_addrs,
+			     function->function_addrs_count,
+			     sizeof (struct function_addrs),
+			     function_addrs_search));
+  if (function_addrs == NULL)
+    return 0;
+
+  while (((size_t) (function_addrs - function->function_addrs) + 1
+	  < function->function_addrs_count)
+	 && pc >= (function_addrs + 1)->low
+	 && pc < (function_addrs + 1)->high)
+    ++function_addrs;
+
+  /* We found an inlined call.  */
+
+  inlined = function_addrs->function;
+
+  /* Report any calls inlined into this one.  */
+  ret = report_inlined_functions (pc, inlined, callback, data,
+				  filename, lineno);
+  if (ret != 0)
+    return ret;
+
+  /* Report this inlined call.  */
+  ret = callback (data, pc, *filename, *lineno, inlined->name);
+  if (ret != 0)
+    return ret;
+
+  /* Our caller will report the caller of the inlined function; tell
+     it the appropriate filename and line number.  */
+  *filename = inlined->caller_filename;
+  *lineno = inlined->caller_lineno;
+
+  return 0;
+}
+
+/* Return the file/line information for a PC using the DWARF mapping
+   we built earlier.  */
+
+static int
+dwarf_fileline (void *fileline_data, uintptr_t pc, backtrace_callback callback,
+		backtrace_error_callback error_callback, void *data)
+{
+  struct dwarf_data *ddata = (struct dwarf_data *) fileline_data;
+  struct unit_addrs *entry;
+  int new_data;
+  struct line *ln;
+  struct function_addrs *function_addrs;
+  struct function *function;
+  const char *filename;
+  int lineno;
+  int ret;
+
+  /* Find an address range that includes PC.  */
+  entry = bsearch (&pc, ddata->addrs, ddata->addrs_count,
+		   sizeof (struct unit_addrs), unit_addrs_search);
+
+  if (entry == NULL)
+    return callback (data, pc, NULL, 0, NULL);
+
+  /* If there are multiple ranges that contain PC, use the last one,
+     in order to produce predictable results.  If we assume that all
+     ranges are properly nested, then the last range will be the
+     smallest one.  */
+  while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count
+	 && pc >= (entry + 1)->low
+	 && pc < (entry + 1)->high)
+    ++entry;
+
+  /* We parse the line number information as we need it, so in case we
+     are multi-threaded we need to lock.  */
+  if (!backtrace_lock (error_callback, data))
+    return 0;
+
+  /* Skip units with no useful line number information.  Note that we
+     can only look at the lines_count field of an arbitrary unit while
+     holding the lock.  */
+
+  while (entry->u->lines_count == (size_t) -1
+	 && (size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count
+	 && (entry + 1)->low <= pc
+	 && (entry + 1)->high > pc)
+    ++entry;
+
+  new_data = 0;
+  if (entry->u->lines == NULL && entry->u->lines_count != (size_t) -1)
+    {
+      struct line_header lhdr;
+
+      if (read_line_info (ddata, error_callback, data, entry->u, &lhdr))
+	{
+	  read_function_info (ddata, &lhdr, error_callback, data, entry->u,
+			      &ddata->fvec);
+	  free_line_header (&lhdr, error_callback, data);
+	}
+      new_data = 1;
+    }
+
+  if (!backtrace_unlock (error_callback, data))
+    return 0;
+
+  /* Now that we've unlocked we can't look at an arbitrary unit, but
+     we can safely look at entry->u.  */
+
+  if (entry->u->lines_count == (size_t) -1)
+    {
+      /* If reading the line number information failed in some way,
+	 try again to see if there is a better compilation unit for
+	 this PC.  */
+      if (new_data)
+	dwarf_fileline (ddata, pc, callback, error_callback, data);
+      return callback (data, pc, NULL, 0, NULL);
+    }
+
+  /* Search for PC within this unit.  */
+
+  ln = (struct line *) bsearch (&pc, entry->u->lines, entry->u->lines_count,
+				sizeof (struct line), line_search);
+  if (ln == NULL)
+    {
+      error_callback (data, "inconsistent DWARF line number info", 0);
+      return 0;
+    }
+
+  /* Search for function name within this unit.  */
+
+  if (entry->u->function_addrs_count == 0)
+    return callback (data, pc, ln->filename, ln->lineno, NULL);
+
+  function_addrs = ((struct function_addrs *)
+		    bsearch (&pc, entry->u->function_addrs,
+			     entry->u->function_addrs_count,
+			     sizeof (struct function_addrs),
+			     function_addrs_search));
+  if (function_addrs == NULL)
+    return callback (data, pc, ln->filename, ln->lineno, NULL);
+
+  /* If there are multiple function ranges that contain PC, use the
+     last one, in order to produce predictable results.  */
+
+  while (((size_t) (function_addrs - entry->u->function_addrs + 1)
+	  < entry->u->function_addrs_count)
+	 && pc >= (function_addrs + 1)->low
+	 && pc < (function_addrs + 1)->high)
+    ++function_addrs;
+
+  function = function_addrs->function;
+
+  filename = ln->filename;
+  lineno = ln->lineno;
+
+  ret = report_inlined_functions (pc, function, callback, data,
+				  &filename, &lineno);
+  if (ret != 0)
+    return ret;
+
+  return callback (data, pc, filename, lineno, function->name);
+}
+
+/* Build our data structures from the .debug_info and .debug_line
+   sections.  Set *FILELINE_FN and *FILELINE_DATA.  Return 1 on
+   success, 0 on failure.  */
+
+int
+backtrace_dwarf_initialize (const unsigned char *dwarf_info,
+			    size_t dwarf_info_size,
+			    const unsigned char *dwarf_line,
+			    size_t dwarf_line_size,
+			    const unsigned char *dwarf_abbrev,
+			    size_t dwarf_abbrev_size,
+			    const unsigned char *dwarf_ranges,
+			    size_t dwarf_ranges_size,
+			    const unsigned char *dwarf_str,
+			    size_t dwarf_str_size,
+			    int is_bigendian,
+			    backtrace_error_callback error_callback,
+			    void *data, fileline *fileline_fn,
+			    void **fileline_data)
+{
+  struct unit_addrs_vector addrs_vec;
+  struct unit_addrs *addrs;
+  size_t addrs_count;
+  struct dwarf_data *fdata;
+
+  if (!build_address_map (dwarf_info, dwarf_info_size, dwarf_abbrev,
+			  dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
+			  dwarf_str, dwarf_str_size, is_bigendian,
+			  error_callback, data, &addrs_vec))
+    return 0;
+
+  if (!backtrace_vector_release (&addrs_vec.vec, error_callback, data))
+    return 0;
+  addrs = (struct unit_addrs *) addrs_vec.vec.base;
+  addrs_count = addrs_vec.count;
+  qsort (addrs, addrs_count, sizeof (struct unit_addrs), unit_addrs_compare);
+
+  fdata = ((struct dwarf_data *)
+	   backtrace_alloc (sizeof (struct dwarf_data), error_callback, data));
+  if (fdata == NULL)
+    return 0;
+
+  fdata->addrs = addrs;
+  fdata->addrs_count = addrs_count;
+  fdata->dwarf_info = dwarf_info;
+  fdata->dwarf_info_size = dwarf_info_size;
+  fdata->dwarf_line = dwarf_line;
+  fdata->dwarf_line_size = dwarf_line_size;
+  fdata->dwarf_ranges = dwarf_ranges;
+  fdata->dwarf_ranges_size = dwarf_ranges_size;
+  fdata->dwarf_str = dwarf_str;
+  fdata->dwarf_str_size = dwarf_str_size;
+  fdata->is_bigendian = is_bigendian;
+  memset (&fdata->fvec, 0, sizeof fdata->fvec);
+
+  *fileline_fn = dwarf_fileline;
+  *fileline_data = fdata;
+
+  return 1;
+}
Index: libbacktrace/nothread.c
===================================================================
--- libbacktrace/nothread.c	(revision 0)
+++ libbacktrace/nothread.c	(revision 0)
@@ -0,0 +1,78 @@
+/* nothread.c -- Non-threading routines for the backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* The backtrace lock and unlock routines when not using threads.  */
+
+/* Acquire the lock.  */
+
+int
+backtrace_lock (backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+		void *data ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+/* Release the lock.  */
+
+int
+backtrace_unlock (backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+		  void *data ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+/* Acquire the memory lock.  */
+
+int
+backtrace_lock_alloc (
+    backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+    void *data ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+/* Release the memory lock.  */
+
+int
+backtrace_unlock_alloc (
+    backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+    void *data ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
Index: libbacktrace/elf.c
===================================================================
--- libbacktrace/elf.c	(revision 0)
+++ libbacktrace/elf.c	(revision 0)
@@ -0,0 +1,682 @@
+/* elf.c -- Get debug data from an ELF file for backtraces.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* The configure script must tell us whether we are 32-bit or 64-bit
+   ELF.  We could make this code test and support either possibility,
+   but there is no point.  This code only works for the currently
+   running executable, which means that we know the ELF mode at
+   configure mode.  */
+
+#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64
+#error "Unknown BACKTRACE_ELF_SIZE"
+#endif
+
+/* Basic types.  */
+
+typedef uint16_t Elf_Half;
+typedef uint32_t Elf_Word;
+typedef int32_t  Elf_Sword;
+
+#if BACKTRACE_ELF_SIZE == 32
+
+typedef uint32_t Elf_Addr;
+typedef uint32_t Elf_Off;
+
+typedef uint32_t Elf_WXword;
+
+#else
+
+typedef uint64_t Elf_Addr;
+typedef uint64_t Elf_Off;
+typedef uint64_t Elf_Xword;
+typedef int64_t  Elf_Sxword;
+
+typedef uint64_t Elf_WXword;
+
+#endif
+
+/* Data structures and associated constants.  */
+
+#define EI_NIDENT 16
+
+typedef struct {
+  unsigned char	e_ident[EI_NIDENT];	/* ELF "magic number" */
+  Elf_Half	e_type;			/* Identifies object file type */
+  Elf_Half	e_machine;		/* Specifies required architecture */
+  Elf_Word	e_version;		/* Identifies object file version */
+  Elf_Addr	e_entry;		/* Entry point virtual address */
+  Elf_Off	e_phoff;		/* Program header table file offset */
+  Elf_Off	e_shoff;		/* Section header table file offset */
+  Elf_Word	e_flags;		/* Processor-specific flags */
+  Elf_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf_Half	e_phentsize;		/* Program header table entry size */
+  Elf_Half	e_phnum;		/* Program header table entry count */
+  Elf_Half	e_shentsize;		/* Section header table entry size */
+  Elf_Half	e_shnum;		/* Section header table entry count */
+  Elf_Half	e_shstrndx;		/* Section header string table index */
+} Elf_Ehdr;
+
+#define EI_MAG0 0
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+
+#define ELFMAG0 0x7f
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_CURRENT 1
+
+typedef struct {
+  Elf_Word	sh_name;		/* Section name, index in string tbl */
+  Elf_Word	sh_type;		/* Type of section */
+  Elf_WXword	sh_flags;		/* Miscellaneous section attributes */
+  Elf_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf_Off	sh_offset;		/* Section file offset */
+  Elf_WXword	sh_size;		/* Size of section in bytes */
+  Elf_Word	sh_link;		/* Index of another section */
+  Elf_Word	sh_info;		/* Additional section information */
+  Elf_WXword	sh_addralign;		/* Section alignment */
+  Elf_WXword	sh_entsize;		/* Entry size if section holds table */
+} Elf_Shdr;
+
+#define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
+#define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
+
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_DYNSYM 11
+
+#if BACKTRACE_ELF_SIZE == 32
+
+typedef struct
+{
+  Elf_Word	st_name;		/* Symbol name, index in string tbl */
+  Elf_Addr	st_value;		/* Symbol value */
+  Elf_Word	st_size;		/* Symbol size */
+  unsigned char	st_info;		/* Symbol binding and type */
+  unsigned char	st_other;		/* Visibility and other data */
+  Elf_Half	st_shndx;		/* Symbol section index */
+} Elf_Sym;
+
+#else /* BACKTRACE_ELF_SIZE != 32 */
+
+typedef struct
+{
+  Elf_Word	st_name;		/* Symbol name, index in string tbl */
+  unsigned char	st_info;		/* Symbol binding and type */
+  unsigned char	st_other;		/* Visibility and other data */
+  Elf_Half	st_shndx;		/* Symbol section index */
+  Elf_Addr	st_value;		/* Symbol value */
+  Elf_Xword	st_size;		/* Symbol size */
+} Elf_Sym;
+
+#endif /* BACKTRACE_ELF_SIZE != 32 */
+
+#define STT_FUNC 2
+
+/* An index of ELF sections we care about.  */
+
+enum debug_section
+{
+  DEBUG_INFO,
+  DEBUG_LINE,
+  DEBUG_ABBREV,
+  DEBUG_RANGES,
+  DEBUG_STR,
+  DEBUG_MAX
+};
+
+/* Names of sections, indexed by enum elf_section.  */
+
+const char * const debug_section_names[DEBUG_MAX] =
+{
+  ".debug_info",
+  ".debug_line",
+  ".debug_abbrev",
+  ".debug_ranges",
+  ".debug_str"
+};
+
+/* Information we gather for the sections we care about.  */
+
+struct debug_section_info
+{
+  /* Section file offset.  */
+  off_t offset;
+  /* Section size.  */
+  size_t size;
+  /* Section contents, after read from file.  */
+  const unsigned char *data;
+};
+
+/* Information we keep for an ELF symbol.  */
+
+struct elf_symbol
+{
+  /* The name of the symbol.  */
+  const char *name;
+  /* The address of the symbol.  */
+  uintptr_t address;
+  /* The size of the symbol.  */
+  size_t size;
+};
+
+/* Information to pass to elf_syminfo.  */
+
+struct elf_syminfo_data
+{
+  /* The ELF symbols, sorted by address.  */
+  struct elf_symbol *symbols;
+  /* The number of symbols.  */
+  size_t count;
+};
+
+/* A dummy callback function used when we can't find any debug info.  */
+
+static int
+elf_nodebug (void *fileline_data ATTRIBUTE_UNUSED,
+	     uintptr_t pc ATTRIBUTE_UNUSED,
+	     backtrace_callback callback ATTRIBUTE_UNUSED,
+	     backtrace_error_callback error_callback, void *data)
+{
+  error_callback (data, "no debug info in ELF executable", -1);
+  return 0;
+}
+
+/* A dummy callback function used when we can't find a symbol
+   table.  */
+
+static void
+elf_nosyms (void *syminfo_data ATTRIBUTE_UNUSED,
+	    uintptr_t pc ATTRIBUTE_UNUSED,
+	    backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
+	    backtrace_error_callback error_callback, void *data)
+{
+  error_callback (data, "no symbol table in ELF executable", -1);
+}
+
+/* Compare struct elf_symbol for qsort.  */
+
+static int
+elf_symbol_compare (const void *v1, const void *v2)
+{
+  const struct elf_symbol *e1 = (const struct elf_symbol *) v1;
+  const struct elf_symbol *e2 = (const struct elf_symbol *) v2;
+
+  if (e1->address < e2->address)
+    return -1;
+  else if (e1->address > e2->address)
+    return 1;
+  else
+    return 0;
+}
+
+/* Comparea PC against an elf_symbol for bsearch.  We allocate one
+   extra entry in the array so that this can look safely at the next
+   entry.  */
+
+static int
+elf_symbol_search (const void *vkey, const void *ventry)
+{
+  const uintptr_t *key = (const uintptr_t *) vkey;
+  const struct elf_symbol *entry = (const struct elf_symbol *) ventry;
+  uintptr_t pc;
+
+  pc = *key;
+  if (pc < entry->address)
+    return -1;
+  else if (pc >= entry->address + entry->size)
+    return 1;
+  else
+    return 0;
+}
+
+/* Initialize the symbol table info for elf_syminfo.  */
+
+static int
+elf_initialize_syminfo (const unsigned char *symtab_data, size_t symtab_size,
+			const unsigned char *strtab, size_t strtab_size,
+			backtrace_error_callback error_callback,
+			void *data, struct elf_syminfo_data *sdata)
+{
+  size_t sym_count;
+  const Elf_Sym *sym;
+  size_t elf_symbol_count;
+  size_t elf_symbol_size;
+  struct elf_symbol *elf_symbols;
+  size_t i;
+  unsigned int j;
+
+  sym_count = symtab_size / sizeof (Elf_Sym);
+
+  /* We only care about function symbols.  Count them.  */
+  sym = (const Elf_Sym *) symtab_data;
+  elf_symbol_count = 0;
+  for (i = 0; i < sym_count; ++i, ++sym)
+    {
+      if ((sym->st_info & 0xf) == STT_FUNC)
+	++elf_symbol_count;
+    }
+
+  elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol);
+  elf_symbols = ((struct elf_symbol *)
+		 backtrace_alloc (elf_symbol_size, error_callback, data));
+  if (elf_symbols == NULL)
+    return 0;
+
+  sym = (const Elf_Sym *) symtab_data;
+  j = 0;
+  for (i = 0; i < sym_count; ++i, ++sym)
+    {
+      if ((sym->st_info & 0xf) != STT_FUNC)
+	continue;
+      if (sym->st_name >= strtab_size)
+	{
+	  error_callback (data, "symbol string index out of range", 0);
+	  backtrace_free (elf_symbols, elf_symbol_size, error_callback, data);
+	  return 0;
+	}
+      elf_symbols[j].name = (const char *) strtab + sym->st_name;
+      elf_symbols[j].address = sym->st_value;
+      elf_symbols[j].size = sym->st_size;
+      ++j;
+    }
+
+  qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
+	 elf_symbol_compare);
+
+  sdata->symbols = elf_symbols;
+  sdata->count = elf_symbol_count;
+
+  return 1;
+}
+
+/* Return the symbol name and value for a PC.  */
+
+static void
+elf_syminfo (void *syminfo_data, uintptr_t pc,
+	     backtrace_syminfo_callback callback,
+	     backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+	     void *data)
+{
+  struct elf_syminfo_data *edata = (struct elf_syminfo_data *) syminfo_data;
+  struct elf_symbol *sym;
+
+  sym = ((struct elf_symbol *)
+	 bsearch (&pc, edata->symbols, edata->count,
+		  sizeof (struct elf_symbol), elf_symbol_search));
+  if (sym == NULL)
+    callback (data, pc, NULL, 0);
+  else
+    callback (data, pc, sym->name, sym->address);
+}
+
+/* Initialize the backtrace data we need from an ELF executable.  At
+   the ELF level, all we need to do is find the debug info
+   sections.  */
+
+int
+backtrace_initialize (int descriptor, backtrace_error_callback error_callback,
+		      void *data, fileline *fileline_fn, void **fileline_data,
+		      syminfo *syminfo_fn, void **syminfo_data)
+{
+  struct backtrace_view ehdr_view;
+  Elf_Ehdr ehdr;
+  off_t shoff;
+  unsigned int shnum;
+  unsigned int shstrndx;
+  struct backtrace_view shdrs_view;
+  int shdrs_view_valid;
+  const Elf_Shdr *shdrs;
+  const Elf_Shdr *shstrhdr;
+  size_t shstr_size;
+  off_t shstr_off;
+  struct backtrace_view names_view;
+  int names_view_valid;
+  const char *names;
+  unsigned int symtab_shndx;
+  unsigned int dynsym_shndx;
+  unsigned int i;
+  struct debug_section_info sections[DEBUG_MAX];
+  struct backtrace_view symtab_view;
+  int symtab_view_valid;
+  struct backtrace_view strtab_view;
+  int strtab_view_valid;
+  off_t min_offset;
+  off_t max_offset;
+  struct backtrace_view debug_view;
+  int debug_view_valid;
+
+  shdrs_view_valid = 0;
+  names_view_valid = 0;
+  symtab_view_valid = 0;
+  strtab_view_valid = 0;
+  debug_view_valid = 0;
+
+  if (!backtrace_get_view (descriptor, 0, sizeof ehdr, error_callback, data,
+			   &ehdr_view))
+    goto fail;
+
+  memcpy (&ehdr, ehdr_view.data, sizeof ehdr);
+
+  backtrace_release_view (&ehdr_view, error_callback, data);
+
+  if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+      || ehdr.e_ident[EI_MAG1] != ELFMAG1
+      || ehdr.e_ident[EI_MAG2] != ELFMAG2
+      || ehdr.e_ident[EI_MAG3] != ELFMAG3)
+    {
+      error_callback (data, "executable file is not ELF", 0);
+      goto fail;
+    }
+  if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
+    {
+      error_callback (data, "executable file is unrecognized ELF version", 0);
+      goto fail;
+    }
+
+#if BACKTRACE_ELF_SIZE == 32
+#define BACKTRACE_ELFCLASS ELFCLASS32
+#else
+#define BACKTRACE_ELFCLASS ELFCLASS64
+#endif
+
+  if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)
+    {
+      error_callback (data, "executable file is unexpected ELF class", 0);
+      goto fail;
+    }
+
+  if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB
+      && ehdr.e_ident[EI_DATA] != ELFDATA2MSB)
+    {
+      error_callback (data, "executable file has unknown endianness", 0);
+      goto fail;
+    }
+
+  shoff = ehdr.e_shoff;
+  shnum = ehdr.e_shnum;
+  shstrndx = ehdr.e_shstrndx;
+
+  if ((shnum == 0 || shstrndx == SHN_XINDEX)
+      && shoff != 0)
+    {
+      struct backtrace_view shdr_view;
+      const Elf_Shdr *shdr;
+
+      if (!backtrace_get_view (descriptor, shoff, sizeof shdr,
+			       error_callback, data, &shdr_view))
+	goto fail;
+
+      shdr = (const Elf_Shdr *) shdr_view.data;
+
+      if (shnum == 0)
+	shnum = shdr->sh_size;
+
+      if (shstrndx == SHN_XINDEX)
+	{
+	  shstrndx = shdr->sh_link;
+
+	  /* Versions of the GNU binutils between 2.12 and 2.18 did
+	     not handle objects with more than SHN_LORESERVE sections
+	     correctly.  All large section indexes were offset by
+	     0x100.  There is more information at
+	     http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
+	     Fortunately these object files are easy to detect, as the
+	     GNU binutils always put the section header string table
+	     near the end of the list of sections.  Thus if the
+	     section header string table index is larger than the
+	     number of sections, then we know we have to subtract
+	     0x100 to get the real section index.  */
+	  if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100)
+	    shstrndx -= 0x100;
+	}
+
+      backtrace_release_view (&shdr_view, error_callback, data);
+    }
+
+  /* To translate PC to file/line when using DWARF, we need to find
+     the .debug_info and .debug_line sections.  */
+
+  /* Read the section headers, skipping the first one.  */
+
+  if (!backtrace_get_view (descriptor, shoff + sizeof (Elf_Shdr),
+			   (shnum - 1) * sizeof (Elf_Shdr),
+			   error_callback, data, &shdrs_view))
+    goto fail;
+  shdrs_view_valid = 1;
+  shdrs = (const Elf_Shdr *) shdrs_view.data;
+
+  /* Read the section names.  */
+
+  shstrhdr = &shdrs[shstrndx - 1];
+  shstr_size = shstrhdr->sh_size;
+  shstr_off = shstrhdr->sh_offset;
+
+  if (!backtrace_get_view (descriptor, shstr_off, shstr_size,
+			   error_callback, data, &names_view))
+    goto fail;
+  names_view_valid = 1;
+  names = (const char *) names_view.data;
+
+  symtab_shndx = 0;
+  dynsym_shndx = 0;
+
+  memset (sections, 0, sizeof sections);
+  for (i = 1; i < shnum; ++i)
+    {
+      const Elf_Shdr *shdr;
+      unsigned int sh_name;
+      const char *name;
+      int j;
+
+      shdr = &shdrs[i - 1];
+
+      if (shdr->sh_type == SHT_SYMTAB)
+	symtab_shndx = i;
+      else if (shdr->sh_type == SHT_DYNSYM)
+	dynsym_shndx = i;
+
+      sh_name = shdr->sh_name;
+      if (sh_name >= shstr_size)
+	{
+	  error_callback (data, "ELF section name out of range", 0);
+	  goto fail;
+	}
+
+      name = names + sh_name;
+
+      for (j = 0; j < (int) DEBUG_MAX; ++j)
+	{
+	  if (strcmp (name, debug_section_names[j]) == 0)
+	    {
+	      sections[j].offset = shdr->sh_offset;
+	      sections[j].size = shdr->sh_size;
+	      break;
+	    }
+	}
+    }
+
+  if (symtab_shndx == 0)
+    symtab_shndx = dynsym_shndx;
+  if (symtab_shndx == 0)
+    {
+      *syminfo_fn = elf_nosyms;
+      *syminfo_data = NULL;
+    }
+  else
+    {
+      const Elf_Shdr *symtab_shdr;
+      unsigned int strtab_shndx;
+      const Elf_Shdr *strtab_shdr;
+      struct elf_syminfo_data *sdata;
+
+      symtab_shdr = &shdrs[symtab_shndx - 1];
+      strtab_shndx = symtab_shdr->sh_link;
+      if (strtab_shndx >= shnum)
+	{
+	  error_callback (data,
+			  "ELF symbol table strtab link out of range", 0);
+	  goto fail;
+	}
+      strtab_shdr = &shdrs[strtab_shndx - 1];
+
+      if (!backtrace_get_view (descriptor, symtab_shdr->sh_offset,
+			       symtab_shdr->sh_size, error_callback, data,
+			       &symtab_view))
+	goto fail;
+      symtab_view_valid = 1;
+
+      if (!backtrace_get_view (descriptor, strtab_shdr->sh_offset,
+			       strtab_shdr->sh_size, error_callback, data,
+			       &strtab_view))
+	goto fail;
+      strtab_view_valid = 1;
+
+      sdata = ((struct elf_syminfo_data *)
+	       backtrace_alloc (sizeof *sdata, error_callback, data));
+      if (sdata == NULL)
+	goto fail;
+
+      if (!elf_initialize_syminfo (symtab_view.data, symtab_shdr->sh_size,
+				   strtab_view.data, strtab_shdr->sh_size,
+				   error_callback, data, sdata))
+	{
+	  backtrace_free (sdata, sizeof *sdata, error_callback, data);
+	  goto fail;
+	}
+
+      /* We no longer need the symbol table, but we hold on to the
+	 string table permanently.  */
+      backtrace_release_view (&symtab_view, error_callback, data);
+
+      *syminfo_fn = elf_syminfo;
+      *syminfo_data = sdata;
+    }
+
+  /* FIXME: Need to handle compressed debug sections.  */
+
+  backtrace_release_view (&shdrs_view, error_callback, data);
+  shdrs_view_valid = 0;
+  backtrace_release_view (&names_view, error_callback, data);
+  names_view_valid = 0;
+
+  /* Read all the debug sections in a single view, since they are
+     probably adjacent in the file.  We never release this view.  */
+
+  min_offset = 0;
+  max_offset = 0;
+  for (i = 0; i < (int) DEBUG_MAX; ++i)
+    {
+      off_t end;
+
+      if (min_offset == 0 || sections[i].offset < min_offset)
+	min_offset = sections[i].offset;
+      end = sections[i].offset + sections[i].size;
+      if (end > max_offset)
+	max_offset = end;
+    }
+  if (min_offset == 0 || max_offset == 0)
+    {
+      if (!backtrace_close (descriptor, error_callback, data))
+	goto fail;
+      *fileline_fn = elf_nodebug;
+      *fileline_data = NULL;
+      return 1;
+    }
+
+  if (!backtrace_get_view (descriptor, min_offset, max_offset - min_offset,
+			   error_callback, data, &debug_view))
+    goto fail;
+  debug_view_valid = 1;
+
+  /* We've read all we need from the executable.  */
+  if (!backtrace_close (descriptor, error_callback, data))
+    goto fail;
+  descriptor = -1;
+
+  for (i = 0; i < (int) DEBUG_MAX; ++i)
+    sections[i].data = ((const unsigned char *) debug_view.data
+			+ (sections[i].offset - min_offset));
+
+  if (!backtrace_dwarf_initialize (sections[DEBUG_INFO].data,
+				   sections[DEBUG_INFO].size,
+				   sections[DEBUG_LINE].data,
+				   sections[DEBUG_LINE].size,
+				   sections[DEBUG_ABBREV].data,
+				   sections[DEBUG_ABBREV].size,
+				   sections[DEBUG_RANGES].data,
+				   sections[DEBUG_RANGES].size,
+				   sections[DEBUG_STR].data,
+				   sections[DEBUG_STR].size,
+				   ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
+				   error_callback, data,
+				   fileline_fn, fileline_data))
+    goto fail;
+
+  return 1;
+
+ fail:
+  if (shdrs_view_valid)
+    backtrace_release_view (&shdrs_view, error_callback, data);
+  if (names_view_valid)
+    backtrace_release_view (&names_view, error_callback, data);
+  if (symtab_view_valid)
+    backtrace_release_view (&symtab_view, error_callback, data);
+  if (strtab_view_valid)
+    backtrace_release_view (&strtab_view, error_callback, data);
+  if (debug_view_valid)
+    backtrace_release_view (&debug_view, error_callback, data);
+  if (descriptor != -1)
+    backtrace_close (descriptor, error_callback, data);
+  return 0;
+}
Index: libbacktrace/thread.c
===================================================================
--- libbacktrace/thread.c	(revision 0)
+++ libbacktrace/thread.c	(revision 0)
@@ -0,0 +1,117 @@
+/* thread.c -- Threading routines for the backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <pthread.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* The backtrace lock and unlock routines when using threads.  */
+
+/* The lock.  */
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* The lock for the memory allocator.  */
+
+static pthread_mutex_t lock_alloc = PTHREAD_MUTEX_INITIALIZER;
+
+/* Acquire the lock.  */
+
+int
+backtrace_lock (backtrace_error_callback error_callback, void *data)
+{
+  int errnum;
+
+  errnum = pthread_mutex_lock (&lock);
+  if (errnum != 0)
+    {
+      error_callback (data, "pthread_mutex_lock", errnum);
+      return 0;
+    }
+  return 1;
+}
+
+/* Release the lock.  */
+
+int
+backtrace_unlock (backtrace_error_callback error_callback, void *data)
+{
+  int errnum;
+
+  errnum = pthread_mutex_unlock (&lock);
+  if (errnum != 0)
+    {
+      error_callback (data, "pthread_mutex_unlock", errnum);
+      return 0;
+    }
+  return 1;
+}
+
+/* Acquire the memory lock.  */
+
+int
+backtrace_lock_alloc (
+    backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+    void *data ATTRIBUTE_UNUSED)
+{
+  int errnum;
+
+  errnum = pthread_mutex_lock (&lock_alloc);
+  if (errnum != 0)
+    {
+      error_callback (data, "pthread_mutex_lock", errnum);
+      return 0;
+    }
+  return 1;
+}
+
+/* Release the memory lock.  */
+
+int
+backtrace_unlock_alloc (
+    backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+    void *data ATTRIBUTE_UNUSED)
+{
+  int errnum;
+
+  errnum = pthread_mutex_unlock (&lock_alloc);
+  if (errnum != 0)
+    {
+      error_callback (data, "pthread_mutex_unlock", errnum);
+      return 0;
+    }
+  return 1;
+}
Index: libbacktrace/read.c
===================================================================
--- libbacktrace/read.c	(revision 0)
+++ libbacktrace/read.c	(revision 0)
@@ -0,0 +1,94 @@
+/* read.c -- File views without mmap.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* This file implements file views when mmap is not available.  */
+
+/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET.  */
+
+int
+backtrace_get_view (int descriptor, off_t offset, size_t size,
+		    backtrace_error_callback error_callback,
+		    void *data, struct backtrace_view *view)
+{
+  ssize_t got;
+
+  if (lseek (descriptor, offset, SEEK_SET) < 0)
+    {
+      error_callback (data, "lseek", errno);
+      return 0;
+    }
+
+  view->base = backtrace_alloc (size, error_callback, data);
+  if (view->base == NULL)
+    return 0;
+  view->data = view->base;
+  view->len = size;
+
+  got = read (descriptor, view->base, size);
+  if (got < 0)
+    {
+      error_callback (data, "read", errno);
+      free (view->base);
+      return 0;
+    }
+
+  if ((size_t) got < size)
+    {
+      error_callback (data, "file too short", 0);
+      free (view->base);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Release a view read by backtrace_get_view.  */
+
+void
+backtrace_release_view (struct backtrace_view *view,
+			backtrace_error_callback error_callback,
+			void *data)
+{
+  backtrace_free (view->base, view->len, error_callback, data);
+  view->data = NULL;
+  view->base = NULL;
+}
Index: libbacktrace/gthread.c
===================================================================
--- libbacktrace/gthread.c	(revision 0)
+++ libbacktrace/gthread.c	(revision 0)
@@ -0,0 +1,134 @@
+/* gthread.c -- GCC threading routines for the backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include "gthr-default.h"
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* The backtrace lock and unlock routines when using the GCC thread
+   interface.  */
+
+/* The lock.  */
+
+#ifdef __GTHREADS
+static __gthread_mutex_t lock = __GTHREAD_MUTEX_INIT;
+static __gthread_mutex_t lock_alloc = __GTHREAD_MUTEX_INIT;
+#endif
+
+/* Acquire the lock.  */
+
+int
+backtrace_lock (backtrace_error_callback error_callback, void *data)
+{
+  int errnum;
+
+#ifdef __GTHREADS
+  errnum = __gthread_mutex_lock (&lock);
+#else
+  errnum = 0;
+#endif
+  if (errnum != 0)
+    {
+      error_callback (data, "__gthread_mutex_lock", errnum);
+      return 0;
+    }
+  return 1;
+}
+
+/* Release the lock.  */
+
+int
+backtrace_unlock (backtrace_error_callback error_callback, void *data)
+{
+  int errnum;
+
+#ifdef __GTHREADS
+  errnum = __gthread_mutex_unlock (&lock);
+#else
+  errnum = 0;
+#endif
+  if (errnum != 0)
+    {
+      error_callback (data, "__gthread_mutex_unlock", errnum);
+      return 0;
+    }
+  return 1;
+}
+
+/* Acquire the memory lock.  */
+
+int
+backtrace_lock_alloc (
+    backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+    void *data ATTRIBUTE_UNUSED)
+{
+  int errnum;
+
+#ifdef __GTHREADS
+  errnum = __gthread_mutex_lock (&lock_alloc);
+#else
+  errnum = 0;
+#endif
+  if (errnum != 0)
+    {
+      error_callback (data, "__gthread_mutex_lock", errnum);
+      return 0;
+    }
+  return 1;
+}
+
+/* Release the memory lock.  */
+
+int
+backtrace_unlock_alloc (
+    backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+    void *data ATTRIBUTE_UNUSED)
+{
+  int errnum;
+
+#ifdef __GTHREADS
+  errnum = __gthread_mutex_unlock (&lock_alloc);
+#else
+  errnum = 0;
+#endif
+  if (errnum != 0)
+    {
+      error_callback (data, "__gthread_mutex_unlock", errnum);
+      return 0;
+    }
+  return 1;
+}
Index: libbacktrace/backtrace.c
===================================================================
--- libbacktrace/backtrace.c	(revision 0)
+++ libbacktrace/backtrace.c	(revision 0)
@@ -0,0 +1,104 @@
+/* backtrace.c -- Entry point for stack backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include "unwind.h"
+#include "backtrace.h"
+
+/* The main backtrace routine.  */
+
+/* Data passed through _Unwind_Backtrace.  */
+
+struct backtrace_data
+{
+  /* Number of frames to skip.  */
+  int skip;
+  /* Callback routine.  */
+  backtrace_callback callback;
+  /* Error callback routine.  */
+  backtrace_error_callback error_callback;
+  /* Data to pass to callback routines.  */
+  void *data;
+  /* Value to return from backtrace.  */
+  int ret;
+};
+
+/* Unwind library callback routine.  This is passed to
+   _Unwind_Backtrace.  */
+
+static _Unwind_Reason_Code
+unwind (struct _Unwind_Context *context, void *vdata)
+{
+  struct backtrace_data *bdata = (struct backtrace_data *) vdata;
+  uintptr_t pc;
+  int ip_before_insn = 0;
+
+#ifdef HAVE_GETIPINFO
+  pc = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+  pc = _Unwind_GetIP (context);
+#endif
+
+  if (bdata->skip > 0)
+    {
+      --bdata->skip;
+      return _URC_NO_REASON;
+    }
+
+  if (!ip_before_insn)
+    --pc;
+
+  bdata->ret = backtrace_pcinfo (pc, bdata->callback, bdata->error_callback,
+				 bdata->data);
+  if (bdata->ret != 0)
+    return _URC_END_OF_STACK;
+
+  return _URC_NO_REASON;
+}
+
+/* Get a stack backtrace.  */
+
+int
+backtrace (int skip, backtrace_callback callback,
+	   backtrace_error_callback error_callback, void *data)
+{
+  struct backtrace_data bdata;
+
+  bdata.skip = skip + 1;
+  bdata.callback = callback;
+  bdata.error_callback = error_callback;
+  bdata.data = data;
+  bdata.ret = 0;
+  _Unwind_Backtrace (unwind, &bdata);
+  return bdata.ret;
+}
Index: libbacktrace/internal.h
===================================================================
--- libbacktrace/internal.h	(revision 0)
+++ libbacktrace/internal.h	(revision 0)
@@ -0,0 +1,214 @@
+/* internal.h -- Internal header file for stack backtrace library.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#ifndef BACKTRACE_INTERNAL_H
+#define BACKTRACE_INTERNAL_H
+
+/* We assume that <sys/types.h> and "backtrace.h" have already been
+   included.  */
+
+#ifndef GCC_VERSION
+# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+#ifndef ATTRIBUTE_MALLOC
+# if (GCC_VERSION >= 2096)
+#  define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+#  define ATTRIBUTE_MALLOC
+# endif
+#endif
+
+/* Return the executable name, if known.  */
+
+extern const char *backtrace_executable_name (void);
+
+/* Lock the mutex that controls shared data structures.  Returns 1 on
+   success, 0 on error.  */
+
+extern int backtrace_lock (backtrace_error_callback error_callback,
+			   void *data);
+
+/* Unlock the mutex that controls shared data structures.  Returns 1
+   on success, 0 on error.  */
+
+extern int backtrace_unlock (backtrace_error_callback error_callback,
+			     void *data);
+
+/* Like backtrace_lock, for the lock for the memory allocator.  */
+
+extern int backtrace_lock_alloc (backtrace_error_callback error_callback,
+				 void *data);
+
+/* Like backtrace_unlock, for the lock for the memory allocator.  */
+
+extern int backtrace_unlock_alloc (backtrace_error_callback error_callback,
+				   void *data);
+
+/* Open a file for reading.  Returns -1 on error.  */
+extern int backtrace_open (const char *filename,
+			   backtrace_error_callback error_callback,
+			   void *data);
+
+/* A view of the contents of a file.  This supports mmap when
+   available.  A view will remain in memory even after backtrace_close
+   is called on the file descriptor from which the view was
+   obtained.  */
+
+struct backtrace_view
+{
+  /* The data that the caller requested.  */
+  const void *data;
+  /* The base of the view.  */
+  void *base;
+  /* The total length of the view.  */
+  size_t len;
+};
+
+/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET.  Store the
+   result in *VIEW.  Returns 1 on success, 0 on error.  */
+extern int backtrace_get_view (int descriptor, off_t offset, size_t size,
+			       backtrace_error_callback error_callback,
+			       void *data, struct backtrace_view *view);
+
+/* Release a view created by backtrace_get_view.  */
+extern void backtrace_release_view (struct backtrace_view *view,
+				    backtrace_error_callback error_callback,
+				    void *data);
+
+/* Close a file opened by backtrace_open.  Returns 1 on success, 0 on
+   error.  */
+
+extern int backtrace_close (int descriptor,
+			    backtrace_error_callback error_callback,
+			    void *data);
+
+/* Allocate memory.  This is like malloc.  */
+
+extern void *backtrace_alloc (size_t size,
+			      backtrace_error_callback error_callback,
+			      void *data) ATTRIBUTE_MALLOC;
+
+/* Free memory allocated by backtrace_alloc.  */
+
+extern void backtrace_free (void *mem, size_t size,
+			    backtrace_error_callback error_callback,
+			    void *data);
+
+/* A growable vector of some struct.  This is used for more efficient
+   allocation when we don't know the final size of some group of data
+   that we want to represent as an array.  */
+
+struct backtrace_vector
+{
+  /* The base of the vector.  */
+  void *base;
+  /* The number of bytes in the vector.  */
+  size_t size;
+  /* The number of bytes available at the current allocation.  */
+  size_t alc;
+};
+
+/* Grow VEC by SIZE bytes.  Return a pointer to the newly allocated
+   bytes.  Note that this may move the entire vector to a new memory
+   location.  Returns NULL on failure.  */
+
+extern void *backtrace_vector_grow (size_t size,
+				    backtrace_error_callback error_callback,
+				    void *data,
+				    struct backtrace_vector *vec);
+
+/* Finish the current allocation on VEC.  Prepare to start a new
+   allocation.  The finished allocation will never be freed.  */
+
+extern void backtrace_vector_finish (struct backtrace_vector *vec);
+
+/* Release any extra space allocated for VEC.  Returns 1 on success, 0
+   on failure.  */
+
+extern int backtrace_vector_release (struct backtrace_vector *vec,
+				     backtrace_error_callback error_callback,
+				     void *data);
+
+/* The type of the function that collects file/line information.  This
+   is like backtrace_pcinfo.  */
+
+typedef int (*fileline) (void *fileline_data, uintptr_t pc,
+			 backtrace_callback callback,
+			 backtrace_error_callback error_callback, void *data);
+
+/* The type of the function that collects symbol information.  This is
+   like backtrace_syminfo.  */
+
+typedef void (*syminfo) (void *syminfo_data, uintptr_t pc,
+			 backtrace_syminfo_callback callback,
+			 backtrace_error_callback error_callback, void *data);
+
+/* Read initial debug data from a descriptor.  This is called after
+   the descriptor has first been opened, with backtrace_lock held.
+   Returns 1 on success, 0 on error.  There will be multiple
+   implementations of this function, for different file formats.  Each
+   system will compile the appropriate one.  */
+
+extern int backtrace_initialize (int descriptor,
+				 backtrace_error_callback error_callback,
+				 void *data, fileline *fn,
+				 void **fileline_data,
+				 syminfo *sfn,
+				 void **syminfo_data);
+
+/* Prepare to read file/line information from DWARF debug data.  */
+
+extern int backtrace_dwarf_initialize (const unsigned char* dwarf_info,
+				       size_t dwarf_info_size,
+				       const unsigned char *dwarf_line,
+				       size_t dwarf_line_size,
+				       const unsigned char *dwarf_abbrev,
+				       size_t dwarf_abbrev_size,
+				       const unsigned char *dwarf_ranges,
+				       size_t dwarf_range_size,
+				       const unsigned char *dwarf_str,
+				       size_t dwarf_str_size,
+				       int is_bigendian,
+				       backtrace_error_callback error_callback,
+				       void *data,
+				       fileline *fn, void **fileline_data);
+
+#endif
Index: libbacktrace/btest.c
===================================================================
--- libbacktrace/btest.c	(revision 0)
+++ libbacktrace/btest.c	(revision 0)
@@ -0,0 +1,613 @@
+/* btest.c -- Test for libbacktrace library
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* This program tests the externally visible interfaces of the
+   libbacktrace library.  */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+/* Portable attribute syntax.  Actually some of these tests probably
+   won't work if the attributes are not recognized.  */
+
+#ifndef GCC_VERSION
+# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Used to collect backtrace info.  */
+
+struct info
+{
+  char *filename;
+  int lineno;
+  char *function;
+};
+
+/* Passed to backtrace callback function.  */
+
+struct bdata
+{
+  struct info *all;
+  size_t index;
+  size_t max;
+  int failed;
+};
+
+/* Passed to backtrace_simple callback function.  */
+
+struct sdata
+{
+  uintptr_t *addrs;
+  size_t index;
+  size_t max;
+  int failed;
+};
+
+/* Passed to backtrace_syminfo callback function.  */
+
+struct symdata
+{
+  const char *name;
+  uintptr_t val;
+  int failed;
+};
+
+/* The number of failures.  */
+
+static int failures;
+
+/* Return the base name in a path.  */
+
+static const char *
+base (const char *p)
+{
+  const char *last;
+  const char *s;
+
+  last = NULL;
+  for (s = p; *s != '\0'; ++s)
+    {
+      if (IS_DIR_SEPARATOR (*s))
+	last = s + 1;
+    }
+  return last != NULL ? last : p;
+}
+
+/* Check an entry in a struct info array.  */
+
+static void
+check (const char *name, int index, const struct info *all, int want_lineno,
+       const char *want_function, int *failed)
+{
+  if (*failed)
+    return;
+  if (strcmp (base (all[index].filename), "btest.c") != 0)
+    {
+      fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
+	       all[index].filename);
+      *failed = 1;
+    }
+  if (all[index].lineno != want_lineno)
+    {
+      fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
+	       all[index].lineno, want_lineno);
+      *failed = 1;
+    }
+  if (strcmp (all[index].function, want_function) != 0)
+    {
+      fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
+	       all[index].function, want_function);
+      *failed = 1;
+    }
+}
+
+/* The backtrace callback function.  */
+
+static int
+callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
+	      const char *filename, int lineno, const char *function)
+{
+  struct bdata *data = (struct bdata *) vdata;
+  struct info *p;
+
+  if (data->index >= data->max)
+    {
+      fprintf (stderr, "callback_one: callback called too many times\n");
+      data->failed = 1;
+      return 1;
+    }
+
+  p = &data->all[data->index];
+  if (filename == NULL)
+    p->filename = NULL;
+  else
+    {
+      p->filename = strdup (filename);
+      assert (p->filename != NULL);
+    }
+  p->lineno = lineno;
+  if (function == NULL)
+    p->function = NULL;
+  else
+    {
+      p->function = strdup (function);
+      assert (p->function != NULL);
+    }
+  ++data->index;
+
+  return 0;
+}
+
+/* An error callback passed to backtrace.  */
+
+static void
+error_callback_one (void *vdata, const char *msg, int errnum)
+{
+  struct bdata *data = (struct bdata *) vdata;
+
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  data->failed = 1;
+}
+
+/* The backtrace_simple callback function.  */
+
+static int
+callback_two (void *vdata, uintptr_t pc)
+{
+  struct sdata *data = (struct sdata *) vdata;
+
+  if (data->index >= data->max)
+    {
+      fprintf (stderr, "callback_two: callback called too many times\n");
+      data->failed = 1;
+      return 1;
+    }
+
+  data->addrs[data->index] = pc;
+  ++data->index;
+
+  return 0;
+}
+
+/* An error callback passed to backtrace_simple.  */
+
+static void
+error_callback_two (void *vdata, const char *msg, int errnum)
+{
+  struct sdata *data = (struct sdata *) vdata;
+
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  data->failed = 1;
+}
+
+/* The backtrace_syminfo callback function.  */
+
+static void
+callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
+		const char *symname, uintptr_t symval)
+{
+  struct symdata *data = (struct symdata *) vdata;
+
+  if (symname == NULL)
+    data->name = NULL;
+  else
+    {
+      data->name = strdup (symname);
+      assert (data->name != NULL);
+    }
+  data->val = symval;
+}
+
+/* The backtrace_syminfo error callback function.  */
+
+static void
+error_callback_three (void *vdata, const char *msg, int errnum)
+{
+  struct symdata *data = (struct symdata *) vdata;
+
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  data->failed = 1;
+}
+
+/* Test the backtrace function with non-inlined functions.  */
+
+static int test1 (void) __attribute__ ((noinline));
+static int f2 (int) __attribute__ ((noinline));
+static int f3 (int, int) __attribute__ ((noinline));
+
+static int
+test1 (void)
+{
+  /* Returning a value here and elsewhere avoids a tailcall which
+     would mess up the backtrace.  */
+  return f2 (__LINE__) + 1;
+}
+
+static int
+f2 (int f1line)
+{
+  return f3 (f1line, __LINE__) + 2;
+}
+
+static int
+f3 (int f1line, int f2line)
+{
+  struct info all[20];
+  struct bdata data;
+  int f3line;
+  int i;
+
+  data.all = &all[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace (0, callback_one, error_callback_one, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test1: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  check ("test1", 0, all, f3line, "f3", &data.failed);
+  check ("test1", 1, all, f2line, "f2", &data.failed);
+  check ("test1", 2, all, f1line, "test1", &data.failed);
+
+  printf ("%s: backtrace noinline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Test the backtrace function with inlined functions.  */
+
+static inline int test2 (void) __attribute__ ((always_inline));
+static inline int f12 (int) __attribute__ ((always_inline));
+static inline int f13 (int, int) __attribute__ ((always_inline));
+
+static inline int
+test2 (void)
+{
+  return f12 (__LINE__) + 1;
+}
+
+static inline int
+f12 (int f1line)
+{
+  return f13 (f1line, __LINE__) + 2;
+}
+
+static inline int
+f13 (int f1line, int f2line)
+{
+  struct info all[20];
+  struct bdata data;
+  int f3line;
+  int i;
+
+  data.all = &all[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace (0, callback_one, error_callback_one, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test2: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  check ("test2", 0, all, f3line, "f13", &data.failed);
+  check ("test2", 1, all, f2line, "f12", &data.failed);
+  check ("test2", 2, all, f1line, "test2", &data.failed);
+
+  printf ("%s: backtrace inline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Test the backtrace_simple function with non-inlined functions.  */
+
+static int test3 (void) __attribute__ ((noinline));
+static int f22 (int) __attribute__ ((noinline));
+static int f23 (int, int) __attribute__ ((noinline));
+
+static int
+test3 (void)
+{
+  return f22 (__LINE__) + 1;
+}
+
+static int
+f22 (int f1line)
+{
+  return f23 (f1line, __LINE__) + 2;
+}
+
+static int
+f23 (int f1line, int f2line)
+{
+  uintptr_t addrs[20];
+  struct sdata data;
+  int f3line;
+  int i;
+
+  data.addrs = &addrs[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace_simple (0, callback_two, error_callback_two, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test3: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  if (!data.failed)
+    {
+      struct info all[20];
+      struct bdata bdata;
+      int j;
+
+      bdata.all = &all[0];
+      bdata.index = 0;
+      bdata.max = 20;
+      bdata.failed = 0;
+
+      for (j = 0; j < 3; ++j)
+	{
+	  i = backtrace_pcinfo (addrs[j], callback_one, error_callback_one,
+				&bdata);
+	  if (i != 0)
+	    {
+	      fprintf (stderr,
+		       ("test3: unexpected return value "
+			"from backtrace_pcinfo %d\n"),
+		       i);
+	      bdata.failed = 1;
+	    }
+	  if (!bdata.failed && bdata.index != (size_t) (j + 1))
+	    {
+	      fprintf (stderr,
+		       ("wrong number of calls from backtrace_pcinfo "
+			"got %u expected %d\n"),
+		       (unsigned int) bdata.index, j + 1);
+	      bdata.failed = 1;
+	    }
+	}      
+
+      check ("test3", 0, all, f3line, "f23", &bdata.failed);
+      check ("test3", 1, all, f2line, "f22", &bdata.failed);
+      check ("test3", 2, all, f1line, "test3", &bdata.failed);
+
+      if (bdata.failed)
+	data.failed = 1;
+
+      for (j = 0; j < 3; ++j)
+	{
+	  struct symdata symdata;
+
+	  symdata.name = NULL;
+	  symdata.val = 0;
+	  symdata.failed = 0;
+
+	  i = backtrace_syminfo (addrs[j], callback_three,
+				 error_callback_three, &symdata);
+	  if (i == 0)
+	    {
+	      fprintf (stderr,
+		       ("test3: [%d]: unexpected return value "
+			"from backtrace_syminfo %d\n"),
+		       j, i);
+	      symdata.failed = 1;
+	    }
+
+	  if (!symdata.failed)
+	    {
+	      const char *expected;
+
+	      switch (j)
+		{
+		case 0:
+		  expected = "f23";
+		  break;
+		case 1:
+		  expected = "f22";
+		  break;
+		case 2:
+		  expected = "test3";
+		  break;
+		case 3:
+		  assert (0);
+		}
+
+	      if (symdata.name == NULL)
+		{
+		  fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
+		  symdata.failed = 1;
+		}
+	      /* Use strncmp, not strcmp, because GCC might create a
+		 clone.  */
+	      else if (strncmp (symdata.name, expected, strlen (expected))
+		       != 0)
+		{
+		  fprintf (stderr,
+			   ("test3: [%d]: unexpected syminfo name "
+			    "got %s expected %s\n"),
+			   j, symdata.name, expected);
+		  symdata.failed = 1;
+		}
+	    }
+
+	  if (symdata.failed)
+	    data.failed = 1;
+	}
+    }
+
+  printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Test the backtrace_simple function with inlined functions.  */
+
+static inline int test4 (void) __attribute__ ((always_inline));
+static inline int f32 (int) __attribute__ ((always_inline));
+static inline int f33 (int, int) __attribute__ ((always_inline));
+
+static inline int
+test4 (void)
+{
+  return f32 (__LINE__) + 1;
+}
+
+static inline int
+f32 (int f1line)
+{
+  return f33 (f1line, __LINE__) + 2;
+}
+
+static inline int
+f33 (int f1line, int f2line)
+{
+  uintptr_t addrs[20];
+  struct sdata data;
+  int f3line;
+  int i;
+
+  data.addrs = &addrs[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace_simple (0, callback_two, error_callback_two, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test3: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  if (!data.failed)
+    {
+      struct info all[20];
+      struct bdata bdata;
+
+      bdata.all = &all[0];
+      bdata.index = 0;
+      bdata.max = 20;
+      bdata.failed = 0;
+
+      i = backtrace_pcinfo (addrs[0], callback_one, error_callback_one,
+			    &bdata);
+      if (i != 0)
+	{
+	  fprintf (stderr,
+		   ("test4: unexpected return value "
+		    "from backtrace_pcinfo %d\n"),
+		   i);
+	  bdata.failed = 1;
+	}
+
+      check ("test4", 0, all, f3line, "f33", &bdata.failed);
+      check ("test4", 1, all, f2line, "f32", &bdata.failed);
+      check ("test4", 2, all, f1line, "test4", &bdata.failed);
+
+      if (bdata.failed)
+	data.failed = 1;
+    }
+
+  printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Run all the tests.  */
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  backtrace_set_executable_name (argv[0]);
+
+#if BACKTRACE_SUPPORTED
+  test1 ();
+  test2 ();
+  test3 ();
+  test4 ();
+#endif
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
Index: libbacktrace/mmapio.c
===================================================================
--- libbacktrace/mmapio.c	(revision 0)
+++ libbacktrace/mmapio.c	(revision 0)
@@ -0,0 +1,96 @@
+/* mmapio.c -- File views using mmap.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* This file implements file views and memory allocation when mmap is
+   available.  */
+
+/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET.  */
+
+int
+backtrace_get_view (int descriptor, off_t offset, size_t size,
+		    backtrace_error_callback error_callback,
+		    void *data, struct backtrace_view *view)
+{
+  size_t pagesize;
+  unsigned int inpage;
+  off_t pageoff;
+  void *map;
+
+  pagesize = getpagesize ();
+  inpage = offset % pagesize;
+  pageoff = offset - inpage;
+
+  size += inpage;
+  size = (size + (pagesize - 1)) & ~ (pagesize - 1);
+
+  map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff);
+  if (map == MAP_FAILED)
+    {
+      error_callback (data, "mmap", errno);
+      return 0;
+    }
+
+  view->data = (char *) map + inpage;
+  view->base = map;
+  view->len = size;
+
+  return 1;
+}
+
+/* Release a view read by backtrace_get_view.  */
+
+void
+backtrace_release_view (struct backtrace_view *view,
+			backtrace_error_callback error_callback,
+			void *data)
+{
+  union {
+    const void *cv;
+    void *v;
+  } const_cast;
+
+  const_cast.cv = view->base;
+  if (munmap (const_cast.v, view->len) < 0)
+    error_callback (data, "munmap", errno);
+}
Index: libbacktrace/fileline.c
===================================================================
--- libbacktrace/fileline.c	(revision 0)
+++ libbacktrace/fileline.c	(revision 0)
@@ -0,0 +1,150 @@
+/* fileline.c -- Get file and line number information in a backtrace.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* The name of the executable, if the program sets it.  */
+
+static const char *executable_name;
+
+/* Set the name of the executable.  */
+
+void
+backtrace_set_executable_name (const char *name)
+{
+  executable_name = name;
+}
+
+/* Get the name of the executable--an internal function, to avoid a
+   globally visible variable name.  */
+
+const char *
+backtrace_executable_name (void)
+{
+  return executable_name;
+}
+
+/* The function we call to get file/line information.  */
+
+static fileline fileline_fn;
+
+/* Data to pass to fileline_fn.  */
+
+static void *fileline_data;
+
+/* The function we call to get symbol information.  */
+
+static syminfo syminfo_fn;
+
+/* Data to pass to syminfo_fn.  */
+
+static void *syminfo_data;
+
+/* Set non-zero if we could not find the executable information.  This
+   is used so that if we are called many times we don't keep trying
+   the same failing attempt.  */
+
+static int fileline_initialization_failed;
+
+/* Initialize the fileline information from the executable.  */
+
+static void
+fileline_initialize (backtrace_error_callback error_callback, void *data)
+{
+  int descriptor;
+
+  if (!backtrace_lock (error_callback, data))
+    return;
+
+  if (fileline_fn != NULL || fileline_initialization_failed)
+    {
+      backtrace_unlock (error_callback, data);
+      if (fileline_initialization_failed)
+	error_callback (data, "failed to read executable information", 0);
+      return;
+    }
+
+  if (executable_name != NULL)
+    descriptor = backtrace_open (executable_name, error_callback, data);
+  else
+    descriptor = backtrace_open ("/proc/self/exe", error_callback, data);
+  if (descriptor < 0)
+    {
+      fileline_initialization_failed = 1;
+      backtrace_unlock (error_callback, data);
+      return;
+    }
+
+  if (!backtrace_initialize (descriptor, error_callback, data,
+			     &fileline_fn, &fileline_data, &syminfo_fn,
+			     &syminfo_data))
+    fileline_initialization_failed = 1;
+
+  if (!backtrace_unlock (error_callback, data))
+    fileline_initialization_failed = 1;
+}
+
+/* Given a PC, find the file name, line number, and function name.  */
+
+int
+backtrace_pcinfo (uintptr_t pc, backtrace_callback callback,
+		  backtrace_error_callback error_callback, void *data)
+{
+  fileline_initialize (error_callback, data);
+
+  if (fileline_initialization_failed)
+    return 0;
+
+  return fileline_fn (fileline_data, pc, callback, error_callback, data);
+}
+
+/* Given a PC, find the symbol for it, and its value.  */
+
+int
+backtrace_syminfo (uintptr_t pc, backtrace_syminfo_callback callback,
+		   backtrace_error_callback error_callback, void *data)
+{
+  fileline_initialize (error_callback, data);
+
+  if (fileline_initialization_failed)
+    return 0;
+
+  syminfo_fn (syminfo_data, pc, callback, error_callback, data);
+  return 1;
+}
Index: libbacktrace/simple.c
===================================================================
--- libbacktrace/simple.c	(revision 0)
+++ libbacktrace/simple.c	(revision 0)
@@ -0,0 +1,104 @@
+/* simple.c -- The backtrace_simple function.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include "unwind.h"
+#include "backtrace.h"
+
+/* The simple_backtrace routine.  */
+
+/* Data passed through _Unwind_Backtrace.  */
+
+struct backtrace_simple_data
+{
+  /* Number of frames to skip.  */
+  int skip;
+  /* Callback routine.  */
+  backtrace_simple_callback callback;
+  /* Error callback routine.  */
+  backtrace_error_callback error_callback;
+  /* Data to pass to callback routine.  */
+  void *data;
+  /* Value to return from backtrace.  */
+  int ret;
+};
+
+/* Unwind library callback routine.  This is passd to
+   _Unwind_Backtrace.  */
+
+static _Unwind_Reason_Code
+simple_unwind (struct _Unwind_Context *context, void *vdata)
+{
+  struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata;
+  uintptr_t pc;
+  int ip_before_insn = 0;
+
+#ifdef HAVE_GETIPINFO
+  pc = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+  pc = _Unwind_GetIP (context);
+#endif
+
+  if (bdata->skip > 0)
+    {
+      --bdata->skip;
+      return _URC_NO_REASON;
+    }
+
+  if (!ip_before_insn)
+    --pc;
+
+  bdata->ret = bdata->callback (bdata->data, pc);
+
+  if (bdata->ret != 0)
+    return _URC_END_OF_STACK;
+
+  return _URC_NO_REASON;
+}
+
+/* Get a simple stack backtrace.  */
+
+int
+backtrace_simple (int skip, backtrace_simple_callback callback,
+		  backtrace_error_callback error_callback, void *data)
+{
+  struct backtrace_simple_data bdata;
+
+  bdata.skip = skip + 1;
+  bdata.callback = callback;
+  bdata.error_callback = error_callback;
+  bdata.data = data;
+  bdata.ret = 0;
+  _Unwind_Backtrace (simple_unwind, &bdata);
+  return bdata.ret;
+}
Index: libbacktrace/mmap.c
===================================================================
--- libbacktrace/mmap.c	(revision 0)
+++ libbacktrace/mmap.c	(revision 0)
@@ -0,0 +1,226 @@
+/* mmap.c -- Memory allocation with mmap.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* Memory allocation on systems that provide anonymous mmap.  This
+   permits the backtrace functions to be invoked from a signal
+   handler, assuming that mmap is async-signal safe.  */
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* A list of free memory blocks.  */
+
+struct backtrace_freelist_struct
+{
+  /* Next on list.  */
+  struct backtrace_freelist_struct *next;
+  /* Size of this block, including this structure.  */
+  size_t size;
+};
+
+/* Free list.  */
+
+struct backtrace_freelist_struct *backtrace_freelist;
+
+/* Free memory allocated by backtrace_alloc.  */
+
+static void
+backtrace_free_locked (void *addr, size_t size)
+{
+  /* Just leak small blocks.  We don't have to be perfect.  */
+  if (size >= sizeof (struct backtrace_freelist_struct))
+    {
+      struct backtrace_freelist_struct *p;
+
+      p = (struct backtrace_freelist_struct *) addr;
+      p->next = backtrace_freelist;
+      p->size = size;
+    }
+}
+
+/* Allocate memory like malloc.  */
+
+void *
+backtrace_alloc (size_t size, backtrace_error_callback error_callback,
+		 void *data)
+{
+  void *ret;
+  struct backtrace_freelist_struct **pp;
+  size_t pagesize;
+  size_t asksize;
+  void *page;
+
+  ret = NULL;
+
+  if (!backtrace_lock_alloc (error_callback, data))
+    return NULL;
+
+  /* Take space from the free list.  */
+
+  for (pp = &backtrace_freelist; *pp != NULL; pp = &(*pp)->next)
+    {
+      if ((*pp)->size >= size)
+	{
+	  struct backtrace_freelist_struct *p;
+
+	  p = *pp;
+	  *pp = p->next;
+
+	  /* Round for alignment; we assume that no type we care about
+	     is more than 8 bytes.  */
+	  size = (size + 7) & ~ (size_t) 7;
+	  if (size < p->size)
+	    backtrace_free_locked ((char *) p + size, p->size - size);
+
+	  ret = (void *) p;
+
+	  break;
+	}
+    }
+
+  if (!backtrace_unlock_alloc (error_callback, data))
+    return NULL;
+
+  if (ret == NULL)
+    {
+      /* Allocate a new page.  */
+
+      pagesize = getpagesize ();
+      asksize = (size + pagesize - 1) & ~ (pagesize - 1);
+      page = mmap (NULL, asksize, PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (page == NULL)
+	error_callback (data, "mmap", errno);
+      else
+	{
+	  size = (size + 7) & ~ (size_t) 7;
+	  if (size < asksize)
+	    backtrace_free ((char *) page + size, asksize - size,
+			    error_callback, data);
+
+	  ret = page;
+	}
+    }
+
+  return ret;
+}
+
+/* Free memory allocated by backtrace_alloc.  */
+
+void
+backtrace_free (void *addr, size_t size,
+		backtrace_error_callback error_callback, void *data)
+{
+  if (!backtrace_lock_alloc (error_callback, data))
+    return;
+
+  backtrace_free_locked (addr, size);
+
+  backtrace_unlock_alloc (error_callback, data);
+}
+
+/* Grow VEC by SIZE bytes.  */
+
+void *
+backtrace_vector_grow (size_t size, backtrace_error_callback error_callback,
+		       void *data, struct backtrace_vector *vec)
+{
+  void *ret;
+
+  if (size > vec->alc)
+    {
+      size_t pagesize;
+      size_t alc;
+      void *base;
+
+      pagesize = getpagesize ();
+      alc = vec->size + size;
+      if (vec->size == 0)
+	alc = 16 * size;
+      else if (alc < pagesize)
+	{
+	  alc *= 2;
+	  if (alc > pagesize)
+	    alc = pagesize;
+	}
+      else
+	alc = (alc + pagesize - 1) & ~ (pagesize - 1);
+      base = backtrace_alloc (alc, error_callback, data);
+      if (base == NULL)
+	return NULL;
+      if (vec->base != NULL)
+	{
+	  memcpy (base, vec->base, vec->size);
+	  backtrace_free (vec->base, vec->alc, error_callback, data);
+	}
+      vec->base = base;
+      vec->alc = alc - vec->size;
+    }
+
+  ret = (char *) vec->base + vec->size;
+  vec->size += size;
+  vec->alc -= size;
+  return ret;
+}
+
+/* Finish the current allocation on VEC.  */
+
+void
+backtrace_vector_finish (struct backtrace_vector *vec)
+{
+  vec->base = (char *) vec->base + vec->size;
+  vec->size = 0;
+}
+
+/* Release any extra space allocated for VEC.  */
+
+int
+backtrace_vector_release (struct backtrace_vector *vec,
+			  backtrace_error_callback error_callback,
+			  void *data)
+{
+  backtrace_free ((char *) vec->base + vec->size, vec->alc,
+		  error_callback, data);
+  vec->alc = 0;
+  return 1;
+}
Index: libbacktrace/alloc.c
===================================================================
--- libbacktrace/alloc.c	(revision 0)
+++ libbacktrace/alloc.c	(revision 0)
@@ -0,0 +1,134 @@
+/* alloc.c -- Memory allocation without mmap.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* Allocation routines to use on systems that do not support anonymous
+   mmap.  This implementation just uses malloc, which means that the
+   backtrace functions may not be safely invoked from a signal
+   handler.  */
+
+/* Allocate memory like malloc.  */
+
+void *
+backtrace_alloc (size_t size, backtrace_error_callback error_callback,
+		 void *data)
+{
+  void *ret;
+
+  ret = malloc (size);
+  if (ret == NULL)
+    error_callback (data, "malloc", errno);
+  return ret;
+}
+
+/* Free memory.  */
+
+void
+backtrace_free (void *p, size_t size ATTRIBUTE_UNUSED,
+		backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+		void *data ATTRIBUTE_UNUSED)
+{
+  free (p);
+}
+
+/* Grow VEC by SIZE bytes.  */
+
+void *
+backtrace_vector_grow (size_t size, backtrace_error_callback error_callback,
+		       void *data, struct backtrace_vector *vec)
+{
+  void *ret;
+
+  if (size > vec->alc)
+    {
+      size_t alc;
+      void *base;
+
+      if (vec->size == 0)
+	alc = 32 * size;
+      else if (vec->size >= 4096)
+	alc = vec->size + 4096;
+      else
+	alc = 2 * vec->size;
+
+      if (alc < vec->size + size)
+	alc = vec->size + size;
+
+      base = realloc (vec->base, alc);
+      if (base == NULL)
+	{
+	  error_callback (data, "realloc", errno);
+	  return NULL;
+	}
+
+      vec->base = base;
+      vec->alc = alc - vec->size;
+    }
+
+  ret = (char *) vec->base + vec->size;
+  vec->size += size;
+  vec->alc -= size;
+  return ret;
+}
+
+/* Finish the current allocation on VEC.  */
+
+void
+backtrace_vector_finish (struct backtrace_vector *vec)
+{
+  vec->base = (char *) vec->base + vec->size;
+  vec->size = 0;
+}
+
+/* Release any extra space allocated for VEC.  */
+
+int
+backtrace_vector_release (struct backtrace_vector *vec,
+			  backtrace_error_callback error_callback,
+			  void *data)
+{
+  vec->base = realloc (vec->base, vec->size);
+  if (vec->base == NULL)
+    {
+      error_callback (data, "realloc", errno);
+      return 0;
+    }
+  vec->alc = 0;
+  return 1;
+}
Index: libbacktrace/print.c
===================================================================
--- libbacktrace/print.c	(revision 0)
+++ libbacktrace/print.c	(revision 0)
@@ -0,0 +1,80 @@
+/* print.c -- Print the current backtrace.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.  
+    
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* Print one level of a backtrace.  */
+
+static int
+print_callback (void *data, uintptr_t pc, const char *filename, int lineno,
+		const char *function)
+{
+  FILE *f = (FILE *) data;
+
+  fprintf (f, "0x%lx %s\n\t%s:%d\n",
+	   (unsigned long) pc,
+	   function == NULL ? "???" : function,
+	   filename == NULL ? "???" : filename,
+	   lineno);
+  return 0;
+}
+
+/* Print errors to stderr.  */
+
+static void
+error_callback (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
+{
+  const char *name;
+
+  name = backtrace_executable_name ();
+  if (name == NULL)
+    name = "/proc/self/exe";
+  fprintf (stderr, "%s: libbacktrace: %s", name, msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fputc ('\n', stderr);
+}
+
+/* Print a backtrace.  */
+
+void
+backtrace_print (int skip, FILE *f)
+{
+  backtrace (skip + 1, print_callback, error_callback, (void *) f);
+}
