Compare commits
112 Commits
android-m-
...
android-m-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4f2112fa9 | ||
|
|
61d9ae5ab1 | ||
|
|
f2985ed840 | ||
|
|
2b93492478 | ||
|
|
a40a21110d | ||
|
|
3fe1515e38 | ||
|
|
a3c01467ec | ||
|
|
5341691955 | ||
|
|
ff4afc136e | ||
|
|
182b91f628 | ||
|
|
bf830ade7f | ||
|
|
5891abdc66 | ||
|
|
e80369ab0c | ||
|
|
b3db7764d0 | ||
|
|
f57f794515 | ||
|
|
17379d2b08 | ||
|
|
2278d29ada | ||
|
|
516fcb28f2 | ||
|
|
7e919daeaa | ||
|
|
9101b00400 | ||
|
|
0acb15ead6 | ||
|
|
2590705858 | ||
|
|
c46c0e960d | ||
|
|
61c21b63bc | ||
|
|
4c43aac9a5 | ||
|
|
442a3fcae6 | ||
|
|
89a121d43a | ||
|
|
807f27f954 | ||
|
|
9f03ed12a6 | ||
|
|
4498917406 | ||
|
|
b447440a4b | ||
|
|
34c5f5eacd | ||
|
|
36443fd542 | ||
|
|
9bbb5a7a09 | ||
|
|
374adfee47 | ||
|
|
5390173ad4 | ||
|
|
1ff4094a7f | ||
|
|
820a86f2df | ||
|
|
c8ba22c847 | ||
|
|
afab3ffcce | ||
|
|
1923d4c03a | ||
|
|
667dc75ee1 | ||
|
|
4955cde2c5 | ||
|
|
d2a9fb3267 | ||
|
|
cebef1a781 | ||
|
|
7656d0cec0 | ||
|
|
e8ceb95c68 | ||
|
|
8af3263349 | ||
|
|
f16c6e17b2 | ||
|
|
8264cbba7e | ||
|
|
bff1968222 | ||
|
|
f0a73476a1 | ||
|
|
ec83a61c8b | ||
|
|
adc5795fb7 | ||
|
|
189394b885 | ||
|
|
a3a619835d | ||
|
|
fed2659869 | ||
|
|
795a8e3d69 | ||
|
|
9e1c862cb6 | ||
|
|
1661125315 | ||
|
|
2565492db0 | ||
|
|
c4786d366b | ||
|
|
3b49d61ac2 | ||
|
|
10726d52ac | ||
|
|
86ac443cd1 | ||
|
|
361d4b4c87 | ||
|
|
bc0b8ff2fb | ||
|
|
d29486343a | ||
|
|
c99fabb7a0 | ||
|
|
3bcfd47c68 | ||
|
|
f37c237b8b | ||
|
|
95fd031c4d | ||
|
|
613f814508 | ||
|
|
e70d7a78f0 | ||
|
|
3fef96f827 | ||
|
|
e5544ae1f8 | ||
|
|
6c9ad82b1c | ||
|
|
1946856b1f | ||
|
|
a7a87dda4a | ||
|
|
4f2e1d3b1e | ||
|
|
2cc41d3e00 | ||
|
|
ca7bc509cf | ||
|
|
df1a3c6d21 | ||
|
|
a58d249840 | ||
|
|
e5cfafe344 | ||
|
|
70b6e1daff | ||
|
|
60bc90909a | ||
|
|
0875ba3095 | ||
|
|
cd588f847f | ||
|
|
730ed9dfec | ||
|
|
b31409040f | ||
|
|
d11c3e5c3a | ||
|
|
e9774a5227 | ||
|
|
d640b225ec | ||
|
|
60a11dcb44 | ||
|
|
91ce715af1 | ||
|
|
a8d82f126d | ||
|
|
dda4fd4644 | ||
|
|
5e3dc45a16 | ||
|
|
3a40a0000a | ||
|
|
147a50d06e | ||
|
|
a20a35fdda | ||
|
|
880a293390 | ||
|
|
d1e10d7d16 | ||
|
|
4d44675283 | ||
|
|
609f11b31e | ||
|
|
c6f25641eb | ||
|
|
e55151472b | ||
|
|
33ef6c20f2 | ||
|
|
90de6820f7 | ||
|
|
e1e434af12 | ||
|
|
0cdef7e7f3 |
@@ -194,14 +194,15 @@ The tests are all built from the tests/ directory.
|
|||||||
### Device tests
|
### Device tests
|
||||||
|
|
||||||
$ mma
|
$ mma
|
||||||
|
$ adb remount
|
||||||
$ adb sync
|
$ adb sync
|
||||||
$ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
|
$ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
|
||||||
$ adb shell \
|
$ adb shell \
|
||||||
/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
|
/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
|
||||||
# Only for 64-bit targets
|
# Only for 64-bit targets
|
||||||
$ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
|
$ adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests64
|
||||||
$ adb shell \
|
$ adb shell \
|
||||||
/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static64
|
/data/nativetest64/bionic-unit-tests-static/bionic-unit-tests-static64
|
||||||
|
|
||||||
### Host tests
|
### Host tests
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ benchmark_cflags := \
|
|||||||
-Wunused \
|
-Wunused \
|
||||||
|
|
||||||
benchmark_cppflags := \
|
benchmark_cppflags := \
|
||||||
-std=gnu++11 \
|
|
||||||
|
|
||||||
benchmarklib_src_files := \
|
benchmarklib_src_files := \
|
||||||
Benchmark.cpp \
|
Benchmark.cpp \
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <benchmark/Benchmark.h>
|
#include <benchmark/Benchmark.h>
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ libc_common_src_files := \
|
|||||||
libc_common_src_files += \
|
libc_common_src_files += \
|
||||||
bionic/__FD_chk.cpp \
|
bionic/__FD_chk.cpp \
|
||||||
bionic/__fgets_chk.cpp \
|
bionic/__fgets_chk.cpp \
|
||||||
|
bionic/__fread_chk.cpp \
|
||||||
|
bionic/__fwrite_chk.cpp \
|
||||||
|
bionic/__getcwd_chk.cpp \
|
||||||
bionic/__memchr_chk.cpp \
|
bionic/__memchr_chk.cpp \
|
||||||
bionic/__memmove_chk.cpp \
|
bionic/__memmove_chk.cpp \
|
||||||
bionic/__memrchr_chk.cpp \
|
bionic/__memrchr_chk.cpp \
|
||||||
@@ -575,10 +578,6 @@ libc_common_cflags := \
|
|||||||
-D_LIBC=1 \
|
-D_LIBC=1 \
|
||||||
-Wall -Wextra -Wunused \
|
-Wall -Wextra -Wunused \
|
||||||
|
|
||||||
ifneq ($(TARGET_USES_LOGD),false)
|
|
||||||
libc_common_cflags += -DTARGET_USES_LOGD
|
|
||||||
endif
|
|
||||||
|
|
||||||
use_clang := $(USE_CLANG_PLATFORM_BUILD)
|
use_clang := $(USE_CLANG_PLATFORM_BUILD)
|
||||||
|
|
||||||
# Clang/llvm has incompatible long double (fp128) for x86_64.
|
# Clang/llvm has incompatible long double (fp128) for x86_64.
|
||||||
@@ -624,7 +623,6 @@ libc_common_conlyflags := \
|
|||||||
|
|
||||||
# Define some common cppflags
|
# Define some common cppflags
|
||||||
libc_common_cppflags := \
|
libc_common_cppflags := \
|
||||||
-std=gnu++11
|
|
||||||
|
|
||||||
# Define some common includes
|
# Define some common includes
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) arm,mips,x8
|
|||||||
int setgroups:setgroups32(int, const gid_t*) arm,x86
|
int setgroups:setgroups32(int, const gid_t*) arm,x86
|
||||||
int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
|
int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
|
||||||
int setpgid(pid_t, pid_t) all
|
int setpgid(pid_t, pid_t) all
|
||||||
pid_t vfork(void) arm
|
|
||||||
int setregid:setregid32(gid_t, gid_t) arm,x86
|
int setregid:setregid32(gid_t, gid_t) arm,x86
|
||||||
int setregid:setregid(gid_t, gid_t) arm64,mips,mips64,x86_64
|
int setregid:setregid(gid_t, gid_t) arm64,mips,mips64,x86_64
|
||||||
int chroot(const char*) all
|
int chroot(const char*) all
|
||||||
@@ -333,7 +332,7 @@ int __set_tls:set_thread_area(void*) mips,mips64
|
|||||||
int __set_thread_area:set_thread_area(void*) x86
|
int __set_thread_area:set_thread_area(void*) x86
|
||||||
|
|
||||||
# vdso stuff.
|
# vdso stuff.
|
||||||
int clock_gettime(clockid_t, timespec*) arm,mips,mips64,x86
|
int clock_gettime(clockid_t, timespec*) arm,mips,mips64
|
||||||
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86_64
|
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86,x86_64
|
||||||
int gettimeofday(timeval*, timezone*) arm,mips,mips64,x86
|
int gettimeofday(timeval*, timezone*) arm,mips,mips64
|
||||||
int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86_64
|
int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86,x86_64
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ libc_bionic_src_files_arm += \
|
|||||||
arch-arm/bionic/__bionic_clone.S \
|
arch-arm/bionic/__bionic_clone.S \
|
||||||
arch-arm/bionic/_exit_with_stack_teardown.S \
|
arch-arm/bionic/_exit_with_stack_teardown.S \
|
||||||
arch-arm/bionic/libgcc_compat.c \
|
arch-arm/bionic/libgcc_compat.c \
|
||||||
arch-arm/bionic/libgcc_protect_unwind.c \
|
|
||||||
arch-arm/bionic/__restore.S \
|
arch-arm/bionic/__restore.S \
|
||||||
arch-arm/bionic/setjmp.S \
|
arch-arm/bionic/setjmp.S \
|
||||||
arch-arm/bionic/syscall.S \
|
arch-arm/bionic/syscall.S \
|
||||||
|
arch-arm/bionic/vfork.S \
|
||||||
|
|
||||||
libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c
|
libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c
|
||||||
libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
|
libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: This file should go away once unwinder migration to libc++.so is complete.
|
|
||||||
|
|
||||||
extern char _Unwind_Backtrace __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Find_exidx __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Restore_VFP_D __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Restore_VFP __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Restore_VFP_D_16_to_31 __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Restore_WMMXD __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Restore_WMMXC __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_GetCFA __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_RaiseException __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_ForcedUnwind __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Resume __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Resume_or_Rethrow __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_Complete __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_DeleteException __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_VRS_Get __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_VRS_Set __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Backtrace __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_VRS_Pop __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Save_VFP_D __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Save_VFP __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Save_VFP_D_16_to_31 __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Save_WMMXD __attribute((visibility("protected")));
|
|
||||||
extern char __gnu_Unwind_Save_WMMXC __attribute((visibility("protected")));
|
|
||||||
extern char ___Unwind_RaiseException __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_RaiseException __attribute((visibility("protected")));
|
|
||||||
extern char ___Unwind_Resume __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_Resume __attribute((visibility("protected")));
|
|
||||||
extern char ___Unwind_Resume_or_Rethrow __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_Resume_or_Rethrow __attribute((visibility("protected")));
|
|
||||||
extern char ___Unwind_ForcedUnwind __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_ForcedUnwind __attribute((visibility("protected")));
|
|
||||||
extern char ___Unwind_Backtrace __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_GetRegionStart __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_GetLanguageSpecificData __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_GetDataRelBase __attribute((visibility("protected")));
|
|
||||||
extern char _Unwind_GetTextRelBase __attribute((visibility("protected")));
|
|
||||||
|
|
||||||
void* __bionic_libgcc_unwind_symbols[] = {
|
|
||||||
&_Unwind_Backtrace,
|
|
||||||
&__gnu_Unwind_Find_exidx,
|
|
||||||
&__gnu_Unwind_Restore_VFP_D,
|
|
||||||
&__gnu_Unwind_Restore_VFP,
|
|
||||||
&__gnu_Unwind_Restore_VFP_D_16_to_31,
|
|
||||||
&__gnu_Unwind_Restore_WMMXD,
|
|
||||||
&__gnu_Unwind_Restore_WMMXC,
|
|
||||||
&_Unwind_GetCFA,
|
|
||||||
&__gnu_Unwind_RaiseException,
|
|
||||||
&__gnu_Unwind_ForcedUnwind,
|
|
||||||
&__gnu_Unwind_Resume,
|
|
||||||
&__gnu_Unwind_Resume_or_Rethrow,
|
|
||||||
&_Unwind_Complete,
|
|
||||||
&_Unwind_DeleteException,
|
|
||||||
&_Unwind_VRS_Get,
|
|
||||||
&_Unwind_VRS_Set,
|
|
||||||
&__gnu_Unwind_Backtrace,
|
|
||||||
&_Unwind_VRS_Pop,
|
|
||||||
&__gnu_Unwind_Save_VFP_D,
|
|
||||||
&__gnu_Unwind_Save_VFP,
|
|
||||||
&__gnu_Unwind_Save_VFP_D_16_to_31,
|
|
||||||
&__gnu_Unwind_Save_WMMXD,
|
|
||||||
&__gnu_Unwind_Save_WMMXC,
|
|
||||||
&___Unwind_RaiseException,
|
|
||||||
&_Unwind_RaiseException,
|
|
||||||
&___Unwind_Resume,
|
|
||||||
&_Unwind_Resume,
|
|
||||||
&___Unwind_Resume_or_Rethrow,
|
|
||||||
&_Unwind_Resume_or_Rethrow,
|
|
||||||
&___Unwind_ForcedUnwind,
|
|
||||||
&_Unwind_ForcedUnwind,
|
|
||||||
&___Unwind_Backtrace,
|
|
||||||
&_Unwind_GetRegionStart,
|
|
||||||
&_Unwind_GetLanguageSpecificData,
|
|
||||||
&_Unwind_GetDataRelBase,
|
|
||||||
&_Unwind_GetTextRelBase,
|
|
||||||
};
|
|
||||||
46
libc/arch-arm/bionic/vfork.S
Normal file
46
libc/arch-arm/bionic/vfork.S
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <private/bionic_asm.h>
|
||||||
|
|
||||||
|
ENTRY(vfork)
|
||||||
|
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
|
||||||
|
mrc p15, 0, r3, c13, c0, 3
|
||||||
|
ldr r3, [r3, #4]
|
||||||
|
mov r0, #0
|
||||||
|
str r0, [r3, #12]
|
||||||
|
|
||||||
|
mov ip, r7
|
||||||
|
ldr r7, =__NR_vfork
|
||||||
|
swi #0
|
||||||
|
mov r7, ip
|
||||||
|
cmn r0, #(MAX_ERRNO + 1)
|
||||||
|
bxls lr
|
||||||
|
neg r0, r0
|
||||||
|
b __set_errno_internal
|
||||||
|
END(vfork)
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
.macro m_scan_byte
|
.macro m_scan_byte
|
||||||
ldrb r3, [r0]
|
ldrb r3, [r0]
|
||||||
cbz r3, strcat_r0_scan_done
|
cbz r3, .L_strcat_r0_scan_done
|
||||||
add r0, #1
|
add r0, #1
|
||||||
.endm // m_scan_byte
|
.endm // m_scan_byte
|
||||||
|
|
||||||
@@ -84,10 +84,10 @@ ENTRY(strcat)
|
|||||||
// Quick check to see if src is empty.
|
// Quick check to see if src is empty.
|
||||||
ldrb r2, [r1]
|
ldrb r2, [r1]
|
||||||
pld [r1, #0]
|
pld [r1, #0]
|
||||||
cbnz r2, strcat_continue
|
cbnz r2, .L_strcat_continue
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
strcat_continue:
|
.L_strcat_continue:
|
||||||
// To speed up really small dst strings, unroll checking the first 4 bytes.
|
// To speed up really small dst strings, unroll checking the first 4 bytes.
|
||||||
m_push
|
m_push
|
||||||
m_scan_byte
|
m_scan_byte
|
||||||
@@ -96,95 +96,95 @@ strcat_continue:
|
|||||||
m_scan_byte
|
m_scan_byte
|
||||||
|
|
||||||
ands r3, r0, #7
|
ands r3, r0, #7
|
||||||
beq strcat_mainloop
|
beq .L_strcat_mainloop
|
||||||
|
|
||||||
// Align to a double word (64 bits).
|
// Align to a double word (64 bits).
|
||||||
rsb r3, r3, #8
|
rsb r3, r3, #8
|
||||||
lsls ip, r3, #31
|
lsls ip, r3, #31
|
||||||
beq strcat_align_to_32
|
beq .L_strcat_align_to_32
|
||||||
|
|
||||||
ldrb r5, [r0]
|
ldrb r5, [r0]
|
||||||
cbz r5, strcat_r0_scan_done
|
cbz r5, .L_strcat_r0_scan_done
|
||||||
add r0, r0, #1
|
add r0, r0, #1
|
||||||
|
|
||||||
strcat_align_to_32:
|
.L_strcat_align_to_32:
|
||||||
bcc strcat_align_to_64
|
bcc .L_strcat_align_to_64
|
||||||
|
|
||||||
ldrb r2, [r0]
|
ldrb r2, [r0]
|
||||||
cbz r2, strcat_r0_scan_done
|
cbz r2, .L_strcat_r0_scan_done
|
||||||
add r0, r0, #1
|
add r0, r0, #1
|
||||||
ldrb r4, [r0]
|
ldrb r4, [r0]
|
||||||
cbz r4, strcat_r0_scan_done
|
cbz r4, .L_strcat_r0_scan_done
|
||||||
add r0, r0, #1
|
add r0, r0, #1
|
||||||
|
|
||||||
strcat_align_to_64:
|
.L_strcat_align_to_64:
|
||||||
tst r3, #4
|
tst r3, #4
|
||||||
beq strcat_mainloop
|
beq .L_strcat_mainloop
|
||||||
ldr r3, [r0], #4
|
ldr r3, [r0], #4
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcat_zero_in_second_register
|
bne .L_strcat_zero_in_second_register
|
||||||
b strcat_mainloop
|
b .L_strcat_mainloop
|
||||||
|
|
||||||
strcat_r0_scan_done:
|
.L_strcat_r0_scan_done:
|
||||||
// For short copies, hard-code checking the first 8 bytes since this
|
// For short copies, hard-code checking the first 8 bytes since this
|
||||||
// new code doesn't win until after about 8 bytes.
|
// new code doesn't win until after about 8 bytes.
|
||||||
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r5, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
|
m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish
|
||||||
m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
|
m_copy_byte reg=r5, cmd=cbnz, label=.L_strcpy_continue
|
||||||
|
|
||||||
strcpy_finish:
|
.L_strcpy_finish:
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_continue:
|
.L_strcpy_continue:
|
||||||
ands r3, r0, #7
|
ands r3, r0, #7
|
||||||
beq strcpy_check_src_align
|
beq .L_strcpy_check_src_align
|
||||||
|
|
||||||
// Align to a double word (64 bits).
|
// Align to a double word (64 bits).
|
||||||
rsb r3, r3, #8
|
rsb r3, r3, #8
|
||||||
lsls ip, r3, #31
|
lsls ip, r3, #31
|
||||||
beq strcpy_align_to_32
|
beq .L_strcpy_align_to_32
|
||||||
|
|
||||||
ldrb r2, [r1], #1
|
ldrb r2, [r1], #1
|
||||||
strb r2, [r0], #1
|
strb r2, [r0], #1
|
||||||
cbz r2, strcpy_complete
|
cbz r2, .L_strcpy_complete
|
||||||
|
|
||||||
strcpy_align_to_32:
|
.L_strcpy_align_to_32:
|
||||||
bcc strcpy_align_to_64
|
bcc .L_strcpy_align_to_64
|
||||||
|
|
||||||
ldrb r2, [r1], #1
|
ldrb r2, [r1], #1
|
||||||
strb r2, [r0], #1
|
strb r2, [r0], #1
|
||||||
cbz r2, strcpy_complete
|
cbz r2, .L_strcpy_complete
|
||||||
ldrb r2, [r1], #1
|
ldrb r2, [r1], #1
|
||||||
strb r2, [r0], #1
|
strb r2, [r0], #1
|
||||||
cbz r2, strcpy_complete
|
cbz r2, .L_strcpy_complete
|
||||||
|
|
||||||
strcpy_align_to_64:
|
.L_strcpy_align_to_64:
|
||||||
tst r3, #4
|
tst r3, #4
|
||||||
beq strcpy_check_src_align
|
beq .L_strcpy_check_src_align
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
|
|
||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
|
|
||||||
strcpy_check_src_align:
|
.L_strcpy_check_src_align:
|
||||||
// At this point dst is aligned to a double word, check if src
|
// At this point dst is aligned to a double word, check if src
|
||||||
// is also aligned to a double word.
|
// is also aligned to a double word.
|
||||||
ands r3, r1, #7
|
ands r3, r1, #7
|
||||||
bne strcpy_unaligned_copy
|
bne .L_strcpy_unaligned_copy
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
strcpy_mainloop:
|
.L_strcpy_mainloop:
|
||||||
ldrd r2, r3, [r1], #8
|
ldrd r2, r3, [r1], #8
|
||||||
|
|
||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
@@ -192,128 +192,128 @@ strcpy_mainloop:
|
|||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_second_register
|
bne .L_strcpy_zero_in_second_register
|
||||||
|
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
b strcpy_mainloop
|
b .L_strcpy_mainloop
|
||||||
|
|
||||||
strcpy_complete:
|
.L_strcpy_complete:
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_zero_in_first_register:
|
.L_strcpy_zero_in_first_register:
|
||||||
lsls lr, ip, #17
|
lsls lr, ip, #17
|
||||||
bne strcpy_copy1byte
|
bne .L_strcpy_copy1byte
|
||||||
bcs strcpy_copy2bytes
|
bcs .L_strcpy_copy2bytes
|
||||||
lsls ip, ip, #1
|
lsls ip, ip, #1
|
||||||
bne strcpy_copy3bytes
|
bne .L_strcpy_copy3bytes
|
||||||
|
|
||||||
strcpy_copy4bytes:
|
.L_strcpy_copy4bytes:
|
||||||
// Copy 4 bytes to the destiniation.
|
// Copy 4 bytes to the destiniation.
|
||||||
str r2, [r0]
|
str r2, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_copy1byte:
|
.L_strcpy_copy1byte:
|
||||||
strb r2, [r0]
|
strb r2, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_copy2bytes:
|
.L_strcpy_copy2bytes:
|
||||||
strh r2, [r0]
|
strh r2, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_copy3bytes:
|
.L_strcpy_copy3bytes:
|
||||||
strh r2, [r0], #2
|
strh r2, [r0], #2
|
||||||
lsr r2, #16
|
lsr r2, #16
|
||||||
strb r2, [r0]
|
strb r2, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_zero_in_second_register:
|
.L_strcpy_zero_in_second_register:
|
||||||
lsls lr, ip, #17
|
lsls lr, ip, #17
|
||||||
bne strcpy_copy5bytes
|
bne .L_strcpy_copy5bytes
|
||||||
bcs strcpy_copy6bytes
|
bcs .L_strcpy_copy6bytes
|
||||||
lsls ip, ip, #1
|
lsls ip, ip, #1
|
||||||
bne strcpy_copy7bytes
|
bne .L_strcpy_copy7bytes
|
||||||
|
|
||||||
// Copy 8 bytes to the destination.
|
// Copy 8 bytes to the destination.
|
||||||
strd r2, r3, [r0]
|
strd r2, r3, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_copy5bytes:
|
.L_strcpy_copy5bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strb r3, [r0]
|
strb r3, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_copy6bytes:
|
.L_strcpy_copy6bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strh r3, [r0]
|
strh r3, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_copy7bytes:
|
.L_strcpy_copy7bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strh r3, [r0], #2
|
strh r3, [r0], #2
|
||||||
lsr r3, #16
|
lsr r3, #16
|
||||||
strb r3, [r0]
|
strb r3, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unaligned_copy:
|
.L_strcpy_unaligned_copy:
|
||||||
// Dst is aligned to a double word, while src is at an unknown alignment.
|
// Dst is aligned to a double word, while src is at an unknown alignment.
|
||||||
// There are 7 different versions of the unaligned copy code
|
// There are 7 different versions of the unaligned copy code
|
||||||
// to prevent overreading the src. The mainloop of every single version
|
// to prevent overreading the src. The mainloop of every single version
|
||||||
// will store 64 bits per loop. The difference is how much of src can
|
// will store 64 bits per loop. The difference is how much of src can
|
||||||
// be read without potentially crossing a page boundary.
|
// be read without potentially crossing a page boundary.
|
||||||
tbb [pc, r3]
|
tbb [pc, r3]
|
||||||
strcpy_unaligned_branchtable:
|
.L_strcpy_unaligned_branchtable:
|
||||||
.byte 0
|
.byte 0
|
||||||
.byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign7 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
.byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign6 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
.byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign5 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
.byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign4 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
.byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign3 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
.byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign2 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
.byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
|
.byte ((.L_strcpy_unalign1 - .L_strcpy_unaligned_branchtable)/2)
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 7 bytes before possibly crossing a page.
|
// Can read 7 bytes before possibly crossing a page.
|
||||||
strcpy_unalign7:
|
.L_strcpy_unalign7:
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
|
|
||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
|
|
||||||
ldrb r3, [r1]
|
ldrb r3, [r1]
|
||||||
cbz r3, strcpy_unalign7_copy5bytes
|
cbz r3, .L_strcpy_unalign7_copy5bytes
|
||||||
ldrb r4, [r1, #1]
|
ldrb r4, [r1, #1]
|
||||||
cbz r4, strcpy_unalign7_copy6bytes
|
cbz r4, .L_strcpy_unalign7_copy6bytes
|
||||||
ldrb r5, [r1, #2]
|
ldrb r5, [r1, #2]
|
||||||
cbz r5, strcpy_unalign7_copy7bytes
|
cbz r5, .L_strcpy_unalign7_copy7bytes
|
||||||
|
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
|
|
||||||
lsrs ip, r3, #24
|
lsrs ip, r3, #24
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
beq strcpy_unalign_return
|
beq .L_strcpy_unalign_return
|
||||||
b strcpy_unalign7
|
b .L_strcpy_unalign7
|
||||||
|
|
||||||
strcpy_unalign7_copy5bytes:
|
.L_strcpy_unalign7_copy5bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strb r3, [r0]
|
strb r3, [r0]
|
||||||
strcpy_unalign_return:
|
.L_strcpy_unalign_return:
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unalign7_copy6bytes:
|
.L_strcpy_unalign7_copy6bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strb r3, [r0], #1
|
strb r3, [r0], #1
|
||||||
strb r4, [r0], #1
|
strb r4, [r0], #1
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unalign7_copy7bytes:
|
.L_strcpy_unalign7_copy7bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strb r3, [r0], #1
|
strb r3, [r0], #1
|
||||||
strb r4, [r0], #1
|
strb r4, [r0], #1
|
||||||
@@ -322,41 +322,41 @@ strcpy_unalign7_copy7bytes:
|
|||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 6 bytes before possibly crossing a page.
|
// Can read 6 bytes before possibly crossing a page.
|
||||||
strcpy_unalign6:
|
.L_strcpy_unalign6:
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
|
|
||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
|
|
||||||
ldrb r4, [r1]
|
ldrb r4, [r1]
|
||||||
cbz r4, strcpy_unalign_copy5bytes
|
cbz r4, .L_strcpy_unalign_copy5bytes
|
||||||
ldrb r5, [r1, #1]
|
ldrb r5, [r1, #1]
|
||||||
cbz r5, strcpy_unalign_copy6bytes
|
cbz r5, .L_strcpy_unalign_copy6bytes
|
||||||
|
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
|
|
||||||
tst r3, #0xff0000
|
tst r3, #0xff0000
|
||||||
beq strcpy_copy7bytes
|
beq .L_strcpy_copy7bytes
|
||||||
lsrs ip, r3, #24
|
lsrs ip, r3, #24
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
beq strcpy_unalign_return
|
beq .L_strcpy_unalign_return
|
||||||
b strcpy_unalign6
|
b .L_strcpy_unalign6
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 5 bytes before possibly crossing a page.
|
// Can read 5 bytes before possibly crossing a page.
|
||||||
strcpy_unalign5:
|
.L_strcpy_unalign5:
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
|
|
||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
|
|
||||||
ldrb r4, [r1]
|
ldrb r4, [r1]
|
||||||
cbz r4, strcpy_unalign_copy5bytes
|
cbz r4, .L_strcpy_unalign_copy5bytes
|
||||||
|
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
|
|
||||||
@@ -365,17 +365,17 @@ strcpy_unalign5:
|
|||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_second_register
|
bne .L_strcpy_zero_in_second_register
|
||||||
|
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
b strcpy_unalign5
|
b .L_strcpy_unalign5
|
||||||
|
|
||||||
strcpy_unalign_copy5bytes:
|
.L_strcpy_unalign_copy5bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strb r4, [r0]
|
strb r4, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unalign_copy6bytes:
|
.L_strcpy_unalign_copy6bytes:
|
||||||
str r2, [r0], #4
|
str r2, [r0], #4
|
||||||
strb r4, [r0], #1
|
strb r4, [r0], #1
|
||||||
strb r5, [r0]
|
strb r5, [r0]
|
||||||
@@ -383,13 +383,13 @@ strcpy_unalign_copy6bytes:
|
|||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 4 bytes before possibly crossing a page.
|
// Can read 4 bytes before possibly crossing a page.
|
||||||
strcpy_unalign4:
|
.L_strcpy_unalign4:
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
|
|
||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
|
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
@@ -397,20 +397,20 @@ strcpy_unalign4:
|
|||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_second_register
|
bne .L_strcpy_zero_in_second_register
|
||||||
|
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
b strcpy_unalign4
|
b .L_strcpy_unalign4
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 3 bytes before possibly crossing a page.
|
// Can read 3 bytes before possibly crossing a page.
|
||||||
strcpy_unalign3:
|
.L_strcpy_unalign3:
|
||||||
ldrb r2, [r1]
|
ldrb r2, [r1]
|
||||||
cbz r2, strcpy_unalign3_copy1byte
|
cbz r2, .L_strcpy_unalign3_copy1byte
|
||||||
ldrb r3, [r1, #1]
|
ldrb r3, [r1, #1]
|
||||||
cbz r3, strcpy_unalign3_copy2bytes
|
cbz r3, .L_strcpy_unalign3_copy2bytes
|
||||||
ldrb r4, [r1, #2]
|
ldrb r4, [r1, #2]
|
||||||
cbz r4, strcpy_unalign3_copy3bytes
|
cbz r4, .L_strcpy_unalign3_copy3bytes
|
||||||
|
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
@@ -418,26 +418,26 @@ strcpy_unalign3:
|
|||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
|
|
||||||
lsrs lr, r2, #24
|
lsrs lr, r2, #24
|
||||||
beq strcpy_copy4bytes
|
beq .L_strcpy_copy4bytes
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_second_register
|
bne .L_strcpy_zero_in_second_register
|
||||||
|
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
b strcpy_unalign3
|
b .L_strcpy_unalign3
|
||||||
|
|
||||||
strcpy_unalign3_copy1byte:
|
.L_strcpy_unalign3_copy1byte:
|
||||||
strb r2, [r0]
|
strb r2, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unalign3_copy2bytes:
|
.L_strcpy_unalign3_copy2bytes:
|
||||||
strb r2, [r0], #1
|
strb r2, [r0], #1
|
||||||
strb r3, [r0]
|
strb r3, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unalign3_copy3bytes:
|
.L_strcpy_unalign3_copy3bytes:
|
||||||
strb r2, [r0], #1
|
strb r2, [r0], #1
|
||||||
strb r3, [r0], #1
|
strb r3, [r0], #1
|
||||||
strb r4, [r0]
|
strb r4, [r0]
|
||||||
@@ -445,34 +445,34 @@ strcpy_unalign3_copy3bytes:
|
|||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 2 bytes before possibly crossing a page.
|
// Can read 2 bytes before possibly crossing a page.
|
||||||
strcpy_unalign2:
|
.L_strcpy_unalign2:
|
||||||
ldrb r2, [r1]
|
ldrb r2, [r1]
|
||||||
cbz r2, strcpy_unalign_copy1byte
|
cbz r2, .L_strcpy_unalign_copy1byte
|
||||||
ldrb r4, [r1, #1]
|
ldrb r4, [r1, #1]
|
||||||
cbz r4, strcpy_unalign_copy2bytes
|
cbz r4, .L_strcpy_unalign_copy2bytes
|
||||||
|
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
|
|
||||||
tst r2, #0xff0000
|
tst r2, #0xff0000
|
||||||
beq strcpy_copy3bytes
|
beq .L_strcpy_copy3bytes
|
||||||
lsrs ip, r2, #24
|
lsrs ip, r2, #24
|
||||||
beq strcpy_copy4bytes
|
beq .L_strcpy_copy4bytes
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_second_register
|
bne .L_strcpy_zero_in_second_register
|
||||||
|
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
b strcpy_unalign2
|
b .L_strcpy_unalign2
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
// Can read 1 byte before possibly crossing a page.
|
// Can read 1 byte before possibly crossing a page.
|
||||||
strcpy_unalign1:
|
.L_strcpy_unalign1:
|
||||||
ldrb r2, [r1]
|
ldrb r2, [r1]
|
||||||
cbz r2, strcpy_unalign_copy1byte
|
cbz r2, .L_strcpy_unalign_copy1byte
|
||||||
|
|
||||||
ldr r2, [r1], #4
|
ldr r2, [r1], #4
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
@@ -482,27 +482,27 @@ strcpy_unalign1:
|
|||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_first_register
|
bne .L_strcpy_zero_in_first_register
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcpy_zero_in_second_register
|
bne .L_strcpy_zero_in_second_register
|
||||||
|
|
||||||
strd r2, r3, [r0], #8
|
strd r2, r3, [r0], #8
|
||||||
b strcpy_unalign1
|
b .L_strcpy_unalign1
|
||||||
|
|
||||||
strcpy_unalign_copy1byte:
|
.L_strcpy_unalign_copy1byte:
|
||||||
strb r2, [r0]
|
strb r2, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
strcpy_unalign_copy2bytes:
|
.L_strcpy_unalign_copy2bytes:
|
||||||
strb r2, [r0], #1
|
strb r2, [r0], #1
|
||||||
strb r4, [r0]
|
strb r4, [r0]
|
||||||
m_pop
|
m_pop
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
strcat_mainloop:
|
.L_strcat_mainloop:
|
||||||
ldrd r2, r3, [r0], #8
|
ldrd r2, r3, [r0], #8
|
||||||
|
|
||||||
pld [r0, #64]
|
pld [r0, #64]
|
||||||
@@ -510,59 +510,59 @@ strcat_mainloop:
|
|||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcat_zero_in_first_register
|
bne .L_strcat_zero_in_first_register
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne strcat_zero_in_second_register
|
bne .L_strcat_zero_in_second_register
|
||||||
b strcat_mainloop
|
b .L_strcat_mainloop
|
||||||
|
|
||||||
strcat_zero_in_first_register:
|
.L_strcat_zero_in_first_register:
|
||||||
// Prefetch the src now, it's going to be used soon.
|
// Prefetch the src now, it's going to be used soon.
|
||||||
pld [r1, #0]
|
pld [r1, #0]
|
||||||
lsls lr, ip, #17
|
lsls lr, ip, #17
|
||||||
bne strcat_sub8
|
bne .L_strcat_sub8
|
||||||
bcs strcat_sub7
|
bcs .L_strcat_sub7
|
||||||
lsls ip, ip, #1
|
lsls ip, ip, #1
|
||||||
bne strcat_sub6
|
bne .L_strcat_sub6
|
||||||
|
|
||||||
sub r0, r0, #5
|
sub r0, r0, #5
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_sub8:
|
.L_strcat_sub8:
|
||||||
sub r0, r0, #8
|
sub r0, r0, #8
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_sub7:
|
.L_strcat_sub7:
|
||||||
sub r0, r0, #7
|
sub r0, r0, #7
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_sub6:
|
.L_strcat_sub6:
|
||||||
sub r0, r0, #6
|
sub r0, r0, #6
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_zero_in_second_register:
|
.L_strcat_zero_in_second_register:
|
||||||
// Prefetch the src now, it's going to be used soon.
|
// Prefetch the src now, it's going to be used soon.
|
||||||
pld [r1, #0]
|
pld [r1, #0]
|
||||||
lsls lr, ip, #17
|
lsls lr, ip, #17
|
||||||
bne strcat_sub4
|
bne .L_strcat_sub4
|
||||||
bcs strcat_sub3
|
bcs .L_strcat_sub3
|
||||||
lsls ip, ip, #1
|
lsls ip, ip, #1
|
||||||
bne strcat_sub2
|
bne .L_strcat_sub2
|
||||||
|
|
||||||
sub r0, r0, #1
|
sub r0, r0, #1
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_sub4:
|
.L_strcat_sub4:
|
||||||
sub r0, r0, #4
|
sub r0, r0, #4
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_sub3:
|
.L_strcat_sub3:
|
||||||
sub r0, r0, #3
|
sub r0, r0, #3
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
|
|
||||||
strcat_sub2:
|
.L_strcat_sub2:
|
||||||
sub r0, r0, #2
|
sub r0, r0, #2
|
||||||
b strcat_r0_scan_done
|
b .L_strcat_r0_scan_done
|
||||||
END(strcat)
|
END(strcat)
|
||||||
|
|||||||
@@ -65,38 +65,38 @@ ENTRY(strlen)
|
|||||||
mov r1, r0
|
mov r1, r0
|
||||||
|
|
||||||
ands r3, r0, #7
|
ands r3, r0, #7
|
||||||
beq mainloop
|
beq .L_mainloop
|
||||||
|
|
||||||
// Align to a double word (64 bits).
|
// Align to a double word (64 bits).
|
||||||
rsb r3, r3, #8
|
rsb r3, r3, #8
|
||||||
lsls ip, r3, #31
|
lsls ip, r3, #31
|
||||||
beq align_to_32
|
beq .L_align_to_32
|
||||||
|
|
||||||
ldrb r2, [r1], #1
|
ldrb r2, [r1], #1
|
||||||
cbz r2, update_count_and_return
|
cbz r2, .L_update_count_and_return
|
||||||
|
|
||||||
align_to_32:
|
.L_align_to_32:
|
||||||
bcc align_to_64
|
bcc .L_align_to_64
|
||||||
ands ip, r3, #2
|
ands ip, r3, #2
|
||||||
beq align_to_64
|
beq .L_align_to_64
|
||||||
|
|
||||||
ldrb r2, [r1], #1
|
ldrb r2, [r1], #1
|
||||||
cbz r2, update_count_and_return
|
cbz r2, .L_update_count_and_return
|
||||||
ldrb r2, [r1], #1
|
ldrb r2, [r1], #1
|
||||||
cbz r2, update_count_and_return
|
cbz r2, .L_update_count_and_return
|
||||||
|
|
||||||
align_to_64:
|
.L_align_to_64:
|
||||||
tst r3, #4
|
tst r3, #4
|
||||||
beq mainloop
|
beq .L_mainloop
|
||||||
ldr r3, [r1], #4
|
ldr r3, [r1], #4
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne zero_in_second_register
|
bne .L_zero_in_second_register
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
mainloop:
|
.L_mainloop:
|
||||||
ldrd r2, r3, [r1], #8
|
ldrd r2, r3, [r1], #8
|
||||||
|
|
||||||
pld [r1, #64]
|
pld [r1, #64]
|
||||||
@@ -104,62 +104,62 @@ mainloop:
|
|||||||
sub ip, r2, #0x01010101
|
sub ip, r2, #0x01010101
|
||||||
bic ip, ip, r2
|
bic ip, ip, r2
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne zero_in_first_register
|
bne .L_zero_in_first_register
|
||||||
|
|
||||||
sub ip, r3, #0x01010101
|
sub ip, r3, #0x01010101
|
||||||
bic ip, ip, r3
|
bic ip, ip, r3
|
||||||
ands ip, ip, #0x80808080
|
ands ip, ip, #0x80808080
|
||||||
bne zero_in_second_register
|
bne .L_zero_in_second_register
|
||||||
b mainloop
|
b .L_mainloop
|
||||||
|
|
||||||
update_count_and_return:
|
.L_update_count_and_return:
|
||||||
sub r0, r1, r0
|
sub r0, r1, r0
|
||||||
sub r0, r0, #1
|
sub r0, r0, #1
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
zero_in_first_register:
|
.L_zero_in_first_register:
|
||||||
sub r0, r1, r0
|
sub r0, r1, r0
|
||||||
lsls r3, ip, #17
|
lsls r3, ip, #17
|
||||||
bne sub8_and_return
|
bne .L_sub8_and_return
|
||||||
bcs sub7_and_return
|
bcs .L_sub7_and_return
|
||||||
lsls ip, ip, #1
|
lsls ip, ip, #1
|
||||||
bne sub6_and_return
|
bne .L_sub6_and_return
|
||||||
|
|
||||||
sub r0, r0, #5
|
sub r0, r0, #5
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
sub8_and_return:
|
.L_sub8_and_return:
|
||||||
sub r0, r0, #8
|
sub r0, r0, #8
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
sub7_and_return:
|
.L_sub7_and_return:
|
||||||
sub r0, r0, #7
|
sub r0, r0, #7
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
sub6_and_return:
|
.L_sub6_and_return:
|
||||||
sub r0, r0, #6
|
sub r0, r0, #6
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
zero_in_second_register:
|
.L_zero_in_second_register:
|
||||||
sub r0, r1, r0
|
sub r0, r1, r0
|
||||||
lsls r3, ip, #17
|
lsls r3, ip, #17
|
||||||
bne sub4_and_return
|
bne .L_sub4_and_return
|
||||||
bcs sub3_and_return
|
bcs .L_sub3_and_return
|
||||||
lsls ip, ip, #1
|
lsls ip, ip, #1
|
||||||
bne sub2_and_return
|
bne .L_sub2_and_return
|
||||||
|
|
||||||
sub r0, r0, #1
|
sub r0, r0, #1
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
sub4_and_return:
|
.L_sub4_and_return:
|
||||||
sub r0, r0, #4
|
sub r0, r0, #4
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
sub3_and_return:
|
.L_sub3_and_return:
|
||||||
sub r0, r0, #3
|
sub r0, r0, #3
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
sub2_and_return:
|
.L_sub2_and_return:
|
||||||
sub r0, r0, #2
|
sub r0, r0, #2
|
||||||
bx lr
|
bx lr
|
||||||
END(strlen)
|
END(strlen)
|
||||||
|
|||||||
@@ -133,8 +133,7 @@ ENTRY_PRIVATE(MEMCPY_BASE)
|
|||||||
strbcs ip, [r0], #1
|
strbcs ip, [r0], #1
|
||||||
strbcs lr, [r0], #1
|
strbcs lr, [r0], #1
|
||||||
|
|
||||||
ldmfd sp!, {r0, lr}
|
ldmfd sp!, {r0, pc}
|
||||||
bx lr
|
|
||||||
END(MEMCPY_BASE)
|
END(MEMCPY_BASE)
|
||||||
|
|
||||||
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
|
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
|
||||||
|
|||||||
@@ -69,12 +69,9 @@ END(bzero)
|
|||||||
ENTRY(memset)
|
ENTRY(memset)
|
||||||
// The neon memset only wins for less than 132.
|
// The neon memset only wins for less than 132.
|
||||||
cmp r2, #132
|
cmp r2, #132
|
||||||
bhi __memset_large_copy
|
bhi .L_memset_large_copy
|
||||||
|
|
||||||
stmfd sp!, {r0}
|
|
||||||
.cfi_def_cfa_offset 4
|
|
||||||
.cfi_rel_offset r0, 0
|
|
||||||
|
|
||||||
|
mov r3, r0
|
||||||
vdup.8 q0, r1
|
vdup.8 q0, r1
|
||||||
|
|
||||||
/* make sure we have at least 32 bytes to write */
|
/* make sure we have at least 32 bytes to write */
|
||||||
@@ -84,7 +81,7 @@ ENTRY(memset)
|
|||||||
|
|
||||||
1: /* The main loop writes 32 bytes at a time */
|
1: /* The main loop writes 32 bytes at a time */
|
||||||
subs r2, r2, #32
|
subs r2, r2, #32
|
||||||
vst1.8 {d0 - d3}, [r0]!
|
vst1.8 {d0 - d3}, [r3]!
|
||||||
bhs 1b
|
bhs 1b
|
||||||
|
|
||||||
2: /* less than 32 left */
|
2: /* less than 32 left */
|
||||||
@@ -93,22 +90,20 @@ ENTRY(memset)
|
|||||||
beq 3f
|
beq 3f
|
||||||
|
|
||||||
// writes 16 bytes, 128-bits aligned
|
// writes 16 bytes, 128-bits aligned
|
||||||
vst1.8 {d0, d1}, [r0]!
|
vst1.8 {d0, d1}, [r3]!
|
||||||
3: /* write up to 15-bytes (count in r2) */
|
3: /* write up to 15-bytes (count in r2) */
|
||||||
movs ip, r2, lsl #29
|
movs ip, r2, lsl #29
|
||||||
bcc 1f
|
bcc 1f
|
||||||
vst1.8 {d0}, [r0]!
|
vst1.8 {d0}, [r3]!
|
||||||
1: bge 2f
|
1: bge 2f
|
||||||
vst1.32 {d0[0]}, [r0]!
|
vst1.32 {d0[0]}, [r3]!
|
||||||
2: movs ip, r2, lsl #31
|
2: movs ip, r2, lsl #31
|
||||||
strbmi r1, [r0], #1
|
strbmi r1, [r3], #1
|
||||||
strbcs r1, [r0], #1
|
strbcs r1, [r3], #1
|
||||||
strbcs r1, [r0], #1
|
strbcs r1, [r3], #1
|
||||||
ldmfd sp!, {r0}
|
|
||||||
bx lr
|
bx lr
|
||||||
END(memset)
|
|
||||||
|
|
||||||
ENTRY_PRIVATE(__memset_large_copy)
|
.L_memset_large_copy:
|
||||||
/* compute the offset to align the destination
|
/* compute the offset to align the destination
|
||||||
* offset = (4-(src&3))&3 = -src & 3
|
* offset = (4-(src&3))&3 = -src & 3
|
||||||
*/
|
*/
|
||||||
@@ -136,8 +131,7 @@ ENTRY_PRIVATE(__memset_large_copy)
|
|||||||
strbcs r1, [r0], #1
|
strbcs r1, [r0], #1
|
||||||
strbmi r1, [r0], #1
|
strbmi r1, [r0], #1
|
||||||
subs r2, r2, r3
|
subs r2, r2, r3
|
||||||
popls {r0, r4-r7, lr} /* return */
|
popls {r0, r4-r7, pc} /* return */
|
||||||
bxls lr
|
|
||||||
|
|
||||||
/* align the destination to a cache-line */
|
/* align the destination to a cache-line */
|
||||||
mov r12, r1
|
mov r12, r1
|
||||||
@@ -180,9 +174,8 @@ ENTRY_PRIVATE(__memset_large_copy)
|
|||||||
strhmi r1, [r0], #2
|
strhmi r1, [r0], #2
|
||||||
movs r2, r2, lsl #2
|
movs r2, r2, lsl #2
|
||||||
strbcs r1, [r0]
|
strbcs r1, [r0]
|
||||||
ldmfd sp!, {r0, r4-r7, lr}
|
ldmfd sp!, {r0, r4-r7, pc}
|
||||||
bx lr
|
END(memset)
|
||||||
END(__memset_large_copy)
|
|
||||||
|
|
||||||
.data
|
.data
|
||||||
error_string:
|
error_string:
|
||||||
|
|||||||
@@ -221,8 +221,7 @@ ENTRY(memcmp)
|
|||||||
bne 8b
|
bne 8b
|
||||||
|
|
||||||
9: /* restore registers and return */
|
9: /* restore registers and return */
|
||||||
ldmfd sp!, {r4, lr}
|
ldmfd sp!, {r4, pc}
|
||||||
bx lr
|
|
||||||
|
|
||||||
10: /* process less than 12 bytes */
|
10: /* process less than 12 bytes */
|
||||||
cmp r2, #0
|
cmp r2, #0
|
||||||
|
|||||||
@@ -194,8 +194,7 @@ ENTRY(memcpy)
|
|||||||
|
|
||||||
/* we're done! restore everything and return */
|
/* we're done! restore everything and return */
|
||||||
1: ldmfd sp!, {r5-r11}
|
1: ldmfd sp!, {r5-r11}
|
||||||
ldmfd sp!, {r0, r4, lr}
|
ldmfd sp!, {r0, r4, pc}
|
||||||
bx lr
|
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
|
|
||||||
@@ -385,8 +384,7 @@ ENTRY(memcpy)
|
|||||||
|
|
||||||
/* we're done! restore sp and spilled registers and return */
|
/* we're done! restore sp and spilled registers and return */
|
||||||
add sp, sp, #28
|
add sp, sp, #28
|
||||||
ldmfd sp!, {r0, r4, lr}
|
ldmfd sp!, {r0, r4, pc}
|
||||||
bx lr
|
|
||||||
END(memcpy)
|
END(memcpy)
|
||||||
|
|
||||||
// Only reached when the __memcpy_chk check fails.
|
// Only reached when the __memcpy_chk check fails.
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ ENTRY(memset)
|
|||||||
strbcs r1, [r0], #1
|
strbcs r1, [r0], #1
|
||||||
strbmi r1, [r0], #1
|
strbmi r1, [r0], #1
|
||||||
subs r2, r2, r3
|
subs r2, r2, r3
|
||||||
popls {r0, r4-r7, lr} /* return */
|
popls {r0, r4-r7, pc} /* return */
|
||||||
bxls lr
|
|
||||||
|
|
||||||
/* align the destination to a cache-line */
|
/* align the destination to a cache-line */
|
||||||
mov r12, r1
|
mov r12, r1
|
||||||
@@ -126,8 +125,7 @@ ENTRY(memset)
|
|||||||
strhmi r1, [r0], #2
|
strhmi r1, [r0], #2
|
||||||
movs r2, r2, lsl #2
|
movs r2, r2, lsl #2
|
||||||
strbcs r1, [r0]
|
strbcs r1, [r0]
|
||||||
ldmfd sp!, {r0, r4-r7, lr}
|
ldmfd sp!, {r0, r4-r7, pc}
|
||||||
bx lr
|
|
||||||
END(memset)
|
END(memset)
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|||||||
@@ -118,6 +118,5 @@ ENTRY_PRIVATE(MEMCPY_BASE)
|
|||||||
strbcs ip, [r0], #1
|
strbcs ip, [r0], #1
|
||||||
strbcs lr, [r0], #1
|
strbcs lr, [r0], #1
|
||||||
|
|
||||||
ldmfd sp!, {r0, lr}
|
ldmfd sp!, {r0, pc}
|
||||||
bx lr
|
|
||||||
END(MEMCPY_BASE)
|
END(MEMCPY_BASE)
|
||||||
|
|||||||
@@ -69,10 +69,7 @@ END(bzero)
|
|||||||
|
|
||||||
/* memset() returns its first argument. */
|
/* memset() returns its first argument. */
|
||||||
ENTRY(memset)
|
ENTRY(memset)
|
||||||
stmfd sp!, {r0}
|
mov r3, r0
|
||||||
.cfi_def_cfa_offset 4
|
|
||||||
.cfi_rel_offset r0, 0
|
|
||||||
|
|
||||||
vdup.8 q0, r1
|
vdup.8 q0, r1
|
||||||
|
|
||||||
/* make sure we have at least 32 bytes to write */
|
/* make sure we have at least 32 bytes to write */
|
||||||
@@ -82,7 +79,7 @@ ENTRY(memset)
|
|||||||
|
|
||||||
1: /* The main loop writes 32 bytes at a time */
|
1: /* The main loop writes 32 bytes at a time */
|
||||||
subs r2, r2, #32
|
subs r2, r2, #32
|
||||||
vst1.8 {d0 - d3}, [r0]!
|
vst1.8 {d0 - d3}, [r3]!
|
||||||
bhs 1b
|
bhs 1b
|
||||||
|
|
||||||
2: /* less than 32 left */
|
2: /* less than 32 left */
|
||||||
@@ -91,18 +88,17 @@ ENTRY(memset)
|
|||||||
beq 3f
|
beq 3f
|
||||||
|
|
||||||
// writes 16 bytes, 128-bits aligned
|
// writes 16 bytes, 128-bits aligned
|
||||||
vst1.8 {d0, d1}, [r0]!
|
vst1.8 {d0, d1}, [r3]!
|
||||||
3: /* write up to 15-bytes (count in r2) */
|
3: /* write up to 15-bytes (count in r2) */
|
||||||
movs ip, r2, lsl #29
|
movs ip, r2, lsl #29
|
||||||
bcc 1f
|
bcc 1f
|
||||||
vst1.8 {d0}, [r0]!
|
vst1.8 {d0}, [r3]!
|
||||||
1: bge 2f
|
1: bge 2f
|
||||||
vst1.32 {d0[0]}, [r0]!
|
vst1.32 {d0[0]}, [r3]!
|
||||||
2: movs ip, r2, lsl #31
|
2: movs ip, r2, lsl #31
|
||||||
strbmi r1, [r0], #1
|
strbmi r1, [r3], #1
|
||||||
strbcs r1, [r0], #1
|
strbcs r1, [r3], #1
|
||||||
strbcs r1, [r0], #1
|
strbcs r1, [r3], #1
|
||||||
ldmfd sp!, {r0}
|
|
||||||
bx lr
|
bx lr
|
||||||
END(memset)
|
END(memset)
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/* Generated by gensyscalls.py. Do not edit. */
|
|
||||||
|
|
||||||
#include <private/bionic_asm.h>
|
|
||||||
|
|
||||||
ENTRY(vfork)
|
|
||||||
mov ip, r7
|
|
||||||
ldr r7, =__NR_vfork
|
|
||||||
swi #0
|
|
||||||
mov r7, ip
|
|
||||||
cmn r0, #(MAX_ERRNO + 1)
|
|
||||||
bxls lr
|
|
||||||
neg r0, r0
|
|
||||||
b __set_errno_internal
|
|
||||||
END(vfork)
|
|
||||||
@@ -31,6 +31,11 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
ENTRY(vfork)
|
ENTRY(vfork)
|
||||||
|
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
|
||||||
|
mrs x0, tpidr_el0
|
||||||
|
ldr x0, [x0, #8]
|
||||||
|
str wzr, [x0, #20]
|
||||||
|
|
||||||
mov x0, #(CLONE_VM | CLONE_VFORK | SIGCHLD)
|
mov x0, #(CLONE_VM | CLONE_VFORK | SIGCHLD)
|
||||||
mov x1, xzr
|
mov x1, xzr
|
||||||
mov x2, xzr
|
mov x2, xzr
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ ENTRY(vfork)
|
|||||||
.set noreorder
|
.set noreorder
|
||||||
.cpload t9
|
.cpload t9
|
||||||
|
|
||||||
|
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
|
||||||
|
.set push
|
||||||
|
.set mips32r2
|
||||||
|
rdhwr v0, $29 // v0 = tls; kernel trap on mips32r1
|
||||||
|
.set pop
|
||||||
|
lw v0, REGSZ*1(v0) // v0 = v0[TLS_SLOT_THREAD_ID ie 1]
|
||||||
|
sw $0, REGSZ*2+4(v0) // v0->cached_pid_ = 0
|
||||||
|
|
||||||
li a0, (CLONE_VM | CLONE_VFORK | SIGCHLD)
|
li a0, (CLONE_VM | CLONE_VFORK | SIGCHLD)
|
||||||
li a1, 0
|
li a1, 0
|
||||||
li a2, 0
|
li a2, 0
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ LEAF(vfork,FRAMESZ)
|
|||||||
PTR_SUBU sp, FRAMESZ
|
PTR_SUBU sp, FRAMESZ
|
||||||
#endif
|
#endif
|
||||||
SETUP_GP64(a5, vfork)
|
SETUP_GP64(a5, vfork)
|
||||||
|
|
||||||
|
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
|
||||||
|
rdhwr v0, $29 // v0 = tls
|
||||||
|
REG_L v0, REGSZ*1(v0) // v0 = v0[TLS_SLOT_THREAD_ID ie 1]
|
||||||
|
sw $0, REGSZ*2+4(v0) // v0->cached_pid_ = 0
|
||||||
|
|
||||||
LI a0, (CLONE_VM | CLONE_VFORK | SIGCHLD)
|
LI a0, (CLONE_VM | CLONE_VFORK | SIGCHLD)
|
||||||
move a1, $0
|
move a1, $0
|
||||||
move a2, $0
|
move a2, $0
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ ENTRY(vfork)
|
|||||||
popl %ecx // Grab the return address.
|
popl %ecx // Grab the return address.
|
||||||
.cfi_adjust_cfa_offset 4
|
.cfi_adjust_cfa_offset 4
|
||||||
.cfi_rel_offset ecx, 0
|
.cfi_rel_offset ecx, 0
|
||||||
|
|
||||||
|
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
|
||||||
|
movl %gs:0, %eax
|
||||||
|
movl 4(%eax), %eax
|
||||||
|
movl $0, 12(%eax)
|
||||||
|
|
||||||
movl $__NR_vfork, %eax
|
movl $__NR_vfork, %eax
|
||||||
int $0x80
|
int $0x80
|
||||||
cmpl $-MAX_ERRNO, %eax
|
cmpl $-MAX_ERRNO, %eax
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <private/bionic_asm.h>
|
#include <private/bionic_asm.h>
|
||||||
|
|
||||||
ENTRY(clock_gettime)
|
ENTRY(__clock_gettime)
|
||||||
pushl %ebx
|
pushl %ebx
|
||||||
.cfi_def_cfa_offset 8
|
.cfi_def_cfa_offset 8
|
||||||
.cfi_rel_offset ebx, 0
|
.cfi_rel_offset ebx, 0
|
||||||
@@ -23,4 +23,4 @@ ENTRY(clock_gettime)
|
|||||||
popl %ecx
|
popl %ecx
|
||||||
popl %ebx
|
popl %ebx
|
||||||
ret
|
ret
|
||||||
END(clock_gettime)
|
END(__clock_gettime)
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <private/bionic_asm.h>
|
#include <private/bionic_asm.h>
|
||||||
|
|
||||||
ENTRY(gettimeofday)
|
ENTRY(__gettimeofday)
|
||||||
pushl %ebx
|
pushl %ebx
|
||||||
.cfi_def_cfa_offset 8
|
.cfi_def_cfa_offset 8
|
||||||
.cfi_rel_offset ebx, 0
|
.cfi_rel_offset ebx, 0
|
||||||
@@ -23,4 +23,4 @@ ENTRY(gettimeofday)
|
|||||||
popl %ecx
|
popl %ecx
|
||||||
popl %ebx
|
popl %ebx
|
||||||
ret
|
ret
|
||||||
END(gettimeofday)
|
END(__gettimeofday)
|
||||||
@@ -32,6 +32,12 @@
|
|||||||
|
|
||||||
ENTRY(vfork)
|
ENTRY(vfork)
|
||||||
popq %rdi // Grab the return address.
|
popq %rdi // Grab the return address.
|
||||||
|
|
||||||
|
// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
|
||||||
|
mov %fs:0, %rax
|
||||||
|
mov 8(%rax), %rax
|
||||||
|
movl $0, 20(%rax)
|
||||||
|
|
||||||
movl $__NR_vfork, %eax
|
movl $__NR_vfork, %eax
|
||||||
syscall
|
syscall
|
||||||
pushq %rdi // Restore the return address.
|
pushq %rdi // Restore the return address.
|
||||||
|
|||||||
47
libc/bionic/__fread_chk.cpp
Normal file
47
libc/bionic/__fread_chk.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef _FORTIFY_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include "private/libc_logging.h"
|
||||||
|
|
||||||
|
extern "C" size_t __fread_chk(void * __restrict buf, size_t size, size_t count,
|
||||||
|
FILE * __restrict stream, size_t buf_size) {
|
||||||
|
size_t total;
|
||||||
|
if (__predict_false(__size_mul_overflow(size, count, &total))) {
|
||||||
|
// overflow: trigger the error path in fread
|
||||||
|
return fread(buf, size, count, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__predict_false(total > buf_size)) {
|
||||||
|
__fortify_chk_fail("fread: prevented write past end of buffer", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fread(buf, size, count, stream);
|
||||||
|
}
|
||||||
47
libc/bionic/__fwrite_chk.cpp
Normal file
47
libc/bionic/__fwrite_chk.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef _FORTIFY_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include "private/libc_logging.h"
|
||||||
|
|
||||||
|
extern "C" size_t __fwrite_chk(const void * __restrict buf, size_t size, size_t count,
|
||||||
|
FILE * __restrict stream, size_t buf_size) {
|
||||||
|
size_t total;
|
||||||
|
if (__predict_false(__size_mul_overflow(size, count, &total))) {
|
||||||
|
// overflow: trigger the error path in fwrite
|
||||||
|
return fwrite(buf, size, count, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__predict_false(total > buf_size)) {
|
||||||
|
__fortify_chk_fail("fwrite: prevented read past end of buffer", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fwrite(buf, size, count, stream);
|
||||||
|
}
|
||||||
40
libc/bionic/__getcwd_chk.cpp
Normal file
40
libc/bionic/__getcwd_chk.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef _FORTIFY_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "private/libc_logging.h"
|
||||||
|
|
||||||
|
extern char* __getcwd_chk(char* buf, size_t len, size_t buflen) {
|
||||||
|
if (__predict_false(len > buflen)) {
|
||||||
|
__fortify_chk_fail("getcwd: prevented write past end of buffer", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getcwd(buf, len);
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "private/bionic_lock.h"
|
||||||
#include "private/bionic_systrace.h"
|
#include "private/bionic_systrace.h"
|
||||||
#include "private/libc_logging.h"
|
#include "private/libc_logging.h"
|
||||||
|
|
||||||
@@ -29,12 +30,17 @@
|
|||||||
|
|
||||||
#define WRITE_OFFSET 32
|
#define WRITE_OFFSET 32
|
||||||
|
|
||||||
static const prop_info* g_pinfo = NULL;
|
constexpr char SYSTRACE_PROPERTY_NAME[] = "debug.atrace.tags.enableflags";
|
||||||
|
|
||||||
|
static Lock g_lock;
|
||||||
|
static const prop_info* g_pinfo;
|
||||||
static uint32_t g_serial = -1;
|
static uint32_t g_serial = -1;
|
||||||
static uint64_t g_tags = 0;
|
static uint64_t g_tags;
|
||||||
static int g_trace_marker_fd = -1;
|
static int g_trace_marker_fd = -1;
|
||||||
|
|
||||||
static bool should_trace() {
|
static bool should_trace() {
|
||||||
|
bool result = false;
|
||||||
|
g_lock.lock();
|
||||||
// If g_pinfo is null, this means that systrace hasn't been run and it's safe to
|
// If g_pinfo is null, this means that systrace hasn't been run and it's safe to
|
||||||
// assume that no trace writing will need to take place. However, to avoid running
|
// assume that no trace writing will need to take place. However, to avoid running
|
||||||
// this costly find check each time, we set it to a non-tracing value so that next
|
// this costly find check each time, we set it to a non-tracing value so that next
|
||||||
@@ -42,32 +48,39 @@ static bool should_trace() {
|
|||||||
// this function also deals with the bootup case, during which the call to property
|
// this function also deals with the bootup case, during which the call to property
|
||||||
// set will fail if the property server hasn't yet started.
|
// set will fail if the property server hasn't yet started.
|
||||||
if (g_pinfo == NULL) {
|
if (g_pinfo == NULL) {
|
||||||
g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
|
g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
|
||||||
if (g_pinfo == NULL) {
|
if (g_pinfo == NULL) {
|
||||||
__system_property_set("debug.atrace.tags.enableflags", "0");
|
__system_property_set(SYSTRACE_PROPERTY_NAME, "0");
|
||||||
g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
|
g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
|
||||||
if (g_pinfo == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (g_pinfo != NULL) {
|
||||||
|
|
||||||
// Find out which tags have been enabled on the command line and set
|
// Find out which tags have been enabled on the command line and set
|
||||||
// the value of tags accordingly. If the value of the property changes,
|
// the value of tags accordingly. If the value of the property changes,
|
||||||
// the serial will also change, so the costly system_property_read function
|
// the serial will also change, so the costly system_property_read function
|
||||||
// can be avoided by calling the much cheaper system_property_serial
|
// can be avoided by calling the much cheaper system_property_serial
|
||||||
// first. The values within pinfo may change, but its location is guaranteed
|
// first. The values within pinfo may change, but its location is guaranteed
|
||||||
// not to move.
|
// not to move.
|
||||||
const uint32_t cur_serial = __system_property_serial(g_pinfo);
|
uint32_t cur_serial = __system_property_serial(g_pinfo);
|
||||||
if (cur_serial != g_serial) {
|
if (cur_serial != g_serial) {
|
||||||
g_serial = cur_serial;
|
g_serial = cur_serial;
|
||||||
char value[PROP_VALUE_MAX];
|
char value[PROP_VALUE_MAX];
|
||||||
__system_property_read(g_pinfo, 0, value);
|
__system_property_read(g_pinfo, 0, value);
|
||||||
g_tags = strtoull(value, NULL, 0);
|
g_tags = strtoull(value, NULL, 0);
|
||||||
}
|
}
|
||||||
|
result = ((g_tags & ATRACE_TAG_BIONIC) != 0);
|
||||||
|
}
|
||||||
|
g_lock.unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, verify that this tag value enables bionic tracing.
|
static int get_trace_marker_fd() {
|
||||||
return ((g_tags & ATRACE_TAG_BIONIC) != 0);
|
g_lock.lock();
|
||||||
|
if (g_trace_marker_fd == -1) {
|
||||||
|
g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
|
||||||
|
}
|
||||||
|
g_lock.unlock();
|
||||||
|
return g_trace_marker_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedTrace::ScopedTrace(const char* message) {
|
ScopedTrace::ScopedTrace(const char* message) {
|
||||||
@@ -75,11 +88,9 @@ ScopedTrace::ScopedTrace(const char* message) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_trace_marker_fd == -1) {
|
int trace_marker_fd = get_trace_marker_fd();
|
||||||
g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
|
if (trace_marker_fd == -1) {
|
||||||
if (g_trace_marker_fd == -1) {
|
return;
|
||||||
__libc_fatal("Could not open kernel trace file: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If bionic tracing has been enabled, then write the message to the
|
// If bionic tracing has been enabled, then write the message to the
|
||||||
@@ -87,12 +98,10 @@ ScopedTrace::ScopedTrace(const char* message) {
|
|||||||
int length = strlen(message);
|
int length = strlen(message);
|
||||||
char buf[length + WRITE_OFFSET];
|
char buf[length + WRITE_OFFSET];
|
||||||
size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
|
size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
|
||||||
ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, buf, len));
|
|
||||||
|
|
||||||
// Error while writing
|
// Tracing may stop just after checking property and before writing the message.
|
||||||
if (static_cast<size_t>(wbytes) != len) {
|
// So the write is acceptable to fail. See b/20666100.
|
||||||
__libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
|
TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedTrace::~ScopedTrace() {
|
ScopedTrace::~ScopedTrace() {
|
||||||
@@ -100,10 +109,10 @@ ScopedTrace::~ScopedTrace() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, "E", 1));
|
int trace_marker_fd = get_trace_marker_fd();
|
||||||
|
if (trace_marker_fd == -1) {
|
||||||
// Error while writing
|
return;
|
||||||
if (static_cast<size_t>(wbytes) != 1) {
|
|
||||||
__libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEMP_FAILURE_RETRY(write(trace_marker_fd, "E", 1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <elf.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -35,14 +36,22 @@
|
|||||||
#include "debug_mapinfo.h"
|
#include "debug_mapinfo.h"
|
||||||
#include "malloc_debug_disable.h"
|
#include "malloc_debug_disable.h"
|
||||||
|
|
||||||
|
#if defined(__LP64__)
|
||||||
|
#define Elf_W(x) Elf64_##x
|
||||||
|
#else
|
||||||
|
#define Elf_W(x) Elf32_##x
|
||||||
|
#endif
|
||||||
|
|
||||||
// Format of /proc/<PID>/maps:
|
// Format of /proc/<PID>/maps:
|
||||||
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
|
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
|
||||||
static mapinfo_t* parse_maps_line(char* line) {
|
static mapinfo_t* parse_maps_line(char* line) {
|
||||||
uintptr_t start;
|
uintptr_t start;
|
||||||
uintptr_t end;
|
uintptr_t end;
|
||||||
|
uintptr_t offset;
|
||||||
|
char permissions[4];
|
||||||
int name_pos;
|
int name_pos;
|
||||||
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start,
|
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
|
||||||
&end, &name_pos) < 2) {
|
&end, permissions, &offset, &name_pos) < 2) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +68,14 @@ static mapinfo_t* parse_maps_line(char* line) {
|
|||||||
if (mi) {
|
if (mi) {
|
||||||
mi->start = start;
|
mi->start = start;
|
||||||
mi->end = end;
|
mi->end = end;
|
||||||
|
mi->offset = offset;
|
||||||
|
if (permissions[0] != 'r') {
|
||||||
|
// Any unreadable map will just get a zero load base.
|
||||||
|
mi->load_base = 0;
|
||||||
|
mi->load_base_read = true;
|
||||||
|
} else {
|
||||||
|
mi->load_base_read = false;
|
||||||
|
}
|
||||||
memcpy(mi->name, name, name_len);
|
memcpy(mi->name, name, name_len);
|
||||||
mi->name[name_len] = '\0';
|
mi->name[name_len] = '\0';
|
||||||
}
|
}
|
||||||
@@ -95,11 +112,58 @@ __LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline bool get_val(mapinfo_t* mi, uintptr_t addr, T* store) {
|
||||||
|
if (addr < mi->start || addr + sizeof(T) > mi->end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Make sure the address is aligned properly.
|
||||||
|
if (addr & (sizeof(T)-1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*store = *reinterpret_cast<T*>(addr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ void mapinfo_read_loadbase(mapinfo_t* mi) {
|
||||||
|
mi->load_base = 0;
|
||||||
|
mi->load_base_read = true;
|
||||||
|
uintptr_t addr = mi->start;
|
||||||
|
Elf_W(Ehdr) ehdr;
|
||||||
|
if (!get_val<Elf_W(Half)>(mi, addr + offsetof(Elf_W(Ehdr), e_phnum), &ehdr.e_phnum)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Ehdr), e_phoff), &ehdr.e_phoff)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr += ehdr.e_phoff;
|
||||||
|
for (size_t i = 0; i < ehdr.e_phnum; i++) {
|
||||||
|
Elf_W(Phdr) phdr;
|
||||||
|
if (!get_val<Elf_W(Word)>(mi, addr + offsetof(Elf_W(Phdr), p_type), &phdr.p_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Phdr), p_offset), &phdr.p_offset)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (phdr.p_type == PT_LOAD && phdr.p_offset == mi->offset) {
|
||||||
|
if (!get_val<Elf_W(Addr)>(mi, addr + offsetof(Elf_W(Phdr), p_vaddr), &phdr.p_vaddr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mi->load_base = phdr.p_vaddr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr += sizeof(phdr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the containing map info for the PC.
|
// Find the containing map info for the PC.
|
||||||
__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) {
|
__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) {
|
||||||
for (; mi != NULL; mi = mi->next) {
|
for (; mi != NULL; mi = mi->next) {
|
||||||
if ((pc >= mi->start) && (pc < mi->end)) {
|
if ((pc >= mi->start) && (pc < mi->end)) {
|
||||||
*rel_pc = pc - mi->start;
|
if (!mi->load_base_read) {
|
||||||
|
mapinfo_read_loadbase(mi);
|
||||||
|
}
|
||||||
|
*rel_pc = pc - mi->start + mi->load_base;
|
||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ struct mapinfo_t {
|
|||||||
struct mapinfo_t* next;
|
struct mapinfo_t* next;
|
||||||
uintptr_t start;
|
uintptr_t start;
|
||||||
uintptr_t end;
|
uintptr_t end;
|
||||||
|
uintptr_t offset;
|
||||||
|
uintptr_t load_base;
|
||||||
|
bool load_base_read;
|
||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#undef _FORTIFY_SOURCE
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|||||||
@@ -64,18 +64,15 @@ char** environ;
|
|||||||
// Declared in "private/bionic_ssp.h".
|
// Declared in "private/bionic_ssp.h".
|
||||||
uintptr_t __stack_chk_guard = 0;
|
uintptr_t __stack_chk_guard = 0;
|
||||||
|
|
||||||
/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped
|
// Setup for the main thread. For dynamic executables, this is called by the
|
||||||
* in memory. Beware: all writes to libc globals from this function will
|
// linker _before_ libc is mapped in memory. This means that all writes to
|
||||||
* apply to linker-private copies and will not be visible from libc later on.
|
// globals from this function will apply to linker-private copies and will not
|
||||||
*
|
// be visible from libc later on.
|
||||||
* Note: this function creates a pthread_internal_t for the initial thread and
|
//
|
||||||
* stores the pointer in TLS, but does not add it to pthread's thread list. This
|
// Note: this function creates a pthread_internal_t for the initial thread and
|
||||||
* has to be done later from libc itself (see __libc_init_common).
|
// stores the pointer in TLS, but does not add it to pthread's thread list. This
|
||||||
*
|
// has to be done later from libc itself (see __libc_init_common).
|
||||||
* This function also stores a pointer to the kernel argument block in a TLS slot to be
|
void __libc_init_main_thread(KernelArgumentBlock& args) {
|
||||||
* picked up by the libc constructor.
|
|
||||||
*/
|
|
||||||
void __libc_init_tls(KernelArgumentBlock& args) {
|
|
||||||
__libc_auxv = args.auxv;
|
__libc_auxv = args.auxv;
|
||||||
|
|
||||||
static pthread_internal_t main_thread;
|
static pthread_internal_t main_thread;
|
||||||
@@ -99,6 +96,9 @@ void __libc_init_tls(KernelArgumentBlock& args) {
|
|||||||
__init_thread(&main_thread);
|
__init_thread(&main_thread);
|
||||||
__init_tls(&main_thread);
|
__init_tls(&main_thread);
|
||||||
__set_tls(main_thread.tls);
|
__set_tls(main_thread.tls);
|
||||||
|
|
||||||
|
// Store a pointer to the kernel argument block in a TLS slot to be
|
||||||
|
// picked up by the libc constructor.
|
||||||
main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
|
main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
|
||||||
|
|
||||||
__init_alternate_signal_stack(&main_thread);
|
__init_alternate_signal_stack(&main_thread);
|
||||||
|
|||||||
@@ -49,16 +49,10 @@
|
|||||||
#include "libc_init_common.h"
|
#include "libc_init_common.h"
|
||||||
#include "pthread_internal.h"
|
#include "pthread_internal.h"
|
||||||
|
|
||||||
|
#include "private/bionic_page.h"
|
||||||
#include "private/bionic_tls.h"
|
#include "private/bionic_tls.h"
|
||||||
#include "private/KernelArgumentBlock.h"
|
#include "private/KernelArgumentBlock.h"
|
||||||
|
|
||||||
// Returns the address of the page containing address 'x'.
|
|
||||||
#define PAGE_START(x) ((x) & PAGE_MASK)
|
|
||||||
|
|
||||||
// Returns the address of the next page after address 'x', unless 'x' is
|
|
||||||
// itself at the start of a page.
|
|
||||||
#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
|
|
||||||
|
|
||||||
extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
|
extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
|
||||||
|
|
||||||
static void call_array(void(**list)()) {
|
static void call_array(void(**list)()) {
|
||||||
@@ -90,7 +84,7 @@ __noreturn void __libc_init(void* raw_args,
|
|||||||
int (*slingshot)(int, char**, char**),
|
int (*slingshot)(int, char**, char**),
|
||||||
structors_array_t const * const structors) {
|
structors_array_t const * const structors) {
|
||||||
KernelArgumentBlock args(raw_args);
|
KernelArgumentBlock args(raw_args);
|
||||||
__libc_init_tls(args);
|
__libc_init_main_thread(args);
|
||||||
__libc_init_AT_SECURE(args);
|
__libc_init_AT_SECURE(args);
|
||||||
__libc_init_common(args);
|
__libc_init_common(args);
|
||||||
|
|
||||||
|
|||||||
@@ -448,7 +448,6 @@ static int __libc_write_stderr(const char* tag, const char* msg) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_USES_LOGD
|
|
||||||
static int __libc_open_log_socket() {
|
static int __libc_open_log_socket() {
|
||||||
// ToDo: Ideally we want this to fail if the gid of the current
|
// ToDo: Ideally we want this to fail if the gid of the current
|
||||||
// process is AID_LOGD, but will have to wait until we have
|
// process is AID_LOGD, but will have to wait until we have
|
||||||
@@ -486,10 +485,8 @@ struct log_time { // Wire format
|
|||||||
uint32_t tv_sec;
|
uint32_t tv_sec;
|
||||||
uint32_t tv_nsec;
|
uint32_t tv_nsec;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
static int __libc_write_log(int priority, const char* tag, const char* msg) {
|
static int __libc_write_log(int priority, const char* tag, const char* msg) {
|
||||||
#ifdef TARGET_USES_LOGD
|
|
||||||
int main_log_fd = __libc_open_log_socket();
|
int main_log_fd = __libc_open_log_socket();
|
||||||
if (main_log_fd == -1) {
|
if (main_log_fd == -1) {
|
||||||
// Try stderr instead.
|
// Try stderr instead.
|
||||||
@@ -517,24 +514,6 @@ static int __libc_write_log(int priority, const char* tag, const char* msg) {
|
|||||||
vec[4].iov_len = strlen(tag) + 1;
|
vec[4].iov_len = strlen(tag) + 1;
|
||||||
vec[5].iov_base = const_cast<char*>(msg);
|
vec[5].iov_base = const_cast<char*>(msg);
|
||||||
vec[5].iov_len = strlen(msg) + 1;
|
vec[5].iov_len = strlen(msg) + 1;
|
||||||
#else
|
|
||||||
int main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
|
|
||||||
if (main_log_fd == -1) {
|
|
||||||
if (errno == ENOTDIR) {
|
|
||||||
// /dev/log isn't a directory? Maybe we're running on the host? Try stderr instead.
|
|
||||||
return __libc_write_stderr(tag, msg);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
iovec vec[3];
|
|
||||||
vec[0].iov_base = &priority;
|
|
||||||
vec[0].iov_len = 1;
|
|
||||||
vec[1].iov_base = const_cast<char*>(tag);
|
|
||||||
vec[1].iov_len = strlen(tag) + 1;
|
|
||||||
vec[2].iov_base = const_cast<char*>(msg);
|
|
||||||
vec[2].iov_len = strlen(msg) + 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
|
int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
|
||||||
close(main_log_fd);
|
close(main_log_fd);
|
||||||
@@ -557,7 +536,6 @@ int __libc_format_log(int priority, const char* tag, const char* format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
|
static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
|
||||||
#ifdef TARGET_USES_LOGD
|
|
||||||
iovec vec[6];
|
iovec vec[6];
|
||||||
char log_id = LOG_ID_EVENTS;
|
char log_id = LOG_ID_EVENTS;
|
||||||
vec[0].iov_base = &log_id;
|
vec[0].iov_base = &log_id;
|
||||||
@@ -581,17 +559,6 @@ static int __libc_android_log_event(int32_t tag, char type, const void* payload,
|
|||||||
vec[5].iov_len = len;
|
vec[5].iov_len = len;
|
||||||
|
|
||||||
int event_log_fd = __libc_open_log_socket();
|
int event_log_fd = __libc_open_log_socket();
|
||||||
#else
|
|
||||||
iovec vec[3];
|
|
||||||
vec[0].iov_base = &tag;
|
|
||||||
vec[0].iov_len = sizeof(tag);
|
|
||||||
vec[1].iov_base = &type;
|
|
||||||
vec[1].iov_len = sizeof(type);
|
|
||||||
vec[2].iov_base = const_cast<void*>(payload);
|
|
||||||
vec[2].iov_len = len;
|
|
||||||
|
|
||||||
int event_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/events", O_CLOEXEC | O_WRONLY));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (event_log_fd == -1) {
|
if (event_log_fd == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
static ThreadLocalBuffer<char, MAXPATHLEN> g_basename_tls_buffer;
|
static ThreadLocalBuffer<char, MAXPATHLEN> g_basename_tls_buffer;
|
||||||
static ThreadLocalBuffer<char, MAXPATHLEN> g_dirname_tls_buffer;
|
static ThreadLocalBuffer<char, MAXPATHLEN> g_dirname_tls_buffer;
|
||||||
|
|
||||||
__LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
|
static int __basename_r(const char* path, char* buffer, size_t buffer_size) {
|
||||||
const char* startp = NULL;
|
const char* startp = NULL;
|
||||||
const char* endp = NULL;
|
const char* endp = NULL;
|
||||||
int len;
|
int len;
|
||||||
@@ -91,7 +91,12 @@ __LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_s
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
__LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_size) {
|
// Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable.
|
||||||
|
__LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
|
||||||
|
return __basename_r(path, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __dirname_r(const char* path, char* buffer, size_t buffer_size) {
|
||||||
const char* endp = NULL;
|
const char* endp = NULL;
|
||||||
int len;
|
int len;
|
||||||
int result;
|
int result;
|
||||||
@@ -150,14 +155,19 @@ __LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_si
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable.
|
||||||
|
__LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_size) {
|
||||||
|
return __dirname_r(path, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
char* basename(const char* path) {
|
char* basename(const char* path) {
|
||||||
char* buf = g_basename_tls_buffer.get();
|
char* buf = g_basename_tls_buffer.get();
|
||||||
int rc = basename_r(path, buf, g_basename_tls_buffer.size());
|
int rc = __basename_r(path, buf, g_basename_tls_buffer.size());
|
||||||
return (rc < 0) ? NULL : buf;
|
return (rc < 0) ? NULL : buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* dirname(const char* path) {
|
char* dirname(const char* path) {
|
||||||
char* buf = g_dirname_tls_buffer.get();
|
char* buf = g_dirname_tls_buffer.get();
|
||||||
int rc = dirname_r(path, buf, g_dirname_tls_buffer.size());
|
int rc = __dirname_r(path, buf, g_dirname_tls_buffer.size());
|
||||||
return (rc < 0) ? NULL : buf;
|
return (rc < 0) ? NULL : buf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,8 +133,9 @@ static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size
|
|||||||
size |= SIZE_FLAG_ZYGOTE_CHILD;
|
size |= SIZE_FLAG_ZYGOTE_CHILD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the lock held for as little time as possible to prevent deadlocks.
|
||||||
|
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
||||||
HashEntry* entry = find_entry(g_hash_table, slot, backtrace, numEntries, size);
|
HashEntry* entry = find_entry(g_hash_table, slot, backtrace, numEntries, size);
|
||||||
|
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
entry->allocations++;
|
entry->allocations++;
|
||||||
} else {
|
} else {
|
||||||
@@ -302,8 +303,6 @@ extern "C" void* leak_malloc(size_t bytes) {
|
|||||||
|
|
||||||
void* base = g_malloc_dispatch->malloc(size);
|
void* base = g_malloc_dispatch->malloc(size);
|
||||||
if (base != NULL) {
|
if (base != NULL) {
|
||||||
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
|
||||||
|
|
||||||
uintptr_t backtrace[BACKTRACE_SIZE];
|
uintptr_t backtrace[BACKTRACE_SIZE];
|
||||||
size_t numEntries = GET_BACKTRACE(backtrace, BACKTRACE_SIZE);
|
size_t numEntries = GET_BACKTRACE(backtrace, BACKTRACE_SIZE);
|
||||||
|
|
||||||
@@ -328,8 +327,6 @@ extern "C" void leak_free(void* mem) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
|
||||||
|
|
||||||
// check the guard to make sure it is valid
|
// check the guard to make sure it is valid
|
||||||
AllocationEntry* header = to_header(mem);
|
AllocationEntry* header = to_header(mem);
|
||||||
|
|
||||||
@@ -342,6 +339,7 @@ extern "C" void leak_free(void* mem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
||||||
if (header->guard == GUARD || is_valid_entry(header->entry)) {
|
if (header->guard == GUARD || is_valid_entry(header->entry)) {
|
||||||
// decrement the allocations
|
// decrement the allocations
|
||||||
HashEntry* entry = header->entry;
|
HashEntry* entry = header->entry;
|
||||||
|
|||||||
@@ -612,7 +612,7 @@ extern "C" bool malloc_debug_initialize(HashTable*, const MallocDebug* malloc_di
|
|||||||
error_log("Unable to open /dev/qemu_trace");
|
error_log("Unable to open /dev/qemu_trace");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
qtrace = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (qtrace == MAP_FAILED) {
|
if (qtrace == MAP_FAILED) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "private/android_filesystem_config.h"
|
#include "private/android_filesystem_config.h"
|
||||||
|
#include "private/bionic_macros.h"
|
||||||
#include "private/ErrnoRestorer.h"
|
#include "private/ErrnoRestorer.h"
|
||||||
#include "private/libc_logging.h"
|
#include "private/libc_logging.h"
|
||||||
#include "private/ThreadLocalBuffer.h"
|
#include "private/ThreadLocalBuffer.h"
|
||||||
@@ -66,11 +67,15 @@ struct passwd_state_t {
|
|||||||
static ThreadLocalBuffer<group_state_t> g_group_tls_buffer;
|
static ThreadLocalBuffer<group_state_t> g_group_tls_buffer;
|
||||||
static ThreadLocalBuffer<passwd_state_t> g_passwd_tls_buffer;
|
static ThreadLocalBuffer<passwd_state_t> g_passwd_tls_buffer;
|
||||||
|
|
||||||
|
static void init_group_state(group_state_t* state) {
|
||||||
|
memset(state, 0, sizeof(group_state_t));
|
||||||
|
state->group_.gr_mem = state->group_members_;
|
||||||
|
}
|
||||||
|
|
||||||
static group_state_t* __group_state() {
|
static group_state_t* __group_state() {
|
||||||
group_state_t* result = g_group_tls_buffer.get();
|
group_state_t* result = g_group_tls_buffer.get();
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
memset(result, 0, sizeof(group_state_t));
|
init_group_state(result);
|
||||||
result->group_.gr_mem = result->group_members_;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -397,17 +402,28 @@ char* getlogin() { // NOLINT: implementing bad function.
|
|||||||
return (pw != NULL) ? pw->pw_name : NULL;
|
return (pw != NULL) ? pw->pw_name : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static group* getgrgid_internal(gid_t gid, group_state_t* state) {
|
||||||
|
group* grp = android_id_to_group(state, gid);
|
||||||
|
if (grp != NULL) {
|
||||||
|
return grp;
|
||||||
|
}
|
||||||
|
return app_id_to_group(gid, state);
|
||||||
|
}
|
||||||
|
|
||||||
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
|
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
|
||||||
group_state_t* state = __group_state();
|
group_state_t* state = __group_state();
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
return getgrgid_internal(gid, state);
|
||||||
|
}
|
||||||
|
|
||||||
group* gr = android_id_to_group(state, gid);
|
static group* getgrnam_internal(const char* name, group_state_t* state) {
|
||||||
if (gr != NULL) {
|
group* grp = android_name_to_group(state, name);
|
||||||
return gr;
|
if (grp != NULL) {
|
||||||
|
return grp;
|
||||||
}
|
}
|
||||||
return app_id_to_group(gid, state);
|
return app_id_to_group(app_id_from_name(name, true), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
||||||
@@ -415,11 +431,36 @@ group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
|||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
return getgrnam_internal(name, state);
|
||||||
|
}
|
||||||
|
|
||||||
if (android_name_to_group(state, name) != 0) {
|
static int getgroup_r(bool by_name, const char* name, gid_t gid, struct group* grp, char* buf,
|
||||||
return &state->group_;
|
size_t buflen, struct group** result) {
|
||||||
|
ErrnoRestorer errno_restorer;
|
||||||
|
*result = NULL;
|
||||||
|
char* p = reinterpret_cast<char*>(
|
||||||
|
BIONIC_ALIGN(reinterpret_cast<uintptr_t>(buf), sizeof(uintptr_t)));
|
||||||
|
if (p + sizeof(group_state_t) > buf + buflen) {
|
||||||
|
return ERANGE;
|
||||||
}
|
}
|
||||||
return app_id_to_group(app_id_from_name(name, true), state);
|
group_state_t* state = reinterpret_cast<group_state_t*>(p);
|
||||||
|
init_group_state(state);
|
||||||
|
group* retval = (by_name ? getgrnam_internal(name, state) : getgrgid_internal(gid, state));
|
||||||
|
if (retval != NULL) {
|
||||||
|
*grp = *retval;
|
||||||
|
*result = grp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) {
|
||||||
|
return getgroup_r(false, NULL, gid, grp, buf, buflen, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getgrnam_r(const char* name, struct group* grp, char* buf, size_t buflen,
|
||||||
|
struct group **result) {
|
||||||
|
return getgroup_r(true, name, 0, grp, buf, buflen, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have an /etc/networks, so all inputs return NULL.
|
// We don't have an /etc/networks, so all inputs return NULL.
|
||||||
|
|||||||
@@ -97,8 +97,11 @@ long sysconf(int name) {
|
|||||||
case _SC_ATEXIT_MAX: return LONG_MAX; // Unlimited.
|
case _SC_ATEXIT_MAX: return LONG_MAX; // Unlimited.
|
||||||
case _SC_IOV_MAX: return UIO_MAXIOV;
|
case _SC_IOV_MAX: return UIO_MAXIOV;
|
||||||
|
|
||||||
case _SC_PAGESIZE: // Fall through, PAGESIZE and PAGE_SIZE always hold the same value.
|
// _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
|
||||||
case _SC_PAGE_SIZE: return PAGE_SIZE;
|
case _SC_PAGESIZE:
|
||||||
|
case _SC_PAGE_SIZE:
|
||||||
|
return static_cast<long>(getauxval(AT_PAGESZ));
|
||||||
|
|
||||||
case _SC_XOPEN_UNIX: return _XOPEN_UNIX;
|
case _SC_XOPEN_UNIX: return _XOPEN_UNIX;
|
||||||
case _SC_AIO_LISTIO_MAX: return _POSIX_AIO_LISTIO_MAX; // Minimum requirement.
|
case _SC_AIO_LISTIO_MAX: return _POSIX_AIO_LISTIO_MAX; // Minimum requirement.
|
||||||
case _SC_AIO_MAX: return _POSIX_AIO_MAX; // Minimum requirement.
|
case _SC_AIO_MAX: return _POSIX_AIO_MAX; // Minimum requirement.
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "private/ScopedReaddir.h"
|
#include "private/ScopedReaddir.h"
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ static int __get_meminfo_page_count(const char* pattern) {
|
|||||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||||
long total;
|
long total;
|
||||||
if (sscanf(buf, pattern, &total) == 1) {
|
if (sscanf(buf, pattern, &total) == 1) {
|
||||||
page_count = static_cast<int>(total / (PAGE_SIZE / 1024));
|
page_count = static_cast<int>(total / (sysconf(_SC_PAGE_SIZE) / 1024));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,19 +19,24 @@
|
|||||||
#include <sys/auxv.h>
|
#include <sys/auxv.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// x86 has a vdso, but there's nothing useful to us in it.
|
#if defined(__aarch64__) || defined(__x86_64__) || defined (__i386__)
|
||||||
#if defined(__aarch64__) || defined(__x86_64__)
|
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
|
#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
|
||||||
#define VDSO_GETTIMEOFDAY_SYMBOL "__kernel_gettimeofday"
|
#define VDSO_GETTIMEOFDAY_SYMBOL "__kernel_gettimeofday"
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__) || defined(__i386__)
|
||||||
#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
|
#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
|
||||||
#define VDSO_GETTIMEOFDAY_SYMBOL "__vdso_gettimeofday"
|
#define VDSO_GETTIMEOFDAY_SYMBOL "__vdso_gettimeofday"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "private/bionic_prctl.h"
|
||||||
|
#include "private/libc_logging.h"
|
||||||
|
|
||||||
extern "C" int __clock_gettime(int, timespec*);
|
extern "C" int __clock_gettime(int, timespec*);
|
||||||
extern "C" int __gettimeofday(timeval*, struct timezone*);
|
extern "C" int __gettimeofday(timeval*, struct timezone*);
|
||||||
|
|
||||||
@@ -46,28 +51,31 @@ enum {
|
|||||||
VDSO_END
|
VDSO_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static vdso_entry vdso_entries[] = {
|
static union {
|
||||||
|
vdso_entry entries[VDSO_END];
|
||||||
|
char padding[PAGE_SIZE];
|
||||||
|
} vdso __attribute__((aligned(PAGE_SIZE))) = {{
|
||||||
[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast<void*>(__clock_gettime) },
|
[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast<void*>(__clock_gettime) },
|
||||||
[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) },
|
[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) },
|
||||||
};
|
}};
|
||||||
|
|
||||||
int clock_gettime(int clock_id, timespec* tp) {
|
int clock_gettime(int clock_id, timespec* tp) {
|
||||||
static int (*vdso_clock_gettime)(int, timespec*) =
|
int (*vdso_clock_gettime)(int, timespec*) =
|
||||||
reinterpret_cast<int (*)(int, timespec*)>(vdso_entries[VDSO_CLOCK_GETTIME].fn);
|
reinterpret_cast<int (*)(int, timespec*)>(vdso.entries[VDSO_CLOCK_GETTIME].fn);
|
||||||
return vdso_clock_gettime(clock_id, tp);
|
return vdso_clock_gettime(clock_id, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gettimeofday(timeval* tv, struct timezone* tz) {
|
int gettimeofday(timeval* tv, struct timezone* tz) {
|
||||||
static int (*vdso_gettimeofday)(timeval*, struct timezone*) =
|
int (*vdso_gettimeofday)(timeval*, struct timezone*) =
|
||||||
reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso_entries[VDSO_GETTIMEOFDAY].fn);
|
reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso.entries[VDSO_GETTIMEOFDAY].fn);
|
||||||
return vdso_gettimeofday(tv, tz);
|
return vdso_gettimeofday(tv, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __libc_init_vdso() {
|
static void __libc_init_vdso_entries() {
|
||||||
// Do we have a vdso?
|
// Do we have a vdso?
|
||||||
uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
|
uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
|
||||||
ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
|
ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
|
||||||
if (vdso_ehdr == NULL) {
|
if (vdso_ehdr == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +93,7 @@ void __libc_init_vdso() {
|
|||||||
|
|
||||||
// Where's the dynamic table?
|
// Where's the dynamic table?
|
||||||
ElfW(Addr) vdso_addr = 0;
|
ElfW(Addr) vdso_addr = 0;
|
||||||
ElfW(Dyn)* vdso_dyn = NULL;
|
ElfW(Dyn)* vdso_dyn = nullptr;
|
||||||
ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff);
|
ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff);
|
||||||
for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) {
|
for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) {
|
||||||
if (vdso_phdr[i].p_type == PT_DYNAMIC) {
|
if (vdso_phdr[i].p_type == PT_DYNAMIC) {
|
||||||
@@ -94,13 +102,13 @@ void __libc_init_vdso() {
|
|||||||
vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr;
|
vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vdso_addr == 0 || vdso_dyn == NULL) {
|
if (vdso_addr == 0 || vdso_dyn == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where are the string and symbol tables?
|
// Where are the string and symbol tables?
|
||||||
const char* strtab = NULL;
|
const char* strtab = nullptr;
|
||||||
ElfW(Sym)* symtab = NULL;
|
ElfW(Sym)* symtab = nullptr;
|
||||||
for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) {
|
for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) {
|
||||||
if (d->d_tag == DT_STRTAB) {
|
if (d->d_tag == DT_STRTAB) {
|
||||||
strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr);
|
strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr);
|
||||||
@@ -108,20 +116,31 @@ void __libc_init_vdso() {
|
|||||||
symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr);
|
symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strtab == NULL || symtab == NULL) {
|
if (strtab == nullptr || symtab == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are there any symbols we want?
|
// Are there any symbols we want?
|
||||||
for (size_t i = 0; i < symbol_count; ++i) {
|
for (size_t i = 0; i < symbol_count; ++i) {
|
||||||
for (size_t j = 0; j < VDSO_END; ++j) {
|
for (size_t j = 0; j < VDSO_END; ++j) {
|
||||||
if (strcmp(vdso_entries[j].name, strtab + symtab[i].st_name) == 0) {
|
if (strcmp(vdso.entries[j].name, strtab + symtab[i].st_name) == 0) {
|
||||||
vdso_entries[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
|
vdso.entries[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __libc_init_vdso() {
|
||||||
|
__libc_init_vdso_entries();
|
||||||
|
|
||||||
|
// We can't use PR_SET_VMA because this isn't an anonymous region.
|
||||||
|
// Long-term we should be able to replace all of this with ifuncs.
|
||||||
|
static_assert(PAGE_SIZE == sizeof(vdso), "sizeof(vdso) too large");
|
||||||
|
if (mprotect(vdso.entries, sizeof(vdso), PROT_READ) == -1) {
|
||||||
|
__libc_fatal("failed to mprotect PROT_READ vdso function pointer table: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void __libc_init_vdso() {
|
void __libc_init_vdso() {
|
||||||
|
|||||||
@@ -81,17 +81,6 @@
|
|||||||
|
|
||||||
#define MB_LEN_MAX 4
|
#define MB_LEN_MAX 4
|
||||||
|
|
||||||
/* New code should use sysconf(_SC_PAGE_SIZE) instead. */
|
|
||||||
#ifndef PAGE_SIZE
|
|
||||||
#define PAGE_SIZE 4096
|
|
||||||
#endif
|
|
||||||
#ifndef PAGESIZE
|
|
||||||
#define PAGESIZE PAGE_SIZE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* glibc's PAGE_MASK is the bitwise negation of BSD's! TODO: remove? */
|
|
||||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
|
||||||
|
|
||||||
#define SEM_VALUE_MAX 0x3fffffff
|
#define SEM_VALUE_MAX 0x3fffffff
|
||||||
|
|
||||||
/* POSIX says these belong in <unistd.h> but BSD has some in <limits.h>. */
|
/* POSIX says these belong in <unistd.h> but BSD has some in <limits.h>. */
|
||||||
|
|||||||
@@ -382,6 +382,16 @@ extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
|
|||||||
__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
|
__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
|
||||||
__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
|
__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
|
||||||
|
|
||||||
|
extern size_t __fread_chk(void * __restrict, size_t, size_t, FILE * __restrict, size_t);
|
||||||
|
extern size_t __fread_real(void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fread);
|
||||||
|
__errordecl(__fread_too_big_error, "fread called with size * count bigger than buffer");
|
||||||
|
__errordecl(__fread_overflow, "fread called with overflowing size * count");
|
||||||
|
|
||||||
|
extern size_t __fwrite_chk(const void * __restrict, size_t, size_t, FILE * __restrict, size_t);
|
||||||
|
extern size_t __fwrite_real(const void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fwrite);
|
||||||
|
__errordecl(__fwrite_too_big_error, "fwrite called with size * count bigger than buffer");
|
||||||
|
__errordecl(__fwrite_overflow, "fwrite called with overflowing size * count");
|
||||||
|
|
||||||
#if defined(__BIONIC_FORTIFY)
|
#if defined(__BIONIC_FORTIFY)
|
||||||
|
|
||||||
__BIONIC_FORTIFY_INLINE
|
__BIONIC_FORTIFY_INLINE
|
||||||
@@ -428,6 +438,58 @@ int sprintf(char *dest, const char *format, ...)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
__BIONIC_FORTIFY_INLINE
|
||||||
|
size_t fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
|
||||||
|
size_t bos = __bos0(buf);
|
||||||
|
|
||||||
|
#if !defined(__clang__)
|
||||||
|
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
|
||||||
|
return __fread_real(buf, size, count, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
|
||||||
|
size_t total;
|
||||||
|
if (__size_mul_overflow(size, count, &total)) {
|
||||||
|
__fread_overflow();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total > bos) {
|
||||||
|
__fread_too_big_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __fread_real(buf, size, count, stream);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return __fread_chk(buf, size, count, stream, bos);
|
||||||
|
}
|
||||||
|
|
||||||
|
__BIONIC_FORTIFY_INLINE
|
||||||
|
size_t fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
|
||||||
|
size_t bos = __bos0(buf);
|
||||||
|
|
||||||
|
#if !defined(__clang__)
|
||||||
|
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
|
||||||
|
return __fwrite_real(buf, size, count, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
|
||||||
|
size_t total;
|
||||||
|
if (__size_mul_overflow(size, count, &total)) {
|
||||||
|
__fwrite_overflow();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total > bos) {
|
||||||
|
__fwrite_too_big_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __fwrite_real(buf, size, count, stream);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return __fwrite_chk(buf, size, count, stream, bos);
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(__clang__)
|
#if !defined(__clang__)
|
||||||
|
|
||||||
__BIONIC_FORTIFY_INLINE
|
__BIONIC_FORTIFY_INLINE
|
||||||
|
|||||||
@@ -578,4 +578,19 @@
|
|||||||
#define _BIONIC_NOT_BEFORE_21(x)
|
#define _BIONIC_NOT_BEFORE_21(x)
|
||||||
#endif /* __ANDROID_API__ >= 21 */
|
#endif /* __ANDROID_API__ >= 21 */
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
|
||||||
|
#if __LP64__
|
||||||
|
#define __size_mul_overflow(a, b, result) __builtin_umull_overflow(a, b, result)
|
||||||
|
#else
|
||||||
|
#define __size_mul_overflow(a, b, result) __builtin_umul_overflow(a, b, result)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
static __inline__ __always_inline int __size_mul_overflow(__SIZE_TYPE__ a, __SIZE_TYPE__ b,
|
||||||
|
__SIZE_TYPE__ *result) {
|
||||||
|
*result = a * b;
|
||||||
|
static const __SIZE_TYPE__ mul_no_overflow = 1UL << (sizeof(__SIZE_TYPE__) * 4);
|
||||||
|
return (a >= mul_no_overflow || b >= mul_no_overflow) && a > 0 && (__SIZE_TYPE__)-1 / a < b;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* !_SYS_CDEFS_H_ */
|
#endif /* !_SYS_CDEFS_H_ */
|
||||||
|
|||||||
1
libc/include/sys/fcntl.h
Normal file
1
libc/include/sys/fcntl.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include <fcntl.h>
|
||||||
1
libc/include/sys/syslog.h
Normal file
1
libc/include/sys/syslog.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include <syslog.h>
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SYS_TIME_H_
|
#ifndef _SYS_TIME_H_
|
||||||
#define _SYS_TIME_H_
|
#define _SYS_TIME_H_
|
||||||
|
|
||||||
@@ -32,6 +33,9 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
|
|
||||||
|
/* POSIX says <sys/time.h> gets you most of <sys/select.h> and may get you all of it. */
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
extern int gettimeofday(struct timeval *, struct timezone *);
|
extern int gettimeofday(struct timeval *, struct timezone *);
|
||||||
@@ -73,6 +77,15 @@ extern int utimes(const char *, const struct timeval *);
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
|
||||||
|
(ts)->tv_sec = (tv)->tv_sec; \
|
||||||
|
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
|
||||||
|
}
|
||||||
|
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
|
||||||
|
(tv)->tv_sec = (ts)->tv_sec; \
|
||||||
|
(tv)->tv_usec = (ts)->tv_nsec / 1000; \
|
||||||
|
}
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif /* _SYS_TIME_H_ */
|
#endif /* _SYS_TIME_H_ */
|
||||||
|
|||||||
1
libc/include/sys/unistd.h
Normal file
1
libc/include/sys/unistd.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include <unistd.h>
|
||||||
@@ -30,11 +30,13 @@
|
|||||||
#define _SYS_USER_H_
|
#define _SYS_USER_H_
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <limits.h> /* For PAGE_SIZE. */
|
|
||||||
#include <stddef.h> /* For size_t. */
|
#include <stddef.h> /* For size_t. */
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||||
|
|
||||||
#if __i386__
|
#if __i386__
|
||||||
|
|
||||||
struct user_fpregs_struct {
|
struct user_fpregs_struct {
|
||||||
|
|||||||
@@ -1,28 +1 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 The Android Open Source Project
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * 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 COPYRIGHT HOLDERS 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
|
|
||||||
* COPYRIGHT OWNER 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.
|
|
||||||
*/
|
|
||||||
#include <linux/vt.h>
|
#include <linux/vt.h>
|
||||||
|
|||||||
1
libc/include/syscall.h
Normal file
1
libc/include/syscall.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include <sys/syscall.h>
|
||||||
@@ -224,6 +224,10 @@ extern int tcsetpgrp(int fd, pid_t _pid);
|
|||||||
} while (_rc == -1 && errno == EINTR); \
|
} while (_rc == -1 && errno == EINTR); \
|
||||||
_rc; })
|
_rc; })
|
||||||
|
|
||||||
|
extern char* __getcwd_chk(char*, size_t, size_t);
|
||||||
|
__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
|
||||||
|
extern char* __getcwd_real(char*, size_t) __RENAME(getcwd);
|
||||||
|
|
||||||
extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
|
extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
|
||||||
__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
|
__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
|
||||||
__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
|
__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
|
||||||
@@ -251,6 +255,37 @@ extern ssize_t __readlinkat_real(int dirfd, const char*, char*, size_t) __RENAME
|
|||||||
|
|
||||||
#if defined(__BIONIC_FORTIFY)
|
#if defined(__BIONIC_FORTIFY)
|
||||||
|
|
||||||
|
__BIONIC_FORTIFY_INLINE
|
||||||
|
char* getcwd(char* buf, size_t size) {
|
||||||
|
size_t bos = __bos(buf);
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
/*
|
||||||
|
* Work around LLVM's incorrect __builtin_object_size implementation here
|
||||||
|
* to avoid needing the workaround in the __getcwd_chk ABI forever.
|
||||||
|
*
|
||||||
|
* https://llvm.org/bugs/show_bug.cgi?id=23277
|
||||||
|
*/
|
||||||
|
if (buf == NULL) {
|
||||||
|
bos = __BIONIC_FORTIFY_UNKNOWN_SIZE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
|
||||||
|
return __getcwd_real(buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__builtin_constant_p(size) && (size > bos)) {
|
||||||
|
__getcwd_dest_size_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__builtin_constant_p(size) && (size <= bos)) {
|
||||||
|
return __getcwd_real(buf, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return __getcwd_chk(buf, size, bos);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__USE_FILE_OFFSET64)
|
#if defined(__USE_FILE_OFFSET64)
|
||||||
#define __PREAD_PREFIX(x) __pread64_ ## x
|
#define __PREAD_PREFIX(x) __pread64_ ## x
|
||||||
#else
|
#else
|
||||||
|
|||||||
1
libc/include/wait.h
Normal file
1
libc/include/wait.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include <sys/wait.h>
|
||||||
@@ -961,29 +961,30 @@ struct drm_radeon_cs {
|
|||||||
#define RADEON_INFO_GTT_USAGE 0x1f
|
#define RADEON_INFO_GTT_USAGE 0x1f
|
||||||
#define RADEON_INFO_ACTIVE_CU_COUNT 0x20
|
#define RADEON_INFO_ACTIVE_CU_COUNT 0x20
|
||||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||||
|
#define RADEON_INFO_VA_UNMAP_WORKING 0x25
|
||||||
struct drm_radeon_info {
|
struct drm_radeon_info {
|
||||||
uint32_t request;
|
uint32_t request;
|
||||||
uint32_t pad;
|
uint32_t pad;
|
||||||
uint64_t value;
|
|
||||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||||
|
uint64_t value;
|
||||||
};
|
};
|
||||||
#define SI_TILE_MODE_COLOR_LINEAR_ALIGNED 8
|
#define SI_TILE_MODE_COLOR_LINEAR_ALIGNED 8
|
||||||
#define SI_TILE_MODE_COLOR_1D 13
|
#define SI_TILE_MODE_COLOR_1D 13
|
||||||
#define SI_TILE_MODE_COLOR_1D_SCANOUT 9
|
|
||||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||||
|
#define SI_TILE_MODE_COLOR_1D_SCANOUT 9
|
||||||
#define SI_TILE_MODE_COLOR_2D_8BPP 14
|
#define SI_TILE_MODE_COLOR_2D_8BPP 14
|
||||||
#define SI_TILE_MODE_COLOR_2D_16BPP 15
|
#define SI_TILE_MODE_COLOR_2D_16BPP 15
|
||||||
#define SI_TILE_MODE_COLOR_2D_32BPP 16
|
#define SI_TILE_MODE_COLOR_2D_32BPP 16
|
||||||
#define SI_TILE_MODE_COLOR_2D_64BPP 17
|
|
||||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||||
|
#define SI_TILE_MODE_COLOR_2D_64BPP 17
|
||||||
#define SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP 11
|
#define SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP 11
|
||||||
#define SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP 12
|
#define SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP 12
|
||||||
#define SI_TILE_MODE_DEPTH_STENCIL_1D 4
|
#define SI_TILE_MODE_DEPTH_STENCIL_1D 4
|
||||||
#define SI_TILE_MODE_DEPTH_STENCIL_2D 0
|
|
||||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||||
|
#define SI_TILE_MODE_DEPTH_STENCIL_2D 0
|
||||||
#define SI_TILE_MODE_DEPTH_STENCIL_2D_2AA 3
|
#define SI_TILE_MODE_DEPTH_STENCIL_2D_2AA 3
|
||||||
#define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA 3
|
#define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA 3
|
||||||
#define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA 2
|
#define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA 2
|
||||||
#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
|
|
||||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||||
|
#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,5 +16,5 @@
|
|||||||
***
|
***
|
||||||
****************************************************************************
|
****************************************************************************
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#define LINUX_VERSION_CODE 201226
|
#define LINUX_VERSION_CODE 201234
|
||||||
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||||
|
|||||||
@@ -1332,6 +1332,15 @@ LIBC {
|
|||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
__fread_chk;
|
||||||
|
__fwrite_chk;
|
||||||
|
__getcwd_chk;
|
||||||
|
getgrgid_r;
|
||||||
|
getgrnam_r;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
___Unwind_Backtrace; # arm
|
___Unwind_Backtrace; # arm
|
||||||
@@ -1453,4 +1462,4 @@ LIBC_PRIVATE {
|
|||||||
SHA1Init; # arm x86 mips
|
SHA1Init; # arm x86 mips
|
||||||
SHA1Transform; # arm x86 mips
|
SHA1Transform; # arm x86 mips
|
||||||
SHA1Update; # arm x86 mips
|
SHA1Update; # arm x86 mips
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|||||||
33
libc/private/bionic_page.h
Normal file
33
libc/private/bionic_page.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIONIC_PAGE_H_
|
||||||
|
#define _BIONIC_PAGE_H_
|
||||||
|
|
||||||
|
// Get PAGE_SIZE and PAGE_MASK.
|
||||||
|
#include <sys/user.h>
|
||||||
|
|
||||||
|
// Returns the address of the page containing address 'x'.
|
||||||
|
#define PAGE_START(x) ((x) & PAGE_MASK)
|
||||||
|
|
||||||
|
// Returns the offset of address 'x' in its page.
|
||||||
|
#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
|
||||||
|
|
||||||
|
// Returns the address of the next page after address 'x', unless 'x' is
|
||||||
|
// itself at the start of a page.
|
||||||
|
#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
|
||||||
|
|
||||||
|
#endif // _BIONIC_PAGE_H_
|
||||||
@@ -67,6 +67,9 @@ enum {
|
|||||||
TLS_SLOT_STACK_GUARD = 5, // GCC requires this specific slot for x86.
|
TLS_SLOT_STACK_GUARD = 5, // GCC requires this specific slot for x86.
|
||||||
TLS_SLOT_DLERROR,
|
TLS_SLOT_DLERROR,
|
||||||
|
|
||||||
|
// Fast storage for Thread::Current() in ART.
|
||||||
|
TLS_SLOT_ART_THREAD_SELF,
|
||||||
|
|
||||||
BIONIC_TLS_SLOTS // Must come last!
|
BIONIC_TLS_SLOTS // Must come last!
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,7 +117,7 @@ __END_DECLS
|
|||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
class KernelArgumentBlock;
|
class KernelArgumentBlock;
|
||||||
extern __LIBC_HIDDEN__ void __libc_init_tls(KernelArgumentBlock& args);
|
extern __LIBC_HIDDEN__ void __libc_init_main_thread(KernelArgumentBlock& args);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
|
#endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
#include "atexit.h"
|
#include "atexit.h"
|
||||||
#include "private/thread_private.h"
|
#include "private/thread_private.h"
|
||||||
|
|
||||||
|
/* BEGIN android-changed */
|
||||||
|
#include "private/bionic_prctl.h"
|
||||||
|
/* END android-changed */
|
||||||
|
|
||||||
struct atexit {
|
struct atexit {
|
||||||
struct atexit *next; /* next in list */
|
struct atexit *next; /* next in list */
|
||||||
int ind; /* next index in this table */
|
int ind; /* next index in this table */
|
||||||
@@ -95,6 +99,10 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso)
|
|||||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
if (p == MAP_FAILED)
|
if (p == MAP_FAILED)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
/* BEGIN android-changed */
|
||||||
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
|
||||||
|
"atexit handlers");
|
||||||
|
/* END android-changed */
|
||||||
if (__atexit == NULL) {
|
if (__atexit == NULL) {
|
||||||
memset(&p->fns[0], 0, sizeof(p->fns[0]));
|
memset(&p->fns[0], 0, sizeof(p->fns[0]));
|
||||||
p->ind = 1;
|
p->ind = 1;
|
||||||
@@ -204,6 +212,10 @@ __atexit_register_cleanup(void (*func)(void))
|
|||||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
if (p == MAP_FAILED)
|
if (p == MAP_FAILED)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
/* BEGIN android-changed */
|
||||||
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
|
||||||
|
"atexit handlers");
|
||||||
|
/* END android-changed */
|
||||||
p->ind = 1;
|
p->ind = 1;
|
||||||
p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
|
p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
|
||||||
sizeof(p->fns[0]);
|
sizeof(p->fns[0]);
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "private/bionic_prctl.h"
|
||||||
|
|
||||||
// Android gets these from "thread_private.h".
|
// Android gets these from "thread_private.h".
|
||||||
#include "thread_private.h"
|
#include "thread_private.h"
|
||||||
//static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
|
//static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||||
@@ -76,12 +78,18 @@ _rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
|
|||||||
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
|
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsp, sizeof(**rsp),
|
||||||
|
"arc4random _rs structure");
|
||||||
|
|
||||||
if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
|
if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
|
||||||
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
|
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
|
||||||
munmap(*rsxp, sizeof(**rsxp));
|
munmap(*rsxp, sizeof(**rsxp));
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsxp, sizeof(**rsxp),
|
||||||
|
"arc4random _rsx structure");
|
||||||
|
|
||||||
_ARC4_ATFORK(_rs_forkhandler);
|
_ARC4_ATFORK(_rs_forkhandler);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: fnmatch.c,v 1.17 2013/11/24 23:51:29 deraadt Exp $ */
|
/* $OpenBSD: fnmatch.c,v 1.19 2015/08/01 18:11:08 millert Exp $ */
|
||||||
|
|
||||||
/* Copyright (c) 2011, VMware, Inc.
|
/* Copyright (c) 2011, VMware, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
@@ -88,7 +88,6 @@
|
|||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include "charclass.h"
|
#include "charclass.h"
|
||||||
|
|
||||||
@@ -193,6 +192,8 @@ static int fnmatch_ch(const char **pattern, const char **string, int flags)
|
|||||||
result = 0;
|
result = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!**pattern)
|
||||||
|
break;
|
||||||
|
|
||||||
leadingclosebrace:
|
leadingclosebrace:
|
||||||
/* Look at only well-formed range patterns;
|
/* Look at only well-formed range patterns;
|
||||||
@@ -294,10 +295,6 @@ int fnmatch(const char *pattern, const char *string, int flags)
|
|||||||
const char *mismatch = NULL;
|
const char *mismatch = NULL;
|
||||||
int matchlen = 0;
|
int matchlen = 0;
|
||||||
|
|
||||||
if (strnlen(pattern, PATH_MAX) == PATH_MAX ||
|
|
||||||
strnlen(string, PATH_MAX) == PATH_MAX)
|
|
||||||
return (FNM_NOMATCH);
|
|
||||||
|
|
||||||
if (*pattern == '*')
|
if (*pattern == '*')
|
||||||
goto firstsegment;
|
goto firstsegment;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ LOCAL_CONLYFLAGS += \
|
|||||||
-std=gnu99 \
|
-std=gnu99 \
|
||||||
|
|
||||||
LOCAL_CPPFLAGS += \
|
LOCAL_CPPFLAGS += \
|
||||||
-std=gnu++11 \
|
|
||||||
-Wold-style-cast \
|
-Wold-style-cast \
|
||||||
|
|
||||||
ifeq ($(TARGET_IS_64_BIT),true)
|
ifeq ($(TARGET_IS_64_BIT),true)
|
||||||
@@ -60,7 +59,7 @@ LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
|
|||||||
|
|
||||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libz liblog
|
LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libbase libz liblog
|
||||||
|
|
||||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
||||||
|
|
||||||
@@ -83,4 +82,26 @@ LOCAL_POST_LINK_CMD = $(hide) $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) \
|
|||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
|
||||||
|
ifeq (address, $(strip $(SANITIZE_TARGET)))
|
||||||
|
|
||||||
|
define add-linker-symlink
|
||||||
|
$(eval _from := $(TARGET_OUT)/bin/$(1))
|
||||||
|
$(eval _to:=$(2))
|
||||||
|
$(_from): $(LOCAL_MODULE_MAKEFILE)
|
||||||
|
@echo "Symlink: $$@ -> $(_to)"
|
||||||
|
@mkdir -p $$(dir $$@)
|
||||||
|
@rm -rf $$@
|
||||||
|
$(hide) ln -sf $(_to) $$@
|
||||||
|
ALL_MODULES.linker.INSTALLED += $(_from)
|
||||||
|
linker: $(_from)
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call add-linker-symlink,linker_asan,linker))
|
||||||
|
ifeq ($(TARGET_IS_64_BIT),true)
|
||||||
|
$(eval $(call add-linker-symlink,linker_asan64,linker64))
|
||||||
|
endif
|
||||||
|
ALL_MODULES += linker
|
||||||
|
endif
|
||||||
|
|
||||||
include $(call first-makefiles-under,$(LOCAL_PATH))
|
include $(call first-makefiles-under,$(LOCAL_PATH))
|
||||||
|
|||||||
@@ -135,9 +135,6 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
|
|||||||
signal_name = "SIGILL";
|
signal_name = "SIGILL";
|
||||||
has_address = true;
|
has_address = true;
|
||||||
break;
|
break;
|
||||||
case SIGPIPE:
|
|
||||||
signal_name = "SIGPIPE";
|
|
||||||
break;
|
|
||||||
case SIGSEGV:
|
case SIGSEGV:
|
||||||
signal_name = "SIGSEGV";
|
signal_name = "SIGSEGV";
|
||||||
has_address = true;
|
has_address = true;
|
||||||
@@ -273,7 +270,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)
|
|||||||
signal(signal_number, SIG_DFL);
|
signal(signal_number, SIG_DFL);
|
||||||
|
|
||||||
// These signals are not re-thrown when we resume. This means that
|
// These signals are not re-thrown when we resume. This means that
|
||||||
// crashing due to (say) SIGPIPE doesn't work the way you'd expect it
|
// crashing due to (say) SIGABRT doesn't work the way you'd expect it
|
||||||
// to. We work around this by throwing them manually. We don't want
|
// to. We work around this by throwing them manually. We don't want
|
||||||
// to do this for *all* signals because it'll screw up the si_addr for
|
// to do this for *all* signals because it'll screw up the si_addr for
|
||||||
// faults like SIGSEGV. It does screw up the si_code, which is why we
|
// faults like SIGSEGV. It does screw up the si_code, which is why we
|
||||||
@@ -281,7 +278,6 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)
|
|||||||
switch (signal_number) {
|
switch (signal_number) {
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
case SIGFPE:
|
case SIGFPE:
|
||||||
case SIGPIPE:
|
|
||||||
#if defined(SIGSTKFLT)
|
#if defined(SIGSTKFLT)
|
||||||
case SIGSTKFLT:
|
case SIGSTKFLT:
|
||||||
#endif
|
#endif
|
||||||
@@ -307,7 +303,6 @@ __LIBC_HIDDEN__ void debuggerd_init() {
|
|||||||
sigaction(SIGBUS, &action, nullptr);
|
sigaction(SIGBUS, &action, nullptr);
|
||||||
sigaction(SIGFPE, &action, nullptr);
|
sigaction(SIGFPE, &action, nullptr);
|
||||||
sigaction(SIGILL, &action, nullptr);
|
sigaction(SIGILL, &action, nullptr);
|
||||||
sigaction(SIGPIPE, &action, nullptr);
|
|
||||||
sigaction(SIGSEGV, &action, nullptr);
|
sigaction(SIGSEGV, &action, nullptr);
|
||||||
#if defined(SIGSTKFLT)
|
#if defined(SIGSTKFLT)
|
||||||
sigaction(SIGSTKFLT, &action, nullptr);
|
sigaction(SIGSTKFLT, &action, nullptr);
|
||||||
|
|||||||
@@ -67,9 +67,11 @@ void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
|||||||
do_android_update_LD_LIBRARY_PATH(ld_library_path);
|
do_android_update_LD_LIBRARY_PATH(ld_library_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
|
static void* dlopen_ext(const char* filename, int flags,
|
||||||
|
const android_dlextinfo* extinfo, void* caller_addr) {
|
||||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
soinfo* result = do_dlopen(filename, flags, extinfo);
|
soinfo* caller = find_containing_library(caller_addr);
|
||||||
|
soinfo* result = do_dlopen(filename, flags, extinfo, caller);
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
|
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -78,11 +80,13 @@ static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
|
void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
|
||||||
return dlopen_ext(filename, flags, extinfo);
|
void* caller_addr = __builtin_return_address(0);
|
||||||
|
return dlopen_ext(filename, flags, extinfo, caller_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* dlopen(const char* filename, int flags) {
|
void* dlopen(const char* filename, int flags) {
|
||||||
return dlopen_ext(filename, flags, nullptr);
|
void* caller_addr = __builtin_return_address(0);
|
||||||
|
return dlopen_ext(filename, flags, nullptr, caller_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* dlsym(void* handle, const char* symbol) {
|
void* dlsym(void* handle, const char* symbol) {
|
||||||
|
|||||||
@@ -57,6 +57,8 @@
|
|||||||
#include "linker_phdr.h"
|
#include "linker_phdr.h"
|
||||||
#include "linker_relocs.h"
|
#include "linker_relocs.h"
|
||||||
#include "linker_reloc_iterators.h"
|
#include "linker_reloc_iterators.h"
|
||||||
|
|
||||||
|
#include "base/strings.h"
|
||||||
#include "ziparchive/zip_archive.h"
|
#include "ziparchive/zip_archive.h"
|
||||||
|
|
||||||
extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
|
extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
|
||||||
@@ -85,9 +87,26 @@ static const char* const kDefaultLdPaths[] = {
|
|||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char* const kAsanDefaultLdPaths[] = {
|
||||||
|
#if defined(__LP64__)
|
||||||
|
"/data/vendor/lib64",
|
||||||
|
"/vendor/lib64",
|
||||||
|
"/data/lib64",
|
||||||
|
"/system/lib64",
|
||||||
|
#else
|
||||||
|
"/data/vendor/lib",
|
||||||
|
"/vendor/lib",
|
||||||
|
"/data/lib",
|
||||||
|
"/system/lib",
|
||||||
|
#endif
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
static const ElfW(Versym) kVersymNotNeeded = 0;
|
static const ElfW(Versym) kVersymNotNeeded = 0;
|
||||||
static const ElfW(Versym) kVersymGlobal = 1;
|
static const ElfW(Versym) kVersymGlobal = 1;
|
||||||
|
static const char* const kZipFileSeparator = "!/";
|
||||||
|
|
||||||
|
static const char* const* g_default_ld_paths;
|
||||||
static std::vector<std::string> g_ld_library_paths;
|
static std::vector<std::string> g_ld_library_paths;
|
||||||
static std::vector<std::string> g_ld_preload_names;
|
static std::vector<std::string> g_ld_preload_names;
|
||||||
|
|
||||||
@@ -285,30 +304,15 @@ static void soinfo_free(soinfo* si) {
|
|||||||
sonext = prev;
|
sonext = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
si->~soinfo();
|
||||||
g_soinfo_allocator.free(si);
|
g_soinfo_allocator.free(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_path(const char* path, const char* delimiters,
|
static void parse_path(const char* path, const char* delimiters,
|
||||||
std::vector<std::string>* paths) {
|
std::vector<std::string>* paths) {
|
||||||
if (path == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
paths->clear();
|
paths->clear();
|
||||||
|
if (path != nullptr) {
|
||||||
for (const char *p = path; ; ++p) {
|
*paths = android::base::Split(path, delimiters);
|
||||||
size_t len = strcspn(p, delimiters);
|
|
||||||
// skip empty tokens
|
|
||||||
if (len == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
paths->push_back(std::string(p, len));
|
|
||||||
p += len;
|
|
||||||
|
|
||||||
if (*p == '\0') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1125,7 +1129,7 @@ static int open_library_in_zipfile(const char* const path,
|
|||||||
// of the zip file on disk and the subdirectory to search within it.
|
// of the zip file on disk and the subdirectory to search within it.
|
||||||
// For example, if path is "foo.zip!/bar/bas/x.so", then we search for
|
// For example, if path is "foo.zip!/bar/bas/x.so", then we search for
|
||||||
// "bar/bas/x.so" within "foo.zip".
|
// "bar/bas/x.so" within "foo.zip".
|
||||||
const char* separator = strstr(path, "!/");
|
const char* separator = strstr(path, kZipFileSeparator);
|
||||||
if (separator == nullptr) {
|
if (separator == nullptr) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1185,9 +1189,9 @@ static bool format_path(char* buf, size_t buf_size, const char* path, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int open_library_on_default_path(const char* name, off64_t* file_offset) {
|
static int open_library_on_default_path(const char* name, off64_t* file_offset) {
|
||||||
for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) {
|
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
if (!format_path(buf, sizeof(buf), kDefaultLdPaths[i], name)) {
|
if (!format_path(buf, sizeof(buf), g_default_ld_paths[i], name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1211,7 +1215,7 @@ static int open_library_on_paths(const char* name, off64_t* file_offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
if (strchr(buf, '!') != nullptr) {
|
if (strstr(buf, kZipFileSeparator) != nullptr) {
|
||||||
fd = open_library_in_zipfile(buf, file_offset);
|
fd = open_library_in_zipfile(buf, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1235,7 +1239,7 @@ static int open_library(const char* name, soinfo *needed_by, off64_t* file_offse
|
|||||||
|
|
||||||
// If the name contains a slash, we should attempt to open it directly and not search the paths.
|
// If the name contains a slash, we should attempt to open it directly and not search the paths.
|
||||||
if (strchr(name, '/') != nullptr) {
|
if (strchr(name, '/') != nullptr) {
|
||||||
if (strchr(name, '!') != nullptr) {
|
if (strstr(name, kZipFileSeparator) != nullptr) {
|
||||||
int fd = open_library_in_zipfile(name, file_offset);
|
int fd = open_library_in_zipfile(name, file_offset);
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
return fd;
|
return fd;
|
||||||
@@ -1469,9 +1473,17 @@ static soinfo::soinfo_list_t make_global_group() {
|
|||||||
return global_group;
|
return global_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_libraries(soinfo* start_with, const char* const library_names[],
|
// add_as_children - add first-level loaded libraries (i.e. library_names[], but
|
||||||
size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads,
|
// not their transitive dependencies) as children of the start_with library.
|
||||||
size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
|
// This is false when find_libraries is called for dlopen(), when newly loaded
|
||||||
|
// libraries must form a disjoint tree.
|
||||||
|
static bool find_libraries(soinfo* start_with,
|
||||||
|
const char* const library_names[],
|
||||||
|
size_t library_names_count, soinfo* soinfos[],
|
||||||
|
std::vector<soinfo*>* ld_preloads,
|
||||||
|
size_t ld_preloads_count, int rtld_flags,
|
||||||
|
const android_dlextinfo* extinfo,
|
||||||
|
bool add_as_children) {
|
||||||
// Step 0: prepare.
|
// Step 0: prepare.
|
||||||
LoadTaskList load_tasks;
|
LoadTaskList load_tasks;
|
||||||
for (size_t i = 0; i < library_names_count; ++i) {
|
for (size_t i = 0; i < library_names_count; ++i) {
|
||||||
@@ -1519,7 +1531,7 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[]
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needed_by != nullptr) {
|
if (needed_by != nullptr && (needed_by != start_with || add_as_children)) {
|
||||||
needed_by->add_child(si);
|
needed_by->add_child(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1546,8 +1558,8 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[]
|
|||||||
// Step 2: link libraries.
|
// Step 2: link libraries.
|
||||||
soinfo::soinfo_list_t local_group;
|
soinfo::soinfo_list_t local_group;
|
||||||
walk_dependencies_tree(
|
walk_dependencies_tree(
|
||||||
start_with == nullptr ? soinfos : &start_with,
|
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
|
||||||
start_with == nullptr ? soinfos_count : 1,
|
(start_with != nullptr && add_as_children) ? 1 : soinfos_count,
|
||||||
[&] (soinfo* si) {
|
[&] (soinfo* si) {
|
||||||
local_group.push_back(si);
|
local_group.push_back(si);
|
||||||
return true;
|
return true;
|
||||||
@@ -1579,12 +1591,15 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[]
|
|||||||
return linked;
|
return linked;
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
|
static soinfo* find_library(const char* name, int rtld_flags,
|
||||||
|
const android_dlextinfo* extinfo,
|
||||||
|
soinfo* needed_by) {
|
||||||
soinfo* si;
|
soinfo* si;
|
||||||
|
|
||||||
if (name == nullptr) {
|
if (name == nullptr) {
|
||||||
si = somain;
|
si = somain;
|
||||||
} else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
|
} else if (!find_libraries(needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
|
||||||
|
extinfo, /* add_as_children */ false)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1646,7 +1661,7 @@ static void soinfo_unload(soinfo* root) {
|
|||||||
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
|
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
|
||||||
si->get_realpath(), library_name);
|
si->get_realpath(), library_name);
|
||||||
|
|
||||||
soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
|
soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr, nullptr);
|
||||||
if (needed != nullptr) {
|
if (needed != nullptr) {
|
||||||
// Not found: for example if symlink was deleted between dlopen and dlclose
|
// Not found: for example if symlink was deleted between dlopen and dlclose
|
||||||
// Since we cannot really handle errors at this point - print and continue.
|
// Since we cannot really handle errors at this point - print and continue.
|
||||||
@@ -1694,21 +1709,26 @@ void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
|
|||||||
// See b/17302493 for further details.
|
// See b/17302493 for further details.
|
||||||
// Once the above bug is fixed, this code can be modified to use
|
// Once the above bug is fixed, this code can be modified to use
|
||||||
// snprintf again.
|
// snprintf again.
|
||||||
size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
|
size_t required_len = 0;
|
||||||
|
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
||||||
|
required_len += strlen(g_default_ld_paths[i]) + 1;
|
||||||
|
}
|
||||||
if (buffer_size < required_len) {
|
if (buffer_size < required_len) {
|
||||||
__libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
|
__libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
|
||||||
"buffer len %zu, required len %zu", buffer_size, required_len);
|
"buffer len %zu, required len %zu", buffer_size, required_len);
|
||||||
}
|
}
|
||||||
char* end = stpcpy(buffer, kDefaultLdPaths[0]);
|
char* end = buffer;
|
||||||
*end = ':';
|
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
||||||
strcpy(end + 1, kDefaultLdPaths[1]);
|
if (i > 0) *end++ = ':';
|
||||||
|
end = stpcpy(end, g_default_ld_paths[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
||||||
parse_LD_LIBRARY_PATH(ld_library_path);
|
parse_LD_LIBRARY_PATH(ld_library_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
|
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, soinfo *caller) {
|
||||||
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
|
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
|
||||||
DL_ERR("invalid flags to dlopen: %x", flags);
|
DL_ERR("invalid flags to dlopen: %x", flags);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -1727,7 +1747,7 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProtectedDataGuard guard;
|
ProtectedDataGuard guard;
|
||||||
soinfo* si = find_library(name, flags, extinfo);
|
soinfo* si = find_library(name, flags, extinfo, caller);
|
||||||
if (si != nullptr) {
|
if (si != nullptr) {
|
||||||
si->call_constructors();
|
si->call_constructors();
|
||||||
}
|
}
|
||||||
@@ -1965,9 +1985,32 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
|
|||||||
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else { // We got a definition.
|
||||||
// We got a definition.
|
#if !defined(__LP64__)
|
||||||
|
// When relocating dso with text_relocation .text segment is
|
||||||
|
// not executable. We need to restore elf flags before resolving
|
||||||
|
// STT_GNU_IFUNC symbol.
|
||||||
|
bool protect_segments = has_text_relocations &&
|
||||||
|
lsi == this &&
|
||||||
|
ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
|
||||||
|
if (protect_segments) {
|
||||||
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't protect segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
sym_addr = lsi->resolve_symbol_address(s);
|
sym_addr = lsi->resolve_symbol_address(s);
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
if (protect_segments) {
|
||||||
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
count_relocation(kRelocSymbol);
|
count_relocation(kRelocSymbol);
|
||||||
}
|
}
|
||||||
@@ -2004,7 +2047,32 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
|
|||||||
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
|
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
|
||||||
reinterpret_cast<void*>(reloc),
|
reinterpret_cast<void*>(reloc),
|
||||||
reinterpret_cast<void*>(load_bias + addend));
|
reinterpret_cast<void*>(load_bias + addend));
|
||||||
*reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
|
{
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
// When relocating dso with text_relocation .text segment is
|
||||||
|
// not executable. We need to restore elf flags for this
|
||||||
|
// particular call.
|
||||||
|
if (has_text_relocations) {
|
||||||
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't protect segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
// Unprotect it afterwards...
|
||||||
|
if (has_text_relocations) {
|
||||||
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
@@ -3144,6 +3212,16 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
|
|||||||
insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
|
insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void init_default_ld_library_path() {
|
||||||
|
const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
|
||||||
|
somain->load_bias);
|
||||||
|
const char* bname = basename(interp);
|
||||||
|
if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0))
|
||||||
|
g_default_ld_paths = kAsanDefaultLdPaths;
|
||||||
|
else
|
||||||
|
g_default_ld_paths = kDefaultLdPaths;
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" int __system_properties_init(void);
|
extern "C" int __system_properties_init(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3234,6 +3312,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
|||||||
|
|
||||||
somain = si;
|
somain = si;
|
||||||
|
|
||||||
|
init_default_ld_library_path();
|
||||||
|
|
||||||
if (!si->prelink_image()) {
|
if (!si->prelink_image()) {
|
||||||
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -3265,7 +3345,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
|||||||
|
|
||||||
if (needed_libraries_count > 0 &&
|
if (needed_libraries_count > 0 &&
|
||||||
!find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
|
!find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
|
||||||
&g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
|
&g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
|
||||||
|
/* add_as_children */ true)) {
|
||||||
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
} else if (needed_libraries_count == 0) {
|
} else if (needed_libraries_count == 0) {
|
||||||
@@ -3418,7 +3499,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
|||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
__libc_init_tls(args);
|
__libc_init_main_thread(args);
|
||||||
|
|
||||||
// Initialize the linker's own global variables
|
// Initialize the linker's own global variables
|
||||||
linker_so.call_constructors();
|
linker_so.call_constructors();
|
||||||
|
|||||||
@@ -29,13 +29,14 @@
|
|||||||
#ifndef _LINKER_H_
|
#ifndef _LINKER_H_
|
||||||
#define _LINKER_H_
|
#define _LINKER_H_
|
||||||
|
|
||||||
|
#include <android/dlext.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <android/dlext.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "private/bionic_page.h"
|
||||||
#include "private/libc_logging.h"
|
#include "private/libc_logging.h"
|
||||||
#include "linked_list.h"
|
#include "linked_list.h"
|
||||||
|
|
||||||
@@ -77,16 +78,6 @@
|
|||||||
#define ELF64_R_TYPE(info) (((info) >> 56) & 0xff)
|
#define ELF64_R_TYPE(info) (((info) >> 56) & 0xff)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Returns the address of the page containing address 'x'.
|
|
||||||
#define PAGE_START(x) ((x) & PAGE_MASK)
|
|
||||||
|
|
||||||
// Returns the offset of address 'x' in its page.
|
|
||||||
#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
|
|
||||||
|
|
||||||
// Returns the address of the next page after address 'x', unless 'x' is
|
|
||||||
// itself at the start of a page.
|
|
||||||
#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
|
|
||||||
|
|
||||||
#define FLAG_LINKED 0x00000001
|
#define FLAG_LINKED 0x00000001
|
||||||
#define FLAG_EXE 0x00000004 // The main executable
|
#define FLAG_EXE 0x00000004 // The main executable
|
||||||
#define FLAG_LINKER 0x00000010 // The linker itself
|
#define FLAG_LINKER 0x00000010 // The linker itself
|
||||||
@@ -425,7 +416,7 @@ soinfo* get_libdl_info();
|
|||||||
|
|
||||||
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
|
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
|
||||||
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
|
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
|
||||||
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
|
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, soinfo *caller);
|
||||||
void do_dlclose(soinfo* si);
|
void do_dlclose(soinfo* si);
|
||||||
|
|
||||||
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
|
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
|
||||||
|
|||||||
@@ -264,10 +264,18 @@ bool soinfo::mips_check_and_adjust_fp_modes() {
|
|||||||
|
|
||||||
// FP ABI-variant compatibility checks for MIPS o32 ABI
|
// FP ABI-variant compatibility checks for MIPS o32 ABI
|
||||||
if (abiflags == nullptr) {
|
if (abiflags == nullptr) {
|
||||||
// Old compiles lack the new abiflags section.
|
// Old compilers and some translators don't emit the new abiflags section.
|
||||||
// These compilers used -mfp32 -mdouble-float -modd-spreg defaults,
|
const char* filename = get_realpath();
|
||||||
// ie FP32 aka DOUBLE, using odd-numbered single-prec regs
|
size_t len = strlen(filename);
|
||||||
|
if (len > 4 && (strcmp(filename+len-4, ".dex") == 0 ||
|
||||||
|
strcmp(filename+len-4, ".oat") == 0 )) {
|
||||||
|
// Assume dex2oat is compatible with target
|
||||||
|
mips_fpabi = MIPS_ABI_FP_XX;
|
||||||
|
} else {
|
||||||
|
// Old Android compilers used -mfp32 -mdouble-float -modd-spreg defaults,
|
||||||
|
// ie FP32 aka DOUBLE, using FR=0 mode fpregs & odd single-prec fpregs
|
||||||
mips_fpabi = MIPS_ABI_FP_DOUBLE;
|
mips_fpabi = MIPS_ABI_FP_DOUBLE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mips_fpabi = abiflags->fp_abi;
|
mips_fpabi = abiflags->fp_abi;
|
||||||
if ( (abiflags->flags1 & MIPS_AFL_FLAGS1_ODDSPREG)
|
if ( (abiflags->flags1 & MIPS_AFL_FLAGS1_ODDSPREG)
|
||||||
|
|||||||
@@ -771,6 +771,26 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the program interpreter string, or nullptr if missing.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* phdr_table -> program header table
|
||||||
|
* phdr_count -> number of entries in tables
|
||||||
|
* load_bias -> load bias
|
||||||
|
* Return:
|
||||||
|
* pointer to the program interpreter string.
|
||||||
|
*/
|
||||||
|
const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
|
||||||
|
ElfW(Addr) load_bias) {
|
||||||
|
for (size_t i = 0; i<phdr_count; ++i) {
|
||||||
|
const ElfW(Phdr)& phdr = phdr_table[i];
|
||||||
|
if (phdr.p_type == PT_INTERP) {
|
||||||
|
return reinterpret_cast<const char*>(load_bias + phdr.p_vaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Sets loaded_phdr_ to the address of the program header table as it appears
|
// Sets loaded_phdr_ to the address of the program header table as it appears
|
||||||
// in the loaded segments in memory. This is in contrast with phdr_table_,
|
// in the loaded segments in memory. This is in contrast with phdr_table_,
|
||||||
// which is temporary and will be released before the library is relocated.
|
// which is temporary and will be released before the library is relocated.
|
||||||
|
|||||||
@@ -109,4 +109,7 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co
|
|||||||
ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
|
ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
|
||||||
ElfW(Word)* dynamic_flags);
|
ElfW(Word)* dynamic_flags);
|
||||||
|
|
||||||
|
const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
|
||||||
|
ElfW(Addr) load_bias);
|
||||||
|
|
||||||
#endif /* LINKER_PHDR_H */
|
#endif /* LINKER_PHDR_H */
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
|
|||||||
|
|
||||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||||
|
|
||||||
LOCAL_CFLAGS += -g -Wall -Wextra -Wunused -Werror -std=gnu++11
|
LOCAL_CFLAGS += -g -Wall -Wextra -Wunused -Werror
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ else
|
|||||||
test_cflags += -DUSE_JEMALLOC
|
test_cflags += -DUSE_JEMALLOC
|
||||||
endif
|
endif
|
||||||
|
|
||||||
test_cppflags = \
|
test_cppflags := \
|
||||||
-std=gnu++11 \
|
|
||||||
|
|
||||||
libBionicStandardTests_src_files := \
|
libBionicStandardTests_src_files := \
|
||||||
arpa_inet_test.cpp \
|
arpa_inet_test.cpp \
|
||||||
@@ -93,6 +92,7 @@ libBionicStandardTests_src_files := \
|
|||||||
sys_epoll_test.cpp \
|
sys_epoll_test.cpp \
|
||||||
sys_mman_test.cpp \
|
sys_mman_test.cpp \
|
||||||
sys_personality_test.cpp \
|
sys_personality_test.cpp \
|
||||||
|
sys_prctl_test.cpp \
|
||||||
sys_procfs_test.cpp \
|
sys_procfs_test.cpp \
|
||||||
sys_resource_test.cpp \
|
sys_resource_test.cpp \
|
||||||
sys_select_test.cpp \
|
sys_select_test.cpp \
|
||||||
@@ -279,6 +279,7 @@ bionic-unit-tests_src_files := \
|
|||||||
dlfcn_test.cpp \
|
dlfcn_test.cpp \
|
||||||
libdl_test.cpp \
|
libdl_test.cpp \
|
||||||
pthread_dlfcn_test.cpp \
|
pthread_dlfcn_test.cpp \
|
||||||
|
thread_local_test.cpp \
|
||||||
|
|
||||||
bionic-unit-tests_cflags := $(test_cflags)
|
bionic-unit-tests_cflags := $(test_cflags)
|
||||||
|
|
||||||
@@ -407,7 +408,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := \
|
|||||||
|
|
||||||
LOCAL_CXX = $(LOCAL_PATH)/file-check-cxx \
|
LOCAL_CXX = $(LOCAL_PATH)/file-check-cxx \
|
||||||
$(HOST_OUT_EXECUTABLES)/FileCheck \
|
$(HOST_OUT_EXECUTABLES)/FileCheck \
|
||||||
$($(LOCAL_2ND_ARCH_VAR_PREFIX)CXX_BARE) \
|
$($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CXX) \
|
||||||
GCC \
|
GCC \
|
||||||
|
|
||||||
LOCAL_CLANG := false
|
LOCAL_CLANG := false
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ void RunSingleBufferAlignTest(
|
|||||||
VerifyFencepost(&buf_align[len]);
|
VerifyFencepost(&buf_align[len]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete buf;
|
delete[] buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunSrcDstBufferAlignTest(
|
void RunSrcDstBufferAlignTest(
|
||||||
@@ -292,8 +292,8 @@ void RunSrcDstBufferAlignTest(
|
|||||||
VerifyFencepost(&dst_align[len]);
|
VerifyFencepost(&dst_align[len]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete src;
|
delete[] src;
|
||||||
delete dst;
|
delete[] dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunCmpBufferAlignTest(
|
void RunCmpBufferAlignTest(
|
||||||
@@ -344,8 +344,8 @@ void RunCmpBufferAlignTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete buf1;
|
delete[] buf1;
|
||||||
delete buf2;
|
delete[] buf2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t)) {
|
void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t)) {
|
||||||
@@ -389,7 +389,7 @@ void RunSrcDstBufferOverreadTest(void (*test_func)(uint8_t*, uint8_t*, size_t))
|
|||||||
}
|
}
|
||||||
ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
|
ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
|
||||||
free(memory);
|
free(memory);
|
||||||
delete dst;
|
delete[] dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunCmpBufferOverreadTest(
|
void RunCmpBufferOverreadTest(
|
||||||
|
|||||||
@@ -1072,7 +1072,7 @@ TEST(dlfcn, dt_runpath) {
|
|||||||
ASSERT_TRUE(fn != nullptr) << dlerror();
|
ASSERT_TRUE(fn != nullptr) << dlerror();
|
||||||
|
|
||||||
void *p = fn();
|
void *p = fn();
|
||||||
ASSERT_TRUE(p == nullptr);
|
ASSERT_TRUE(p != nullptr);
|
||||||
|
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,3 +230,43 @@ void test_ppoll() {
|
|||||||
// clang should emit a warning, but doesn't
|
// clang should emit a warning, but doesn't
|
||||||
ppoll(fds, 2, &timeout, NULL);
|
ppoll(fds, 2, &timeout, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_fread_overflow() {
|
||||||
|
char buf[4];
|
||||||
|
// NOLINTNEXTLINE(whitespace/line_length)
|
||||||
|
// GCC: error: call to '__fread_overflow' declared with attribute error: fread called with overflowing size * count
|
||||||
|
// clang should emit a warning, but doesn't
|
||||||
|
fread(buf, 2, (size_t)-1, stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_fread_too_big() {
|
||||||
|
char buf[4];
|
||||||
|
// NOLINTNEXTLINE(whitespace/line_length)
|
||||||
|
// GCC: error: call to '__fread_too_big_error' declared with attribute error: fread called with size * count bigger than buffer
|
||||||
|
// clang should emit a warning, but doesn't
|
||||||
|
fread(buf, 1, 5, stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_fwrite_overflow() {
|
||||||
|
char buf[4];
|
||||||
|
// NOLINTNEXTLINE(whitespace/line_length)
|
||||||
|
// GCC: error: call to '__fwrite_overflow' declared with attribute error: fwrite called with overflowing size * count
|
||||||
|
// clang should emit a warning, but doesn't
|
||||||
|
fwrite(buf, 2, (size_t)-1, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_fwrite_too_big() {
|
||||||
|
char buf[4] = {0};
|
||||||
|
// NOLINTNEXTLINE(whitespace/line_length)
|
||||||
|
// GCC: error: call to '__fwrite_too_big_error' declared with attribute error: fwrite called with size * count bigger than buffer
|
||||||
|
// clang should emit a warning, but doesn't
|
||||||
|
fwrite(buf, 1, 5, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_getcwd() {
|
||||||
|
char buf[4];
|
||||||
|
// NOLINTNEXTLINE(whitespace/line_length)
|
||||||
|
// GCC: error: call to '__getcwd_dest_size_error' declared with attribute error: getcwd called with size bigger than destination
|
||||||
|
// clang should emit a warning, but doesn't
|
||||||
|
getcwd(buf, 5);
|
||||||
|
}
|
||||||
|
|||||||
@@ -623,6 +623,12 @@ TEST_F(DEATHTEST, FD_ISSET_2_fortified) {
|
|||||||
ASSERT_FORTIFY(FD_ISSET(0, set));
|
ASSERT_FORTIFY(FD_ISSET(0, set));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DEATHTEST, getcwd_fortified) {
|
||||||
|
char buf[1];
|
||||||
|
size_t ct = atoi("2"); // prevent optimizations
|
||||||
|
ASSERT_FORTIFY(getcwd(buf, ct));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DEATHTEST, pread_fortified) {
|
TEST_F(DEATHTEST, pread_fortified) {
|
||||||
char buf[1];
|
char buf[1];
|
||||||
size_t ct = atoi("2"); // prevent optimizations
|
size_t ct = atoi("2"); // prevent optimizations
|
||||||
@@ -647,6 +653,22 @@ TEST_F(DEATHTEST, read_fortified) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DEATHTEST, fread_fortified) {
|
||||||
|
char buf[1];
|
||||||
|
size_t ct = atoi("2"); // prevent optimizations
|
||||||
|
FILE* fp = fopen("/dev/null", "r");
|
||||||
|
ASSERT_FORTIFY(fread(buf, 1, ct, fp));
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DEATHTEST, fwrite_fortified) {
|
||||||
|
char buf[1] = {0};
|
||||||
|
size_t ct = atoi("2"); // prevent optimizations
|
||||||
|
FILE* fp = fopen("/dev/null", "w");
|
||||||
|
ASSERT_FORTIFY(fwrite(buf, 1, ct, fp));
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DEATHTEST, readlink_fortified) {
|
TEST_F(DEATHTEST, readlink_fortified) {
|
||||||
char buf[1];
|
char buf[1];
|
||||||
size_t ct = atoi("2"); // prevent optimizations
|
size_t ct = atoi("2"); // prevent optimizations
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ static bool EnumerateTests(int argc, char** argv, std::vector<TestCase>& testcas
|
|||||||
while (*p != '\0' && isspace(*p)) {
|
while (*p != '\0' && isspace(*p)) {
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
if (*p != '\0') {
|
if (*p != '\0' && *p != '#') {
|
||||||
// This is not we want, gtest must meet with some error when parsing the arguments.
|
// This is not we want, gtest must meet with some error when parsing the arguments.
|
||||||
fprintf(stderr, "argument error, check with --help\n");
|
fprintf(stderr, "argument error, check with --help\n");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ libtest_dt_runpath_b_src_files := \
|
|||||||
empty.cpp
|
empty.cpp
|
||||||
|
|
||||||
libtest_dt_runpath_b_shared_libraries := libtest_dt_runpath_a
|
libtest_dt_runpath_b_shared_libraries := libtest_dt_runpath_a
|
||||||
libtest_dt_runpath_b_ldflags := -Wl,--rpath,\$${ORIGIN}/../dt_runpath_a
|
libtest_dt_runpath_b_ldflags := -Wl,--rpath,\$${ORIGIN}/../dt_runpath_a -Wl,--enable-new-dtags
|
||||||
libtest_dt_runpath_b_relative_path := dt_runpath_b_c_x
|
libtest_dt_runpath_b_relative_path := dt_runpath_b_c_x
|
||||||
module := libtest_dt_runpath_b
|
module := libtest_dt_runpath_b
|
||||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||||
@@ -43,7 +43,7 @@ libtest_dt_runpath_c_src_files := \
|
|||||||
empty.cpp
|
empty.cpp
|
||||||
|
|
||||||
libtest_dt_runpath_c_shared_libraries := libtest_dt_runpath_a
|
libtest_dt_runpath_c_shared_libraries := libtest_dt_runpath_a
|
||||||
libtest_dt_runpath_c_ldflags := -Wl,--rpath,\$${ORIGIN}/invalid_dt_runpath
|
libtest_dt_runpath_c_ldflags := -Wl,--rpath,\$${ORIGIN}/invalid_dt_runpath -Wl,--enable-new-dtags
|
||||||
libtest_dt_runpath_c_relative_path := dt_runpath_b_c_x
|
libtest_dt_runpath_c_relative_path := dt_runpath_b_c_x
|
||||||
module := libtest_dt_runpath_c
|
module := libtest_dt_runpath_c
|
||||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||||
@@ -53,7 +53,7 @@ libtest_dt_runpath_d_src_files := \
|
|||||||
dlopen_b.cpp
|
dlopen_b.cpp
|
||||||
|
|
||||||
libtest_dt_runpath_d_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
|
libtest_dt_runpath_d_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
|
||||||
libtest_dt_runpath_d_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x
|
libtest_dt_runpath_d_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
|
||||||
module := libtest_dt_runpath_d
|
module := libtest_dt_runpath_d
|
||||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
TEST_PATH := $(LOCAL_PATH)/..
|
TEST_PATH := $(LOCAL_PATH)/..
|
||||||
|
|
||||||
common_cppflags += -std=gnu++11
|
common_cppflags :=
|
||||||
common_additional_dependencies := \
|
common_additional_dependencies := \
|
||||||
$(LOCAL_PATH)/Android.mk \
|
$(LOCAL_PATH)/Android.mk \
|
||||||
$(LOCAL_PATH)/Android.build.dt_runpath.mk \
|
$(LOCAL_PATH)/Android.build.dt_runpath.mk \
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "buffer_tests.h"
|
#include "buffer_tests.h"
|
||||||
|
|
||||||
@@ -1396,6 +1397,10 @@ TEST(string, strnlen_147048) {
|
|||||||
delete[] heap_src;
|
delete[] heap_src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(string, strnlen_74741) {
|
||||||
|
ASSERT_EQ(4U, strnlen("test", SIZE_MAX));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(string, mempcpy) {
|
TEST(string, mempcpy) {
|
||||||
char dst[6];
|
char dst[6];
|
||||||
ASSERT_EQ(&dst[4], reinterpret_cast<char*>(mempcpy(dst, "hello", 4)));
|
ASSERT_EQ(&dst[4], reinterpret_cast<char*>(mempcpy(dst, "hello", 4)));
|
||||||
|
|||||||
@@ -163,8 +163,6 @@ TEST(getpwnam, app_id_u1_i0) {
|
|||||||
check_get_passwd("u1_i0", 199000, TYPE_APP);
|
check_get_passwd("u1_i0", 199000, TYPE_APP);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__BIONIC__)
|
|
||||||
|
|
||||||
static void check_group(const group* grp, const char* group_name, gid_t gid) {
|
static void check_group(const group* grp, const char* group_name, gid_t gid) {
|
||||||
ASSERT_TRUE(grp != NULL);
|
ASSERT_TRUE(grp != NULL);
|
||||||
ASSERT_STREQ(group_name, grp->gr_name);
|
ASSERT_STREQ(group_name, grp->gr_name);
|
||||||
@@ -174,6 +172,8 @@ static void check_group(const group* grp, const char* group_name, gid_t gid) {
|
|||||||
ASSERT_TRUE(grp->gr_mem[1] == NULL);
|
ASSERT_TRUE(grp->gr_mem[1] == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
|
||||||
static void check_getgrgid(const char* group_name, gid_t gid) {
|
static void check_getgrgid(const char* group_name, gid_t gid) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
group* grp = getgrgid(gid);
|
group* grp = getgrgid(gid);
|
||||||
@@ -190,17 +190,49 @@ static void check_getgrnam(const char* group_name, gid_t gid) {
|
|||||||
check_group(grp, group_name, gid);
|
check_group(grp, group_name, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_getgrgid_r(const char* group_name, gid_t gid) {
|
||||||
|
group grp_storage;
|
||||||
|
char buf[512];
|
||||||
|
group* grp;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
int result = getgrgid_r(gid, &grp_storage, buf, sizeof(buf), &grp);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
ASSERT_EQ(0, errno);
|
||||||
|
SCOPED_TRACE("getgrgid_r");
|
||||||
|
check_group(grp, group_name, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_getgrnam_r(const char* group_name, gid_t gid) {
|
||||||
|
group grp_storage;
|
||||||
|
char buf[512];
|
||||||
|
group* grp;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
int result = getgrnam_r(group_name, &grp_storage, buf, sizeof(buf), &grp);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
ASSERT_EQ(0, errno);
|
||||||
|
SCOPED_TRACE("getgrnam_r");
|
||||||
|
check_group(grp, group_name, gid);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_get_group(const char* group_name, gid_t gid) {
|
static void check_get_group(const char* group_name, gid_t gid) {
|
||||||
check_getgrgid(group_name, gid);
|
check_getgrgid(group_name, gid);
|
||||||
check_getgrnam(group_name, gid);
|
check_getgrnam(group_name, gid);
|
||||||
|
check_getgrgid_r(group_name, gid);
|
||||||
|
check_getgrnam_r(group_name, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !defined(__BIONIC__)
|
#else // !defined(__BIONIC__)
|
||||||
|
|
||||||
static void check_get_group(const char* /* group_name */, gid_t /* gid */) {
|
static void print_no_getgrnam_test_info() {
|
||||||
GTEST_LOG_(INFO) << "This test is about gid/group_name translation for Android, which does nothing on libc other than bionic.\n";
|
GTEST_LOG_(INFO) << "This test is about gid/group_name translation for Android, which does nothing on libc other than bionic.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_get_group(const char*, gid_t) {
|
||||||
|
print_no_getgrnam_test_info();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(getgrnam, system_id_root) {
|
TEST(getgrnam, system_id_root) {
|
||||||
@@ -259,3 +291,53 @@ TEST(getgrnam, app_id_u1_a40000) {
|
|||||||
TEST(getgrnam, app_id_u1_i0) {
|
TEST(getgrnam, app_id_u1_i0) {
|
||||||
check_get_group("u1_i0", 199000);
|
check_get_group("u1_i0", 199000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(getgrnam_r, reentrancy) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
group grp_storage[2];
|
||||||
|
char buf[2][512];
|
||||||
|
group* grp[3];
|
||||||
|
int result = getgrnam_r("root", &grp_storage[0], buf[0], sizeof(buf[0]), &grp[0]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_group(grp[0], "root", 0);
|
||||||
|
grp[1] = getgrnam("system");
|
||||||
|
check_group(grp[1], "system", 1000);
|
||||||
|
result = getgrnam_r("radio", &grp_storage[1], buf[1], sizeof(buf[1]), &grp[2]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_group(grp[2], "radio", 1001);
|
||||||
|
check_group(grp[0], "root", 0);
|
||||||
|
check_group(grp[1], "system", 1000);
|
||||||
|
#else
|
||||||
|
print_no_getgrnam_test_info();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(getgrgid_r, reentrancy) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
group grp_storage[2];
|
||||||
|
char buf[2][512];
|
||||||
|
group* grp[3];
|
||||||
|
int result = getgrgid_r(0, &grp_storage[0], buf[0], sizeof(buf[0]), &grp[0]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_group(grp[0], "root", 0);
|
||||||
|
grp[1] = getgrgid(1000);
|
||||||
|
check_group(grp[1], "system", 1000);
|
||||||
|
result = getgrgid_r(1001, &grp_storage[1], buf[1], sizeof(buf[1]), &grp[2]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_group(grp[2], "radio", 1001);
|
||||||
|
check_group(grp[0], "root", 0);
|
||||||
|
check_group(grp[1], "system", 1000);
|
||||||
|
#else
|
||||||
|
print_no_getgrnam_test_info();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(getgrnam_r, large_enough_suggested_buffer_size) {
|
||||||
|
long size = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||||
|
ASSERT_GT(size, 0);
|
||||||
|
char buf[size];
|
||||||
|
group grp_storage;
|
||||||
|
group* grp;
|
||||||
|
ASSERT_EQ(0, getgrnam_r("root", &grp_storage, buf, size, &grp));
|
||||||
|
check_group(grp, "root", 0);
|
||||||
|
}
|
||||||
|
|||||||
39
tests/sys_prctl_test.cpp
Normal file
39
tests/sys_prctl_test.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "private/bionic_prctl.h"
|
||||||
|
|
||||||
|
// http://b/20017123.
|
||||||
|
TEST(sys_prctl, bug_20017123) {
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||||
|
void* p = mmap(NULL, page_size * 3, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
ASSERT_NE(MAP_FAILED, p);
|
||||||
|
ASSERT_EQ(0, mprotect(p, page_size, PROT_NONE));
|
||||||
|
ASSERT_NE(-1, prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, page_size * 3, "anonymous map space"));
|
||||||
|
volatile char* vp = reinterpret_cast<volatile char*>(p);
|
||||||
|
// Below memory access causes SEGV if the memory map is screwed up.
|
||||||
|
*(vp + page_size) = 0;
|
||||||
|
ASSERT_EQ(0, munmap(p, page_size * 3));
|
||||||
|
#else
|
||||||
|
GTEST_LOG_(INFO) << "This test does nothing as it tests an Android specific kernel feature.";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
168
tests/thread_local_test.cpp
Normal file
168
tests/thread_local_test.cpp
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
// Gcc has a bug with -O -fdata-section for the arm target: http://b/22772147.
|
||||||
|
// Until that bug is fixed, disable optimization since
|
||||||
|
// it is not essential for this test.
|
||||||
|
#pragma GCC optimize("-O0")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__thread int local_var = 100;
|
||||||
|
int shared_var = 200;
|
||||||
|
|
||||||
|
static void reset_vars() {
|
||||||
|
local_var = 1000;
|
||||||
|
shared_var = 2000;
|
||||||
|
// local_var should be reset by threads
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void* (*MyThread)(void*);
|
||||||
|
|
||||||
|
static void* inc_shared_var(void* p) {
|
||||||
|
int *data = reinterpret_cast<int*>(p);
|
||||||
|
shared_var++;
|
||||||
|
*data = shared_var;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* inc_local_var(void* p) {
|
||||||
|
int *data = reinterpret_cast<int*>(p);
|
||||||
|
local_var++;
|
||||||
|
*data = local_var;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run_one_thread(MyThread foo) {
|
||||||
|
pthread_t t;
|
||||||
|
int data;
|
||||||
|
int error = pthread_create(&t, nullptr, foo, &data);
|
||||||
|
if (!error)
|
||||||
|
error = pthread_join(t, nullptr);
|
||||||
|
return error ? error : data;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(thread_local_storage, shared) {
|
||||||
|
reset_vars();
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2000);
|
||||||
|
|
||||||
|
// Update shared_var, local_var remains 1000.
|
||||||
|
ASSERT_EQ(run_one_thread(inc_shared_var), 2001);
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2001);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(inc_shared_var), 2002);
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2002);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(inc_shared_var), 2003);
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2003);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(thread_local_storage, local) {
|
||||||
|
reset_vars();
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2000);
|
||||||
|
|
||||||
|
// When a child thread updates its own TLS variable,
|
||||||
|
// this thread's local_var and shared_var are not changed.
|
||||||
|
// TLS local_var is initialized to 100 in a thread.
|
||||||
|
ASSERT_EQ(run_one_thread(inc_local_var), 101);
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2000);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(inc_local_var), 101);
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2000);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(inc_local_var), 101);
|
||||||
|
ASSERT_EQ(local_var, 1000);
|
||||||
|
ASSERT_EQ(shared_var, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test TLS initialization of more complicated type, array of struct.
|
||||||
|
struct Point {
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Point Triangle[3];
|
||||||
|
|
||||||
|
__thread Triangle local_triangle = {{10,10}, {20,20}, {30,30}};
|
||||||
|
Triangle shared_triangle = {{1,1}, {2,2}, {3,3}};
|
||||||
|
|
||||||
|
static void reset_triangle() {
|
||||||
|
static const Triangle t1 = {{3,3}, {4,4}, {5,5}};
|
||||||
|
static const Triangle t2 = {{2,2}, {3,3}, {4,4}};
|
||||||
|
memcpy(local_triangle, t1, sizeof(local_triangle));
|
||||||
|
memcpy(shared_triangle, t2, sizeof(shared_triangle));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* move_shared_triangle(void* p) {
|
||||||
|
int *data = reinterpret_cast<int*>(p);
|
||||||
|
shared_triangle[1].y++;
|
||||||
|
*data = shared_triangle[1].y;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* move_local_triangle(void* p) {
|
||||||
|
int *data = reinterpret_cast<int*>(p);
|
||||||
|
local_triangle[1].y++;
|
||||||
|
*data = local_triangle[1].y;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(thread_local_storage, shared_triangle) {
|
||||||
|
reset_triangle();
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 3);
|
||||||
|
|
||||||
|
// Update shared_triangle, local_triangle remains 1000.
|
||||||
|
ASSERT_EQ(run_one_thread(move_shared_triangle), 4);
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 4);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(move_shared_triangle), 5);
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 5);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(move_shared_triangle), 6);
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(thread_local_storage, local_triangle) {
|
||||||
|
reset_triangle();
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 3);
|
||||||
|
|
||||||
|
// Update local_triangle, parent thread's
|
||||||
|
// shared_triangle and local_triangle are unchanged.
|
||||||
|
ASSERT_EQ(run_one_thread(move_local_triangle), 21);
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 3);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(move_local_triangle), 21);
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 3);
|
||||||
|
|
||||||
|
ASSERT_EQ(run_one_thread(move_local_triangle), 21);
|
||||||
|
ASSERT_EQ(local_triangle[1].y, 4);
|
||||||
|
ASSERT_EQ(shared_triangle[1].y, 3);
|
||||||
|
}
|
||||||
@@ -402,11 +402,11 @@ static void AssertGetPidCorrect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(unistd, getpid_caching_and_fork) {
|
static void TestGetPidCachingWithFork(int (*fork_fn)()) {
|
||||||
pid_t parent_pid = getpid();
|
pid_t parent_pid = getpid();
|
||||||
ASSERT_EQ(syscall(__NR_getpid), parent_pid);
|
ASSERT_EQ(syscall(__NR_getpid), parent_pid);
|
||||||
|
|
||||||
pid_t fork_result = fork();
|
pid_t fork_result = fork_fn();
|
||||||
ASSERT_NE(fork_result, -1);
|
ASSERT_NE(fork_result, -1);
|
||||||
if (fork_result == 0) {
|
if (fork_result == 0) {
|
||||||
// We're the child.
|
// We're the child.
|
||||||
@@ -424,6 +424,14 @@ TEST(unistd, getpid_caching_and_fork) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(unistd, getpid_caching_and_fork) {
|
||||||
|
TestGetPidCachingWithFork(fork);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unistd, getpid_caching_and_vfork) {
|
||||||
|
TestGetPidCachingWithFork(vfork);
|
||||||
|
}
|
||||||
|
|
||||||
static int GetPidCachingCloneStartRoutine(void*) {
|
static int GetPidCachingCloneStartRoutine(void*) {
|
||||||
AssertGetPidCorrect();
|
AssertGetPidCorrect();
|
||||||
return 123;
|
return 123;
|
||||||
@@ -694,6 +702,8 @@ TEST(unistd, sysconf) {
|
|||||||
VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
|
VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
|
||||||
VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
|
VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
|
||||||
VERIFY_SYSCONF_POSITIVE(_SC_PAGE_SIZE);
|
VERIFY_SYSCONF_POSITIVE(_SC_PAGE_SIZE);
|
||||||
|
VerifySysconf(_SC_PAGE_SIZE, "_SC_PAGE_SIZE",
|
||||||
|
[](long v){return v == sysconf(_SC_PAGESIZE) && v == getpagesize();});
|
||||||
VERIFY_SYSCONF_POSITIVE(_SC_XOPEN_UNIX);
|
VERIFY_SYSCONF_POSITIVE(_SC_XOPEN_UNIX);
|
||||||
VERIFY_SYSCONF_POSITIVE(_SC_AIO_LISTIO_MAX);
|
VERIFY_SYSCONF_POSITIVE(_SC_AIO_LISTIO_MAX);
|
||||||
VERIFY_SYSCONF_POSITIVE(_SC_AIO_MAX);
|
VERIFY_SYSCONF_POSITIVE(_SC_AIO_MAX);
|
||||||
|
|||||||
Reference in New Issue
Block a user