aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2019-11-08 13:30:43 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-11-08 13:30:43 +0000
commiteade600017299a5ec1eeb656eb218d3b31e7ef14 (patch)
tree0c86be1ad77a014b8ccd18f7f8f3270c618fe072
parent02da8a06116d919d0d49bfccb503754d3f253b9c (diff)
parent9f636a4a0ca402e5c08eeb553af945116c379919 (diff)
downloadelfutils-eade600017299a5ec1eeb656eb218d3b31e7ef14.tar.gz
Merge "Upgrade elfutils to 09c9e8091c36eff7f1f4220ac12afe66d0322c59"
-rw-r--r--METADATA6
-rw-r--r--configure.ac12
-rw-r--r--lib/ChangeLog6
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/atomics.h37
-rw-r--r--lib/stdatomic-fbsd.h442
-rw-r--r--libcpu/ChangeLog8
-rw-r--r--libcpu/i386_data.h2
-rw-r--r--libcpu/i386_disasm.c12
-rw-r--r--libdw/ChangeLog14
-rw-r--r--libdw/Makefile.am4
-rw-r--r--libdw/dwarf_begin_elf.c35
-rw-r--r--libdw/dwarf_end.c33
-rw-r--r--libdw/libdwP.h59
-rw-r--r--libdw/libdw_alloc.c6
-rw-r--r--libdwfl/ChangeLog11
-rw-r--r--libdwfl/dwfl_frame.c66
-rw-r--r--libdwfl/libdwflP.h3
-rw-r--r--src/ChangeLog32
-rw-r--r--src/unstrip.c83
20 files changed, 751 insertions, 123 deletions
diff --git a/METADATA b/METADATA
index 8d16a3f1..4cc663f5 100644
--- a/METADATA
+++ b/METADATA
@@ -9,10 +9,10 @@ third_party {
type: GIT
value: "git://sourceware.org/git/elfutils.git"
}
- version: "47780c9e4cbd312da6d93c9d70c554d34d83dd05"
+ version: "09c9e8091c36eff7f1f4220ac12afe66d0322c59"
last_upgrade_date {
year: 2019
- month: 10
- day: 7
+ month: 11
+ day: 6
}
}
diff --git a/configure.ac b/configure.ac
index d380d016..9be34d12 100644
--- a/configure.ac
+++ b/configure.ac
@@ -226,6 +226,18 @@ LDFLAGS="$save_LDFLAGS"])
AS_IF([test "x$ac_cv_tls" != xyes],
AC_MSG_ERROR([__thread support required]))
+dnl Before 4.9 gcc doesn't ship stdatomic.h, but the nessesary atomics are
+dnl available by (at least) 4.7. So if the system doesn't have a stdatomic.h we
+dnl fall back on one copied from FreeBSD that handles the difference.
+AC_CACHE_CHECK([whether gcc provides stdatomic.h], ac_cv_has_stdatomic,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include <stdatomic.h>]])],
+ ac_cv_has_stdatomic=yes, ac_cv_has_stdatomic=no)])
+AM_CONDITIONAL(HAVE_STDATOMIC_H, test "x$ac_cv_has_stdatomic" = xyes)
+AS_IF([test "x$ac_cv_has_stdatomic" = xyes], [AC_DEFINE(HAVE_STDATOMIC_H)])
+
+AH_TEMPLATE([HAVE_STDATOMIC_H], [Define to 1 if `stdatomic.h` is provided by the
+ system, 0 otherwise.])
+
dnl This test must come as early as possible after the compiler configuration
dnl tests, because the choice of the file model can (in principle) affect
dnl whether functions and headers are available, whether they work, etc.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 7381860c..3799c3aa 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,9 @@
+2019-08-25 Jonathon Anderson <jma14@rice.edu>
+
+ * stdatomic-fbsd.h: New file, taken from FreeBSD.
+ * atomics.h: New file.
+ * Makefile.am (noinst_HEADERS): Added *.h above.
+
2019-05-03 Rosen Penev <rosenp@gmail.com>
* color.c (parse_opt): Cast program_invocation_short_name to char *.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 36d21a07..3086cf06 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -38,7 +38,8 @@ libeu_a_SOURCES = xstrdup.c xstrndup.c xmalloc.c next_prime.c \
color.c printversion.c
noinst_HEADERS = fixedsizehash.h libeu.h system.h dynamicsizehash.h list.h \
- eu-config.h color.h printversion.h bpf.h
+ eu-config.h color.h printversion.h bpf.h \
+ atomics.h stdatomic-fbsd.h
EXTRA_DIST = dynamicsizehash.c
if !GPROF
diff --git a/lib/atomics.h b/lib/atomics.h
new file mode 100644
index 00000000..ffd12f87
--- /dev/null
+++ b/lib/atomics.h
@@ -0,0 +1,37 @@
+/* Conditional wrapper header for C11-style atomics.
+ Copyright (C) 2019-2019 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+
+#if HAVE_STDATOMIC_H
+/* If possible, use the compiler's preferred atomics. */
+# include <stdatomic.h>
+#else
+/* Otherwise, try to use the builtins provided by this compiler. */
+# include "stdatomic-fbsd.h"
+#endif /* HAVE_STDATOMIC_H */
diff --git a/lib/stdatomic-fbsd.h b/lib/stdatomic-fbsd.h
new file mode 100644
index 00000000..49626662
--- /dev/null
+++ b/lib/stdatomic-fbsd.h
@@ -0,0 +1,442 @@
+/*-
+ * Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
+ * David Chisnall <theraven@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _STDATOMIC_H_
+#define _STDATOMIC_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+#if !defined(__has_builtin)
+#define __has_builtin(x) 0
+#endif
+#if !defined(__GNUC_PREREQ__)
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define __GNUC_PREREQ__(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GNUC_PREREQ__(maj, min) 0
+#endif
+#endif
+
+#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS)
+#if __has_feature(c_atomic)
+#define __CLANG_ATOMICS
+#elif __GNUC_PREREQ__(4, 7)
+#define __GNUC_ATOMICS
+#elif !defined(__GNUC__)
+#error "stdatomic.h does not support your compiler"
+#endif
+#endif
+
+/*
+ * language independent type to represent a Boolean value
+ */
+
+typedef int __Bool;
+
+/*
+ * 7.17.1 Atomic lock-free macros.
+ */
+
+#ifdef __GCC_ATOMIC_BOOL_LOCK_FREE
+#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_CHAR_LOCK_FREE
+#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE
+#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE
+#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_SHORT_LOCK_FREE
+#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_INT_LOCK_FREE
+#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_LONG_LOCK_FREE
+#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_LLONG_LOCK_FREE
+#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
+#endif
+#ifdef __GCC_ATOMIC_POINTER_LOCK_FREE
+#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
+#endif
+
+#if !defined(__CLANG_ATOMICS)
+#define _Atomic(T) struct { volatile __typeof__(T) __val; }
+#endif
+
+/*
+ * 7.17.2 Initialization.
+ */
+
+#if defined(__CLANG_ATOMICS)
+#define ATOMIC_VAR_INIT(value) (value)
+#define atomic_init(obj, value) __c11_atomic_init(obj, value)
+#else
+#define ATOMIC_VAR_INIT(value) { .__val = (value) }
+#define atomic_init(obj, value) ((void)((obj)->__val = (value)))
+#endif
+
+/*
+ * Clang and recent GCC both provide predefined macros for the memory
+ * orderings. If we are using a compiler that doesn't define them, use the
+ * clang values - these will be ignored in the fallback path.
+ */
+
+#ifndef __ATOMIC_RELAXED
+#define __ATOMIC_RELAXED 0
+#endif
+#ifndef __ATOMIC_CONSUME
+#define __ATOMIC_CONSUME 1
+#endif
+#ifndef __ATOMIC_ACQUIRE
+#define __ATOMIC_ACQUIRE 2
+#endif
+#ifndef __ATOMIC_RELEASE
+#define __ATOMIC_RELEASE 3
+#endif
+#ifndef __ATOMIC_ACQ_REL
+#define __ATOMIC_ACQ_REL 4
+#endif
+#ifndef __ATOMIC_SEQ_CST
+#define __ATOMIC_SEQ_CST 5
+#endif
+
+/*
+ * 7.17.3 Order and consistency.
+ *
+ * The memory_order_* constants that denote the barrier behaviour of the
+ * atomic operations.
+ */
+
+typedef enum {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+/*
+ * 7.17.4 Fences.
+ */
+
+//#define __unused
+
+//static __inline void
+//atomic_thread_fence(memory_order __order __unused)
+//{
+//
+//#ifdef __CLANG_ATOMICS
+// __c11_atomic_thread_fence(__order);
+//#elif defined(__GNUC_ATOMICS)
+// __atomic_thread_fence(__order);
+//#else
+// __sync_synchronize();
+//#endif
+//}
+//
+//static __inline void
+//atomic_signal_fence(memory_order __order __unused)
+//{
+//
+//#ifdef __CLANG_ATOMICS
+// __c11_atomic_signal_fence(__order);
+//#elif defined(__GNUC_ATOMICS)
+// __atomic_signal_fence(__order);
+//#else
+// __asm volatile ("" ::: "memory");
+//#endif
+//}
+
+//#undef __unused
+
+/*
+ * 7.17.5 Lock-free property.
+ */
+
+#if defined(_KERNEL)
+/* Atomics in kernelspace are always lock-free. */
+#define atomic_is_lock_free(obj) \
+ ((void)(obj), (__Bool)1)
+#elif defined(__CLANG_ATOMICS)
+#define atomic_is_lock_free(obj) \
+ __atomic_is_lock_free(sizeof(*(obj)), obj)
+#elif defined(__GNUC_ATOMICS)
+#define atomic_is_lock_free(obj) \
+ __atomic_is_lock_free(sizeof((obj)->__val), &(obj)->__val)
+#else
+#define atomic_is_lock_free(obj) \
+ ((void)(obj), sizeof((obj)->__val) <= sizeof(void *))
+#endif
+
+/*
+ * 7.17.6 Atomic integer types.
+ */
+
+typedef _Atomic(__Bool) atomic_bool;
+typedef _Atomic(char) atomic_char;
+typedef _Atomic(signed char) atomic_schar;
+typedef _Atomic(unsigned char) atomic_uchar;
+typedef _Atomic(short) atomic_short;
+typedef _Atomic(unsigned short) atomic_ushort;
+typedef _Atomic(int) atomic_int;
+typedef _Atomic(unsigned int) atomic_uint;
+typedef _Atomic(long) atomic_long;
+typedef _Atomic(unsigned long) atomic_ulong;
+typedef _Atomic(long long) atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+#if 0
+typedef _Atomic(char16_t) atomic_char16_t;
+typedef _Atomic(char32_t) atomic_char32_t;
+#endif
+typedef _Atomic(wchar_t) atomic_wchar_t;
+typedef _Atomic(int_least8_t) atomic_int_least8_t;
+typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
+typedef _Atomic(int_least16_t) atomic_int_least16_t;
+typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
+typedef _Atomic(int_least32_t) atomic_int_least32_t;
+typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
+typedef _Atomic(int_least64_t) atomic_int_least64_t;
+typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
+typedef _Atomic(intptr_t) atomic_intptr_t;
+typedef _Atomic(uintptr_t) atomic_uintptr_t;
+typedef _Atomic(size_t) atomic_size_t;
+typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
+typedef _Atomic(intmax_t) atomic_intmax_t;
+typedef _Atomic(uintmax_t) atomic_uintmax_t;
+
+/*
+ * 7.17.7 Operations on atomic types.
+ */
+
+/*
+ * Compiler-specific operations.
+ */
+
+#if defined(__CLANG_ATOMICS)
+#define atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure) \
+ __c11_atomic_compare_exchange_strong(object, expected, desired, \
+ success, failure)
+#define atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, success, failure) \
+ __c11_atomic_compare_exchange_weak(object, expected, desired, \
+ success, failure)
+#define atomic_exchange_explicit(object, desired, order) \
+ __c11_atomic_exchange(object, desired, order)
+#define atomic_fetch_add_explicit(object, operand, order) \
+ __c11_atomic_fetch_add(object, operand, order)
+#define atomic_fetch_and_explicit(object, operand, order) \
+ __c11_atomic_fetch_and(object, operand, order)
+#define atomic_fetch_or_explicit(object, operand, order) \
+ __c11_atomic_fetch_or(object, operand, order)
+#define atomic_fetch_sub_explicit(object, operand, order) \
+ __c11_atomic_fetch_sub(object, operand, order)
+#define atomic_fetch_xor_explicit(object, operand, order) \
+ __c11_atomic_fetch_xor(object, operand, order)
+#define atomic_load_explicit(object, order) \
+ __c11_atomic_load(object, order)
+#define atomic_store_explicit(object, desired, order) \
+ __c11_atomic_store(object, desired, order)
+#elif defined(__GNUC_ATOMICS)
+#define atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure) \
+ __atomic_compare_exchange_n(&(object)->__val, expected, \
+ desired, 0, success, failure)
+#define atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, success, failure) \
+ __atomic_compare_exchange_n(&(object)->__val, expected, \
+ desired, 1, success, failure)
+#define atomic_exchange_explicit(object, desired, order) \
+ __atomic_exchange_n(&(object)->__val, desired, order)
+#define atomic_fetch_add_explicit(object, operand, order) \
+ __atomic_fetch_add(&(object)->__val, operand, order)
+#define atomic_fetch_and_explicit(object, operand, order) \
+ __atomic_fetch_and(&(object)->__val, operand, order)
+#define atomic_fetch_or_explicit(object, operand, order) \
+ __atomic_fetch_or(&(object)->__val, operand, order)
+#define atomic_fetch_sub_explicit(object, operand, order) \
+ __atomic_fetch_sub(&(object)->__val, operand, order)
+#define atomic_fetch_xor_explicit(object, operand, order) \
+ __atomic_fetch_xor(&(object)->__val, operand, order)
+#define atomic_load_explicit(object, order) \
+ __atomic_load_n(&(object)->__val, order)
+#define atomic_store_explicit(object, desired, order) \
+ __atomic_store_n(&(object)->__val, desired, order)
+#else
+#define __atomic_apply_stride(object, operand) \
+ (((__typeof__((object)->__val))0) + (operand))
+#define atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure) __extension__ ({ \
+ __typeof__(expected) __ep = (expected); \
+ __typeof__(*__ep) __e = *__ep; \
+ (void)(success); (void)(failure); \
+ (__Bool)((*__ep = __sync_val_compare_and_swap(&(object)->__val, \
+ __e, desired)) == __e); \
+})
+#define atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, success, failure) \
+ atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure)
+#if __has_builtin(__sync_swap)
+/* Clang provides a full-barrier atomic exchange - use it if available. */
+#define atomic_exchange_explicit(object, desired, order) \
+ ((void)(order), __sync_swap(&(object)->__val, desired))
+#else
+/*
+ * __sync_lock_test_and_set() is only an acquire barrier in theory (although in
+ * practice it is usually a full barrier) so we need an explicit barrier before
+ * it.
+ */
+#define atomic_exchange_explicit(object, desired, order) \
+__extension__ ({ \
+ __typeof__(object) __o = (object); \
+ __typeof__(desired) __d = (desired); \
+ (void)(order); \
+ __sync_synchronize(); \
+ __sync_lock_test_and_set(&(__o)->__val, __d); \
+})
+#endif
+#define atomic_fetch_add_explicit(object, operand, order) \
+ ((void)(order), __sync_fetch_and_add(&(object)->__val, \
+ __atomic_apply_stride(object, operand)))
+#define atomic_fetch_and_explicit(object, operand, order) \
+ ((void)(order), __sync_fetch_and_and(&(object)->__val, operand))
+#define atomic_fetch_or_explicit(object, operand, order) \
+ ((void)(order), __sync_fetch_and_or(&(object)->__val, operand))
+#define atomic_fetch_sub_explicit(object, operand, order) \
+ ((void)(order), __sync_fetch_and_sub(&(object)->__val, \
+ __atomic_apply_stride(object, operand)))
+#define atomic_fetch_xor_explicit(object, operand, order) \
+ ((void)(order), __sync_fetch_and_xor(&(object)->__val, operand))
+#define atomic_load_explicit(object, order) \
+ ((void)(order), __sync_fetch_and_add(&(object)->__val, 0))
+#define atomic_store_explicit(object, desired, order) \
+ ((void)atomic_exchange_explicit(object, desired, order))
+#endif
+
+/*
+ * Convenience functions.
+ *
+ * Don't provide these in kernel space. In kernel space, we should be
+ * disciplined enough to always provide explicit barriers.
+ */
+
+#ifndef _KERNEL
+#define atomic_compare_exchange_strong(object, expected, desired) \
+ atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, memory_order_seq_cst, memory_order_seq_cst)
+#define atomic_compare_exchange_weak(object, expected, desired) \
+ atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, memory_order_seq_cst, memory_order_seq_cst)
+#define atomic_exchange(object, desired) \
+ atomic_exchange_explicit(object, desired, memory_order_seq_cst)
+#define atomic_fetch_add(object, operand) \
+ atomic_fetch_add_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_and(object, operand) \
+ atomic_fetch_and_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_or(object, operand) \
+ atomic_fetch_or_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_sub(object, operand) \
+ atomic_fetch_sub_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_xor(object, operand) \
+ atomic_fetch_xor_explicit(object, operand, memory_order_seq_cst)
+#define atomic_load(object) \
+ atomic_load_explicit(object, memory_order_seq_cst)
+#define atomic_store(object, desired) \
+ atomic_store_explicit(object, desired, memory_order_seq_cst)
+#endif /* !_KERNEL */
+
+/*
+ * 7.17.8 Atomic flag type and operations.
+ *
+ * XXX: Assume atomic_bool can be used as an atomic_flag. Is there some
+ * kind of compiler built-in type we could use?
+ */
+
+typedef struct {
+ atomic_bool __flag;
+} atomic_flag;
+
+#define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(0) }
+
+static __inline __Bool
+atomic_flag_test_and_set_explicit(volatile atomic_flag *__object,
+ memory_order __order)
+{
+ return (atomic_exchange_explicit(&__object->__flag, 1, __order));
+}
+
+static __inline void
+atomic_flag_clear_explicit(volatile atomic_flag *__object, memory_order __order)
+{
+
+ atomic_store_explicit(&__object->__flag, 0, __order);
+}
+
+#ifndef _KERNEL
+static __inline __Bool
+atomic_flag_test_and_set(volatile atomic_flag *__object)
+{
+
+ return (atomic_flag_test_and_set_explicit(__object,
+ memory_order_seq_cst));
+}
+
+static __inline void
+atomic_flag_clear(volatile atomic_flag *__object)
+{
+
+ atomic_flag_clear_explicit(__object, memory_order_seq_cst);
+}
+#endif /* !_KERNEL */
+
+#endif /* !_STDATOMIC_H_ */ \ No newline at end of file
diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog
index e23097bd..52567be8 100644
--- a/libcpu/ChangeLog
+++ b/libcpu/ChangeLog
@@ -1,3 +1,11 @@
+2019-10-17 Mark Wielaard <mark@klomp.org>
+
+ * i386_data.h (FCT_sel): Check for param_start + 2 >= end instead
+ of just >.
+ * i386_disasm.c (i386_disasm): Check param_start < end. Don't
+ assert, but assign INVALID to str. Make sure we get past any
+ unrecognized opcode.
+
2019-09-07 Mark Wielaard <mark@klomp.org>
* riscv_disasm.c (riscv_disasm): Use UINT64_C to make calculation
diff --git a/libcpu/i386_data.h b/libcpu/i386_data.h
index b8a34c3e..06356b8a 100644
--- a/libcpu/i386_data.h
+++ b/libcpu/i386_data.h
@@ -1336,7 +1336,7 @@ FCT_sel (struct output_data *d)
{
assert (d->opoff1 % 8 == 0);
assert (d->opoff1 / 8 == 5);
- if (*d->param_start + 2 > d->end)
+ if (*d->param_start + 2 >= d->end)
return -1;
*d->param_start += 2;
uint16_t absval = read_2ubyte_unaligned (&d->data[5]);
diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c
index 8a206398..4422ffa2 100644
--- a/libcpu/i386_disasm.c
+++ b/libcpu/i386_disasm.c
@@ -610,7 +610,9 @@ i386_disasm (Ebl *ebl __attribute__((unused)),
/* Account for displacement. */
if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
- || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
+ || ((modrm & 0xc7) == 0x4
+ && param_start < end
+ && (codep[0] & 0x7) == 0x5))
param_start += 4;
else if ((modrm & 0xc0) == 0x40)
param_start += 1;
@@ -821,7 +823,8 @@ i386_disasm (Ebl *ebl __attribute__((unused)),
}
FALLTHROUGH;
default:
- assert (! "INVALID not handled");
+ str = "INVALID not handled";
+ break;
}
}
else
@@ -1124,8 +1127,9 @@ i386_disasm (Ebl *ebl __attribute__((unused)),
/* Invalid (or at least unhandled) opcode. */
if (prefixes != 0)
goto print_prefix;
- assert (*startp == data);
- ++data;
+ /* Make sure we get past the unrecognized opcode if we haven't yet. */
+ if (*startp == data)
+ ++data;
ADD_STRING ("(bad)");
addr += data - begin;
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 498cf0b7..b1f73bc8 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,17 @@
+2019-11-01 Jonathon Anderson <jma14@rice.edu>
+
+ * dwarf_begin_elf.c (valid_p): Switch calloc for malloc for fake CUs.
+ Add explicit initialization of some fields.
+ * dwarf_end.c (cu_free): Add clause to limit freeing of CU internals.
+
+2019-08-26 Jonathon Anderson <jma14@rice.edu>
+
+ * libdw_alloc.c (__libdw_allocate): Added thread-safe stack allocator.
+ * libdwP.h (Dwarf): Likewise.
+ * dwarf_begin_elf.c (dwarf_begin_elf): Support for above.
+ * dwarf_end.c (dwarf_end): Likewise.
+ * Makefile.am: Use -pthread to provide rwlocks.
+
2019-07-05 Omar Sandoval <osandov@fb.com>
* Makefile.am (libdw_so_LIBS): Replace libebl.a with libebl_pic.a.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 274571c3..ce793e90 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -31,7 +31,7 @@ include $(top_srcdir)/config/eu.am
if BUILD_STATIC
AM_CFLAGS += $(fpic_CFLAGS)
endif
-AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf
+AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf -pthread
VERSION = 1
lib_LIBRARIES = libdw.a
@@ -109,7 +109,7 @@ libdw_so_LIBS = ../libebl/libebl_pic.a ../backends/libebl_backends_pic.a \
../libcpu/libcpu_pic.a libdw_pic.a ../libdwelf/libdwelf_pic.a \
../libdwfl/libdwfl_pic.a
libdw_so_DEPS = ../lib/libeu.a ../libelf/libelf.so
-libdw_so_LDLIBS = $(libdw_so_DEPS) -lz $(argp_LDADD) $(zip_LIBS)
+libdw_so_LDLIBS = $(libdw_so_DEPS) -lz $(argp_LDADD) $(zip_LIBS) -pthread
libdw_so_SOURCES =
libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS)
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 38c8f5c6..8c116847 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -223,7 +223,7 @@ valid_p (Dwarf *result)
inside the .debug_loc or .debug_loclists section. */
if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
{
- result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ result->fake_loc_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
if (unlikely (result->fake_loc_cu == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -240,12 +240,16 @@ valid_p (Dwarf *result)
result->fake_loc_cu->endp
= (result->sectiondata[IDX_debug_loc]->d_buf
+ result->sectiondata[IDX_debug_loc]->d_size);
+ result->fake_loc_cu->locs = NULL;
+ result->fake_loc_cu->address_size = 0;
+ result->fake_loc_cu->version = 0;
+ result->fake_loc_cu->split = NULL;
}
}
if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL)
{
- result->fake_loclists_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ result->fake_loclists_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
if (unlikely (result->fake_loclists_cu == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -263,6 +267,10 @@ valid_p (Dwarf *result)
result->fake_loclists_cu->endp
= (result->sectiondata[IDX_debug_loclists]->d_buf
+ result->sectiondata[IDX_debug_loclists]->d_size);
+ result->fake_loclists_cu->locs = NULL;
+ result->fake_loclists_cu->address_size = 0;
+ result->fake_loclists_cu->version = 0;
+ result->fake_loclists_cu->split = NULL;
}
}
@@ -272,7 +280,7 @@ valid_p (Dwarf *result)
inside the .debug_addr section, if it exists. */
if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL)
{
- result->fake_addr_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ result->fake_addr_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
if (unlikely (result->fake_addr_cu == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -291,6 +299,10 @@ valid_p (Dwarf *result)
result->fake_addr_cu->endp
= (result->sectiondata[IDX_debug_addr]->d_buf
+ result->sectiondata[IDX_debug_addr]->d_size);
+ result->fake_addr_cu->locs = NULL;
+ result->fake_addr_cu->address_size = 0;
+ result->fake_addr_cu->version = 0;
+ result->fake_addr_cu->split = NULL;
}
}
@@ -397,7 +409,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
assert (sizeof (struct Dwarf) < mem_default_size);
/* Allocate the data structure. */
- Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size);
+ Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf));
if (unlikely (result == NULL)
|| unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0))
{
@@ -414,14 +426,17 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
result->elf = elf;
result->alt_fd = -1;
- /* Initialize the memory handling. */
+ /* Initialize the memory handling. Initial blocks are allocated on first
+ actual allocation. */
result->mem_default_size = mem_default_size;
result->oom_handler = __libdw_oom;
- result->mem_tail = (struct libdw_memblock *) (result + 1);
- result->mem_tail->size = (result->mem_default_size
- - offsetof (struct libdw_memblock, mem));
- result->mem_tail->remaining = result->mem_tail->size;
- result->mem_tail->prev = NULL;
+ if (pthread_key_create (&result->mem_key, NULL) != 0)
+ {
+ free (result);
+ __libdw_seterrno (DWARF_E_NOMEM); /* no memory or max pthread keys. */
+ return NULL;
+ }
+ atomic_init (&result->mem_tail, (uintptr_t)NULL);
if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR)
{
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 29795c10..7e194a55 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -52,18 +52,23 @@ cu_free (void *arg)
{
struct Dwarf_CU *p = (struct Dwarf_CU *) arg;
- Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
-
tdestroy (p->locs, noop_free);
- /* Free split dwarf one way (from skeleton to split). */
- if (p->unit_type == DW_UT_skeleton
- && p->split != NULL && p->split != (void *)-1)
+ /* Only free the CU internals if its not a fake CU. */
+ if(p != p->dbg->fake_loc_cu && p != p->dbg->fake_loclists_cu
+ && p != p->dbg->fake_addr_cu)
{
- /* The fake_addr_cu might be shared, only release one. */
- if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
- p->split->dbg->fake_addr_cu = NULL;
- INTUSE(dwarf_end) (p->split->dbg);
+ Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
+
+ /* Free split dwarf one way (from skeleton to split). */
+ if (p->unit_type == DW_UT_skeleton
+ && p->split != NULL && p->split != (void *)-1)
+ {
+ /* The fake_addr_cu might be shared, only release one. */
+ if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
+ p->split->dbg->fake_addr_cu = NULL;
+ INTUSE(dwarf_end) (p->split->dbg);
+ }
}
}
@@ -94,14 +99,18 @@ dwarf_end (Dwarf *dwarf)
/* And the split Dwarf. */
tdestroy (dwarf->split_tree, noop_free);
- struct libdw_memblock *memp = dwarf->mem_tail;
- /* The first block is allocated together with the Dwarf object. */
- while (memp->prev != NULL)
+ /* Free the internally allocated memory. */
+ struct libdw_memblock *memp;
+ memp = (struct libdw_memblock *) (atomic_load_explicit
+ (&dwarf->mem_tail,
+ memory_order_relaxed));
+ while (memp != NULL)
{
struct libdw_memblock *prevp = memp->prev;
free (memp);
memp = prevp;
}
+ pthread_key_delete (dwarf->mem_key);
/* Free the pubnames helper structure. */
free (dwarf->pubnames_sets);
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index eebb7d12..ad2599eb 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -31,9 +31,11 @@
#include <libintl.h>
#include <stdbool.h>
+#include <pthread.h>
#include <libdw.h>
#include <dwarf.h>
+#include "atomics.h"
/* gettext helper macros. */
@@ -147,6 +149,17 @@ enum
#include "dwarf_sig8_hash.h"
+/* Structure for internal memory handling. This is basically a simplified
+ reimplementation of obstacks. Unfortunately the standard obstack
+ implementation is not usable in libraries. */
+struct libdw_memblock
+{
+ size_t size;
+ size_t remaining;
+ struct libdw_memblock *prev;
+ char mem[0];
+};
+
/* This is the structure representing the debugging state. */
struct Dwarf
{
@@ -218,16 +231,11 @@ struct Dwarf
/* Similar for addrx/constx, which will come from .debug_addr section. */
struct Dwarf_CU *fake_addr_cu;
- /* Internal memory handling. This is basically a simplified
- reimplementation of obstacks. Unfortunately the standard obstack
- implementation is not usable in libraries. */
- struct libdw_memblock
- {
- size_t size;
- size_t remaining;
- struct libdw_memblock *prev;
- char mem[0];
- } *mem_tail;
+ /* Internal memory handling. Each thread allocates separately and only
+ allocates from its own blocks, while all the blocks are pushed atomically
+ onto a unified stack for easy deallocation. */
+ pthread_key_t mem_key;
+ atomic_uintptr_t mem_tail;
/* Default size of allocated memory blocks. */
size_t mem_default_size;
@@ -570,21 +578,28 @@ libdw_valid_user_form (int form)
extern void __libdw_seterrno (int value) internal_function;
-/* Memory handling, the easy parts. This macro does not do any locking. */
+/* Memory handling, the easy parts. This macro does not do nor need to do any
+ locking for proper concurrent operation. */
#define libdw_alloc(dbg, type, tsize, cnt) \
- ({ struct libdw_memblock *_tail = (dbg)->mem_tail; \
- size_t _required = (tsize) * (cnt); \
- type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\
- size_t _padding = ((__alignof (type) \
- - ((uintptr_t) _result & (__alignof (type) - 1))) \
- & (__alignof (type) - 1)); \
- if (unlikely (_tail->remaining < _required + _padding)) \
- _result = (type *) __libdw_allocate (dbg, _required, __alignof (type));\
+ ({ struct libdw_memblock *_tail = pthread_getspecific (dbg->mem_key); \
+ size_t _req = (tsize) * (cnt); \
+ type *_result; \
+ if (unlikely (_tail == NULL)) \
+ _result = (type *) __libdw_allocate (dbg, _req, __alignof (type)); \
else \
{ \
- _required += _padding; \
- _result = (type *) ((char *) _result + _padding); \
- _tail->remaining -= _required; \
+ _result = (type *) (_tail->mem + (_tail->size - _tail->remaining)); \
+ size_t _padding = ((__alignof (type) \
+ - ((uintptr_t) _result & (__alignof (type) - 1))) \
+ & (__alignof (type) - 1)); \
+ if (unlikely (_tail->remaining < _req + _padding)) \
+ _result = (type *) __libdw_allocate (dbg, _req, __alignof (type)); \
+ else \
+ { \
+ _req += _padding; \
+ _result = (type *) ((char *) _result + _padding); \
+ _tail->remaining -= _req; \
+ } \
} \
_result; })
diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c
index f1e08714..f2e74d18 100644
--- a/libdw/libdw_alloc.c
+++ b/libdw/libdw_alloc.c
@@ -52,8 +52,10 @@ __libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
newp->size = size - offsetof (struct libdw_memblock, mem);
newp->remaining = (uintptr_t) newp + size - (result + minsize);
- newp->prev = dbg->mem_tail;
- dbg->mem_tail = newp;
+ newp->prev = (struct libdw_memblock*)atomic_exchange_explicit(
+ &dbg->mem_tail, (uintptr_t)newp, memory_order_relaxed);
+ if (pthread_setspecific (dbg->mem_key, newp) != 0)
+ dbg->oom_handler ();
return (void *) result;
}
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 04a39637..07a1e8df 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,14 @@
+2019-10-07 Omar Sandoval <osandov@fb.com>
+
+ * dwfl_frame.c (dwfl_getthreads): Get rid of unnecessary
+ thread_free_all_states calls.
+ (getthread): Ditto.
+ (state_free): Remove function.
+ (thread_free_all_states): Remove function.
+ (free_states): Add function.
+ (dwfl_thread_getframes): Don't update thread->unwound while unwinding.
+ * libdwflP.h (struct Dwfl_Thread): Update comment for unwound member.
+
2019-08-12 Mark Wielaard <mark@klomp.org>
* gzip.c (open_stream): Return DWFL_E_ERRNO on bad file operation.
diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c
index 881f735a..5bbf850e 100644
--- a/libdwfl/dwfl_frame.c
+++ b/libdwfl/dwfl_frame.c
@@ -71,19 +71,14 @@ state_fetch_pc (Dwfl_Frame *state)
/* Do not call it on your own, to be used by thread_* functions only. */
static void
-state_free (Dwfl_Frame *state)
+free_states (Dwfl_Frame *state)
{
- Dwfl_Thread *thread = state->thread;
- assert (thread->unwound == state);
- thread->unwound = state->unwound;
- free (state);
-}
-
-static void
-thread_free_all_states (Dwfl_Thread *thread)
-{
- while (thread->unwound)
- state_free (thread->unwound);
+ while (state)
+ {
+ Dwfl_Frame *next = state->unwound;
+ free(state);
+ state = next;
+ }
}
static Dwfl_Frame *
@@ -279,24 +274,15 @@ dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg),
process->callbacks_arg,
&thread.callbacks_arg);
if (thread.tid < 0)
- {
- Dwfl_Error saved_errno = dwfl_errno ();
- thread_free_all_states (&thread);
- __libdwfl_seterrno (saved_errno);
- return -1;
- }
+ return -1;
if (thread.tid == 0)
{
- thread_free_all_states (&thread);
__libdwfl_seterrno (DWFL_E_NOERROR);
return 0;
}
int err = callback (&thread, arg);
if (err != DWARF_CB_OK)
- {
- thread_free_all_states (&thread);
- return err;
- }
+ return err;
assert (thread.unwound == NULL);
}
/* NOTREACHED */
@@ -356,11 +342,8 @@ getthread (Dwfl *dwfl, pid_t tid,
if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
&thread.callbacks_arg))
{
- int err;
thread.tid = tid;
- err = callback (&thread, arg);
- thread_free_all_states (&thread);
- return err;
+ return callback (&thread, arg);
}
return -1;
@@ -411,12 +394,6 @@ dwfl_thread_getframes (Dwfl_Thread *thread,
int (*callback) (Dwfl_Frame *state, void *arg),
void *arg)
{
- if (thread->unwound != NULL)
- {
- /* We had to be called from inside CALLBACK. */
- __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
- return -1;
- }
Ebl *ebl = thread->process->ebl;
if (ebl_frame_nregs (ebl) == 0)
{
@@ -432,33 +409,34 @@ dwfl_thread_getframes (Dwfl_Thread *thread,
if (! process->callbacks->set_initial_registers (thread,
thread->callbacks_arg))
{
- thread_free_all_states (thread);
+ free_states (thread->unwound);
+ thread->unwound = NULL;
return -1;
}
- if (! state_fetch_pc (thread->unwound))
+ Dwfl_Frame *state = thread->unwound;
+ thread->unwound = NULL;
+ if (! state_fetch_pc (state))
{
if (process->callbacks->thread_detach)
process->callbacks->thread_detach (thread, thread->callbacks_arg);
- thread_free_all_states (thread);
+ free_states (state);
return -1;
}
-
- Dwfl_Frame *state;
do
{
- state = thread->unwound;
int err = callback (state, arg);
if (err != DWARF_CB_OK)
{
if (process->callbacks->thread_detach)
process->callbacks->thread_detach (thread, thread->callbacks_arg);
- thread_free_all_states (thread);
+ free_states (state);
return err;
}
__libdwfl_frame_unwind (state);
+ Dwfl_Frame *next = state->unwound;
/* The old frame is no longer needed. */
- state_free (thread->unwound);
- state = thread->unwound;
+ free (state);
+ state = next;
}
while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
@@ -467,12 +445,12 @@ dwfl_thread_getframes (Dwfl_Thread *thread,
process->callbacks->thread_detach (thread, thread->callbacks_arg);
if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
{
- thread_free_all_states (thread);
+ free_states (state);
__libdwfl_seterrno (err);
return -1;
}
assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
- thread_free_all_states (thread);
+ free_states (state);
return 0;
}
INTDEF(dwfl_thread_getframes)
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 941a8b66..6b2d4867 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -242,8 +242,7 @@ struct Dwfl_Thread
{
Dwfl_Process *process;
pid_t tid;
- /* The current frame being unwound. Initially it is the bottom frame.
- Later the processed frames get freed and this pointer is updated. */
+ /* Bottom (innermost) frame while we're initializing, NULL afterwards. */
Dwfl_Frame *unwound;
void *callbacks_arg;
};
diff --git a/src/ChangeLog b/src/ChangeLog
index db56a136..3144c935 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,35 @@
+2019-10-26 Mark Wielaard <mark@klomp.org>
+
+ * unstrip.c (collect_symbols): Check symbol strings are
+ terminated.
+
+2019-10-18 Mark Wielaard <mark@klomp.org>
+
+ * unstrip.c (adjust_relocs): Set versym data d_size to the actual
+ size allocated.
+
+2019-10-20 Mark Wielaard <mark@klomp.org>
+
+ * unstrip.c (copy_elided_sections): Set and check max_off.
+
+2019-10-21 Mark Wielaard <mark@klomp.org>
+
+ * unstrip.c (adjust_relocs): Add map_size argument and check ndx
+ against it.
+ (adjust_all_relocs): Add map_size argument and pass it to
+ adjust_relocs.
+ (add_new_section_symbols): Call adjust_all_relocs with symndx_map
+ size.
+ (collect)symbols): Check sym and string data can be found.
+ (compare_symbols_output): Call error when (different) symbols are
+ equal.
+ (new_shstrtab): Make unstripped_strent array one larger. Check
+ stripped_shnum isn't zero.
+ (copy_elided_sections): Add ndx_sec_num as size of ndx_section
+ array. Check sh_link and sh_info are not larger than ndx_sec_num.
+ Allocate symbols and symndx_map arrays on heap, not stack. Pass
+ map sizes to adjust_all_relocs.
+
2019-09-28 Dmitry V. Levin <ldv@altlinux.org>
* elflint.c (main): When an input file cannot be opened,
diff --git a/src/unstrip.c b/src/unstrip.c
index fc878325..9b8c09a1 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -433,7 +433,7 @@ update_sh_size (Elf_Scn *outscn, const Elf_Data *data)
/* Update relocation sections using the symbol table. */
static void
adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
- size_t map[], const GElf_Shdr *symshdr)
+ size_t map[], size_t map_size, const GElf_Shdr *symshdr)
{
Elf_Data *data = elf_getdata (outscn, NULL);
@@ -441,7 +441,11 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
{
size_t ndx = GELF_R_SYM (*info);
if (ndx != STN_UNDEF)
- *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
+ {
+ if (ndx > map_size)
+ error (EXIT_FAILURE, 0, "bad symbol ndx section");
+ *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
+ }
}
switch (shdr->sh_type)
@@ -572,7 +576,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
record_new_data (versym);
data->d_buf = versym;
- data->d_size = nent * shdr->sh_entsize;
+ data->d_size = nent * sizeof versym[0];
elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
update_sh_size (outscn, data);
}
@@ -588,7 +592,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
/* Adjust all the relocation sections in the file. */
static void
adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
- size_t map[])
+ size_t map[], size_t map_size)
{
size_t new_sh_link = elf_ndxscn (symtab);
Elf_Scn *scn = NULL;
@@ -603,7 +607,7 @@ adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
stripped_symtab. */
if (shdr->sh_type != SHT_NOBITS && shdr->sh_type != SHT_GROUP
&& shdr->sh_link == new_sh_link)
- adjust_relocs (scn, scn, shdr, map, symshdr);
+ adjust_relocs (scn, scn, shdr, map, map_size, symshdr);
}
}
@@ -687,7 +691,7 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
}
/* Adjust any relocations referring to the old symbol table. */
- adjust_all_relocs (elf, symscn, shdr, symndx_map);
+ adjust_all_relocs (elf, symscn, shdr, symndx_map, nsym - 1);
return symdata;
}
@@ -835,7 +839,9 @@ collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
struct section *split_bss)
{
Elf_Data *symdata = elf_getdata (symscn, NULL);
+ ELF_CHECK (symdata != NULL, _("cannot get symbol section data: %s"));
Elf_Data *strdata = elf_getdata (strscn, NULL);
+ ELF_CHECK (strdata != NULL, _("cannot get string section data: %s"));
Elf_Data *shndxdata = NULL; /* XXX */
for (size_t i = 1; i < nent; ++i)
@@ -848,7 +854,9 @@ collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
if (sym->st_shndx != SHN_XINDEX)
shndx = sym->st_shndx;
- if (sym->st_name >= strdata->d_size)
+ if (sym->st_name >= strdata->d_size
+ || memrchr (strdata->d_buf + sym->st_name, '\0',
+ strdata->d_size - sym->st_name) == NULL)
error (EXIT_FAILURE, 0,
_("invalid string offset in symbol [%zu]"), i);
@@ -931,14 +939,14 @@ compare_symbols_output (const void *a, const void *b)
{
/* binutils always puts section symbols in section index order. */
CMP (shndx);
- else
- assert (s1 == s2);
+ else if (s1 != s2)
+ error (EXIT_FAILURE, 0, "section symbols in unexpected order");
}
/* Nothing really matters, so preserve the original order. */
CMP (map);
- else
- assert (s1 == s2);
+ else if (s1 != s2)
+ error (EXIT_FAILURE, 0, "found two identical symbols");
}
return cmp;
@@ -1305,7 +1313,7 @@ new_shstrtab (Elf *unstripped, size_t unstripped_shnum,
if (strtab == NULL)
return NULL;
- Dwelf_Strent *unstripped_strent[unstripped_shnum - 1];
+ Dwelf_Strent *unstripped_strent[unstripped_shnum];
memset (unstripped_strent, 0, sizeof unstripped_strent);
for (struct section *sec = sections;
sec < &sections[stripped_shnum - 1];
@@ -1388,6 +1396,19 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
error (EXIT_FAILURE, 0, _("\
more sections in stripped file than debug file -- arguments reversed?"));
+ if (unlikely (stripped_shnum == 0))
+ error (EXIT_FAILURE, 0, _("no sections in stripped file"));
+
+ /* Used as sanity check for allocated section offset, if the section
+ offset needs to be preserved. We want to know the max size of the
+ ELF file, to check if any existing section offsets are OK. */
+ int64_t max_off = -1;
+ if (stripped_ehdr->e_type != ET_REL)
+ {
+ elf_flagelf (stripped, ELF_C_SET, ELF_F_LAYOUT);
+ max_off = elf_update (stripped, ELF_C_NULL);
+ }
+
/* Cache the stripped file's section details. */
struct section sections[stripped_shnum - 1];
Elf_Scn *scn = NULL;
@@ -1550,10 +1571,11 @@ more sections in stripped file than debug file -- arguments reversed?"));
/* Make sure each main file section has a place to go. */
const struct section *stripped_dynsym = NULL;
size_t debuglink = SHN_UNDEF;
- size_t ndx_section[stripped_shnum - 1];
+ size_t ndx_sec_num = stripped_shnum - 1;
+ size_t ndx_section[ndx_sec_num];
Dwelf_Strtab *strtab = NULL;
for (struct section *sec = sections;
- sec < &sections[stripped_shnum - 1];
+ sec < &sections[ndx_sec_num];
++sec)
{
size_t secndx = elf_ndxscn (sec->scn);
@@ -1658,9 +1680,21 @@ more sections in stripped file than debug file -- arguments reversed?"));
shdr_mem.sh_flags |= SHF_INFO_LINK;
if (sec->shdr.sh_link != SHN_UNDEF)
- shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
+ {
+ if (sec->shdr.sh_link > ndx_sec_num)
+ error (EXIT_FAILURE, 0,
+ "section [%zd] has invalid sh_link %" PRId32,
+ elf_ndxscn (sec->scn), sec->shdr.sh_link);
+ shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
+ }
if (SH_INFO_LINK_P (&sec->shdr) && sec->shdr.sh_info != 0)
- shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
+ {
+ if (sec->shdr.sh_info > ndx_sec_num)
+ error (EXIT_FAILURE, 0,
+ "section [%zd] has invalid sh_info %" PRId32,
+ elf_ndxscn (sec->scn), sec->shdr.sh_info);
+ shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
+ }
if (strtab != NULL)
shdr_mem.sh_name = dwelf_strent_off (sec->strent);
@@ -1675,6 +1709,11 @@ more sections in stripped file than debug file -- arguments reversed?"));
/* Preserve the file layout of the allocated sections. */
if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC))
{
+ if (max_off > 0 && sec->shdr.sh_offset > (Elf64_Off) max_off)
+ error (EXIT_FAILURE, 0,
+ "allocated section offset too large [%zd] %" PRIx64,
+ elf_ndxscn (sec->scn), sec->shdr.sh_offset);
+
shdr_mem.sh_offset = sec->shdr.sh_offset;
placed[elf_ndxscn (sec->outscn) - 1] = true;
@@ -1776,8 +1815,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
/* First collect all the symbols from both tables. */
const size_t total_syms = stripped_nsym - 1 + unstripped_nsym - 1;
- struct symbol symbols[total_syms];
- size_t symndx_map[total_syms];
+ struct symbol *symbols = xmalloc (total_syms * sizeof (struct symbol));
+ size_t *symndx_map = xmalloc (total_syms * sizeof (size_t));
if (stripped_symtab != NULL)
collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
@@ -1958,12 +1997,16 @@ more sections in stripped file than debug file -- arguments reversed?"));
++sec)
if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link)
adjust_relocs (sec->outscn, sec->scn, &sec->shdr,
- symndx_map, shdr);
+ symndx_map, total_syms, shdr);
}
/* Also adjust references to the other old symbol table. */
adjust_all_relocs (unstripped, unstripped_symtab, shdr,
- &symndx_map[stripped_nsym - 1]);
+ &symndx_map[stripped_nsym - 1],
+ total_syms - (stripped_nsym - 1));
+
+ free (symbols);
+ free (symndx_map);
}
else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
check_symtab_section_symbols (unstripped,