1/* Generate checksums of executables for PCH validation
2   Copyright (C) 2005-2015 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3.  If not see
18<http://www.gnu.org/licenses/>.  */
19
20#include "bconfig.h"
21#include "system.h"
22#include "md5.h"
23
24static void
25usage (void)
26{
27  fputs ("Usage: genchecksums <filename> ...\n", stderr);
28}
29
30/* Important: BLOCKSIZE must be a multiple of 64.  */
31#define BLOCKSIZE 4096
32
33static void
34dosum (struct md5_ctx *ctx, const char *file)
35{
36  FILE *f;
37  char buffer[BLOCKSIZE + 72];
38  size_t sum;
39
40  f = fopen (file, "rb");
41  if (!f)
42    {
43      fprintf (stderr, "opening %s: %s\n", file, xstrerror (errno));
44      exit (1);
45    }
46
47  /* Some executable formats have timestamps in the first 16 bytes, yuck.  */
48  if (fseek (f, 16, SEEK_SET) != 0)
49     {
50      fprintf (stderr, "seeking in %s: %s\n", file, xstrerror (errno));
51      exit (1);
52    }
53
54  /* Iterate over full file contents.  */
55  while (1)
56    {
57      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
58	 computation function processes the whole buffer so that with the
59	 next round of the loop another block can be read.  */
60      size_t n;
61      sum = 0;
62
63      /* Read block.  Take care for partial reads.  */
64      do
65	{
66	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, f);
67
68	  sum += n;
69	}
70      while (sum < BLOCKSIZE && n != 0);
71      if (n == 0 && ferror (f))
72        exit (1);
73
74      /* If end of file is reached, end the loop.  */
75      if (n == 0)
76	break;
77
78      /* Process buffer with BLOCKSIZE bytes.  Note that
79			BLOCKSIZE % 64 == 0
80       */
81      md5_process_block (buffer, BLOCKSIZE, ctx);
82    }
83
84  /* Add the last bytes if necessary.  */
85  if (sum > 0)
86    md5_process_bytes (buffer, sum, ctx);
87
88  if (fclose (f) != 0)
89     {
90      fprintf (stderr, "reading %s: %s\n", file, xstrerror (errno));
91      exit (1);
92    }
93}
94
95int
96main (int argc, char ** argv)
97{
98  struct md5_ctx ctx;
99  unsigned char result[16];
100  int i;
101
102  if (argc < 2)
103    {
104      usage ();
105      return 1;
106    }
107
108  md5_init_ctx (&ctx);
109  for (i = 1; i < argc; i++)
110    dosum (&ctx, argv[i]);
111  md5_finish_ctx (&ctx, result);
112
113  puts ("#include \"config.h\"");
114  puts ("#include \"system.h\"");
115  fputs ("EXPORTED_CONST unsigned char executable_checksum[16] = { ", stdout);
116  for (i = 0; i < 16; i++)
117    printf ("0x%02x%s", result[i], i == 15 ? " };\n" : ", ");
118
119  return 0;
120}
121