[binutils-gdb] AArch64: Detect exit from execve syscall

Alan Hayward alahay01@sourceware.org
Mon Feb 11 16:49:00 GMT 2019


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ea638c43121624bb4b09bb89b88314f99c85a48d

commit ea638c43121624bb4b09bb89b88314f99c85a48d
Author: Alan Hayward <alan.hayward@arm.com>
Date:   Mon Feb 11 16:38:29 2019 +0000

    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.

Diff:
---
 gdb/ChangeLog            |  5 +++++
 gdb/aarch64-linux-tdep.c | 56 +++++++++++++++++++++++++++++-------------------
 2 files changed, 39 insertions(+), 22 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f4f0c0c..4ab3af0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 62cfc76..39e6076 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -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



More information about the Gdb-cvs mailing list