Merge "Mark __progname as weak for native_bridge"
diff --git a/libc/arch-x86/bionic/__restore.S b/libc/arch-x86/bionic/__restore.S
index cb18fd0..5977eab 100644
--- a/libc/arch-x86/bionic/__restore.S
+++ b/libc/arch-x86/bionic/__restore.S
@@ -27,14 +27,7 @@
*/
#include <private/bionic_asm.h>
-
-// DWARF constants.
-#define DW_CFA_def_cfa_expression 0x0f
-#define DW_CFA_expression 0x10
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_sdata4 0x0b
-#define DW_OP_breg4 0x74
-#define DW_OP_deref 0x06
+#include <private/bionic_asm_dwarf_exprs.h>
// Offsets into struct sigcontext.
#define OFFSET_EDI 16
@@ -52,84 +45,47 @@
#define DW_x86_REG_ECX 1
#define DW_x86_REG_EDX 2
#define DW_x86_REG_EBX 3
+#define DW_x86_REG_ESP 4
#define DW_x86_REG_EBP 5
#define DW_x86_REG_ESI 6
#define DW_x86_REG_EDI 7
#define DW_x86_REG_EIP 8
-#define cfi_signal_frame_start(f) \
-.section .eh_frame,"a",@progbits; \
-.L ## f ## _START_EH_FRAME: \
- .long 2f - 1f; /* CIE length. */ \
-1:.long 0; /* CIE ID. */ \
- .byte 1; /* Version. */ \
- .string "zRS"; /* Augmentation string. */ \
- .uleb128 1; /* Code alignment factor. */ \
- .sleb128 -4; /* Data alignment factor. */ \
- .uleb128 DW_x86_REG_EIP; /* Return address register. */ \
- .uleb128 1; /* 1 byte of augmentation data. */ \
- .byte (DW_EH_PE_pcrel|DW_EH_PE_sdata4); /* FDE encoding. */ \
- .align 8; \
-2: \
- .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \
-.L ## f ## _START_FDE: \
- .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \
- .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \
- .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \
- .uleb128 0; /* FDE augmentation length. */ \
+#define RESTORE_GPR(reg, extra_offset) \
+ m_cfi_breg_offset DW_x86_REG_ ## reg, \
+ DW_x86_REG_ESP, \
+ (OFFSET_ ## reg + (extra_offset));
-#define cfi_signal_frame_end(f) \
-.L ## f ## _END_FDE: \
+// Restoring ESP is unnecessary as the unwinder simply uses the CFA value.
+#define RESTORE_GPRS(extra_offset) \
+ m_cfi_def_cfa_deref DW_x86_REG_ESP, (OFFSET_ESP + (extra_offset)); \
+ RESTORE_GPR(EDI, extra_offset) \
+ RESTORE_GPR(ESI, extra_offset) \
+ RESTORE_GPR(EBP, extra_offset) \
+ RESTORE_GPR(EBX, extra_offset) \
+ RESTORE_GPR(EDX, extra_offset) \
+ RESTORE_GPR(ECX, extra_offset) \
+ RESTORE_GPR(EAX, extra_offset) \
+ RESTORE_GPR(EIP, extra_offset) \
-#define cfi_def_cfa(offset) \
- .byte DW_CFA_def_cfa_expression; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg4; \
- .sleb128 offset; \
- .byte DW_OP_deref; \
-2: \
+ .text
-#define cfi_offset(reg_number,offset) \
- .byte DW_CFA_expression; \
- .uleb128 reg_number; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg4; \
- .sleb128 offset; \
-2: \
-
-ENTRY_PRIVATE(__restore)
-.L__restore_START:
+ .cfi_startproc
+ .cfi_signal_frame
+ RESTORE_GPRS(4)
+ nop // See comment in libc/arch-x86_64/bionic/__restore_rt.S about this nop.
+ENTRY_PRIVATE_NO_DWARF(__restore)
popl %eax
+ RESTORE_GPRS(0)
movl $__NR_sigreturn, %eax
int $0x80
-.L__restore_END:
END(__restore)
-cfi_signal_frame_start(__restore)
- cfi_def_cfa(OFFSET_ESP + 4)
- cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 4)
- cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 4)
- cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 4)
- cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 4)
- cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 4)
- cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 4)
- cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 4)
- cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 4)
-cfi_signal_frame_end(__restore)
-ENTRY_PRIVATE(__restore_rt)
-.L__restore_rt_START:
+ .cfi_startproc
+ .cfi_signal_frame
+ RESTORE_GPRS(160)
+ nop // See comment in libc/arch-x86_64/bionic/__restore_rt.S about this nop.
+ENTRY_PRIVATE_NO_DWARF(__restore_rt)
movl $__NR_rt_sigreturn, %eax
int $0x80
-.L__restore_rt_END:
END(__restore_rt)
-cfi_signal_frame_start(__restore_rt)
- cfi_def_cfa(OFFSET_ESP + 160)
- cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 160)
- cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 160)
- cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 160)
- cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 160)
- cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 160)
- cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 160)
- cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 160)
- cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 160)
-cfi_signal_frame_end(__restore_rt)
diff --git a/libc/arch-x86_64/bionic/__restore_rt.S b/libc/arch-x86_64/bionic/__restore_rt.S
index 785b3b3..f3e4012 100644
--- a/libc/arch-x86_64/bionic/__restore_rt.S
+++ b/libc/arch-x86_64/bionic/__restore_rt.S
@@ -27,15 +27,9 @@
*/
#include <private/bionic_asm.h>
+#include <private/bionic_asm_dwarf_exprs.h>
-// DWARF constants.
-#define DW_CFA_def_cfa_expression 0x0f
-#define DW_CFA_expression 0x10
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_sdata4 0x0b
-#define DW_OP_breg4 0x74
-#define DW_OP_breg7 0x77
-#define DW_OP_deref 0x06
+// In the signal trampoline frame, rsp points to a ucontext_t struct.
// Offsets into struct ucontext_t of uc_mcontext.gregs[x].
#define OFFSET_R8 40
@@ -49,11 +43,11 @@
#define OFFSET_RDI 104
#define OFFSET_RSI 112
#define OFFSET_RBP 120
-#define OFFSET_RSP 160
#define OFFSET_RBX 128
#define OFFSET_RDX 136
#define OFFSET_RAX 144
#define OFFSET_RCX 152
+#define OFFSET_RSP 160
#define OFFSET_RIP 168
// Non-standard DWARF constants for the x86-64 registers.
@@ -75,69 +69,47 @@
#define DW_x86_64_R15 15
#define DW_x86_64_RIP 16
-#define cfi_signal_frame_start(f) \
-.section .eh_frame,"a",@progbits; \
-.L ## f ## _START_EH_FRAME: \
- .long 2f - 1f; /* CIE length. */ \
-1:.long 0; /* CIE ID. */ \
- .byte 1; /* Version. */ \
- .string "zRS"; /* Augmentation string. */ \
- .uleb128 1; /* Code alignment factor. */ \
- .sleb128 -8; /* Data alignment factor. */ \
- .uleb128 DW_x86_64_RIP; /* Return address register. */ \
- .uleb128 1; /* 1 byte of augmentation data. */ \
- .byte (DW_EH_PE_pcrel | DW_EH_PE_sdata4); /* FDE encoding. */ \
- .align 8; \
-2: \
- .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \
-.L ## f ## _START_FDE: \
- .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \
- .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \
- .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \
- .uleb128 0; /* FDE augmentation length. */ \
+// Insert a nop between .cfi_startproc and the trampoline symbol so that unwinders can find the FDE.
+// A function's last instruction can be a call instruction (e.g. to __cxa_throw), in which case the
+// return address (e.g. from __cxa_throw to the caller) will be just after the function. This
+// address may also be the start of the next function, so to avoid ambiguity, unwinders assume that
+// a return address PC can refer to the address just after a function, but never to the start of a
+// function. (This is implemented by subtracting 1 from the return address PC before looking it up.)
+// This is fine for ordinary functions, but breaks on trampolines. Inserting a nop fixes it.
+//
+// N.B. Unwinders have two other strategies for recognizing the signal trampoline:
+// - Read the instructions that the return address PC points at and look for a sigreturn syscall.
+// (Hence, the instructions must not change at all.)
+// - Do a symbol table lookup and check that against the PC (e.g. LLDB looks for
+// __kernel_rt_sigreturn and __restore_rt.)
+// Either way, the nop is needed to avoid ambiguity if the function before the trampoline could end
+// with a call.
-#define cfi_signal_frame_end(f) \
-.L ## f ## _END_FDE: \
+#define RESTORE_GPR(reg) m_cfi_breg_offset DW_x86_64_ ## reg, DW_x86_64_RSP, OFFSET_ ## reg;
-#define cfi_def_cfa(offset) \
- .byte DW_CFA_def_cfa_expression; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg7; \
- .sleb128 offset; \
- .byte DW_OP_deref; \
-2: \
-
-#define cfi_offset(reg_number,offset) \
- .byte DW_CFA_expression; \
- .uleb128 reg_number; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg7; \
- .sleb128 offset; \
-2: \
-
-ENTRY_PRIVATE(__restore_rt)
-.L__restore_rt_START:
+ .text
+ .cfi_startproc
+ .cfi_signal_frame
+ m_cfi_def_cfa_deref DW_x86_64_RSP, OFFSET_RSP
+ RESTORE_GPR(R8)
+ RESTORE_GPR(R9)
+ RESTORE_GPR(R10)
+ RESTORE_GPR(R11)
+ RESTORE_GPR(R12)
+ RESTORE_GPR(R13)
+ RESTORE_GPR(R14)
+ RESTORE_GPR(R15)
+ RESTORE_GPR(RDI)
+ RESTORE_GPR(RSI)
+ RESTORE_GPR(RBP)
+ RESTORE_GPR(RBX)
+ RESTORE_GPR(RDX)
+ RESTORE_GPR(RAX)
+ RESTORE_GPR(RCX)
+ // Restoring RSP is unnecessary as the unwinder simply uses the CFA value.
+ RESTORE_GPR(RIP)
+ nop
+ENTRY_PRIVATE_NO_DWARF(__restore_rt)
mov $__NR_rt_sigreturn, %rax
syscall
-.L__restore_rt_END:
END(__restore_rt)
-cfi_signal_frame_start(__restore_rt)
- cfi_def_cfa(OFFSET_RSP)
- cfi_offset(DW_x86_64_R8, OFFSET_R8)
- cfi_offset(DW_x86_64_R9, OFFSET_R9)
- cfi_offset(DW_x86_64_R10, OFFSET_R10)
- cfi_offset(DW_x86_64_R11, OFFSET_R11)
- cfi_offset(DW_x86_64_R12, OFFSET_R12)
- cfi_offset(DW_x86_64_R13, OFFSET_R13)
- cfi_offset(DW_x86_64_R14, OFFSET_R14)
- cfi_offset(DW_x86_64_R15, OFFSET_R15)
- cfi_offset(DW_x86_64_RDI, OFFSET_RDI)
- cfi_offset(DW_x86_64_RSI, OFFSET_RSI)
- cfi_offset(DW_x86_64_RBP, OFFSET_RBP)
- cfi_offset(DW_x86_64_RSP, OFFSET_RSP)
- cfi_offset(DW_x86_64_RBX, OFFSET_RBX)
- cfi_offset(DW_x86_64_RDX, OFFSET_RDX)
- cfi_offset(DW_x86_64_RAX, OFFSET_RAX)
- cfi_offset(DW_x86_64_RCX, OFFSET_RCX)
- cfi_offset(DW_x86_64_RIP, OFFSET_RIP)
-cfi_signal_frame_end(__restore_rt)
diff --git a/libc/private/bionic_asm_dwarf_exprs.h b/libc/private/bionic_asm_dwarf_exprs.h
new file mode 100644
index 0000000..f988c6e
--- /dev/null
+++ b/libc/private/bionic_asm_dwarf_exprs.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// Define assembler macros for generating DWARF CFI instructions that use DWARF expressions.
+// Assemblers don't natively support DWARF expressions, so use the C preprocessor and assembler
+// macros to lower them to .cfi_escape directives.
+//
+// Signal trampolines need to use DWARF expressions to record the locations of saved registers,
+// because the offsets from the restored SP to the saved registers is variable. e.g. A signal frame
+// can have optional FP/SIMD extensions, and there may be extra padding if the interrupted SP wasn't
+// aligned.
+
+// DWARF constants.
+#define DW_CFA_def_cfa_expression 0x0f
+#define DW_CFA_expression 0x10
+#define DW_OP_breg0 0x70
+#define DW_OP_deref 0x06
+
+// Return the size of a small uleb128 value: either 1 or 2 bytes
+#define ULEB128_14BIT_SIZE(val) \
+ (1 + (((val) > 0x7f) & 1))
+
+// Return the size of a small sleb128 value: either 1 or 2 bytes
+#define SLEB128_14BIT_SIZE(val) \
+ (1 + (((val) < -0x40) & 1) + \
+ (((val) > 0x3f) & 1) )
+
+// Output a 1 or 2-byte CFI uleb128 absolute value.
+.macro m_cfi_uleb128 val
+ .if (\val) < 0 || (\val) > 0x3fff
+ .error "m_cfi_uleb128 value is out of range (\val)"
+ .elseif (\val) > 0x7f
+ .cfi_escape ((\val) & 0x7f) | 0x80
+ .cfi_escape (\val) >> 7
+ .else
+ .cfi_escape (\val)
+ .endif
+.endm
+
+// Output a 1 or 2-byte CFI sleb128 absolute value.
+.macro m_cfi_sleb128 val
+ .if (\val) < -0x2000 || (\val) > 0x1fff
+ .error "m_cfi_sleb128 value is out of range (\val)"
+ .elseif (\val) < -0x40 || (\val) > 0x3f
+ .cfi_escape ((\val) & 0x7f) | 0x80
+ .cfi_escape ((\val) >> 7) & 0x7f
+ .else
+ .cfi_escape (\val) & 0x7f
+ .endif
+.endm
+
+.macro check_base_reg reg_no
+ .if (\reg_no) < 0 || (\reg_no) > 31
+ .error "base register is out of range for DW_OP_breg0..DW_OP_breg31 (\reg_no)"
+ .endif
+.endm
+
+// Set CFA to the expression, *(base_reg + offset)
+.macro m_cfi_def_cfa_deref base_reg, offset
+ check_base_reg (\base_reg)
+ .cfi_escape DW_CFA_def_cfa_expression
+ m_cfi_uleb128 (1 + SLEB128_14BIT_SIZE(\offset) + 1) // size of DWARF expression in bytes
+ .cfi_escape DW_OP_breg0 + (\base_reg) // expr: 1 byte
+ m_cfi_sleb128 (\offset) // expr: 1 or 2 bytes
+ .cfi_escape DW_OP_deref // expr: 1 byte
+.endm
+
+// Set the address of the register's previous value to the expression, (base_reg + offset)
+.macro m_cfi_breg_offset dest_reg, base_reg, offset
+ check_base_reg (\base_reg)
+ .cfi_escape DW_CFA_expression
+ m_cfi_uleb128 (\dest_reg)
+ m_cfi_uleb128 (1 + SLEB128_14BIT_SIZE(\offset)) // size of DWARF expression in bytes
+ .cfi_escape DW_OP_breg0 + (\base_reg) // expr: 1 byte
+ m_cfi_sleb128 (\offset) // expr: 1 or 2 bytes
+.endm
diff --git a/tests/Android.bp b/tests/Android.bp
index 8760256..bf921c8 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -41,6 +41,9 @@
// We want to test deprecated API too.
"-Wno-deprecated-declarations",
+ // Needed to test pthread_internal_t layout.
+ "-Wno-invalid-offsetof",
+
// For glibc.
"-D__STDC_LIMIT_MACROS",
],
@@ -392,6 +395,7 @@
"string_posix_strerror_r_test.cpp",
"strings_nofortify_test.cpp",
"strings_test.cpp",
+ "struct_layout_test.cpp",
"sstream_test.cpp",
"sys_auxv_test.cpp",
"sys_epoll_test.cpp",
diff --git a/tests/struct_layout_test.cpp b/tests/struct_layout_test.cpp
new file mode 100644
index 0000000..9da702c
--- /dev/null
+++ b/tests/struct_layout_test.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 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 <stdio.h>
+
+#if defined(__BIONIC__)
+#include "bionic/pthread_internal.h"
+
+// Ensure that the layout of these data structures is architecture independent and only depends on
+// the bitness of the architecture.
+template <typename CheckSize, typename CheckOffset>
+void tests(CheckSize check_size, CheckOffset check_offset) {
+#define CHECK_SIZE(name, size) \
+ check_size(#name, sizeof(name), size);
+#define CHECK_OFFSET(name, field, offset) \
+ check_offset(#name, #field, offsetof(name, field), offset);
+#ifdef __LP64__
+ CHECK_SIZE(pthread_internal_t, 768);
+ CHECK_OFFSET(pthread_internal_t, next, 0);
+ CHECK_OFFSET(pthread_internal_t, prev, 8);
+ CHECK_OFFSET(pthread_internal_t, tid, 16);
+ CHECK_OFFSET(pthread_internal_t, attr, 24);
+ CHECK_OFFSET(pthread_internal_t, join_state, 80);
+ CHECK_OFFSET(pthread_internal_t, cleanup_stack, 88);
+ CHECK_OFFSET(pthread_internal_t, start_routine, 96);
+ CHECK_OFFSET(pthread_internal_t, start_routine_arg, 104);
+ CHECK_OFFSET(pthread_internal_t, return_value, 112);
+ CHECK_OFFSET(pthread_internal_t, start_mask, 120);
+ CHECK_OFFSET(pthread_internal_t, alternate_signal_stack, 128);
+ CHECK_OFFSET(pthread_internal_t, shadow_call_stack_guard_region, 136);
+ CHECK_OFFSET(pthread_internal_t, stack_top, 144);
+ CHECK_OFFSET(pthread_internal_t, startup_handshake_lock, 152);
+ CHECK_OFFSET(pthread_internal_t, mmap_base, 160);
+ CHECK_OFFSET(pthread_internal_t, mmap_size, 168);
+ CHECK_OFFSET(pthread_internal_t, mmap_base_unguarded, 176);
+ CHECK_OFFSET(pthread_internal_t, mmap_size_unguarded, 184);
+ CHECK_OFFSET(pthread_internal_t, vma_name_buffer, 192);
+ CHECK_OFFSET(pthread_internal_t, thread_local_dtors, 224);
+ CHECK_OFFSET(pthread_internal_t, current_dlerror, 232);
+ CHECK_OFFSET(pthread_internal_t, dlerror_buffer, 240);
+ CHECK_OFFSET(pthread_internal_t, bionic_tls, 752);
+ CHECK_OFFSET(pthread_internal_t, errno_value, 760);
+ CHECK_SIZE(bionic_tls, 12200);
+ CHECK_OFFSET(bionic_tls, key_data, 0);
+ CHECK_OFFSET(bionic_tls, locale, 2080);
+ CHECK_OFFSET(bionic_tls, basename_buf, 2088);
+ CHECK_OFFSET(bionic_tls, dirname_buf, 6184);
+ CHECK_OFFSET(bionic_tls, mntent_buf, 10280);
+ CHECK_OFFSET(bionic_tls, mntent_strings, 10320);
+ CHECK_OFFSET(bionic_tls, ptsname_buf, 11344);
+ CHECK_OFFSET(bionic_tls, ttyname_buf, 11376);
+ CHECK_OFFSET(bionic_tls, strerror_buf, 11440);
+ CHECK_OFFSET(bionic_tls, strsignal_buf, 11695);
+ CHECK_OFFSET(bionic_tls, group, 11952);
+ CHECK_OFFSET(bionic_tls, passwd, 12040);
+ CHECK_OFFSET(bionic_tls, fdtrack_disabled, 12192);
+ CHECK_OFFSET(bionic_tls, padding, 12193);
+#else
+ CHECK_SIZE(pthread_internal_t, 664);
+ CHECK_OFFSET(pthread_internal_t, next, 0);
+ CHECK_OFFSET(pthread_internal_t, prev, 4);
+ CHECK_OFFSET(pthread_internal_t, tid, 8);
+ CHECK_OFFSET(pthread_internal_t, attr, 16);
+ CHECK_OFFSET(pthread_internal_t, join_state, 40);
+ CHECK_OFFSET(pthread_internal_t, cleanup_stack, 44);
+ CHECK_OFFSET(pthread_internal_t, start_routine, 48);
+ CHECK_OFFSET(pthread_internal_t, start_routine_arg, 52);
+ CHECK_OFFSET(pthread_internal_t, return_value, 56);
+ CHECK_OFFSET(pthread_internal_t, start_mask, 60);
+ CHECK_OFFSET(pthread_internal_t, alternate_signal_stack, 68);
+ CHECK_OFFSET(pthread_internal_t, shadow_call_stack_guard_region, 72);
+ CHECK_OFFSET(pthread_internal_t, stack_top, 76);
+ CHECK_OFFSET(pthread_internal_t, startup_handshake_lock, 80);
+ CHECK_OFFSET(pthread_internal_t, mmap_base, 88);
+ CHECK_OFFSET(pthread_internal_t, mmap_size, 92);
+ CHECK_OFFSET(pthread_internal_t, mmap_base_unguarded, 96);
+ CHECK_OFFSET(pthread_internal_t, mmap_size_unguarded, 100);
+ CHECK_OFFSET(pthread_internal_t, vma_name_buffer, 104);
+ CHECK_OFFSET(pthread_internal_t, thread_local_dtors, 136);
+ CHECK_OFFSET(pthread_internal_t, current_dlerror, 140);
+ CHECK_OFFSET(pthread_internal_t, dlerror_buffer, 144);
+ CHECK_OFFSET(pthread_internal_t, bionic_tls, 656);
+ CHECK_OFFSET(pthread_internal_t, errno_value, 660);
+ CHECK_SIZE(bionic_tls, 11080);
+ CHECK_OFFSET(bionic_tls, key_data, 0);
+ CHECK_OFFSET(bionic_tls, locale, 1040);
+ CHECK_OFFSET(bionic_tls, basename_buf, 1044);
+ CHECK_OFFSET(bionic_tls, dirname_buf, 5140);
+ CHECK_OFFSET(bionic_tls, mntent_buf, 9236);
+ CHECK_OFFSET(bionic_tls, mntent_strings, 9260);
+ CHECK_OFFSET(bionic_tls, ptsname_buf, 10284);
+ CHECK_OFFSET(bionic_tls, ttyname_buf, 10316);
+ CHECK_OFFSET(bionic_tls, strerror_buf, 10380);
+ CHECK_OFFSET(bionic_tls, strsignal_buf, 10635);
+ CHECK_OFFSET(bionic_tls, group, 10892);
+ CHECK_OFFSET(bionic_tls, passwd, 10952);
+ CHECK_OFFSET(bionic_tls, fdtrack_disabled, 11076);
+ CHECK_OFFSET(bionic_tls, padding, 11077);
+#endif // __LP64__
+#undef CHECK_SIZE
+#undef CHECK_OFFSET
+}
+#endif // defined(__BIONIC__)
+
+TEST(struct_layout, sizes_offsets) {
+#if defined(__BIONIC__)
+ bool failed = false;
+
+ auto check_size = [&](const char* name, size_t size, size_t expected_size) {
+ EXPECT_EQ(expected_size, size) << "sizeof(" << name << ")";
+ if (size != expected_size) {
+ failed = true;
+ }
+ };
+ auto check_offset = [&](const char* name, const char* field, size_t offset,
+ size_t expected_offset) {
+ EXPECT_EQ(expected_offset, offset) << "offsetof(" << name << ", " << field << ")";
+ if (offset != expected_offset) {
+ failed = true;
+ }
+ };
+ tests(check_size, check_offset);
+
+ if (failed) {
+ printf(
+ "Please update the tests function in bionic/tests/struct_layout_test.cpp with the "
+ "following contents:\n");
+
+ auto print_size = [&](const char* name, size_t size, size_t expected_size) {
+ (void)expected_size;
+ printf(" CHECK_SIZE(%s, %zu);\n", name, size);
+ };
+ auto print_offset = [&](const char* name, const char* field, size_t offset,
+ size_t expected_offset) {
+ (void)expected_offset;
+ printf(" CHECK_OFFSET(%s, %s, %zu);\n", name, field, offset);
+ };
+ tests(print_size, print_offset);
+ }
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}