fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / scripts / modsign / mod-extract.c
1 /* mod-extract.c: module extractor for signing
2  *
3  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <elf.h>
22 #include <asm/byteorder.h>
23
24 void extract_elf64(void *buffer, size_t size, Elf64_Ehdr *hdr);
25 void extract_elf32(void *buffer, size_t size, Elf32_Ehdr *hdr);
26
27 struct byteorder {
28         uint16_t (*get16)(const uint16_t *);
29         uint32_t (*get32)(const uint32_t *);
30         uint64_t (*get64)(const uint64_t *);
31         void (*set16)(uint16_t *, uint16_t);
32         void (*set32)(uint32_t *, uint32_t);
33         void (*set64)(uint64_t *, uint64_t);
34 };
35
36 uint16_t get16_le(const uint16_t *p) { return __le16_to_cpu(*p); }
37 uint32_t get32_le(const uint32_t *p) { return __le32_to_cpu(*p); }
38 uint64_t get64_le(const uint64_t *p) { return __le64_to_cpu(*p); }
39 uint16_t get16_be(const uint16_t *p) { return __be16_to_cpu(*p); }
40 uint32_t get32_be(const uint32_t *p) { return __be32_to_cpu(*p); }
41 uint64_t get64_be(const uint64_t *p) { return __be64_to_cpu(*p); }
42
43 void set16_le(uint16_t *p, uint16_t n) { *p = __cpu_to_le16(n); }
44 void set32_le(uint32_t *p, uint32_t n) { *p = __cpu_to_le32(n); }
45 void set64_le(uint64_t *p, uint64_t n) { *p = __cpu_to_le64(n); }
46 void set16_be(uint16_t *p, uint16_t n) { *p = __cpu_to_be16(n); }
47 void set32_be(uint32_t *p, uint32_t n) { *p = __cpu_to_be32(n); }
48 void set64_be(uint64_t *p, uint64_t n) { *p = __cpu_to_be64(n); }
49
50 const struct byteorder byteorder_le = {
51         get16_le, get32_le, get64_le,
52         set16_le, set32_le, set64_le
53 };
54 const struct byteorder byteorder_be = {
55         get16_be, get32_be, get64_be,
56         set16_be, set32_be, set64_be
57 };
58 const struct byteorder *order;
59
60 uint16_t get16(const uint16_t *p) { return order->get16(p); }
61 uint32_t get32(const uint32_t *p) { return order->get32(p); }
62 uint64_t get64(const uint64_t *p) { return order->get64(p); }
63 void set16(uint16_t *p, uint16_t n) { order->set16(p, n); }
64 void set32(uint32_t *p, uint32_t n) { order->set32(p, n); }
65 void set64(uint64_t *p, uint64_t n) { order->set64(p, n); }
66
67 FILE *outfd;
68 uint8_t csum, xcsum;
69
70 void write_out(const void *data, size_t size)
71 {
72         const uint8_t *p = data;
73         size_t loop;
74
75         for (loop = 0; loop < size; loop++) {
76                 csum += p[loop];
77                 xcsum += p[loop];
78         }
79
80         if (fwrite(data, 1, size, outfd) != size) {
81                 perror("write");
82                 exit(1);
83         }
84 }
85
86 #define write_out_val(VAL) write_out(&(VAL), sizeof(VAL))
87
88 int is_verbose;
89
90 void verbose(const char *fmt, ...) __attribute__((format(printf,1,2)));
91 void verbose(const char *fmt, ...)
92 {
93         va_list va;
94
95         if (is_verbose) {
96                 va_start(va, fmt);
97                 vprintf(fmt, va);
98                 va_end(va);
99         }
100 }
101
102 void usage(void) __attribute__((noreturn));
103 void usage(void)
104 {
105         fprintf(stderr, "Usage: mod-extract [-v] <modulefile> <extractfile>\n");
106         exit(2);
107 }
108
109 /*
110  *
111  */
112 int main(int argc, char **argv)
113 {
114         struct stat st;
115         Elf32_Ehdr *hdr32;
116         Elf64_Ehdr *hdr64;
117         size_t len;
118         void *buffer;
119         int fd, be, b64;
120
121         while (argc > 1 && strcmp("-v", argv[1]) == 0) {
122                 argv++;
123                 argc--;
124                 is_verbose++;
125         }
126
127         if (argc != 3)
128                 usage();
129
130         /* map the module into memory */
131         fd = open(argv[1], O_RDONLY);
132         if (fd < 0) {
133                 perror("open input");
134                 exit(1);
135         }
136
137         if (fstat(fd, &st) < 0) {
138                 perror("fstat");
139                 exit(1);
140         }
141
142         len = st.st_size;
143
144         buffer = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
145         if (buffer == MAP_FAILED) {
146                 perror("mmap");
147                 exit(1);
148         }
149
150         if (close(fd) < 0) {
151                 perror("close input");
152                 exit(1);
153         }
154
155         /* check it's an ELF object */
156         hdr32 = buffer;
157         hdr64 = buffer;
158
159         if (hdr32->e_ident[EI_MAG0] != ELFMAG0 ||
160             hdr32->e_ident[EI_MAG1] != ELFMAG1 ||
161             hdr32->e_ident[EI_MAG2] != ELFMAG2 ||
162             hdr32->e_ident[EI_MAG3] != ELFMAG3
163             ) {
164                 fprintf(stderr, "Module does not appear to be ELF\n");
165                 exit(3);
166         }
167
168         /* determine endianness and word size */
169         b64 = (hdr32->e_ident[EI_CLASS] == ELFCLASS64);
170         be = (hdr32->e_ident[EI_DATA] == ELFDATA2MSB);
171         order = be ? &byteorder_be : &byteorder_le;
172
173         verbose("Module is %s-bit %s-endian\n",
174                 b64 ? "64" : "32",
175                 be ? "big" : "little");
176
177         /* open the output file */
178         outfd = fopen(argv[2], "w");
179         if (!outfd) {
180                 perror("open output");
181                 exit(1);
182         }
183
184         /* perform the extraction */
185         if (b64)
186                 extract_elf64(buffer, len, hdr64);
187         else
188                 extract_elf32(buffer, len, hdr32);
189
190         /* done */
191         if (fclose(outfd) == EOF) {
192                 perror("close output");
193                 exit(1);
194         }
195
196         return 0;
197 }
198
199 /*
200  * extract a RELA table
201  * - need to canonicalise the entries in case section addition/removal has
202  *   rearranged the symbol table and the section table
203  */
204 void extract_elf64_rela(const void *buffer, int secix, int targetix,
205                         const Elf64_Rela *relatab, size_t nrels,
206                         const Elf64_Sym *symbols, size_t nsyms,
207                         const Elf64_Shdr *sections, size_t nsects, int *canonmap,
208                         const char *strings, size_t nstrings,
209                         const char *sh_name)
210 {
211         struct {
212                 uint64_t        r_offset;
213                 uint64_t        r_addend;
214                 uint64_t        st_value;
215                 uint64_t        st_size;
216                 uint32_t        r_type;
217                 uint16_t        st_shndx;
218                 uint8_t         st_info;
219                 uint8_t         st_other;
220
221         } __attribute__((packed)) relocation;
222
223         const Elf64_Sym *symbol;
224         size_t loop;
225
226         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
227         for (loop = 0; loop < nrels; loop++) {
228                 Elf64_Section st_shndx;
229                 Elf64_Xword r_info;
230
231                 /* decode the relocation */
232                 r_info = get64(&relatab[loop].r_info);
233                 relocation.r_offset = relatab[loop].r_offset;
234                 relocation.r_addend = relatab[loop].r_addend;
235                 set32(&relocation.r_type, ELF64_R_TYPE(r_info));
236
237                 if (ELF64_R_SYM(r_info) >= nsyms) {
238                         fprintf(stderr, "Invalid symbol ID %lx in relocation %zu\n",
239                                 ELF64_R_SYM(r_info), loop);
240                         exit(1);
241                 }
242
243                 /* decode the symbol referenced by the relocation */
244                 symbol = &symbols[ELF64_R_SYM(r_info)];
245                 relocation.st_info = symbol->st_info;
246                 relocation.st_other = symbol->st_other;
247                 relocation.st_value = symbol->st_value;
248                 relocation.st_size = symbol->st_size;
249                 relocation.st_shndx = symbol->st_shndx;
250                 st_shndx = get16(&symbol->st_shndx);
251
252                 /* canonicalise the section used by the symbol */
253                 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
254                         set16(&relocation.st_shndx, canonmap[st_shndx]);
255
256                 write_out_val(relocation);
257
258                 /* undefined symbols must be named if referenced */
259                 if (st_shndx == SHN_UNDEF) {
260                         const char *name = strings + get32(&symbol->st_name);
261                         write_out(name, strlen(name) + 1);
262                 }
263         }
264
265         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
266 }
267
268 /*
269  * extract a REL table
270  * - need to canonicalise the entries in case section addition/removal has
271  *   rearranged the symbol table and the section table
272  */
273 void extract_elf64_rel(const void *buffer, int secix, int targetix,
274                        const Elf64_Rel *relatab, size_t nrels,
275                        const Elf64_Sym *symbols, size_t nsyms,
276                        const Elf64_Shdr *sections, size_t nsects, int *canonmap,
277                        const char *strings, size_t nstrings,
278                        const char *sh_name)
279 {
280         struct {
281                 uint64_t        r_offset;
282                 uint64_t        st_value;
283                 uint64_t        st_size;
284                 uint32_t        r_type;
285                 uint16_t        st_shndx;
286                 uint8_t         st_info;
287                 uint8_t         st_other;
288
289         } __attribute__((packed)) relocation;
290
291         const Elf64_Sym *symbol;
292         size_t loop;
293
294         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
295         for (loop = 0; loop < nrels; loop++) {
296                 Elf64_Section st_shndx;
297                 Elf64_Xword r_info;
298
299                 /* decode the relocation */
300                 r_info = get64(&relatab[loop].r_info);
301                 relocation.r_offset = relatab[loop].r_offset;
302                 set32(&relocation.r_type, ELF64_R_TYPE(r_info));
303
304                 if (ELF64_R_SYM(r_info) >= nsyms) {
305                         fprintf(stderr, "Invalid symbol ID %lx in relocation %zi\n",
306                                 ELF64_R_SYM(r_info), loop);
307                         exit(1);
308                 }
309
310                 /* decode the symbol referenced by the relocation */
311                 symbol = &symbols[ELF64_R_SYM(r_info)];
312                 relocation.st_info = symbol->st_info;
313                 relocation.st_other = symbol->st_other;
314                 relocation.st_value = symbol->st_value;
315                 relocation.st_size = symbol->st_size;
316                 relocation.st_shndx = symbol->st_shndx;
317                 st_shndx = get16(&symbol->st_shndx);
318
319                 /* canonicalise the section used by the symbol */
320                 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
321                         set16(&relocation.st_shndx, canonmap[st_shndx]);
322
323                 write_out_val(relocation);
324
325                 /* undefined symbols must be named if referenced */
326                 if (st_shndx == SHN_UNDEF) {
327                         const char *name = strings + get32(&symbol->st_name);
328                         write_out(name, strlen(name) + 1);
329                 }
330         }
331
332         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
333 }
334
335 /*
336  * extract the data from a 64-bit module
337  */
338 void extract_elf64(void *buffer, size_t len, Elf64_Ehdr *hdr)
339 {
340         const Elf64_Sym *symbols;
341         Elf64_Shdr *sections;
342         const char *secstrings, *strings;
343         size_t nsyms, nstrings;
344         int loop, shnum, *canonlist, *canonmap, canon, changed, tmp;
345
346         sections = buffer + get64(&hdr->e_shoff);
347         secstrings = buffer + get64(&sections[get16(&hdr->e_shstrndx)].sh_offset);
348         shnum = get16(&hdr->e_shnum);
349
350         /* find the symbol table and the string table and produce a list of
351          * index numbers of sections that contribute to the kernel's module
352          * image
353          */
354         canonlist = calloc(sizeof(int), shnum * 2);
355         if (!canonlist) {
356                 perror("calloc");
357                 exit(1);
358         }
359         canonmap = canonlist + shnum;
360         canon = 0;
361
362         symbols = NULL;
363         strings = NULL;
364         nstrings = 0;
365         nsyms = 0;
366
367         for (loop = 1; loop < shnum; loop++) {
368                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
369                 Elf64_Word  sh_type     = get32(&sections[loop].sh_type);
370                 Elf64_Xword sh_size     = get64(&sections[loop].sh_size);
371                 Elf64_Xword sh_flags    = get64(&sections[loop].sh_flags);
372                 Elf64_Off   sh_offset   = get64(&sections[loop].sh_offset);
373                 void *data = buffer + sh_offset;
374
375                 /* quick sanity check */
376                 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
377                         fprintf(stderr, "Section goes beyond EOF\n");
378                         exit(3);
379                 }
380
381                 /* we only need to canonicalise allocatable sections */
382                 if (sh_flags & SHF_ALLOC)
383                         canonlist[canon++] = loop;
384
385                 /* keep track of certain special sections */
386                 switch (sh_type) {
387                 case SHT_SYMTAB:
388                         if (strcmp(sh_name, ".symtab") == 0) {
389                                 symbols = data;
390                                 nsyms = sh_size / sizeof(Elf64_Sym);
391                         }
392                         break;
393
394                 case SHT_STRTAB:
395                         if (strcmp(sh_name, ".strtab") == 0) {
396                                 strings = data;
397                                 nstrings = sh_size;
398                         }
399                         break;
400
401                 default:
402                         break;
403                 }
404         }
405
406         if (!symbols) {
407                 fprintf(stderr, "Couldn't locate symbol table\n");
408                 exit(3);
409         }
410
411         if (!strings) {
412                 fprintf(stderr, "Couldn't locate strings table\n");
413                 exit(3);
414         }
415
416         /* canonicalise the index numbers of the contributing section */
417         do {
418                 changed = 0;
419
420                 for (loop = 0; loop < canon - 1; loop++) {
421                         const char *x = secstrings + get32(&sections[canonlist[loop + 0]].sh_name);
422                         const char *y = secstrings + get32(&sections[canonlist[loop + 1]].sh_name);
423                         if (strcmp(x, y) > 0) {
424                                 tmp = canonlist[loop + 0];
425                                 canonlist[loop + 0] = canonlist[loop + 1];
426                                 canonlist[loop + 1] = tmp;
427                                 changed = 1;
428                         }
429                 }
430
431         } while(changed);
432
433         for (loop = 0; loop < canon; loop++)
434                 canonmap[canonlist[loop]] = loop + 1;
435
436         if (is_verbose > 1) {
437                 printf("\nSection canonicalisation map:\n");
438                 for (loop = 1; loop < shnum; loop++) {
439                         const char *x = secstrings + get32(&sections[loop].sh_name);
440                         printf("%4d %s\n", canonmap[loop], x);
441                 }
442
443                 printf("\nAllocated section list in canonical order:\n");
444                 for (loop = 0; loop < canon; loop++) {
445                         const char *x = secstrings + get32(&sections[canonlist[loop]].sh_name);
446                         printf("%4d %s\n", canonlist[loop], x);
447                 }
448         }
449
450         memset(canonlist, 0, sizeof(int) * shnum);
451
452         /* iterate through the section table looking for sections we want to
453          * contribute to the signature */
454         verbose("\n");
455         verbose("FILE POS CS SECT NAME\n");
456         verbose("======== == ==== ==============================\n");
457
458         for (loop = 1; loop < shnum; loop++) {
459                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
460                 Elf64_Word  sh_type     = get32(&sections[loop].sh_type);
461                 Elf64_Xword sh_size     = get64(&sections[loop].sh_size);
462                 Elf64_Xword sh_flags    = get64(&sections[loop].sh_flags);
463                 Elf64_Word  sh_info     = get32(&sections[loop].sh_info);
464                 Elf64_Off   sh_offset   = get64(&sections[loop].sh_offset);
465                 void *data = buffer + sh_offset;
466
467                 csum = 0;
468
469                 /* include canonicalised relocation sections */
470                 if (sh_type == SHT_REL || sh_type == SHT_RELA) {
471                         if (sh_info <= 0 && sh_info >= hdr->e_shnum) {
472                                 fprintf(stderr,
473                                         "Invalid ELF - REL/RELA sh_info does"
474                                         " not refer to a valid section\n");
475                                 exit(3);
476                         }
477
478                         if (canonlist[sh_info]) {
479                                 Elf32_Word xsh_info;
480
481                                 verbose("%08lx ", ftell(outfd));
482
483                                 set32(&xsh_info, canonmap[sh_info]);
484
485                                 /* write out selected portions of the section
486                                  * header */
487                                 write_out(sh_name, strlen(sh_name));
488                                 write_out_val(sections[loop].sh_type);
489                                 write_out_val(sections[loop].sh_flags);
490                                 write_out_val(sections[loop].sh_size);
491                                 write_out_val(sections[loop].sh_addralign);
492                                 write_out_val(xsh_info);
493
494                                 if (sh_type == SHT_RELA)
495                                         extract_elf64_rela(buffer, loop, sh_info,
496                                                            data, sh_size / sizeof(Elf64_Rela),
497                                                            symbols, nsyms,
498                                                            sections, shnum, canonmap,
499                                                            strings, nstrings,
500                                                            sh_name);
501                                 else
502                                         extract_elf64_rel(buffer, loop, sh_info,
503                                                           data, sh_size / sizeof(Elf64_Rel),
504                                                           symbols, nsyms,
505                                                           sections, shnum, canonmap,
506                                                           strings, nstrings,
507                                                           sh_name);
508                         }
509
510                         continue;
511                 }
512
513                 /* include allocatable loadable sections */
514                 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
515                         goto include_section;
516
517                 /* not this section */
518                 continue;
519
520         include_section:
521                 verbose("%08lx ", ftell(outfd));
522
523                 /* write out selected portions of the section header */
524                 write_out(sh_name, strlen(sh_name));
525                 write_out_val(sections[loop].sh_type);
526                 write_out_val(sections[loop].sh_flags);
527                 write_out_val(sections[loop].sh_size);
528                 write_out_val(sections[loop].sh_addralign);
529
530                 /* write out the section data */
531                 write_out(data, sh_size);
532
533                 verbose("%02x %4d %s\n", csum, loop, sh_name);
534
535                 /* note the section has been written */
536                 canonlist[loop] = 1;
537         }
538
539         verbose("%08lx         (%lu bytes csum 0x%02x)\n",
540                 ftell(outfd), ftell(outfd), xcsum);
541 }
542
543 /*
544  * extract a RELA table
545  * - need to canonicalise the entries in case section addition/removal has
546  *   rearranged the symbol table and the section table
547  */
548 void extract_elf32_rela(const void *buffer, int secix, int targetix,
549                         const Elf32_Rela *relatab, size_t nrels,
550                         const Elf32_Sym *symbols, size_t nsyms,
551                         const Elf32_Shdr *sections, size_t nsects, int *canonmap,
552                         const char *strings, size_t nstrings,
553                         const char *sh_name)
554 {
555         struct {
556                 uint32_t        r_offset;
557                 uint32_t        r_addend;
558                 uint32_t        st_value;
559                 uint32_t        st_size;
560                 uint16_t        st_shndx;
561                 uint8_t         r_type;
562                 uint8_t         st_info;
563                 uint8_t         st_other;
564
565         } __attribute__((packed)) relocation;
566
567         const Elf32_Sym *symbol;
568         size_t loop;
569
570         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
571         for (loop = 0; loop < nrels; loop++) {
572                 Elf32_Section st_shndx;
573                 Elf32_Word r_info;
574
575                 /* decode the relocation */
576                 r_info = get32(&relatab[loop].r_info);
577                 relocation.r_offset = relatab[loop].r_offset;
578                 relocation.r_addend = relatab[loop].r_addend;
579                 relocation.r_type = ELF32_R_TYPE(r_info);
580
581                 if (ELF32_R_SYM(r_info) >= nsyms) {
582                         fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n",
583                                 ELF32_R_SYM(r_info), loop);
584                         exit(1);
585                 }
586
587                 /* decode the symbol referenced by the relocation */
588                 symbol = &symbols[ELF32_R_SYM(r_info)];
589                 relocation.st_info = symbol->st_info;
590                 relocation.st_other = symbol->st_other;
591                 relocation.st_value = symbol->st_value;
592                 relocation.st_size = symbol->st_size;
593                 relocation.st_shndx = symbol->st_shndx;
594                 st_shndx = get16(&symbol->st_shndx);
595
596                 /* canonicalise the section used by the symbol */
597                 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
598                         set16(&relocation.st_shndx, canonmap[st_shndx]);
599
600                 write_out_val(relocation);
601
602                 /* undefined symbols must be named if referenced */
603                 if (st_shndx == SHN_UNDEF) {
604                         const char *name = strings + get32(&symbol->st_name);
605                         write_out(name, strlen(name) + 1);
606                 }
607         }
608
609         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
610 }
611
612 /*
613  * extract a REL table
614  * - need to canonicalise the entries in case section addition/removal has
615  *   rearranged the symbol table and the section table
616  */
617 void extract_elf32_rel(const void *buffer, int secix, int targetix,
618                        const Elf32_Rel *relatab, size_t nrels,
619                        const Elf32_Sym *symbols, size_t nsyms,
620                        const Elf32_Shdr *sections, size_t nsects, int *canonmap,
621                        const char *strings, size_t nstrings,
622                        const char *sh_name)
623 {
624         struct {
625                 uint32_t        r_offset;
626                 uint32_t        st_value;
627                 uint32_t        st_size;
628                 uint16_t        st_shndx;
629                 uint8_t         r_type;
630                 uint8_t         st_info;
631                 uint8_t         st_other;
632
633         } __attribute__((packed)) relocation;
634
635         const Elf32_Sym *symbol;
636         size_t loop;
637
638         /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
639         for (loop = 0; loop < nrels; loop++) {
640                 Elf32_Section st_shndx;
641                 Elf32_Word r_info;
642
643                 /* decode the relocation */
644                 r_info = get32(&relatab[loop].r_info);
645                 relocation.r_offset = relatab[loop].r_offset;
646                 relocation.r_type = ELF32_R_TYPE(r_info);
647
648                 if (ELF32_R_SYM(r_info) >= nsyms) {
649                         fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n",
650                                 ELF32_R_SYM(r_info), loop);
651                         exit(1);
652                 }
653
654                 /* decode the symbol referenced by the relocation */
655                 symbol = &symbols[ELF32_R_SYM(r_info)];
656                 relocation.st_info = symbol->st_info;
657                 relocation.st_other = symbol->st_other;
658                 relocation.st_value = symbol->st_value;
659                 relocation.st_size = symbol->st_size;
660                 relocation.st_shndx = symbol->st_shndx;
661                 st_shndx = get16(&symbol->st_shndx);
662
663                 /* canonicalise the section used by the symbol */
664                 if (st_shndx > SHN_UNDEF && st_shndx < nsects)
665                         set16(&relocation.st_shndx, canonmap[st_shndx]);
666
667                 write_out_val(relocation);
668
669                 /* undefined symbols must be named if referenced */
670                 if (st_shndx == SHN_UNDEF) {
671                         const char *name = strings + get32(&symbol->st_name);
672                         write_out(name, strlen(name) + 1);
673                 }
674         }
675
676         verbose("%02x %4d %s [canon]\n", csum, secix, sh_name);
677 }
678
679 /*
680  * extract the data from a 32-bit module
681  */
682 void extract_elf32(void *buffer, size_t len, Elf32_Ehdr *hdr)
683 {
684         const Elf32_Sym *symbols;
685         Elf32_Shdr *sections;
686         const char *secstrings, *strings;
687         size_t nsyms, nstrings;
688         int loop, shnum, *canonlist, *canonmap, canon, changed, tmp;
689
690         sections = buffer + get32(&hdr->e_shoff);
691         secstrings = buffer + get32(&sections[get16(&hdr->e_shstrndx)].sh_offset);
692         shnum = get16(&hdr->e_shnum);
693
694         /* find the symbol table and the string table and produce a list of
695          * index numbers of sections that contribute to the kernel's module
696          * image
697          */
698         canonlist = calloc(sizeof(int), shnum * 2);
699         if (!canonlist) {
700                 perror("calloc");
701                 exit(1);
702         }
703         canonmap = canonlist + shnum;
704         canon = 0;
705
706         symbols = NULL;
707         strings = NULL;
708         nstrings = 0;
709         nsyms = 0;
710
711         for (loop = 1; loop < shnum; loop++) {
712                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
713                 Elf32_Word  sh_type     = get32(&sections[loop].sh_type);
714                 Elf32_Xword sh_size     = get32(&sections[loop].sh_size);
715                 Elf32_Xword sh_flags    = get32(&sections[loop].sh_flags);
716                 Elf32_Off   sh_offset   = get32(&sections[loop].sh_offset);
717                 void *data = buffer + sh_offset;
718
719                 /* quick sanity check */
720                 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
721                         fprintf(stderr, "Section goes beyond EOF\n");
722                         exit(3);
723                 }
724
725                 /* we only need to canonicalise allocatable sections */
726                 if (sh_flags & SHF_ALLOC)
727                         canonlist[canon++] = loop;
728
729                 /* keep track of certain special sections */
730                 switch (sh_type) {
731                 case SHT_SYMTAB:
732                         if (strcmp(sh_name, ".symtab") == 0) {
733                                 symbols = data;
734                                 nsyms = sh_size / sizeof(Elf32_Sym);
735                         }
736                         break;
737
738                 case SHT_STRTAB:
739                         if (strcmp(sh_name, ".strtab") == 0) {
740                                 strings = data;
741                                 nstrings = sh_size;
742                         }
743                         break;
744
745                 default:
746                         break;
747                 }
748         }
749
750         if (!symbols) {
751                 fprintf(stderr, "Couldn't locate symbol table\n");
752                 exit(3);
753         }
754
755         if (!strings) {
756                 fprintf(stderr, "Couldn't locate strings table\n");
757                 exit(3);
758         }
759
760         /* canonicalise the index numbers of the contributing section */
761         do {
762                 changed = 0;
763
764                 for (loop = 0; loop < canon - 1; loop++) {
765                         const char *x = secstrings + get32(&sections[canonlist[loop + 0]].sh_name);
766                         const char *y = secstrings + get32(&sections[canonlist[loop + 1]].sh_name);
767                         if (strcmp(x, y) > 0) {
768                                 tmp = canonlist[loop + 0];
769                                 canonlist[loop + 0] = canonlist[loop + 1];
770                                 canonlist[loop + 1] = tmp;
771                                 changed = 1;
772                         }
773                 }
774
775         } while(changed);
776
777         for (loop = 0; loop < canon; loop++)
778                 canonmap[canonlist[loop]] = loop + 1;
779
780         if (is_verbose > 1) {
781                 printf("\nSection canonicalisation map:\n");
782                 for (loop = 1; loop < shnum; loop++) {
783                         const char *x = secstrings + get32(&sections[loop].sh_name);
784                         printf("%4d %s\n", canonmap[loop], x);
785                 }
786
787                 printf("\nAllocated section list in canonical order:\n");
788                 for (loop = 0; loop < canon; loop++) {
789                         const char *x = secstrings + get32(&sections[canonlist[loop]].sh_name);
790                         printf("%4d %s\n", canonlist[loop], x);
791                 }
792         }
793
794         memset(canonlist, 0, sizeof(int) * shnum);
795
796         /* iterate through the section table looking for sections we want to
797          * contribute to the signature */
798         verbose("\n");
799         verbose("FILE POS CS SECT NAME\n");
800         verbose("======== == ==== ==============================\n");
801
802         for (loop = 1; loop < shnum; loop++) {
803                 const char *sh_name = secstrings + get32(&sections[loop].sh_name);
804                 Elf32_Word  sh_type     = get32(&sections[loop].sh_type);
805                 Elf32_Xword sh_size     = get32(&sections[loop].sh_size);
806                 Elf32_Xword sh_flags    = get32(&sections[loop].sh_flags);
807                 Elf32_Word  sh_info     = get32(&sections[loop].sh_info);
808                 Elf32_Off   sh_offset   = get32(&sections[loop].sh_offset);
809                 void *data = buffer + sh_offset;
810
811                 csum = 0;
812
813                 /* quick sanity check */
814                 if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) {
815                         fprintf(stderr, "section goes beyond EOF\n");
816                         exit(3);
817                 }
818
819                 /* include canonicalised relocation sections */
820                 if (sh_type == SHT_REL || sh_type == SHT_RELA) {
821                         if (sh_info <= 0 && sh_info >= hdr->e_shnum) {
822                                 fprintf(stderr,
823                                         "Invalid ELF - REL/RELA sh_info does"
824                                         " not refer to a valid section\n");
825                                 exit(3);
826                         }
827
828                         if (canonlist[sh_info]) {
829                                 Elf32_Word xsh_info;
830
831                                 verbose("%08lx ", ftell(outfd));
832
833                                 set32(&xsh_info, canonmap[sh_info]);
834
835                                 /* write out selected portions of the section header */
836                                 write_out(sh_name, strlen(sh_name));
837                                 write_out_val(sections[loop].sh_type);
838                                 write_out_val(sections[loop].sh_flags);
839                                 write_out_val(sections[loop].sh_size);
840                                 write_out_val(sections[loop].sh_addralign);
841                                 write_out_val(xsh_info);
842
843                                 if (sh_type == SHT_RELA)
844                                         extract_elf32_rela(buffer, loop, sh_info,
845                                                            data, sh_size / sizeof(Elf32_Rela),
846                                                            symbols, nsyms,
847                                                            sections, shnum, canonmap,
848                                                            strings, nstrings,
849                                                            sh_name);
850                                 else
851                                         extract_elf32_rel(buffer, loop, sh_info,
852                                                           data, sh_size / sizeof(Elf32_Rel),
853                                                           symbols, nsyms,
854                                                           sections, shnum, canonmap,
855                                                           strings, nstrings,
856                                                           sh_name);
857                         }
858
859                         continue;
860                 }
861
862                 /* include allocatable loadable sections */
863                 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
864                         goto include_section;
865
866                 /* not this section */
867                 continue;
868
869         include_section:
870                 verbose("%08lx ", ftell(outfd));
871
872                 /* write out selected portions of the section header */
873                 write_out(sh_name, strlen(sh_name));
874                 write_out_val(sections[loop].sh_type);
875                 write_out_val(sections[loop].sh_flags);
876                 write_out_val(sections[loop].sh_size);
877                 write_out_val(sections[loop].sh_addralign);
878
879                 /* write out the section data */
880                 write_out(data, sh_size);
881
882                 verbose("%02x %4d %s\n", csum, loop, sh_name);
883
884                 /* note the section has been written */
885                 canonlist[loop] = 1;
886         }
887
888         verbose("%08lx         (%lu bytes csum 0x%02x)\n",
889                 ftell(outfd), ftell(outfd), xcsum);
890 }