===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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
===================================================================
@@ -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);
+}
===================================================================
@@ -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);
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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);
+}