/* This testcase is part of GDB, the GNU debugger.

   Copyright 1998-2017 Free Software Foundation, Inc.

   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/>.  */

/*
 * Test program for trace action commands
 */

#include <string.h>

#include "trace-common.h"

static char   gdb_char_test;
static short  gdb_short_test;
static long   gdb_long_test;
static char   gdb_arr_test[25];
static struct GDB_STRUCT_TEST
{
  char   c;
  short  s;
  long   l;
  int    bfield : 11;	/* collect bitfield */
  char   arr[25];
  struct GDB_STRUCT_TEST *next;
} gdb_struct1_test, gdb_struct2_test, *gdb_structp_test, **gdb_structpp_test;

static union GDB_UNION_TEST
{
  char   c;
  short  s;
  long   l;
  int    bfield : 11;	/* collect bitfield */
  char   arr[4];
  union GDB_UNION_TEST *next;
} gdb_union1_test;

void gdb_recursion_test (int, int, int, int,  int,  int,  int);
/* This function pointer is used to force the function to be called via
   the global entry instead of local entry on ppc64le; otherwise, breakpoints
   set at the global entry (i.e., '*foo') will not be hit.  */
typedef void (*gdb_recursion_test_fp) (int, int, int, int,  int,  int,  int);
gdb_recursion_test_fp gdb_recursion_test_ptr = gdb_recursion_test;

void gdb_recursion_test (int depth, 
			 int q1, 
			 int q2, 
			 int q3, 
			 int q4, 
			 int q5, 
			 int q6)
{	/* gdb_recursion_test line 0 */
  int q = q1;						/* gdbtestline 1 */

  q1 = q2;						/* gdbtestline 2 */
  q2 = q3;						/* gdbtestline 3 */
  q3 = q4;						/* gdbtestline 4 */
  q4 = q5;						/* gdbtestline 5 */
  q5 = q6;						/* gdbtestline 6 */
  q6 = q;						/* gdbtestline 7 */
  if (depth--)						/* gdbtestline 8 */
    gdb_recursion_test_ptr (depth, q1, q2, q3, q4, q5, q6);	/* gdbtestline 9 */
}


unsigned long   gdb_c_test( unsigned long *parm )

{
   char *p = "gdb_c_test";
   char *ridiculously_long_variable_name_with_equally_long_string_assignment;
   register long local_reg = 7;
   static unsigned long local_static, local_static_sizeof;
   long local_long;
   unsigned long *stack_ptr;
   unsigned long end_of_stack;

   ridiculously_long_variable_name_with_equally_long_string_assignment = 
     "ridiculously long variable name with equally long string assignment";
   local_static = 9;
   local_static_sizeof = sizeof (struct GDB_STRUCT_TEST);
   local_long = local_reg + 1;
   stack_ptr  = (unsigned long *) &local_long;
   end_of_stack = 
     (unsigned long) &stack_ptr + sizeof(stack_ptr) + sizeof(end_of_stack) - 1;

   gdb_char_test   = gdb_struct1_test.c = (char)   ((long) parm[1] & 0xff);
   gdb_short_test  = gdb_struct1_test.s = (short)  ((long) parm[2] & 0xffff);
   gdb_long_test   = gdb_struct1_test.l = (long)   ((long) parm[3] & 0xffffffff);
   gdb_union1_test.l = (long) parm[4];
   gdb_arr_test[0] = gdb_struct1_test.arr[0] = (char) ((long) parm[1] & 0xff);
   gdb_arr_test[1] = gdb_struct1_test.arr[1] = (char) ((long) parm[2] & 0xff);
   gdb_arr_test[2] = gdb_struct1_test.arr[2] = (char) ((long) parm[3] & 0xff);
   gdb_arr_test[3] = gdb_struct1_test.arr[3] = (char) ((long) parm[4] & 0xff);
   gdb_arr_test[4] = gdb_struct1_test.arr[4] = (char) ((long) parm[5] & 0xff);
   gdb_arr_test[5] = gdb_struct1_test.arr[5] = (char) ((long) parm[6] & 0xff);
   gdb_struct1_test.bfield = 144;
   gdb_struct1_test.next = &gdb_struct2_test;
   gdb_structp_test      = &gdb_struct1_test;
   gdb_structpp_test     = &gdb_structp_test;

   gdb_recursion_test_ptr (3, (long) parm[1], (long) parm[2], (long) parm[3],
		       (long) parm[4], (long) parm[5], (long) parm[6]);

   gdb_char_test = gdb_short_test = gdb_long_test = 0;
   gdb_structp_test  = (void *) 0;
   gdb_structpp_test = (void *) 0;
   memset ((char *) &gdb_struct1_test, 0, sizeof (gdb_struct1_test));
   memset ((char *) &gdb_struct2_test, 0, sizeof (gdb_struct2_test));
   local_static_sizeof = 0;
   local_static = 0;
   return ( (unsigned long) 0 );
}

void gdb_asm_test (void)
{
}

static void begin ()	/* called before anything else */
{
}

static void end ()	/* called after everything else */
{
}

int
main (argc, argv, envp)
     int argc;
     char *argv[], **envp;
{
  int i;
  unsigned long myparms[10];

  FAST_TRACEPOINT_LABEL (fast_tracepoint_loc);

  begin ();
  for (i = 0; i < sizeof (myparms) / sizeof (myparms[0]); i++)
    myparms[i] = i;

  gdb_c_test (&myparms[0]);

  end ();
  return 0;
}

