From 43fca9e2ecb920a0efc9a65afb2ef3ec87fd55c3 Mon Sep 17 00:00:00 2001 From: Greg Cawthorne Date: Sat, 17 Apr 2021 20:36:48 +0100 Subject: [PATCH 1/6] slowpath-aarch64-port inital AArch64 port of drmemory. Only contains slowpath support with shared_slowpath off. Pattern mode and fastpath modes are being worked on separately. Currently this build does break some x86 functionality. Depends on: https://github.com/DynamoRIO/dynamorio/tree/mem-ref-for-clean-calls-aarch64/core Current tests we have analysed: Test project /home/grecaw01/APD-testing/drmem-upstream3/drmemory/build Start 1: drmf_proj 1/49 Test #1: drmf_proj ......................... Passed 0.45 sec Start 2: unit_tests 2/49 Test #2: unit_tests ........................ Passed 0.02 sec Start 3: hello 3/49 Test #3: hello ............................. Passed 3.55 sec Start 4: free 4/49 Test #4: free .............................. Passed 3.67 sec Start 5: malloc 5/49 Test #5: malloc ............................ Passed 3.88 sec Start 6: leak_indirect 6/49 Test #6: leak_indirect ..................... Passed 3.52 sec Start 7: patterns 7/49 Test #7: patterns .......................... Passed 3.93 sec Start 8: free.exitcode 8/49 Test #8: free.exitcode ..................... Passed 3.64 sec Start 9: track_origins 9/49 Test #9: track_origins .....................***Failed 0.34 sec Start 10: free.pattern 10/49 Test #10: free.pattern ......................***Failed 0.35 sec Start 11: malloc.pattern 11/49 Test #11: malloc.pattern ....................***Failed 0.34 sec Start 12: track_origins.pattern 12/49 Test #12: track_origins.pattern .............***Failed 0.34 sec Start 13: fuzz_corpus 13/49 Test #13: fuzz_corpus ....................... Passed 3.56 sec Start 14: fuzz_buffer 14/49 Test #14: fuzz_buffer ....................... Passed 4.62 sec Start 15: fuzz_buffer.replace_buffer 15/49 Test #15: fuzz_buffer.replace_buffer ........ Passed 4.62 sec Start 16: fuzz_buffer.overflow 16/49 Test #16: fuzz_buffer.overflow ..............***Failed 0.34 sec Start 17: fuzz_buffer.mutator.o-b-s-3 17/49 Test #17: fuzz_buffer.mutator.o-b-s-3 ....... Passed 4.59 sec Start 18: fuzz_buffer.mutator.r-b-s-3 18/49 Test #18: fuzz_buffer.mutator.r-b-s-3 ....... Passed 4.63 sec Start 19: fuzz_buffer.mutator.o-b-3 19/49 Test #19: fuzz_buffer.mutator.o-b-3 ......... Passed 4.60 sec Start 20: fuzz_buffer.mutator.r-n 20/49 Test #20: fuzz_buffer.mutator.r-n ........... Passed 4.54 sec Start 21: fuzz_buffer.mutator.random_seed 21/49 Test #21: fuzz_buffer.mutator.random_seed ... Passed 4.57 sec Start 22: fuzz_buffer.one-input 22/49 Test #22: fuzz_buffer.one-input ............. Passed 3.82 sec Start 23: fuzz_buffer.load_input 23/49 Test #23: fuzz_buffer.load_input ............ Passed 3.81 sec Start 24: fuzz_buffer.skip_initial 24/49 Test #24: fuzz_buffer.skip_initial .......... Passed 4.01 sec Start 25: fuzz_buffer.fixed_size 25/49 Test #25: fuzz_buffer.fixed_size ............ Passed 5.36 sec Start 26: fuzz_buffer.offset 26/49 Test #26: fuzz_buffer.offset ................ Passed 5.42 sec Start 27: fuzz_buffer.module_name 27/49 Test #27: fuzz_buffer.module_name ........... Passed 4.58 sec Start 28: fuzz_buffer.dictionary 28/49 Test #28: fuzz_buffer.dictionary ............ Passed 4.20 sec Start 29: fuzz_buffer.cpp 29/49 Test #29: fuzz_buffer.cpp ................... Passed 17.77 sec Start 30: fuzz_custom_mutator 30/49 Test #30: fuzz_custom_mutator ............... Passed 4.57 sec Start 31: drsyscall_test 31/49 Test #31: drsyscall_test .................... Passed 0.22 sec Start 32: strace_test 32/49 Test #32: strace_test ....................... Passed 0.22 sec Start 33: drfuzz_test_empty 33/49 Test #33: drfuzz_test_empty ................. Passed 0.22 sec Start 34: drfuzz_test_mutator 34/49 Test #34: drfuzz_test_mutator ............... Passed 2.38 sec Start 35: drfuzz_test_repeat 35/49 Test #35: drfuzz_test_repeat ................***Failed Start 36: drfuzz_test_segfault 36/49 Test #36: drfuzz_test_segfault .............. Passed 0.20 sec Start 37: drfuzz_test_app_abort 37/49 Test #37: drfuzz_test_app_abort ............. Passed 0.22 sec Start 38: drfuzz_test_no_crash 38/49 Test #38: drfuzz_test_no_crash .............. Passed 0.22 sec Start 39: umbra_test_empty 39/49 Test #39: umbra_test_empty .................. Passed 0.22 sec Start 40: umbra_test_overlap 40/49 Test #40: umbra_test_overlap ................ Passed 0.23 sec Start 41: umbra_test_shadow_mem 41/49 Test #41: umbra_test_shadow_mem ............. Passed 0.30 sec Start 42: umbra_test_insert_app_to_shadow 42/49 Test #42: umbra_test_insert_app_to_shadow ... Passed 0.29 sec Start 43: umbra_test_consistency 43/49 Test #43: umbra_test_consistency ............ Passed 0.30 sec Start 44: umbra_test_allscales 44/49 Test #44: umbra_test_allscales .............. Passed 0.39 sec Start 45: drltrace 45/49 Test #45: drltrace .......................... Passed 0.35 sec Start 46: drltrace_libcalls 46/49 Test #46: drltrace_libcalls ................. Passed 0.36 sec Start 47: drltrace_symargs 47/49 Test #47: drltrace_symargs .................. Passed 0.36 sec Start 48: drltrace_libargs 48/49 Test #48: drltrace_libargs .................. Passed 0.35 sec Start 49: strace_sample 49/49 Test #49: strace_sample ..................... Passed 0.22 sec 88% tests passed, 6 tests failed out of 49 --- CMakeLists.txt | 12 +- common/alloc.c | 7 +- common/asm_utils_aarch64.asm | 133 +++++ common/callstack.c | 190 ++++--- common/sysnum_linux.h | 339 ++++++++++++ common/utils.c | 19 + common/utils.h | 51 ++ drfuzz/CMakeLists.txt | 2 +- drfuzz/drfuzz.c | 13 +- drltrace/CMakeLists.txt | 9 + drltrace/drltrace_linux.config | 1 + drmemory/alloc_drmem.c | 2 +- drmemory/annotations.c | 6 +- drmemory/fastpath.c | 6 +- drmemory/fastpath.h | 7 + drmemory/fastpath_arm.c | 18 +- drmemory/fuzzer.c | 21 +- drmemory/instru.c | 21 +- drmemory/leak.c | 3 +- drmemory/optionsx.h | 10 +- drmemory/pattern.c | 53 +- drmemory/perturb.c | 2 +- drmemory/shadow.c | 228 +++++++- drmemory/shadow.h | 20 + drmemory/slowpath.c | 49 +- drmemory/slowpath.h | 23 +- drmemory/slowpath_arm.c | 345 +++++++++++- drmemory/spill.c | 216 +++++++- drmemory/spill.h | 44 +- drmemory/stack.c | 21 +- drmemory/stack_arch.h | 3 + drmemory/stack_arm.c | 167 ++++-- drmemory/syscall_linux.c | 3 +- drsyscall/aarch64_syscall_num.h | 338 ++++++++++++ drsyscall/drsyscall.c | 8 +- drsyscall/drsyscall.h | 2 +- drsyscall/drsyscall_linux.c | 24 +- drsyscall/table_defines.h | 6 +- drsyscall/table_linux.c | 833 +++++++++++++++-------------- drsyscall/table_linux_ioctl.c | 2 +- tests/CMakeLists.txt | 121 +++-- tests/framework/drsyscall_client.c | 17 +- tests/suppress.c | 3 + umbra/umbra_64.c | 62 ++- 44 files changed, 2740 insertions(+), 720 deletions(-) create mode 100644 common/asm_utils_aarch64.asm create mode 100644 drsyscall/aarch64_syscall_num.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 711106097..c31a64b6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,8 @@ endif () # The target arch: if (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") set(ARM 1) +elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64") + set(AARCH64 1) else () set(X86 1) endif () @@ -323,13 +325,18 @@ if (UNIX) endif () if (ARM) set(EXTRA_FLAGS "${EXTRA_FLAGS} -mthumb -march=armv7-a") + endif () + if (AARCH64) + set(EXTRA_FLAGS "${EXTRA_FLAGS} -march=armv8-a") + endif () + if (ARM OR AARCH64) if (ANDROID OR CMAKE_C_LIBRARY_ARCHITECTURE MATCHES "gnueabi$") set(EXTRA_FLAGS "${EXTRA_FLAGS} -mfloat-abi=softfp") # Android requires PIE. We export symbols to match our test assumptions. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie -Wl,--export-dynamic") - endif () endif () +endif() # We use C++11. set(EXTRA_CXXFLAGS "-std=c++11") set(CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER} @@ -1007,6 +1014,8 @@ set(asm_deps "${DynamoRIO_DIR}/cpp2asm_defines.h") if (ARM) set(asm_file "asm_utils_arm.asm") +elseif (AARCH64) + set(asm_file "asm_utils_aarch64.asm") else () set(asm_file "asm_utils_x86.asm") endif () @@ -1099,6 +1108,7 @@ endfunction(append_src_compile_flags) string(REGEX REPLACE "-D" "" DEFINES_NO_D "${DEFINES}") string(REGEX REPLACE "-D" "" DR_DEFINES_NO_D "${DR_DEFINES}") + option(BUILD_TOOL_TESTS "build Dr. Memory/Dr. Heapstat tests" ON) if (TOOL_DR_HEAPSTAT) diff --git a/common/alloc.c b/common/alloc.c index a83a3d35b..ad5895b70 100644 --- a/common/alloc.c +++ b/common/alloc.c @@ -995,12 +995,16 @@ generate_jmp_ind_stub(void *drcontext, app_pc tgt_pc, byte *epc) instr_t *instr; /* assuming %rax is dead, mov pc => %rax; jmp %rax */ ASSERT(tgt_pc != NULL, "wrong target pc for call stub"); +#ifdef AARCH64 + instr = INSTR_CREATE_b(drcontext, opnd_create_pc(tgt_pc)); +#else instr = INSTR_CREATE_mov_imm(drcontext, opnd_create_reg(DR_REG_XAX), OPND_CREATE_INTPTR(tgt_pc)); epc = instr_encode(drcontext, instr, epc); instr_destroy(drcontext, instr); instr = INSTR_CREATE_jmp_ind(drcontext, opnd_create_reg(DR_REG_XAX)); +#endif epc = instr_encode(drcontext, instr, epc); instr_destroy(drcontext, instr); return epc; @@ -2482,7 +2486,8 @@ find_alloc_routines(const module_data_t *mod, const possible_alloc_routine_t *po instr_init(drcontext, &inst); decode(drcontext, pc, &inst); if (!instr_valid(&inst) || instr_get_opcode(&inst) == - IF_X86_ELSE(OP_jmp_ind, OP_bx)) + IF_AARCH64_ELSE(OP_br || instr_get_opcode(&inst) == OP_blr, + IF_X86_ELSE(OP_jmp_ind, OP_bx))) pc = NULL; instr_free(drcontext, &inst); } else diff --git a/common/asm_utils_aarch64.asm b/common/asm_utils_aarch64.asm new file mode 100644 index 000000000..157dd7005 --- /dev/null +++ b/common/asm_utils_aarch64.asm @@ -0,0 +1,133 @@ +/* ********************************************************** + * Copyright (c) 2012-2015 Google, Inc. All rights reserved. + * **********************************************************/ + +/* Dr. Memory: the memory debugger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License, and no later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* ********************************************************** + * Portions Copyright (c) 2014-2015 Google, Inc. 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. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 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 VMWARE, INC. 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. + */ + + +/*************************************************************************** + * assembly utilities + */ + +#include "cpp2asm_defines.h" + +START_FILE + +/* void get_stack_registers(reg_t *sp OUT, reg_t *fp OUT) */ +/* Get this reviewed. Assuming x0 and x1 hold addresses + * of the memory locations for the arguments which are + * passed by reference. +*/ +#define FUNCNAME get_stack_registers + DECLARE_FUNC(FUNCNAME) +GLOBAL_LABEL(FUNCNAME:) + mov x2, SP + str x2, [x0] + str FP, [x1] + ret + END_FUNC(FUNCNAME) +#undef FUNCNAME + + +#ifdef LINUX +/* Straight from DynamoRIO. + * Signature: raw_syscall(sysnum, num_args, arg1, arg2, ...) + * x8 - syscall number + * x0 to x6 - syscall arguments + */ + DECLARE_FUNC(raw_syscall) +GLOBAL_LABEL(raw_syscall:) + /*Set up first 6 args and read 7th arg from stack + only if there are at least 7 args*/ + cmp w1, #7 + mov x8, x0 + mov x0, x2 + mov x1, x3 + mov x2, x4 + mov x3, x5 + mov x4, x6 + mov x5, x7 + b.cc 1f +1: + svc #0 + ret + END_FUNC(raw_syscall) +#endif /* LINUX */ + + +/* void zero_pointers_on_stack(size_t count); + * assuming count must be multiple of ARG_SZ + * + * Scans the memory in [xsp - count - ARG_SZ, xsp - ARG_SZ) and set it to 0 + * if the content looks like a pointer (> 0x10000). + * Meant to be used to zero the stack, which is dangerous to do + * from C as we can easily clobber our own local variables. + */ +#define FUNCNAME zero_pointers_on_stack + DECLARE_FUNC_SEH(FUNCNAME) +GLOBAL_LABEL(FUNCNAME:) + neg x0, x0 + sub x0, x0, #ARG_SZ + mov x2, #0 +1: + /* we assume no pointer pointing to address below 0x10000 */ + ldr x1, [SP, x0] + cmp x1, HEX(10000) + b.le 2f /* skip store if not a pointer */ + str x2, [SP, x0] +2: + add x0, x0, #ARG_SZ + cmp x0, #-ARG_SZ + bne 1b + ret + END_FUNC(FUNCNAME) +#undef FUNCNAME + + +END_FILE diff --git a/common/callstack.c b/common/callstack.c index fa773f5c2..2c6fb09c9 100644 --- a/common/callstack.c +++ b/common/callstack.c @@ -1056,57 +1056,68 @@ is_retaddr(app_pc pc, bool exclude_tool_lib) bool match; STATS_INC(cstack_is_retaddr_backdecode); DR_TRY_EXCEPT(dr_get_current_drcontext(), { - IF_X86_ELSE({ - match = ((*(pc - 5) == OP_CALL_DIR - /* rule out call to next instr used for PIC */ - IF_UNIX(&& *(int*)(pc - 4) != 0)) || - (*(pc - 2) == OP_CALL_IND && - /* indirect through mem: 0xff /2 (mod==0) - * => top 5 bits are 0x02, and rule out disp32 (rm==0x5) - */ - ((((*(pc - 1) >> 3) == 0x02) && ((*(pc - 1) & 0x3) != 0x5)) || - /* indirect through reg: 0xff /2 (mod==3) + IF_AARCH64_ELSE( + match = + //TODO: Should be checked, BLR + PAC variation? + /* A64 bl