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
|
||||
|
||||
$ mma
|
||||
$ adb remount
|
||||
$ adb sync
|
||||
$ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
|
||||
$ adb shell \
|
||||
/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
|
||||
# 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 \
|
||||
/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static64
|
||||
/data/nativetest64/bionic-unit-tests-static/bionic-unit-tests-static64
|
||||
|
||||
### Host tests
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ benchmark_cflags := \
|
||||
-Wunused \
|
||||
|
||||
benchmark_cppflags := \
|
||||
-std=gnu++11 \
|
||||
|
||||
benchmarklib_src_files := \
|
||||
Benchmark.cpp \
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <benchmark/Benchmark.h>
|
||||
|
||||
|
||||
@@ -70,6 +70,9 @@ libc_common_src_files := \
|
||||
libc_common_src_files += \
|
||||
bionic/__FD_chk.cpp \
|
||||
bionic/__fgets_chk.cpp \
|
||||
bionic/__fread_chk.cpp \
|
||||
bionic/__fwrite_chk.cpp \
|
||||
bionic/__getcwd_chk.cpp \
|
||||
bionic/__memchr_chk.cpp \
|
||||
bionic/__memmove_chk.cpp \
|
||||
bionic/__memrchr_chk.cpp \
|
||||
@@ -575,10 +578,6 @@ libc_common_cflags := \
|
||||
-D_LIBC=1 \
|
||||
-Wall -Wextra -Wunused \
|
||||
|
||||
ifneq ($(TARGET_USES_LOGD),false)
|
||||
libc_common_cflags += -DTARGET_USES_LOGD
|
||||
endif
|
||||
|
||||
use_clang := $(USE_CLANG_PLATFORM_BUILD)
|
||||
|
||||
# Clang/llvm has incompatible long double (fp128) for x86_64.
|
||||
@@ -624,7 +623,6 @@ libc_common_conlyflags := \
|
||||
|
||||
# Define some common cppflags
|
||||
libc_common_cppflags := \
|
||||
-std=gnu++11
|
||||
|
||||
# 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:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
|
||||
int setpgid(pid_t, pid_t) all
|
||||
pid_t vfork(void) arm
|
||||
int setregid:setregid32(gid_t, gid_t) arm,x86
|
||||
int setregid:setregid(gid_t, gid_t) arm64,mips,mips64,x86_64
|
||||
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
|
||||
|
||||
# vdso stuff.
|
||||
int clock_gettime(clockid_t, timespec*) arm,mips,mips64,x86
|
||||
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86_64
|
||||
int gettimeofday(timeval*, timezone*) arm,mips,mips64,x86
|
||||
int __gettimeofday:gettimeofday(timeval*, timezone*) arm64,x86_64
|
||||
int clock_gettime(clockid_t, timespec*) arm,mips,mips64
|
||||
int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86,x86_64
|
||||
int gettimeofday(timeval*, timezone*) arm,mips,mips64
|
||||
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/_exit_with_stack_teardown.S \
|
||||
arch-arm/bionic/libgcc_compat.c \
|
||||
arch-arm/bionic/libgcc_protect_unwind.c \
|
||||
arch-arm/bionic/__restore.S \
|
||||
arch-arm/bionic/setjmp.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_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
|
||||
ldrb r3, [r0]
|
||||
cbz r3, strcat_r0_scan_done
|
||||
cbz r3, .L_strcat_r0_scan_done
|
||||
add r0, #1
|
||||
.endm // m_scan_byte
|
||||
|
||||
@@ -84,10 +84,10 @@ ENTRY(strcat)
|
||||
// Quick check to see if src is empty.
|
||||
ldrb r2, [r1]
|
||||
pld [r1, #0]
|
||||
cbnz r2, strcat_continue
|
||||
cbnz r2, .L_strcat_continue
|
||||
bx lr
|
||||
|
||||
strcat_continue:
|
||||
.L_strcat_continue:
|
||||
// To speed up really small dst strings, unroll checking the first 4 bytes.
|
||||
m_push
|
||||
m_scan_byte
|
||||
@@ -96,95 +96,95 @@ strcat_continue:
|
||||
m_scan_byte
|
||||
|
||||
ands r3, r0, #7
|
||||
beq strcat_mainloop
|
||||
beq .L_strcat_mainloop
|
||||
|
||||
// Align to a double word (64 bits).
|
||||
rsb r3, r3, #8
|
||||
lsls ip, r3, #31
|
||||
beq strcat_align_to_32
|
||||
beq .L_strcat_align_to_32
|
||||
|
||||
ldrb r5, [r0]
|
||||
cbz r5, strcat_r0_scan_done
|
||||
cbz r5, .L_strcat_r0_scan_done
|
||||
add r0, r0, #1
|
||||
|
||||
strcat_align_to_32:
|
||||
bcc strcat_align_to_64
|
||||
.L_strcat_align_to_32:
|
||||
bcc .L_strcat_align_to_64
|
||||
|
||||
ldrb r2, [r0]
|
||||
cbz r2, strcat_r0_scan_done
|
||||
cbz r2, .L_strcat_r0_scan_done
|
||||
add r0, r0, #1
|
||||
ldrb r4, [r0]
|
||||
cbz r4, strcat_r0_scan_done
|
||||
cbz r4, .L_strcat_r0_scan_done
|
||||
add r0, r0, #1
|
||||
|
||||
strcat_align_to_64:
|
||||
.L_strcat_align_to_64:
|
||||
tst r3, #4
|
||||
beq strcat_mainloop
|
||||
beq .L_strcat_mainloop
|
||||
ldr r3, [r0], #4
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcat_zero_in_second_register
|
||||
b strcat_mainloop
|
||||
bne .L_strcat_zero_in_second_register
|
||||
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
|
||||
// new code doesn't win until after about 8 bytes.
|
||||
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
|
||||
m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
|
||||
m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r5, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish
|
||||
m_copy_byte reg=r5, cmd=cbnz, label=.L_strcpy_continue
|
||||
|
||||
strcpy_finish:
|
||||
.L_strcpy_finish:
|
||||
m_pop
|
||||
|
||||
strcpy_continue:
|
||||
.L_strcpy_continue:
|
||||
ands r3, r0, #7
|
||||
beq strcpy_check_src_align
|
||||
beq .L_strcpy_check_src_align
|
||||
|
||||
// Align to a double word (64 bits).
|
||||
rsb r3, r3, #8
|
||||
lsls ip, r3, #31
|
||||
beq strcpy_align_to_32
|
||||
beq .L_strcpy_align_to_32
|
||||
|
||||
ldrb r2, [r1], #1
|
||||
strb r2, [r0], #1
|
||||
cbz r2, strcpy_complete
|
||||
cbz r2, .L_strcpy_complete
|
||||
|
||||
strcpy_align_to_32:
|
||||
bcc strcpy_align_to_64
|
||||
.L_strcpy_align_to_32:
|
||||
bcc .L_strcpy_align_to_64
|
||||
|
||||
ldrb r2, [r1], #1
|
||||
strb r2, [r0], #1
|
||||
cbz r2, strcpy_complete
|
||||
cbz r2, .L_strcpy_complete
|
||||
ldrb r2, [r1], #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
|
||||
beq strcpy_check_src_align
|
||||
beq .L_strcpy_check_src_align
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
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
|
||||
// is also aligned to a double word.
|
||||
ands r3, r1, #7
|
||||
bne strcpy_unaligned_copy
|
||||
bne .L_strcpy_unaligned_copy
|
||||
|
||||
.p2align 2
|
||||
strcpy_mainloop:
|
||||
.L_strcpy_mainloop:
|
||||
ldrd r2, r3, [r1], #8
|
||||
|
||||
pld [r1, #64]
|
||||
@@ -192,128 +192,128 @@ strcpy_mainloop:
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_second_register
|
||||
bne .L_strcpy_zero_in_second_register
|
||||
|
||||
strd r2, r3, [r0], #8
|
||||
b strcpy_mainloop
|
||||
b .L_strcpy_mainloop
|
||||
|
||||
strcpy_complete:
|
||||
.L_strcpy_complete:
|
||||
m_pop
|
||||
|
||||
strcpy_zero_in_first_register:
|
||||
.L_strcpy_zero_in_first_register:
|
||||
lsls lr, ip, #17
|
||||
bne strcpy_copy1byte
|
||||
bcs strcpy_copy2bytes
|
||||
bne .L_strcpy_copy1byte
|
||||
bcs .L_strcpy_copy2bytes
|
||||
lsls ip, ip, #1
|
||||
bne strcpy_copy3bytes
|
||||
bne .L_strcpy_copy3bytes
|
||||
|
||||
strcpy_copy4bytes:
|
||||
.L_strcpy_copy4bytes:
|
||||
// Copy 4 bytes to the destiniation.
|
||||
str r2, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_copy1byte:
|
||||
.L_strcpy_copy1byte:
|
||||
strb r2, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_copy2bytes:
|
||||
.L_strcpy_copy2bytes:
|
||||
strh r2, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_copy3bytes:
|
||||
.L_strcpy_copy3bytes:
|
||||
strh r2, [r0], #2
|
||||
lsr r2, #16
|
||||
strb r2, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_zero_in_second_register:
|
||||
.L_strcpy_zero_in_second_register:
|
||||
lsls lr, ip, #17
|
||||
bne strcpy_copy5bytes
|
||||
bcs strcpy_copy6bytes
|
||||
bne .L_strcpy_copy5bytes
|
||||
bcs .L_strcpy_copy6bytes
|
||||
lsls ip, ip, #1
|
||||
bne strcpy_copy7bytes
|
||||
bne .L_strcpy_copy7bytes
|
||||
|
||||
// Copy 8 bytes to the destination.
|
||||
strd r2, r3, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_copy5bytes:
|
||||
.L_strcpy_copy5bytes:
|
||||
str r2, [r0], #4
|
||||
strb r3, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_copy6bytes:
|
||||
.L_strcpy_copy6bytes:
|
||||
str r2, [r0], #4
|
||||
strh r3, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_copy7bytes:
|
||||
.L_strcpy_copy7bytes:
|
||||
str r2, [r0], #4
|
||||
strh r3, [r0], #2
|
||||
lsr r3, #16
|
||||
strb r3, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_unaligned_copy:
|
||||
.L_strcpy_unaligned_copy:
|
||||
// Dst is aligned to a double word, while src is at an unknown alignment.
|
||||
// There are 7 different versions of the unaligned copy code
|
||||
// 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
|
||||
// be read without potentially crossing a page boundary.
|
||||
tbb [pc, r3]
|
||||
strcpy_unaligned_branchtable:
|
||||
.L_strcpy_unaligned_branchtable:
|
||||
.byte 0
|
||||
.byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign7 - .L_strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign6 - .L_strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign5 - .L_strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign4 - .L_strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign3 - .L_strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign2 - .L_strcpy_unaligned_branchtable)/2)
|
||||
.byte ((.L_strcpy_unalign1 - .L_strcpy_unaligned_branchtable)/2)
|
||||
|
||||
.p2align 2
|
||||
// Can read 7 bytes before possibly crossing a page.
|
||||
strcpy_unalign7:
|
||||
.L_strcpy_unalign7:
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
|
||||
ldrb r3, [r1]
|
||||
cbz r3, strcpy_unalign7_copy5bytes
|
||||
cbz r3, .L_strcpy_unalign7_copy5bytes
|
||||
ldrb r4, [r1, #1]
|
||||
cbz r4, strcpy_unalign7_copy6bytes
|
||||
cbz r4, .L_strcpy_unalign7_copy6bytes
|
||||
ldrb r5, [r1, #2]
|
||||
cbz r5, strcpy_unalign7_copy7bytes
|
||||
cbz r5, .L_strcpy_unalign7_copy7bytes
|
||||
|
||||
ldr r3, [r1], #4
|
||||
pld [r1, #64]
|
||||
|
||||
lsrs ip, r3, #24
|
||||
strd r2, r3, [r0], #8
|
||||
beq strcpy_unalign_return
|
||||
b strcpy_unalign7
|
||||
beq .L_strcpy_unalign_return
|
||||
b .L_strcpy_unalign7
|
||||
|
||||
strcpy_unalign7_copy5bytes:
|
||||
.L_strcpy_unalign7_copy5bytes:
|
||||
str r2, [r0], #4
|
||||
strb r3, [r0]
|
||||
strcpy_unalign_return:
|
||||
.L_strcpy_unalign_return:
|
||||
m_pop
|
||||
|
||||
strcpy_unalign7_copy6bytes:
|
||||
.L_strcpy_unalign7_copy6bytes:
|
||||
str r2, [r0], #4
|
||||
strb r3, [r0], #1
|
||||
strb r4, [r0], #1
|
||||
m_pop
|
||||
|
||||
strcpy_unalign7_copy7bytes:
|
||||
.L_strcpy_unalign7_copy7bytes:
|
||||
str r2, [r0], #4
|
||||
strb r3, [r0], #1
|
||||
strb r4, [r0], #1
|
||||
@@ -322,41 +322,41 @@ strcpy_unalign7_copy7bytes:
|
||||
|
||||
.p2align 2
|
||||
// Can read 6 bytes before possibly crossing a page.
|
||||
strcpy_unalign6:
|
||||
.L_strcpy_unalign6:
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
|
||||
ldrb r4, [r1]
|
||||
cbz r4, strcpy_unalign_copy5bytes
|
||||
cbz r4, .L_strcpy_unalign_copy5bytes
|
||||
ldrb r5, [r1, #1]
|
||||
cbz r5, strcpy_unalign_copy6bytes
|
||||
cbz r5, .L_strcpy_unalign_copy6bytes
|
||||
|
||||
ldr r3, [r1], #4
|
||||
pld [r1, #64]
|
||||
|
||||
tst r3, #0xff0000
|
||||
beq strcpy_copy7bytes
|
||||
beq .L_strcpy_copy7bytes
|
||||
lsrs ip, r3, #24
|
||||
strd r2, r3, [r0], #8
|
||||
beq strcpy_unalign_return
|
||||
b strcpy_unalign6
|
||||
beq .L_strcpy_unalign_return
|
||||
b .L_strcpy_unalign6
|
||||
|
||||
.p2align 2
|
||||
// Can read 5 bytes before possibly crossing a page.
|
||||
strcpy_unalign5:
|
||||
.L_strcpy_unalign5:
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
|
||||
ldrb r4, [r1]
|
||||
cbz r4, strcpy_unalign_copy5bytes
|
||||
cbz r4, .L_strcpy_unalign_copy5bytes
|
||||
|
||||
ldr r3, [r1], #4
|
||||
|
||||
@@ -365,17 +365,17 @@ strcpy_unalign5:
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_second_register
|
||||
bne .L_strcpy_zero_in_second_register
|
||||
|
||||
strd r2, r3, [r0], #8
|
||||
b strcpy_unalign5
|
||||
b .L_strcpy_unalign5
|
||||
|
||||
strcpy_unalign_copy5bytes:
|
||||
.L_strcpy_unalign_copy5bytes:
|
||||
str r2, [r0], #4
|
||||
strb r4, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_unalign_copy6bytes:
|
||||
.L_strcpy_unalign_copy6bytes:
|
||||
str r2, [r0], #4
|
||||
strb r4, [r0], #1
|
||||
strb r5, [r0]
|
||||
@@ -383,13 +383,13 @@ strcpy_unalign_copy6bytes:
|
||||
|
||||
.p2align 2
|
||||
// Can read 4 bytes before possibly crossing a page.
|
||||
strcpy_unalign4:
|
||||
.L_strcpy_unalign4:
|
||||
ldr r2, [r1], #4
|
||||
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
|
||||
ldr r3, [r1], #4
|
||||
pld [r1, #64]
|
||||
@@ -397,20 +397,20 @@ strcpy_unalign4:
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_second_register
|
||||
bne .L_strcpy_zero_in_second_register
|
||||
|
||||
strd r2, r3, [r0], #8
|
||||
b strcpy_unalign4
|
||||
b .L_strcpy_unalign4
|
||||
|
||||
.p2align 2
|
||||
// Can read 3 bytes before possibly crossing a page.
|
||||
strcpy_unalign3:
|
||||
.L_strcpy_unalign3:
|
||||
ldrb r2, [r1]
|
||||
cbz r2, strcpy_unalign3_copy1byte
|
||||
cbz r2, .L_strcpy_unalign3_copy1byte
|
||||
ldrb r3, [r1, #1]
|
||||
cbz r3, strcpy_unalign3_copy2bytes
|
||||
cbz r3, .L_strcpy_unalign3_copy2bytes
|
||||
ldrb r4, [r1, #2]
|
||||
cbz r4, strcpy_unalign3_copy3bytes
|
||||
cbz r4, .L_strcpy_unalign3_copy3bytes
|
||||
|
||||
ldr r2, [r1], #4
|
||||
ldr r3, [r1], #4
|
||||
@@ -418,26 +418,26 @@ strcpy_unalign3:
|
||||
pld [r1, #64]
|
||||
|
||||
lsrs lr, r2, #24
|
||||
beq strcpy_copy4bytes
|
||||
beq .L_strcpy_copy4bytes
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_second_register
|
||||
bne .L_strcpy_zero_in_second_register
|
||||
|
||||
strd r2, r3, [r0], #8
|
||||
b strcpy_unalign3
|
||||
b .L_strcpy_unalign3
|
||||
|
||||
strcpy_unalign3_copy1byte:
|
||||
.L_strcpy_unalign3_copy1byte:
|
||||
strb r2, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_unalign3_copy2bytes:
|
||||
.L_strcpy_unalign3_copy2bytes:
|
||||
strb r2, [r0], #1
|
||||
strb r3, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_unalign3_copy3bytes:
|
||||
.L_strcpy_unalign3_copy3bytes:
|
||||
strb r2, [r0], #1
|
||||
strb r3, [r0], #1
|
||||
strb r4, [r0]
|
||||
@@ -445,34 +445,34 @@ strcpy_unalign3_copy3bytes:
|
||||
|
||||
.p2align 2
|
||||
// Can read 2 bytes before possibly crossing a page.
|
||||
strcpy_unalign2:
|
||||
.L_strcpy_unalign2:
|
||||
ldrb r2, [r1]
|
||||
cbz r2, strcpy_unalign_copy1byte
|
||||
cbz r2, .L_strcpy_unalign_copy1byte
|
||||
ldrb r4, [r1, #1]
|
||||
cbz r4, strcpy_unalign_copy2bytes
|
||||
cbz r4, .L_strcpy_unalign_copy2bytes
|
||||
|
||||
ldr r2, [r1], #4
|
||||
ldr r3, [r1], #4
|
||||
pld [r1, #64]
|
||||
|
||||
tst r2, #0xff0000
|
||||
beq strcpy_copy3bytes
|
||||
beq .L_strcpy_copy3bytes
|
||||
lsrs ip, r2, #24
|
||||
beq strcpy_copy4bytes
|
||||
beq .L_strcpy_copy4bytes
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_second_register
|
||||
bne .L_strcpy_zero_in_second_register
|
||||
|
||||
strd r2, r3, [r0], #8
|
||||
b strcpy_unalign2
|
||||
b .L_strcpy_unalign2
|
||||
|
||||
.p2align 2
|
||||
// Can read 1 byte before possibly crossing a page.
|
||||
strcpy_unalign1:
|
||||
.L_strcpy_unalign1:
|
||||
ldrb r2, [r1]
|
||||
cbz r2, strcpy_unalign_copy1byte
|
||||
cbz r2, .L_strcpy_unalign_copy1byte
|
||||
|
||||
ldr r2, [r1], #4
|
||||
ldr r3, [r1], #4
|
||||
@@ -482,27 +482,27 @@ strcpy_unalign1:
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_first_register
|
||||
bne .L_strcpy_zero_in_first_register
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcpy_zero_in_second_register
|
||||
bne .L_strcpy_zero_in_second_register
|
||||
|
||||
strd r2, r3, [r0], #8
|
||||
b strcpy_unalign1
|
||||
b .L_strcpy_unalign1
|
||||
|
||||
strcpy_unalign_copy1byte:
|
||||
.L_strcpy_unalign_copy1byte:
|
||||
strb r2, [r0]
|
||||
m_pop
|
||||
|
||||
strcpy_unalign_copy2bytes:
|
||||
.L_strcpy_unalign_copy2bytes:
|
||||
strb r2, [r0], #1
|
||||
strb r4, [r0]
|
||||
m_pop
|
||||
|
||||
.p2align 2
|
||||
strcat_mainloop:
|
||||
.L_strcat_mainloop:
|
||||
ldrd r2, r3, [r0], #8
|
||||
|
||||
pld [r0, #64]
|
||||
@@ -510,59 +510,59 @@ strcat_mainloop:
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcat_zero_in_first_register
|
||||
bne .L_strcat_zero_in_first_register
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne strcat_zero_in_second_register
|
||||
b strcat_mainloop
|
||||
bne .L_strcat_zero_in_second_register
|
||||
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.
|
||||
pld [r1, #0]
|
||||
lsls lr, ip, #17
|
||||
bne strcat_sub8
|
||||
bcs strcat_sub7
|
||||
bne .L_strcat_sub8
|
||||
bcs .L_strcat_sub7
|
||||
lsls ip, ip, #1
|
||||
bne strcat_sub6
|
||||
bne .L_strcat_sub6
|
||||
|
||||
sub r0, r0, #5
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
|
||||
strcat_sub8:
|
||||
.L_strcat_sub8:
|
||||
sub r0, r0, #8
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
|
||||
strcat_sub7:
|
||||
.L_strcat_sub7:
|
||||
sub r0, r0, #7
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
|
||||
strcat_sub6:
|
||||
.L_strcat_sub6:
|
||||
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.
|
||||
pld [r1, #0]
|
||||
lsls lr, ip, #17
|
||||
bne strcat_sub4
|
||||
bcs strcat_sub3
|
||||
bne .L_strcat_sub4
|
||||
bcs .L_strcat_sub3
|
||||
lsls ip, ip, #1
|
||||
bne strcat_sub2
|
||||
bne .L_strcat_sub2
|
||||
|
||||
sub r0, r0, #1
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
|
||||
strcat_sub4:
|
||||
.L_strcat_sub4:
|
||||
sub r0, r0, #4
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
|
||||
strcat_sub3:
|
||||
.L_strcat_sub3:
|
||||
sub r0, r0, #3
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
|
||||
strcat_sub2:
|
||||
.L_strcat_sub2:
|
||||
sub r0, r0, #2
|
||||
b strcat_r0_scan_done
|
||||
b .L_strcat_r0_scan_done
|
||||
END(strcat)
|
||||
|
||||
@@ -65,38 +65,38 @@ ENTRY(strlen)
|
||||
mov r1, r0
|
||||
|
||||
ands r3, r0, #7
|
||||
beq mainloop
|
||||
beq .L_mainloop
|
||||
|
||||
// Align to a double word (64 bits).
|
||||
rsb r3, r3, #8
|
||||
lsls ip, r3, #31
|
||||
beq align_to_32
|
||||
beq .L_align_to_32
|
||||
|
||||
ldrb r2, [r1], #1
|
||||
cbz r2, update_count_and_return
|
||||
cbz r2, .L_update_count_and_return
|
||||
|
||||
align_to_32:
|
||||
bcc align_to_64
|
||||
.L_align_to_32:
|
||||
bcc .L_align_to_64
|
||||
ands ip, r3, #2
|
||||
beq align_to_64
|
||||
beq .L_align_to_64
|
||||
|
||||
ldrb r2, [r1], #1
|
||||
cbz r2, update_count_and_return
|
||||
cbz r2, .L_update_count_and_return
|
||||
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
|
||||
beq mainloop
|
||||
beq .L_mainloop
|
||||
ldr r3, [r1], #4
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne zero_in_second_register
|
||||
bne .L_zero_in_second_register
|
||||
|
||||
.p2align 2
|
||||
mainloop:
|
||||
.L_mainloop:
|
||||
ldrd r2, r3, [r1], #8
|
||||
|
||||
pld [r1, #64]
|
||||
@@ -104,62 +104,62 @@ mainloop:
|
||||
sub ip, r2, #0x01010101
|
||||
bic ip, ip, r2
|
||||
ands ip, ip, #0x80808080
|
||||
bne zero_in_first_register
|
||||
bne .L_zero_in_first_register
|
||||
|
||||
sub ip, r3, #0x01010101
|
||||
bic ip, ip, r3
|
||||
ands ip, ip, #0x80808080
|
||||
bne zero_in_second_register
|
||||
b mainloop
|
||||
bne .L_zero_in_second_register
|
||||
b .L_mainloop
|
||||
|
||||
update_count_and_return:
|
||||
.L_update_count_and_return:
|
||||
sub r0, r1, r0
|
||||
sub r0, r0, #1
|
||||
bx lr
|
||||
|
||||
zero_in_first_register:
|
||||
.L_zero_in_first_register:
|
||||
sub r0, r1, r0
|
||||
lsls r3, ip, #17
|
||||
bne sub8_and_return
|
||||
bcs sub7_and_return
|
||||
bne .L_sub8_and_return
|
||||
bcs .L_sub7_and_return
|
||||
lsls ip, ip, #1
|
||||
bne sub6_and_return
|
||||
bne .L_sub6_and_return
|
||||
|
||||
sub r0, r0, #5
|
||||
bx lr
|
||||
|
||||
sub8_and_return:
|
||||
.L_sub8_and_return:
|
||||
sub r0, r0, #8
|
||||
bx lr
|
||||
|
||||
sub7_and_return:
|
||||
.L_sub7_and_return:
|
||||
sub r0, r0, #7
|
||||
bx lr
|
||||
|
||||
sub6_and_return:
|
||||
.L_sub6_and_return:
|
||||
sub r0, r0, #6
|
||||
bx lr
|
||||
|
||||
zero_in_second_register:
|
||||
.L_zero_in_second_register:
|
||||
sub r0, r1, r0
|
||||
lsls r3, ip, #17
|
||||
bne sub4_and_return
|
||||
bcs sub3_and_return
|
||||
bne .L_sub4_and_return
|
||||
bcs .L_sub3_and_return
|
||||
lsls ip, ip, #1
|
||||
bne sub2_and_return
|
||||
bne .L_sub2_and_return
|
||||
|
||||
sub r0, r0, #1
|
||||
bx lr
|
||||
|
||||
sub4_and_return:
|
||||
.L_sub4_and_return:
|
||||
sub r0, r0, #4
|
||||
bx lr
|
||||
|
||||
sub3_and_return:
|
||||
.L_sub3_and_return:
|
||||
sub r0, r0, #3
|
||||
bx lr
|
||||
|
||||
sub2_and_return:
|
||||
.L_sub2_and_return:
|
||||
sub r0, r0, #2
|
||||
bx lr
|
||||
END(strlen)
|
||||
|
||||
@@ -133,8 +133,7 @@ ENTRY_PRIVATE(MEMCPY_BASE)
|
||||
strbcs ip, [r0], #1
|
||||
strbcs lr, [r0], #1
|
||||
|
||||
ldmfd sp!, {r0, lr}
|
||||
bx lr
|
||||
ldmfd sp!, {r0, pc}
|
||||
END(MEMCPY_BASE)
|
||||
|
||||
ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
|
||||
|
||||
@@ -69,12 +69,9 @@ END(bzero)
|
||||
ENTRY(memset)
|
||||
// The neon memset only wins for less than 132.
|
||||
cmp r2, #132
|
||||
bhi __memset_large_copy
|
||||
|
||||
stmfd sp!, {r0}
|
||||
.cfi_def_cfa_offset 4
|
||||
.cfi_rel_offset r0, 0
|
||||
bhi .L_memset_large_copy
|
||||
|
||||
mov r3, r0
|
||||
vdup.8 q0, r1
|
||||
|
||||
/* 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 */
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r0]!
|
||||
vst1.8 {d0 - d3}, [r3]!
|
||||
bhs 1b
|
||||
|
||||
2: /* less than 32 left */
|
||||
@@ -93,22 +90,20 @@ ENTRY(memset)
|
||||
beq 3f
|
||||
|
||||
// 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) */
|
||||
movs ip, r2, lsl #29
|
||||
bcc 1f
|
||||
vst1.8 {d0}, [r0]!
|
||||
vst1.8 {d0}, [r3]!
|
||||
1: bge 2f
|
||||
vst1.32 {d0[0]}, [r0]!
|
||||
vst1.32 {d0[0]}, [r3]!
|
||||
2: movs ip, r2, lsl #31
|
||||
strbmi r1, [r0], #1
|
||||
strbcs r1, [r0], #1
|
||||
strbcs r1, [r0], #1
|
||||
ldmfd sp!, {r0}
|
||||
strbmi r1, [r3], #1
|
||||
strbcs r1, [r3], #1
|
||||
strbcs r1, [r3], #1
|
||||
bx lr
|
||||
END(memset)
|
||||
|
||||
ENTRY_PRIVATE(__memset_large_copy)
|
||||
.L_memset_large_copy:
|
||||
/* compute the offset to align the destination
|
||||
* offset = (4-(src&3))&3 = -src & 3
|
||||
*/
|
||||
@@ -136,8 +131,7 @@ ENTRY_PRIVATE(__memset_large_copy)
|
||||
strbcs r1, [r0], #1
|
||||
strbmi r1, [r0], #1
|
||||
subs r2, r2, r3
|
||||
popls {r0, r4-r7, lr} /* return */
|
||||
bxls lr
|
||||
popls {r0, r4-r7, pc} /* return */
|
||||
|
||||
/* align the destination to a cache-line */
|
||||
mov r12, r1
|
||||
@@ -180,9 +174,8 @@ ENTRY_PRIVATE(__memset_large_copy)
|
||||
strhmi r1, [r0], #2
|
||||
movs r2, r2, lsl #2
|
||||
strbcs r1, [r0]
|
||||
ldmfd sp!, {r0, r4-r7, lr}
|
||||
bx lr
|
||||
END(__memset_large_copy)
|
||||
ldmfd sp!, {r0, r4-r7, pc}
|
||||
END(memset)
|
||||
|
||||
.data
|
||||
error_string:
|
||||
|
||||
@@ -221,8 +221,7 @@ ENTRY(memcmp)
|
||||
bne 8b
|
||||
|
||||
9: /* restore registers and return */
|
||||
ldmfd sp!, {r4, lr}
|
||||
bx lr
|
||||
ldmfd sp!, {r4, pc}
|
||||
|
||||
10: /* process less than 12 bytes */
|
||||
cmp r2, #0
|
||||
|
||||
@@ -194,8 +194,7 @@ ENTRY(memcpy)
|
||||
|
||||
/* we're done! restore everything and return */
|
||||
1: ldmfd sp!, {r5-r11}
|
||||
ldmfd sp!, {r0, r4, lr}
|
||||
bx lr
|
||||
ldmfd sp!, {r0, r4, pc}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
@@ -385,8 +384,7 @@ ENTRY(memcpy)
|
||||
|
||||
/* we're done! restore sp and spilled registers and return */
|
||||
add sp, sp, #28
|
||||
ldmfd sp!, {r0, r4, lr}
|
||||
bx lr
|
||||
ldmfd sp!, {r0, r4, pc}
|
||||
END(memcpy)
|
||||
|
||||
// Only reached when the __memcpy_chk check fails.
|
||||
|
||||
@@ -82,8 +82,7 @@ ENTRY(memset)
|
||||
strbcs r1, [r0], #1
|
||||
strbmi r1, [r0], #1
|
||||
subs r2, r2, r3
|
||||
popls {r0, r4-r7, lr} /* return */
|
||||
bxls lr
|
||||
popls {r0, r4-r7, pc} /* return */
|
||||
|
||||
/* align the destination to a cache-line */
|
||||
mov r12, r1
|
||||
@@ -126,8 +125,7 @@ ENTRY(memset)
|
||||
strhmi r1, [r0], #2
|
||||
movs r2, r2, lsl #2
|
||||
strbcs r1, [r0]
|
||||
ldmfd sp!, {r0, r4-r7, lr}
|
||||
bx lr
|
||||
ldmfd sp!, {r0, r4-r7, pc}
|
||||
END(memset)
|
||||
|
||||
.data
|
||||
|
||||
@@ -118,6 +118,5 @@ ENTRY_PRIVATE(MEMCPY_BASE)
|
||||
strbcs ip, [r0], #1
|
||||
strbcs lr, [r0], #1
|
||||
|
||||
ldmfd sp!, {r0, lr}
|
||||
bx lr
|
||||
ldmfd sp!, {r0, pc}
|
||||
END(MEMCPY_BASE)
|
||||
|
||||
@@ -69,10 +69,7 @@ END(bzero)
|
||||
|
||||
/* memset() returns its first argument. */
|
||||
ENTRY(memset)
|
||||
stmfd sp!, {r0}
|
||||
.cfi_def_cfa_offset 4
|
||||
.cfi_rel_offset r0, 0
|
||||
|
||||
mov r3, r0
|
||||
vdup.8 q0, r1
|
||||
|
||||
/* 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 */
|
||||
subs r2, r2, #32
|
||||
vst1.8 {d0 - d3}, [r0]!
|
||||
vst1.8 {d0 - d3}, [r3]!
|
||||
bhs 1b
|
||||
|
||||
2: /* less than 32 left */
|
||||
@@ -91,18 +88,17 @@ ENTRY(memset)
|
||||
beq 3f
|
||||
|
||||
// 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) */
|
||||
movs ip, r2, lsl #29
|
||||
bcc 1f
|
||||
vst1.8 {d0}, [r0]!
|
||||
vst1.8 {d0}, [r3]!
|
||||
1: bge 2f
|
||||
vst1.32 {d0[0]}, [r0]!
|
||||
vst1.32 {d0[0]}, [r3]!
|
||||
2: movs ip, r2, lsl #31
|
||||
strbmi r1, [r0], #1
|
||||
strbcs r1, [r0], #1
|
||||
strbcs r1, [r0], #1
|
||||
ldmfd sp!, {r0}
|
||||
strbmi r1, [r3], #1
|
||||
strbcs r1, [r3], #1
|
||||
strbcs r1, [r3], #1
|
||||
bx lr
|
||||
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>
|
||||
|
||||
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 x1, xzr
|
||||
mov x2, xzr
|
||||
|
||||
@@ -37,6 +37,14 @@ ENTRY(vfork)
|
||||
.set noreorder
|
||||
.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 a1, 0
|
||||
li a2, 0
|
||||
|
||||
@@ -46,6 +46,12 @@ LEAF(vfork,FRAMESZ)
|
||||
PTR_SUBU sp, FRAMESZ
|
||||
#endif
|
||||
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)
|
||||
move a1, $0
|
||||
move a2, $0
|
||||
|
||||
@@ -34,6 +34,12 @@ ENTRY(vfork)
|
||||
popl %ecx // Grab the return address.
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.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
|
||||
int $0x80
|
||||
cmpl $-MAX_ERRNO, %eax
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(clock_gettime)
|
||||
ENTRY(__clock_gettime)
|
||||
pushl %ebx
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset ebx, 0
|
||||
@@ -23,4 +23,4 @@ ENTRY(clock_gettime)
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
ret
|
||||
END(clock_gettime)
|
||||
END(__clock_gettime)
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(gettimeofday)
|
||||
ENTRY(__gettimeofday)
|
||||
pushl %ebx
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset ebx, 0
|
||||
@@ -23,4 +23,4 @@ ENTRY(gettimeofday)
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
ret
|
||||
END(gettimeofday)
|
||||
END(__gettimeofday)
|
||||
@@ -32,6 +32,12 @@
|
||||
|
||||
ENTRY(vfork)
|
||||
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
|
||||
syscall
|
||||
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 <string.h>
|
||||
|
||||
#include "private/bionic_lock.h"
|
||||
#include "private/bionic_systrace.h"
|
||||
#include "private/libc_logging.h"
|
||||
|
||||
@@ -29,12 +30,17 @@
|
||||
|
||||
#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 uint64_t g_tags = 0;
|
||||
static uint64_t g_tags;
|
||||
static int g_trace_marker_fd = -1;
|
||||
|
||||
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
|
||||
// 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
|
||||
@@ -42,32 +48,39 @@ static bool should_trace() {
|
||||
// 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.
|
||||
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) {
|
||||
__system_property_set("debug.atrace.tags.enableflags", "0");
|
||||
g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
|
||||
if (g_pinfo == NULL) {
|
||||
return false;
|
||||
}
|
||||
__system_property_set(SYSTRACE_PROPERTY_NAME, "0");
|
||||
g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 serial will also change, so the costly system_property_read function
|
||||
// can be avoided by calling the much cheaper system_property_serial
|
||||
// first. The values within pinfo may change, but its location is guaranteed
|
||||
// not to move.
|
||||
const uint32_t cur_serial = __system_property_serial(g_pinfo);
|
||||
if (cur_serial != g_serial) {
|
||||
g_serial = cur_serial;
|
||||
char value[PROP_VALUE_MAX];
|
||||
__system_property_read(g_pinfo, 0, value);
|
||||
g_tags = strtoull(value, NULL, 0);
|
||||
if (g_pinfo != NULL) {
|
||||
// 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 serial will also change, so the costly system_property_read function
|
||||
// can be avoided by calling the much cheaper system_property_serial
|
||||
// first. The values within pinfo may change, but its location is guaranteed
|
||||
// not to move.
|
||||
uint32_t cur_serial = __system_property_serial(g_pinfo);
|
||||
if (cur_serial != g_serial) {
|
||||
g_serial = cur_serial;
|
||||
char value[PROP_VALUE_MAX];
|
||||
__system_property_read(g_pinfo, 0, value);
|
||||
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.
|
||||
return ((g_tags & ATRACE_TAG_BIONIC) != 0);
|
||||
static int get_trace_marker_fd() {
|
||||
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) {
|
||||
@@ -75,11 +88,9 @@ ScopedTrace::ScopedTrace(const char* message) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_trace_marker_fd == -1) {
|
||||
g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
|
||||
if (g_trace_marker_fd == -1) {
|
||||
__libc_fatal("Could not open kernel trace file: %s\n", strerror(errno));
|
||||
}
|
||||
int trace_marker_fd = get_trace_marker_fd();
|
||||
if (trace_marker_fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
char buf[length + WRITE_OFFSET];
|
||||
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
|
||||
if (static_cast<size_t>(wbytes) != len) {
|
||||
__libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
|
||||
}
|
||||
// Tracing may stop just after checking property and before writing the message.
|
||||
// So the write is acceptable to fail. See b/20666100.
|
||||
TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
|
||||
}
|
||||
|
||||
ScopedTrace::~ScopedTrace() {
|
||||
@@ -100,10 +109,10 @@ ScopedTrace::~ScopedTrace() {
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, "E", 1));
|
||||
|
||||
// Error while writing
|
||||
if (static_cast<size_t>(wbytes) != 1) {
|
||||
__libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
|
||||
int trace_marker_fd = get_trace_marker_fd();
|
||||
if (trace_marker_fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
TEMP_FAILURE_RETRY(write(trace_marker_fd, "E", 1));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <elf.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -35,14 +36,22 @@
|
||||
#include "debug_mapinfo.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:
|
||||
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
|
||||
static mapinfo_t* parse_maps_line(char* line) {
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
uintptr_t offset;
|
||||
char permissions[4];
|
||||
int name_pos;
|
||||
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start,
|
||||
&end, &name_pos) < 2) {
|
||||
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
|
||||
&end, permissions, &offset, &name_pos) < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -59,6 +68,14 @@ static mapinfo_t* parse_maps_line(char* line) {
|
||||
if (mi) {
|
||||
mi->start = start;
|
||||
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);
|
||||
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.
|
||||
__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) {
|
||||
for (; mi != NULL; mi = mi->next) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ struct mapinfo_t {
|
||||
struct mapinfo_t* next;
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
uintptr_t offset;
|
||||
uintptr_t load_base;
|
||||
bool load_base_read;
|
||||
char name[];
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#undef _FORTIFY_SOURCE
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -64,18 +64,15 @@ char** environ;
|
||||
// Declared in "private/bionic_ssp.h".
|
||||
uintptr_t __stack_chk_guard = 0;
|
||||
|
||||
/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped
|
||||
* in memory. Beware: all writes to libc 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
|
||||
* 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
|
||||
* picked up by the libc constructor.
|
||||
*/
|
||||
void __libc_init_tls(KernelArgumentBlock& args) {
|
||||
// Setup for the main thread. For dynamic executables, this is called by the
|
||||
// linker _before_ libc is mapped in memory. This means that all writes to
|
||||
// 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
|
||||
// has to be done later from libc itself (see __libc_init_common).
|
||||
void __libc_init_main_thread(KernelArgumentBlock& args) {
|
||||
__libc_auxv = args.auxv;
|
||||
|
||||
static pthread_internal_t main_thread;
|
||||
@@ -99,6 +96,9 @@ void __libc_init_tls(KernelArgumentBlock& args) {
|
||||
__init_thread(&main_thread);
|
||||
__init_tls(&main_thread);
|
||||
__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;
|
||||
|
||||
__init_alternate_signal_stack(&main_thread);
|
||||
|
||||
@@ -49,16 +49,10 @@
|
||||
#include "libc_init_common.h"
|
||||
#include "pthread_internal.h"
|
||||
|
||||
#include "private/bionic_page.h"
|
||||
#include "private/bionic_tls.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 *);
|
||||
|
||||
static void call_array(void(**list)()) {
|
||||
@@ -90,7 +84,7 @@ __noreturn void __libc_init(void* raw_args,
|
||||
int (*slingshot)(int, char**, char**),
|
||||
structors_array_t const * const structors) {
|
||||
KernelArgumentBlock args(raw_args);
|
||||
__libc_init_tls(args);
|
||||
__libc_init_main_thread(args);
|
||||
__libc_init_AT_SECURE(args);
|
||||
__libc_init_common(args);
|
||||
|
||||
|
||||
@@ -448,7 +448,6 @@ static int __libc_write_stderr(const char* tag, const char* msg) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef TARGET_USES_LOGD
|
||||
static int __libc_open_log_socket() {
|
||||
// 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
|
||||
@@ -486,10 +485,8 @@ struct log_time { // Wire format
|
||||
uint32_t tv_sec;
|
||||
uint32_t tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
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();
|
||||
if (main_log_fd == -1) {
|
||||
// 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[5].iov_base = const_cast<char*>(msg);
|
||||
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])));
|
||||
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) {
|
||||
#ifdef TARGET_USES_LOGD
|
||||
iovec vec[6];
|
||||
char log_id = LOG_ID_EVENTS;
|
||||
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;
|
||||
|
||||
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) {
|
||||
return -1;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
static ThreadLocalBuffer<char, MAXPATHLEN> g_basename_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* endp = NULL;
|
||||
int len;
|
||||
@@ -91,7 +91,12 @@ __LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_s
|
||||
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;
|
||||
int len;
|
||||
int result;
|
||||
@@ -150,14 +155,19 @@ __LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_si
|
||||
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* 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;
|
||||
}
|
||||
|
||||
char* dirname(const char* path) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -133,8 +133,9 @@ static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size
|
||||
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);
|
||||
|
||||
if (entry != NULL) {
|
||||
entry->allocations++;
|
||||
} else {
|
||||
@@ -302,8 +303,6 @@ extern "C" void* leak_malloc(size_t bytes) {
|
||||
|
||||
void* base = g_malloc_dispatch->malloc(size);
|
||||
if (base != NULL) {
|
||||
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
||||
|
||||
uintptr_t backtrace[BACKTRACE_SIZE];
|
||||
size_t numEntries = GET_BACKTRACE(backtrace, BACKTRACE_SIZE);
|
||||
|
||||
@@ -328,8 +327,6 @@ extern "C" void leak_free(void* mem) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
||||
|
||||
// check the guard to make sure it is valid
|
||||
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)) {
|
||||
// decrement the allocations
|
||||
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");
|
||||
return false;
|
||||
} 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);
|
||||
|
||||
if (qtrace == MAP_FAILED) {
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private/android_filesystem_config.h"
|
||||
#include "private/bionic_macros.h"
|
||||
#include "private/ErrnoRestorer.h"
|
||||
#include "private/libc_logging.h"
|
||||
#include "private/ThreadLocalBuffer.h"
|
||||
@@ -66,11 +67,15 @@ struct passwd_state_t {
|
||||
static ThreadLocalBuffer<group_state_t> g_group_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() {
|
||||
group_state_t* result = g_group_tls_buffer.get();
|
||||
if (result != nullptr) {
|
||||
memset(result, 0, sizeof(group_state_t));
|
||||
result->group_.gr_mem = result->group_members_;
|
||||
init_group_state(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -397,17 +402,28 @@ char* getlogin() { // NOLINT: implementing bad function.
|
||||
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_state_t* state = __group_state();
|
||||
if (state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return getgrgid_internal(gid, state);
|
||||
}
|
||||
|
||||
group* gr = android_id_to_group(state, gid);
|
||||
if (gr != NULL) {
|
||||
return gr;
|
||||
static group* getgrnam_internal(const char* name, group_state_t* state) {
|
||||
group* grp = android_name_to_group(state, name);
|
||||
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.
|
||||
@@ -415,11 +431,36 @@ group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
||||
if (state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return getgrnam_internal(name, state);
|
||||
}
|
||||
|
||||
if (android_name_to_group(state, name) != 0) {
|
||||
return &state->group_;
|
||||
static int getgroup_r(bool by_name, const char* name, gid_t gid, struct group* grp, char* buf,
|
||||
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.
|
||||
|
||||
@@ -97,8 +97,11 @@ long sysconf(int name) {
|
||||
case _SC_ATEXIT_MAX: return LONG_MAX; // Unlimited.
|
||||
case _SC_IOV_MAX: return UIO_MAXIOV;
|
||||
|
||||
case _SC_PAGESIZE: // Fall through, PAGESIZE and PAGE_SIZE always hold the same value.
|
||||
case _SC_PAGE_SIZE: return PAGE_SIZE;
|
||||
// _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
|
||||
case _SC_PAGESIZE:
|
||||
case _SC_PAGE_SIZE:
|
||||
return static_cast<long>(getauxval(AT_PAGESZ));
|
||||
|
||||
case _SC_XOPEN_UNIX: return _XOPEN_UNIX;
|
||||
case _SC_AIO_LISTIO_MAX: return _POSIX_AIO_LISTIO_MAX; // Minimum requirement.
|
||||
case _SC_AIO_MAX: return _POSIX_AIO_MAX; // Minimum requirement.
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.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) {
|
||||
long total;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,24 @@
|
||||
#include <sys/auxv.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// x86 has a vdso, but there's nothing useful to us in it.
|
||||
#if defined(__aarch64__) || defined(__x86_64__)
|
||||
#if defined(__aarch64__) || defined(__x86_64__) || defined (__i386__)
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
|
||||
#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_GETTIMEOFDAY_SYMBOL "__vdso_gettimeofday"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "private/bionic_prctl.h"
|
||||
#include "private/libc_logging.h"
|
||||
|
||||
extern "C" int __clock_gettime(int, timespec*);
|
||||
extern "C" int __gettimeofday(timeval*, struct timezone*);
|
||||
|
||||
@@ -46,28 +51,31 @@ enum {
|
||||
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_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) },
|
||||
};
|
||||
}};
|
||||
|
||||
int clock_gettime(int clock_id, timespec* tp) {
|
||||
static int (*vdso_clock_gettime)(int, timespec*) =
|
||||
reinterpret_cast<int (*)(int, timespec*)>(vdso_entries[VDSO_CLOCK_GETTIME].fn);
|
||||
int (*vdso_clock_gettime)(int, timespec*) =
|
||||
reinterpret_cast<int (*)(int, timespec*)>(vdso.entries[VDSO_CLOCK_GETTIME].fn);
|
||||
return vdso_clock_gettime(clock_id, tp);
|
||||
}
|
||||
|
||||
int gettimeofday(timeval* tv, struct timezone* tz) {
|
||||
static int (*vdso_gettimeofday)(timeval*, struct timezone*) =
|
||||
reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso_entries[VDSO_GETTIMEOFDAY].fn);
|
||||
int (*vdso_gettimeofday)(timeval*, struct timezone*) =
|
||||
reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso.entries[VDSO_GETTIMEOFDAY].fn);
|
||||
return vdso_gettimeofday(tv, tz);
|
||||
}
|
||||
|
||||
void __libc_init_vdso() {
|
||||
static void __libc_init_vdso_entries() {
|
||||
// Do we have a vdso?
|
||||
uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
|
||||
ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
|
||||
if (vdso_ehdr == NULL) {
|
||||
if (vdso_ehdr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +93,7 @@ void __libc_init_vdso() {
|
||||
|
||||
// Where's the dynamic table?
|
||||
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);
|
||||
for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (vdso_addr == 0 || vdso_dyn == NULL) {
|
||||
if (vdso_addr == 0 || vdso_dyn == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Where are the string and symbol tables?
|
||||
const char* strtab = NULL;
|
||||
ElfW(Sym)* symtab = NULL;
|
||||
const char* strtab = nullptr;
|
||||
ElfW(Sym)* symtab = nullptr;
|
||||
for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) {
|
||||
if (d->d_tag == DT_STRTAB) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (strtab == NULL || symtab == NULL) {
|
||||
if (strtab == nullptr || symtab == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Are there any symbols we want?
|
||||
for (size_t i = 0; i < symbol_count; ++i) {
|
||||
for (size_t j = 0; j < VDSO_END; ++j) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
void __libc_init_vdso() {
|
||||
|
||||
@@ -81,17 +81,6 @@
|
||||
|
||||
#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
|
||||
|
||||
/* 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_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)
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
@@ -428,6 +438,58 @@ int sprintf(char *dest, const char *format, ...)
|
||||
}
|
||||
#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__)
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
|
||||
@@ -578,4 +578,19 @@
|
||||
#define _BIONIC_NOT_BEFORE_21(x)
|
||||
#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_ */
|
||||
|
||||
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
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_TIME_H_
|
||||
#define _SYS_TIME_H_
|
||||
|
||||
@@ -32,6 +33,9 @@
|
||||
#include <sys/types.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
|
||||
|
||||
extern int gettimeofday(struct timeval *, struct timezone *);
|
||||
@@ -73,6 +77,15 @@ extern int utimes(const char *, const struct timeval *);
|
||||
} \
|
||||
} 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
|
||||
|
||||
#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_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <limits.h> /* For PAGE_SIZE. */
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
|
||||
#if __i386__
|
||||
|
||||
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>
|
||||
|
||||
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); \
|
||||
_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);
|
||||
__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
|
||||
__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)
|
||||
|
||||
__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)
|
||||
#define __PREAD_PREFIX(x) __pread64_ ## x
|
||||
#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_ACTIVE_CU_COUNT 0x20
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define RADEON_INFO_VA_UNMAP_WORKING 0x25
|
||||
struct drm_radeon_info {
|
||||
uint32_t request;
|
||||
uint32_t pad;
|
||||
uint64_t value;
|
||||
/* 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_1D 13
|
||||
#define SI_TILE_MODE_COLOR_1D_SCANOUT 9
|
||||
/* 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_16BPP 15
|
||||
#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 */
|
||||
#define SI_TILE_MODE_COLOR_2D_64BPP 17
|
||||
#define SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP 11
|
||||
#define SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP 12
|
||||
#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 */
|
||||
#define SI_TILE_MODE_DEPTH_STENCIL_2D 0
|
||||
#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_8AA 2
|
||||
#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
|
||||
#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))
|
||||
|
||||
@@ -1332,6 +1332,15 @@ LIBC {
|
||||
*;
|
||||
};
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
__fread_chk;
|
||||
__fwrite_chk;
|
||||
__getcwd_chk;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
} LIBC;
|
||||
|
||||
LIBC_PRIVATE {
|
||||
global:
|
||||
___Unwind_Backtrace; # arm
|
||||
@@ -1453,4 +1462,4 @@ LIBC_PRIVATE {
|
||||
SHA1Init; # arm x86 mips
|
||||
SHA1Transform; # 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_DLERROR,
|
||||
|
||||
// Fast storage for Thread::Current() in ART.
|
||||
TLS_SLOT_ART_THREAD_SELF,
|
||||
|
||||
BIONIC_TLS_SLOTS // Must come last!
|
||||
};
|
||||
|
||||
@@ -114,7 +117,7 @@ __END_DECLS
|
||||
|
||||
#if defined(__cplusplus)
|
||||
class KernelArgumentBlock;
|
||||
extern __LIBC_HIDDEN__ void __libc_init_tls(KernelArgumentBlock& args);
|
||||
extern __LIBC_HIDDEN__ void __libc_init_main_thread(KernelArgumentBlock& args);
|
||||
#endif
|
||||
|
||||
#endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
#include "atexit.h"
|
||||
#include "private/thread_private.h"
|
||||
|
||||
/* BEGIN android-changed */
|
||||
#include "private/bionic_prctl.h"
|
||||
/* END android-changed */
|
||||
|
||||
struct atexit {
|
||||
struct atexit *next; /* next in list */
|
||||
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);
|
||||
if (p == MAP_FAILED)
|
||||
goto unlock;
|
||||
/* BEGIN android-changed */
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
|
||||
"atexit handlers");
|
||||
/* END android-changed */
|
||||
if (__atexit == NULL) {
|
||||
memset(&p->fns[0], 0, sizeof(p->fns[0]));
|
||||
p->ind = 1;
|
||||
@@ -204,6 +212,10 @@ __atexit_register_cleanup(void (*func)(void))
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
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->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
|
||||
sizeof(p->fns[0]);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "private/bionic_prctl.h"
|
||||
|
||||
// Android gets these from "thread_private.h".
|
||||
#include "thread_private.h"
|
||||
//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)
|
||||
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,
|
||||
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
|
||||
munmap(*rsxp, sizeof(**rsxp));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsxp, sizeof(**rsxp),
|
||||
"arc4random _rsx structure");
|
||||
|
||||
_ARC4_ATFORK(_rs_forkhandler);
|
||||
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.
|
||||
* All rights reserved.
|
||||
@@ -88,7 +88,6 @@
|
||||
#include <fnmatch.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "charclass.h"
|
||||
|
||||
@@ -193,6 +192,8 @@ static int fnmatch_ch(const char **pattern, const char **string, int flags)
|
||||
result = 0;
|
||||
continue;
|
||||
}
|
||||
if (!**pattern)
|
||||
break;
|
||||
|
||||
leadingclosebrace:
|
||||
/* 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;
|
||||
int matchlen = 0;
|
||||
|
||||
if (strnlen(pattern, PATH_MAX) == PATH_MAX ||
|
||||
strnlen(string, PATH_MAX) == PATH_MAX)
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
if (*pattern == '*')
|
||||
goto firstsegment;
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ LOCAL_CONLYFLAGS += \
|
||||
-std=gnu99 \
|
||||
|
||||
LOCAL_CPPFLAGS += \
|
||||
-std=gnu++11 \
|
||||
-Wold-style-cast \
|
||||
|
||||
ifeq ($(TARGET_IS_64_BIT),true)
|
||||
@@ -60,7 +59,7 @@ LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
|
||||
|
||||
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
|
||||
|
||||
@@ -83,4 +82,26 @@ LOCAL_POST_LINK_CMD = $(hide) $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) \
|
||||
|
||||
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))
|
||||
|
||||
@@ -135,9 +135,6 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
|
||||
signal_name = "SIGILL";
|
||||
has_address = true;
|
||||
break;
|
||||
case SIGPIPE:
|
||||
signal_name = "SIGPIPE";
|
||||
break;
|
||||
case SIGSEGV:
|
||||
signal_name = "SIGSEGV";
|
||||
has_address = true;
|
||||
@@ -273,7 +270,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)
|
||||
signal(signal_number, SIG_DFL);
|
||||
|
||||
// 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 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
|
||||
@@ -281,7 +278,6 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)
|
||||
switch (signal_number) {
|
||||
case SIGABRT:
|
||||
case SIGFPE:
|
||||
case SIGPIPE:
|
||||
#if defined(SIGSTKFLT)
|
||||
case SIGSTKFLT:
|
||||
#endif
|
||||
@@ -307,7 +303,6 @@ __LIBC_HIDDEN__ void debuggerd_init() {
|
||||
sigaction(SIGBUS, &action, nullptr);
|
||||
sigaction(SIGFPE, &action, nullptr);
|
||||
sigaction(SIGILL, &action, nullptr);
|
||||
sigaction(SIGPIPE, &action, nullptr);
|
||||
sigaction(SIGSEGV, &action, nullptr);
|
||||
#if defined(SIGSTKFLT)
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
#include "linker_phdr.h"
|
||||
#include "linker_relocs.h"
|
||||
#include "linker_reloc_iterators.h"
|
||||
|
||||
#include "base/strings.h"
|
||||
#include "ziparchive/zip_archive.h"
|
||||
|
||||
extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
|
||||
@@ -85,9 +87,26 @@ static const char* const kDefaultLdPaths[] = {
|
||||
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) 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_preload_names;
|
||||
|
||||
@@ -285,30 +304,15 @@ static void soinfo_free(soinfo* si) {
|
||||
sonext = prev;
|
||||
}
|
||||
|
||||
si->~soinfo();
|
||||
g_soinfo_allocator.free(si);
|
||||
}
|
||||
|
||||
static void parse_path(const char* path, const char* delimiters,
|
||||
std::vector<std::string>* paths) {
|
||||
if (path == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
paths->clear();
|
||||
|
||||
for (const char *p = path; ; ++p) {
|
||||
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;
|
||||
}
|
||||
if (path != nullptr) {
|
||||
*paths = android::base::Split(path, delimiters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
// For example, if path is "foo.zip!/bar/bas/x.so", then we search for
|
||||
// "bar/bas/x.so" within "foo.zip".
|
||||
const char* separator = strstr(path, "!/");
|
||||
const char* separator = strstr(path, kZipFileSeparator);
|
||||
if (separator == nullptr) {
|
||||
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) {
|
||||
for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) {
|
||||
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1211,7 +1215,7 @@ static int open_library_on_paths(const char* name, off64_t* file_offset,
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
if (strchr(buf, '!') != nullptr) {
|
||||
if (strstr(buf, kZipFileSeparator) != nullptr) {
|
||||
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 (strchr(name, '/') != nullptr) {
|
||||
if (strchr(name, '!') != nullptr) {
|
||||
if (strstr(name, kZipFileSeparator) != nullptr) {
|
||||
int fd = open_library_in_zipfile(name, file_offset);
|
||||
if (fd != -1) {
|
||||
return fd;
|
||||
@@ -1469,9 +1473,17 @@ static soinfo::soinfo_list_t make_global_group() {
|
||||
return global_group;
|
||||
}
|
||||
|
||||
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) {
|
||||
// add_as_children - add first-level loaded libraries (i.e. library_names[], but
|
||||
// not their transitive dependencies) as children of the start_with library.
|
||||
// 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.
|
||||
LoadTaskList load_tasks;
|
||||
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;
|
||||
}
|
||||
|
||||
if (needed_by != nullptr) {
|
||||
if (needed_by != nullptr && (needed_by != start_with || add_as_children)) {
|
||||
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.
|
||||
soinfo::soinfo_list_t local_group;
|
||||
walk_dependencies_tree(
|
||||
start_with == nullptr ? soinfos : &start_with,
|
||||
start_with == nullptr ? soinfos_count : 1,
|
||||
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
|
||||
(start_with != nullptr && add_as_children) ? 1 : soinfos_count,
|
||||
[&] (soinfo* si) {
|
||||
local_group.push_back(si);
|
||||
return true;
|
||||
@@ -1579,12 +1591,15 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[]
|
||||
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;
|
||||
|
||||
if (name == nullptr) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1646,7 +1661,7 @@ static void soinfo_unload(soinfo* root) {
|
||||
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
|
||||
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) {
|
||||
// Not found: for example if symlink was deleted between dlopen and dlclose
|
||||
// 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.
|
||||
// Once the above bug is fixed, this code can be modified to use
|
||||
// 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) {
|
||||
__libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
|
||||
"buffer len %zu, required len %zu", buffer_size, required_len);
|
||||
}
|
||||
char* end = stpcpy(buffer, kDefaultLdPaths[0]);
|
||||
*end = ':';
|
||||
strcpy(end + 1, kDefaultLdPaths[1]);
|
||||
char* end = buffer;
|
||||
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
||||
if (i > 0) *end++ = ':';
|
||||
end = stpcpy(end, g_default_ld_paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void do_android_update_LD_LIBRARY_PATH(const char* 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) {
|
||||
DL_ERR("invalid flags to dlopen: %x", flags);
|
||||
return nullptr;
|
||||
@@ -1727,7 +1747,7 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo)
|
||||
}
|
||||
|
||||
ProtectedDataGuard guard;
|
||||
soinfo* si = find_library(name, flags, extinfo);
|
||||
soinfo* si = find_library(name, flags, extinfo, caller);
|
||||
if (si != nullptr) {
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// We got a definition.
|
||||
} else { // 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);
|
||||
#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);
|
||||
}
|
||||
@@ -2004,7 +2047,32 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
|
||||
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
|
||||
reinterpret_cast<void*>(reloc),
|
||||
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;
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
@@ -3234,6 +3312,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||
|
||||
somain = si;
|
||||
|
||||
init_default_ld_library_path();
|
||||
|
||||
if (!si->prelink_image()) {
|
||||
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -3265,7 +3345,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||
|
||||
if (needed_libraries_count > 0 &&
|
||||
!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());
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (needed_libraries_count == 0) {
|
||||
@@ -3418,7 +3499,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
__libc_init_tls(args);
|
||||
__libc_init_main_thread(args);
|
||||
|
||||
// Initialize the linker's own global variables
|
||||
linker_so.call_constructors();
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
#ifndef _LINKER_H_
|
||||
#define _LINKER_H_
|
||||
|
||||
#include <android/dlext.h>
|
||||
#include <elf.h>
|
||||
#include <inttypes.h>
|
||||
#include <link.h>
|
||||
#include <unistd.h>
|
||||
#include <android/dlext.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private/bionic_page.h"
|
||||
#include "private/libc_logging.h"
|
||||
#include "linked_list.h"
|
||||
|
||||
@@ -77,16 +78,6 @@
|
||||
#define ELF64_R_TYPE(info) (((info) >> 56) & 0xff)
|
||||
#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_EXE 0x00000004 // The main executable
|
||||
#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_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);
|
||||
|
||||
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
|
||||
if (abiflags == nullptr) {
|
||||
// Old compiles lack the new abiflags section.
|
||||
// These compilers used -mfp32 -mdouble-float -modd-spreg defaults,
|
||||
// ie FP32 aka DOUBLE, using odd-numbered single-prec regs
|
||||
mips_fpabi = MIPS_ABI_FP_DOUBLE;
|
||||
// Old compilers and some translators don't emit the new abiflags section.
|
||||
const char* filename = get_realpath();
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
mips_fpabi = abiflags->fp_abi;
|
||||
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
|
||||
// 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.
|
||||
|
||||
@@ -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(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 */
|
||||
|
||||
@@ -23,7 +23,7 @@ LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
|
||||
|
||||
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_SRC_FILES := \
|
||||
|
||||
@@ -46,8 +46,7 @@ else
|
||||
test_cflags += -DUSE_JEMALLOC
|
||||
endif
|
||||
|
||||
test_cppflags = \
|
||||
-std=gnu++11 \
|
||||
test_cppflags := \
|
||||
|
||||
libBionicStandardTests_src_files := \
|
||||
arpa_inet_test.cpp \
|
||||
@@ -93,6 +92,7 @@ libBionicStandardTests_src_files := \
|
||||
sys_epoll_test.cpp \
|
||||
sys_mman_test.cpp \
|
||||
sys_personality_test.cpp \
|
||||
sys_prctl_test.cpp \
|
||||
sys_procfs_test.cpp \
|
||||
sys_resource_test.cpp \
|
||||
sys_select_test.cpp \
|
||||
@@ -279,6 +279,7 @@ bionic-unit-tests_src_files := \
|
||||
dlfcn_test.cpp \
|
||||
libdl_test.cpp \
|
||||
pthread_dlfcn_test.cpp \
|
||||
thread_local_test.cpp \
|
||||
|
||||
bionic-unit-tests_cflags := $(test_cflags)
|
||||
|
||||
@@ -407,7 +408,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := \
|
||||
|
||||
LOCAL_CXX = $(LOCAL_PATH)/file-check-cxx \
|
||||
$(HOST_OUT_EXECUTABLES)/FileCheck \
|
||||
$($(LOCAL_2ND_ARCH_VAR_PREFIX)CXX_BARE) \
|
||||
$($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CXX) \
|
||||
GCC \
|
||||
|
||||
LOCAL_CLANG := false
|
||||
|
||||
@@ -256,7 +256,7 @@ void RunSingleBufferAlignTest(
|
||||
VerifyFencepost(&buf_align[len]);
|
||||
}
|
||||
}
|
||||
delete buf;
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
void RunSrcDstBufferAlignTest(
|
||||
@@ -292,8 +292,8 @@ void RunSrcDstBufferAlignTest(
|
||||
VerifyFencepost(&dst_align[len]);
|
||||
}
|
||||
}
|
||||
delete src;
|
||||
delete dst;
|
||||
delete[] src;
|
||||
delete[] dst;
|
||||
}
|
||||
|
||||
void RunCmpBufferAlignTest(
|
||||
@@ -344,8 +344,8 @@ void RunCmpBufferAlignTest(
|
||||
}
|
||||
}
|
||||
}
|
||||
delete buf1;
|
||||
delete buf2;
|
||||
delete[] buf1;
|
||||
delete[] buf2;
|
||||
}
|
||||
|
||||
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);
|
||||
free(memory);
|
||||
delete dst;
|
||||
delete[] dst;
|
||||
}
|
||||
|
||||
void RunCmpBufferOverreadTest(
|
||||
|
||||
@@ -1072,7 +1072,7 @@ TEST(dlfcn, dt_runpath) {
|
||||
ASSERT_TRUE(fn != nullptr) << dlerror();
|
||||
|
||||
void *p = fn();
|
||||
ASSERT_TRUE(p == nullptr);
|
||||
ASSERT_TRUE(p != nullptr);
|
||||
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
@@ -230,3 +230,43 @@ void test_ppoll() {
|
||||
// clang should emit a warning, but doesn't
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
char buf[1];
|
||||
size_t ct = atoi("2"); // prevent optimizations
|
||||
@@ -647,6 +653,22 @@ TEST_F(DEATHTEST, read_fortified) {
|
||||
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) {
|
||||
char buf[1];
|
||||
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)) {
|
||||
++p;
|
||||
}
|
||||
if (*p != '\0') {
|
||||
if (*p != '\0' && *p != '#') {
|
||||
// This is not we want, gtest must meet with some error when parsing the arguments.
|
||||
fprintf(stderr, "argument error, check with --help\n");
|
||||
return false;
|
||||
|
||||
@@ -31,7 +31,7 @@ libtest_dt_runpath_b_src_files := \
|
||||
empty.cpp
|
||||
|
||||
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
|
||||
module := libtest_dt_runpath_b
|
||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||
@@ -43,7 +43,7 @@ libtest_dt_runpath_c_src_files := \
|
||||
empty.cpp
|
||||
|
||||
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
|
||||
module := libtest_dt_runpath_c
|
||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||
@@ -53,7 +53,7 @@ libtest_dt_runpath_d_src_files := \
|
||||
dlopen_b.cpp
|
||||
|
||||
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
|
||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
TEST_PATH := $(LOCAL_PATH)/..
|
||||
|
||||
common_cppflags += -std=gnu++11
|
||||
common_cppflags :=
|
||||
common_additional_dependencies := \
|
||||
$(LOCAL_PATH)/Android.mk \
|
||||
$(LOCAL_PATH)/Android.build.dt_runpath.mk \
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "buffer_tests.h"
|
||||
|
||||
@@ -1396,6 +1397,10 @@ TEST(string, strnlen_147048) {
|
||||
delete[] heap_src;
|
||||
}
|
||||
|
||||
TEST(string, strnlen_74741) {
|
||||
ASSERT_EQ(4U, strnlen("test", SIZE_MAX));
|
||||
}
|
||||
|
||||
TEST(string, mempcpy) {
|
||||
char dst[6];
|
||||
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);
|
||||
}
|
||||
|
||||
#if defined(__BIONIC__)
|
||||
|
||||
static void check_group(const group* grp, const char* group_name, gid_t gid) {
|
||||
ASSERT_TRUE(grp != NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
#if defined(__BIONIC__)
|
||||
|
||||
static void check_getgrgid(const char* group_name, gid_t gid) {
|
||||
errno = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
check_getgrgid(group_name, gid);
|
||||
check_getgrnam(group_name, gid);
|
||||
check_getgrgid_r(group_name, gid);
|
||||
check_getgrnam_r(group_name, gid);
|
||||
}
|
||||
|
||||
#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";
|
||||
}
|
||||
|
||||
static void check_get_group(const char*, gid_t) {
|
||||
print_no_getgrnam_test_info();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(getgrnam, system_id_root) {
|
||||
@@ -259,3 +291,53 @@ TEST(getgrnam, app_id_u1_a40000) {
|
||||
TEST(getgrnam, app_id_u1_i0) {
|
||||
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();
|
||||
ASSERT_EQ(syscall(__NR_getpid), parent_pid);
|
||||
|
||||
pid_t fork_result = fork();
|
||||
pid_t fork_result = fork_fn();
|
||||
ASSERT_NE(fork_result, -1);
|
||||
if (fork_result == 0) {
|
||||
// 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*) {
|
||||
AssertGetPidCorrect();
|
||||
return 123;
|
||||
@@ -694,6 +702,8 @@ TEST(unistd, sysconf) {
|
||||
VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
|
||||
VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
|
||||
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_AIO_LISTIO_MAX);
|
||||
VERIFY_SYSCONF_POSITIVE(_SC_AIO_MAX);
|
||||
|
||||
Reference in New Issue
Block a user