1
2
3
4
5 package org.xwt.imp;
6
7 import java.io.*;
8
9 public class MIPSInterpreter extends MIPSEmu {
10
11
12 private int[] registers = new int[32];
13 private intinthilo
14
15
16 private int[] fpregs = new int[32];
17
18
19
20
21
22
23
24
25 private int fcsr;
26
27 private int nextPC;
28
29
30 private String image;
31
32
33 private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }
34 private final int roundingMode() { return fcsr & 3; }
35 private final double getDouble(int r) {
36 return Double.longBitsToDouble(((fpregs[r+1]&0xffffffffL) << 32) | (fpregs[r]&0xffffffffL));
37 }
38 private final void setDouble(int r, double d) {
39 long l = Double.doubleToLongBits(d);
40 fpregs[r+1] = (int)(l >>> 32); fpregs[r] = (int)l;
41 }
42 private final float getFloat(int r) { return Float.intBitsToFloat(fpregs[r]); }
43 private final void setFloat(int r, float f) { fpregs[r] = Float.floatToRawIntBits(f); }
44
45
46 public void execute() throws EmulationException {
47 int[] r = registers;
48 if(state == PAUSED) state = RUNNING;
49 if(state != RUNNING) throw new IllegalStateException("execute() called in inappropriate state");
50 runSome(nextPC);
51 }
52
53
54
55 private int runSome(int pc) throws FaultException,EmulationException {
56 int[] r = registers;
57 int[] f = fpregs;
58 int nextPC = pc + 4;
59 try {
60 OUTER: for(;;) {
61 int insn;
62 try {
63 insn = readPages[pc>>>PAGE_SHIFT][(pc>>>2)&PAGE_WORDS-1];
64 } catch (RuntimeException e) {
65 insn = memRead(pc);
66 }
67
68 int op = (insn >>> 26) & 0xff;
69 int rs = (insn >>> 21) & 0x1f;
70 int rt = (insn >>> 16) & 0x1f;
71 int ft = (insn >>> 16) & 0x1f;
72 int rd = (insn >>> 11) & 0x1f;
73 int fs = (insn >>> 11) & 0x1f;
74 int shamt = (insn >>> 6) & 0x1f;
75 int fd = (insn >>> 6) & 0x1f;
76 int subcode = insn & 0x3f;
77
78 int jumpTarget = (insn & 0x03ffffff);
79 int unsignedImmediate = insn & 0xffff;
80 int signedImmediate = (insn << 16) >> 16;
81 int branchTarget = signedImmediate;
82
83 intintp, addr;
84
85 r[ZERO] = 0;
86
87 switch(op) {
88 case 0: {
89 switch(subcode) {
90 case 0:
91 if(insn == 0) break;
92 r[rd] = r[rt] << shamt;
93 break;
94 case 2:
95 r[rd] = r[rt] >>> shamt;
96 break;
97 case 3:
98 r[rd] = r[rt] >> shamt;
99 break;
100
101 case 4:
102 r[rd] = r[rt] << r[rs];
103 break;
104 case 6:
105 r[rd] = r[rt] >>> r[rs];
106 break;
107 case 7:
108 r[rd] = r[rt] >> r[rs];
109 break;
110 case 8:
111 tmp = r[rs]; pc += 4; nextPC = tmp;
112 continue OUTER;
113 case 9:
114 tmp = r[rs]; pc += 4; r[rd] = pc+4; nextPC = tmp;
115 continue OUTER;
116 case 12:
117 r[V0] = syscall(r[V0],r[A0],r[A1],r[A2],r[A3]);
118 if(state != RUNNING) {
119 this.nextPC = nextPC;
120 break OUTER;
121 }
122 break;
123 case 13:
124 throw new EmulationException("Break");
125 case 16:
126 r[rd] = hi;
127 break;
128 case 17:
129 hi = r[rs];
130 break;
131 case 18:
132 r[rd] = lo;
133 break;
134 case 19:
135 lo = r[rs];
136 break;
137 case 24: {
138 long hilo = (long)(r[rs]) * ((long)r[rt]);
139 hi = (int) (hilo >>> 32);
140 lo = (int) hilo;
141 break;
142 }
143 case 25: {
144 long hilo = (r[rs] & 0xffffffffL) * (r[rt] & 0xffffffffL);
145 hi = (int) (hilo >>> 32);
146 lo = (int) hilo;
147 break;
148 }
149 case 26:
150 hi = r[rs]%r[rt];
151 lo = r[rs]/r[rt];
152 break;
153 case 27:
154 hi = (int)((r[rs] & 0xffffffffL) % (r[rt] & 0xffffffffL));
155 lo = (int)((r[rs] & 0xffffffffL) / (r[rt] & 0xffffffffL));
156 break;
157 case 32:
158 r[rd] = r[rs] + r[rt];
159 break;
160 case 33:
161 r[rd] = r[rs] + r[rt];
162 break;
163 case 34:
164 r[rd] = r[rs] - r[rt];
165 break;
166 case 35:
167 r[rd] = r[rs] - r[rt];
168 break;
169 case 36:
170 r[rd] = r[rs] & r[rt];
171 break;
172 case 37:
173 r[rd] = r[rs] | r[rt];
174 break;
175 case 38:
176 r[rd] = r[rs] ^ r[rt];
177 break;
178 case 39:
179 r[rd] = ~(r[rs] | r[rt]);
180 break;
181 case 42:
182 r[rd] = r[rs] < r[rt] ? 1 : 0;
183 break;
184 case 43:
185 r[rd] = ((r[rs] & 0xffffffffL) < (r[rt] & 0xffffffffL)) ? 1 : 0;
186 break;
187 default:
188 throw new EmulationException("Illegal instruction 0/" + subcode);
189 }
190 break;
191 }
192 case 1: {
193 switch(rt) {
194 case 0:
195 if(r[rs] < 0) {
196 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
197 continue OUTER;
198 }
199 break;
200 case 1:
201 if(r[rs] >= 0) {
202 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
203 continue OUTER;
204 }
205 break;
206 case 16:
207 if(r[rs] < 0) {
208 pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
209 continue OUTER;
210 }
211 break;
212 case 17:
213 if(r[rs] >= 0) {
214 pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
215 continue OUTER;
216 }
217 break;
218 default:
219 throw new EmulationException("Illegal Instruction");
220 }
221 break;
222 }
223 case 2: {
224 tmp = (pc&0xf0000000) | (jumpTarget << 2);
225 pc+=4; nextPC = tmp;
226 continue OUTER;
227 }
228 case 3: {
229 tmp = (pc&0xf0000000) | (jumpTarget << 2);
230 pc+=4; r[RA] = pc+4; nextPC = tmp;
231 continue OUTER;
232 }
233 case 4:
234 if(r[rs] == r[rt]) {
235 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
236 continue OUTER;
237 }
238 break;
239 case 5:
240 if(r[rs] != r[rt]) {
241 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
242 continue OUTER;
243 }
244 break;
245 case 6:
246 if(r[rs] <= 0) {
247 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
248 continue OUTER;
249 }
250 break;
251 case 7:
252 if(r[rs] > 0) {
253 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
254 continue OUTER;
255 }
256 break;
257 case 8:
258 r[rt] = r[rs] + signedImmediate;
259 break;
260 case 9:
261 r[rt] = r[rs] + signedImmediate;
262 break;
263 case 10:
264 r[rt] = r[rs] < signedImmediate ? 1 : 0;
265 break;
266 case 11:
267 r[rt] = (r[rs]&0xffffffffL) < (unsignedImmediate&0xffffffffL) ? 1 : 0;
268 break;
269 case 12:
270 r[rt] = r[rs] & unsignedImmediate;
271 break;
272 case 13:
273 r[rt] = r[rs] | unsignedImmediate;
274 break;
275 case 14:
276 r[rt] = r[rs] ^ unsignedImmediate;
277 break;
278 case 15:
279 r[rt] = unsignedImmediate << 16;
280 break;
281 case 16:
282 throw new EmulationException("TLB/Exception support not implemented");
283 case 17: {
284 boolean debug = false;
285 String line = debug ? sourceLine(pc) : "";
286 boolean debugon = debug && (line.indexOf("dtoa.c:51") >= 0 || line.indexOf("dtoa.c:52") >= 0 || line.indexOf("test.c") >= 0);
287 if(rs > 8 && debugon)
288 System.out.println(" FP Op: " + op + "/" + rs + "/" + subcode + " " + line);
289
290 if(roundingMode() != 0 && rs != 6 && !((rs==16 || rs==17) && subcode == 36 ))
291 throw new EmulationException("Non-cvt.w.z operation attempted with roundingMode != round to nearest");
292 switch(rs) {
293 case 0:
294 r[rt] = f[rd];
295 break;
296 case 2:
297 if(fs != 31) throw new EmulationException("FCR " + fs + " unavailable");
298 r[rt] = fcsr;
299 break;
300 case 4:
301 f[rd] = r[rt];
302 break;
303 case 6:
304 if(fs != 31) throw new EmulationException("FCR " + fs + " unavailable");
305 fcsr = r[rt];
306 break;
307 case 8:
308 if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) {
309 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
310 continue OUTER;
311 }
312 break;
313 case 16: {
314 switch(subcode) {
315 case 0:
316 setFloat(fd,getFloat(fs)+getFloat(ft));
317 break;
318 case 1:
319 setFloat(fd,getFloat(fs)-getFloat(ft));
320 break;
321 case 2:
322 setFloat(fd,getFloat(fs)*getFloat(ft));
323 break;
324 case 3:
325 setFloat(fd,getFloat(fs)/getFloat(ft));
326 break;
327 case 5:
328 setFloat(fd,Math.abs(getFloat(fs)));
329 break;
330 case 6:
331 f[fd] = f[fs];
332 break;
333 case 7:
334 setFloat(fd,-getFloat(fs));
335 break;
336 case 33:
337 setDouble(fd,getFloat(fs));
338 break;
339 case 36:
340 switch(roundingMode()) {
341 case 0: f[fd] = (int)Math.floor(getFloat(fs)+0.5f); break;
342 case 1: f[fd] = (int)getFloat(fs); break;
343 case 2: f[fd] = (int)Math.ceil(getFloat(fs)); break;
344 case 3: f[fd] = (int)Math.floor(getFloat(fs)); break;
345 }
346 break;
347 case -50:
348 setFC(getFloat(fs) == getFloat(ft));
349 break;
350 case 60:
351 setFC(getFloat(fs) < getFloat(ft));
352 break;
353 default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
354 }
355 break;
356 }
357 case 17: {
358 switch(subcode) {
359 case 0:
360 setDouble(fd,getDouble(fs)+getDouble(ft));
361 break;
362 case 1:
363 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") - f" + ft + " (" + getDouble(ft) + ")");
364 setDouble(fd,getDouble(fs)-getDouble(ft));
365 break;
366 case 2:
367 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") * f" + ft + " (" + getDouble(ft) + ")");
368 setDouble(fd,getDouble(fs)*getDouble(ft));
369 if(debugon) System.out.println("f" + fd + " = " + getDouble(fd));
370 break;
371 case 3:
372 setDouble(fd,getDouble(fs)/getDouble(ft));
373 break;
374 case 5:
375 setDouble(fd,Math.abs(getDouble(fs)));
376 break;
377 case 6:
378 f[fd] = f[fs];
379 f[fd+1] = f[fs+1];
380 break;
381 case 7:
382 setDouble(fd,-getDouble(fs));
383 break;
384 case 32:
385 setFloat(fd,(float)getDouble(fs));
386 break;
387 case 36:
388 if(debugon) System.out.println("CVT.W.D rm: " + roundingMode() + " f" + fs + ":" + getDouble(fs));
389 switch(roundingMode()) {
390 case 0: f[fd] = (int)Math.floor(getDouble(fs)+0.5); break;
391 case 1: f[fd] = (int)getDouble(fs); break;
392 case 2: f[fd] = (int)Math.ceil(getDouble(fs)); break;
393 case 3: f[fd] = (int)Math.floor(getDouble(fs)); break;
394 }
395 if(debugon) System.out.println("CVT.W.D: f" + fd + ":" + f[fd]);
396 break;
397 case 50:
398 setFC(getDouble(fs) == getDouble(ft));
399 break;
400 case 60:
401 setFC(getDouble(fs) < getDouble(ft));
402 break;
403 case 62:
404 setFC(getDouble(fs) <= getDouble(ft));
405 break;
406 default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
407 }
408 break;
409 }
410 case 20: {
411 switch(subcode) {
412 case 33:
413 setDouble(fd,(double)f[fs]);
414 break;
415 default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
416 }
417 break;
418 }
419 default:
420 throw new EmulationException("Invalid Instruction 17/" + rs);
421 }
422 break;
423 }
424 case 18: case 19:
425 throw new EmulationException("No coprocessor installed");
426 case 32: {
427 addr = r[rs] + signedImmediate;
428 try {
429 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
430 } catch(RuntimeException e) {
431 tmp = memRead(addr&~3);
432 }
433 switch(addr&3) {
434 case 0: tmp = (tmp>>>24)&0xff; break;
435 case 1: tmp = (tmp>>>16)&0xff; break;
436 case 2: tmp = (tmp>>> 8)&0xff; break;
437 case 3: tmp = (tmp>>> 0)&0xff; break;
438 }
439 if((tmp&0x80)!=0) tmp |= 0xffffff00;
440 r[rt] = tmp;
441 break;
442 }
443 case 33: {
444 addr = r[rs] + signedImmediate;
445 try {
446 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
447 } catch(RuntimeException e) {
448 tmp = memRead(addr&~3);
449 }
450 switch(addr&2) {
451 case 0: tmp = (tmp>>>16)&0xffff; break;
452 case 2: tmp = (tmp>>> 0)&0xffff; break;
453 }
454 if((tmp&0x8000)!=0) tmp |= 0xffff0000;
455 r[rt] = tmp;
456 break;
457 }
458 case 34: {
459 addr = r[rs] + signedImmediate;
460 try {
461 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
462 } catch(RuntimeException e) {
463 tmp = memRead(addr&~3);
464 }
465 switch(addr&3) {
466 case 0: r[rt] = (r[rt]&0x00000000)|(tmp<< 0); break;
467 case 1: r[rt] = (r[rt]&0x000000ff)|(tmp<< 8); break;
468 case 2: r[rt] = (r[rt]&0x0000ffff)|(tmp<<16); break;
469 case 3: r[rt] = (r[rt]&0x00ffffff)|(tmp<<24); break;
470 }
471 break;
472 }
473 case 35:
474 addr = r[rs] + signedImmediate;
475 try {
476 r[rt] = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
477 } catch(RuntimeException e) {
478 r[rt] = memRead(addr);
479 }
480 break;
481 case 36: {
482 addr = r[rs] + signedImmediate;
483 try {
484 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
485 } catch(RuntimeException e) {
486 tmp = memRead(addr);
487 }
488 switch(addr&3) {
489 case 0: r[rt] = (tmp>>>24)&0xff; break;
490 case 1: r[rt] = (tmp>>>16)&0xff; break;
491 case 2: r[rt] = (tmp>>> 8)&0xff; break;
492 case 3: r[rt] = (tmp>>> 0)&0xff; break;
493 }
494 break;
495 }
496 case 37: {
497 addr = r[rs] + signedImmediate;
498 try {
499 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
500 } catch(RuntimeException e) {
501 tmp = memRead(addr&~3);
502 }
503 switch(addr&2) {
504 case 0: r[rt] = (tmp>>>16)&0xffff; break;
505 case 2: r[rt] = (tmp>>> 0)&0xffff; break;
506 }
507 break;
508 }
509 case 38: {
510 addr = r[rs] + signedImmediate;
511 try {
512 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
513 } catch(RuntimeException e) {
514 tmp = memRead(addr&~3);
515 }
516 switch(addr&3) {
517 case 0: r[rt] = (r[rt]&0xffffff00)|(tmp>>>24); break;
518 case 1: r[rt] = (r[rt]&0xffff0000)|(tmp>>>16); break;
519 case 2: r[rt] = (r[rt]&0xff000000)|(tmp>>> 8); break;
520 case 3: r[rt] = (r[rt]&0x00000000)|(tmp>>> 0); break;
521 }
522 break;
523 }
524 case 40: {
525 addr = r[rs] + signedImmediate;
526 try {
527 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
528 } catch(RuntimeException e) {
529 tmp = memRead(addr&~3);
530 }
531 switch(addr&3) {
532 case 0: tmp = (tmp&0x00ffffff) | ((r[rt]&0xff)<<24); break;
533 case 1: tmp = (tmp&0xff00ffff) | ((r[rt]&0xff)<<16); break;
534 case 2: tmp = (tmp&0xffff00ff) | ((r[rt]&0xff)<< 8); break;
535 case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break;
536 }
537 try {
538 writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = tmp;
539 } catch(RuntimeException e) {
540 memWrite(addr&~3,tmp);
541 }
542 break;
543 }
544 case 41: {
545 addr = r[rs] + signedImmediate;
546 try {
547 tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
548 } catch(RuntimeException e) {
549 tmp = memRead(addr&~3);
550 }
551 switch(addr&2) {
552 case 0: tmp = (tmp&0x0000ffff) | ((r[rt]&0xffff)<<16); break;
553 case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break;
554 }
555 try {
556 writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = tmp;
557 } catch(RuntimeException e) {
558 memWrite(addr&~3,tmp);
559 }
560 break;
561 }
562 case 42: {
563 addr = r[rs] + signedImmediate;
564 tmp = memRead(addr&~3);
565 switch(addr&3) {
566 case 0: tmp=(tmp&0x00000000)|(r[rt]>>> 0); break;
567 case 1: tmp=(tmp&0xff000000)|(r[rt]>>> 8); break;
568 case 2: tmp=(tmp&0xffff0000)|(r[rt]>>>16); break;
569 case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break;
570 }
571 try {
572 writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = tmp;
573 } catch(RuntimeException e) {
574 memWrite(addr&~3,tmp);
575 }
576 break;
577 }
578 case 43:
579 addr = r[rs] + signedImmediate;
580 try {
581 writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = r[rt];
582 } catch(RuntimeException e) {
583 memWrite(addr&~3,r[rt]);
584 }
585 break;
586 case 46: {
587 addr = r[rs] + signedImmediate;
588 tmp = memRead(addr&~3);
589 switch(addr&3) {
590 case 0: tmp=(tmp&0x00ffffff)|(r[rt]<<24); break;
591 case 1: tmp=(tmp&0x0000ffff)|(r[rt]<<16); break;
592 case 2: tmp=(tmp&0x000000ff)|(r[rt]<< 8); break;
593 case 3: tmp=(tmp&0x00000000)|(r[rt]<< 0); break;
594 }
595 memWrite(addr&~3,tmp);
596 break;
597 }
598 case 49:
599 f[rt] = memRead(r[rs] + signedImmediate);
600 break;
601 case 57:
602 memWrite(r[rs] + signedImmediate,f[rt]);
603 break;
604 default:
605 throw new EmulationException("Invalid Instruction: " + op);
606 }
607 pc = nextPC;
608 nextPC = pc + 4;
609 }
610 } catch(EmulationException e) {
611 this.nextPC = pc;
612 throw e;
613 }
614 return 0;
615 }
616
617
618 void loadImage(String file) throws IOException {
619 ELF elf = new ELF(file);
620 if(elf.header.type != ELF.ELFHeader.ET_EXEC)
621 throw new IOException("Binary is not an executable");
622 if(elf.header.machine != ELF.ELFHeader.EM_MIPS)
623 throw new IOException("Binary is not for the MIPS I Architecture");
624 entryPoint = elf.header.entry;
625 ELF.PHeader[] pheaders = elf.pheaders;
626 brk = 0;
627 for(int i=0;i<pheaders.length;i++) {
628 ELF.PHeader ph = pheaders[i];
629 if(ph.type != ELF.PHeader.PT_LOAD) continue;
630 int memsize = ph.memsz;
631 int filesize = ph.filesz;
632 if(memsize == 0) continue;
633 if(memsize < 0) throw new IOException("pheader size too large");
634 int addr = ph.vaddr;
635 if(addr == 0x0) throw new IOException("pheader vaddr == 0x0");
636 if(addr+memsize >= (brk<<PAGE_SHIFT)) brk = (addr+memsize+PAGE_SIZE-1) >> PAGE_SHIFT;
637
638 for(int j=0;j<memsize+PAGE_SIZE-1;j+=PAGE_SIZE) {
639 int page = (j+addr) >>> PAGE_SHIFT;
640 if(readPages[page] == null)
641 readPages[page] = new int[PAGE_WORDS];
642 if(ph.writable()) writePages[page] = readPages[page];
643 }
644 if(filesize != 0) {
645 filesize = filesize & ~3;
646 DataInputStream dis = new DataInputStream(ph.getInputStream());
647 do {
648 readPages[addr >>> PAGE_SHIFT][(addr >>> 2)&(PAGE_WORDS-1)] = dis.readInt();
649 addr+=4;
650 filesize-=4;
651 } while(filesize > 0);
652 dis.close();
653 }
654 }
655 image = file;
656 state = INITIALIZED;
657 }
658
659 protected void _start(int pc) {
660 registers[SP] = INITIAL_SP;
661 registers[RA] = 0xdeadbeef;
662 nextPC = pc;
663 }
664 public MIPSInterpreter() { }
665 public MIPSInterpreter(String image) throws IOException { loadImage(image); }
666
667
668
669 public String sourceLine(int pc) {
670 final String addr2line = "mips-unknown-elf-addr2line";
671 String line;
672 if(image==null) return null;
673 try {
674 Process p = Runtime.getRuntime().exec(new String[]{addr2line,"-e",image,toHex(pc)});
675 line = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();
676 if(line == null) return null;
677 while(line.startsWith("../")) line = line.substring(3);
678 return line;
679 } catch(IOException e) {
680 return null;
681 }
682 }
683
684 public class DebugShutdownHook implements Runnable {
685 public void run() {
686 int pc = nextPC;
687 if(getState() == RUNNING)
688 System.err.print("\nCPU Executing " + toHex(pc) + ": " + sourceLine(pc) + "\n");
689 }
690 }
691
692 public static void main(String[] argv) throws Exception {
693 String image = argv[0];
694 MIPSInterpreter emu = new MIPSInterpreter();
695 emu.loadImage(image);
696 Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook()));
697
698 int addr = emu.sbrk(PAGE_SIZE);
699 for(int i=0;i<10;i++) {
700 String s = "User Info item: " + (i+1) + "\0";
701 byte[] b = s.getBytes("US-ASCII");
702 emu.copyout(b,addr,b.length);
703 emu.setUserInfo(i,addr);
704 addr += b.length;
705 }
706
707 int status = emu.run(argv);
708 System.err.println("Exit status: " + status);
709 System.exit(status);
710 }
711 }
712
713 abstract class MIPSEmu implements Syscalls, Errno {
714
715 protected final static int ZERO = 0;
716 protected final static int AT = 1;
717 protected final static int K0 = 26;
718 protected final static int K1 = 27;
719 protected final static int GP = 28;
720 protected final static int SP = 29;
721 protected final static int FP = 30;
722 protected final static int RA = 31;
723
724
725 protected final static int V0 = 2;
726 protected final static int V1 = 3;
727
728 protected final static int A0 = 4;
729 protected final static int A1 = 5;
730 protected final static int A2 = 6;
731 protected final static int A3 = 7;
732
733 protected final static int T0 = 8;
734 protected final static int T1 = 9;
735 protected final static int T2 = 10;
736 protected final static int T3 = 11;
737 protected final static int T4 = 12;
738 protected final static int T5 = 13;
739 protected final static int T6 = 14;
740 protected final static int T7 = 15;
741 protected final static int T8 = 24;
742 protected final static int T9 = 25;
743
744 protected final static int S0 = 16;
745 protected final static int S1 = 17;
746 protected final static int S2 = 18;
747 protected final static int S3 = 19;
748 protected final static int S4 = 20;
749 protected final static int S5 = 21;
750 protected final static int S6 = 22;
751 protected final static int S7 = 23;
752
753
754
755
756
757
758 protected final static int PAGE_SIZE = 4096;
759 protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2);
760 protected final static int PAGE_SHIFT = 12;
761 protected final static int STACK_PAGES = 256;
762
763
764 protected final static int TOTAL_PAGES = 65536;
765 protected final static int BRK_LIMIT = 32768;
766
767
768 protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE;
769
770 protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE;
771
772 protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE;
773
774 private final static int[] emptyPage = new int[0];
775
776
777 protected final int[][] readPages;
778 protected final int[][] writePages;
779
780
781 protected int brk;
782
783
784 protected int entryPoint;
785
786
787 public final static int UNINITIALIZED = 0;
788 public final static int INITIALIZED = 1;
789 public final static int RUNNING = 2;
790 public final static int PAUSED = 3;
791 public final static int DONE = 4;
792
793
794 protected int state = UNINITIALIZED;
795 public final int getState() { return state; }
796 protected int exitStatus;
797
798
799 private final static int OPEN_MAX = 256;
800 private FileDescriptor[] fds;
801
802
803 private byte[] _byteBuf = null;
804 private final static int MAX_CHUNK = 4*1024*1024-8;
805
806
807
808 public abstract void execute() throws EmulationException;
809
810 protected abstract void _start(int pc);
811
812 public static final int PID = 1;
813
814 public MIPSEmu() {
815 readPages = new int[TOTAL_PAGES][];
816 writePages = new int[TOTAL_PAGES][];
817 for(int i=0;i<STACK_PAGES;i++)
818 readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
819 }
820
821 public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
822 int n=0;
823 if((addr&3)!=0) {
824 int word = memRead(addr&~3);
825 switch(addr&3) {
826 case 1: a[n++] = (byte)((word>>>16)&0xff); if(length-n==0) break;
827 case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break;
828 case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break;
829 }
830 addr = (addr&~3)+4;
831 }
832 while(length-n > 3) {
833 int start = (addr&(PAGE_SIZE-1))>>2;
834 int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
835 int[] page = readPages[addr >>> PAGE_SHIFT];
836 if(page == null) throw new ReadFaultException(addr);
837 if(page == emptyPage) { addr+=(end-start); n+=(end-start); continue; }
838 for(int i=start;i<end;i++,addr+=4) {
839 int word = page[i];
840 a[n++] = (byte)((word>>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff);
841 a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff);
842 }
843 }
844 if(length-n > 0) {
845 int word = memRead(addr);
846 if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff);
847 if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff);
848 if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff);
849 }
850 }
851
852 public void copyout(byte[] a, int addr, int length) throws FaultException {
853 int n=0;
854 if((addr&3)!=0) {
855 int word = memRead(addr&~3);
856 switch(addr&3) {
857 case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break;
858 case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break;
859 case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break;
860 }
861 memWrite(addr&~3,word);
862 addr = (addr&~3)+4;
863 }
864
865 while(length-n > 3) {
866 int start = (addr&(PAGE_SIZE-1))>>2;
867 int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
868 int[] page = writePages[addr >>> PAGE_SHIFT];
869 if(page == null) throw new WriteFaultException(addr);
870 if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; }
871 for(int i=start;i<end;i++,addr+=4) {
872 int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
873 page[i] = word;
874 }
875 }
876 if(length-n > 0) {
877 int word = memRead(addr);
878 word = (word&0x00ffffff)|((a[n]&0xff)<<24);
879 if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); }
880 if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); }
881 memWrite(addr,word);
882 }
883 }
884
885 protected final int memRead(int addr) throws ReadFaultException {
886 if((addr & 3) != 0) throw new ReadFaultException(addr);
887 int page = addr >>> PAGE_SHIFT;
888 int entry = (addr >>> 2) & (PAGE_WORDS-1);
889 try {
890 return readPages[page][entry];
891 } catch(ArrayIndexOutOfBoundsException e) {
892 if(page < 0) throw e;
893 if(page > readPages.length) throw new ReadFaultException(addr);
894 if(readPages[page] != emptyPage) throw e;
895 initPage(page);
896 return 0;
897 } catch(NullPointerException e) {
898 throw new ReadFaultException(addr);
899 }
900 }
901
902 protected final void memWrite(int addr, int value) throws WriteFaultException {
903 if((addr & 3) != 0) throw new WriteFaultException(addr);
904 int page = addr >>> PAGE_SHIFT;
905 int entry = (addr>>>2)&(PAGE_WORDS-1);
906 try {
907 writePages[page][entry] = value;
908 } catch(ArrayIndexOutOfBoundsException e) {
909 if(page < 0) throw e;
910 if(page > writePages.length) throw new WriteFaultException(addr);
911 if(readPages[page] != emptyPage) throw e;
912 initPage(page);
913 writePages[page][entry] = value;
914 } catch(NullPointerException e) {
915 throw new WriteFaultException(addr);
916 }
917 }
918
919 protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; }
920
921 public final int exitStatus() {
922 if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state");
923 return exitStatus;
924 }
925
926 public final int run(String[] args) throws EmulationException {
927 start(args);
928 for(;;) {
929 execute();
930 if(state != PAUSED) break;
931 System.err.println("WARNING: Pause requested while executing run()");
932 try { Thread.sleep(500); } catch(InterruptedException e) { }
933 }
934 if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state");
935 return exitStatus();
936 }
937
938 private void addArgs(String[] args) throws EmulationException {
939 if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state");
940 int count = args.length;
941 byte[] nullTerminator = new byte[1];
942 int total = 4;
943 for(int i=0;i<count;i++) total += args[i].length() + 1 + 4;
944 if(total > PAGE_SIZE) throw new EmulationException("Arguments too large");
945 int start = ARGS_ADDR;
946 int addr = start + (count+1)*4;
947 int[] table = new int[count+1];
948 for(int i=0;i<count;i++) {
949 byte[] a;
950 try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw new Error(e.getMessage()); }
951 table[i] = addr;
952
953 copyout(a,addr,a.length);
954 addr += a.length;
955 copyout(nullTerminator,addr,1);
956 addr += 1;
957
958 }
959 addr=start;
960 for(int i=0;i<count;i++) {
961 memWrite(addr,table[i]);
962 addr += 4;
963 }
964 }
965
966 public void setUserInfo(int index, int word) throws EmulationException {
967 if(index < 0 || index >= 1024) throw new EmulationException("setUserInfo called with index >= 1024");
968 memWrite(USER_INFO_ADDR+index*4,word);
969 }
970
971 public int getUserInfo(int index) throws EmulationException {
972 if(index < 0 || index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024");
973 return memRead(USER_INFO_ADDR+index*4);
974 }
975
976 public final void start(String[] args) throws EmulationException {
977 if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state");
978 _start(entryPoint);
979 addArgs(args);
980 fds = new FileDescriptor[OPEN_MAX];
981 fds[0] = new InputStreamFD(System.in) { public boolean isatty() { return true; } };
982 fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } };
983 fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } };
984 state = PAUSED;
985 }
986
987
988
989 private int write(int fdn, int addr, int count) {
990 int n = 0;
991 int r;
992 FileDescriptor fd;
993 count = Math.min(count,MAX_CHUNK);
994 try {
995 fd = fds[fdn];
996 if(fd == null || !fd.writable()) return -EBADFD;
997 } catch(ArrayIndexOutOfBoundsException e) {
998 return -EBADFD;
999 }
1000 try {
1001 byte[] buf = byteBuf(count);
1002 copyin(addr,buf,count);
1003 return fd.write(buf,0,count);
1004 } catch(FaultException e) {
1005 System.err.println(e);
1006 return -EFAULT;
1007 } catch(IOException e) {
1008 System.err.println(e);
1009 return -EIO;
1010 }
1011 }
1012
1013 private int read(int fdn, int addr, int count) {
1014 FileDescriptor fd;
1015 count = Math.min(count,MAX_CHUNK);
1016 try {
1017 fd = fds[fdn];
1018 if(fd == null || !fd.readable()) return -EBADFD;
1019 } catch(ArrayIndexOutOfBoundsException e) {
1020 return -EBADFD;
1021 }
1022 try {
1023 byte[] buf = byteBuf(count);
1024 int n = fd.read(buf,0,count);
1025 copyout(buf,addr,n);
1026 return n;
1027 } catch(FaultException e) {
1028 System.err.println(e);
1029 return -EFAULT;
1030 } catch(IOException e) {
1031 System.err.println(e);
1032 return -EIO;
1033 }
1034 }
1035
1036 private int close(int fdn) {
1037 FileDescriptor fd;
1038 try {
1039 fd = fds[fdn];
1040 if(fd == null) return -EBADFD;
1041 } catch(ArrayIndexOutOfBoundsException e) {
1042 return -EBADFD;
1043 }
1044 fds[fdn] = null;
1045 fd.close();
1046 return 0;
1047 }
1048
1049 private int stat(FileInfo fi, int addr) {
1050 int size = fi.size();
1051 try {
1052 memWrite(addr+0,0);
1053 memWrite(addr+4,(fi.type() & 0xf000)|0644);
1054 memWrite(addr+8,1);
1055 memWrite(addr+12,0);
1056 memWrite(addr+16,size);
1057 memWrite(addr+20,0);
1058
1059 memWrite(addr+28,(int)(fi.modTime()/1000));
1060
1061 memWrite(addr+36,0);
1062
1063 memWrite(addr+44,512);
1064 memWrite(addr+48,(size+511)&(~511));
1065
1066
1067 } catch(FaultException e) {
1068 System.err.println(e);
1069 return -EFAULT;
1070 }
1071 return 0;
1072 }
1073
1074 private int fstat(int fdn, int addr) {
1075 FileDescriptor fd;
1076 try {
1077 fd = fds[fdn];
1078 if(fd == null) return -EBADFD;
1079 } catch(ArrayIndexOutOfBoundsException e) {
1080 return -EBADFD;
1081 }
1082 return stat(fd.fileInfo(),addr);
1083 }
1084
1085 public int sbrk(int incr) {
1086 if(incr==0) return brk<<PAGE_SHIFT;
1087 int oldBrk = brk;
1088 int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
1089 if(newBrk >= BRK_LIMIT) {
1090 System.err.println("Hit BRK_LIMIT");
1091 return -ENOMEM;
1092 }
1093 for(int i=oldBrk;i<newBrk+256;i++)
1094 readPages[i] = writePages[i] = emptyPage;
1095 brk = newBrk;
1096 return oldBrk<<PAGE_SHIFT;
1097 }
1098
1099 private int open(int addr, int flags, int mode) {
1100 final int O_RDONLY = 0;
1101 final int O_WRONLY = 1;
1102 final int O_RDWR = 2;
1103 final int O_APPEND = 0x0008;
1104 final int O_CREAT = 0x0200;
1105 final int O_NONBLOCK = 0x4000;
1106 final int O_EXCL = 0x0800;
1107
1108 if((flags & O_APPEND) != 0) {
1109 System.err.println("WARNING: O_APPEND not supported");
1110 return -EOPNOTSUPP;
1111 }
1112 if((flags & O_NONBLOCK) != 0) {
1113 System.err.println("WARNING: O_NONBLOCK not supported");
1114 return -EOPNOTSUPP;
1115 }
1116
1117 try {
1118 int fdn=-1;
1119 File f = new File(cstring(addr));
1120 System.err.println("Opening: " + f);
1121 if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
1122 if(!f.createNewFile()) return -EEXIST;
1123 if(f.exists()) {
1124 if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
1125 } else {
1126 if((flags & O_CREAT) == 0) return -ENOENT;
1127 }
1128 for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
1129 if(fdn==-1) return -ENFILE;
1130 fds[fdn] = new RegularFileDescriptor(f,flags&3);
1131 return fdn;
1132 } catch(FaultException e) {
1133 return -EFAULT;
1134 } catch(FileNotFoundException e) {
1135 if(e.getMessage().indexOf("Permission denied") >= 0) return -EACCES;
1136 return -ENOENT;
1137 } catch(IOException e) {
1138 return -EIO;
1139 }
1140 }
1141
1142 private int seek(int fdn, int offset, int whence) {
1143 FileDescriptor fd;
1144 try {
1145 fd = fds[fdn];
1146 if(fd == null || !fd.readable()) return -EBADFD;
1147 } catch(ArrayIndexOutOfBoundsException e) {
1148 return -EBADFD;
1149 }
1150 try {
1151 return fd.seek(offset,whence);
1152 } catch(IOException e) {
1153 System.err.println(e);
1154 return -EPIPE;
1155 }
1156 }
1157
1158
1159
1160 private int kill(int pid, int signal) {
1161 if(pid != PID) return -ESRCH;
1162 if(signal < 0 || signal >= 32) return -EINVAL;
1163 switch(signal) {
1164 case 0: return 0;
1165 case 17:
1166 case 18:
1167 case 21:
1168 case 22:
1169 state = PAUSED;
1170 break;
1171 case 19:
1172 case 20:
1173 case 23:
1174 case 28:
1175 break;
1176 default: {
1177 String msg = "Terminating on signal: " + signal + "\n";
1178 exitStatus = 1;
1179 state = DONE;
1180 if(fds[2]==null) {
1181 System.out.print(msg);
1182 } else {
1183 byte[] b = msg.getBytes();
1184 try {
1185 fds[2].write(b,0,b.length);
1186 } catch(IOException e) { }
1187 }
1188 }
1189 }
1190 return 0;
1191 }
1192
1193 private int getpid() { return PID; }
1194
1195 protected int syscall(int syscall, int a, int b, int c, int d) {
1196 switch(syscall) {
1197 case SYS_null: return 0;
1198 case SYS_exit: exitStatus = a; state = DONE; return 0;
1199 case SYS_pause: state = PAUSED; return 0;
1200 case SYS_write: return write(a,b,c);
1201 case SYS_fstat: return fstat(a,b);
1202 case SYS_sbrk: return sbrk(a);
1203 case SYS_open: return open(a,b,c);
1204 case SYS_close: return close(a);
1205 case SYS_read: return read(a,b,c);
1206 case SYS_seek: return seek(a,b,c);
1207 case SYS_kill: return kill(a,b);
1208 case SYS_getpid: return getpid();
1209 default:
1210 System.err.println("Attempted to use unknown syscall: " + syscall);
1211 return -ENOSYS;
1212 }
1213 }
1214
1215
1216 private String cstring(int addr) throws ReadFaultException {
1217 StringBuffer sb = new StringBuffer();
1218 for(;;) {
1219 int word = memRead(addr&~3);
1220 switch(addr&3) {
1221 case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++;
1222 case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++;
1223 case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++;
1224 case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++;
1225 }
1226 }
1227 }
1228
1229
1230 public static class ReadFaultException extends FaultException {
1231 public ReadFaultException(int addr) { super(addr); }
1232 }
1233 public static class WriteFaultException extends FaultException {
1234 public WriteFaultException(int addr) { super(addr); }
1235 }
1236 public static abstract class FaultException extends EmulationException {
1237 private int addr;
1238 public FaultException(int addr) { this.addr = addr; }
1239 public String getMessage() { return "fault at: " + toHex(addr); }
1240 }
1241 public static class EmulationException extends Exception {
1242 public EmulationException() { }
1243 public EmulationException(String s) { super(s); }
1244 }
1245
1246
1247 static class FileInfo {
1248 public static final int S_IFIFO = 0010000;
1249 public static final int S_FCHR = 0020000;
1250 public static final int S_IFDIR = 0040000;
1251 public static final int S_IFREG = 0100000;
1252
1253 public int size() { return 0; }
1254 public int type() { return S_IFIFO; }
1255 public long modTime() { return 0; }
1256 }
1257
1258 public static class FileFileInfo extends FileInfo {
1259 public File f;
1260 public FileFileInfo(File f) { this.f = f; }
1261 public int size() { return (int)f.length(); }
1262 public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; }
1263 public long modTime() { return f.lastModified(); }
1264 }
1265
1266
1267 public static abstract class FileDescriptor {
1268 public boolean readable() { return false; }
1269 public boolean writable() { return false; }
1270
1271 private static final FileInfo nullFi = new FileInfo();
1272 private FileInfo fi;
1273 public FileInfo fileInfo() { return fi; }
1274
1275 FileDescriptor() { this(null); }
1276 FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; }
1277
1278 public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
1279 public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
1280
1281 public int seek(int n, int whence) throws IOException { return -ESPIPE; }
1282 public boolean isatty() { return false; }
1283
1284 void close() { }
1285 }
1286
1287 public static class RegularFileDescriptor extends FileDescriptor {
1288 private int mode;
1289 private RandomAccessFile raf;
1290 public boolean readable() { return mode != 1; }
1291 public boolean writable() { return mode != 0; }
1292
1293 RegularFileDescriptor(File f,int m) throws IOException {
1294 super(new FileFileInfo(f));
1295 String mode = m == 0 ? "r" : "rw";
1296 this.mode = m;
1297 raf = new RandomAccessFile(f,mode);
1298 if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large");
1299 }
1300
1301 public int seek(int n, int whence) throws IOException {
1302 final int SEEK_SET = 0;
1303 final int SEEK_CUR = 1;
1304 final int SEEK_END = 2;
1305
1306 switch(whence) {
1307 case SEEK_SET: break;
1308 case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break;
1309 case SEEK_END: n = (int)(raf.length()+n); break;
1310 default: return -EINVAL;
1311 }
1312 raf.seek(n);
1313 return n;
1314 }
1315
1316 public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; }
1317 public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; }
1318
1319 void close() { try { raf.close(); } catch(Exception e) { } }
1320 }
1321
1322 public class OutputStreamFD extends FileDescriptor {
1323 private OutputStream os;
1324 public boolean writable() { return true; }
1325 public OutputStreamFD(OutputStream os) { this.os = os; }
1326 public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; }
1327 }
1328
1329 public class InputStreamFD extends FileDescriptor {
1330 private InputStream is;
1331 public boolean readable() { return true; }
1332 public InputStreamFD(InputStream is) { this.is = is; }
1333 public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; }
1334 }
1335
1336
1337 private byte[] byteBuf(int size) {
1338 if(_byteBuf==null) _byteBuf = new byte[size];
1339 else if(_byteBuf.length < size)
1340 _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)];
1341 return _byteBuf;
1342 }
1343 protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1344 protected final static int min(int a, int b) { return a < b ? a : b; }
1345 protected final static int max(int a, int b) { return a > b ? a : b; }
1346 }
1347
1348 class ELF {
1349 private MyRandomAccessFile fd;
1350
1351 public ELFHeader header;
1352 public PHeader[] pheaders;
1353 public SHeader[] sheaders;
1354
1355 private boolean sectionReaderActive;
1356
1357 public class ELFHeader {
1358 byte klass;
1359 byte data;
1360 byte osabi;
1361 byte abiversion;
1362
1363 public static final short ET_EXEC = 2;
1364 public short type;
1365 public static final short EM_MIPS = 8;
1366 public short machine;
1367 public int version;
1368 public int entry;
1369 public int phoff;
1370 public int shoff;
1371 public int flags;
1372 public short ehsize;
1373 public short phentsize;
1374 public short phnum;
1375 public short shentsize;
1376 public short shnum;
1377 public short shstrndx;
1378
1379 private static final int ELF_MAGIC = 0x7f454c46;
1380 ELFHeader() throws IOException {
1381 if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " );
1382 klass = fd.readByte();
1383 data = fd.readByte();
1384 fd.skipFully(1);
1385 osabi = fd.readByte();
1386 abiversion = fd.readByte();
1387 fd.skipFully(7);
1388 type = fd.readShort();
1389 machine = fd.readShort();
1390 version = fd.readInt();
1391 entry = fd.readInt();
1392 phoff = fd.readInt();
1393 shoff = fd.readInt();
1394 flags = fd.readInt();
1395 ehsize = fd.readShort();
1396 phentsize = fd.readShort();
1397 phnum = fd.readShort();
1398 shentsize = fd.readShort();
1399 shnum = fd.readShort();
1400 shstrndx = fd.readShort();
1401 }
1402 }
1403
1404 public class PHeader {
1405 public int type;
1406 public int offset;
1407 public int vaddr;
1408 public int paddr;
1409 public int filesz;
1410 public int memsz;
1411 public int flags;
1412 public int align;
1413
1414 public static final int PF_X = 0x1;
1415 public static final int PF_W = 0x2;
1416 public static final int PF_R = 0x4;
1417
1418 public static final int PT_LOAD = 1;
1419
1420 PHeader() throws IOException {
1421 type = fd.readInt();
1422 offset = fd.readInt();
1423 vaddr = fd.readInt();
1424 paddr = fd.readInt();
1425 filesz = fd.readInt();
1426 memsz = fd.readInt();
1427 flags = fd.readInt();
1428 align = fd.readInt();
1429 if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz");
1430 }
1431
1432 public boolean writable() { return (flags & PF_W) != 0; }
1433
1434 public InputStream getInputStream() throws IOException {
1435 return new BufferedInputStream(new SectionInputStream(
1436 offset,offset+filesz));
1437 }
1438 }
1439
1440 public class SHeader {
1441 int nameidx;
1442 public String name;
1443 public int type;
1444 public int flags;
1445 public int addr;
1446 public int offset;
1447 public int size;
1448 public int link;
1449 public int info;
1450 public int addralign;
1451 public int entsize;
1452
1453 public static final int T_NOBITS = 8;
1454
1455 SHeader() throws IOException {
1456 nameidx = fd.readInt();
1457 type = fd.readInt();
1458 flags = fd.readInt();
1459 addr = fd.readInt();
1460 offset = fd.readInt();
1461 size = fd.readInt();
1462 link = fd.readInt();
1463 info = fd.readInt();
1464 addralign = fd.readInt();
1465 entsize = fd.readInt();
1466 }
1467
1468 public InputStream getInputStream() throws IOException {
1469 return new BufferedInputStream(new SectionInputStream(
1470 offset, type == T_NOBITS ? 0 : offset+size));
1471 }
1472 }
1473
1474 public ELF(String file) throws IOException, ELFException {
1475 fd = new MyRandomAccessFile(file,"r");
1476 header = new ELFHeader();
1477 pheaders = new PHeader[header.phnum];
1478 for(int i=0;i<header.phnum;i++) {
1479 fd.seek(header.phoff+i*header.phentsize);
1480 pheaders[i] = new PHeader();
1481 }
1482 sheaders = new SHeader[header.shnum];
1483 for(int i=0;i<header.shnum;i++) {
1484 fd.seek(header.shoff+i*header.shentsize);
1485 sheaders[i] = new SHeader();
1486 }
1487 if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
1488 fd.seek(sheaders[header.shstrndx].offset);
1489 byte[] a = new byte[sheaders[header.shstrndx].size];
1490 fd.readFully(a);
1491 for(int i=0;i<header.shnum;i++) {
1492 SHeader s = sheaders[i];
1493 StringBuffer sb = new StringBuffer();
1494 for(int off = s.nameidx;off < a.length && a[off] != 0; off++) sb.append((char)a[off]);
1495 s.name = sb.toString();
1496 }
1497 }
1498
1499 public SHeader sectionWithName(String name) {
1500 for(int i=0;i<sheaders.length;i++)
1501 if(sheaders[i].name.equals(name))
1502 return sheaders[i];
1503 return null;
1504 }
1505
1506 public class ELFException extends IOException { ELFException(String s) { super(s); } }
1507
1508 private class MyRandomAccessFile extends RandomAccessFile {
1509 MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
1510 public void skipFully(int n) throws IOException {
1511 while(n>0) n-= skipBytes(n);
1512 }
1513 }
1514
1515 private class SectionInputStream extends InputStream {
1516 private int pos;
1517 private int maxpos;
1518 SectionInputStream(int start, int end) throws IOException {
1519 if(sectionReaderActive)
1520 throw new IOException("Section reader already active");
1521 sectionReaderActive = true;
1522 pos = start;
1523 fd.seek(pos);
1524 maxpos = end;
1525 }
1526
1527 private int bytesLeft() { return maxpos - pos; }
1528 public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.read(); if(b >= 0) pos++; return b; }
1529 public int read(byte[] b, int off, int len) throws IOException {
1530 int n = fd.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n;
1531 }
1532 public void close() { sectionReaderActive = false; }
1533 }
1534
1535 private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1536
1537 public static void main(String[] args) throws IOException {
1538 ELF elf = new ELF(args[0]);
1539 System.out.println("Type: " + toHex(elf.header.type));
1540 System.out.println("Machine: " + toHex(elf.header.machine));
1541 for(int i=0;i<elf.pheaders.length;i++) {
1542 ELF.PHeader ph = elf.pheaders[i];
1543 System.out.println("PHeader " + toHex(i));
1544 System.out.println("\tOffset: " + ph.offset);
1545 System.out.println("\tVaddr: " + toHex(ph.vaddr));
1546 System.out.println("\tFile Size: " + ph.filesz);
1547 System.out.println("\tMem Size: " + ph.memsz);
1548 }
1549 for(int i=0;i<elf.sheaders.length;i++) {
1550 ELF.SHeader sh = elf.sheaders[i];
1551 System.out.println("SHeader " + toHex(i));
1552 System.out.println("\tName: " + sh.name);
1553 System.out.println("\tOffset: " + sh.offset);
1554 System.out.println("\tAddr: " + toHex(sh.addr));
1555 System.out.println("\tSize: " + sh.size);
1556 System.out.println("\tType: " + toHex(sh.type));
1557 }
1558 }
1559 }
1560 interface Errno {
1561 public static final int EPERM = 1;
1562 public static final int ENOENT = 2;
1563 public static final int ESRCH = 3;
1564 public static final int EINTR = 4;
1565 public static final int EIO = 5;
1566 public static final int ENXIO = 6;
1567 public static final int ENOEXEC = 8;
1568 public static final int EBADF = 9;
1569 public static final int ECHILD = 10;
1570 public static final int EAGAIN = 11;
1571 public static final int ENOMEM = 12;
1572 public static final int EACCES = 13;
1573 public static final int EFAULT = 14;
1574 public static final int ENOTBLK = 15;
1575 public static final int EBUSY = 16;
1576 public static final int EEXIST = 17;
1577 public static final int EXDEV = 18;
1578 public static final int ENODEV = 19;
1579 public static final int ENOTDIR = 20;
1580 public static final int EISDIR = 21;
1581 public static final int EINVAL = 22;
1582 public static final int ENFILE = 23;
1583 public static final int EMFILE = 24;
1584 public static final int ENOTTY = 25;
1585 public static final int ETXTBSY = 26;
1586 public static final int EFBIG = 27;
1587 public static final int ENOSPC = 28;
1588 public static final int ESPIPE = 29;
1589 public static final int EROFS = 30;
1590 public static final int EMLINK = 31;
1591 public static final int EPIPE = 32;
1592 public static final int EDOM = 33;
1593 public static final int ERANGE = 34;
1594 public static final int ENOMSG = 35;
1595 public static final int EIDRM = 36;
1596 public static final int ECHRNG = 37;
1597 public static final int ELNRNG = 41;
1598 public static final int EUNATCH = 42;
1599 public static final int ENOCSI = 43;
1600 public static final int EDEADLK = 45;
1601 public static final int ENOLCK = 46;
1602 public static final int EBADE = 50;
1603 public static final int EBADR = 51;
1604 public static final int EXFULL = 52;
1605 public static final int ENOANO = 53;
1606 public static final int EBADRQC = 54;
1607 public static final int EBADSLT = 55;
1608 public static final int EDEADLOCK = 56;
1609 public static final int EBFONT = 57;
1610 public static final int ENOSTR = 60;
1611 public static final int ENODATA = 61;
1612 public static final int ETIME = 62;
1613 public static final int ENOSR = 63;
1614 public static final int ENONET = 64;
1615 public static final int ENOPKG = 65;
1616 public static final int EREMOTE = 66;
1617 public static final int ENOLINK = 67;
1618 public static final int EADV = 68;
1619 public static final int ESRMNT = 69;
1620 public static final int ECOMM = 70;
1621 public static final int EPROTO = 71;
1622 public static final int EMULTIHOP = 74;
1623 public static final int ELBIN = 75;
1624 public static final int EDOTDOT = 76;
1625 public static final int EBADMSG = 77;
1626 public static final int EFTYPE = 79;
1627 public static final int ENOTUNIQ = 80;
1628 public static final int EBADFD = 81;
1629 public static final int EREMCHG = 82;
1630 public static final int ELIBACC = 83;
1631 public static final int ELIBBAD = 84;
1632 public static final int ELIBSCN = 85;
1633 public static final int ELIBMAX = 86;
1634 public static final int ELIBEXEC = 87;
1635 public static final int ENOSYS = 88;
1636 public static final int ENMFILE = 89;
1637 public static final int ENOTEMPTY = 90;
1638 public static final int ENAMETOOLONG = 91;
1639 public static final int ELOOP = 92;
1640 public static final int EOPNOTSUPP = 95;
1641 public static final int EPFNOSUPPORT = 96;
1642 public static final int ECONNRESET = 104;
1643 public static final int ENOBUFS = 105;
1644 public static final int EAFNOSUPPORT = 106;
1645 public static final int EPROTOTYPE = 107;
1646 public static final int ENOTSOCK = 108;
1647 public static final int ENOPROTOOPT = 109;
1648 public static final int ESHUTDOWN = 110;
1649 public static final int ECONNREFUSED = 111;
1650 public static final int EADDRINUSE = 112;
1651 public static final int ECONNABORTED = 113;
1652 public static final int ENETUNREACH = 114;
1653 public static final int ENETDOWN = 115;
1654 public static final int ETIMEDOUT = 116;
1655 public static final int EHOSTDOWN = 117;
1656 public static final int EHOSTUNREACH = 118;
1657 public static final int EINPROGRESS = 119;
1658 public static final int EALREADY = 120;
1659 public static final int EDESTADDRREQ = 121;
1660 public static final int EMSGSIZE = 122;
1661 public static final int EPROTONOSUPPORT = 123;
1662 public static final int ESOCKTNOSUPPORT = 124;
1663 public static final int EADDRNOTAVAIL = 125;
1664 public static final int ENETRESET = 126;
1665 public static final int EISCONN = 127;
1666 public static final int ENOTCONN = 128;
1667 public static final int ETOOMANYREFS = 129;
1668 public static final int EPROCLIM = 130;
1669 public static final int EUSERS = 131;
1670 public static final int EDQUOT = 132;
1671 public static final int ESTALE = 133;
1672 public static final int ENOTSUP = 134;
1673 public static final int ENOMEDIUM = 135;
1674 public static final int ENOSHARE = 136;
1675 public static final int ECASECLASH = 137;
1676 public static final int EILSEQ = 138;
1677 public static final int EOVERFLOW = 139;
1678 public static final int __ELASTERROR = 2000;
1679 }
1680 interface Syscalls {
1681 public static final int SYS_null = 0;
1682 public static final int SYS_exit = 1;
1683 public static final int SYS_pause = 2;
1684 public static final int SYS_open = 3;
1685 public static final int SYS_close = 4;
1686 public static final int SYS_read = 5;
1687 public static final int SYS_write = 6;
1688 public static final int SYS_sbrk = 7;
1689 public static final int SYS_fstat = 8;
1690 public static final int SYS_isatty = 9;
1691 public static final int SYS_seek = 10;
1692 public static final int SYS_kill = 11;
1693 public static final int SYS_getpid = 12;
1694 }
1695