1 /* Generate checksums of executables for PCH validation
2    Copyright (C) 2005-2018 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10 
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along 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 
24 static void
usage(void)25 usage (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 
33 static void
dosum(struct md5_ctx * ctx,const char * file)34 dosum (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 
95 int
main(int argc,char ** argv)96 main (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