Updated to arc-runtime-45.5021.433.7
diff --git a/mods/android/bionic/config.py b/mods/android/bionic/config.py
index 49c68cd..de8d08f 100755
--- a/mods/android/bionic/config.py
+++ b/mods/android/bionic/config.py
@@ -133,6 +133,8 @@
if OPTIONS.is_bare_metal_build():
# For direct syscalls used internally.
sources.append('android/bionic/libc/arch-x86/bionic/syscall.S')
+ # For saving register context for waiting threads.
+ sources.append('android/bionic/libc/arch-x86/bionic/save_reg_context.S')
else:
# See the comment in _filter_libc_common_for_arm.
# TODO(crbug.com/318433): Use order-only dependencies.
@@ -158,7 +160,7 @@
# As we support ARM NDKs even on NaCl x86-64, we provide legacy
# APIs.
'android/bionic/libc/bionic/legacy_32_bit_support.cpp'])
- sources.append('android/bionic/libc/arch-amd64/bionic/save_reg_context.S')
+ sources.append('android/bionic/libc/arch-x86_64/bionic/save_reg_context.S')
def _remove_unnecessary_defines(vars):
@@ -1472,7 +1474,7 @@
_BIONIC_TEST_LIB_MODULES + ['no-elf-hash-table-library']]
test_binary = n.link(variables={'ldflags': ldflags})
- n.add_disabled_tests('pthread_thread_context.*')
+ n.add_disabled_tests('PthreadThreadContext*.*')
n.run(test_binary, implicit=test_deps)
# pthread_context_test should run only with a single thread. As
@@ -1480,7 +1482,7 @@
# result of this test, we use a separate TestNinjaGenerator for this
# test.
n = ninja_generator.TestNinjaGenerator('bionic_pthread_context_test')
- n.add_enabled_tests('pthread_thread_context.*')
+ n.add_enabled_tests('PthreadThreadContext*.*')
n.run(test_binary, implicit=test_deps)
# Build the shared object for dlfcn.dlopen_library_with_only_gnu_hash.
diff --git a/mods/android/bionic/libc/arch-nacl/syscalls/thread_context.h b/mods/android/bionic/libc/arch-nacl/syscalls/thread_context.h
index a2d92ab..b3fc0a3 100644
--- a/mods/android/bionic/libc/arch-nacl/syscalls/thread_context.h
+++ b/mods/android/bionic/libc/arch-nacl/syscalls/thread_context.h
@@ -40,6 +40,18 @@
__pthread_save_context_regs(regs_tmp, sizeof(regs_tmp)); \
}
+#elif defined(__i386__) && !defined(__native_client__)
+
+extern void BionicInternalSaveRegContext(uint32_t*);
+
+#define SAVE_CONTEXT_REGS() \
+ { \
+ uint32_t regs_tmp[15]; \
+ BionicInternalSaveRegContext(regs_tmp); \
+ __pthread_save_context_regs(regs_tmp, sizeof(regs_tmp)); \
+ }
+
+
#elif defined(__arm__)
#ifndef __thumb__
diff --git a/mods/android/bionic/libc/arch-x86/bionic/save_reg_context.S b/mods/android/bionic/libc/arch-x86/bionic/save_reg_context.S
new file mode 100644
index 0000000..895e0e7
--- /dev/null
+++ b/mods/android/bionic/libc/arch-x86/bionic/save_reg_context.S
@@ -0,0 +1,58 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+.macro store_reg x, y
+ movl \x, \y(%edi)
+.endm
+
+// void BionicInternalSaveRegContext(uint32_t[15])
+// Saves register context necessary for traversing the stack in a minidump.
+.global BionicInternalSaveRegContext
+.type BionicInternalSaveRegContext, @function
+BionicInternalSaveRegContext:
+ .cfi_startproc
+ pushl %edi
+ .cfi_adjust_cfa_offset 4
+ mov 8(%esp), %edi
+
+ // The ordering matches the one specified in ucontext.h.
+ // We're not efficient here because first four registers are segment registers.
+ store_reg %esi, 0x14
+ store_reg %ebp, 0x18
+ store_reg %ebx, 0x20
+ store_reg %edx, 0x24
+ store_reg %ecx, 0x28
+ store_reg %eax, 0x2c
+
+ // edi
+ mov 0(%esp), %eax
+ store_reg %eax, 0x10
+
+ // Store caller's ESP.
+ // Hmm... really?
+ leal 8(%esp), %eax
+ store_reg %eax, 0x1c
+
+ // Store caller's EIP.
+ movl 4(%esp), %eax
+ store_reg %eax, 0x38
+
+ popl %edi
+ .cfi_adjust_cfa_offset -4
+ ret
+
+ .cfi_endproc
+ .size BionicInternalSaveRegContext, . - BionicInternalSaveRegContext
+
+.section .note.GNU-stack, "", @progbits
diff --git a/mods/android/bionic/libc/arch-amd64/bionic/save_reg_context.S b/mods/android/bionic/libc/arch-x86_64/bionic/save_reg_context.S
similarity index 100%
rename from mods/android/bionic/libc/arch-amd64/bionic/save_reg_context.S
rename to mods/android/bionic/libc/arch-x86_64/bionic/save_reg_context.S
diff --git a/mods/android/bionic/libc/bionic/pthread_context.cpp b/mods/android/bionic/libc/bionic/pthread_context.cpp
index 1f036e6..26fc429 100644
--- a/mods/android/bionic/libc/bionic/pthread_context.cpp
+++ b/mods/android/bionic/libc/bionic/pthread_context.cpp
@@ -25,16 +25,24 @@
extern "C" {
void __pthread_save_context_regs(void* regs, int size) {
+ // Not yet supported for nacl-i686.
+#if defined(__x86_64__) || defined(__arm__) || \
+ (defined(__i386__) && !defined(__native_client__))
pthread_internal_t* thread = __get_thread();
memcpy(thread->context_regs, regs, size);
thread->has_context_regs = 1;
ANDROID_MEMBAR_FULL();
+#endif
}
void __pthread_clear_context_regs() {
+ // Not yet supported for nacl-i686.
+#if defined(__x86_64__) || defined(__arm__) || \
+ (defined(__i386__) && !defined(__native_client__))
pthread_internal_t* thread = __get_thread();
thread->has_context_regs = 0;
ANDROID_MEMBAR_FULL();
+#endif
}
static bool obtain_lock(bool try_lock) {
@@ -87,15 +95,18 @@
dst->stack_base = src->stack_end_from_irt - kIrtStackSize;
dst->stack_size = kIrtStackSize;
}
- #else
+#else
if (src->attr.stack_base) {
dst->stack_base =
reinterpret_cast<char*>(src->attr.stack_base) +
src->attr.guard_size;
dst->stack_size = src->attr.stack_size - src->attr.guard_size;
}
- #endif
+#endif
+ // Not yet supported for nacl-i686.
+#if defined(__x86_64__) || defined(__arm__) || \
+ (defined(__i386__) && !defined(__native_client__))
// Copy registers, then do a second (racy) read of has_context_regs.
if (src->has_context_regs) {
memcpy(dst->context_regs, src->context_regs,
@@ -103,6 +114,7 @@
ANDROID_MEMBAR_FULL();
dst->has_context_regs = src->has_context_regs;
}
+#endif
}
void __pthread_get_current_thread_info(__pthread_context_info_t* info) {
diff --git a/mods/android/bionic/libc/bionic/pthread_internal.h b/mods/android/bionic/libc/bionic/pthread_internal.h
index f617c5e..a0fa25b 100644
--- a/mods/android/bionic/libc/bionic/pthread_internal.h
+++ b/mods/android/bionic/libc/bionic/pthread_internal.h
@@ -96,7 +96,10 @@
// ARC MOD BEGIN bionic-thread-info
// Storage for thread context at the time of invoking a blocking call.
volatile bool has_context_regs;
+#if defined(__x86_64__) || defined(__arm__) || \
+ (defined(__i386__) && !defined(__native_client__))
greg_t context_regs[NGREG];
+#endif
// ARC MOD END
pthread_mutex_t startup_handshake_mutex;
diff --git a/mods/android/bionic/tests/pthread_context_test.cpp b/mods/android/bionic/tests/pthread_context_test.cpp
index 0a8bb73..0fc6508 100644
--- a/mods/android/bionic/tests/pthread_context_test.cpp
+++ b/mods/android/bionic/tests/pthread_context_test.cpp
@@ -20,80 +20,135 @@
#include <private/pthread_context.h>
#include <thread_context.h>
-struct Args {
- Args()
- : has_started(false),
- should_exit(false) {
- pthread_mutex_init(&mu, NULL);
- pthread_cond_init(&cond, NULL);
- }
- ~Args() {
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&mu);
+namespace {
+
+// Tests that need to create a thread and be cleaned up later.
+class PthreadThreadContextThreadTest : public testing::Test {
+ public:
+ PthreadThreadContextThreadTest()
+ : thread_(), thread_has_started_(false),
+ thread_should_exit_(false) {
+ pthread_mutex_init(&mu_, NULL);
+ pthread_cond_init(&cond_, NULL);
}
- bool has_started;
- bool should_exit;
- pthread_mutex_t mu;
- pthread_cond_t cond;
+ virtual ~PthreadThreadContextThreadTest() {
+ pthread_cond_destroy(&cond_);
+ pthread_mutex_destroy(&mu_);
+ }
+
+ virtual void SetUp() {
+ ASSERT_EQ(1, __pthread_get_thread_count(true));
+
+ // Create a new thread and wait until it goes into futex_wait loop,
+ // which is instrumented to export thread context information.
+ {
+ ScopedPthreadMutexLocker lock(&mu_);
+ ASSERT_EQ(0, pthread_create(&thread_, NULL, WaitFn, this));
+ while (!thread_has_started_)
+ pthread_cond_wait(&cond_, &mu_);
+ }
+ }
+
+ virtual void TearDown() {
+ // Let the thread finish.
+ {
+ ScopedPthreadMutexLocker lock(&mu_);
+ thread_should_exit_ = true;
+ pthread_cond_signal(&cond_);
+ }
+ pthread_join(thread_, NULL);
+ }
+
+
+ static void* WaitFn(void* arg) {
+ PthreadThreadContextThreadTest* self =
+ static_cast<PthreadThreadContextThreadTest*>(arg);
+ {
+ ScopedPthreadMutexLocker lock(&self->mu_);
+ self->thread_has_started_ = true;
+ pthread_cond_signal(&self->cond_);
+
+ while (!self->thread_should_exit_)
+ pthread_cond_wait(&self->cond_, &self->mu_);
+ }
+ return NULL;
+ }
+
+ static bool HasContextRegs() {
+ __pthread_context_info_t info;
+ info.has_context_regs = true;
+ __pthread_get_current_thread_info(&info);
+ return info.has_context_regs;
+ }
+
+ protected:
+ pthread_t thread_;
+ bool thread_has_started_;
+ bool thread_should_exit_;
+ pthread_mutex_t mu_;
+ pthread_cond_t cond_;
};
-static void* WaitFn(void* arg) {
- Args* args = static_cast<Args*>(arg);
- {
- ScopedPthreadMutexLocker lock(&args->mu);
- args->has_started = true;
- pthread_cond_signal(&args->cond);
-
- while (!args->should_exit)
- pthread_cond_wait(&args->cond, &args->mu);
+TEST_F(PthreadThreadContextThreadTest, get_thread_infos) {
+ // Verify data in the thread list.
+ __pthread_context_info_t infos[100];
+ int thread_count = __pthread_get_thread_infos(true, true, 100, infos);
+ ASSERT_EQ(2, thread_count);
+ for (int i = 0; i < thread_count; ++i) {
+ SCOPED_TRACE(i);
+ ASSERT_TRUE(infos[i].stack_base != NULL);
+ EXPECT_GT(infos[i].stack_size, 0);
+#if defined(BARE_METAL_BIONIC)
+ ASSERT_EQ(infos[i].stack_size, 1024 * 1024);
+#endif
}
- return NULL;
}
-TEST(pthread_thread_context, get_thread_infos) {
- ASSERT_EQ(1, __pthread_get_thread_count(true));
+TEST_F(PthreadThreadContextThreadTest, get_thread_contexts) {
+ // We want the other thread to be inside futex call inside
+ // pthread_cond_wait(). The other option is to let the other thread
+ // __nanosleep. This is not reliable but better than nothing.
+ //
+ // This might turn out to be flaky, if so we should wait longer here.
+ usleep(100000);
- Args args;
- // Create a new thread and wait until it finishes its
- // initialization.
- // TODO(crbug.com/372248): Remove the wait. This synchronization is
- // only for Bare Metal mode. On Bare Metal mode, pthread_context
- // uses |stack_end_from_irt| in pthread_internal_t to find the
- // location of a stack. Unlike other pthread attributes, this is
- // filled by the created thread, not by the creator. So, there is a
- // race. pthread_context may read an uninitialized value in
- // |stack_end_from_irt|.
- pthread_t thread;
- {
- ScopedPthreadMutexLocker lock(&args.mu);
- ASSERT_EQ(0, pthread_create(&thread, NULL, WaitFn, &args));
- while (!args.has_started)
- pthread_cond_wait(&args.cond, &args.mu);
- }
+ // __nanosleep call would clear the context_regs.
+ ASSERT_FALSE(HasContextRegs());
+ SAVE_CONTEXT_REGS();
+#if defined(__x86_64__) || defined(__arm__) || \
+ (defined(__i386__) && !defined(__native_client__))
+ ASSERT_TRUE(HasContextRegs());
+#else
+ ASSERT_FALSE(HasContextRegs());
+#endif
// Verify data in the thread list.
__pthread_context_info_t infos[100];
int thread_count = __pthread_get_thread_infos(true, true, 100, infos);
ASSERT_EQ(2, thread_count);
for (int i = 0; i < thread_count; ++i) {
+ SCOPED_TRACE(i);
ASSERT_TRUE(infos[i].stack_base != NULL);
- ASSERT_GT(infos[i].stack_size, 0);
-#if defined(BARE_METAL_BIONIC)
- ASSERT_EQ(infos[i].stack_size, 1024 * 1024);
+ EXPECT_GT(infos[i].stack_size, 0);
+#if defined(__x86_64__)
+ ASSERT_TRUE(infos[i].has_context_regs);
+ EXPECT_NE(0, infos[i].context_regs[REG_RIP]);
+#elif defined(__i386__) && !defined(__native_client__)
+ ASSERT_TRUE(infos[i].has_context_regs);
+ EXPECT_NE(0, infos[i].context_regs[REG_EIP]);
+#elif defined(__arm__)
+ ASSERT_TRUE(infos[i].has_context_regs);
+ EXPECT_NE(0, infos[i].context_regs[15]);
+#else
+ EXPECT_FALSE(infos[i].has_context_regs);
#endif
}
-
- // Let the thread finish.
- {
- ScopedPthreadMutexLocker lock(&args.mu);
- args.should_exit = true;
- pthread_cond_signal(&args.cond);
- }
- pthread_join(thread, NULL);
+ CLEAR_CONTEXT_REGS();
}
-TEST(pthread_thread_context, get_cur_thread_context) {
+
+TEST(PthreadThreadContextSinglethreadTest, get_cur_thread_context) {
__pthread_context_info_t info;
info.has_context_regs = true;
__pthread_get_current_thread_info(&info);
@@ -104,12 +159,15 @@
__pthread_get_current_thread_info(&info);
#if defined(__x86_64__)
ASSERT_TRUE(info.has_context_regs);
- ASSERT_NE(0, info.context_regs[REG_RIP]);
+ EXPECT_NE(0, info.context_regs[REG_RIP]);
+#elif defined(__i386__) && !defined(__native_client__)
+ ASSERT_TRUE(info.has_context_regs);
+ EXPECT_NE(0, info.context_regs[REG_EIP]);
#elif defined(__arm__)
ASSERT_TRUE(info.has_context_regs);
- ASSERT_NE(0, info.context_regs[15]);
+ EXPECT_NE(0, info.context_regs[15]);
#else
- ASSERT_FALSE(info.has_context_regs);
+ EXPECT_FALSE(info.has_context_regs);
#endif
CLEAR_CONTEXT_REGS();
@@ -117,3 +175,5 @@
__pthread_get_current_thread_info(&info);
ASSERT_FALSE(info.has_context_regs);
}
+
+} // anonymous namespace
diff --git a/mods/native_client/src/untrusted/minidump_generator/minidump_generator.cc b/mods/native_client/src/untrusted/minidump_generator/minidump_generator.cc
index 50cba8f..04c54d1 100644
--- a/mods/native_client/src/untrusted/minidump_generator/minidump_generator.cc
+++ b/mods/native_client/src/untrusted/minidump_generator/minidump_generator.cc
@@ -417,6 +417,27 @@
COPY_REG(rip, REG_RIP);
stack_start = regs.get()->rsp;
#undef COPY_REG
+#elif defined(__i386__) && !defined(__native_client__)
+#define COPY_REG(REG, src_idx) \
+ regs.get()->REG = info.context_regs[src_idx]
+ TypedMDRVA<MDRawContextX86> regs(minidump_writer);
+ if (!regs.Allocate())
+ return;
+ thread->thread_context = regs.location();
+ regs.get()->context_flags =
+ MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_INTEGER;
+ regs.get()->eflags = 0;
+ COPY_REG(edi, REG_EDI);
+ COPY_REG(esi, REG_ESI);
+ COPY_REG(ebp, REG_EBP);
+ COPY_REG(ebx, REG_EBX);
+ COPY_REG(edx, REG_EDX);
+ COPY_REG(ecx, REG_ECX);
+ COPY_REG(eax, REG_EAX);
+ COPY_REG(esp, REG_ESP);
+ COPY_REG(eip, REG_EIP);
+ stack_start = regs.get()->esp;
+#undef COPY_REG
#elif defined(__arm__)
TypedMDRVA<MDRawContextARM> regs(minidump_writer);
if (!regs.Allocate())
@@ -428,7 +449,7 @@
regs.get()->cpsr = 0;
stack_start = regs.get()->iregs[13];
#else
- // TODO(igorc): Support stack traces in 32-bit mode.
+ // TODO(igorc): Support stack traces in NaCl x86 mode.
return;
#endif