1 | /* Generate checksums of executables for PCH validation |
2 | Copyright (C) 2005-2023 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 |
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 |
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, format: "opening %s: %s\n" , file, xstrerror (errno)); |
44 | exit (status: 1); |
45 | } |
46 | |
47 | /* Some executable formats have timestamps in the first 16 bytes, yuck. */ |
48 | if (fseek (stream: f, off: 16, SEEK_SET) != 0) |
49 | { |
50 | fprintf (stderr, format: "seeking in %s: %s\n" , file, xstrerror (errno)); |
51 | exit (status: 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 (status: 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, len: sum, ctx); |
87 | |
88 | if (fclose (stream: f) != 0) |
89 | { |
90 | fprintf (stderr, format: "reading %s: %s\n" , file, xstrerror (errno)); |
91 | exit (status: 1); |
92 | } |
93 | } |
94 | |
95 | int |
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: &ctx); |
109 | for (i = 1; i < argc; i++) |
110 | dosum (ctx: &ctx, file: argv[i]); |
111 | md5_finish_ctx (ctx: &ctx, resbuf: result); |
112 | |
113 | puts (s: "#include \"config.h\"" ); |
114 | puts (s: "#include \"system.h\"" ); |
115 | fputs ("EXPORTED_CONST unsigned char executable_checksum[16] = { " , stdout); |
116 | for (i = 0; i < 16; i++) |
117 | printf (format: "0x%02x%s" , result[i], i == 15 ? " };\n" : ", " ); |
118 | |
119 | return 0; |
120 | } |
121 | |