/* -*- Mode: C; indent-tabs-mode: nil -*- */
/*
 *             COPYRIGHT (c) 1994 BY             *
 *  GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS.  *
 *             ALL RIGHTS RESERVED               *

Permission to use, copy, modify, distribute and sell this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all copies
and that both that copyright notice and this permission notice appear
in supporting documentation, and that the name of the author
not be used in advertising or publicity pertaining to distribution
of the software without specific, written prior permission.

THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

The purpose of this routine is to attempt to detect the use of
procedure descriptors by making a note of how far apart the
system allocates pointers to subroutines of different sizes.
If all the subroutines are the same distance apart then
procedure descriptors are probably in use on this architecture.

This file should be compiled without any compiler optimization
such as inlining that would confuse the test. Although base functions
have been made somewhat complex in order to avoid that in any case.

Now if a linker lays out procedures like this:

[DESCRIPTOR][CODE TEXT...][DESCRIPTOR][CODE TEXT...]

Then this code will be confused into thinking descriptors aren't used.
But usually the hallmark of a descriptor architecture is that descriptors
are in a table located away from the program code text.

The -examine <nbytes> argument lets you see in a crude way what
is contained in the pointer to a procedure data.

19-MAY-1994 GJC@WORLD.STD.COM

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef WIN32
#include <windows.h>
#endif

struct v
{
  long n;
  double *a;
};

struct v *
vcons (n, x)
     long n;
     double x;
{
  struct v *p;
  long j;
  p = (struct v *) malloc (sizeof (struct v));
  p->n = n;
  p->a = (double *) malloc (sizeof (double) * n);
  for (j = 0; j < n; ++j)
    p->a[j] = x;
  return (p);
}

struct v *
vprod (x, y)
     struct v *x, *y;
{
  struct v *z;
  long j;
  z = vcons (x->n, 0.0);
  for (j = 0; j < x->n; ++j)
    z->a[j] = x->a[j] * y->a[j];
  return (z);
}

double
vsume (x)
     struct v *x;
{
  double sum = 0.0;
  long j;
  for (j = 0; j < x->n; ++j)
    sum += x->a[j];
  return (sum);
}

double
viprod (x, y)
     struct v *x, *y;
{
  return (vsume (vprod (x, y)));
}

double
vnorm (x)
     struct v *x;
{
  return (viprod (x, x));
}

double
case10 ()
{
  double acc = 0.0;
  acc += vnorm (vcons ((long) vsume (vcons (0, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (1, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (2, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (3, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (4, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (5, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (6, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (7, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (8, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (9, 1.0)), 2.0));
  return (acc);
}

double
case20 ()
{
  double acc = 0.0;
  acc += vnorm (vcons ((long) vsume (vcons (0, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (1, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (2, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (3, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (4, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (5, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (6, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (7, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (8, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (9, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (10, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (11, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (12, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (13, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (14, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (15, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (16, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (17, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (18, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (19, 1.0)), 2.0));
  return (acc);
}

double
case30 ()
{
  double acc = 0.0;
  acc += vnorm (vcons ((long) vsume (vcons (0, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (1, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (2, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (3, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (4, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (5, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (6, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (7, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (8, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (9, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (10, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (11, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (12, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (13, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (14, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (15, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (16, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (17, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (18, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (19, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (20, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (21, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (22, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (23, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (24, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (25, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (26, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (27, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (28, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (29, 1.0)), 2.0));
  return (acc);
}

double
case40 ()
{
  double acc = 0.0;
  acc += vnorm (vcons ((long) vsume (vcons (0, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (1, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (2, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (3, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (4, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (5, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (6, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (7, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (8, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (9, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (10, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (11, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (12, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (13, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (14, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (15, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (16, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (17, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (18, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (19, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (20, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (21, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (22, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (23, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (24, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (25, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (26, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (27, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (28, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (29, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (30, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (31, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (32, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (33, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (34, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (35, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (36, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (37, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (38, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (39, 1.0)), 2.0));
  return (acc);
}

double
case50 ()
{
  double acc = 0.0;
  acc += vnorm (vcons ((long) vsume (vcons (0, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (1, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (2, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (3, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (4, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (5, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (6, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (7, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (8, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (9, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (10, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (11, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (12, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (13, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (14, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (15, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (16, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (17, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (18, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (19, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (20, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (21, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (22, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (23, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (24, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (25, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (26, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (27, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (28, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (29, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (30, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (31, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (32, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (33, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (34, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (35, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (36, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (37, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (38, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (39, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (40, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (41, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (42, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (43, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (44, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (45, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (46, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (47, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (48, 1.0)), 2.0));
  acc += vnorm (vcons ((long) vsume (vcons (49, 1.0)), 2.0));
  return (acc);
}

void
sayarch (x)
     char *x;
{
  printf ("This architecture %s procedure descriptors\n", x);
}


struct apair
{
  char *name;
  unsigned long addr;
};
struct adelt
{
  long delta;
  long count;
};

#ifndef WIN32
#define __cdecl
#endif

int __cdecl
apairl (const void *v_a, const void *v_b)
{
  const struct apair *a = v_a;
  const struct apair *b = v_b;
  if (a->addr < b->addr)
    return (-1);
  else if (a->addr > b->addr)
    return (1);
  else
    return (0);
}

int __cdecl
adeltl (const void *v_a, const void *v_b)
{
  const struct adelt *a = v_a;
  const struct adelt *b = v_b;

  if (a->delta < b->delta)
    return (-1);
  else if (a->delta > b->delta)
    return (1);
  else
    return (0);
}

#ifdef WIN32
void
describe_system_info(void)
{
  /* %I64X */

  SYSTEM_INFO si;
  GetSystemInfo(&si);
  printf ("%30s = %ld\n", "wProcessorArchitecture", (long) si.wProcessorArchitecture);
  printf ("%30s = %ld\n", "wReserved;", (long) si.wReserved);
  printf ("%30s = %ld\n", "dwPageSize", (long) si.dwPageSize);
  printf ("%30s = 0x%016llX\n", "lpMinimumApplicationAddress", (long long) si.lpMinimumApplicationAddress);
  printf ("%30s = 0x%016llX\n", "lpMaximumApplicationAddress", (long long) si.lpMaximumApplicationAddress);
  printf ("%30s = 0x%lX\n", "dwActiveProcessorMask", (long) si.dwActiveProcessorMask);
  printf ("%30s = %ld\n", "dwNumberOfProcessors", (long) si.dwNumberOfProcessors);
  printf ("%30s = %ld\n", "dwProcessorType", (long) si.dwProcessorType);
  printf ("%30s = %ld\n", "dwAllocationGranularity", (long) si.dwAllocationGranularity);
  printf ("%30s = %ld\n", "wProcessorLevel", (long) si.wProcessorLevel);
  printf ("%30s = 0x%lX\n", "wProcessorRevision", (long) si.wProcessorRevision);
}
#endif

int
main (argc, argv)
     int argc;
     char **argv;
{
  struct apair all[10];
  struct adelt deltas[10];
  long j, k, n = 10, min_delta, max_delta, delta, d, ebytes = 0;
  unsigned char *data, *prev_data;
  printf ("Crashme(pddet): (c) Copyright 1990-2014 George J. Carrette\n");
  printf ("From http://alum.mit.edu/www/gjc/crashme.html\n");
  printf ("sizeof(char)   = %ld\n", (long) sizeof (char));
  printf ("sizeof(char *) = %ld\n", (long) sizeof (char *));
  printf ("sizeof(int)    = %ld\n", (long) sizeof (int));
  printf ("sizeof(long)   = %ld\n", (long) sizeof (long));
#ifdef WIN32
  describe_system_info ();
#endif
  for (j = 1; (j + 1) < argc; j += 2)
    {
      if (strcmp (argv[j], "-examine") == 0)
        ebytes = atol (argv[j + 1]);
    }
  for (j = 0; j < n; ++j)
    {
      deltas[j].delta = 0;
      deltas[j].count = 0;
    }
  all[0].name = "vcons";
  all[0].addr = (unsigned long) vcons;
  all[1].name = "vprod";
  all[1].addr = (unsigned long) vprod;
  all[2].name = "vsume";
  all[2].addr = (unsigned long) vsume;
  all[3].name = "viprod";
  all[3].addr = (unsigned long) viprod;
  all[4].name = "vnorm";
  all[4].addr = (unsigned long) vnorm;
  all[5].name = "case10";
  all[5].addr = (unsigned long) case10;
  all[6].name = "case20";
  all[6].addr = (unsigned long) case20;
  all[7].name = "case30";
  all[7].addr = (unsigned long) case30;
  all[8].name = "case40";
  all[8].addr = (unsigned long) case40;
  all[9].name = "case50";
  all[9].addr = (unsigned long) case50;
  if (ebytes > 0)
    {
      printf ("%10s %10s %s\n", "procedure", "address", "examine");
      for (j = 0; j < n; ++j)
        {
          printf ("%10s %10ld ", all[j].name, (long) all[j].addr);
          data = (unsigned char *) all[j].addr;
          if (j > 0)
            prev_data = (unsigned char *) all[j - 1].addr;
          else
            prev_data = NULL;
          for (k = 0; k < ebytes; ++k)
            if (prev_data && (prev_data[k] == data[k]))
              printf ("..");
            else
              printf ("%02X", data[k]);
          printf ("\n");
        }
    }
  qsort (all, n, sizeof (struct apair), apairl);
  printf ("%10s %10s %10s\n", "procedure", "address", "delta");
  for (j = 0; j < n; ++j)
    {
      if (j > 0)
        {
          delta = all[j].addr - all[j - 1].addr;
          if (j == 1)
            min_delta = max_delta = delta;
          else
            {
              if (delta < min_delta)
                min_delta = delta;
              if (delta > max_delta)
                max_delta = delta;
            }
          for (k = 0; k < n; ++k)
            if (deltas[k].count == 0)
              {
                deltas[k].delta = delta;
                deltas[k].count = 1;
                break;
              }
            else if (deltas[k].delta == delta)
              {
                ++deltas[k].count;
                break;
              }
        }
      else
        delta = 0;
      printf ("%10s %10ld %10ld\n", all[j].name, (long) all[j].addr,
              (long) delta);
    }
  printf ("min_delta = %ld, max_delta = %ld\n", (long) min_delta,
          (long) max_delta);
  if (min_delta == max_delta)
    sayarch ("probably uses");
  else
    {
      qsort (deltas, n, sizeof (struct adelt), adeltl);
      printf ("%10s %s\n", "delta", "count");
      for (d = 0, k = 0; k < n; ++k)
        if (deltas[k].count > 0)
          {
            printf ("%10ld %ld\n", (long) deltas[k].delta,
                    (long) deltas[k].count);
            ++d;
          }
      if (d > 4)
        sayarch ("probably does not use");
      else
        sayarch ("may be using");
    }
  return (EXIT_SUCCESS);
}
