1 /* Copyright (C) 2013 Free Software Foundation, Inc.
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 3 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 /* Version 2013-06-24. */
25 #include <sys/types.h>
39 #define static_assert(expr) \
40 extern int never_defined_just_used_for_checking[(expr) ? 1 : -1]
42 # define min(a, b) ((a) < (b) ? (a) : (b))
45 static_assert (sizeof (unsigned long) >= sizeof (uint32_t));
48 static const bool false = 0, true = 1;
50 /* This is bfd_calc_gnu_debuglink_crc32 from bfd/opncls.c. */
52 calc_gnu_debuglink_crc32 (unsigned long crc,
53 const unsigned char *buf,
56 static const unsigned long crc32_table[256] =
58 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
59 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
60 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
61 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
62 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
63 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
64 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
65 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
66 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
67 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
68 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
69 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
70 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
71 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
72 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
73 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
74 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
75 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
76 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
77 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
78 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
79 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
80 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
81 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
82 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
83 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
84 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
85 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
86 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
87 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
88 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
89 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
90 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
91 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
92 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
93 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
94 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
95 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
96 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
97 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
98 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
99 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
100 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
101 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
102 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
103 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
104 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
105 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
106 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
107 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
108 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
111 const unsigned char *end;
113 crc = ~crc & 0xffffffff;
114 for (end = buf + len; buf < end; ++ buf)
115 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
116 return ~crc & 0xffffffff;
119 static size_t updated_count, matched_count, failed_count;
121 static const char *usr_lib_debug;
124 crc32 (const char *fname, const char *base_fname, uint32_t *crcp)
126 char *reldir = strdup (base_fname);
128 error (1, 0, _("out of memory"));
129 char *s = reldir + strlen (reldir);
130 while (s > reldir && s[-1] != '/')
133 if (asprintf (&debugname, "%s/%s/%s", usr_lib_debug, reldir, fname) <= 0)
134 error (1, 0, _("out of memory"));
136 int fd = open (debugname, O_RDONLY);
139 error (0, errno, _("cannot open \"%s\""), debugname);
142 off64_t size = lseek64 (fd, 0, SEEK_END);
145 error (0, errno, _("cannot get size of \"%s\""), debugname);
151 while (offset < size)
153 const size_t maplen = min (0x10000, size - offset);
157 map = mmap (NULL, maplen, PROT_READ, MAP_PRIVATE | MAP_POPULATE,
159 if (map == MAP_FAILED)
161 error (0, errno, _("cannot map 0x%llx bytes at offset 0x%llx "
163 (unsigned long long) maplen, (unsigned long long) offset,
172 buf = malloc (maplen);
174 error (1, 0, _("out of memory"));
176 ssize_t got = pread (fd, buf, maplen, offset);
179 error (0, errno, _("cannot read 0x%llx bytes at offset 0x%llx "
181 (unsigned long long) maplen, (unsigned long long) offset,
188 crc = calc_gnu_debuglink_crc32 (crc, map ?: buf, maplen);
189 if (map && munmap (map, maplen) != 0)
190 error (1, errno, _("cannot unmap 0x%llx bytes at offset 0x%llx "
192 (unsigned long long) maplen, (unsigned long long) offset,
199 error (0, errno, _("cannot close \"%s\""), debugname);
209 process (Elf *elf, int fd, const char *fname)
211 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
214 error (0, 0, _("cannot get ELF header of \"%s\""), fname);
217 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB
218 && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
220 error (0, 0, _("invalid ELF endianity of \"%s\""), fname);
224 const char scnname[] = ".gnu_debuglink";
225 while ((scn = elf_nextscn (elf, scn)) != NULL)
227 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
230 error (0, 0, _("cannot get section # %zu in \"%s\""),
231 elf_ndxscn (scn), fname);
234 const char *sname = elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name);
237 error (0, 0, _("cannot get name of section # %zu in \"%s\""),
238 elf_ndxscn (scn), fname);
241 if (strcmp (sname, scnname) != 0)
243 Elf_Data *data = elf_getdata (scn, NULL);
246 error (0, 0, _("cannot get data of section \"%s\" # %zu in \"%s\""),
247 scnname, elf_ndxscn (scn), fname);
250 if ((data->d_size & 3) != 0)
252 error (0, 0, _("invalid size of section \"%s\" # %zu in \"%s\""),
253 scnname, elf_ndxscn (scn), fname);
256 const uint8_t *zerop = memchr (data->d_buf, '\0', data->d_size);
257 const uint8_t *crcp = (zerop == NULL
259 : (const uint8_t *) ((uintptr_t) (zerop + 1 + 3)
261 if (crcp + 4 != (uint8_t *) data->d_buf + data->d_size)
263 error (0, 0, _("invalid format of section \"%s\" # %zu in \"%s\""),
264 scnname, elf_ndxscn (scn), fname);
267 uint32_t had_crc_targetendian = *(const uint32_t *) crcp;
268 uint32_t had_crc = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB
269 ? le32toh (had_crc_targetendian)
270 : be32toh (had_crc_targetendian));
272 if (! crc32 (data->d_buf, fname, &crc))
280 off64_t seekto = (shdr->sh_offset + data->d_off
281 + (crcp - (const uint8_t *) data->d_buf));
282 uint32_t crc_targetendian = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB
283 ? htole32 (crc) : htobe32 (crc));
284 ssize_t wrote = pwrite (fd, &crc_targetendian, sizeof (crc_targetendian),
286 if (wrote != sizeof (crc_targetendian))
288 error (0, 0, _("cannot write new CRC to 0x%llx "
289 "inside section \"%s\" # %zu in \"%s\""),
290 (unsigned long long) seekto, scnname, elf_ndxscn (scn), fname);
295 error (0, 0, _("cannot find section \"%s\" in \"%s\""), scnname, fname);
300 main (int argc, char **argv)
303 error (1, 0, _("usr/lib/debug [<relative filenames>...]"));
304 usr_lib_debug = argv[1];
305 if (elf_version (EV_CURRENT) == EV_NONE)
306 error (1, 0, _("error initializing libelf: %s"), elf_errmsg (-1));
307 for (int argi = 2; argi < argc; argi++)
309 const char *fname = argv[argi];
310 struct stat stat_buf;
311 if (stat(fname, &stat_buf) < 0)
313 error (0, errno, _("cannot stat input \"%s\""), fname);
318 /* Make sure we can read and write */
319 chmod (fname, stat_buf.st_mode | S_IRUSR | S_IWUSR);
322 int fd = open64 (fname, O_RDWR);
325 error (0, errno, _("cannot open \"%s\""), fname);
330 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
333 error (0, 0, _("cannot open \"%s\" as ELF: %s"), fname,
339 if (! process (elf, fd, fname))
341 if (elf_end (elf) != 0)
343 error (0, 0, _("cannot close \"%s\" as ELF: %s"), fname,
350 error (0, errno, _("cannot close \"%s\""), fname);
355 /* Restore old access rights. Including any suid bits reset. */
356 chmod (fname, stat_buf.st_mode);
361 printf ("%s: Updated %zu CRC32s, %zu CRC32s did match.\n", argv[0],
362 updated_count, matched_count);
364 printf ("%s: Failed for %zu files.\n", argv[0], failed_count);
365 return failed_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE;