]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/libpe/libpe_section.c
Update to ELF Tool Chain r3475
[FreeBSD/FreeBSD.git] / contrib / elftoolchain / libpe / libpe_section.c
1 /*-
2  * Copyright (c) 2016 Kai Wang
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/param.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include "_libpe.h"
35
36 ELFTC_VCSID("$Id: libpe_section.c 3446 2016-05-03 01:31:17Z emaste $");
37
38 PE_Scn *
39 libpe_alloc_scn(PE *pe)
40 {
41         PE_Scn *ps;
42
43         if ((ps = calloc(1, sizeof(PE_Scn))) == NULL) {
44                 errno = ENOMEM;
45                 return (NULL);
46         }
47         STAILQ_INIT(&ps->ps_b);
48         ps->ps_pe = pe;
49
50         return (ps);
51 }
52
53 void
54 libpe_release_scn(PE_Scn *ps)
55 {
56         PE *pe;
57         PE_SecBuf *sb, *_sb;
58
59         assert(ps != NULL);
60
61         pe = ps->ps_pe;
62
63         STAILQ_REMOVE(&pe->pe_scn, ps, _PE_Scn, ps_next);
64
65         STAILQ_FOREACH_SAFE(sb, &ps->ps_b, sb_next, _sb)
66                 libpe_release_buffer(sb);
67
68         free(ps);
69 }
70
71 static int
72 cmp_scn(PE_Scn *a, PE_Scn *b)
73 {
74
75         if (a->ps_sh.sh_addr < b->ps_sh.sh_addr)
76                 return (-1);
77         else if (a->ps_sh.sh_addr == b->ps_sh.sh_addr)
78                 return (0);
79         else
80                 return (1);
81 }
82
83 static void
84 sort_sections(PE *pe)
85 {
86
87         if (STAILQ_EMPTY(&pe->pe_scn))
88                 return;
89
90         /* Sort the list of Scn by RVA in ascending order. */
91         STAILQ_SORT(&pe->pe_scn, _PE_Scn, ps_next, cmp_scn);
92 }
93
94 int
95 libpe_parse_section_headers(PE *pe)
96 {
97         char tmp[sizeof(PE_SecHdr)], *hdr;
98         PE_Scn *ps;
99         PE_SecHdr *sh;
100         PE_CoffHdr *ch;
101         PE_DataDir *dd;
102         int found, i;
103
104         assert(pe->pe_ch != NULL);
105
106         for (i = 0; (uint16_t) i < pe->pe_ch->ch_nsec; i++) {
107                 if (read(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
108                     (ssize_t) sizeof(PE_SecHdr)) {
109                         pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
110                         return (0);
111                 }
112
113                 if ((ps = libpe_alloc_scn(pe)) == NULL)
114                         return (-1);
115                 STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
116                 ps->ps_ndx = ++pe->pe_nscn;     /* Setion index is 1-based */
117                 sh = &ps->ps_sh;
118
119                 /*
120                  * Note that the section name won't be NUL-terminated if
121                  * its length happens to be 8.
122                  */
123                 memcpy(sh->sh_name, tmp, sizeof(sh->sh_name));
124                 hdr = tmp + 8;
125                 PE_READ32(hdr, sh->sh_virtsize);
126                 PE_READ32(hdr, sh->sh_addr);
127                 PE_READ32(hdr, sh->sh_rawsize);
128                 PE_READ32(hdr, sh->sh_rawptr);
129                 PE_READ32(hdr, sh->sh_relocptr);
130                 PE_READ32(hdr, sh->sh_lineptr);
131                 PE_READ16(hdr, sh->sh_nreloc);
132                 PE_READ16(hdr, sh->sh_nline);
133                 PE_READ32(hdr, sh->sh_char);
134         }
135
136         /*
137          * For all the data directories that don't belong to any section,
138          * we create pseudo sections for them to make layout easier.
139          */
140         dd = pe->pe_dd;
141         if (dd != NULL && dd->dd_total > 0) {
142                 for (i = 0; (uint32_t) i < pe->pe_dd->dd_total; i++) {
143                         if (dd->dd_e[i].de_size == 0)
144                                 continue;
145                         found = 0;
146                         STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
147                                 sh = &ps->ps_sh;
148                                 if (dd->dd_e[i].de_addr >= sh->sh_addr &&
149                                     dd->dd_e[i].de_addr + dd->dd_e[i].de_size <=
150                                     sh->sh_addr + sh->sh_virtsize) {
151                                         found = 1;
152                                         break;
153                                 }
154                         }
155                         if (found)
156                                 continue;
157
158                         if ((ps = libpe_alloc_scn(pe)) == NULL)
159                                 return (-1);
160                         STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
161                         ps->ps_ndx = 0xFFFF0000U | i;
162                         sh = &ps->ps_sh;
163                         sh->sh_rawptr = dd->dd_e[i].de_addr; /* FIXME */
164                         sh->sh_rawsize = dd->dd_e[i].de_size;
165                 }
166         }
167
168         /*
169          * Also consider the COFF symbol table as a pseudo section.
170          */
171         ch = pe->pe_ch;
172         if (ch->ch_nsym > 0) {
173                 if ((ps = libpe_alloc_scn(pe)) == NULL)
174                         return (-1);
175                 STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
176                 ps->ps_ndx = 0xFFFFFFFFU;
177                 sh = &ps->ps_sh;
178                 sh->sh_rawptr = ch->ch_symptr;
179                 sh->sh_rawsize = ch->ch_nsym * PE_SYM_ENTRY_SIZE;
180                 pe->pe_nsym = ch->ch_nsym;
181         }
182
183         /* PE file headers initialization is complete if we reach here. */
184         return (0);
185 }
186
187 int
188 libpe_load_section(PE *pe, PE_Scn *ps)
189 {
190         PE_SecHdr *sh;
191         PE_SecBuf *sb;
192         size_t sz;
193         char tmp[4];
194
195         assert(pe != NULL && ps != NULL);
196         assert((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0);
197
198         sh = &ps->ps_sh;
199
200         /* Allocate a PE_SecBuf struct without buffer for empty sections. */
201         if (sh->sh_rawsize == 0) {
202                 (void) libpe_alloc_buffer(ps, 0);
203                 ps->ps_flags |= LIBPE_F_LOAD_SECTION;
204                 return (0);
205         }
206
207         if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
208                 if (lseek(pe->pe_fd, (off_t) sh->sh_rawptr, SEEK_SET) < 0) {
209                         errno = EIO;
210                         return (-1);
211                 }
212         }
213
214         if ((sb = libpe_alloc_buffer(ps, sh->sh_rawsize)) == NULL)
215                 return (-1);
216
217         if (read(pe->pe_fd, sb->sb_pb.pb_buf, sh->sh_rawsize) !=
218             (ssize_t) sh->sh_rawsize) {
219                 errno = EIO;
220                 return (-1);
221         }
222
223         if (ps->ps_ndx == 0xFFFFFFFFU) {
224                 /*
225                  * Index 0xFFFFFFFF indicates this section is a pseudo
226                  * section that contains the COFF symbol table. We should
227                  * read in the string table right after it.
228                  */
229                 if (read(pe->pe_fd, tmp, sizeof(tmp)) !=
230                     (ssize_t) sizeof(tmp)) {
231                         errno = EIO;
232                         return (-1);
233                 }
234                 sz = le32dec(tmp);
235
236                 /*
237                  * The minimum value for the size field is 4, which indicates
238                  * there is no string table.
239                  */
240                 if (sz > 4) {
241                         sz -= 4;
242                         if ((sb = libpe_alloc_buffer(ps, sz)) == NULL)
243                                 return (-1);
244                         if (read(pe->pe_fd, sb->sb_pb.pb_buf, sz) !=
245                             (ssize_t) sz) {
246                                 errno = EIO;
247                                 return (-1);
248                         }
249                 }
250         }
251
252         ps->ps_flags |= LIBPE_F_LOAD_SECTION;
253
254         return (0);
255 }
256
257 int
258 libpe_load_all_sections(PE *pe)
259 {
260         PE_Scn *ps;
261         PE_SecHdr *sh;
262         unsigned r, s;
263         off_t off;
264         char tmp[256];
265
266         /* Calculate the current offset into the file. */
267         off = 0;
268         if (pe->pe_dh != NULL)
269                 off += pe->pe_dh->dh_lfanew + 4;
270         if (pe->pe_ch != NULL)
271                 off += sizeof(PE_CoffHdr) + pe->pe_ch->ch_optsize;
272
273         STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
274                 if (ps->ps_flags & LIBPE_F_LOAD_SECTION)
275                         continue;
276                 sh = &ps->ps_sh;
277
278                 /*
279                  * For special files, we consume the padding in between
280                  * and advance to the section offset.
281                  */
282                 if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
283                         /* Can't go backwards. */
284                         if (off > sh->sh_rawptr) {
285                                 errno = EIO;
286                                 return (-1);
287                         }
288                         if (off < sh->sh_rawptr) {
289                                 r = sh->sh_rawptr - off;
290                                 for (; r > 0; r -= s) {
291                                         s = r > sizeof(tmp) ? sizeof(tmp) : r;
292                                         if (read(pe->pe_fd, tmp, s) !=
293                                             (ssize_t) s) {
294                                                 errno = EIO;
295                                                 return (-1);
296                                         }
297                                 }
298                         }
299                 }
300
301                 /* Load the section content. */
302                 if (libpe_load_section(pe, ps) < 0)
303                         return (-1);
304         }
305
306         return (0);
307 }
308
309 int
310 libpe_resync_sections(PE *pe, off_t off)
311 {
312         PE_Scn *ps;
313         PE_SecHdr *sh;
314         size_t falign, nsec;
315
316         /* Firstly, sort all sections by their file offsets. */
317         sort_sections(pe);
318
319         /* Count the number of sections. */
320         nsec = 0;
321         STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
322                 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
323                         continue;
324                 if (ps->ps_ndx & 0xFFFF0000U)
325                         continue;
326                 nsec++;
327         }
328         pe->pe_nscn = nsec;
329
330         /*
331          * Calculate the file offset for the first section. (`off' is
332          * currently pointing to the COFF header.)
333          */
334         off += sizeof(PE_CoffHdr);
335         if (pe->pe_ch != NULL && pe->pe_ch->ch_optsize > 0)
336                 off += pe->pe_ch->ch_optsize;
337         else {
338                 switch (pe->pe_obj) {
339                 case PE_O_PE32:
340                         off += PE_COFF_OPT_SIZE_32;
341                         break;
342                 case PE_O_PE32P:
343                         off += PE_COFF_OPT_SIZE_32P;
344                         break;
345                 case PE_O_COFF:
346                 default:
347                         break;
348                 }
349         }
350         off += nsec * sizeof(PE_SecHdr);
351
352         /*
353          * Determine the file alignment for sections.
354          */
355         if (pe->pe_oh != NULL && pe->pe_oh->oh_filealign > 0)
356                 falign = pe->pe_oh->oh_filealign;
357         else {
358                 /*
359                  * Use the default file alignment defined by the
360                  * PE/COFF specification.
361                  */
362                 if (pe->pe_obj == PE_O_COFF)
363                         falign = 4;
364                 else
365                         falign = 512;
366         }
367
368         /*
369          * Step through each section (and pseduo section) and verify
370          * alignment constraint and overlapping, make adjustment if need.
371          */
372         pe->pe_rvamax = 0;
373         STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
374                 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
375                         continue;
376
377                 sh = &ps->ps_sh;
378
379                 if (sh->sh_addr + sh->sh_virtsize > pe->pe_rvamax)
380                         pe->pe_rvamax = sh->sh_addr + sh->sh_virtsize;
381
382                 if (ps->ps_ndx & 0xFFFF0000U)
383                         ps->ps_falign = 4;
384                 else
385                         ps->ps_falign = falign;
386
387                 off = roundup(off, ps->ps_falign);
388
389                 if (off != sh->sh_rawptr)
390                         ps->ps_flags |= PE_F_DIRTY;
391
392                 if (ps->ps_flags & PE_F_DIRTY) {
393                         if ((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0) {
394                                 if (libpe_load_section(pe, ps) < 0)
395                                         return (-1);
396                         }
397                         sh->sh_rawsize = libpe_resync_buffers(ps);
398                 }
399
400                 /*
401                  * Sections only contains uninitialized data should set
402                  * PointerToRawData to zero according to the PE/COFF
403                  * specification.
404                  */
405                 if (sh->sh_rawsize == 0)
406                         sh->sh_rawptr = 0;
407                 else
408                         sh->sh_rawptr = off;
409
410                 off += sh->sh_rawsize;
411         }
412
413         return (0);
414 }
415
416 off_t
417 libpe_write_section_headers(PE *pe, off_t off)
418 {
419         char tmp[sizeof(PE_SecHdr)], *hdr;
420         PE_Scn *ps;
421         PE_SecHdr *sh;
422
423         if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER || pe->pe_nscn == 0)
424                 return (off);
425
426         if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0) {
427                 off += sizeof(PE_SecHdr) * pe->pe_ch->ch_nsec;
428                 return (off);
429         }
430
431         STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
432                 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
433                         continue;
434                 if (ps->ps_ndx & 0xFFFF0000U)
435                         continue;
436                 if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0 &&
437                     (ps->ps_flags & PE_F_DIRTY) == 0)
438                         goto next_header;
439
440                 sh = &ps->ps_sh;
441
442                 memcpy(tmp, sh->sh_name, sizeof(sh->sh_name));
443                 hdr = tmp + 8;
444                 PE_WRITE32(hdr, sh->sh_virtsize);
445                 PE_WRITE32(hdr, sh->sh_addr);
446                 PE_WRITE32(hdr, sh->sh_rawsize);
447                 PE_WRITE32(hdr, sh->sh_rawptr);
448                 PE_WRITE32(hdr, sh->sh_relocptr);
449                 PE_WRITE32(hdr, sh->sh_lineptr);
450                 PE_WRITE16(hdr, sh->sh_nreloc);
451                 PE_WRITE16(hdr, sh->sh_nline);
452                 PE_WRITE32(hdr, sh->sh_char);
453
454                 if (write(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
455                     (ssize_t) sizeof(PE_SecHdr)) {
456                         errno = EIO;
457                         return (-1);
458                 }
459
460         next_header:
461                 off += sizeof(PE_SecHdr);
462         }
463
464         return (off);
465 }
466
467 off_t
468 libpe_write_sections(PE *pe, off_t off)
469 {
470         PE_Scn *ps;
471         PE_SecHdr *sh;
472
473         if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER)
474                 return (off);
475
476         STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
477                 sh = &ps->ps_sh;
478
479                 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
480                         continue;
481
482                 /* Skip empty sections. */
483                 if (sh->sh_rawptr == 0 || sh->sh_rawsize == 0)
484                         continue;
485
486                 /*
487                  * Padding between sections. (padding always written
488                  * in case the the section headers or sections are
489                  * moved or shrunk.)
490                  */
491                 assert(off <= sh->sh_rawptr);
492                 if (off < sh->sh_rawptr)
493                         libpe_pad(pe, sh->sh_rawptr - off);
494
495                 if ((ps->ps_flags & PE_F_DIRTY) == 0) {
496                         assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
497                         if (lseek(pe->pe_fd,
498                             (off_t) (sh->sh_rawptr + sh->sh_rawsize),
499                             SEEK_SET) < 0) {
500                                 errno = EIO;
501                                 return (-1);
502                         }
503                         off = sh->sh_rawptr + sh->sh_rawsize;
504                         continue;
505                 }
506
507                 off = sh->sh_rawptr;
508
509                 if (libpe_write_buffers(ps) < 0)
510                         return (-1);
511
512                 off += sh->sh_rawsize;
513
514                 ps->ps_flags &= ~PE_F_DIRTY;
515         }
516
517         return (off);
518 }