/[rvvs89]/uvm/core/loader.c


UCC Code Repository

Contents of /uvm/core/loader.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 355 - (show annotations) (download)
Mon Mar 1 08:05:23 2010 UTC (11 years, 9 months ago) by rvvs89
File MIME type: text/plain
File size: 17522 byte(s)
Syncing to work on netbook.
1 /*
2 * File: loader.c
3 * Author: Rufus Garton Smith
4 *
5 * Primordial Java classloader.
6 *
7 * $Id$
8 * Created on 20 February 2010, 6:50 PM
9 */
10
11 #include <stdint.h>
12 #include <stdlib.h>
13 /* FIXME: remove me */
14 #include <stdio.h>
15 #include "loader.h"
16 #include "uvm.h"
17
18 #define MAGIC (0xCAFEBABE)
19
20 #define CONSTANT_Unknown 0
21 #define CONSTANT_Utf8 1
22 #define CONSTANT_Continued 2
23 #define CONSTANT_Integer 3
24 #define CONSTANT_Float 4
25 #define CONSTANT_Long 5
26 #define CONSTANT_Double 6
27 #define CONSTANT_Class 7
28 #define CONSTANT_String 8
29 #define CONSTANT_Fieldref 9
30 #define CONSTANT_Methodref 10
31 #define CONSTANT_InterfaceMethodref 11
32 #define CONSTANT_NameAndType 12
33
34 #define ACC_PUBLIC (0x0001) /* class, field, method */
35 #define ACC_PRIVATE (0x0002) /* field, method */
36 #define ACC_PROTECTED (0x0004) /* field, method */
37 #define ACC_STATIC (0x0008) /* field, method */
38 #define ACC_FINAL (0x0010) /* class, field, method */
39 #define ACC_SUPER (0x0020) /* class */
40 #define ACC_SYNCHRONIZED (0x0020) /* method */
41 #define ACC_VOLATILE (0x0040) /* field */
42 #define ACC_TRANSIENT (0x0080) /* field */
43 #define ACC_NATIVE (0x0100) /* method */
44 #define ACC_INTERFACE (0x0200) /* class */
45 #define ACC_ABSTRACT (0x0400) /* class, method */
46 #define ACC_STRICT (0x0800) /* method */
47 #define ACC_SYNTHETIC (0x1000) /* field */
48
49 #define ACC_CLASS_MASK (ACC_PUBLIC | ACC_FINAL | ACC_SUPER |\
50 ACC_INTERFACE | ACC_ABSTRACT)
51 #define ACC_FIELD_MASK (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |\
52 ACC_STATIC | ACC_FINAL | ACC_VOLATILE |\
53 ACC_TRANSIENT)
54 #define ACC_METHOD_MASK (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |\
55 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |\
56 ACC_NATIVE | ACC_ABSTRACT | ACC_STATIC)
57
58 #define UTF_UPPER_0_MASK (0x00)
59 #define UTF_UPPER_1_MASK (0x80)
60 #define UTF_UPPER_2_MASK (0xC0)
61 #define UTF_UPPER_3_MASK (0xE0)
62 #define UTF_UPPER_4_MASK (0xF0)
63
64 struct cp_ref {
65 uint16_t ref1;
66 uint16_t ref2;
67 };
68
69 union cp_data {
70 uint32_t data;
71 uint16_t index;
72 struct cp_ref ref;
73 uint8_t *utf8;
74 };
75
76 struct field {
77 uint16_t access;
78 uint16_t name;
79 uint16_t descriptor;
80 uint16_t constant;
81 };
82
83 struct class {
84 uint16_t cp_count;
85 uint8_t *cp_tag;
86 union cp_data *cp_info;
87 uint16_t access;
88 uint16_t this;
89 uint16_t super;
90 uint16_t iface_count;
91 uint16_t *iface;
92 uint16_t field_count;
93 struct field *field;
94 };
95
96 /* FIXME: remove me */
97 static void uvm_dump_class(struct class *class);
98
99 static int uvm_load_magic(struct binput *in) {
100 int status;
101 uint32_t magic;
102
103 if (status = in->read4(in, &magic))
104 return status;
105 return magic == MAGIC ? 0 : UVME_MAGIC;
106 }
107
108 static int uvm_load_version(struct binput *in) {
109 int status;
110 uint16_t minor, major;
111
112 if (status = in->read2(in, &minor))
113 return status;
114 if (status = in->read2(in, &major))
115 return status;
116 /* TODO: check class version values here */
117 return 0;
118 }
119
120 static int uvm_load_this(struct binput *in, struct class *class) {
121 int status;
122 #ifdef ENABLE_VERIFIER
123 uint_fast16_t tmp;
124 #endif
125
126 if (status = in->read2(in, &class->this))
127 return status;
128 #ifdef ENABLE_VERIFIER
129 tmp = class->this;
130 if (!tmp || tmp >= class->cp_count)
131 return UVME_CPREF;
132 if (class->cp_tag[tmp - 1] != CONSTANT_Class)
133 return UVME_CPREF;
134 #endif
135 return 0;
136 }
137
138 static int uvm_load_super(struct binput *in, struct class *class) {
139 int status;
140 #ifdef ENABLE_VERIFIER
141 uint_fast16_t tmp;
142 #endif
143
144 if (status = in->read2(in, &class->super))
145 return status;
146 #ifdef ENABLE_VERIFIER
147 tmp = class->super;
148 /* java.lang.Object has no superclass */
149 if (tmp) {
150 if (tmp >= class->cp_count)
151 return UVME_CPREF;
152 if (class->cp_tag[tmp - 1] != CONSTANT_Class)
153 return UVME_CPREF;
154 }
155 #endif
156 return 0;
157 }
158
159 #ifdef ENABLE_VERIFIER
160
161 /** verifies internal constant pool referential integrity */
162 static int uvm_load_cp_tag_verify(struct binput *in, struct class *class, uint_fast16_t i) {
163 union cp_data *data;
164
165 data = &class->cp_info[i];
166 switch (class->cp_tag[i]) {
167 case CONSTANT_Utf8:
168 case CONSTANT_Integer:
169 case CONSTANT_Float:
170 case CONSTANT_Long:
171 case CONSTANT_Double:
172 case CONSTANT_Continued:
173 /* all these types require no further verification */
174 return 0;
175 case CONSTANT_Class:
176 case CONSTANT_String:
177 /* TODO: check for index == 0 */
178 if (data->index - 1 >= class->cp_count || class->cp_tag[data->index - 1] != CONSTANT_Utf8)
179 return UVME_CPREF;
180 return 0;
181 case CONSTANT_Fieldref:
182 case CONSTANT_Methodref:
183 case CONSTANT_InterfaceMethodref:
184 /* TODO: check for index == 0 */
185 if (data->ref.ref1 - 1 >= class->cp_count || class->cp_tag[data->ref.ref1 - 1] != CONSTANT_Class)
186 return UVME_CPREF;
187 if (data->ref.ref2 - 1 >= class->cp_count || class->cp_tag[data->ref.ref2 - 1] != CONSTANT_NameAndType)
188 return UVME_CPREF;
189 return 0;
190 case CONSTANT_NameAndType:
191 /* TODO: check for index == 0 */
192 if (data->ref.ref1 - 1 >= class->cp_count || class->cp_tag[data->ref.ref1 - 1] != CONSTANT_Utf8)
193 return UVME_CPREF;
194 if (data->ref.ref2 - 1 >= class->cp_count || class->cp_tag[data->ref.ref2 - 1] != CONSTANT_Utf8)
195 return UVME_CPREF;
196 return 0;
197 default:
198 return UVME_CPTAG;
199 }
200 }
201 #endif
202
203 static int uvm_load_cp_Utf8(struct binput *in, union cp_data *out) {
204 int status, i;
205 uint8_t *tmp;
206 uint16_t length;
207 #ifdef ENABLE_VERIFIER
208 int expect = 0;
209 #endif
210
211 if (status = in->read2(in, &length))
212 return status;
213 #ifdef ENABLE_MALLOC
214 if (!(tmp = calloc(length + 1, 1)))
215 return UVME_NOMEM;
216 out->utf8 = tmp;
217 for (i = 0; i < length; i++) {
218 if (status = in->read1(in, &tmp[i]))
219 return status;
220 #ifdef ENABLE_VERIFIER
221 switch (expect) {
222 case 0:
223 if ((tmp[i] & UTF_UPPER_1_MASK) == UTF_UPPER_0_MASK) {
224 continue;
225 } else if ((tmp[i] & UTF_UPPER_3_MASK) == UTF_UPPER_2_MASK) {
226 expect = 1;
227 continue;
228 } else if ((tmp[i] & UTF_UPPER_4_MASK) == UTF_UPPER_3_MASK) {
229 expect = 2;
230 continue;
231 }
232 break;
233 case 1:
234 case 2:
235 if ((tmp[i] & UTF_UPPER_2_MASK) == UTF_UPPER_1_MASK) {
236 expect--;
237 continue;
238 }
239 }
240 return UVME_CPUTF;
241 #endif
242 }
243 #ifdef ENABLE_VERIFIER
244 if (expect)
245 return UVME_CPUTF;
246 #endif
247 return 0;
248 #else
249 return UVM_IMPL;
250 #endif
251 }
252
253 static int uvm_load_cp_32(struct binput *in, union cp_data *out) {
254 int status;
255
256 if (status = in->read4(in, &out->data))
257 return status;
258 return 0;
259 }
260
261 static int uvm_load_cp_64(struct binput *in, union cp_data *out) {
262 int status;
263
264 if (status = in->read4(in, &out->data))
265 return status;
266 if (status = in->read4(in, &(out + 1)->data))
267 return status;
268 return 0;
269 }
270
271 static int uvm_load_cp_index(struct binput *in, union cp_data *out) {
272 int status;
273
274 if (status = in->read2(in, &out->index))
275 return status;
276 return 0;
277 }
278
279 static int uvm_load_cp_ref(struct binput *in, union cp_data *out) {
280 int status;
281
282 if (status = in->read2(in, &out->ref.ref1))
283 return status;
284 if (status = in->read2(in, &out->ref.ref2))
285 return status;
286 return 0;
287 }
288
289 static int uvm_load_cp_tag(struct binput *in, struct class *class, uint_fast16_t i) {
290 int status;
291 uint8_t *tag;
292 union cp_data *info;
293
294 tag = &class->cp_tag[i];
295 info = &class->cp_info[i];
296 if (status = in->read1(in, &class->cp_tag[i]))
297 return status;
298 switch (*tag) {
299 case CONSTANT_Utf8:
300 if (status = uvm_load_cp_Utf8(in, info))
301 return status;
302 break;
303 case CONSTANT_Integer:
304 case CONSTANT_Float:
305 if (status = uvm_load_cp_32(in, info))
306 return status;
307 break;
308 case CONSTANT_Long:
309 case CONSTANT_Double:
310 #ifdef ENABLE_VERIFIER
311 if (i == class->cp_count)
312 return UVME_CP64ATEOCP;
313 #endif
314 class->cp_tag[i + 1] = CONSTANT_Continued;
315 if (status = uvm_load_cp_64(in, info))
316 return status;
317 break;
318 case CONSTANT_Class:
319 case CONSTANT_String:
320 if (status = uvm_load_cp_index(in, info))
321 return status;
322 break;
323 case CONSTANT_Fieldref:
324 case CONSTANT_Methodref:
325 case CONSTANT_InterfaceMethodref:
326 case CONSTANT_NameAndType:
327 if (status = uvm_load_cp_ref(in, info))
328 return status;
329 break;
330 default:
331 printf("Bad Tag: %d\n", *tag);
332 *tag = CONSTANT_Unknown;
333 return UVME_CPTAG;
334 }
335 return 0;
336 }
337
338 static int uvm_load_cp(struct binput *in, struct class *out) {
339 int status;
340 uint_fast16_t i, cp_count;
341
342 {
343 uint16_t tmp;
344 if (status = in->read2(in, &tmp))
345 return status;
346 out->cp_count = cp_count = tmp - 1;
347 }
348 /* TODO: determine appropriate minimum cp size */
349 #ifdef ENABLE_VERIFIER
350 if (cp_count < 2)
351 return UVME_CPSIZ;
352 #endif
353 #ifdef ENABLE_MALLOC
354 if (!(out->cp_tag = calloc(cp_count, sizeof *out->cp_tag)))
355 return UVME_NOMEM;
356 if (!(out->cp_info = calloc(cp_count, sizeof *out->cp_info))) {
357 status = UVME_NOMEM;
358 goto E0;
359 }
360 /* read constant pool */
361 for (i = 0; i < cp_count; i++) {
362 if (status = uvm_load_cp_tag(in, out, i))
363 goto E1;
364 if (out->cp_tag[i] == CONSTANT_Long || out->cp_tag[i] == CONSTANT_Double)
365 i++;
366 }
367 #ifdef ENABLE_VERIFIER
368 /* check internal referential integrity */
369 for (i = 0; i < cp_count; i++) {
370 if (status = uvm_load_cp_tag_verify(in, out, i))
371 goto E1;
372 }
373 #endif
374 return 0;
375 E1:
376 free(out->cp_info);
377 E0:
378 free(out->cp_tag);
379 return status;
380 #else
381 return UVM_IMPL;
382 #endif
383 }
384
385 static int uvm_load_iface(struct binput *in, struct class *out, uint_fast16_t i) {
386 int status;
387 uint16_t tmp;
388
389 if (status = in->read2(in, &tmp))
390 return status;
391 out->iface[i] = tmp;
392 #ifdef ENABLE_VERIFIER
393 if (!tmp || tmp >= out->cp_count)
394 return UVME_CPREF;
395 if (out->cp_tag[tmp - 1] != CONSTANT_Class)
396 return UVME_CPREF;
397 #endif
398 return 0;
399 }
400
401 static int uvm_load_ifaces(struct binput *in, struct class *out) {
402 int status;
403 uint_fast16_t i, iface_count;
404
405 if (status = in->read2(in, &out->iface_count))
406 return status;
407 #ifdef ENABLE_MALLOC
408 iface_count = out->iface_count;
409 if (!(out->iface = calloc(iface_count, sizeof *out->iface)))
410 return UVME_NOMEM;
411 for (i = 0; i < iface_count; i++)
412 if (status = uvm_load_iface(in, out, i))
413 return status;
414 return 0;
415 #else
416 return UVM_IMPL;
417 #endif
418 }
419
420 static int uvm_load_fields(struct binput *in, struct class *out) {
421 int status;
422
423 if (status = in->read2(in, &out->field_count))
424 return status;
425
426 return UVM_IMPL;
427 }
428
429 static int uvm_load_access(struct binput *in, struct class *out) {
430 int status;
431 uint_fast16_t tmp;
432
433 {
434 uint16_t tmp2;
435
436 if (status = in->read2(in, &tmp2))
437 return status;
438 /* mask out unrecognised bits and check validity of combination */
439 tmp2 &= ACC_CLASS_MASK;
440 out->access = tmp = tmp2;
441 }
442 #ifdef ENABLE_VERIFIER
443 if (tmp & ACC_INTERFACE) {
444 if (!(tmp & ACC_ABSTRACT))
445 return UVME_CACCESS;
446 if (tmp & ~(ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC))
447 return UVME_CACCESS;
448 } else {
449 if ((tmp & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
450 return UVME_CACCESS;
451 }
452 #endif
453 return 0;
454 }
455
456 int uvm_read2(struct binput *in, uint16_t *out) {
457 int status;
458 uint16_t ret;
459 uint8_t tmp;
460
461 if (status = in->read1(in, &tmp))
462 return status;
463 ret = ((uint16_t) tmp) << 010;
464 if (status = in->read1(in, &tmp))
465 return status;
466 ret += tmp;
467 *out = ret;
468 return 0;
469 }
470
471 int uvm_read4(struct binput *in, uint32_t *out) {
472 int status;
473 uint32_t ret;
474 uint16_t tmp;
475
476 if (status = in->read2(in, &tmp))
477 return status;
478 ret = ((uint32_t) tmp) << 020;
479 if (status = in->read2(in, &tmp))
480 return status;
481 ret += tmp;
482 *out = ret;
483 return 0;
484 }
485
486 int uvm_read8(struct binput *in, uint64_t *out) {
487 int status;
488 uint64_t ret;
489 uint32_t tmp;
490
491 if (status = in->read4(in, &tmp))
492 return status;
493 ret = ((uint64_t) tmp) << 040;
494 if (status = in->read4(in, &tmp))
495 return status;
496 ret += tmp;
497 *out = ret;
498 return 0;
499 }
500
501 int uvm_skip(struct binput *in, size_t i) {
502 return UVM_IMPL;
503 }
504
505 /** FIXME: remove me */
506 static void uvm_dump_class(struct class *class) {
507 #if 0
508 int i;
509
510 printf("CP Size: %d\n", class->cp_count);
511 for (i = 1; i < class->cp_count; i++) {
512 printf("Tag[%d]: ", i);
513 switch (class->cp_tag[i - 1]) {
514 case CONSTANT_Utf8:
515 printf("%s (Utf8)\n", class->cp_info[i - 1].utf8);
516 break;
517 case CONSTANT_Integer:
518 printf("%uld (Integer)\n", class->cp_info[i - 1].data);
519 break;
520 case CONSTANT_Float:
521 printf("(Float)\n");
522 break;
523 case CONSTANT_Long:
524 printf("%lld (Long)\n", (long long int) ((((int64_t) class->cp_info[i - 1].data) << 040) + (int64_t) class->cp_info[i].data));
525 i++;
526 break;
527 case CONSTANT_Double:
528 printf("(Double)\n");
529 i++;
530 break;
531 case CONSTANT_Class:
532 printf("(Class)\n");
533 break;
534 case CONSTANT_String:
535 printf("(String)\n");
536 break;
537 case CONSTANT_Fieldref:
538 printf("(Fieldref)\n");
539 break;
540 case CONSTANT_Methodref:
541 printf("(Methodref)\n");
542 break;
543 case CONSTANT_InterfaceMethodref:
544 printf("(InterfaceMethodref)\n");
545 break;
546 case CONSTANT_NameAndType:
547 printf("(NameAndType)\n");
548 break;
549 default:
550 printf("Unknown\n");
551 return;
552 }
553 }
554 #endif
555 }
556
557 int uvm_load(struct binput *in) {
558 int status;
559 struct class class;
560
561 if (!in->read2)
562 in->read2 = &uvm_read2;
563 if (!in->read4)
564 in->read4 = &uvm_read4;
565 if (!in->read8)
566 in->read8 = &uvm_read8;
567 if (status = uvm_load_magic(in))
568 return status;
569 if (status = uvm_load_version(in))
570 return status;
571 if (status = uvm_load_cp(in, &class))
572 return status;
573 if (status = uvm_load_access(in, &class))
574 return status;
575 if (status = uvm_load_this(in, &class))
576 return status;
577 if (status = uvm_load_super(in, &class))
578 return status;
579 if (status = uvm_load_ifaces(in, &class))
580 return status;
581 if (status = uvm_load_fields(in, &class)) {
582 uvm_dump_class(&class);
583 return status;
584 }
585 uvm_dump_class(&class);
586 in->close(in);
587 return 0;
588 }
589
590 void uvm_load_error(char *message, int value) {
591 char *err;
592 switch (value) {
593 case 0:
594 err = "Success";
595 break;
596 case UVME_EOF:
597 err = "Input source ran out of data";
598 break;
599 case UVME_EIO:
600 err = "Input source encountered an error";
601 break;
602 case UVME_NOMEM:
603 err = "Insufficient space";
604 break;
605 case UVME_MAGIC:
606 err = "Bad magic number";
607 break;
608 case UVME_VERSION:
609 err = "Unsupported class file version";
610 break;
611 case UVME_CPSIZ:
612 err = "Constant pool too small";
613 break;
614 case UVME_CPTAG:
615 err = "Invalid constant pool tag";
616 break;
617 case UVME_CPUTF:
618 err = "Invalid UTF-8 string format";
619 break;
620 case UVME_CP64ATEOCP:
621 err = "Constant pool tag spanning two entries at last entry";
622 break;
623 case UVME_CACCESS:
624 err = "Invalid class access flags";
625 break;
626 case UVME_CPREF:
627 err = "Invalid constant pool reference";
628 break;
629 case UVM_IMPL:
630 err = "Unimplemented";
631 break;
632 default:
633 err = "Unknown error";
634 }
635 printf("%s: %s.\n", message, err);
636 }

Properties

Name Value
svn:keywords Id

Managed by UCC Webmasters ViewVC Help
Powered by ViewVC 1.1.26