Source code: Bootstrap/BootImage.java
1 // BootImage.java, created Mon Feb 5 23:23:20 2001 by joewhaley
2 // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3 // Licensed under the terms of the GNU LGPL; see COPYING for details.
4 package Bootstrap;
5
6 import java.io.IOException;
7 import java.io.PrintStream;
8 import java.lang.reflect.Array;
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16
17 import Allocator.CodeAllocator;
18 import Allocator.ObjectLayout;
19 import Assembler.x86.Code2CodeReference;
20 import Assembler.x86.Code2HeapReference;
21 import Assembler.x86.DirectBindCall;
22 import Assembler.x86.ExternalReference;
23 import Assembler.x86.Heap2CodeReference;
24 import Assembler.x86.Heap2HeapReference;
25 import Assembler.x86.Reloc;
26 import Clazz.jq_Array;
27 import Clazz.jq_Class;
28 import Clazz.jq_CompiledCode;
29 import Clazz.jq_InstanceField;
30 import Clazz.jq_Member;
31 import Clazz.jq_Method;
32 import Clazz.jq_Primitive;
33 import Clazz.jq_Reference;
34 import Clazz.jq_StaticField;
35 import Clazz.jq_StaticMethod;
36 import Clazz.jq_Type;
37 import Linker.ELF.ELF;
38 import Linker.ELF.ELFConstants;
39 import Linker.ELF.ELFOutput;
40 import Linker.ELF.RelocEntry;
41 import Linker.ELF.Section;
42 import Linker.ELF.SymbolTableEntry;
43 import Main.jq;
44 import Memory.Address;
45 import Memory.CodeAddress;
46 import Memory.HeapAddress;
47 import Run_Time.ExceptionDeliverer;
48 import Run_Time.Reflection;
49 import Run_Time.SystemInterface;
50 import Run_Time.Unsafe;
51 import Scheduler.jq_NativeThread;
52 import Util.Assert;
53 import Util.Strings;
54 import Util.Collections.IdentityHashCodeWrapper;
55 import Util.IO.ExtendedDataOutput;
56
57 /**
58 * BootImage
59 *
60 * @author John Whaley <jwhaley@alum.mit.edu>
61 * @version $Id: BootImage.java,v 1.43 2003/08/10 00:14:39 joewhaley Exp $
62 */
63 public class BootImage implements ELFConstants {
64
65 public static /*final*/ boolean TRACE = false;
66 public static final PrintStream out = System.out;
67
68 public static final BootImage DEFAULT = new BootImage(BootstrapCodeAllocator.DEFAULT);
69
70 private final Map/*<IdentityHashCodeWrapper, Entry>*/ hash;
71 private final ArrayList/*<Entry>*/ entries;
72 private int heapCurrent;
73 private final int startAddress;
74
75 private BootstrapCodeAllocator bca;
76 private List data_relocs;
77
78 public BootImage(BootstrapCodeAllocator bca, int initialCapacity, float loadFactor) {
79 hash = new HashMap(initialCapacity, loadFactor);
80 entries = new ArrayList(initialCapacity);
81 this.bca = bca;
82 this.heapCurrent = this.startAddress = 0;
83 this.data_relocs = new LinkedList();
84 }
85 public BootImage(BootstrapCodeAllocator bca, int initialCapacity) {
86 hash = new HashMap(initialCapacity);
87 entries = new ArrayList(initialCapacity);
88 this.bca = bca;
89 this.heapCurrent = this.startAddress = 0;
90 this.data_relocs = new LinkedList();
91 }
92 public BootImage(BootstrapCodeAllocator bca) {
93 hash = new HashMap();
94 entries = new ArrayList();
95 this.bca = bca;
96 this.heapCurrent = this.startAddress = 0;
97 this.data_relocs = new LinkedList();
98 }
99
100 public final HeapAddress addressOf(Object o) {
101 Assert._assert(!(o instanceof Address));
102 return getOrAllocateObject(o);
103 }
104
105 public final void addCodeReloc(HeapAddress addr, CodeAddress target) {
106 Heap2CodeReference r = new Heap2CodeReference(addr, target);
107 data_relocs.add(r);
108 }
109 public final void addDataReloc(HeapAddress addr, HeapAddress target) {
110 Heap2HeapReference r = new Heap2HeapReference(addr, target);
111 data_relocs.add(r);
112 }
113
114 public final void invokeclinit(jq_Class c) {
115 // call forName on this type to trigger class initialization
116 String cname = c.getName().toString();
117 try {
118 Class.forName(cname);
119 } catch (ClassNotFoundException x) {
120 // bootstrapping jvm can't find the class?
121 System.err.println("ERROR: bootstrapping jvm cannot find class "+cname);
122 Assert.UNREACHABLE();
123 }
124 }
125
126 private boolean alloc_enabled = false;
127
128 public void enableAllocations() { alloc_enabled = true; }
129 public void disableAllocations() { alloc_enabled = false; }
130
131 public HeapAddress getOrAllocateObject(Object o) {
132 if (o == null) return HeapAddress.getNull();
133 //jq.Assert(!(o instanceof Address));
134 IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
135 Entry e = (Entry)hash.get(k);
136 if (e != null) return e.getAddress();
137 // not yet allocated, allocate it.
138 Assert._assert(alloc_enabled);
139 Class objType = o.getClass();
140 jq_Reference type = (jq_Reference)Reflection.getJQType(objType);
141 if (!jq.boot_types.contains(type)) {
142 System.err.println("--> class "+type+" is not in the set of boot types!");
143 //new Exception().printStackTrace();
144 return HeapAddress.getNull();
145 }
146 int addr;
147 int size;
148 if (type.isArrayType()) {
149 addr = heapCurrent + ObjectLayout.ARRAY_HEADER_SIZE;
150 size = ((jq_Array)type).getInstanceSize(Array.getLength(o));
151 size = (size+3) & ~3;
152 if (TRACE)
153 out.println("Allocating entry "+entries.size()+": "+objType+" length "+Array.getLength(o)+" size "+size+" "+Strings.hex(System.identityHashCode(o))+" at "+Strings.hex(addr));
154 } else {
155 Assert._assert(type.isClassType());
156 addr = heapCurrent + ObjectLayout.OBJ_HEADER_SIZE;
157 size = ((jq_Class)type).getInstanceSize();
158 if (TRACE)
159 out.println("Allocating entry "+entries.size()+": "+objType+" size "+size+" "+Strings.hex(System.identityHashCode(o))+" at "+Strings.hex(addr)+((o instanceof jq_Type)?": "+o:""));
160 }
161 heapCurrent += size;
162 BootstrapHeapAddress a = new BootstrapHeapAddress(addr);
163 e = Entry.create(o, a);
164 hash.put(k, e);
165 entries.add(e);
166 return a;
167 }
168
169 public static boolean IGNORE_UNKNOWN_OBJECTS = false;
170
171 public HeapAddress getAddressOf(Object o) {
172 Assert._assert(!(o instanceof Address));
173 if (o == null) return HeapAddress.getNull();
174 IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
175 Entry e = (Entry)hash.get(k);
176 if (e == null) {
177 System.err.println("Unknown object of type: "+o.getClass()+" address: "+Strings.hex(System.identityHashCode(o))+" value: "+o);
178 if (IGNORE_UNKNOWN_OBJECTS) return HeapAddress.getNull();
179 throw new UnknownObjectException(o);
180 }
181 Class objType = o.getClass();
182 jq_Reference type = (jq_Reference)Reflection.getJQType(objType);
183 Assert._assert(type.isClsInitialized(), type.toString());
184 return e.getAddress();
185 }
186
187 public Object getObject(int i) {
188 Entry e = (Entry)entries.get(i);
189 return e.getObject();
190 }
191
192 public void addStaticFieldReloc(jq_StaticField f) {
193 jq_Type ftype = f.getType();
194 if (f.isCodeAddressType()) {
195 CodeAddress addr = (CodeAddress)Reflection.getstatic_P(f);
196 if (addr != null && !addr.isNull()) {
197 if (TRACE) out.println("Adding code reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
198 addCodeReloc(f.getAddress(), addr);
199 }
200 } else if (f.isHeapAddressType()) {
201 HeapAddress addr = (HeapAddress)Reflection.getstatic_P(f);
202 if (addr != null && !addr.isNull()) {
203 if (TRACE) out.println("Adding data reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
204 addDataReloc(f.getAddress(), addr);
205 }
206 } else if (ftype.isReferenceType()) {
207 Object val = Reflection.getstatic_A(f);
208 if (val != null) {
209 if (val instanceof Address) {
210 Assert.UNREACHABLE("Error: "+f+" contains "+((Address)val).stringRep());
211 }
212 HeapAddress addr = HeapAddress.addressOf(val);
213 if (TRACE) out.println("Adding data reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
214 addDataReloc(f.getAddress(), addr);
215 }
216 }
217 }
218
219 public void initStaticField(jq_StaticField f) {
220 jq_Class k = f.getDeclaringClass();
221 jq_Type ftype = f.getType();
222 if (ftype.isPrimitiveType()) {
223 if (ftype == jq_Primitive.INT) {
224 int v = Reflection.getstatic_I(f);
225 k.setStaticData(f, v);
226 } else if (ftype == jq_Primitive.FLOAT) {
227 float v = Reflection.getstatic_F(f);
228 k.setStaticData(f, v);
229 } else if (ftype == jq_Primitive.LONG) {
230 long v = Reflection.getstatic_L(f);
231 k.setStaticData(f, v);
232 } else if (ftype == jq_Primitive.DOUBLE) {
233 double v = Reflection.getstatic_D(f);
234 k.setStaticData(f, v);
235 } else if (ftype == jq_Primitive.BOOLEAN) {
236 int v = Reflection.getstatic_Z(f)?1:0;
237 k.setStaticData(f, v);
238 } else if (ftype == jq_Primitive.BYTE) {
239 byte v = Reflection.getstatic_B(f);
240 k.setStaticData(f, v);
241 } else if (ftype == jq_Primitive.SHORT) {
242 short v = Reflection.getstatic_S(f);
243 k.setStaticData(f, v);
244 } else if (ftype == jq_Primitive.CHAR) {
245 char v = Reflection.getstatic_C(f);
246 k.setStaticData(f, v);
247 } else
248 Assert.UNREACHABLE();
249 } else if (ftype.isAddressType()) {
250 Address addr = Reflection.getstatic_P(f);
251 if (addr == null) addr = HeapAddress.getNull();
252 if (TRACE) out.println("Initializing static field "+f+" to "+addr.stringRep());
253 k.setStaticData(f, addr);
254 } else {
255 Object val = Reflection.getstatic_A(f);
256 HeapAddress addr = HeapAddress.addressOf(val);
257 if (TRACE) out.println("Initializing static field "+f+" to "+addr.stringRep());
258 k.setStaticData(f, addr);
259 }
260 }
261
262 public int numOfEntries() { return entries.size(); }
263
264 public static int UPDATE_PERIOD = 10000;
265
266 public void find_reachable(int i) {
267 for (; i<entries.size(); ++i) {
268 if ((i % UPDATE_PERIOD) == 0) {
269 out.print("Scanning: "+i+"/"+entries.size()+" objects, memory used: "+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())+" \r");
270 }
271 Entry e = (Entry)entries.get(i);
272 Object o = e.getObject();
273 if (o == null) continue;
274 HeapAddress addr = e.getAddress();
275 Assert._assert(!addr.isNull());
276 Class objType = o.getClass();
277 jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
278 if (TRACE)
279 out.println("Entry "+i+": "+objType+" "+Strings.hex(System.identityHashCode(o)));
280 addDataReloc((HeapAddress)addr.offset(ObjectLayout.VTABLE_OFFSET), getOrAllocateObject(jqType));
281 if (jqType.isArrayType()) {
282 jq_Type elemType = ((jq_Array)jqType).getElementType();
283 if (elemType.isAddressType()) {
284 // probably a vtable. skip it -- handled separately.
285 } else if (elemType.isReferenceType()) {
286 int length = Array.getLength(o);
287 Object[] v = (Object[])o;
288 for (int k=0; k<length; ++k) {
289 Object o2 = Reflection.arrayload_A(v, k);
290 if (o2 != null) {
291 addDataReloc((HeapAddress)addr.offset(k*HeapAddress.size()), getOrAllocateObject(o2));
292 }
293 }
294 }
295 } else {
296 Assert._assert(jqType.isClassType());
297 jq_Class clazz = (jq_Class)jqType;
298 jq_InstanceField[] fields = clazz.getInstanceFields();
299 for (int k=0; k<fields.length; ++k) {
300 jq_InstanceField f = fields[k];
301 jq_Type ftype = f.getType();
302 if (f.isCodeAddressType()) {
303 CodeAddress val = (CodeAddress)Reflection.getfield_P(o, f);
304 if (val != null && !val.isNull())
305 addCodeReloc((HeapAddress)addr.offset(f.getOffset()), val);
306 } else if (f.isHeapAddressType()) {
307 HeapAddress val = (HeapAddress)Reflection.getfield_P(o, f);
308 if (val != null && !val.isNull())
309 addDataReloc((HeapAddress)addr.offset(f.getOffset()), val);
310 } else if (f.isStackAddressType()) {
311 // no reloc necessary.
312 } else if (ftype.isReferenceType()) {
313 Object val = Reflection.getfield_A(o, f);
314 if (val != null) {
315 addDataReloc((HeapAddress)addr.offset(f.getOffset()), getOrAllocateObject(val));
316 }
317 }
318 }
319 }
320 }
321 }
322
323 public int size() { return heapCurrent-startAddress; }
324
325 private static class Entry {
326 private Object o; // object in host vm
327 private HeapAddress address; // address in target vm
328 private Entry(Object o, HeapAddress address) { this.o = o; this.address = address; }
329 static Entry create(Object o, HeapAddress address) {
330 Assert._assert(o != null);
331 return new Entry(o, address);
332 }
333 Object getObject() { return o; }
334 HeapAddress getAddress() { return address; }
335 }
336
337 public static final char F_RELFLG = (char)0x0001;
338 public static final char F_EXEC = (char)0x0002;
339 public static final char F_LNNO = (char)0x0004;
340 public static final char F_LSYMS = (char)0x0008;
341 public static final char F_AR32WR = (char)0x0100;
342
343 public void dumpFILHDR(ExtendedDataOutput out, int symptr, int nsyms)
344 throws IOException {
345 // FILHDR
346 out.writeUShort((char)0x014c); // f_magic
347 out.writeUShort((char)2); // f_nscns
348 long ms = System.currentTimeMillis();
349 int s = (int)(ms/1000);
350 out.writeUInt(s); // f_timdat
351 out.writeUInt(symptr); // f_symptr
352 out.writeUInt(nsyms); // f_nsyms
353 out.writeUShort((char)0); // f_opthdr
354 out.writeUShort((char)(F_LNNO | F_LSYMS | F_AR32WR)); // f_flags
355 }
356
357 public static final int STYP_TEXT = 0x00000020;
358 public static final int STYP_DATA = 0x00000040;
359 public static final int STYP_BSS = 0x00000080;
360 public static final int STYP_RELOV = 0x01000000;
361 public static final int STYP_EXEC = 0x20000000;
362 public static final int STYP_READ = 0x40000000;
363 public static final int STYP_WRITE = 0x80000000;
364
365 public void dumpTEXTSCNHDR(ExtendedDataOutput out, int size, int nreloc)
366 throws IOException {
367 // SCNHDR
368 write_bytes(out, ".text", 8); // s_name
369 out.writeUInt(0); // s_paddr
370 out.writeUInt(0); // s_vaddr
371 out.writeUInt(size); // s_size
372 out.writeUInt(20+40+40); // s_scnptr
373 out.writeUInt(20+40+40+size); // s_relptr
374 out.writeUInt(0); // s_lnnoptr
375 if (nreloc > 65535)
376 out.writeUShort((char)0xffff); // s_nreloc
377 else
378 out.writeUShort((char)nreloc); // s_nreloc
379 out.writeUShort((char)0); // s_nlnno
380 if (nreloc > 65535)
381 out.writeUInt(STYP_TEXT | STYP_READ | STYP_WRITE | STYP_RELOV); // s_flags
382 else
383 out.writeUInt(STYP_TEXT | STYP_READ | STYP_WRITE); // s_flags
384 }
385
386 public void dumpDATASCNHDR(ExtendedDataOutput out, int scnptr, int size, int nreloc)
387 throws IOException {
388 // SCNHDR
389 write_bytes(out, ".data", 8); // s_name
390 out.writeUInt(0); // s_paddr
391 out.writeUInt(0); // s_vaddr
392 out.writeUInt(size); // s_size
393 out.writeUInt(scnptr); // s_scnptr
394 out.writeUInt(scnptr+size); // s_relptr
395 out.writeUInt(0); // s_lnnoptr
396 if (nreloc > 65535)
397 out.writeUShort((char)0xffff); // s_nreloc
398 else
399 out.writeUShort((char)nreloc); // s_nreloc
400 out.writeUShort((char)0); // s_nlnno
401 if (nreloc > 65535)
402 out.writeUInt(STYP_DATA | STYP_READ | STYP_WRITE | STYP_RELOV); // s_flags
403 else
404 out.writeUInt(STYP_DATA | STYP_READ | STYP_WRITE); // s_flags
405 }
406
407 public static final char RELOC_ADDR32 = (char)0x0006;
408 public static final char RELOC_REL32 = (char)0x0014;
409
410 public void dumpLINENO(ExtendedDataOutput out, int addr, char lnno)
411 throws IOException {
412 out.writeUInt(addr); // l_symndx / l_paddr
413 out.writeUShort(lnno); // l_lnno
414 }
415
416 public static final short N_UNDEF = 0;
417 public static final short N_ABS = -1;
418 public static final short N_DEBUG = -2;
419
420 public static final char T_NULL = 0x00;
421 public static final char T_VOID = 0x01;
422 public static final char T_CHAR = 0x02;
423 public static final char T_SHORT = 0x03;
424 public static final char T_INT = 0x04;
425 public static final char T_LONG = 0x05;
426 public static final char T_FLOAT = 0x06;
427 public static final char T_DOUBLE = 0x07;
428 public static final char T_STRUCT = 0x08;
429 public static final char T_UNION = 0x09;
430 public static final char T_ENUM = 0x0A;
431 public static final char T_MOE = 0x0B;
432 public static final char T_UCHAR = 0x0C;
433 public static final char T_USHORT = 0x0D;
434 public static final char T_UINT = 0x0E;
435 public static final char T_ULONG = 0x0F;
436 public static final char T_LNGDBL = 0x10;
437
438 public static final char DT_NON = 0x0000;
439 public static final char DT_PTR = 0x0100;
440 public static final char DT_FCN = 0x0200;
441 public static final char DT_ARY = 0x0300;
442
443 public static final byte C_NULL = 0;
444 public static final byte C_AUTO = 1;
445 public static final byte C_EXT = 2;
446 public static final byte C_STAT = 3;
447 public static final byte C_REG = 4;
448 public static final byte C_EXTDEF = 5;
449 public static final byte C_LABEL = 6;
450 public static final byte C_ULABEL = 7;
451 public static final byte C_MOS = 8;
452 public static final byte C_ARG = 9;
453 public static final byte C_STRTAG = 10;
454 public static final byte C_MOU = 11;
455 public static final byte C_UNTAG = 12;
456 public static final byte C_TPDEF = 13;
457 public static final byte C_USTATIC = 14;
458 public static final byte C_ENTAG = 15;
459 public static final byte C_MOE = 16;
460 public static final byte C_REGPARM = 17;
461 public static final byte C_FIELD = 18;
462 public static final byte C_AUTOARG = 19;
463 public static final byte C_LASTENT = 20;
464 public static final byte C_BLOCK = 100;
465 public static final byte C_FCN = 101;
466 public static final byte C_EOS = 102;
467 public static final byte C_FILE = 103;
468 public static final byte C_SECTION = 104;
469 public static final byte C_WEAKEXT = 105;
470 public static final byte C_EFCN = -1;
471
472 public void dumpSECTIONSYMENTs(ExtendedDataOutput out)
473 throws IOException {
474 write_bytes(out, ".text", 8);
475 out.writeUInt(0);
476 out.writeShort((short)1);
477 out.writeUShort((char)0);
478 out.writeUByte(C_STAT);
479 out.writeUByte(0);
480
481 write_bytes(out, ".data", 8);
482 out.writeUInt(0);
483 out.writeShort((short)2);
484 out.writeUShort((char)0);
485 out.writeUByte(C_STAT);
486 out.writeUByte(0);
487 }
488
489 public static boolean USE_MICROSOFT_STYLE_MUNGE = true;
490
491 public static final int NUM_OF_EXTERNAL_SYMS = 7;
492 public void dumpEXTSYMENTs(ExtendedDataOutput out, jq_StaticMethod rootm)
493 throws IOException {
494 // NOTE!!! If you change anything here, be SURE to change the number above!!!
495 String s;
496 if (USE_MICROSOFT_STYLE_MUNGE) s = "_entry@0";
497 else s = "entry";
498 write_bytes(out, s, 8); // s_name
499 CodeAddress addr = rootm.getDefaultCompiledVersion().getEntrypoint();
500 out.writeUInt(addr.to32BitValue());
501 out.writeShort((short)1);
502 out.writeUShort((char)DT_FCN);
503 out.writeUByte(C_EXT);
504 out.writeUByte(0);
505
506 out.writeUInt(0); // e_zeroes
507 if (USE_MICROSOFT_STYLE_MUNGE) s = "_trap_handler@4";
508 else s = "trap_handler";
509 int idx = alloc_string(s);
510 out.writeUInt(idx); // e_offset
511 addr = ExceptionDeliverer._trap_handler.getDefaultCompiledVersion().getEntrypoint();
512 out.writeUInt(addr.to32BitValue());
513 out.writeShort((short)1);
514 out.writeUShort((char)DT_FCN);
515 out.writeUByte(C_EXT);
516 out.writeUByte(0);
517
518 out.writeUInt(0); // e_zeroes
519 if (USE_MICROSOFT_STYLE_MUNGE) s = "_debug_trap_handler@4";
520 else s = "debug_trap_handler";
521 idx = alloc_string(s);
522 out.writeUInt(idx); // e_offset
523 addr = ExceptionDeliverer._debug_trap_handler.getDefaultCompiledVersion().getEntrypoint();
524 out.writeUInt(addr.to32BitValue());
525 out.writeShort((short)1);
526 out.writeUShort((char)DT_FCN);
527 out.writeUByte(C_EXT);
528 out.writeUByte(0);
529
530 out.writeUInt(0); // e_zeroes
531 if (USE_MICROSOFT_STYLE_MUNGE) s = "_threadSwitch@4";
532 else s = "threadSwitch";
533 idx = alloc_string(s);
534 out.writeUInt(idx); // e_offset
535 addr = jq_NativeThread._threadSwitch.getDefaultCompiledVersion().getEntrypoint();
536 out.writeUInt(addr.to32BitValue());
537 out.writeShort((short)1);
538 out.writeUShort((char)DT_FCN);
539 out.writeUByte(C_EXT);
540 out.writeUByte(0);
541
542 out.writeUInt(0); // e_zeroes
543 if (USE_MICROSOFT_STYLE_MUNGE) s = "_ctrl_break_handler@0";
544 else s = "ctrl_break_handler";
545 idx = alloc_string(s);
546 out.writeUInt(idx); // e_offset
547 addr = jq_NativeThread._ctrl_break_handler.getDefaultCompiledVersion().getEntrypoint();
548 out.writeUInt(addr.to32BitValue());
549 out.writeShort((short)1);
550 out.writeUShort((char)DT_FCN);
551 out.writeUByte(C_EXT);
552 out.writeUByte(0);
553
554 out.writeUInt(0); // e_zeroes
555 if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_code_startaddress";
556 else s = "joeq_code_startaddress";
557 idx = alloc_string(s);
558 out.writeUInt(idx); // e_offset
559 out.writeUInt(0);
560 out.writeShort((short)1);
561 out.writeUShort((char)(DT_PTR | T_VOID));
562 out.writeUByte(C_EXT);
563 out.writeUByte(0);
564
565 out.writeUInt(0); // e_zeroes
566 if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_data_startaddress";
567 else s = "joeq_data_startaddress";
568 idx = alloc_string(s);
569 out.writeUInt(idx); // e_offset
570 out.writeUInt(0); // e_value
571 out.writeShort((short)2); // e_scnum
572 out.writeUShort((char)(DT_PTR | T_VOID)); // e_type
573 out.writeUByte(C_EXT); // e_sclass
574 out.writeUByte(0); // e_numaux
575 }
576
577 public void dumpEXTDEFSYMENTs(ExtendedDataOutput out, List extrefs)
578 throws IOException {
579 Iterator i = extrefs.iterator();
580 int k = 2+NUM_OF_EXTERNAL_SYMS;
581 while (i.hasNext()) {
582 ExternalReference extref = (ExternalReference)i.next();
583 Assert._assert(extref.getSymbolIndex() == k);
584 String name = extref.getName();
585 if (name.length() <= 8) {
586 write_bytes(out, name, 8); // s_name
587 } else {
588 out.writeUInt(0); // e_zeroes
589 int idx = alloc_string(name);
590 out.writeUInt(idx); // e_offset
591 }
592 out.writeUInt(0);
593 out.writeShort((short)0);
594 out.writeUShort((char)DT_FCN);
595 out.writeUByte(C_EXT);
596 out.writeUByte(0);
597 ++k;
598 }
599 }
600
601 public void dumpSFIELDSYMENT(ExtendedDataOutput out, jq_StaticField sf)
602 throws IOException {
603 //String name = sf.getName().toString();
604 String name = mungeMemberName(sf);
605 if (name.length() <= 8) {
606 write_bytes(out, name, 8); // s_name
607 } else {
608 out.writeUInt(0); // e_zeroes
609 int idx = alloc_string(name);
610 out.writeUInt(idx); // e_offset
611 }
612 HeapAddress addr = sf.getAddress();
613 out.writeUInt(addr.to32BitValue()); // e_value
614 out.writeShort((short)2); // e_scnum
615 jq_Type t = sf.getType();
616 char type = (char)0;
617 if (t.isArrayType()) {
618 t = ((jq_Array)t).getElementType();
619 type = DT_ARY;
620 } else if (t.isReferenceType()) {
621 type = DT_PTR;
622 }
623 if (t.isPrimitiveType()) {
624 if (t == jq_Primitive.INT) type |= T_LONG;
625 else if (t == jq_Primitive.LONG) type |= T_LNGDBL;
626 else if (t == jq_Primitive.FLOAT) type |= T_FLOAT;
627 else if (t == jq_Primitive.DOUBLE) type |= T_DOUBLE;
628 else if (t == jq_Primitive.BYTE) type |= T_CHAR;
629 else if (t == jq_Primitive.BOOLEAN) type |= T_UCHAR;
630 else if (t == jq_Primitive.SHORT) type |= T_SHORT;
631 else if (t == jq_Primitive.CHAR) type |= T_USHORT;
632 else Assert.UNREACHABLE();
633 } else {
634 type |= T_STRUCT;
635 }
636 out.writeUShort(type); // e_type
637 out.writeUByte(C_STAT); // e_sclass
638 out.writeUByte(0); // e_numaux
639 }
640
641 public void dumpIFIELDSYMENT(ExtendedDataOutput out, jq_InstanceField f)
642 throws IOException {
643 String name = f.getName().toString();
644 if (name.length() <= 8) {
645 write_bytes(out, name, 8); // s_name
646 } else {
647 out.writeUInt(0); // e_zeroes
648 int idx = alloc_string(name);
649 out.writeUInt(idx); // e_offset
650 }
651 int off = f.getOffset();
652 out.writeUInt(off); // e_value
653 out.writeShort((short)2); // e_scnum
654 jq_Type t = f.getType();
655 char type = (char)0;
656 if (t.isArrayType()) {
657 t = ((jq_Array)t).getElementType();
658 type = DT_ARY;
659 } else if (t.isReferenceType()) {
660 type = DT_PTR;
661 }
662 if (t.isPrimitiveType()) {
663 if (t == jq_Primitive.INT) type |= T_LONG;
664 else if (t == jq_Primitive.LONG) type |= T_LNGDBL;
665 else if (t == jq_Primitive.FLOAT) type |= T_FLOAT;
666 else if (t == jq_Primitive.DOUBLE) type |= T_DOUBLE;
667 else if (t == jq_Primitive.BYTE) type |= T_CHAR;
668 else if (t == jq_Primitive.BOOLEAN) type |= T_UCHAR;
669 else if (t == jq_Primitive.SHORT) type |= T_SHORT;
670 else if (t == jq_Primitive.CHAR) type |= T_USHORT;
671 else Assert.UNREACHABLE();
672 } else {
673 type |= T_STRUCT;
674 }
675 out.writeUShort(type); // e_type
676 out.writeUByte(C_MOS); // e_sclass
677 out.writeUByte(0); // e_numaux
678 }
679
680 public void dumpMETHODSYMENT(ExtendedDataOutput out, jq_CompiledCode cc)
681 throws IOException {
682 jq_Method m = cc.getMethod();
683 String name;
684 if (m == null) {
685 name = "unknown@"+cc.getEntrypoint().stringRep();
686 } else {
687 //name = m.getName().toString();
688 name = mungeMemberName(m);
689 }
690 if (name.length() <= 8) {
691 write_bytes(out, name, 8); // s_name
692 } else {
693 out.writeUInt(0); // e_zeroes
694 int idx = alloc_string(name);
695 out.writeUInt(idx); // e_offset
696 }
697 CodeAddress addr = cc.getEntrypoint();
698 out.writeUInt(addr.to32BitValue()); // e_value
699 out.writeShort((short)1); // e_scnum
700 out.writeUShort((char)DT_FCN); // e_type
701 out.writeUByte(C_EXT); // e_sclass
702 out.writeUByte(0); // e_numaux
703 }
704
705 public void addSystemInterfaceRelocs_COFF(List extref, List heap2code) {
706 jq_StaticField[] fs = SystemInterface._class.getDeclaredStaticFields();
707 int total = 1+NUM_OF_EXTERNAL_SYMS;
708 for (int i=0; i<fs.length; ++i) {
709 jq_StaticField f = fs[i];
710 if (f.isFinal()) continue;
711 if (f.getType() != CodeAddress._class) continue;
712 {
713 String name = f.getName().toString();
714 int ind = name.lastIndexOf('_');
715 if (USE_MICROSOFT_STYLE_MUNGE)
716 name = "_"+name.substring(0, ind)+"@"+name.substring(ind+1);
717 else
718 name = name.substring(0, ind);
719 if (TRACE) System.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
720 ExternalReference r = new ExternalReference(f.getAddress(), name);
721 r.setSymbolIndex(++total);
722 extref.add(r);
723 heap2code.add(r);
724 }
725 }
726 //return total-3;
727 }
728
729 public void addSystemInterfaceRelocs_ELF(List extref, List heap2code) {
730 jq_StaticField[] fs = SystemInterface._class.getDeclaredStaticFields();
731 int total = 1+NUM_OF_EXTERNAL_SYMS;
732 for (int i=0; i<fs.length; ++i) {
733 jq_StaticField f = fs[i];
734 if (f.isFinal()) continue;
735 if (f.getType() != CodeAddress._class) continue;
736 {
737 String name = f.getName().toString();
738 int ind = name.lastIndexOf('_');
739 name = name.substring(0, ind);
740 if (TRACE) System.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
741 ExternalReference r = new ExternalReference(f.getAddress(), name);
742 r.setSymbolIndex(++total);
743 extref.add(r);
744 heap2code.add(r);
745 }
746 }
747 }
748
749 public int addVTableRelocs(List list) {
750 int total = 0;
751 Iterator i = jq.boot_types.iterator();
752 while (i.hasNext()) {
753 jq_Type t = (jq_Type)i.next();
754 if (t.isReferenceType()) {
755 if (t == Unsafe._class) continue;
756 try {
757 if (TRACE) System.out.println("Adding vtable relocs for: "+t);
758 Address[] vtable = (Address[])((jq_Reference)t).getVTable();
759 HeapAddress addr = getAddressOf(vtable);
760 //jq.Assert(vtable[0] != 0, t.toString());
761 Heap2HeapReference r1 = new Heap2HeapReference(addr, (HeapAddress) vtable[0]);
762 list.add(r1);
763 for (int j=1; j<vtable.length; ++j) {
764 Heap2CodeReference r2 = new Heap2CodeReference((HeapAddress) addr.offset(CodeAddress.size()*j), (CodeAddress) vtable[j]);
765 list.add(r2);
766 }
767 total += vtable.length;
768 } catch (UnknownObjectException x) {
769 x.appendMessage("vtable for "+t);
770 x.setObject(null);
771 throw x;
772 }
773 }
774 }
775 return total;
776 }
777
778 public void dumpCOFF(ExtendedDataOutput out, jq_StaticMethod rootm) throws IOException {
779
780 final List text_relocs1 = bca.getAllCodeRelocs();
781 final List text_relocs2 = bca.getAllDataRelocs();
782
783 Iterator i = text_relocs1.iterator();
784 while (i.hasNext()) {
785 Object r = i.next();
786 ((Reloc)r).patch();
787 // directly bound calls do not need to be relocated,
788 // because they are relative offsets, not absolute addresses.
789 if (r instanceof DirectBindCall)
790 i.remove();
791 }
792
793 // calculate sizes/offsets
794 final int textsize = bca.size();
795 final List exts = new LinkedList();
796 final int nlinenum = 0;
797 int ntextreloc = text_relocs1.size() + text_relocs2.size();
798 if (ntextreloc > 65535) ++ntextreloc;
799 final int datastart = 20+40+40+textsize+(10*ntextreloc);
800 final int datasize = heapCurrent;
801 final int numOfVTableRelocs = addVTableRelocs(data_relocs);
802 addSystemInterfaceRelocs_COFF(exts, data_relocs);
803 int ndatareloc = data_relocs.size();
804 if (ndatareloc > 65535) ++ndatareloc;
805 final int symtabstart = datastart+datasize+(10*ndatareloc)+(10*nlinenum);
806 final int num_ccs = CodeAllocator.getNumberOfCompiledMethods();
807 final int nsyms = 2+NUM_OF_EXTERNAL_SYMS+num_ccs+exts.size();
808
809 if (TRACE) {
810 System.out.println("Text size="+textsize);
811 System.out.println("Num text relocs="+ntextreloc);
812 System.out.println("Data start="+datastart);
813 System.out.println("Data size="+datasize);
814 System.out.println("Num of VTable relocs="+numOfVTableRelocs);
815 System.out.println("Num data relocs="+ntextreloc);
816 System.out.println("Sym tab start="+symtabstart);
817 System.out.println("Num syms="+nsyms);
818 }
819
820 // write file header
821 dumpFILHDR(out, symtabstart, nsyms);
822
823 // write section headers
824 dumpTEXTSCNHDR(out, textsize, ntextreloc);
825 dumpDATASCNHDR(out, datastart, datasize, ndatareloc);
826
827 // write text section
828 bca.dump(out);
829
830 // write text relocs
831 if (ntextreloc > 65535) {
832 out.writeUInt(ntextreloc);
833 out.writeUInt(0);
834 out.writeUShort((char)0);
835 }
836 Iterator it = text_relocs1.iterator();
837 while (it.hasNext()) {
838 Reloc r = (Reloc)it.next();
839 r.dumpCOFF(out);
840 }
841 it = text_relocs2.iterator();
842 while (it.hasNext()) {
843 Reloc r = (Reloc)it.next();
844 r.dumpCOFF(out);
845 }
846 //out.flush();
847
848 // write data section
849 try {
850 dumpHeap(out);
851 } catch (UnknownObjectException x) {
852 Object u = x.getObject();
853 HashSet visited = new HashSet();
854 findReferencePath(u, x, visited);
855 throw x;
856 }
857
858 // write data relocs
859 int j=0;
860 if (ndatareloc > 65535) {
861 out.writeUInt(ndatareloc);
862 out.writeUInt(0);
863 out.writeUShort((char)0);
864 ++j;
865 }
866 it = data_relocs.iterator();
867 while (it.hasNext()) {
868 if ((j % UPDATE_PERIOD) == 0) {
869 BootImage.out.print("Written: "+j+"/"+ndatareloc+" relocations\r");
870 }
871 Reloc r = (Reloc)it.next();
872 r.dumpCOFF(out);
873 ++j;
874 }
875 BootImage.out.println("Written: "+ndatareloc+" relocations \n");
876 Assert._assert(j == ndatareloc);
877
878 // write line numbers
879
880 // write symbol table
881 dumpSECTIONSYMENTs(out);
882 dumpEXTSYMENTs(out, rootm);
883 dumpEXTDEFSYMENTs(out, exts);
884 it = CodeAllocator.getCompiledMethods();
885 j=0;
886 while (it.hasNext()) {
887 jq_CompiledCode r = (jq_CompiledCode)it.next();
888 dumpMETHODSYMENT(out, r);
889 ++j;
890 }
891 Assert._assert(j == num_ccs);
892
893 // write string table
894 dump_strings(out);
895
896 //out.flush();
897 }
898
899 static class UnknownObjectException extends RuntimeException {
900 Object o; StringBuffer message;
901 UnknownObjectException(Object o) {
902 this.o = o;
903 this.message = new StringBuffer();
904 this.message.append("type: ");
905 this.message.append(o.getClass().toString());
906 this.message.append(" address: ");
907 this.message.append(Strings.hex(System.identityHashCode(o)));
908 this.message.append(' ');
909 }
910 void setObject(Object o) { this.o = o; }
911 Object getObject() { return o; }
912 void prependMessage(String s) {
913 StringBuffer sb = new StringBuffer();
914 sb.append(s);
915 sb.append(this.message);
916 this.message = sb;
917 }
918 void appendMessage(String s) { this.message.append(s); }
919 public String toString() { return this.message.toString(); }
920 }
921
922 private jq_StaticField searchStaticVariables(Object p) {
923 Iterator i = PrimordialClassLoader.loader.getAllTypes().iterator();
924 while (i.hasNext()) {
925 Object o = i.next();
926 if (!(o instanceof jq_Class)) continue;
927 jq_Class k = (jq_Class)o;
928 if (!k.isLoaded()) continue;
929 jq_StaticField[] fs = k.getDeclaredStaticFields();
930 for (int j=0; j<fs.length; ++j) {
931 jq_StaticField f = fs[j];
932 if (f.getType().isAddressType()) {
933 // not a possible path.
934 } else if (f.getType().isReferenceType()) {
935 Object val = Reflection.getstatic_A(f);
936 if (val == p) return f;
937 }
938 }
939 }
940 return null;
941 }
942
943 private boolean findReferencePath(Object p, UnknownObjectException x, HashSet visited) {
944 jq_StaticField sf = searchStaticVariables(p);
945 if (sf != null) {
946 x.appendMessage(sf.getDeclaringClass()+"."+sf.getName());
947 return true;
948 }
949 Iterator i = entries.iterator();
950 while (i.hasNext()) {
951 Entry e = (Entry)i.next();
952 Object o = e.getObject();
953 IdentityHashCodeWrapper w = IdentityHashCodeWrapper.create(o);
954 if (visited.contains(w)) continue;
955 Class objType = o.getClass();
956 jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
957 if (jqType.isArrayType()) {
958 jq_Type elemType = ((jq_Array)jqType).getElementType();
959 if (elemType.isAddressType()) {
960 // not a possible path.
961 } else if (elemType.isReferenceType()) {
962 int length = Array.getLength(o);
963 Object[] v = (Object[])o;
964 for (int k=0; k<length; ++k) {
965 Object o2 = Reflection.arrayload_A(v, k);
966 if (o2 == p) {
967 System.err.println("Possible path: ["+k+"]");
968 visited.add(w);
969 if (findReferencePath(o, x, visited)) {
970 x.appendMessage("["+k+"]");
971 return true;
972 } else {
973 System.err.println("Backtracking ["+k+"]");
974 }
975 }
976 }
977 }
978 } else {
979 Assert._assert(jqType.isClassType());
980 jq_Class clazz = (jq_Class)jqType;
981 jq_InstanceField[] fields = clazz.getInstanceFields();
982 for (int k=0; k<fields.length; ++k) {
983 jq_InstanceField f = fields[k];
984 jq_Type ftype = f.getType();
985 if (ftype.isAddressType()) {
986 // not a possible path.
987 } else if (ftype.isReferenceType()) {
988 Object val = Reflection.getfield_A(o, f);
989 if (val == p) {
990 System.err.println("Possible path: ."+f.getName());
991 visited.add(w);
992 if (findReferencePath(o, x, visited)) {
993 x.appendMessage("."+f.getName());
994 return true;
995 } else {
996 System.err.println("Backtracking ."+f.getName());
997 }
998 }
999 }
1000 }
1001 }
1002 }
1003 return false;
1004 }
1005
1006 private void dumpHeap(ExtendedDataOutput out)
1007 throws IOException {
1008 Assert._assert(ObjectLayout.ARRAY_LENGTH_OFFSET == -12);
1009 Assert._assert(ObjectLayout.STATUS_WORD_OFFSET == -8);
1010 Assert._assert(ObjectLayout.VTABLE_OFFSET == -4);
1011 Assert._assert(ObjectLayout.OBJ_HEADER_SIZE == 8);
1012 Assert._assert(ObjectLayout.ARRAY_HEADER_SIZE == 12);
1013 Iterator i = entries.iterator();
1014 int currentAddr=0;
1015 int j=0;
1016 while (i.hasNext()) {
1017 if ((j % UPDATE_PERIOD) == 0) {
1018 System.out.print("Written: "+j+"/"+entries.size()+" objects, "+currentAddr+"/"+heapCurrent+" bytes\r");
1019 }
1020 Entry e = (Entry)i.next();
1021 Object o = e.getObject();
1022 HeapAddress addr = e.getAddress();
1023 Class objType = o.getClass();
1024 jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
1025 if (TRACE)
1026 BootImage.out.println("Dumping entry "+j+": "+objType+" "+Strings.hex(System.identityHashCode(o))+" addr "+addr.stringRep());
1027 Assert._assert(!jqType.isAddressType());
1028 if (!jqType.isClsInitialized()) {
1029 Assert.UNREACHABLE(jqType.toString());
1030 return;
1031 }
1032 HeapAddress vtable;
1033 try { vtable = getAddressOf(jqType.getVTable()); }
1034 catch (UnknownObjectException x) {
1035 x.appendMessage("vtable for "+jqType);
1036 x.setObject(null);
1037 throw x;
1038 }
1039 if (jqType.isArrayType()) {
1040 while (currentAddr+ObjectLayout.ARRAY_HEADER_SIZE < addr.to32BitValue()) {
1041 out.writeByte((byte)0); ++currentAddr;
1042 }
1043 int length = Array.getLength(o);
1044 out.writeUInt(length);
1045 out.writeUInt(0);
1046 out.writeUInt(vtable.to32BitValue());
1047 currentAddr += ObjectLayout.ARRAY_HEADER_SIZE;
1048 Assert._assert(addr.to32BitValue() == currentAddr);
1049 jq_Type elemType = ((jq_Array)jqType).getElementType();
1050 if (elemType.isPrimitiveType()) {
1051 if (elemType == jq_Primitive.INT) {
1052 int[] v = (int[])o;
1053 for (int k=0; k<length; ++k)
1054 out.writeUInt(v[k]);
1055 currentAddr += length << 2;
1056 } else if (elemType == jq_Primitive.FLOAT) {
1057 float[] v = (float[])o;
1058 for (int k=0; k<length; ++k)
1059 out.writeUInt(Float.floatToRawIntBits(v[k]));
1060 currentAddr += length << 2;
1061 } else if (elemType == jq_Primitive.LONG) {
1062 long[] v = (long[])o;
1063 for (int k=0; k<length; ++k)
1064 out.writeULong(v[k]);
1065 currentAddr += length << 3;
1066 } else if (elemType == jq_Primitive.DOUBLE) {
1067 double[] v = (double[])o;
1068 for (int k=0; k<length; ++k)
1069 out.writeULong(Double.doubleToRawLongBits(v[k]));
1070 currentAddr += length << 3;
1071 } else if (elemType == jq_Primitive.BOOLEAN) {
1072 boolean[] v = (boolean[])o;
1073 for (int k=0; k<length; ++k)
1074 out.writeUByte(v[k]?1:0);
1075 currentAddr += length;
1076 } else if (elemType == jq_Primitive.BYTE) {
1077 byte[] v = (byte[])o;
1078 for (int k=0; k<length; ++k)
1079 out.writeByte(v[k]);
1080 currentAddr += length;
1081 } else if (elemType == jq_Primitive.SHORT) {
1082 short[] v = (short[])o;
1083 for (int k=0; k<length; ++k)
1084 out.writeShort(v[k]);
1085 currentAddr += length << 1;
1086 } else if (elemType == jq_Primitive.CHAR) {
1087 char[] v = (char[])o;
1088 for (int k=0; k<length; ++k)
1089 out.writeUShort(v[k]);
1090 currentAddr += length << 1;
1091 } else Assert.UNREACHABLE();
1092 } else if (elemType.isAddressType()) {
1093 Address[] v = (Address[])o;
1094 for (int k=0; k<length; ++k) {
1095 out.writeUInt(v[k]==null?0:v[k].to32BitValue());
1096 }
1097 currentAddr += length << 2;
1098 } else {
1099 Object[] v = (Object[])o;
1100 for (int k=0; k<length; ++k) {
1101 Object o2 = Reflection.arrayload_A(v, k);
1102 try { out.writeUInt(getAddressOf(o2).to32BitValue()); }
1103 catch (UnknownObjectException x) {
1104 System.err.println("Object array element #"+k);
1105 //x.appendMessage("Object array element #"+k+" in ");
1106 //x.setObject(v);
1107 throw x;
1108 }
1109 }
1110 currentAddr += length << 2;
1111 }
1112 } else {
1113 Assert._assert(jqType.isClassType());
1114 jq_Class clazz = (jq_Class)jqType;
1115 while (currentAddr+ObjectLayout.OBJ_HEADER_SIZE < addr.to32BitValue()) {
1116 out.writeByte((byte)0); ++currentAddr;
1117 }
1118 out.writeUInt(0);
1119 out.writeUInt(vtable.to32BitValue());
1120 currentAddr += 8;
1121 Assert._assert(addr.to32BitValue() == currentAddr);
1122 jq_InstanceField[] fields = clazz.getInstanceFields();
1123 for (int k=0; k<fields.length; ++k) {
1124 jq_InstanceField f = fields[k];
1125 jq_Type ftype = f.getType();
1126 int foffset = f.getOffset();
1127 if (TRACE) BootImage.out.println("Field "+f+" offset "+Strings.shex(foffset)+": "+System.identityHashCode(Reflection.getfield(o, f)));
1128 while (currentAddr != addr.offset(foffset).to32BitValue()) {
1129 out.writeByte((byte)0); ++currentAddr;
1130 }
1131 if (ftype.isPrimitiveType()) {
1132 if (ftype == jq_Primitive.INT)
1133 out.writeUInt(Reflection.getfield_I(o, f));
1134 else if (ftype == jq_Primitive.FLOAT)
1135 out.writeUInt(Float.floatToRawIntBits(Reflection.getfield_F(o, f)));
1136 else if (ftype == jq_Primitive.LONG)
1137 out.writeULong(Reflection.getfield_L(o, f));
1138 else if (ftype == jq_Primitive.DOUBLE)
1139 out.writeULong(Double.doubleToRawLongBits(Reflection.getfield_D(o, f)));
1140 else if (ftype == jq_Primitive.BOOLEAN)
1141 out.writeUByte(Reflection.getfield_Z(o, f)?1:0);
1142 else if (ftype == jq_Primitive.BYTE)
1143 out.writeByte(Reflection.getfield_B(o, f));
1144 else if (ftype == jq_Primitive.SHORT)
1145 out.writeShort(Reflection.getfield_S(o, f));
1146 else if (ftype == jq_Primitive.CHAR)
1147 out.writeUShort(Reflection.getfield_C(o, f));
1148 else Assert.UNREACHABLE();
1149 } else if (ftype.isAddressType()) {
1150 Address a = Reflection.getfield_P(o, f);
1151 out.writeUInt(a==null?0:a.to32BitValue());
1152 } else {
1153 try { out.writeUInt(getAddressOf(Reflection.getfield_A(o, f)).to32BitValue()); }
1154 catch (UnknownObjectException x) {
1155 System.err.println("Instance field "+f);
1156 //x.appendMessage("field "+f.getName()+" in ");
1157 //x.setObject(o);
1158 throw x;
1159 }
1160 }
1161 currentAddr += f.getSize();
1162 }
1163 }
1164 ++j;
1165 }
1166 while (currentAddr < heapCurrent) {
1167 out.writeByte((byte)0); ++currentAddr;
1168 }
1169 System.out.println("Written: "+j+" objects, "+heapCurrent+" bytes ");
1170 }
1171
1172 public static void write_bytes(ExtendedDataOutput out, String s, int len)
1173 throws IOException {
1174 Assert._assert(s.length() <= len);
1175 int i;
1176 for (i=0; ; ++i) {
1177 if (i == s.length()) {
1178 for (; i<len; ++i) {
1179 out.write((byte)0);
1180 }
1181 return;
1182 }
1183 out.write((byte)s.charAt(i));
1184 }
1185 }
1186
1187 private String mungeMemberName(jq_Member m) {
1188 String name = m.getDeclaringClass().getName().toString() +
1189 "_"+m.getName()+
1190 "_"+m.getDesc();
1191 return name;
1192 }
1193
1194 int stringTableOffset = 4;
1195 List stringTable = new LinkedList();
1196 private int alloc_string(String name) {
1197 int off = stringTableOffset;
1198 byte[] b = SystemInterface.toCString(name);
1199 stringTable.add(b);
1200 stringTableOffset += b.length;
1201 return off;
1202 }
1203
1204 private void dump_strings(ExtendedDataOutput out)
1205 throws IOException {
1206 Iterator i = stringTable.iterator();
1207 out.writeUInt(stringTableOffset);
1208 while (i.hasNext()) {
1209 byte[] b = (byte[])i.next();
1210 out.write(b);
1211 }
1212 }
1213
1214
1215 public void dumpELF(ExtendedDataOutput out, jq_StaticMethod rootm) throws IOException {
1216 final List text_relocs1 = bca.getAllCodeRelocs();
1217 final List text_relocs2 = bca.getAllDataRelocs();
1218 Iterator i = text_relocs1.iterator();
1219 while (i.hasNext()) {
1220 Object r = i.next();
1221 ((Reloc)r).patch();
1222 // directly bound calls do not need to be relocated,
1223 // because they are relative offsets, not absolute addresses.
1224 if (r instanceof DirectBindCall)
1225 i.remove();
1226 }
1227
1228 System.out.print("Initializing ELF data structures...");
1229 long time = System.currentTimeMillis();
1230 final int datasize = heapCurrent;
1231 ELFOutput f = new ELFOutput(ELFDATA2LSB, ET_REL, EM_386, 0, out);
1232 f.setLittleEndian();
1233 Section.NullSection empty = Section.NullSection.INSTANCE;
1234 Section.StrTabSection shstrtab = new Section.StrTabSection(".shstrtab", 0, 0);
1235 Section.StrTabSection strtab = new Section.StrTabSection(".strtab", 0, 0);
1236 Section.SymTabSection symtab = new Section.SymTabSection(".symtab", 0, 0, strtab);
1237 Section.ProgBitsSection text = new TextSection();
1238 Section.ProgBitsSection data = new DataSection();
1239 Section.RelSection textrel = new Section.RelSection(".rel.text", 0, 0, symtab, text);
1240 Section.RelSection datarel = new Section.RelSection(".rel.data", 0, 0, symtab, data);
1241 f.setSectionHeaderStringTable(shstrtab);
1242 //f.setSymbolStringTable(strtab);
1243 f.addSection(empty);
1244 f.addSection(shstrtab);
1245 f.addSection(strtab);
1246 f.addSection(symtab);
1247 f.addSection(text);
1248 f.addSection(data);
1249 f.addSection(textrel);
1250 f.addSection(datarel);
1251
1252 final List exts = new LinkedList();
1253 final int numOfVTableRelocs = addVTableRelocs(data_relocs);
1254 addSystemInterfaceRelocs_ELF(exts, data_relocs);
1255
1256 symtab.addSymbol(new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_NOTYPE, empty));
1257
1258 SymbolTableEntry textsyment = new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_SECTION, text);
1259 SymbolTableEntry datasyment = new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_SECTION, data);
1260 symtab.addSymbol(textsyment);
1261 symtab.addSymbol(datasyment);
1262
1263 Iterator it = exts.iterator();
1264 while (it.hasNext()) {
1265 ExternalReference r = (ExternalReference)it.next();
1266 SymbolTableEntry e = new SymbolTableEntry(r.getName(), 0, 0, SymbolTableEntry.STB_GLOBAL, SymbolTableEntry.STT_FUNC, empty);
1267 symtab.addSymbol(e);
1268 datarel.addReloc(new RelocEntry(r.getAddress().to32BitValue(), e, RelocEntry.R_386_32));
1269 }
1270
1271 it = CodeAllocator.getCompiledMethods();
1272 while (it.hasNext()) {
1273 jq_CompiledCode cc = (jq_CompiledCode)it.next();
1274 jq_Method m = cc.getMethod();
1275 String name;
1276 if (m == null) {
1277 name = "unknown@"+cc.getEntrypoint().stringRep();
1278 } else {
1279 name = mungeMemberName(m);
1280 }
1281 SymbolTableEntry e = new SymbolTableEntry(name, cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_LOCAL, STT_FUNC, text);
1282 symtab.addSymbol(e);
1283 }
1284
1285 {
1286 jq_CompiledCode cc = rootm.getDefaultCompiledVersion();
1287 SymbolTableEntry e = new SymbolTableEntry("entry", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1288 symtab.addSymbol(e);
1289
1290 cc = ExceptionDeliverer._trap_handler.getDefaultCompiledVersion();
1291 e = new SymbolTableEntry("trap_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1292 symtab.addSymbol(e);
1293
1294 cc = ExceptionDeliverer._debug_trap_handler.getDefaultCompiledVersion();
1295 e = new SymbolTableEntry("debug_trap_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1296 symtab.addSymbol(e);
1297
1298 cc = jq_NativeThread._threadSwitch.getDefaultCompiledVersion();
1299 e = new SymbolTableEntry("threadSwitch", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1300 symtab.addSymbol(e);
1301
1302 cc = jq_NativeThread._ctrl_break_handler.getDefaultCompiledVersion();
1303 e = new SymbolTableEntry("ctrl_break_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1304 symtab.addSymbol(e);
1305
1306 e = new SymbolTableEntry("joeq_code_startaddress", 0, 0, STB_GLOBAL, STT_OBJECT, text);
1307 symtab.addSymbol(e);
1308
1309 e = new SymbolTableEntry("joeq_data_startaddress", 0, 0, STB_GLOBAL, STT_OBJECT, data);
1310 symtab.addSymbol(e);
1311 }
1312
1313 it = text_relocs1.iterator();
1314 while (it.hasNext()) {
1315 Reloc r = (Reloc)it.next();
1316 if (r instanceof Code2CodeReference) {
1317 Code2CodeReference cr = (Code2CodeReference)r;
1318 textrel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1319 } else {
1320 Assert.UNREACHABLE(r.toString());
1321 }
1322 }
1323
1324 it = text_relocs2.iterator();
1325 while (it.hasNext()) {
1326 Reloc r = (Reloc)it.next();
1327 if (r instanceof Code2HeapReference) {
1328 Code2HeapReference cr = (Code2HeapReference)r;
1329 textrel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1330 } else {
1331 Assert.UNREACHABLE(r.toString());
1332 }
1333 }
1334
1335 it = data_relocs.iterator();
1336 while (it.hasNext()) {
1337 Reloc r = (Reloc)it.next();
1338 if (r instanceof Heap2HeapReference) {
1339 Heap2HeapReference cr = (Heap2HeapReference)r;
1340 datarel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1341 } else if (r instanceof Heap2CodeReference) {
1342 Heap2CodeReference cr = (Heap2CodeReference)r;
1343 datarel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), textsyment, RelocEntry.R_386_32));
1344 } else if (r instanceof ExternalReference) {
1345 // already done.
1346 } else {
1347 Assert.UNREACHABLE(r.toString());
1348 }
1349 }
1350
1351 time = System.currentTimeMillis() - time;
1352 System.out.println("done. ("+(time/1000.)+" seconds)");
1353
1354 f.write();
1355
1356 //out.flush();
1357 }
1358
1359 class TextSection extends Section.ProgBitsSection {
1360 TextSection() {
1361 super(".text", Section.SHF_ALLOC | Section.SHF_EXECINSTR | Section.SHF_WRITE, 0);
1362 }
1363 public int getSize() { return bca.size(); }
1364 public int getAddrAlign() { return 64; }
1365 public void writeData(ELF file) throws IOException {
1366 ExtendedDataOutput out = (ExtendedDataOutput) ((ELFOutput)file).getOutput();
1367 bca.dump(out);
1368 }
1369 public void load(Section.UnloadedSection s, ELF file) throws IOException {
1370 Assert.UNREACHABLE();
1371 }
1372 }
1373
1374 class DataSection extends Section.ProgBitsSection {
1375 DataSection() {
1376 super(".data", Section.SHF_ALLOC | Section.SHF_WRITE, 0);
1377 }
1378 public int getSize() { return heapCurrent; }
1379 public int getAddrAlign() { return 64; }
1380 public void writeData(ELF file) throws IOException {
1381 try {
1382 ExtendedDataOutput out = (ExtendedDataOutput) ((ELFOutput)file).getOutput();
1383 dumpHeap(out);
1384 } catch (UnknownObjectException x) {
1385 Object u = x.getObject();
1386 HashSet visited = new HashSet();
1387 findReferencePath(u, x, visited);
1388 throw x;
1389 }
1390 }
1391 public void load(Section.UnloadedSection s, ELF file) throws IOException {
1392 Assert.UNREACHABLE();
1393 }
1394 }
1395
1396 public static final jq_StaticField _DEFAULT;
1397 static {
1398 jq_Class k = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("LBootstrap/BootImage;");
1399 _DEFAULT = k.getOrCreateStaticField("DEFAULT", "LBootstrap/BootImage;");
1400 }
1401
1402}