(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
s390/
tst-ptrace-singleblock.c
       1  /* Testing s390x PTRACE_SINGLEBLOCK ptrace request.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <stdio.h>
      20  #include <stdlib.h>
      21  #include <string.h>
      22  #include <unistd.h>
      23  #include <sys/wait.h>
      24  #include <sys/types.h>
      25  #include <sys/uio.h>
      26  #include <elf.h>
      27  #include <support/xstdlib.h>
      28  #include <support/xunistd.h>
      29  #include <support/check.h>
      30  #include <string.h>
      31  #include <errno.h>
      32  
      33  /* Ensure that we use the PTRACE_SINGLEBLOCK definition from glibc ptrace.h
      34     in tracer_func.  We need the kernel ptrace.h for structs ptrace_area
      35     and gregset_t.  */
      36  #include <sys/ptrace.h>
      37  static const enum __ptrace_request req_singleblock = PTRACE_SINGLEBLOCK;
      38  #include <asm/ptrace.h>
      39  
      40  static void
      41  tracee_func (int pid)
      42  {
      43    /* Dump the mapping information for manual inspection of the printed
      44       tracee addresses.  */
      45    char str[80];
      46    sprintf (str, "cat /proc/%d/maps", pid);
      47    puts (str);
      48    xsystem (str);
      49    fflush (stdout);
      50  
      51    TEST_VERIFY_EXIT (ptrace (PTRACE_TRACEME) == 0);
      52    /* Stop tracee.  Afterwards the tracer_func can operate.  */
      53    kill (pid, SIGSTOP);
      54  
      55    puts ("The PTRACE_SINGLEBLOCK of the tracer will stop after: "
      56  	"brasl %r14,<puts@plt>!");
      57  }
      58  
      59  static void
      60  tracer_func (int pid)
      61  {
      62    unsigned long last_break;
      63    ptrace_area parea;
      64    gregset_t regs;
      65    struct iovec parea2;
      66    gregset_t regs2;
      67  
      68    int status;
      69    int ret;
      70  #define MAX_CHARS_IN_BUF 4096
      71    char buf[MAX_CHARS_IN_BUF + 1];
      72    size_t buf_count;
      73  
      74    while (1)
      75      {
      76        /* Wait for the tracee to be stopped or exited.  */
      77        wait (&status);
      78        if (WIFEXITED (status))
      79  	break;
      80  
      81        /* Get information about tracee: gprs, last breaking address.  */
      82        parea.len = sizeof (regs);
      83        parea.process_addr = (unsigned long) &regs;
      84        parea.kernel_addr = 0;
      85        TEST_VERIFY_EXIT (ptrace (PTRACE_PEEKUSR_AREA, pid, &parea) == 0);
      86        TEST_VERIFY_EXIT (ptrace (PTRACE_GET_LAST_BREAK, pid, NULL, &last_break)
      87  			== 0);
      88  
      89        parea2.iov_len = sizeof (regs2);
      90        parea2.iov_base = &regs2;
      91        TEST_VERIFY_EXIT (ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &parea2)
      92  			== 0);
      93        TEST_VERIFY_EXIT (parea2.iov_len == sizeof (regs2));
      94  
      95        /* Test if gprs obtained by PTRACE_PEEKUSR_AREA and PTRACE_GETREGESET
      96  	 have the same values.  */
      97        TEST_VERIFY_EXIT (memcmp (&regs, &regs2, sizeof (regs)) == 0);
      98  
      99        printf ("child IA: %p last_break: %p\n",
     100  	      (void *) regs[1], (void *) last_break);
     101  
     102        /* Execute tracee until next taken branch.
     103  
     104  	 Note:
     105  	 Before the commit which introduced this testcase,
     106  	 <glibc>/sysdeps/unix/sysv/linux/s390/sys/ptrace.h
     107  	 uses ptrace-request 12 for PTRACE_GETREGS,
     108  	 but <kernel>/include/uapi/linux/ptrace.h
     109  	 uses 12 for PTRACE_SINGLEBLOCK.
     110  
     111  	 The s390 kernel has no support for PTRACE_GETREGS!
     112  	 Thus glibc ptrace.h is adjusted to match kernel ptrace.h.
     113  
     114  	 The glibc sys/ptrace.h header contains the identifier
     115  	 PTRACE_SINGLEBLOCK in enum __ptrace_request.  In contrast, the kernel
     116  	 asm/ptrace.h header defines PTRACE_SINGLEBLOCK.
     117  
     118  	 This test ensures, that PTRACE_SINGLEBLOCK defined in glibc
     119  	 works as expected.  If the kernel would interpret it as
     120  	 PTRACE_GETREGS, then the tracee will not make any progress
     121  	 and this testcase will time out or the ptrace call will fail with
     122  	 different errors.  */
     123  
     124        /* Ptrace request 12 is first done with data argument pointing to
     125  	 a buffer:
     126  	 -If request 12 is interpreted as PTRACE_GETREGS, it will store the regs
     127  	 to buffer without an error.
     128  
     129  	 -If request 12 is interpreted as PTRACE_SINGLEBLOCK, it will fail
     130  	 as data argument is used as signal-number and the address of
     131  	 buf is no valid signal.
     132  
     133  	 -If request 12 is not implemented, it will also fail.
     134  
     135  	 Here the test expects that the buffer is untouched and an error is
     136  	 returned.  */
     137        memset (buf, 'a', MAX_CHARS_IN_BUF);
     138        ret = ptrace (req_singleblock, pid, NULL, buf);
     139        buf [MAX_CHARS_IN_BUF] = '\0';
     140        buf_count = strspn (buf, "a");
     141        TEST_VERIFY_EXIT (buf_count == MAX_CHARS_IN_BUF);
     142        TEST_VERIFY_EXIT (ret == -1);
     143  
     144        /* If request 12 is interpreted as PTRACE_GETREGS, the first ptrace
     145  	 call will touch the buffer which is detected by this test.  */
     146        errno = 0;
     147        ret = ptrace (req_singleblock, pid, NULL, NULL);
     148        if (ret == 0)
     149  	{
     150  	  /* The kernel has support for PTRACE_SINGLEBLOCK ptrace request. */
     151  	  TEST_VERIFY_EXIT (errno == 0);
     152  	}
     153        else
     154  	{
     155  	  /* The kernel (< 3.15) has no support for PTRACE_SINGLEBLOCK ptrace
     156  	     request. */
     157  	  TEST_VERIFY_EXIT (errno == EIO);
     158  	  TEST_VERIFY_EXIT (ret == -1);
     159  
     160  	  /* Just continue tracee until it exits normally.  */
     161  	  TEST_VERIFY_EXIT (ptrace (PTRACE_CONT, pid, NULL, NULL) == 0);
     162  	}
     163      }
     164  }
     165  
     166  static int
     167  do_test (void)
     168  {
     169    int pid;
     170    pid = xfork ();
     171    if (pid)
     172      tracer_func (pid);
     173    else
     174      tracee_func (getpid ());
     175  
     176    return EXIT_SUCCESS;
     177  }
     178  
     179  #include <support/test-driver.c>