/* A concatenation of varinfo1 .. varinfo4 in a shared object.  This
   is to check for correct functionality in a non-zero-biased ELF
   executable. */

/* Relevant compile flags are:

   -Wall -g -I$prefix/include/valgrind

   eg -Wall -g -I`pwd`/Inst/include/valgrind
*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "memcheck/memcheck.h"

/* Cause memcheck to complain about the address "a" and so to print
   its best guess as to what "a" actually is.  a must be
   addressible. */
__attribute__((noinline))
void croak ( void* aV )
{
  char* a = (char*)aV;
  char* undefp = malloc(1);
  char saved = *a;
  assert(undefp);
  *a = *undefp;
  (void) VALGRIND_CHECK_MEM_IS_DEFINED(a, 1);
  *a = saved;
  free(undefp);
}

#include <stdio.h>

/* ------------ varinfo1 ------------ */

int global_u1;

int global_i1 = 17;

char global_u2[10];

char global_i2[10] = { 1,2,3,4,5,6,7,8,9,10 };

__attribute__((noinline))
static int varinfo1_main ( void )
{
  int local;
  char* onheap = malloc(3);
  assert(onheap);
  croak(onheap+1);
  free(onheap);

  croak( &global_u1 );
  croak( &global_i1 );
  croak( &global_u2[3] );
  croak( &global_i2[7] );
  croak( &local );
  return 0;
}

/* ------------ varinfo2 ------------ */
__attribute__((noinline))
static void foo2 ( void )
{
  int var;
  var = 1;
  { char var[10];
    var[6] = 4;
    croak( &var[7] );
    { struct { double foo; float bar; } var;
      croak ( 2 + (char*)&var.bar );
    }
  }
  croak( 1 + (char*)&var );
}
__attribute__((noinline))
static int varinfo2_main ( void )
{
  foo2();
  return 0;
}

/* ------------ varinfo3 ------------ */

static char static_global_def[10]    = {0,0,0,0,0, 0,0,0,0,0};
       char nonstatic_global_def[10] = {0,0,0,0,0, 0,0,0,0,0};
static char static_global_undef[10];
       char nonstatic_global_undef[10];
__attribute__((noinline))
static void bar3 ( char* p1, char* p2, char* p3, char* p4 )
{
   croak(p1);
   croak(p2);
   croak(p3);
   croak(p4);
}
__attribute__((noinline))
static void foo3 ( void )
{
   static char static_local_def[10]    = {0,0,0,0,0, 0,0,0,0,0};
          char nonstatic_local_def[10] = {0,0,0,0,0, 0,0,0,0,0};
   static char static_local_undef[10];
          char nonstatic_local_undef[10];
   croak ( 1 + (char*)&static_global_def );
   croak ( 2 + (char*)&nonstatic_global_def );
   croak ( 3 + (char*)&static_global_undef );
   croak ( 4 + (char*)&nonstatic_global_undef );
   bar3( 5 + (char*)&static_local_def,
         6 + (char*)&nonstatic_local_def,
         7 + (char*)&static_local_undef,
         8 + (char*)&nonstatic_local_undef );
}
__attribute__((noinline))
static int varinfo3_main ( void )
{
  foo3();
  return 0;
}

/* ------------ varinfo4 ------------ */

#include <string.h>

typedef struct { short c1; char* c2[3]; } XX;

typedef
   struct _str { int bing; int bong; XX xyzzy[77]; }
   Str;

__attribute__((noinline))
static int blah4 ( int x, int y )
{
  Str a[10];
  memset(a, 0, sizeof(a));
  croak(1 + (char*)(&a[3].xyzzy[x*y].c1));
  croak( (char*)(&a[5].bong) );
  croak( 1 + (char*)(&a[3].xyzzy[x*y].c2[2]) );
  memset(a, 0, sizeof(a));
  return a[3].xyzzy[x*y].c1;
}
__attribute__((noinline))
static int varinfo4_main ( void )
{
  fprintf(stderr, "answer is %d\n", blah4(3,7) );
  return 0;
}
static void inlinetest(void);
/* ------------ varinfo5 ------------ */

void varinfo5_main ( void )
{
   varinfo1_main();
   varinfo2_main();
   varinfo3_main();
   varinfo4_main();
   inlinetest();
}

#define INLINE    inline __attribute__((always_inline))

INLINE void fun_c(int argc) {
   croak(&argc);
}

INLINE void fun_b(int argb) {
   fun_c(argb);
}

INLINE void fun_a(int *arga) {
   fun_b(*arga);
}

void inlinetest(void)
{
   int i = 1;
   fun_a(&i);
}