(root)/
strace-6.5/
tests/
prctl-fp-mode.c
       1  /*
       2   * Check decoding of prctl PR_GET_FP_MODE/PR_SET_FP_MODE operations.
       3   *
       4   * Copyright (c) 2021 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include "scno.h"
      12  #include <errno.h>
      13  #include <stdio.h>
      14  #include <stdlib.h>
      15  #include <unistd.h>
      16  #include <linux/prctl.h>
      17  
      18  static long injected_val;
      19  
      20  static long
      21  do_prctl(kernel_ulong_t cmd, kernel_ulong_t arg2, kernel_ulong_t arg3)
      22  {
      23  	long rc = syscall(__NR_prctl, cmd, arg2, arg3);
      24  
      25  	if (rc != injected_val)
      26  		error_msg_and_fail("Return value (%ld) differs from expected "
      27  						   "injected value (%ld)",
      28  						   rc, injected_val);
      29  
      30  	return rc;
      31  }
      32  
      33  int
      34  main(int argc, char **argv)
      35  {
      36  	static const kernel_ulong_t bogus_arg2 =
      37  			(kernel_ulong_t) 0xdecafeedbeefda7eULL;
      38  	static const kernel_ulong_t bogus_arg3 =
      39  			(kernel_ulong_t) 0xdecafeedbeefda7eULL;
      40  
      41  	static const struct {
      42  		long arg;
      43  		const char *str;
      44  	} get_strs[] = {
      45  			{-1,       ""},
      46  			{0,        ""},
      47  			{1,        " (PR_FP_MODE_FR)"},
      48  			{2,        " (PR_FP_MODE_FRE)"},
      49  			{3,        " (PR_FP_MODE_FR|PR_FP_MODE_FRE)"},
      50  			{0x20,     ""},
      51  			{0x20 | 3, " (PR_FP_MODE_FR|PR_FP_MODE_FRE|0x20)"}
      52  	};
      53  	static const struct {
      54  		kernel_ulong_t arg;
      55  		const char *str;
      56  	} set_strs[] = {
      57  			{0,        "0"},
      58  			{1,        "PR_FP_MODE_FR"},
      59  			{2,        "PR_FP_MODE_FRE"},
      60  			{3,        "PR_FP_MODE_FR|PR_FP_MODE_FRE"},
      61  			{0x20,     "0x20 /* PR_FP_MODE_??? */"},
      62  			{0x20 | 3, "PR_FP_MODE_FR|PR_FP_MODE_FRE|0x20"}
      63  	};
      64  
      65  	long rc;
      66  	unsigned long num_skip;
      67  	const char *str = NULL;
      68  	bool locked = false;
      69  
      70  	if (argc < 3)
      71  		error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
      72  
      73  	num_skip = strtoul(argv[1], NULL, 0);
      74  	injected_val = strtol(argv[2], NULL, 0);
      75  
      76  	for (size_t i = 0; i < num_skip; i++) {
      77  		if ((prctl_marker() != injected_val) ||
      78  		    ((injected_val == -1) && (errno != ENOTTY)))
      79  			continue;
      80  
      81  		locked = true;
      82  		break;
      83  	}
      84  
      85  	if (!locked)
      86  		error_msg_and_fail("Have not locked on prctl(-1, -2, -3, -4"
      87  				   ", -5) returning %ld", injected_val);
      88  
      89  	/* PR_GET_FP_MODE */
      90  	rc = do_prctl(PR_GET_FP_MODE, bogus_arg2, bogus_arg3);
      91  
      92  	for (size_t i = 0; i < ARRAY_SIZE(get_strs); i++) {
      93  		if (get_strs[i].arg == rc) {
      94  			str = get_strs[i].str;
      95  			break;
      96  		}
      97  	}
      98  	if (!str)
      99  		error_msg_and_fail("Unknown return value: %ld", rc);
     100  
     101  	if (rc < 0) {
     102  		printf("prctl(PR_GET_FP_MODE) = %s%s (INJECTED)\n",
     103  		       sprintrc(rc), str);
     104  	} else {
     105  		printf("prctl(PR_GET_FP_MODE) = %#lx%s (INJECTED)\n",
     106  		       rc, str);
     107  	}
     108  
     109  	/* PR_SET_FP_MODE */
     110  	for (size_t i = 0; i < ARRAY_SIZE(set_strs); i++) {
     111  		rc = do_prctl(PR_SET_FP_MODE, set_strs[i].arg, bogus_arg3);
     112  
     113  		printf("prctl(PR_SET_FP_MODE, %s) = %s (INJECTED)\n", set_strs[i].str,
     114  			   sprintrc(rc));
     115  	}
     116  
     117  	puts("+++ exited with 0 +++");
     118  	return 0;
     119  }