/* Copyright (C) 2014-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <sys/prctl.h>
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#if defined PR_GET_FP_MODE && defined PR_SET_FP_MODE
# define HAVE_PRCTL_FP_MODE 1
# define FR1_MODE (PR_FP_MODE_FR)
# define FRE_MODE (PR_FP_MODE_FR | PR_FP_MODE_FRE)
#else
# define HAVE_PRCTL_FP_MODE 0
# define FR1_MODE 0x1
# define FRE_MODE 0x2
#endif
#define STR_VAL(VAL) #VAL
#define N_STR(VAL) STR_VAL(VAL)
#define START_STATE(NAME) \
case s_ ## NAME: \
{ \
switch (obj) \
{
#define END_STATE \
default: \
return false; \
} \
break; \
}
#define NEXT(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
current_fp_state = s_ ## NEXT_STATE; \
break;
#define NEXT_REQ_FR1(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (has_fr1) \
current_fp_state = s_ ## NEXT_STATE; \
else \
return false; \
} \
break;
#define NEXT_REQ_FR0(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (!is_r6 \
|| (is_r6 && has_fr1 && has_fre)) \
current_fp_state = s_ ## NEXT_STATE; \
else \
return false; \
} \
break;
#define NEXT_REQ_FRE(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (has_fr1 && has_fre) \
current_fp_state = s_ ## NEXT_STATE; \
else \
return false; \
} \
break;
#define NEXT_NO_MODE_CHANGE(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (current_mode_valid_p (s_ ## NEXT_STATE)) \
{ \
current_fp_state = s_ ## NEXT_STATE; \
cant_change_mode = true; \
} \
else \
return false; \
} \
break;
static const char * const shared_lib_names[] =
{
"tst-abi-fpanymod.so", "tst-abi-fpsoftmod.so", "tst-abi-fpsinglemod.so",
"tst-abi-fp32mod.so", "tst-abi-fp64mod.so", "tst-abi-fp64amod.so",
"tst-abi-fpxxmod.so", "tst-abi-fpxxomod.so"
};
struct fp_mode_req
{
int mode1;
int mode2;
int mode3;
};
enum fp_obj
{
o_any,
o_soft,
o_single,
o_fp32,
o_fp64,
o_fp64a,
o_fpxx,
o_fpxxo,
o_max
};
enum fp_state
{
s_any,
s_soft,
s_single,
s_fp32,
s_fpxx,
s_fpxxo,
s_fp64a,
s_fp64,
s_fpxxo_fpxx,
s_fp32_fpxx,
s_fp32_fpxxo,
s_fp32_fpxxo_fpxx,
s_fp32_fp64a_fpxx,
s_fp32_fp64a_fpxxo,
s_fp32_fp64a_fpxxo_fpxx,
s_fp64a_fp32