xref: /inferno-os/libinterp/load.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
1 #include "lib9.h"
2 #include "isa.h"
3 #include "interp.h"
4 #include "raise.h"
5 #include <kernel.h>
6 
7 #define	A(r)	*((Array**)(r))
8 
9 Module*	modules;
10 int	dontcompile;
11 
12 static int
13 operand(uchar **p)
14 {
15 	int c;
16 	uchar *cp;
17 
18 	cp = *p;
19 	c = cp[0];
20 	switch(c & 0xC0) {
21 	case 0x00:
22 		*p = cp+1;
23 		return c;
24 	case 0x40:
25 		*p = cp+1;
26 		return c|~0x7F;
27 	case 0x80:
28 		*p = cp+2;
29 		if(c & 0x20)
30 			c |= ~0x3F;
31 		else
32 			c &= 0x3F;
33 		return (c<<8)|cp[1];
34 	case 0xC0:
35 		*p = cp+4;
36 		if(c & 0x20)
37 			c |= ~0x3F;
38 		else
39 			c &= 0x3F;
40 		return (c<<24)|(cp[1]<<16)|(cp[2]<<8)|cp[3];
41 	}
42 	return 0;
43 }
44 
45 static ulong
46 disw(uchar **p)
47 {
48 	ulong v;
49 	uchar *c;
50 
51 	c = *p;
52 	v  = c[0] << 24;
53 	v |= c[1] << 16;
54 	v |= c[2] << 8;
55 	v |= c[3];
56 	*p = c + 4;
57 	return v;
58 }
59 
60 double
61 canontod(ulong v[2])
62 {
63 	union { double d; unsigned long ul[2]; } a;
64 	a.d = 1.;
65 	if(a.ul[0]) {
66 		a.ul[0] = v[0];
67 		a.ul[1] = v[1];
68 	}
69 	else {
70 		a.ul[1] = v[0];
71 		a.ul[0] = v[1];
72 	}
73 	return a.d;
74 }
75 
76 Module*
77 load(char *path)
78 {
79 	return readmod(path, nil, 0);
80 }
81 
82 int
83 brpatch(Inst *ip, Module *m)
84 {
85 	switch(ip->op) {
86 	case ICALL:
87 	case IJMP:
88 	case IBEQW:
89 	case IBNEW:
90 	case IBLTW:
91 	case IBLEW:
92 	case IBGTW:
93 	case IBGEW:
94 	case IBEQB:
95 	case IBNEB:
96 	case IBLTB:
97 	case IBLEB:
98 	case IBGTB:
99 	case IBGEB:
100 	case IBEQF:
101 	case IBNEF:
102 	case IBLTF:
103 	case IBLEF:
104 	case IBGTF:
105 	case IBGEF:
106 	case IBEQC:
107 	case IBNEC:
108 	case IBLTC:
109 	case IBLEC:
110 	case IBGTC:
111 	case IBGEC:
112 	case IBEQL:
113 	case IBNEL:
114 	case IBLTL:
115 	case IBLEL:
116 	case IBGTL:
117 	case IBGEL:
118 	case ISPAWN:
119 		if(ip->d.imm < 0 || ip->d.imm >= m->nprog)
120 			return 0;
121 		ip->d.imm = (WORD)&m->prog[ip->d.imm];
122 		break;
123 	}
124 	return 1;
125 }
126 
127 Module*
128 parsemod(char *path, uchar *code, ulong length, Dir *dir)
129 {
130 	Heap *h;
131 	Inst *ip;
132 	Type *pt;
133 	String *s;
134 	Module *m;
135 	Array *ary;
136 	ulong ul[2];
137 	WORD lo, hi;
138 	int lsize, id, v, entry, entryt, tnp, tsz, siglen;
139 	int de, pc, i, n, isize, dsize, hsize, dasp;
140 	uchar *mod, sm, *istream, **isp, *si, *addr, *dastack[DADEPTH];
141 	Link *l;
142 
143 	istream = code;
144 	isp = &istream;
145 
146 	m = malloc(sizeof(Module));
147 	if(m == nil)
148 		return nil;
149 
150 	m->dev = dir->dev;
151 	m->dtype = dir->type;
152 	m->qid = dir->qid;
153 	m->mtime = dir->mtime;
154 	m->origmp = H;
155 	m->pctab = nil;
156 
157 	switch(operand(isp)) {
158 	default:
159 		kwerrstr("bad magic");
160 		goto bad;
161 	case SMAGIC:
162 		siglen = operand(isp);
163 		n = length-(*isp-code);
164 		if(n < 0 || siglen > n){
165 			kwerrstr("corrupt signature");
166 			goto bad;
167 		}
168 		if(verifysigner(*isp, siglen, *isp+siglen, n-siglen) == 0) {
169 			kwerrstr("security violation");
170 			goto bad;
171 		}
172 		*isp += siglen;
173 		break;
174 	case XMAGIC:
175 		if(mustbesigned(path, code, length, dir)){
176 			kwerrstr("security violation: not signed");
177 			goto bad;
178 		}
179 		break;
180 	}
181 
182 	m->rt = operand(isp);
183 	m->ss = operand(isp);
184 	isize = operand(isp);
185 	dsize = operand(isp);
186 	hsize = operand(isp);
187 	lsize = operand(isp);
188 	entry = operand(isp);
189 	entryt = operand(isp);
190 
191 	if(isize < 0 || dsize < 0 || hsize < 0 || lsize < 0) {
192 		kwerrstr("implausible Dis file");
193 		goto bad;
194 	}
195 
196 	m->nprog = isize;
197 	m->prog = mallocz(isize*sizeof(Inst), 0);
198 	if(m->prog == nil) {
199 		kwerrstr(exNomem);
200 		goto bad;
201 	}
202 
203 	m->ref = 1;
204 
205 	ip = m->prog;
206 	for(i = 0; i < isize; i++) {
207 		ip->op = *istream++;
208 		ip->add = *istream++;
209 		ip->reg = 0;
210 		ip->s.imm = 0;
211 		ip->d.imm = 0;
212 		switch(ip->add & ARM) {
213 		case AXIMM:
214 		case AXINF:
215 		case AXINM:
216 			ip->reg = operand(isp);
217 		 	break;
218 		}
219 		switch(UXSRC(ip->add)) {
220 		case SRC(AFP):
221 		case SRC(AMP):
222 		case SRC(AIMM):
223 			ip->s.ind = operand(isp);
224 			break;
225 		case SRC(AIND|AFP):
226 		case SRC(AIND|AMP):
227 			ip->s.i.f = operand(isp);
228 			ip->s.i.s = operand(isp);
229 			break;
230 		}
231 		switch(UXDST(ip->add)) {
232 		case DST(AFP):
233 		case DST(AMP):
234 			ip->d.ind = operand(isp);
235 			break;
236 		case DST(AIMM):
237 			ip->d.ind = operand(isp);
238 			if(brpatch(ip, m) == 0) {
239 				kwerrstr("bad branch addr");
240 				goto bad;
241 			}
242 			break;
243 		case DST(AIND|AFP):
244 		case DST(AIND|AMP):
245 			ip->d.i.f = operand(isp);
246 			ip->d.i.s = operand(isp);
247 			break;
248 		}
249 		ip++;
250 	}
251 
252 	m->ntype = hsize;
253 	m->type = malloc(hsize*sizeof(Type*));
254 	if(m->type == nil) {
255 		kwerrstr(exNomem);
256 		goto bad;
257 	}
258 	for(i = 0; i < hsize; i++) {
259 		id = operand(isp);
260 		if(id > hsize) {
261 			kwerrstr("heap id range");
262 			goto bad;
263 		}
264 		tsz = operand(isp);
265 		tnp = operand(isp);
266 		if(tsz < 0 || tnp < 0 || tnp > 128*1024){
267 			kwerrstr("implausible Dis file");
268 			goto bad;
269 		}
270 		pt = dtype(freeheap, tsz, istream, tnp);
271 		if(pt == nil) {
272 			kwerrstr(exNomem);
273 			goto bad;
274 		}
275 		istream += tnp;
276 		m->type[id] = pt;
277 	}
278 
279 	if(dsize != 0) {
280 		pt = m->type[0];
281 		if(pt == 0 || pt->size != dsize) {
282 			kwerrstr("bad desc for mp");
283 			goto bad;
284 		}
285 		h = heapz(pt);
286 		m->origmp = H2D(uchar*, h);
287 	}
288 	addr = m->origmp;
289 	dasp = 0;
290 	for(;;) {
291 		sm = *istream++;
292 		if(sm == 0)
293 			break;
294 		n = DLEN(sm);
295 		if(n == 0)
296 			n = operand(isp);
297 		v = operand(isp);
298 		si = addr + v;
299 		switch(DTYPE(sm)) {
300 		default:
301 			kwerrstr("bad data item");
302 			goto bad;
303 		case DEFS:
304 			s = c2string((char*)istream, n);
305 			istream += n;
306 			*(String**)si = s;
307 			break;
308 		case DEFB:
309 			for(i = 0; i < n; i++)
310 				*si++ = *istream++;
311 			break;
312 		case DEFW:
313 			for(i = 0; i < n; i++) {
314 				*(WORD*)si = disw(isp);
315 				si += sizeof(WORD);
316 			}
317 			break;
318 		case DEFL:
319 			for(i = 0; i < n; i++) {
320 				hi = disw(isp);
321 				lo = disw(isp);
322 				*(LONG*)si = (LONG)hi << 32 | (LONG)(ulong)lo;
323 				si += sizeof(LONG);
324 			}
325 			break;
326 		case DEFF:
327 			for(i = 0; i < n; i++) {
328 				ul[0] = disw(isp);
329 				ul[1] = disw(isp);
330 				*(REAL*)si = canontod(ul);
331 				si += sizeof(REAL);
332 			}
333 			break;
334 		case DEFA:			/* Array */
335 			v = disw(isp);
336 			if(v < 0 || v > m->ntype) {
337 				kwerrstr("bad array type");
338 				goto bad;
339 			}
340 			pt = m->type[v];
341 			v = disw(isp);
342 			h = nheap(sizeof(Array)+(pt->size*v));
343 			h->t = &Tarray;
344 			h->t->ref++;
345 			ary = H2D(Array*, h);
346 			ary->t = pt;
347 			ary->len = v;
348 			ary->root = H;
349 			ary->data = (uchar*)ary+sizeof(Array);
350 			memset((void*)ary->data, 0, pt->size*v);
351 			initarray(pt, ary);
352 			A(si) = ary;
353 			break;
354 		case DIND:			/* Set index */
355 			ary = A(si);
356 			if(ary == H || D2H(ary)->t != &Tarray) {
357 				kwerrstr("ind not array");
358 				goto bad;
359 			}
360 			v = disw(isp);
361 			if(v > ary->len || v < 0 || dasp >= DADEPTH) {
362 				kwerrstr("array init range");
363 				goto bad;
364 			}
365 			dastack[dasp++] = addr;
366 			addr = ary->data+v*ary->t->size;
367 			break;
368 		case DAPOP:
369 			if(dasp == 0) {
370 				kwerrstr("pop range");
371 				goto bad;
372 			}
373 			addr = dastack[--dasp];
374 			break;
375 		}
376 	}
377 	mod = istream;
378 	if(memchr(mod, 0, 128) == 0) {
379 		kwerrstr("bad module name");
380 		goto bad;
381 	}
382 	m->name = strdup((char*)mod);
383 	if(m->name == nil) {
384 		kwerrstr(exNomem);
385 		goto bad;
386 	}
387 	while(*istream++)
388 		;
389 
390 	l = m->ext = (Link*)malloc((lsize+1)*sizeof(Link));
391 	if(l == nil){
392 		kwerrstr(exNomem);
393 		goto bad;
394 	}
395 	for(i = 0; i < lsize; i++, l++) {
396 		pc = operand(isp);
397 		de = operand(isp);
398 		v  = disw(isp);
399 		pt = nil;
400 		if(de != -1)
401 			pt = m->type[de];
402 		mlink(m, l, istream, v, pc, pt);
403 		while(*istream++)
404 			;
405 	}
406 	l->name = nil;
407 
408 	if(m->rt & HASLDT0){
409 		kwerrstr("obsolete dis");
410 		goto bad;
411 	}
412 
413 	if(m->rt & HASLDT){
414 		int j, nl;
415 		Import *i1, **i2;
416 
417 		nl = operand(isp);
418 		i2 = m->ldt = (Import**)malloc((nl+1)*sizeof(Import*));
419 		if(i2 == nil){
420 			kwerrstr(exNomem);
421 			goto bad;
422 		}
423 		for(i = 0; i < nl; i++, i2++){
424 			n = operand(isp);
425 			i1 = *i2 = (Import*)malloc((n+1)*sizeof(Import));
426 			if(i1 == nil){
427 				kwerrstr(exNomem);
428 				goto bad;
429 			}
430 			for(j = 0; j < n; j++, i1++){
431 				i1->sig = disw(isp);
432 				i1->name = strdup((char*)istream);
433 				if(i1->name == nil){
434 					kwerrstr(exNomem);
435 					goto bad;
436 				}
437 				while(*istream++)
438 					;
439 			}
440 		}
441 		istream++;
442 	}
443 
444 	if(m->rt & HASEXCEPT){
445 		int j, nh;
446 		Handler *h;
447 		Except *e;
448 
449 		nh = operand(isp);
450 		m->htab = malloc((nh+1)*sizeof(Handler));
451 		if(m->htab == nil){
452 			kwerrstr(exNomem);
453 			goto bad;
454 		}
455 		h = m->htab;
456 		for(i = 0; i < nh; i++, h++){
457 			h->eoff = operand(isp);
458 			h->pc1 = operand(isp);
459 			h->pc2 = operand(isp);
460 			n = operand(isp);
461 			if(n != -1)
462 				h->t = m->type[n];
463 			n = operand(isp);
464 			h->ne = n>>16;
465 			n &= 0xffff;
466 			h->etab = malloc((n+1)*sizeof(Except));
467 			if(h->etab == nil){
468 				kwerrstr(exNomem);
469 				goto bad;
470 			}
471 			e = h->etab;
472 			for(j = 0; j < n; j++, e++){
473 				e->s = strdup((char*)istream);
474 				if(e->s == nil){
475 					kwerrstr(exNomem);
476 					goto bad;
477 				}
478 				while(*istream++)
479 					;
480 				e->pc = operand(isp);
481 			}
482 			e->s = nil;
483 			e->pc = operand(isp);
484 		}
485 		istream++;
486 	}
487 
488 	m->entryt = nil;
489 	m->entry = m->prog;
490 	if((ulong)entry < isize && (ulong)entryt < hsize) {
491 		m->entry = &m->prog[entry];
492 		m->entryt = m->type[entryt];
493 	}
494 
495 	if(cflag) {
496 		if((m->rt&DONTCOMPILE) == 0 && !dontcompile)
497 			compile(m, isize, nil);
498 	}
499 	else
500 	if(m->rt & MUSTCOMPILE && !dontcompile) {
501 		if(compile(m, isize, nil) == 0) {
502 			kwerrstr("compiler required");
503 			goto bad;
504 		}
505 	}
506 
507 	m->path = strdup(path);
508 	if(m->path == nil) {
509 		kwerrstr(exNomem);
510 		goto bad;
511 	}
512 	m->link = modules;
513 	modules = m;
514 
515 	return m;
516 bad:
517 	destroy(m->origmp);
518 	freemod(m);
519 	return nil;
520 }
521 
522 Module*
523 newmod(char *s)
524 {
525 	Module *m;
526 
527 	m = malloc(sizeof(Module));
528 	if(m == nil)
529 		error(exNomem);
530 	m->ref = 1;
531 	m->path = s;
532 	m->origmp = H;
533 	m->name = strdup(s);
534 	if(m->name == nil) {
535 		free(m);
536 		error(exNomem);
537 	}
538 	m->link = modules;
539 	modules = m;
540 	m->pctab = nil;
541 	return m;
542 }
543 
544 Module*
545 lookmod(char *s)
546 {
547 	Module *m;
548 
549 	for(m = modules; m != nil; m = m->link)
550 		if(strcmp(s, m->path) == 0) {
551 			m->ref++;
552 			return m;
553 		}
554 	return nil;
555 }
556 
557 void
558 freemod(Module *m)
559 {
560 	int i;
561 	Handler *h;
562 	Except *e;
563 	Import *i1, **i2;
564 
565 	if(m->type != nil) {
566 		for(i = 0; i < m->ntype; i++)
567 			freetype(m->type[i]);
568 		free(m->type);
569 	}
570 	free(m->name);
571 	free(m->prog);
572 	free(m->path);
573 	free(m->pctab);
574 	if(m->ldt != nil){
575 		for(i2 = m->ldt; *i2 != nil; i2++){
576 			for(i1 = *i2; i1->name != nil; i1++)
577 				free(i1->name);
578 			free(*i2);
579 		}
580 		free(m->ldt);
581 	}
582 	if(m->htab != nil){
583 		for(h = m->htab; h->etab != nil; h++){
584 			for(e = h->etab; e->s != nil; e++)
585 				free(e->s);
586 			free(h->etab);
587 		}
588 		free(m->htab);
589 	}
590 	free(m);
591 }
592 
593 void
594 unload(Module *m)
595 {
596 	Module **last, *mm;
597 
598 	m->ref--;
599 	if(m->ref > 0)
600 		return;
601 	if(m->ref == -1)
602 		abort();
603 
604 	last = &modules;
605 	for(mm = modules; mm != nil; mm = mm->link) {
606 		if(mm == m) {
607 			*last = m->link;
608 			break;
609 		}
610 		last = &mm->link;
611 	}
612 
613 	if(m->rt == DYNMOD)
614 		freedyncode(m);
615 	else
616 		destroy(m->origmp);
617 
618 	destroylinks(m);
619 
620 	freemod(m);
621 }
622