AArch64: Detect exit from execve syscall
Checking the syscall number when stopped on entry/exit relies on checking the value in register X8. However, on exit from an execve syscall, the registers will all be cleared. Given this is only checked on syscall entry/exit, then a cleared register state either means execve exit or syscall 0 (io_setup) entry with invalid parameters and an invalid FR and LR, which in reality should never happen. Use this to detect execve exit. Move function to allow use of aarch64_sys_execve enum, and use newer regcache functions. Fixes gdb.base/catch-syscall.exp on Aarch64. gdb/ChangeLog: * aarch64-linux-tdep.c (aarch64_linux_get_syscall_number): Check for execve.
This commit is contained in:
parent
7115ab9c4b
commit
ea638c4312
|
@ -1,3 +1,8 @@
|
|||
2019-02-11 Alan Hayward <alan.hayward@arm.com>
|
||||
|
||||
* aarch64-linux-tdep.c (aarch64_linux_get_syscall_number): Check
|
||||
for execve.
|
||||
|
||||
2019-02-10 Philippe Waroquiers <philippe.waroquiers@skynet.be>
|
||||
|
||||
* c-exp.y (direct_abs_decl): Use emplace_back to record the
|
||||
|
|
|
@ -757,28 +757,6 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Implement the "get_syscall_number" gdbarch method. */
|
||||
|
||||
static LONGEST
|
||||
aarch64_linux_get_syscall_number (struct gdbarch *gdbarch,
|
||||
thread_info *thread)
|
||||
{
|
||||
struct regcache *regs = get_thread_regcache (thread);
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
|
||||
/* The content of register x8. */
|
||||
gdb_byte buf[X_REGISTER_SIZE];
|
||||
/* The result. */
|
||||
LONGEST ret;
|
||||
|
||||
/* Getting the system call number from the register x8. */
|
||||
regs->cooked_read (AARCH64_DWARF_X0 + 8, buf);
|
||||
|
||||
ret = extract_signed_integer (buf, X_REGISTER_SIZE, byte_order);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* AArch64 process record-replay constructs: syscall, signal etc. */
|
||||
|
||||
struct linux_record_tdep aarch64_linux_record_tdep;
|
||||
|
@ -1334,6 +1312,40 @@ aarch64_canonicalize_syscall (enum aarch64_syscall syscall_number)
|
|||
}
|
||||
}
|
||||
|
||||
/* Retrieve the syscall number at a ptrace syscall-stop, either on syscall entry
|
||||
or exit. Return -1 upon error. */
|
||||
|
||||
static LONGEST
|
||||
aarch64_linux_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread)
|
||||
{
|
||||
struct regcache *regs = get_thread_regcache (thread);
|
||||
LONGEST ret;
|
||||
|
||||
/* Get the system call number from register x8. */
|
||||
regs->cooked_read (AARCH64_X0_REGNUM + 8, &ret);
|
||||
|
||||
/* On exit from a successful execve, we will be in a new process and all the
|
||||
registers will be cleared - x0 to x30 will be 0, except for a 1 in x7.
|
||||
This function will only ever get called when stopped at the entry or exit
|
||||
of a syscall, so by checking for 0 in x0 (arg0/retval), x1 (arg1), x8
|
||||
(syscall), x29 (FP) and x30 (LR) we can infer:
|
||||
1) Either inferior is at exit from sucessful execve.
|
||||
2) Or inferior is at entry to a call to io_setup with invalid arguments and
|
||||
a corrupted FP and LR.
|
||||
It should be safe enough to assume case 1. */
|
||||
if (ret == 0)
|
||||
{
|
||||
LONGEST x1 = -1, fp = -1, lr = -1;
|
||||
regs->cooked_read (AARCH64_X0_REGNUM + 1, &x1);
|
||||
regs->cooked_read (AARCH64_FP_REGNUM, &fp);
|
||||
regs->cooked_read (AARCH64_LR_REGNUM, &lr);
|
||||
if (x1 == 0 && fp ==0 && lr == 0)
|
||||
return aarch64_sys_execve;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Record all registers but PC register for process-record. */
|
||||
|
||||
static int
|
||||
|
|
Loading…
Reference in New Issue