/* Self tests for gdbarch for GDB, the GNU debugger.

   Copyright (C) 2017-2025 Free Software Foundation, Inc.

   This file is part of GDB.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include "gdbsupport/selftest.h"
#include "selftest-arch.h"
#include "target.h"
#include "test-target.h"
#include "target-float.h"
#include "gdbsupport/def-vector.h"
#include "gdbarch.h"
#include "scoped-mock-context.h"
#include "gdbsupport/unordered_map.h"

namespace selftests {

/* Test gdbarch methods register_to_value and value_to_register.  */

static void
register_to_value_test (struct gdbarch *gdbarch)
{
  const struct builtin_type *builtin = builtin_type (gdbarch);
  struct type *types[] =
    {
      builtin->builtin_void,
      builtin->builtin_char,
      builtin->builtin_short,
      builtin->builtin_int,
      builtin->builtin_long,
      builtin->builtin_signed_char,
      builtin->builtin_unsigned_short,
      builtin->builtin_unsigned_int,
      builtin->builtin_unsigned_long,
      builtin->builtin_float,
      builtin->builtin_double,
      builtin->builtin_long_double,
      builtin->builtin_complex,
      builtin->builtin_double_complex,
      builtin->builtin_string,
      builtin->builtin_bool,
      builtin->builtin_long_long,
      builtin->builtin_unsigned_long_long,
      builtin->builtin_int8,
      builtin->builtin_uint8,
      builtin->builtin_int16,
      builtin->builtin_uint16,
      builtin->builtin_int32,
      builtin->builtin_uint32,
      builtin->builtin_int64,
      builtin->builtin_uint64,
      builtin->builtin_int128,
      builtin->builtin_uint128,
      builtin->builtin_char16,
      builtin->builtin_char32,
    };

  scoped_mock_context<test_target_ops> mockctx (gdbarch);

  frame_info_ptr frame = get_current_frame ();
  const int num_regs = gdbarch_num_cooked_regs (gdbarch);

  /* Test gdbarch methods register_to_value and value_to_register with
     different combinations of register numbers and types.  */
  for (const auto &type : types)
    {
      for (auto regnum = 0; regnum < num_regs; regnum++)
	{
	  if (gdbarch_convert_register_p (gdbarch, regnum, type))
	    {
	      std::vector<gdb_byte> expected (type->length (), 0);

	      if (type->code () == TYPE_CODE_FLT)
		{
		  /* Generate valid float format.  */
		  target_float_from_string (expected.data (), type, "1.25");
		}
	      else
		{
		  for (auto j = 0; j < expected.size (); j++)
		    expected[j] = (regnum + j) % 16;
		}

	      gdbarch_value_to_register (gdbarch, frame, regnum, type,
					 expected.data ());

	      /* Allocate two bytes more for overflow check.  */
	      std::vector<gdb_byte> buf (type->length () + 2, 0);
	      int optim, unavail, ok;

	      /* Set the fingerprint in the last two bytes.  */
	      buf [type->length ()]= 'w';
	      buf [type->length () + 1]= 'l';
	      ok = gdbarch_register_to_value (gdbarch, frame, regnum, type,
					      buf.data (), &optim, &unavail);

	      SELF_CHECK (ok);
	      SELF_CHECK (!optim);
	      SELF_CHECK (!unavail);

	      SELF_CHECK (buf[type->length ()] == 'w');
	      SELF_CHECK (buf[type->length () + 1] == 'l');

	      for (auto k = 0; k < type->length (); k++)
		SELF_CHECK (buf[k] == expected[k]);
	    }
	}
    }
}

/* Test function gdbarch_register_name.  */

static void
register_name_test (struct gdbarch *gdbarch)
{
  if (selftest_skip_warning_arch (gdbarch))
    return;

  scoped_mock_context<test_target_ops> mockctx (gdbarch);

  /* Track the number of times each register name appears.  */
  gdb::unordered_map<std::string, int> name_counts;

  const int num_regs = gdbarch_num_cooked_regs (gdbarch);
  for (auto regnum = 0; regnum < num_regs; regnum++)
    {
      /* If a register is to be hidden from the user then we should get
	 back an empty string, not nullptr.  Every other register should
	 return a non-empty string.  */
      const char *name = gdbarch_register_name (gdbarch, regnum);

      if (run_verbose() && name == nullptr)
	debug_printf ("arch: %s, register: %d returned nullptr\n",
		      gdbarch_bfd_arch_info (gdbarch)->printable_name,
		      regnum);
      SELF_CHECK (name != nullptr);

      /* Every register name, that is not the empty string, should be
	 unique.  If this is not the case then the user will see duplicate
	 copies of the register in e.g. 'info registers' output, but will
	 only be able to interact with one of the copies.  */
      if (*name != '\0')
	{
	  std::string s (name);
	  name_counts[s]++;
	  if (run_verbose() && name_counts[s] > 1)
	    debug_printf ("arch: %s, register: %d (%s) is a duplicate\n",
			  gdbarch_bfd_arch_info (gdbarch)->printable_name,
			  regnum, name);
	  SELF_CHECK (name_counts[s] == 1);
	}
    }
}

/* Test gdbarch_stack_grows_down.  Stacks must either grow down or up.  */

static void
check_stack_growth (struct gdbarch *gdbarch)
{
  /* We don't call gdbarch_stack_grows_down here, instead we're testing the
     implementation by calling gdbarch_inner_than.  GDB assumes that stacks
     either grow down or up (see uses of gdbarch_stack_grows_down), so exactly
     one of these needs to be true.  */
  bool stack_grows_down = gdbarch_inner_than (gdbarch, 1, 2);
  bool stack_grows_up = gdbarch_inner_than (gdbarch, 2, 1);

  SELF_CHECK (stack_grows_up != stack_grows_down);
}

} /* namespace selftests */

INIT_GDB_FILE (gdbarch_selftests)
{
  selftests::register_test_foreach_arch ("register_to_value",
					 selftests::register_to_value_test);

  selftests::register_test_foreach_arch ("register_name",
					 selftests::register_name_test);

  selftests::register_test_foreach_arch ("stack_growth",
					 selftests::check_stack_growth);
}
