Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / tools / sepdebugcrcfix.c
1 /* Copyright (C) 2013 Free Software Foundation, Inc.
2
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.
7
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.
12
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/>.  */
15
16 /* Version 2013-06-24.  */
17
18 #define _GNU_SOURCE
19
20 #include "system.h"
21
22 #include <string.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <sys/mman.h>
29 #include <endian.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <error.h>
33 #include <libelf.h>
34 #include <gelf.h>
35
36 #ifndef _
37 #define _(x) x
38 #endif
39 #define static_assert(expr) \
40   extern int never_defined_just_used_for_checking[(expr) ? 1 : -1]
41 #ifndef min
42 # define min(a, b) ((a) < (b) ? (a) : (b))
43 #endif
44
45 static_assert (sizeof (unsigned long) >= sizeof (uint32_t));
46
47 typedef int bool;
48 static const bool false = 0, true = 1;
49
50 /* This is bfd_calc_gnu_debuglink_crc32 from bfd/opncls.c.  */
51 static unsigned long
52     calc_gnu_debuglink_crc32 (unsigned long crc,
53                               const unsigned char *buf,
54                               size_t len)
55 {
56   static const unsigned long crc32_table[256] =
57     {
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,
109       0x2d02ef8d
110     };
111   const unsigned char *end;
112
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;
117 }
118
119 static size_t updated_count, matched_count, failed_count;
120
121 static const char *usr_lib_debug;
122
123 static bool
124 crc32 (const char *fname, const char *base_fname, uint32_t *crcp)
125 {
126   char *reldir = strdup (base_fname);
127   if (reldir == NULL)
128     error (1, 0, _("out of memory"));
129   char *s = reldir + strlen (reldir);
130   while (s > reldir && s[-1] != '/')
131     *--s = '\0';
132   char *debugname;
133   if (asprintf (&debugname, "%s/%s/%s", usr_lib_debug, reldir, fname) <= 0)
134     error (1, 0, _("out of memory"));
135   free (reldir);
136   int fd = open (debugname, O_RDONLY);
137   if (fd == -1)
138     {
139       error (0, errno, _("cannot open \"%s\""), debugname);
140       return false;
141     }
142   off64_t size = lseek64 (fd, 0, SEEK_END);
143   if (size == -1)
144     {
145       error (0, errno, _("cannot get size of \"%s\""), debugname);
146       return false;
147     }
148   off_t offset = 0;
149   uint32_t crc = 0;
150   void *buf = NULL;
151   while (offset < size)
152     {
153       const size_t maplen = min (0x10000, size - offset);
154       void *map = NULL;
155       if (buf == NULL)
156         {
157           map = mmap (NULL, maplen, PROT_READ, MAP_PRIVATE | MAP_POPULATE,
158                       fd, offset);
159           if (map == MAP_FAILED)
160             {
161               error (0, errno, _("cannot map 0x%llx bytes at offset 0x%llx "
162                                  "of file \"%s\""),
163                      (unsigned long long) maplen, (unsigned long long) offset,
164                      debugname);
165               map = NULL;
166             }
167         }
168       if (map == NULL)
169         {
170           if (buf == NULL)
171             {
172               buf = malloc (maplen);
173               if (buf == NULL)
174                 error (1, 0, _("out of memory"));
175             }
176           ssize_t got = pread (fd, buf, maplen, offset);
177           if (got != maplen)
178             {
179               error (0, errno, _("cannot read 0x%llx bytes at offset 0x%llx "
180                                  "of file \"%s\""),
181                      (unsigned long long) maplen, (unsigned long long) offset,
182                      debugname);
183               free (buf);
184               free (debugname);
185               return false;
186             }
187         }
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 "
191                            "of file \"%s\""),
192                (unsigned long long) maplen, (unsigned long long) offset,
193                debugname);
194       offset += maplen;
195     }
196   free (buf);
197   if (close (fd) != 0)
198     {
199       error (0, errno, _("cannot close \"%s\""), debugname);
200       free (debugname);
201       return false;
202     }
203   free (debugname);
204   *crcp = crc;
205   return true;
206 }
207
208 static bool
209 process (Elf *elf, int fd, const char *fname)
210 {
211   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
212   if (ehdr == NULL)
213     {
214       error (0, 0, _("cannot get ELF header of \"%s\""), fname);
215       return false;
216     }
217   if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB
218       && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
219     {
220       error (0, 0, _("invalid ELF endianity of \"%s\""), fname);
221       return false;
222     }
223   Elf_Scn *scn = NULL;
224   const char scnname[] = ".gnu_debuglink";
225   while ((scn = elf_nextscn (elf, scn)) != NULL)
226     {
227       GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
228       if (shdr == NULL)
229         {
230           error (0, 0, _("cannot get section # %zu in \"%s\""),
231                  elf_ndxscn (scn), fname);
232           continue;
233         }
234       const char *sname = elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name);
235       if (sname == NULL)
236         {
237           error (0, 0, _("cannot get name of section # %zu in \"%s\""),
238                  elf_ndxscn (scn), fname);
239           continue;
240         }
241       if (strcmp (sname, scnname) != 0)
242         continue;
243       Elf_Data *data = elf_getdata (scn, NULL);
244       if (data == NULL)
245         {
246           error (0, 0, _("cannot get data of section \"%s\" # %zu in \"%s\""),
247                  scnname, elf_ndxscn (scn), fname);
248           continue;
249         }
250       if ((data->d_size & 3) != 0)
251         {
252           error (0, 0, _("invalid size of section \"%s\" # %zu in \"%s\""),
253                  scnname, elf_ndxscn (scn), fname);
254           continue;
255         }
256       const uint8_t *zerop = memchr (data->d_buf, '\0', data->d_size);
257       const uint8_t *crcp = (zerop == NULL
258                              ? NULL
259                              : (const uint8_t *) ((uintptr_t) (zerop + 1 + 3)
260                                                   & -4));
261       if (crcp + 4 != (uint8_t *) data->d_buf + data->d_size)
262         {
263           error (0, 0, _("invalid format of section \"%s\" # %zu in \"%s\""),
264                  scnname, elf_ndxscn (scn), fname);
265           continue;
266         }
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));
271       uint32_t crc;
272       if (! crc32 (data->d_buf, fname, &crc))
273         return false;
274       if (crc == had_crc)
275         {
276           matched_count++;
277           return true;
278         }
279       updated_count++;
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),
285                               seekto);
286       if (wrote != sizeof (crc_targetendian))
287         {
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);
291           return false;
292         }
293       return true;
294     }
295   error (0, 0, _("cannot find section \"%s\" in \"%s\""), scnname, fname);
296   return false;
297 }
298
299 int
300 main (int argc, char **argv)
301 {
302   if (argc < 2)
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++)
308     {
309       const char *fname = argv[argi];
310       struct stat stat_buf;
311       if (stat(fname, &stat_buf) < 0)
312         {
313           error (0, errno, _("cannot stat input \"%s\""), fname);
314           failed_count++;
315           continue;
316         }
317
318       /* Make sure we can read and write */
319       chmod (fname, stat_buf.st_mode | S_IRUSR | S_IWUSR);
320
321       bool failed = false;
322       int fd = open64 (fname, O_RDWR);
323       if (fd == -1)
324         {
325           error (0, errno, _("cannot open \"%s\""), fname);
326           failed = true;
327         }
328       else
329         {
330           Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
331           if (elf == NULL)
332             {
333               error (0, 0, _("cannot open \"%s\" as ELF: %s"), fname,
334                      elf_errmsg (-1));
335               failed = true;
336             }
337           else
338             {
339               if (! process (elf, fd, fname))
340                 failed = true;
341               if (elf_end (elf) != 0)
342                 {
343                   error (0, 0, _("cannot close \"%s\" as ELF: %s"), fname,
344                          elf_errmsg (-1));
345                   failed = true;
346                 }
347             }
348           if (close (fd) != 0)
349             {
350               error (0, errno, _("cannot close \"%s\""), fname);
351               failed = true;
352             }
353         }
354
355       /* Restore old access rights. Including any suid bits reset. */
356       chmod (fname, stat_buf.st_mode);
357
358       if (failed)
359         failed_count++;
360     }
361   printf ("%s: Updated %zu CRC32s, %zu CRC32s did match.\n", argv[0],
362           updated_count, matched_count);
363   if (failed_count)
364     printf ("%s: Failed for %zu files.\n", argv[0], failed_count);
365   return failed_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
366 }