home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff214.lzh / MemDiag / MD.c < prev    next >
C/C++ Source or Header  |  1989-05-30  |  9KB  |  254 lines

  1. /* MD.c
  2.  
  3.    by Fabbian G. Dufoe, III
  4.  
  5.    This is a public domain program.  Use it however you like.
  6.  
  7.    This program tests all the memory which the operating system will
  8.    allocate to it.  It writes a test value to each address.  Then it reads
  9.    each address and compares the result with the test value.  If the value
  10.    read from memory doesn't match the test value the program writes the
  11.    address (the pointer value), the expected contents, and the actual
  12.    contents of the memory location to standard output.  When all allocated
  13.    memory has been tested against one test value the program moves to the
  14.    next one.  The test values are 0x00, 0xff, 0x55, and 0xaa.
  15.  
  16.    A command line option directs the program to write a list of bad
  17.    addresses to a file.  The file will contain all the addresses at which an
  18.    error was detected.  The addresses will be listed in ascending order and
  19.    each address will appear only once.  Addresses will be separated by
  20.    newlines.  The addresses will be ASCII characters representing
  21.    hexadecimal values.  The program will not list more than 100 addresses.
  22.  
  23.    While the program is running it writes status messages to standard error.
  24.  
  25.    Usage: MD [>reportfile] [-qaddressfile]
  26. */
  27.  
  28. #define NULL 0L
  29. #define SIZE 1000
  30. #define VERSION "Version 1.1, 10 April 1989\n\n"
  31. #define USAGE "Usage: MD [>reportfile] [-qaddressfile]\n"
  32.  
  33. #include <time.h>
  34. #include <stdio.h>
  35.  
  36. typedef struct
  37. {
  38.    unsigned char *ptr;
  39.    unsigned long int size;
  40. } Block;
  41.  
  42. unsigned char *Addr[100];
  43. unsigned short int AddrCnt = 0;
  44.  
  45. void
  46. main(argc, argv)
  47. int argc;
  48. char **argv;
  49. {
  50.    void AddAddr(unsigned char *);
  51.    FILE *AddrFile;
  52.    unsigned short int AddrList = 0;
  53.    Block block[SIZE];
  54.    unsigned short int count = 0;
  55.    unsigned long int errct = 0;
  56.    unsigned short int high;
  57.    unsigned short int i;
  58.    unsigned long int offset;
  59.    unsigned char *ptr;
  60.    unsigned long int size;
  61.    signed long int t;
  62.    static unsigned char TestVal[] = {0, 0xff, 0x55, 0xaa};
  63.    unsigned short int val;
  64.  
  65.    /* We need to check for command line arguments.  A "-q" directs the
  66.       program to write a file of bad addresses. */
  67.    if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'q')
  68.    {
  69.       /* If we can't open the file we'll terminate the program with an error
  70.          message. */
  71.       if ((AddrFile = fopen(&argv[1][2], "w")) == NULL)
  72.       {
  73.          fputs(USAGE, stderr);
  74.          fputs("Cannot open output file.\n", stderr);
  75.          exit(30);
  76.       }
  77.       AddrList = 1;
  78.    }
  79.    else if (argc > 1)
  80.    {
  81.       /* If the command line arguments were incorrect we'll terminate the
  82.          program with a usage message. */
  83.       fputs(USAGE, stderr);
  84.       exit(30);
  85.    }
  86.  
  87.    /* We want to include the time the diagnostic program was run in the
  88.       report.  That requires getting the current system time.
  89.    */
  90.    time(&t);
  91.  
  92.    /* We'll print a report heading and copyright notice at the beginning.
  93.    */
  94.    printf("MD--Memory Diagnostic.\n");
  95.    printf("by Fabbian G. Dufoe, III\n");
  96.    printf(VERSION);
  97.    printf("Memory tested %s\n\n", ctime(&t));
  98.  
  99.    /* We'll start by allocating memory in blocks of one megabyte.  The plan
  100.       is to allocate as many one-megabyte blocks as we can.  Then we'll
  101.       halve the block size, allocate as many blocks of that size as we can,
  102.       and repeat the process until (a) all the memory is gone or (b) we've
  103.       filled the array we allocated for keeping track of memory blocks.
  104.    */
  105.    size = 1048576;
  106.    while (size > 0 && count < SIZE)
  107.    {
  108.       fprintf(stderr, "Allocating %ld byte blocks.\n", size);
  109.       while ((ptr = (unsigned char *)malloc(size)) != NULL)
  110.       {
  111.          block[count].ptr = ptr;
  112.          block[count++].size = size;
  113.       }
  114.       if (size == 1)
  115.          size = 0;
  116.       else
  117.          size >>= 1;
  118.    }
  119.  
  120.    /* Because we expect seldom to use the entire array we've set aside we
  121.       need to save the number of the highest element actually used.
  122.    */
  123.    high = count;
  124.  
  125.    /* At this point we want to sort the block pointers.  It makes the output
  126.       easier to follow if memory errors are reported in ascending order
  127.       by their address.  We aren't guaranteed that memory will be
  128.       allocated in any particular order.  We'll use an insertion sort and
  129.       we'll sort only that part of the array we used.  That means we'll
  130.       keep the index values between 0 and high.
  131.  
  132.       An insertion sort works by shifting all the items left of the current
  133.       one right one position until an item is less than the current one.
  134.       Imagine the items to be sorted are laid out from left to right.  Then
  135.       the sort places the current item in the position vacated by the last
  136.       item to be shifted right.  The sort starts with the second item as
  137.       the current one and proceeds to the right until all the items have had
  138.       a turn as the current one.
  139.    */
  140.    fprintf(stderr, "Sorting block list.\n");
  141.    for (count = 1; count < high; count++)
  142.    {
  143.       short int i;
  144.  
  145.       ptr = block[count].ptr;
  146.       size = block[count].size;
  147.       i = count - 1;
  148.       while (i >=0 && ptr < block[i].ptr)
  149.       {
  150.          block[i+1].ptr = block[i].ptr;
  151.          block[i+1].size = block[i].size;
  152.          i--;
  153.       }
  154.       block[i+1].ptr = ptr;
  155.       block[i+1].size = size;
  156.    }
  157.    fprintf(stderr, "Sort complete.\n");
  158.  
  159.    /* We'll list the block addresses and size in the report.
  160.    */
  161.    printf("Blocks examined:\n");
  162.    printf("Block #    Address         Size\n\n");
  163.    for (count = 0; count < high; count++)
  164.    {
  165.       printf("%4d      %8lX      %7ld\n", count, block[count].ptr,
  166.              block[count].size);
  167.    }
  168.    printf("\n");
  169.  
  170.    /* Now that we've sorted our list of blocks we're ready to start testing
  171.       them.  The first step is to initialize all the variables to 0, the
  172.       first test value.
  173.    */
  174.    for (count = 0; count < high; count++)
  175.    {
  176.       fprintf(stderr, "Initializing block %d, %ld bytes.\n", count,
  177.                       block[count].size);
  178.       for (offset = 0; offset < block[count].size; offset++)
  179.          *(block[count].ptr+offset) = TestVal[0];
  180.    }
  181.  
  182.    /* Next we'll go through all the blocks to see if they contain the test
  183.       value with which they were loaded.  If not we'll identify the address
  184.       that failed, the value it contained, and the value it should have
  185.       contained.  We'll do that for each valid test value.
  186.    */
  187.    for (val = 1; val < 4; val++)
  188.    {
  189.       fprintf(stderr, "Testing value %X.\n", TestVal[val-1]);
  190.       for (count = 0; count < high; count++)
  191.       {
  192.          fprintf(stderr, "Testing block %d, %ld bytes with %X\n", count,
  193.                          block[count].size, TestVal[val-1]);
  194.          for (offset = 0; offset < block[count].size; offset++)
  195.          {
  196.             if (*(block[count].ptr+offset) != TestVal[val-1])
  197.             {
  198.                printf("ERROR! Address: %8lX  found: %2X  expected: %2X\n",
  199.                        block[count].ptr+offset, *(block[count].ptr+offset),
  200.                        TestVal[val-1]);
  201.                errct++;
  202.                AddAddr(block[count].ptr+offset);
  203.             }
  204.             *(block[count].ptr+offset) = TestVal[val];
  205.          }
  206.       }
  207.    }
  208.  
  209.    /* We've tested for all values except the last one.  It's time to do that
  210.       now.
  211.    */
  212.    val--;
  213.    fprintf(stderr, "Testing value %X.\n", TestVal[val]);
  214.    for (count = 0; count < high; count++)
  215.    {
  216.       fprintf(stderr, "Testing block %d, %ld bytes with %X\n", count,
  217.               block[count].size, TestVal[val]);
  218.       for (offset = 0; offset < block[count].size; offset++)
  219.       {
  220.          if (*(block[count].ptr+offset) != TestVal[val])
  221.          {
  222.             printf("ERROR! Address: %8lX  found: %2X  expected: %2X\n",
  223.                     block[count].ptr+offset, *(block[count].ptr+offset),
  224.                     TestVal[val]);
  225.             errct++;
  226.             AddAddr(block[count].ptr+offset);
  227.          }
  228.       }
  229.    }
  230.  
  231.    /* The testing is finished so we'll report the number of errors we found.
  232.    */
  233.    printf("\nMD found %d errors.\n", errct);
  234.  
  235.    /* When we've completed all our tests we free all the memory we allocated
  236.       and exit. */
  237.    for (count = 0; count < high; count++)
  238.    {
  239.       fprintf(stderr, "Freeing block %d.\n", count);
  240.       free(block[count].ptr);
  241.    }
  242.  
  243.    /* If an address list file was requested we'll write it and close the
  244.       file. */
  245.    if (AddrList == 1)
  246.    {
  247.       for (i = 0; i < AddrCnt; i++)
  248.          fprintf(AddrFile, "%8lX\n", Addr[i]);
  249.       fclose(AddrFile);
  250.    }
  251.  
  252.    exit(0);
  253. }
  254.