Skip to content

Commit

Permalink
i#38 attach: Enable attach on AArch64 (#5460)
Browse files Browse the repository at this point in the history
Implements missing functionality for ptrace attach on AArch64 and
AArch32: generated code sequences were previously x86-only;
-skip_syscall handling only supported x86; and AArch64 does not
support PTRACE_POKEUSER or PTRACE_PEEKUSER.

For AArch32, Thumb vs Arm mode require multiple steps: clearing LSB to
point at the path used as data via a call; switching to Arm mode for
DR's _start; setting the LSB of the initial app PC.

For AArch32, additionally fixes an encoder error where the opcode is
queried before copying a needs-no-encoding instruction.  This is
required for the instruction used to hold data for injection.

Tweaks the disassembler to leave a level 0 instr alone, again to
better handle the data-only insruction used for injection.

Enables the client.attach test on AArch64 and AArch32.  For AArch32,
it needs -skip_syscall.  Long-term we want that on by default
everywhere but we want explicit tests that hit it on all platforms
first.

Tested manually on an AArch32 machine. Unfortunately the client.attach test
is not trival to set up under QEMU with its multiple command lines and
background processes so that is left as beyond the scope of this PR
and is instead considered part of #4719.

Issue: #38
  • Loading branch information
derekbruening authored Apr 13, 2022
1 parent 7795027 commit 19af000
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 88 deletions.
2 changes: 1 addition & 1 deletion api/docs/release.dox
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ changes:
- Nothing yet (placeholder).

Further non-compatibility-affecting changes include:
- Added AArchXX support for attaching to a running process.
- Added new fields analyze_case_ex and instrument_instr_ex to #drbbdup_options_t.
- Added drbbdup support to drwrap via #DRWRAP_INVERT_CONTROL, drwrap_invoke_insert(),
and drwrap_invoke_insert_cleanup_only().
Expand Down Expand Up @@ -1983,7 +1984,6 @@ We hope to include the following major features in future releases:
parent process, injection is very early (before kernel32.dll is loaded),
but we plan to provide injection at the very first user-mode instruction
in the future.
- Linux externally-triggered attaching.
- Persistent and process-shared code caches.
- Full control over trace building.

Expand Down
4 changes: 3 additions & 1 deletion core/arch/aarchxx/aarchxx.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2014-2016 Google, Inc. All rights reserved.
* Copyright (c) 2014-2022 Google, Inc. All rights reserved.
* Copyright (c) 2016 ARM Limited. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -42,6 +42,8 @@ START_FILE
# if !defined(STANDALONE_UNIT_TEST) && !defined(STATIC_LIBRARY)
DECLARE_FUNC(_start)
GLOBAL_LABEL(_start:)
/* i#38: Attaching in middle of blocking syscall requires padded null bytes. */
nop
mov FP, #0 /* clear frame ptr for stack trace bottom */
/* i#1676, i#1708: relocate dynamorio if it is not loaded to preferred address.
* We call this here to ensure it's safe to access globals once in C code
Expand Down
8 changes: 6 additions & 2 deletions core/ir/arm/encode.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2014-2021 Google, Inc. All rights reserved.
* Copyright (c) 2014-2022 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -3033,7 +3033,6 @@ instr_encode_arch(dcontext_t *dcontext, instr_t *instr, byte *copy_pc, byte *fin
}

decode_info_init_for_instr(&di, instr);
di.opcode = instr_get_opcode(instr);
di.check_reachable = check_reachable;
di.start_pc = copy_pc;
di.final_pc = final_pc;
Expand Down Expand Up @@ -3061,6 +3060,11 @@ instr_encode_arch(dcontext_t *dcontext, instr_t *instr, byte *copy_pc, byte *fin
}
CLIENT_ASSERT(instr_operands_valid(instr), "instr_encode error: operands invalid");

/* We delay this until after handling raw instrs to avoid trying to get the opcode
* of a data-only instr.
*/
di.opcode = instr_get_opcode(instr);

info = instr_get_instr_info(instr);
if (info == NULL) {
if (has_instr_opnds != NULL)
Expand Down
22 changes: 14 additions & 8 deletions core/ir/disassemble_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,10 +1522,10 @@ instrlist_disassemble(void *drcontext, app_pc tag, instrlist_t *ilist, file_t ou
level = 4;
/* encode instr and then output as BINARY */
nxt_pc = instr_encode_ignore_reachability(dcontext, instr, bytes);
ASSERT(nxt_pc != NULL);
CLIENT_ASSERT(nxt_pc != NULL, "failed to encode instr");
len = (int)(nxt_pc - bytes);
addr = bytes;
CLIENT_ASSERT(len < 64, "instrlist_disassemble: too-long instr");
CLIENT_ASSERT(len < sizeof(bytes), "instrlist_disassemble: too-long instr");
} else {
addr = instr_get_raw_bits(instr);
len = instr_length(dcontext, instr);
Expand Down Expand Up @@ -1565,12 +1565,18 @@ instrlist_disassemble(void *drcontext, app_pc tag, instrlist_t *ilist, file_t ou
while (len) {
print_file(outfile, " +%-4d %c%d " IF_X64_ELSE("%20s", "%12s"), offs,
instr_is_app(instr) ? 'L' : 'm', level, " ");
next_addr = internal_disassemble_to_file(
dcontext, addr, addr, outfile, false, true,
IF_X64_ELSE(" ",
" "));
if (next_addr == NULL)
break;
/* Leave level 0 alone as it may not be code. */
if (level == 0) {
print_file(outfile, " <...%d bytes...>\n", instr->length);
next_addr = addr + instr->length;
} else {
next_addr = internal_disassemble_to_file(
dcontext, addr, addr, outfile, false, true,
IF_X64_ELSE(" ",
" "));
if (next_addr == NULL)
break;
}
sz = (int)(next_addr - addr);
CLIENT_ASSERT(sz <= len, "instrlist_disassemble: invalid length");
len -= sz;
Expand Down
5 changes: 4 additions & 1 deletion core/ir/opnd.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2011-2022 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -222,6 +222,7 @@ opnd_create_sized_tls_slot(int offs, opnd_size_t size);
/* This should be kept in sync w/ the defines in x86/x86.asm */
enum {
#ifdef X86
DR_SYSNUM_REG = DR_REG_EAX,
# ifdef X64
# ifdef UNIX
/* SysV ABI calling convention */
Expand Down Expand Up @@ -266,12 +267,14 @@ enum {
REGPARM_2 = DR_REG_R2,
REGPARM_3 = DR_REG_R3,
# ifdef X64
DR_SYSNUM_REG = DR_REG_R8,
REGPARM_4 = DR_REG_R4,
REGPARM_5 = DR_REG_R5,
REGPARM_6 = DR_REG_R6,
REGPARM_7 = DR_REG_R7,
NUM_REGPARM = 8,
# else
DR_SYSNUM_REG = DR_REG_R7,
NUM_REGPARM = 4,
# endif /* 64/32 */
REDZONE_SIZE = 0,
Expand Down
Loading

0 comments on commit 19af000

Please sign in to comment.