blob: 3db3e7da4d98ae20eabb435dfa943048a26b28a6 [file] [log] [blame]
Rob Pikeed5e39a2008-06-12 14:50:25 -07001// Inferno libmach/executable.c
2// http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
3//
Russ Cox133a1582009-10-03 10:37:12 -07004// Copyright © 1994-1999 Lucent Technologies Inc.
5// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
6// Portions Copyright © 1997-1999 Vita Nuova Limited.
7// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
8// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
Rob Pikeed5e39a2008-06-12 14:50:25 -07009// Portions Copyright © 2009 The Go Authors. All rights reserved.
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28
29#include <u.h>
30#include <libc.h>
31#include <bio.h>
32#include <bootexec.h>
Rob Pike00274a12009-08-14 10:46:04 -070033#include <mach.h>
Rob Pikeed5e39a2008-06-12 14:50:25 -070034#include "elf.h"
Rob Pike073486c2008-06-15 17:22:57 -070035#include "macho.h"
Rob Pikeed5e39a2008-06-12 14:50:25 -070036
37/*
38 * All a.out header types. The dummy entry allows canonical
Russ Cox9aad9fe2008-08-03 17:25:15 -070039 * processing of the union as a sequence of int32s
Rob Pikeed5e39a2008-06-12 14:50:25 -070040 */
41
42typedef struct {
43 union{
44 /*struct { */
45 Exec exechdr; /* a.out.h */
46 /* uvlong hdr[1];*/
47 /*};*/
48 Ehdr32 elfhdr32; /* elf.h */
49 Ehdr64 elfhdr64; /* elf.h */
50 struct mipsexec mips; /* bootexec.h */
51 struct mips4kexec mipsk4; /* bootexec.h */
52 struct sparcexec sparc; /* bootexec.h */
53 struct nextexec next; /* bootexec.h */
Rob Pike073486c2008-06-15 17:22:57 -070054 Machhdr machhdr; /* macho.h */
Rob Pikeed5e39a2008-06-12 14:50:25 -070055 } e;
Russ Cox9aad9fe2008-08-03 17:25:15 -070056 int32 dummy; /* padding to ensure extra int32 */
Rob Pikeed5e39a2008-06-12 14:50:25 -070057} ExecHdr;
58
59static int nextboot(int, Fhdr*, ExecHdr*);
60static int sparcboot(int, Fhdr*, ExecHdr*);
61static int mipsboot(int, Fhdr*, ExecHdr*);
62static int mips4kboot(int, Fhdr*, ExecHdr*);
63static int common(int, Fhdr*, ExecHdr*);
64static int commonllp64(int, Fhdr*, ExecHdr*);
65static int adotout(int, Fhdr*, ExecHdr*);
66static int elfdotout(int, Fhdr*, ExecHdr*);
Rob Pike073486c2008-06-15 17:22:57 -070067static int machdotout(int, Fhdr*, ExecHdr*);
Rob Pikeed5e39a2008-06-12 14:50:25 -070068static int armdotout(int, Fhdr*, ExecHdr*);
Mateusz Czaplińskieae0a482011-08-29 14:25:43 -040069static int pedotout(int, Fhdr*, ExecHdr*);
Russ Cox19fd5c72010-10-19 18:07:19 -040070static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
Russ Cox9aad9fe2008-08-03 17:25:15 -070071static void setdata(Fhdr*, uvlong, int32, vlong, int32);
72static void settext(Fhdr*, uvlong, uvlong, int32, vlong);
73static void hswal(void*, int, uint32(*)(uint32));
74static uvlong _round(uvlong, uint32);
Rob Pikeed5e39a2008-06-12 14:50:25 -070075
76/*
77 * definition of per-executable file type structures
78 */
79
80typedef struct Exectable{
Russ Cox9aad9fe2008-08-03 17:25:15 -070081 int32 magic; /* big-endian magic number of file */
Rob Pikeed5e39a2008-06-12 14:50:25 -070082 char *name; /* executable identifier */
83 char *dlmname; /* dynamically loadable module identifier */
84 uchar type; /* Internal code */
85 uchar _magic; /* _MAGIC() magic */
86 Mach *mach; /* Per-machine data */
Russ Cox9aad9fe2008-08-03 17:25:15 -070087 int32 hsize; /* header size */
88 uint32 (*swal)(uint32); /* beswal or leswal */
Rob Pikeed5e39a2008-06-12 14:50:25 -070089 int (*hparse)(int, Fhdr*, ExecHdr*);
90} ExecTable;
91
92extern Mach mmips;
93extern Mach mmips2le;
94extern Mach mmips2be;
95extern Mach msparc;
96extern Mach msparc64;
97extern Mach m68020;
98extern Mach mi386;
99extern Mach mamd64;
100extern Mach marm;
101extern Mach mpower;
102extern Mach mpower64;
103extern Mach malpha;
104
105/* BUG: FIX THESE WHEN NEEDED */
106Mach mmips;
107Mach mmips2le;
108Mach mmips2be;
109Mach msparc;
110Mach msparc64;
111Mach m68020;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700112Mach mpower;
113Mach mpower64;
114Mach malpha;
115
116ExecTable exectab[] =
117{
118 { V_MAGIC, /* Mips v.out */
119 "mips plan 9 executable BE",
120 "mips plan 9 dlm BE",
121 FMIPS,
122 1,
123 &mmips,
124 sizeof(Exec),
125 beswal,
126 adotout },
127 { P_MAGIC, /* Mips 0.out (r3k le) */
128 "mips plan 9 executable LE",
129 "mips plan 9 dlm LE",
130 FMIPSLE,
131 1,
132 &mmips,
133 sizeof(Exec),
134 beswal,
135 adotout },
136 { M_MAGIC, /* Mips 4.out */
137 "mips 4k plan 9 executable BE",
138 "mips 4k plan 9 dlm BE",
139 FMIPS2BE,
140 1,
141 &mmips2be,
142 sizeof(Exec),
143 beswal,
144 adotout },
145 { N_MAGIC, /* Mips 0.out */
146 "mips 4k plan 9 executable LE",
147 "mips 4k plan 9 dlm LE",
148 FMIPS2LE,
149 1,
150 &mmips2le,
151 sizeof(Exec),
152 beswal,
153 adotout },
154 { 0x160<<16, /* Mips boot image */
155 "mips plan 9 boot image",
156 nil,
157 FMIPSB,
158 0,
159 &mmips,
160 sizeof(struct mipsexec),
161 beswal,
162 mipsboot },
163 { (0x160<<16)|3, /* Mips boot image */
164 "mips 4k plan 9 boot image",
165 nil,
166 FMIPSB,
167 0,
168 &mmips2be,
169 sizeof(struct mips4kexec),
170 beswal,
171 mips4kboot },
172 { K_MAGIC, /* Sparc k.out */
173 "sparc plan 9 executable",
174 "sparc plan 9 dlm",
175 FSPARC,
176 1,
177 &msparc,
178 sizeof(Exec),
179 beswal,
180 adotout },
181 { 0x01030107, /* Sparc boot image */
182 "sparc plan 9 boot image",
183 nil,
184 FSPARCB,
185 0,
186 &msparc,
187 sizeof(struct sparcexec),
188 beswal,
189 sparcboot },
190 { U_MAGIC, /* Sparc64 u.out */
191 "sparc64 plan 9 executable",
192 "sparc64 plan 9 dlm",
193 FSPARC64,
194 1,
195 &msparc64,
196 sizeof(Exec),
197 beswal,
198 adotout },
199 { A_MAGIC, /* 68020 2.out & boot image */
200 "68020 plan 9 executable",
201 "68020 plan 9 dlm",
202 F68020,
203 1,
204 &m68020,
205 sizeof(Exec),
206 beswal,
207 common },
208 { 0xFEEDFACE, /* Next boot image */
209 "next plan 9 boot image",
210 nil,
211 FNEXTB,
212 0,
213 &m68020,
214 sizeof(struct nextexec),
215 beswal,
216 nextboot },
217 { I_MAGIC, /* I386 8.out & boot image */
218 "386 plan 9 executable",
219 "386 plan 9 dlm",
220 FI386,
221 1,
222 &mi386,
223 sizeof(Exec),
224 beswal,
225 common },
226 { S_MAGIC, /* amd64 6.out & boot image */
227 "amd64 plan 9 executable",
228 "amd64 plan 9 dlm",
229 FAMD64,
230 1,
231 &mamd64,
232 sizeof(Exec)+8,
233 nil,
234 commonllp64 },
235 { Q_MAGIC, /* PowerPC q.out & boot image */
236 "power plan 9 executable",
237 "power plan 9 dlm",
238 FPOWER,
239 1,
240 &mpower,
241 sizeof(Exec),
242 beswal,
243 common },
244 { T_MAGIC, /* power64 9.out & boot image */
245 "power64 plan 9 executable",
246 "power64 plan 9 dlm",
247 FPOWER64,
248 1,
249 &mpower64,
250 sizeof(Exec)+8,
251 nil,
252 commonllp64 },
253 { ELF_MAG, /* any elf32 or elf64 */
254 "elf executable",
255 nil,
256 FNONE,
257 0,
258 &mi386,
259 sizeof(Ehdr64),
260 nil,
261 elfdotout },
Russ Coxfcd536d2009-03-24 18:04:50 -0700262 { MACH64_MAG, /* 64-bit MACH (apple mac) */
Rob Pike073486c2008-06-15 17:22:57 -0700263 "mach executable",
264 nil,
265 FAMD64,
266 0,
Russ Coxfcd536d2009-03-24 18:04:50 -0700267 &mamd64,
268 sizeof(Machhdr),
269 nil,
270 machdotout },
Rob Pike00274a12009-08-14 10:46:04 -0700271 { MACH32_MAG, /* 32-bit MACH (apple mac) */
Russ Coxfcd536d2009-03-24 18:04:50 -0700272 "mach executable",
273 nil,
274 FI386,
275 0,
Rob Pike073486c2008-06-15 17:22:57 -0700276 &mi386,
Russ Coxfcd536d2009-03-24 18:04:50 -0700277 sizeof(Machhdr),
Rob Pike073486c2008-06-15 17:22:57 -0700278 nil,
279 machdotout },
Rob Pikeed5e39a2008-06-12 14:50:25 -0700280 { E_MAGIC, /* Arm 5.out and boot image */
281 "arm plan 9 executable",
282 "arm plan 9 dlm",
283 FARM,
284 1,
285 &marm,
286 sizeof(Exec),
287 beswal,
288 common },
289 { (143<<16)|0413, /* (Free|Net)BSD Arm */
290 "arm *bsd executable",
291 nil,
292 FARM,
293 0,
294 &marm,
295 sizeof(Exec),
296 leswal,
297 armdotout },
298 { L_MAGIC, /* alpha 7.out */
299 "alpha plan 9 executable",
300 "alpha plan 9 dlm",
301 FALPHA,
302 1,
303 &malpha,
304 sizeof(Exec),
305 beswal,
306 common },
307 { 0x0700e0c3, /* alpha boot image */
308 "alpha plan 9 boot image",
309 nil,
310 FALPHA,
311 0,
312 &malpha,
313 sizeof(Exec),
314 beswal,
315 common },
Mateusz Czaplińskieae0a482011-08-29 14:25:43 -0400316 { 0x4d5a9000, /* see dosstub[] in pe.c */
317 "windows PE executable",
318 nil,
319 FWINPE,
320 0,
321 &mi386,
322 sizeof(Exec), /* TODO */
323 nil,
324 pedotout },
Rob Pikeed5e39a2008-06-12 14:50:25 -0700325 { 0 },
326};
327
328Mach *mach = &mi386; /* Global current machine table */
329
330static ExecTable*
331couldbe4k(ExecTable *mp)
332{
333 Dir *d;
334 ExecTable *f;
335
336 if((d=dirstat("/proc/1/regs")) == nil)
337 return mp;
338 if(d->length < 32*8){ /* R3000 */
339 free(d);
340 return mp;
341 }
342 free(d);
343 for (f = exectab; f->magic; f++)
344 if(f->magic == M_MAGIC) {
345 f->name = "mips plan 9 executable on mips2 kernel";
346 return f;
347 }
348 return mp;
349}
350
351int
352crackhdr(int fd, Fhdr *fp)
353{
354 ExecTable *mp;
355 ExecHdr d;
356 int nb, ret;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700357 uint32 magic;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700358
359 fp->type = FNONE;
360 nb = read(fd, (char *)&d.e, sizeof(d.e));
361 if (nb <= 0)
362 return 0;
363
364 ret = 0;
365 magic = beswal(d.e.exechdr.magic); /* big-endian */
366 for (mp = exectab; mp->magic; mp++) {
367 if (nb < mp->hsize)
368 continue;
369
370 /*
371 * The magic number has morphed into something
372 * with fields (the straw was DYN_MAGIC) so now
373 * a flag is needed in Fhdr to distinguish _MAGIC()
374 * magic numbers from foreign magic numbers.
375 *
376 * This code is creaking a bit and if it has to
377 * be modified/extended much more it's probably
378 * time to step back and redo it all.
379 */
380 if(mp->_magic){
381 if(mp->magic != (magic & ~DYN_MAGIC))
382 continue;
383
384 if(mp->magic == V_MAGIC)
385 mp = couldbe4k(mp);
386
387 if ((magic & DYN_MAGIC) && mp->dlmname != nil)
388 fp->name = mp->dlmname;
389 else
390 fp->name = mp->name;
391 }
392 else{
393 if(mp->magic != magic)
394 continue;
395 fp->name = mp->name;
396 }
397 fp->type = mp->type;
398 fp->hdrsz = mp->hsize; /* will be zero on bootables */
399 fp->_magic = mp->_magic;
400 fp->magic = magic;
401
402 mach = mp->mach;
403 if(mp->swal != nil)
Russ Cox9aad9fe2008-08-03 17:25:15 -0700404 hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700405 ret = mp->hparse(fd, fp, &d);
406 seek(fd, mp->hsize, 0); /* seek to end of header */
407 break;
408 }
409 if(mp->magic == 0)
410 werrstr("unknown header type");
411 return ret;
412}
413
414/*
415 * Convert header to canonical form
416 */
417static void
Russ Cox9aad9fe2008-08-03 17:25:15 -0700418hswal(void *v, int n, uint32 (*swap)(uint32))
Rob Pikeed5e39a2008-06-12 14:50:25 -0700419{
Russ Cox9aad9fe2008-08-03 17:25:15 -0700420 uint32 *ulp;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700421
422 for(ulp = v; n--; ulp++)
423 *ulp = (*swap)(*ulp);
424}
425
426/*
427 * Crack a normal a.out-type header
428 */
429static int
430adotout(int fd, Fhdr *fp, ExecHdr *hp)
431{
Russ Cox9aad9fe2008-08-03 17:25:15 -0700432 int32 pgsize;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700433
434 USED(fd);
435 pgsize = mach->pgsize;
436 settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
437 hp->e.exechdr.text, sizeof(Exec));
438 setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
439 hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
Russ Cox19fd5c72010-10-19 18:07:19 -0400440 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700441 return 1;
442}
443
444static void
445commonboot(Fhdr *fp)
446{
447 if (!(fp->entry & mach->ktmask))
448 return;
449
450 switch(fp->type) { /* boot image */
451 case F68020:
452 fp->type = F68020B;
453 fp->name = "68020 plan 9 boot image";
454 break;
455 case FI386:
456 fp->type = FI386B;
457 fp->txtaddr = (u32int)fp->entry;
458 fp->name = "386 plan 9 boot image";
459 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
460 break;
461 case FARM:
462 fp->type = FARMB;
463 fp->txtaddr = (u32int)fp->entry;
464 fp->name = "ARM plan 9 boot image";
465 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
466 return;
467 case FALPHA:
468 fp->type = FALPHAB;
469 fp->txtaddr = (u32int)fp->entry;
470 fp->name = "alpha plan 9 boot image";
471 fp->dataddr = fp->txtaddr+fp->txtsz;
472 break;
473 case FPOWER:
474 fp->type = FPOWERB;
475 fp->txtaddr = (u32int)fp->entry;
476 fp->name = "power plan 9 boot image";
477 fp->dataddr = fp->txtaddr+fp->txtsz;
478 break;
479 case FAMD64:
480 fp->type = FAMD64B;
481 fp->txtaddr = fp->entry;
482 fp->name = "amd64 plan 9 boot image";
483 fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
484 break;
485 default:
486 return;
487 }
488 fp->hdrsz = 0; /* header stripped */
489}
490
491/*
492 * _MAGIC() style headers and
493 * alpha plan9-style bootable images for axp "headerless" boot
494 *
495 */
496static int
497common(int fd, Fhdr *fp, ExecHdr *hp)
498{
499 adotout(fd, fp, hp);
500 if(hp->e.exechdr.magic & DYN_MAGIC) {
501 fp->txtaddr = 0;
502 fp->dataddr = fp->txtsz;
503 return 1;
504 }
505 commonboot(fp);
506 return 1;
507}
508
509static int
510commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
511{
Russ Cox9aad9fe2008-08-03 17:25:15 -0700512 int32 pgsize;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700513 uvlong entry;
514
Russ Cox55db9fe2011-08-25 16:08:13 -0400515 USED(unused);
516
Russ Cox9aad9fe2008-08-03 17:25:15 -0700517 hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700518 if(!(hp->e.exechdr.magic & HDR_MAGIC))
519 return 0;
520
521 /*
522 * There can be more magic here if the
523 * header ever needs more expansion.
524 * For now just catch use of any of the
525 * unused bits.
526 */
527 if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
528 return 0;
Russ Cox219fb022009-10-22 10:59:27 -0700529 union {
530 char *p;
531 uvlong *v;
532 } u;
533 u.p = (char*)&hp->e.exechdr;
534 entry = beswav(*u.v);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700535
536 pgsize = mach->pgsize;
537 settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
538 setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
539 hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
Russ Cox19fd5c72010-10-19 18:07:19 -0400540 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700541
542 if(hp->e.exechdr.magic & DYN_MAGIC) {
543 fp->txtaddr = 0;
544 fp->dataddr = fp->txtsz;
545 return 1;
546 }
547 commonboot(fp);
548 return 1;
549}
550
551/*
552 * mips bootable image.
553 */
554static int
555mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
556{
Russ Cox55db9fe2011-08-25 16:08:13 -0400557 USED(fd);
558 USED(fp);
559 USED(hp);
560
Rob Pikeed5e39a2008-06-12 14:50:25 -0700561abort();
562#ifdef unused
563 USED(fd);
564 fp->type = FMIPSB;
565 switch(hp->e.exechdr.amagic) {
566 default:
567 case 0407: /* some kind of mips */
568 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
569 hp->e.tsize, sizeof(struct mipsexec)+4);
570 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
571 fp->txtoff+hp->e.tsize, hp->e.bsize);
572 break;
573 case 0413: /* some kind of mips */
574 settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
575 hp->e.tsize, 0);
576 setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
577 hp->e.tsize, hp->e.bsize);
578 break;
579 }
580 setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
581 fp->hdrsz = 0; /* header stripped */
582#endif
583 return 1;
584}
585
586/*
587 * mips4k bootable image.
588 */
589static int
590mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
591{
Russ Cox55db9fe2011-08-25 16:08:13 -0400592 USED(fd);
593 USED(fp);
594 USED(hp);
595
Rob Pikeed5e39a2008-06-12 14:50:25 -0700596abort();
597#ifdef unused
598 USED(fd);
599 fp->type = FMIPSB;
600 switch(hp->e.h.amagic) {
601 default:
602 case 0407: /* some kind of mips */
603 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
604 hp->e.h.tsize, sizeof(struct mips4kexec));
605 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
606 fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
607 break;
608 case 0413: /* some kind of mips */
609 settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
610 hp->e.h.tsize, 0);
611 setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
612 hp->e.h.tsize, hp->e.h.bsize);
613 break;
614 }
615 setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
616 fp->hdrsz = 0; /* header stripped */
617#endif
618 return 1;
619}
620
621/*
622 * sparc bootable image
623 */
624static int
625sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
626{
Russ Cox55db9fe2011-08-25 16:08:13 -0400627 USED(fd);
628 USED(fp);
629 USED(hp);
630
Rob Pikeed5e39a2008-06-12 14:50:25 -0700631abort();
632#ifdef unused
633 USED(fd);
634 fp->type = FSPARCB;
635 settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
636 sizeof(struct sparcexec));
637 setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
638 fp->txtoff+hp->e.stext, hp->e.sbss);
639 setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
640 fp->hdrsz = 0; /* header stripped */
641#endif
642 return 1;
643}
644
645/*
646 * next bootable image
647 */
648static int
649nextboot(int fd, Fhdr *fp, ExecHdr *hp)
650{
Russ Cox55db9fe2011-08-25 16:08:13 -0400651 USED(fd);
652 USED(fp);
653 USED(hp);
654
Rob Pikeed5e39a2008-06-12 14:50:25 -0700655abort();
656#ifdef unused
657 USED(fd);
658 fp->type = FNEXTB;
659 settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
660 hp->e.texts.size, hp->e.texts.offset);
661 setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
662 hp->e.datas.offset, hp->e.bsss.size);
663 setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
664 hp->e.symc.symoff);
665 fp->hdrsz = 0; /* header stripped */
666#endif
667 return 1;
668}
669
670/*
671 * Elf32 and Elf64 binaries.
672 */
673static int
674elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
675{
Rob Pikeed5e39a2008-06-12 14:50:25 -0700676 uvlong (*swav)(uvlong);
Russ Cox9aad9fe2008-08-03 17:25:15 -0700677 uint32 (*swal)(uint32);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700678 ushort (*swab)(ushort);
679 Ehdr64 *ep;
Lucio De Re7f417d82011-11-18 23:11:50 -0500680 Phdr64 *ph, *pph;
Rob Pike34691cc2008-06-13 12:55:37 -0700681 Shdr64 *sh;
682 int i, it, id, is, phsz, shsz;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700683
684 /* bitswap the header according to the DATA format */
685 ep = &hp->e.elfhdr64;
686 if(ep->ident[CLASS] != ELFCLASS64) {
687 werrstr("bad ELF class - not 32 bit or 64 bit");
688 return 0;
689 }
690 if(ep->ident[DATA] == ELFDATA2LSB) {
691 swab = leswab;
692 swal = leswal;
693 swav = leswav;
694 } else if(ep->ident[DATA] == ELFDATA2MSB) {
695 swab = beswab;
696 swal = beswal;
697 swav = beswav;
698 } else {
699 werrstr("bad ELF encoding - not big or little endian");
700 return 0;
701 }
702
703 ep->type = swab(ep->type);
704 ep->machine = swab(ep->machine);
705 ep->version = swal(ep->version);
706 ep->elfentry = swal(ep->elfentry);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700707 ep->phoff = swav(ep->phoff);
708 ep->shoff = swav(ep->shoff);
709 ep->flags = swav(ep->flags);
710 ep->ehsize = swab(ep->ehsize);
711 ep->phentsize = swab(ep->phentsize);
712 ep->phnum = swab(ep->phnum);
713 ep->shentsize = swab(ep->shentsize);
714 ep->shnum = swab(ep->shnum);
715 ep->shstrndx = swab(ep->shstrndx);
716 if(ep->type != EXEC || ep->version != CURRENT)
717 return 0;
718
719 /* we could definitely support a lot more machines here */
720 fp->magic = ELF_MAG;
721 fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
722 switch(ep->machine) {
Rob Pikeed5e39a2008-06-12 14:50:25 -0700723 case AMD64:
724 mach = &mamd64;
725 fp->type = FAMD64;
726 break;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700727 default:
728 return 0;
729 }
730
731 if(ep->phentsize != sizeof(Phdr64)) {
732 werrstr("bad ELF header size");
733 return 0;
734 }
735 phsz = sizeof(Phdr64)*ep->phnum;
736 ph = malloc(phsz);
737 if(!ph)
738 return 0;
739 seek(fd, ep->phoff, 0);
740 if(read(fd, ph, phsz) < 0) {
741 free(ph);
742 return 0;
743 }
Russ Cox9aad9fe2008-08-03 17:25:15 -0700744 hswal(ph, phsz/sizeof(uint32), swal);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700745
Rob Pike34691cc2008-06-13 12:55:37 -0700746 shsz = sizeof(Shdr64)*ep->shnum;
747 sh = malloc(shsz);
748 if(sh) {
749 seek(fd, ep->shoff, 0);
750 if(read(fd, sh, shsz) < 0) {
751 free(sh);
752 sh = 0;
753 } else
Russ Coxfcd536d2009-03-24 18:04:50 -0700754 hswal(sh, shsz/sizeof(uint32), swal);
Rob Pike34691cc2008-06-13 12:55:37 -0700755 }
756
Rob Pikeed5e39a2008-06-12 14:50:25 -0700757 /* find text, data and symbols and install them */
758 it = id = is = -1;
759 for(i = 0; i < ep->phnum; i++) {
760 if(ph[i].type == LOAD
761 && (ph[i].flags & (R|X)) == (R|X) && it == -1)
762 it = i;
763 else if(ph[i].type == LOAD
764 && (ph[i].flags & (R|W)) == (R|W) && id == -1)
765 id = i;
766 else if(ph[i].type == NOPTYPE && is == -1)
767 is = i;
768 }
769 if(it == -1 || id == -1) {
770 /*
771 * The SPARC64 boot image is something of an ELF hack.
772 * Text+Data+BSS are represented by ph[0]. Symbols
773 * are represented by ph[1]:
774 *
775 * filesz, memsz, vaddr, paddr, off
776 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
777 * ph[1] : symsz, lcsz, 0, 0, symoff
778 */
779 if(ep->machine == SPARC64 && ep->phnum == 2) {
Russ Cox9aad9fe2008-08-03 17:25:15 -0700780 uint32 txtaddr, txtsz, dataddr, bsssz;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700781
782 txtaddr = ph[0].vaddr | 0x80000000;
783 txtsz = ph[0].filesz - ph[0].paddr;
784 dataddr = txtaddr + txtsz;
785 bsssz = ph[0].memsz - ph[0].filesz;
786 settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
787 setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
Russ Cox19fd5c72010-10-19 18:07:19 -0400788 setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700789 free(ph);
790 return 1;
791 }
792
793 werrstr("No TEXT or DATA sections");
794 free(ph);
Rob Pike34691cc2008-06-13 12:55:37 -0700795 free(sh);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700796 return 0;
797 }
798
799 settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
Lucio De Re7f417d82011-11-18 23:11:50 -0500800 pph = ph + id;
801 setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700802 if(is != -1)
Russ Cox19fd5c72010-10-19 18:07:19 -0400803 setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
Russ Coxfcd536d2009-03-24 18:04:50 -0700804 else if(sh != 0){
Rob Pike34691cc2008-06-13 12:55:37 -0700805 char *buf;
806 uvlong symsize = 0;
807 uvlong symoff = 0;
808 uvlong pclnsz = 0;
Russ Cox19fd5c72010-10-19 18:07:19 -0400809 uvlong pclnoff = 0;
Rob Pike34691cc2008-06-13 12:55:37 -0700810
811 /* load shstrtab names */
812 buf = malloc(sh[ep->shstrndx].size);
813 if (buf == 0)
814 goto done;
Dave Cheneyae502c42011-09-01 13:43:03 -0400815 memset(buf, 0, sh[ep->shstrndx].size);
Rob Pike34691cc2008-06-13 12:55:37 -0700816 seek(fd, sh[ep->shstrndx].offset, 0);
Russ Cox05cc83b2010-09-28 13:00:13 -0400817 i = read(fd, buf, sh[ep->shstrndx].size);
818 USED(i); // shut up ubuntu gcc
Rob Pike34691cc2008-06-13 12:55:37 -0700819
820 for(i = 0; i < ep->shnum; i++) {
Russ Cox899c5282008-09-18 15:06:14 -0700821 if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
Rob Pike34691cc2008-06-13 12:55:37 -0700822 symsize = sh[i].size;
823 symoff = sh[i].offset;
824 }
Russ Cox899c5282008-09-18 15:06:14 -0700825 if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
Rob Pike34691cc2008-06-13 12:55:37 -0700826 pclnsz = sh[i].size;
Russ Cox19fd5c72010-10-19 18:07:19 -0400827 pclnoff = sh[i].offset;
Rob Pike34691cc2008-06-13 12:55:37 -0700828 }
829 }
Russ Cox19fd5c72010-10-19 18:07:19 -0400830 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
Rob Pike34691cc2008-06-13 12:55:37 -0700831 free(buf);
832 }
833done:
Rob Pikeed5e39a2008-06-12 14:50:25 -0700834 free(ph);
Rob Pike34691cc2008-06-13 12:55:37 -0700835 free(sh);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700836 return 1;
837}
838
839static int
840elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
841{
842
Russ Cox9aad9fe2008-08-03 17:25:15 -0700843 uint32 (*swal)(uint32);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700844 ushort (*swab)(ushort);
845 Ehdr32 *ep;
846 Phdr32 *ph;
Russ Coxfcd536d2009-03-24 18:04:50 -0700847 int i, it, id, is, phsz, shsz;
848 Shdr32 *sh;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700849
850 /* bitswap the header according to the DATA format */
851 ep = &hp->e.elfhdr32;
852 if(ep->ident[CLASS] != ELFCLASS32) {
853 return elf64dotout(fd, fp, hp);
854 }
855 if(ep->ident[DATA] == ELFDATA2LSB) {
856 swab = leswab;
857 swal = leswal;
858 } else if(ep->ident[DATA] == ELFDATA2MSB) {
859 swab = beswab;
860 swal = beswal;
861 } else {
862 werrstr("bad ELF encoding - not big or little endian");
863 return 0;
864 }
865
866 ep->type = swab(ep->type);
867 ep->machine = swab(ep->machine);
868 ep->version = swal(ep->version);
869 ep->elfentry = swal(ep->elfentry);
870 ep->phoff = swal(ep->phoff);
871 ep->shoff = swal(ep->shoff);
872 ep->flags = swal(ep->flags);
873 ep->ehsize = swab(ep->ehsize);
874 ep->phentsize = swab(ep->phentsize);
875 ep->phnum = swab(ep->phnum);
876 ep->shentsize = swab(ep->shentsize);
877 ep->shnum = swab(ep->shnum);
878 ep->shstrndx = swab(ep->shstrndx);
879 if(ep->type != EXEC || ep->version != CURRENT)
880 return 0;
881
882 /* we could definitely support a lot more machines here */
883 fp->magic = ELF_MAG;
884 fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
885 switch(ep->machine) {
886 case I386:
887 mach = &mi386;
888 fp->type = FI386;
889 break;
890 case MIPS:
891 mach = &mmips;
892 fp->type = FMIPS;
893 break;
894 case SPARC64:
895 mach = &msparc64;
896 fp->type = FSPARC64;
897 break;
898 case POWER:
899 mach = &mpower;
900 fp->type = FPOWER;
901 break;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700902 case ARM:
903 mach = &marm;
904 fp->type = FARM;
905 break;
906 default:
907 return 0;
908 }
909
910 if(ep->phentsize != sizeof(Phdr32)) {
911 werrstr("bad ELF header size");
912 return 0;
913 }
914 phsz = sizeof(Phdr32)*ep->phnum;
915 ph = malloc(phsz);
916 if(!ph)
917 return 0;
918 seek(fd, ep->phoff, 0);
919 if(read(fd, ph, phsz) < 0) {
920 free(ph);
921 return 0;
922 }
Russ Cox9aad9fe2008-08-03 17:25:15 -0700923 hswal(ph, phsz/sizeof(uint32), swal);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700924
Russ Coxfcd536d2009-03-24 18:04:50 -0700925 shsz = sizeof(Shdr32)*ep->shnum;
926 sh = malloc(shsz);
927 if(sh) {
928 seek(fd, ep->shoff, 0);
929 if(read(fd, sh, shsz) < 0) {
930 free(sh);
931 sh = 0;
932 } else
933 hswal(sh, shsz/sizeof(uint32), swal);
934 }
935
Rob Pikeed5e39a2008-06-12 14:50:25 -0700936 /* find text, data and symbols and install them */
937 it = id = is = -1;
938 for(i = 0; i < ep->phnum; i++) {
939 if(ph[i].type == LOAD
940 && (ph[i].flags & (R|X)) == (R|X) && it == -1)
941 it = i;
942 else if(ph[i].type == LOAD
943 && (ph[i].flags & (R|W)) == (R|W) && id == -1)
944 id = i;
945 else if(ph[i].type == NOPTYPE && is == -1)
946 is = i;
947 }
948 if(it == -1 || id == -1) {
949 /*
950 * The SPARC64 boot image is something of an ELF hack.
951 * Text+Data+BSS are represented by ph[0]. Symbols
952 * are represented by ph[1]:
953 *
954 * filesz, memsz, vaddr, paddr, off
955 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
956 * ph[1] : symsz, lcsz, 0, 0, symoff
957 */
958 if(ep->machine == SPARC64 && ep->phnum == 2) {
Russ Cox9aad9fe2008-08-03 17:25:15 -0700959 uint32 txtaddr, txtsz, dataddr, bsssz;
Rob Pikeed5e39a2008-06-12 14:50:25 -0700960
961 txtaddr = ph[0].vaddr | 0x80000000;
962 txtsz = ph[0].filesz - ph[0].paddr;
963 dataddr = txtaddr + txtsz;
964 bsssz = ph[0].memsz - ph[0].filesz;
965 settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
966 setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
Russ Cox19fd5c72010-10-19 18:07:19 -0400967 setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700968 free(ph);
969 return 1;
970 }
971
972 werrstr("No TEXT or DATA sections");
Russ Coxfcd536d2009-03-24 18:04:50 -0700973 free(sh);
Rob Pikeed5e39a2008-06-12 14:50:25 -0700974 free(ph);
975 return 0;
976 }
977
978 settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
979 setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
980 if(is != -1)
Russ Cox19fd5c72010-10-19 18:07:19 -0400981 setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
Russ Coxfcd536d2009-03-24 18:04:50 -0700982 else if(sh != 0){
983 char *buf;
984 uvlong symsize = 0;
985 uvlong symoff = 0;
Russ Cox19fd5c72010-10-19 18:07:19 -0400986 uvlong pclnsize = 0;
987 uvlong pclnoff = 0;
Russ Coxfcd536d2009-03-24 18:04:50 -0700988
989 /* load shstrtab names */
990 buf = malloc(sh[ep->shstrndx].size);
991 if (buf == 0)
992 goto done;
Dave Cheneyae502c42011-09-01 13:43:03 -0400993 memset(buf, 0, sh[ep->shstrndx].size);
Russ Coxfcd536d2009-03-24 18:04:50 -0700994 seek(fd, sh[ep->shstrndx].offset, 0);
Russ Cox05cc83b2010-09-28 13:00:13 -0400995 i = read(fd, buf, sh[ep->shstrndx].size);
996 USED(i); // shut up ubuntu gcc
Russ Coxfcd536d2009-03-24 18:04:50 -0700997
998 for(i = 0; i < ep->shnum; i++) {
999 if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
1000 symsize = sh[i].size;
1001 symoff = sh[i].offset;
1002 }
1003 if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
Russ Cox19fd5c72010-10-19 18:07:19 -04001004 pclnsize = sh[i].size;
1005 pclnoff = sh[i].offset;
Russ Coxfcd536d2009-03-24 18:04:50 -07001006 }
1007 }
Russ Cox19fd5c72010-10-19 18:07:19 -04001008 setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
Russ Coxfcd536d2009-03-24 18:04:50 -07001009 free(buf);
1010 }
1011done:
1012 free(sh);
Rob Pikeed5e39a2008-06-12 14:50:25 -07001013 free(ph);
1014 return 1;
1015}
1016
Rob Pike073486c2008-06-15 17:22:57 -07001017static int
1018machdotout(int fd, Fhdr *fp, ExecHdr *hp)
1019{
1020 uvlong (*swav)(uvlong);
Russ Cox9aad9fe2008-08-03 17:25:15 -07001021 uint32 (*swal)(uint32);
Rob Pike073486c2008-06-15 17:22:57 -07001022 Machhdr *mp;
1023 MachCmd **cmd;
Rob Pike073486c2008-06-15 17:22:57 -07001024 MachSymSeg *symtab;
1025 MachSymSeg *pclntab;
1026 MachSeg64 *seg;
1027 MachSect64 *sect;
Russ Coxfcd536d2009-03-24 18:04:50 -07001028 MachSeg32 *seg32;
1029 MachSect32 *sect32;
Rob Pike073486c2008-06-15 17:22:57 -07001030 uvlong textsize, datasize, bsssize;
1031 uchar *cmdbuf;
1032 uchar *cmdp;
Russ Coxfcd536d2009-03-24 18:04:50 -07001033 int i, hdrsize;
1034 uint32 textva, textoff, datava, dataoff;
Rob Pike073486c2008-06-15 17:22:57 -07001035
Rob Pike073486c2008-06-15 17:22:57 -07001036 mp = &hp->e.machhdr;
Russ Coxfcd536d2009-03-24 18:04:50 -07001037 if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
1038 werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
Rob Pike073486c2008-06-15 17:22:57 -07001039 return 0;
1040 }
Russ Coxfcd536d2009-03-24 18:04:50 -07001041
Rob Pike073486c2008-06-15 17:22:57 -07001042 swal = leswal;
1043 swav = leswav;
1044
1045 mp->magic = swal(mp->magic);
1046 mp->cputype = swal(mp->cputype);
1047 mp->cpusubtype = swal(mp->cpusubtype);
1048 mp->filetype = swal(mp->filetype);
1049 mp->ncmds = swal(mp->ncmds);
1050 mp->sizeofcmds = swal(mp->sizeofcmds);
1051 mp->flags = swal(mp->flags);
1052 mp->reserved = swal(mp->reserved);
Russ Coxfcd536d2009-03-24 18:04:50 -07001053
1054 switch(mp->magic) {
1055 case 0xFEEDFACE: // 32-bit mach
1056 if (mp->cputype != MACH_CPU_TYPE_X86) {
1057 werrstr("bad MACH cpu type - not 386");
1058 return 0;
1059 }
1060 if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
1061 werrstr("bad MACH cpu subtype - not 386");
1062 return 0;
1063 }
1064 if (mp->filetype != MACH_EXECUTABLE_TYPE) {
1065 werrstr("bad MACH executable type");
1066 return 0;
1067 }
1068 mach = &mi386;
1069 fp->type = FI386;
1070 hdrsize = 28;
1071 break;
1072
1073 case 0xFEEDFACF: // 64-bit mach
1074 if (mp->cputype != MACH_CPU_TYPE_X86_64) {
1075 werrstr("bad MACH cpu type - not amd64");
1076 return 0;
1077 }
1078
1079 if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
1080 werrstr("bad MACH cpu subtype - not amd64");
1081 return 0;
1082 }
1083 mach = &mamd64;
1084 fp->type = FAMD64;
1085 hdrsize = 32;
1086 break;
1087
1088 default:
1089 werrstr("not mach %#ux", mp->magic);
Rob Pike073486c2008-06-15 17:22:57 -07001090 return 0;
1091 }
Rob Pike073486c2008-06-15 17:22:57 -07001092
1093 cmdbuf = malloc(mp->sizeofcmds);
Russ Coxfcd536d2009-03-24 18:04:50 -07001094 seek(fd, hdrsize, 0);
Rob Pike073486c2008-06-15 17:22:57 -07001095 if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
1096 free(cmdbuf);
1097 return 0;
1098 }
1099 cmd = malloc(mp->ncmds * sizeof(MachCmd*));
1100 cmdp = cmdbuf;
Russ Coxfcd536d2009-03-24 18:04:50 -07001101 textva = 0;
1102 textoff = 0;
1103 dataoff = 0;
1104 datava = 0;
Rob Pike073486c2008-06-15 17:22:57 -07001105 symtab = 0;
1106 pclntab = 0;
Lucio De Re7f417d82011-11-18 23:11:50 -05001107 textsize = 0;
1108 datasize = 0;
1109 bsssize = 0;
Rob Pike073486c2008-06-15 17:22:57 -07001110 for (i = 0; i < mp->ncmds; i++) {
1111 MachCmd *c;
1112
1113 cmd[i] = (MachCmd*)cmdp;
1114 c = cmd[i];
1115 c->type = swal(c->type);
1116 c->size = swal(c->size);
1117 switch(c->type) {
Russ Coxfcd536d2009-03-24 18:04:50 -07001118 case MACH_SEGMENT_32:
1119 if(mp->magic != 0xFEEDFACE) {
1120 werrstr("segment 32 in mach 64");
1121 goto bad;
1122 }
1123 seg32 = (MachSeg32*)c;
1124 seg32->vmaddr = swav(seg32->vmaddr);
1125 seg32->vmsize = swav(seg32->vmsize);
1126 seg32->fileoff = swav(seg32->fileoff);
1127 seg32->filesize = swav(seg32->filesize);
1128 seg32->maxprot = swal(seg32->maxprot);
1129 seg32->initprot = swal(seg32->initprot);
1130 seg32->nsects = swal(seg32->nsects);
1131 seg32->flags = swal(seg32->flags);
1132 if (strcmp(seg32->segname, "__TEXT") == 0) {
1133 textva = seg32->vmaddr;
1134 textoff = seg32->fileoff;
1135 sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
1136 if (strcmp(sect32->sectname, "__text") == 0) {
1137 textsize = swal(sect32->size);
1138 } else {
1139 werrstr("no text section");
1140 goto bad;
1141 }
1142 }
1143 if (strcmp(seg32->segname, "__DATA") == 0) {
1144 datava = seg32->vmaddr;
1145 dataoff = seg32->fileoff;
1146 sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
1147 if (strcmp(sect32->sectname, "__data") == 0) {
1148 datasize = swal(sect32->size);
1149 } else {
1150 werrstr("no data section");
1151 goto bad;
1152 }
1153 sect32++;
Russ Cox133a1582009-10-03 10:37:12 -07001154 if (strcmp(sect32->sectname, "__nl_symbol_ptr") == 0)
1155 sect32++;
Russ Coxfcd536d2009-03-24 18:04:50 -07001156 if (strcmp(sect32->sectname, "__bss") == 0) {
1157 bsssize = swal(sect32->size);
1158 } else {
1159 werrstr("no bss section");
1160 goto bad;
1161 }
1162 }
1163 break;
1164
Rob Pike073486c2008-06-15 17:22:57 -07001165 case MACH_SEGMENT_64:
Russ Coxfcd536d2009-03-24 18:04:50 -07001166 if(mp->magic != 0xFEEDFACF) {
1167 werrstr("segment 32 in mach 64");
1168 goto bad;
1169 }
Rob Pike073486c2008-06-15 17:22:57 -07001170 seg = (MachSeg64*)c;
1171 seg->vmaddr = swav(seg->vmaddr);
1172 seg->vmsize = swav(seg->vmsize);
1173 seg->fileoff = swav(seg->fileoff);
1174 seg->filesize = swav(seg->filesize);
1175 seg->maxprot = swal(seg->maxprot);
1176 seg->initprot = swal(seg->initprot);
1177 seg->nsects = swal(seg->nsects);
1178 seg->flags = swal(seg->flags);
1179 if (strcmp(seg->segname, "__TEXT") == 0) {
Russ Coxfcd536d2009-03-24 18:04:50 -07001180 textva = seg->vmaddr;
1181 textoff = seg->fileoff;
Rob Pike073486c2008-06-15 17:22:57 -07001182 sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
1183 if (strcmp(sect->sectname, "__text") == 0) {
1184 textsize = swav(sect->size);
1185 } else {
1186 werrstr("no text section");
1187 goto bad;
1188 }
1189 }
1190 if (strcmp(seg->segname, "__DATA") == 0) {
Russ Coxfcd536d2009-03-24 18:04:50 -07001191 datava = seg->vmaddr;
1192 dataoff = seg->fileoff;
Rob Pike073486c2008-06-15 17:22:57 -07001193 sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
1194 if (strcmp(sect->sectname, "__data") == 0) {
1195 datasize = swav(sect->size);
1196 } else {
1197 werrstr("no data section");
1198 goto bad;
1199 }
1200 sect++;
Russ Cox84edc2e2010-05-24 14:30:51 -07001201 if (strcmp(sect->sectname, "__nl_symbol_ptr") == 0)
1202 sect++;
Rob Pike073486c2008-06-15 17:22:57 -07001203 if (strcmp(sect->sectname, "__bss") == 0) {
1204 bsssize = swav(sect->size);
1205 } else {
1206 werrstr("no bss section");
1207 goto bad;
1208 }
1209 }
1210 break;
1211 case MACH_UNIXTHREAD:
1212 break;
1213 case MACH_SYMSEG:
1214 if (symtab == 0)
1215 symtab = (MachSymSeg*)c;
1216 else if (pclntab == 0)
1217 pclntab = (MachSymSeg*)c;
1218 break;
1219 }
1220 cmdp += c->size;
1221 }
Russ Coxfcd536d2009-03-24 18:04:50 -07001222 if (textva == 0 || datava == 0) {
Rob Pike073486c2008-06-15 17:22:57 -07001223 free(cmd);
1224 free(cmdbuf);
1225 return 0;
1226 }
1227 /* compute entry by taking address after header - weird - BUG? */
Russ Coxfcd536d2009-03-24 18:04:50 -07001228 settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
1229 setdata(fp, datava, datasize, dataoff, bsssize);
Rob Pike073486c2008-06-15 17:22:57 -07001230 if(symtab != 0)
Russ Cox19fd5c72010-10-19 18:07:19 -04001231 setsym(fp, symtab->fileoff, symtab->filesize, 0, 0, 0, pclntab? pclntab->filesize : 0);
Rob Pike073486c2008-06-15 17:22:57 -07001232 free(cmd);
1233 free(cmdbuf);
1234 return 1;
1235bad:
1236 free(cmd);
1237 free(cmdbuf);
1238 return 0;
1239}
1240
Rob Pikeed5e39a2008-06-12 14:50:25 -07001241/*
1242 * (Free|Net)BSD ARM header.
1243 */
1244static int
1245armdotout(int fd, Fhdr *fp, ExecHdr *hp)
1246{
1247 uvlong kbase;
1248
1249 USED(fd);
1250 settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
1251 setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
Russ Cox19fd5c72010-10-19 18:07:19 -04001252 setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
Rob Pikeed5e39a2008-06-12 14:50:25 -07001253
1254 kbase = 0xF0000000;
1255 if ((fp->entry & kbase) == kbase) { /* Boot image */
1256 fp->txtaddr = kbase+sizeof(Exec);
1257 fp->name = "ARM *BSD boot image";
1258 fp->hdrsz = 0; /* header stripped */
1259 fp->dataddr = kbase+fp->txtsz;
1260 }
1261 return 1;
1262}
1263
Mateusz Czaplińskieae0a482011-08-29 14:25:43 -04001264/*
1265 * Structures needed to parse PE image.
1266 */
1267typedef struct {
1268 uint16 Machine;
1269 uint16 NumberOfSections;
1270 uint32 TimeDateStamp;
1271 uint32 PointerToSymbolTable;
1272 uint32 NumberOfSymbols;
1273 uint16 SizeOfOptionalHeader;
1274 uint16 Characteristics;
1275} IMAGE_FILE_HEADER;
1276
1277typedef struct {
1278 uint8 Name[8];
1279 uint32 VirtualSize;
1280 uint32 VirtualAddress;
1281 uint32 SizeOfRawData;
1282 uint32 PointerToRawData;
1283 uint32 PointerToRelocations;
1284 uint32 PointerToLineNumbers;
1285 uint16 NumberOfRelocations;
1286 uint16 NumberOfLineNumbers;
1287 uint32 Characteristics;
1288} IMAGE_SECTION_HEADER;
1289
1290typedef struct {
1291 uint32 VirtualAddress;
1292 uint32 Size;
1293} IMAGE_DATA_DIRECTORY;
1294
1295typedef struct {
1296 uint16 Magic;
1297 uint8 MajorLinkerVersion;
1298 uint8 MinorLinkerVersion;
1299 uint32 SizeOfCode;
1300 uint32 SizeOfInitializedData;
1301 uint32 SizeOfUninitializedData;
1302 uint32 AddressOfEntryPoint;
1303 uint32 BaseOfCode;
1304 uint32 BaseOfData;
1305 uint32 ImageBase;
1306 uint32 SectionAlignment;
1307 uint32 FileAlignment;
1308 uint16 MajorOperatingSystemVersion;
1309 uint16 MinorOperatingSystemVersion;
1310 uint16 MajorImageVersion;
1311 uint16 MinorImageVersion;
1312 uint16 MajorSubsystemVersion;
1313 uint16 MinorSubsystemVersion;
1314 uint32 Win32VersionValue;
1315 uint32 SizeOfImage;
1316 uint32 SizeOfHeaders;
1317 uint32 CheckSum;
1318 uint16 Subsystem;
1319 uint16 DllCharacteristics;
1320 uint32 SizeOfStackReserve;
1321 uint32 SizeOfStackCommit;
1322 uint32 SizeOfHeapReserve;
1323 uint32 SizeOfHeapCommit;
1324 uint32 LoaderFlags;
1325 uint32 NumberOfRvaAndSizes;
1326 IMAGE_DATA_DIRECTORY DataDirectory[16];
1327} IMAGE_OPTIONAL_HEADER;
1328
1329static int
1330match8(void *buf, char *cmp)
1331{
1332 return strncmp((char*)buf, cmp, 8) == 0;
1333}
1334
1335/* TODO(czaplinski): 64b windows? */
1336/*
1337 * Read from Windows PE/COFF .exe file image.
1338 */
1339static int
1340pedotout(int fd, Fhdr *fp, ExecHdr *hp)
1341{
1342 uint32 start, magic;
1343 uint32 symtab, esymtab;
1344 IMAGE_FILE_HEADER fh;
1345 IMAGE_SECTION_HEADER sh;
1346 IMAGE_OPTIONAL_HEADER oh;
1347 uint8 sym[18];
1348 uint32 *valp;
1349 int i;
1350
1351 USED(hp);
1352 seek(fd, 0x3c, 0);
1353 if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
1354 werrstr("crippled PE MSDOS header");
1355 return 0;
1356 }
1357 start = leswal(start);
1358
1359 seek(fd, start, 0);
1360 if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
1361 werrstr("no PE magic number found");
1362 return 0;
1363 }
1364 if (beswal(magic) != 0x50450000) { /* "PE\0\0" */
1365 werrstr("incorrect PE magic number");
1366 return 0;
1367 }
1368
1369 if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
1370 werrstr("crippled PE File Header");
1371 return 0;
1372 }
1373 if (fh.PointerToSymbolTable == 0) {
1374 werrstr("zero pointer to COFF symbol table");
1375 return 0;
1376 }
1377
1378 if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
1379 werrstr("crippled PE Optional Header");
1380 return 0;
1381 }
1382
1383 seek(fd, start+sizeof(magic)+sizeof(fh)+leswab(fh.SizeOfOptionalHeader), 0);
Lucio De Re7f417d82011-11-18 23:11:50 -05001384 fp->txtaddr = 0;
1385 fp->dataddr = 0;
Mateusz Czaplińskieae0a482011-08-29 14:25:43 -04001386 for (i=0; i<leswab(fh.NumberOfSections); i++) {
1387 if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
1388 werrstr("could not read Section Header %d", i+1);
1389 return 0;
1390 }
1391 if (match8(sh.Name, ".text"))
1392 settext(fp, leswal(sh.VirtualAddress), leswal(oh.AddressOfEntryPoint), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
1393 if (match8(sh.Name, ".data"))
1394 setdata(fp, leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
1395 }
1396 if (fp->txtaddr==0 || fp->dataddr==0) {
1397 werrstr("no .text or .data");
1398 return 0;
1399 }
1400
1401 seek(fd, leswal(fh.PointerToSymbolTable), 0);
1402 symtab = esymtab = 0;
1403 for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
Lucio De Re7f417d82011-11-18 23:11:50 -05001404 if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) {
Mateusz Czaplińskieae0a482011-08-29 14:25:43 -04001405 werrstr("crippled COFF symbol %d", i);
1406 return 0;
1407 }
1408 valp = (uint32 *)&sym[8];
1409 if (match8(sym, "symtab"))
1410 symtab = leswal(*valp);
1411 if (match8(sym, "esymtab"))
1412 esymtab = leswal(*valp);
1413 }
1414 if (symtab==0 || esymtab==0) {
1415 werrstr("no symtab or esymtab in COFF symbol table");
1416 return 0;
1417 }
1418 setsym(fp, symtab, esymtab-symtab, 0, 0, 0, 0);
1419
1420 return 1;
1421}
1422
Rob Pikeed5e39a2008-06-12 14:50:25 -07001423static void
Russ Cox9aad9fe2008-08-03 17:25:15 -07001424settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
Rob Pikeed5e39a2008-06-12 14:50:25 -07001425{
1426 fp->txtaddr = a;
1427 fp->entry = e;
1428 fp->txtsz = s;
1429 fp->txtoff = off;
1430}
1431
1432static void
Russ Cox9aad9fe2008-08-03 17:25:15 -07001433setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
Rob Pikeed5e39a2008-06-12 14:50:25 -07001434{
1435 fp->dataddr = a;
1436 fp->datsz = s;
1437 fp->datoff = off;
1438 fp->bsssz = bss;
1439}
1440
1441static void
Russ Cox19fd5c72010-10-19 18:07:19 -04001442setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
Rob Pikeed5e39a2008-06-12 14:50:25 -07001443{
Rob Pikeed5e39a2008-06-12 14:50:25 -07001444 fp->symoff = symoff;
Russ Cox19fd5c72010-10-19 18:07:19 -04001445 fp->symsz = symsz;
1446
1447 if(sppcoff == 0)
1448 sppcoff = symoff+symsz;
1449 fp->sppcoff = symoff;
Rob Pikeed5e39a2008-06-12 14:50:25 -07001450 fp->sppcsz = sppcsz;
Russ Cox19fd5c72010-10-19 18:07:19 -04001451
1452 if(lnpcoff == 0)
1453 lnpcoff = sppcoff + sppcsz;
1454 fp->lnpcoff = lnpcoff;
Rob Pikeed5e39a2008-06-12 14:50:25 -07001455 fp->lnpcsz = lnpcsz;
Rob Pikeed5e39a2008-06-12 14:50:25 -07001456}
1457
Rob Pikeed5e39a2008-06-12 14:50:25 -07001458static uvlong
Russ Cox9aad9fe2008-08-03 17:25:15 -07001459_round(uvlong a, uint32 b)
Rob Pikeed5e39a2008-06-12 14:50:25 -07001460{
1461 uvlong w;
1462
1463 w = (a/b)*b;
1464 if (a!=w)
1465 w += b;
1466 return(w);
1467}