GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/mopd/mopd/../common/file.c Lines: 0 579 0.0 %
Date: 2017-11-13 Branches: 0 332 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: file.c,v 1.19 2017/10/29 08:45:53 mpi Exp $ */
2
3
/*
4
 * Copyright (c) 1995-96 Mats O Jansson.  All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include "os.h"
28
#include "common.h"
29
#include "file.h"
30
#include "mopdef.h"
31
#include <stddef.h>
32
33
#ifndef NOAOUT
34
#if defined(__OpenBSD__)
35
#include <sys/exec.h>
36
#endif
37
#if defined(__bsdi__)
38
#define NOAOUT
39
#endif
40
#if defined(__FreeBSD__)
41
#include <sys/imgact_aout.h>
42
#endif
43
#if !defined(MID_I386)
44
#define MID_I386 134
45
#endif
46
#if !defined(MID_SPARC)
47
#define MID_SPARC 138
48
#endif
49
#if !defined(MID_VAX)
50
#define MID_VAX 140
51
#endif
52
#endif
53
54
#ifndef NOELF
55
#if defined(__OpenBSD__)
56
#include <elf.h>
57
#else
58
#define NOELF
59
#endif
60
#endif
61
62
#ifndef NOELF
63
#if !defined(_LP64)
64
#define NOELF64
65
#endif
66
#endif
67
68
#ifndef NOAOUT
69
static int	getCLBYTES(int);
70
static int	getMID(int, int);
71
#endif
72
73
const char *
74
FileTypeName(mopd_imagetype type)
75
{
76
77
	switch (type) {
78
	case IMAGE_TYPE_MOP:
79
		return ("MOP");
80
81
	case IMAGE_TYPE_ELF32:
82
		return ("Elf32");
83
84
	case IMAGE_TYPE_ELF64:
85
		return ("Elf64");
86
87
	case IMAGE_TYPE_AOUT:
88
		return ("a.out");
89
	}
90
91
	abort();
92
}
93
94
void
95
mopFilePutLX(u_char *buf, int idx, u_int32_t value, int cnt)
96
{
97
	int i;
98
	for (i = 0; i < cnt; i++) {
99
		buf[idx+i] = value % 256;
100
		value = value / 256;
101
	}
102
}
103
104
void
105
mopFilePutBX(u_char *buf, int idx, u_int32_t value, int cnt)
106
{
107
	int i;
108
	for (i = 0; i < cnt; i++) {
109
		buf[idx+cnt-1-i] = value % 256;
110
		value = value / 256;
111
	}
112
}
113
114
u_int32_t
115
mopFileGetLX(u_char *buf, int idx, int cnt)
116
{
117
	u_int32_t ret = 0;
118
	int i;
119
120
	for (i = 0; i < cnt; i++) {
121
		int j = idx + cnt - 1 - i;
122
		if (j < 0)
123
			abort();
124
		ret = ret * 256 + buf[j];
125
	}
126
127
	return(ret);
128
}
129
130
u_int32_t
131
mopFileGetBX(u_char *buf, int idx, int cnt)
132
{
133
	u_int32_t ret = 0;
134
	int i;
135
136
	for (i = 0; i < cnt; i++) {
137
		int j = idx + i;
138
		if (j < 0)
139
			abort();
140
		ret = ret * 256 + buf[j];
141
	}
142
143
	return(ret);
144
}
145
146
#if !defined(NOELF) && !defined(NOELF64)
147
u_int64_t
148
mopFileGetLXX(u_char *buf, int idx, int cnt)
149
{
150
	u_int64_t ret = 0;
151
	int i;
152
153
	for (i = 0; i < cnt; i++) {
154
		int j = idx + cnt - 1 - i;
155
		if (j < 0)
156
			abort();
157
		ret = ret * 256 + buf[j];
158
	}
159
160
	return(ret);
161
}
162
163
u_int64_t
164
mopFileGetBXX(u_char *buf, int idx, int cnt)
165
{
166
	u_int64_t ret = 0;
167
	int i;
168
169
	for (i = 0; i < cnt; i++) {
170
		int j = idx + i;
171
		if (j < 0)
172
			abort();
173
		ret = ret * 256 + buf[j];
174
	}
175
176
	return(ret);
177
}
178
#endif
179
180
void
181
mopFileSwapX(u_char *buf, int idx, int cnt)
182
{
183
	int i;
184
	u_char c;
185
186
	for (i = 0; i < (cnt / 2); i++) {
187
		c = buf[idx+i];
188
		buf[idx+i] = buf[idx+cnt-1-i];
189
		buf[idx+cnt-1-i] = c;
190
	}
191
192
}
193
194
int
195
CheckMopFile(int fd)
196
{
197
	u_char	header[512];
198
	short	image_type;
199
200
	if (read(fd, header, 512) != 512)
201
		return(-1);
202
203
	(void)lseek(fd, (off_t) 0, SEEK_SET);
204
205
	image_type = (u_short)(header[IHD_W_ALIAS+1]*256 + header[IHD_W_ALIAS]);
206
207
	switch(image_type) {
208
	case IHD_C_NATIVE:		/* Native mode image (VAX)   */
209
	case IHD_C_RSX:			/* RSX image produced by TKB */
210
	case IHD_C_BPA:			/* BASIC plus analog         */
211
	case IHD_C_ALIAS:		/* Alias		     */
212
	case IHD_C_CLI:			/* Image is CLI		     */
213
	case IHD_C_PMAX:		/* PMAX system image	     */
214
	case IHD_C_ALPHA:		/* ALPHA system image	     */
215
		break;
216
	default:
217
		return(-1);
218
	}
219
220
	return(0);
221
}
222
223
int
224
GetMopFileInfo(struct dllist *dl, int info)
225
{
226
	u_char		header[512];
227
	short		image_type;
228
	u_int32_t	load_addr, xfr_addr, isd, iha, hbcnt, isize;
229
230
	if (read(dl->ldfd, header, 512) != 512)
231
		return(-1);
232
233
	image_type = (u_short)(header[IHD_W_ALIAS+1]*256 +
234
			       header[IHD_W_ALIAS]);
235
236
	switch (image_type) {
237
	case IHD_C_NATIVE:		/* Native mode image (VAX)   */
238
		isd = (header[IHD_W_SIZE+1]*256 +
239
		       header[IHD_W_SIZE]);
240
		iha = (header[IHD_W_ACTIVOFF+1]*256 +
241
		       header[IHD_W_ACTIVOFF]);
242
		hbcnt = (header[IHD_B_HDRBLKCNT]);
243
		isize = (header[isd+ISD_W_PAGCNT+1]*256 +
244
			 header[isd+ISD_W_PAGCNT]) * 512;
245
		load_addr = ((header[isd+ISD_V_VPN+1]*256 +
246
			      header[isd+ISD_V_VPN]) & ISD_M_VPN)
247
				* 512;
248
		xfr_addr = (header[iha+IHA_L_TFRADR1+3]*0x1000000 +
249
			    header[iha+IHA_L_TFRADR1+2]*0x10000 +
250
			    header[iha+IHA_L_TFRADR1+1]*0x100 +
251
			    header[iha+IHA_L_TFRADR1]) & 0x7fffffff;
252
		if (info == INFO_PRINT) {
253
			printf("Native Image (VAX)\n");
254
			printf("Header Block Count: %d\n",hbcnt);
255
			printf("Image Size:         %08x\n",isize);
256
			printf("Load Address:       %08x\n",load_addr);
257
			printf("Transfer Address:   %08x\n",xfr_addr);
258
		}
259
		break;
260
	case IHD_C_RSX:			/* RSX image produced by TKB */
261
		hbcnt = header[L_BBLK+1]*256 + header[L_BBLK];
262
		isize = (header[L_BLDZ+1]*256 + header[L_BLDZ]) * 64;
263
		load_addr = header[L_BSA+1]*256 + header[L_BSA];
264
		xfr_addr  = header[L_BXFR+1]*256 + header[L_BXFR];
265
		if (info == INFO_PRINT) {
266
			printf("RSX Image\n");
267
			printf("Header Block Count: %d\n",hbcnt);
268
			printf("Image Size:         %08x\n",isize);
269
			printf("Load Address:       %08x\n",load_addr);
270
			printf("Transfer Address:   %08x\n",xfr_addr);
271
		}
272
		break;
273
	case IHD_C_BPA:			/* BASIC plus analog         */
274
		if (info == INFO_PRINT) {
275
			printf("BASIC-Plus Image, not supported\n");
276
		}
277
		return(-1);
278
		break;
279
	case IHD_C_ALIAS:		/* Alias		     */
280
		if (info == INFO_PRINT) {
281
			printf("Alias, not supported\n");
282
		}
283
		return(-1);
284
		break;
285
	case IHD_C_CLI:			/* Image is CLI		     */
286
		if (info == INFO_PRINT) {
287
			printf("CLI, not supported\n");
288
		}
289
		return(-1);
290
		break;
291
	case IHD_C_PMAX:		/* PMAX system image	     */
292
		isd = (header[IHD_W_SIZE+1]*256 +
293
		       header[IHD_W_SIZE]);
294
		iha = (header[IHD_W_ACTIVOFF+1]*256 +
295
		       header[IHD_W_ACTIVOFF]);
296
		hbcnt = (header[IHD_B_HDRBLKCNT]);
297
		isize = (header[isd+ISD_W_PAGCNT+1]*256 +
298
			 header[isd+ISD_W_PAGCNT]) * 512;
299
		load_addr = (header[isd+ISD_V_VPN+1]*256 +
300
			     header[isd+ISD_V_VPN]) * 512;
301
		xfr_addr = (header[iha+IHA_L_TFRADR1+3]*0x1000000 +
302
			    header[iha+IHA_L_TFRADR1+2]*0x10000 +
303
			    header[iha+IHA_L_TFRADR1+1]*0x100 +
304
			    header[iha+IHA_L_TFRADR1]);
305
		if (info == INFO_PRINT) {
306
			printf("PMAX Image \n");
307
			printf("Header Block Count: %d\n",hbcnt);
308
			printf("Image Size:         %08x\n",isize);
309
			printf("Load Address:       %08x\n",load_addr);
310
			printf("Transfer Address:   %08x\n",xfr_addr);
311
		}
312
		break;
313
	case IHD_C_ALPHA:		/* ALPHA system image	     */
314
		isd = (header[EIHD_L_ISDOFF+3]*0x1000000 +
315
		       header[EIHD_L_ISDOFF+2]*0x10000 +
316
		       header[EIHD_L_ISDOFF+1]*0x100 +
317
		       header[EIHD_L_ISDOFF]);
318
		hbcnt = (header[EIHD_L_HDRBLKCNT+3]*0x1000000 +
319
			 header[EIHD_L_HDRBLKCNT+2]*0x10000 +
320
			 header[EIHD_L_HDRBLKCNT+1]*0x100 +
321
			 header[EIHD_L_HDRBLKCNT]);
322
		isize = (header[isd+EISD_L_SECSIZE+3]*0x1000000 +
323
			 header[isd+EISD_L_SECSIZE+2]*0x10000 +
324
			 header[isd+EISD_L_SECSIZE+1]*0x100 +
325
			 header[isd+EISD_L_SECSIZE]);
326
		load_addr = 0;
327
		xfr_addr = 0;
328
		if (info == INFO_PRINT) {
329
			printf("Alpha Image \n");
330
			printf("Header Block Count: %d\n",hbcnt);
331
			printf("Image Size:         %08x\n",isize);
332
			printf("Load Address:       %08x\n",load_addr);
333
			printf("Transfer Address:   %08x\n",xfr_addr);
334
		}
335
		break;
336
	default:
337
		if (info == INFO_PRINT) {
338
			printf("Unknown Image (%d)\n",image_type);
339
		}
340
		return(-1);
341
	}
342
343
	dl->image_type = IMAGE_TYPE_MOP;
344
	dl->loadaddr = load_addr;
345
	dl->xferaddr = xfr_addr;
346
347
	return(0);
348
}
349
350
#ifndef NOAOUT
351
static int
352
getMID(int old_mid, int new_mid)
353
{
354
	int	mid;
355
356
	mid = old_mid;
357
358
	switch (new_mid) {
359
	case MID_I386:
360
		mid = MID_I386;
361
		break;
362
#ifdef MID_M68K
363
	case MID_M68K:
364
		mid = MID_M68K;
365
		break;
366
#endif
367
#ifdef MID_M68K4K
368
	case MID_M68K4K:
369
		mid = MID_M68K4K;
370
		break;
371
#endif
372
#ifdef MID_NS32532
373
	case MID_NS32532:
374
		mid = MID_NS32532;
375
		break;
376
#endif
377
	case MID_SPARC:
378
		mid = MID_SPARC;
379
		break;
380
#ifdef MID_PMAX
381
	case MID_PMAX:
382
		mid = MID_PMAX;
383
		break;
384
#endif
385
#ifdef MID_VAX
386
	case MID_VAX:
387
		mid = MID_VAX;
388
		break;
389
#endif
390
#ifdef MID_ALPHA
391
	case MID_ALPHA:
392
		mid = MID_ALPHA;
393
		break;
394
#endif
395
#ifdef MID_MIPS
396
	case MID_MIPS:
397
		mid = MID_MIPS;
398
		break;
399
#endif
400
#ifdef MID_ARM6
401
	case MID_ARM6:
402
		mid = MID_ARM6;
403
		break;
404
#endif
405
	default:
406
		break;
407
	}
408
409
	return(mid);
410
}
411
412
static int
413
getCLBYTES(int mid)
414
{
415
	int	clbytes;
416
417
	switch (mid) {
418
#ifdef MID_VAX
419
	case MID_VAX:
420
		clbytes = 1024;
421
		break;
422
#endif
423
#ifdef MID_I386
424
	case MID_I386:
425
#endif
426
#ifdef MID_M68K4K
427
	case MID_M68K4K:
428
#endif
429
#ifdef MID_NS32532
430
	case MID_NS32532:
431
#endif
432
#ifdef MID_PMAX
433
	case MID_PMAX:
434
#endif
435
#ifdef MID_MIPS
436
	case MID_MIPS:
437
#endif
438
#ifdef MID_ARM6
439
	case MID_ARM6:
440
#endif
441
#if defined(MID_I386) || defined(MID_M68K4K) || defined(MID_NS32532) || \
442
    defined(MID_PMAX) || defined(MID_MIPS) || defined(MID_ARM6)
443
		clbytes = 4096;
444
		break;
445
#endif
446
#ifdef MID_M68K
447
	case MID_M68K:
448
#endif
449
#ifdef MID_ALPHA
450
	case MID_ALPHA:
451
#endif
452
#ifdef MID_SPARC
453
	case MID_SPARC:
454
#endif
455
#if defined(MID_M68K) || defined(MID_ALPHA) || defined(MID_SPARC)
456
		clbytes = 8192;
457
		break;
458
#endif
459
	default:
460
		clbytes = 0;
461
	}
462
463
	return(clbytes);
464
}
465
#endif
466
467
int
468
CheckElfFile(int fd)
469
{
470
#ifdef NOELF
471
	return(-1);
472
#else
473
	Elf32_Ehdr ehdr;
474
475
	(void)lseek(fd, (off_t) 0, SEEK_SET);
476
477
	if (read(fd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
478
		return(-1);
479
480
	if (ehdr.e_ident[0] != ELFMAG0 ||
481
	    ehdr.e_ident[1] != ELFMAG1 ||
482
	    ehdr.e_ident[2] != ELFMAG2 ||
483
	    ehdr.e_ident[3] != ELFMAG3)
484
		return(-1);
485
486
	/* Must be Elf32 or Elf64... */
487
	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 &&
488
	    ehdr.e_ident[EI_CLASS] != ELFCLASS64)
489
		return(-1);
490
491
	return(0);
492
#endif /* NOELF */
493
}
494
495
int
496
GetElf32FileInfo(struct dllist *dl, int info)
497
{
498
#ifdef NOELF
499
	return(-1);
500
#else
501
	Elf32_Ehdr ehdr;
502
	Elf32_Phdr phdr;
503
	uint32_t e_machine, e_entry;
504
	uint32_t e_phoff, e_phentsize, e_phnum;
505
	int ei_data, i;
506
507
	(void)lseek(dl->ldfd, (off_t) 0, SEEK_SET);
508
509
	if (read(dl->ldfd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
510
		return(-1);
511
512
	if (ehdr.e_ident[0] != ELFMAG0 ||
513
	    ehdr.e_ident[1] != ELFMAG1 ||
514
	    ehdr.e_ident[2] != ELFMAG2 ||
515
	    ehdr.e_ident[3] != ELFMAG3)
516
		return(-1);
517
518
	/* Must be Elf32... */
519
	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32)
520
		return(-1);
521
522
	ei_data = ehdr.e_ident[EI_DATA];
523
524
	switch (ei_data) {
525
	case ELFDATA2LSB:
526
		e_machine = mopFileGetLX((u_char *) &ehdr,
527
		    offsetof(Elf32_Ehdr, e_machine),
528
		    sizeof(ehdr.e_machine));
529
		e_entry = mopFileGetLX((u_char *) &ehdr,
530
		    offsetof(Elf32_Ehdr, e_entry),
531
		    sizeof(ehdr.e_entry));
532
533
		e_phoff = mopFileGetLX((u_char *) &ehdr,
534
		    offsetof(Elf32_Ehdr, e_phoff),
535
		    sizeof(ehdr.e_phoff));
536
		e_phentsize = mopFileGetLX((u_char *) &ehdr,
537
		    offsetof(Elf32_Ehdr, e_phentsize),
538
		    sizeof(ehdr.e_phentsize));
539
		e_phnum = mopFileGetLX((u_char *) &ehdr,
540
		    offsetof(Elf32_Ehdr, e_phnum),
541
		    sizeof(ehdr.e_phnum));
542
		break;
543
544
	case ELFDATA2MSB:
545
		e_machine = mopFileGetBX((u_char *) &ehdr,
546
		    offsetof(Elf32_Ehdr, e_machine),
547
		    sizeof(ehdr.e_machine));
548
		e_entry = mopFileGetBX((u_char *) &ehdr,
549
		    offsetof(Elf32_Ehdr, e_entry),
550
		    sizeof(ehdr.e_entry));
551
552
		e_phoff = mopFileGetBX((u_char *) &ehdr,
553
		    offsetof(Elf32_Ehdr, e_phoff),
554
		    sizeof(ehdr.e_phoff));
555
		e_phentsize = mopFileGetBX((u_char *) &ehdr,
556
		    offsetof(Elf32_Ehdr, e_phentsize),
557
		    sizeof(ehdr.e_phentsize));
558
		e_phnum = mopFileGetBX((u_char *) &ehdr,
559
		    offsetof(Elf32_Ehdr, e_phnum),
560
		    sizeof(ehdr.e_phnum));
561
		break;
562
563
	default:
564
		return(-1);
565
	}
566
567
	if (e_phnum > SEC_MAX)
568
		return(-1);
569
	dl->e_nsec = e_phnum;
570
	for (i = 0; i < dl->e_nsec; i++) {
571
		if (lseek(dl->ldfd, (off_t) e_phoff + (i * e_phentsize),
572
		    SEEK_SET) == (off_t) -1)
573
			return(-1);
574
		if (read(dl->ldfd, (char *) &phdr, sizeof(phdr)) !=
575
		    sizeof(phdr))
576
			return(-1);
577
578
		switch (ei_data) {
579
		case ELFDATA2LSB:
580
			dl->e_sections[i].s_foff =
581
			    mopFileGetLX((u_char *) &phdr,
582
			    offsetof(Elf32_Phdr, p_offset),
583
			    sizeof(phdr.p_offset));
584
			dl->e_sections[i].s_vaddr =
585
			    mopFileGetLX((u_char *) &phdr,
586
			    offsetof(Elf32_Phdr, p_vaddr),
587
			    sizeof(phdr.p_vaddr));
588
			dl->e_sections[i].s_fsize =
589
			    mopFileGetLX((u_char *) &phdr,
590
			    offsetof(Elf32_Phdr, p_filesz),
591
			    sizeof(phdr.p_filesz));
592
			dl->e_sections[i].s_msize =
593
			    mopFileGetLX((u_char *) &phdr,
594
			    offsetof(Elf32_Phdr, p_memsz),
595
			    sizeof(phdr.p_memsz));
596
			break;
597
598
		case ELFDATA2MSB:
599
			dl->e_sections[i].s_foff =
600
			    mopFileGetBX((u_char *) &phdr,
601
			    offsetof(Elf32_Phdr, p_offset),
602
			    sizeof(phdr.p_offset));
603
			dl->e_sections[i].s_vaddr =
604
			    mopFileGetBX((u_char *) &phdr,
605
			    offsetof(Elf32_Phdr, p_vaddr),
606
			    sizeof(phdr.p_vaddr));
607
			dl->e_sections[i].s_fsize =
608
			    mopFileGetBX((u_char *) &phdr,
609
			    offsetof(Elf32_Phdr, p_filesz),
610
			    sizeof(phdr.p_filesz));
611
			dl->e_sections[i].s_msize =
612
			    mopFileGetBX((u_char *) &phdr,
613
			    offsetof(Elf32_Phdr, p_memsz),
614
			    sizeof(phdr.p_memsz));
615
			break;
616
617
		default:
618
			return(-1);
619
		}
620
	}
621
	/*
622
	 * In addition to padding between segments, this also
623
	 * takes care of memsz > filesz.
624
	 */
625
	for (i = 0; i < dl->e_nsec - 1; i++) {
626
		dl->e_sections[i].s_pad =
627
		    dl->e_sections[i + 1].s_vaddr -
628
		    (dl->e_sections[i].s_vaddr + dl->e_sections[i].s_fsize);
629
	}
630
	dl->e_sections[dl->e_nsec - 1].s_pad =
631
	    dl->e_sections[dl->e_nsec - 1].s_msize -
632
	    dl->e_sections[dl->e_nsec - 1].s_fsize;
633
	/*
634
	 * Now compute the logical offsets for each section.
635
	 */
636
	dl->e_sections[0].s_loff = 0;
637
	for (i = 1; i < dl->e_nsec; i++) {
638
		dl->e_sections[i].s_loff =
639
		    dl->e_sections[i - 1].s_loff +
640
		    dl->e_sections[i - 1].s_fsize +
641
		    dl->e_sections[i - 1].s_pad;
642
	}
643
644
	dl->image_type = IMAGE_TYPE_ELF32;
645
	dl->loadaddr = 0;
646
#if 0
647
	dl->xferaddr = e_entry;		/* will relocate itself if necessary */
648
#else
649
	dl->xferaddr = e_entry - dl->e_sections[0].s_vaddr;
650
#endif
651
652
	/* Print info about the image. */
653
	if (info == INFO_PRINT) {
654
		printf("Elf32 image (");
655
		switch (e_machine) {
656
#ifdef EM_VAX
657
		case EM_VAX:
658
			printf("VAX");
659
			break;
660
#endif
661
		default:
662
			printf("machine %d", e_machine);
663
			break;
664
		}
665
		printf(")\n");
666
		printf("Transfer Address:   %08x\n", dl->xferaddr);
667
		printf("Program Sections:   %d\n", dl->e_nsec);
668
		for (i = 0; i < dl->e_nsec; i++) {
669
			printf(" S%d File Size:      %08x\n", i,
670
			    dl->e_sections[i].s_fsize);
671
			printf(" S%d Pad Size:       %08x\n", i,
672
			    dl->e_sections[i].s_pad);
673
		}
674
	}
675
676
	dl->e_machine = e_machine;
677
678
	dl->e_curpos = 0;
679
	dl->e_cursec = 0;
680
681
	return(0);
682
#endif /* NOELF */
683
}
684
685
int
686
GetElf64FileInfo(struct dllist *dl, int info)
687
{
688
#if defined(NOELF) || defined(NOELF64)
689
	return(-1);
690
#else
691
	Elf64_Ehdr ehdr;
692
	Elf64_Phdr phdr;
693
	uint32_t e_machine;
694
	uint32_t e_phentsize, e_phnum;
695
	uint64_t e_entry, e_phoff;
696
	int ei_data, i;
697
698
	(void)lseek(dl->ldfd, (off_t) 0, SEEK_SET);
699
700
	if (read(dl->ldfd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
701
		return(-1);
702
703
	if (ehdr.e_ident[0] != ELFMAG0 ||
704
	    ehdr.e_ident[1] != ELFMAG1 ||
705
	    ehdr.e_ident[2] != ELFMAG2 ||
706
	    ehdr.e_ident[3] != ELFMAG3)
707
		return(-1);
708
709
	/* Must be Elf64... */
710
	if (ehdr.e_ident[EI_CLASS] != ELFCLASS64)
711
		return(-1);
712
713
	ei_data = ehdr.e_ident[EI_DATA];
714
715
	switch (ei_data) {
716
	case ELFDATA2LSB:
717
		e_machine = mopFileGetLX((u_char *) &ehdr,
718
		    offsetof(Elf64_Ehdr, e_machine),
719
		    sizeof(ehdr.e_machine));
720
		e_entry = mopFileGetLXX((u_char *) &ehdr,
721
		    offsetof(Elf64_Ehdr, e_entry),
722
		    sizeof(ehdr.e_entry));
723
724
		e_phoff = mopFileGetLXX((u_char *) &ehdr,
725
		    offsetof(Elf64_Ehdr, e_phoff),
726
		    sizeof(ehdr.e_phoff));
727
		e_phentsize = mopFileGetLX((u_char *) &ehdr,
728
		    offsetof(Elf64_Ehdr, e_phentsize),
729
		    sizeof(ehdr.e_phentsize));
730
		e_phnum = mopFileGetLX((u_char *) &ehdr,
731
		    offsetof(Elf64_Ehdr, e_phnum),
732
		    sizeof(ehdr.e_phnum));
733
		break;
734
735
	case ELFDATA2MSB:
736
		e_machine = mopFileGetBX((u_char *) &ehdr,
737
		    offsetof(Elf64_Ehdr, e_machine),
738
		    sizeof(ehdr.e_machine));
739
		e_entry = mopFileGetBXX((u_char *) &ehdr,
740
		    offsetof(Elf64_Ehdr, e_entry),
741
		    sizeof(ehdr.e_entry));
742
743
		e_phoff = mopFileGetBXX((u_char *) &ehdr,
744
		    offsetof(Elf64_Ehdr, e_phoff),
745
		    sizeof(ehdr.e_phoff));
746
		e_phentsize = mopFileGetBX((u_char *) &ehdr,
747
		    offsetof(Elf64_Ehdr, e_phentsize),
748
		    sizeof(ehdr.e_phentsize));
749
		e_phnum = mopFileGetBX((u_char *) &ehdr,
750
		    offsetof(Elf64_Ehdr, e_phnum),
751
		    sizeof(ehdr.e_phnum));
752
		break;
753
754
	default:
755
		return(-1);
756
	}
757
758
	if (e_phnum > SEC_MAX)
759
		return(-1);
760
	dl->e_nsec = e_phnum;
761
	for (i = 0; i < dl->e_nsec; i++) {
762
		if (lseek(dl->ldfd, (off_t) e_phoff + (i * e_phentsize),
763
		    SEEK_SET) == (off_t) -1)
764
			return(-1);
765
		if (read(dl->ldfd, (char *) &phdr, sizeof(phdr)) !=
766
		    sizeof(phdr))
767
			return(-1);
768
769
		switch (ei_data) {
770
		case ELFDATA2LSB:
771
			dl->e_sections[i].s_foff =
772
			    mopFileGetLX((u_char *) &phdr,
773
			    offsetof(Elf64_Phdr, p_offset),
774
			    sizeof(phdr.p_offset));
775
			dl->e_sections[i].s_vaddr =
776
			    mopFileGetLX((u_char *) &phdr,
777
			    offsetof(Elf64_Phdr, p_vaddr),
778
			    sizeof(phdr.p_vaddr));
779
			dl->e_sections[i].s_fsize =
780
			    mopFileGetLX((u_char *) &phdr,
781
			    offsetof(Elf64_Phdr, p_filesz),
782
			    sizeof(phdr.p_filesz));
783
			dl->e_sections[i].s_msize =
784
			    mopFileGetLX((u_char *) &phdr,
785
			    offsetof(Elf64_Phdr, p_memsz),
786
			    sizeof(phdr.p_memsz));
787
			break;
788
789
		case ELFDATA2MSB:
790
			dl->e_sections[i].s_foff =
791
			    mopFileGetBX((u_char *) &phdr,
792
			    offsetof(Elf64_Phdr, p_offset),
793
			    sizeof(phdr.p_offset));
794
			dl->e_sections[i].s_vaddr =
795
			    mopFileGetBX((u_char *) &phdr,
796
			    offsetof(Elf64_Phdr, p_vaddr),
797
			    sizeof(phdr.p_vaddr));
798
			dl->e_sections[i].s_fsize =
799
			    mopFileGetBX((u_char *) &phdr,
800
			    offsetof(Elf64_Phdr, p_filesz),
801
			    sizeof(phdr.p_filesz));
802
			dl->e_sections[i].s_msize =
803
			    mopFileGetBX((u_char *) &phdr,
804
			    offsetof(Elf64_Phdr, p_memsz),
805
			    sizeof(phdr.p_memsz));
806
			break;
807
808
		default:
809
			return(-1);
810
		}
811
	}
812
	/*
813
	 * In addition to padding between segments, this also
814
	 * takes care of memsz > filesz.
815
	 */
816
	for (i = 0; i < dl->e_nsec - 1; i++) {
817
		dl->e_sections[i].s_pad =
818
		    dl->e_sections[i + 1].s_vaddr -
819
		    (dl->e_sections[i].s_vaddr + dl->e_sections[i].s_fsize);
820
	}
821
	dl->e_sections[dl->e_nsec - 1].s_pad =
822
	    dl->e_sections[dl->e_nsec - 1].s_msize -
823
	    dl->e_sections[dl->e_nsec - 1].s_fsize;
824
	/*
825
	 * Now compute the logical offsets for each section.
826
	 */
827
	dl->e_sections[0].s_loff = 0;
828
	for (i = 1; i < dl->e_nsec; i++) {
829
		dl->e_sections[i].s_loff =
830
		    dl->e_sections[i - 1].s_loff +
831
		    dl->e_sections[i - 1].s_fsize +
832
		    dl->e_sections[i - 1].s_pad;
833
	}
834
835
	dl->image_type = IMAGE_TYPE_ELF64;
836
	dl->loadaddr = 0;
837
#if 0
838
	dl->xferaddr = e_entry;		/* will relocate itself if necessary */
839
#else
840
	dl->xferaddr = e_entry - dl->e_sections[0].s_vaddr;
841
#endif
842
843
	/* Print info about the image. */
844
	if (info == INFO_PRINT) {
845
		printf("Elf64 image (");
846
		switch (e_machine) {
847
#ifdef EM_ALPHA
848
		case EM_ALPHA:
849
#endif
850
#ifdef EM_ALPHA_EXP
851
		case EM_ALPHA_EXP:
852
#endif
853
#if defined(EM_ALPHA) || defined(EM_ALPHA_EXP)
854
			printf("ALPHA");
855
			break;
856
#endif
857
		default:
858
			printf("machine %d", e_machine);
859
			break;
860
		}
861
		printf(")\n");
862
		printf("Transfer Address:   %08x\n", dl->xferaddr);
863
		printf("Program Sections:   %d\n", dl->e_nsec);
864
		for (i = 0; i < dl->e_nsec; i++) {
865
			printf(" S%d File Size:      %08x\n", i,
866
			    dl->e_sections[i].s_fsize);
867
			printf(" S%d Pad Size:       %08x\n", i,
868
			    dl->e_sections[i].s_pad);
869
		}
870
	}
871
872
	dl->e_machine = e_machine;
873
874
	dl->e_curpos = 0;
875
	dl->e_cursec = 0;
876
877
	return(0);
878
#endif /* NOELF || NOELF64 */
879
}
880
881
int
882
CheckAOutFile(int fd)
883
{
884
#ifdef NOAOUT
885
	return(-1);
886
#else
887
	struct exec ex, ex_swap;
888
	int	mid = -1;
889
890
	if (read(fd, (char *)&ex, sizeof(ex)) != sizeof(ex))
891
		return(-1);
892
893
	(void)lseek(fd, (off_t) 0, SEEK_SET);
894
895
	if (read(fd, (char *)&ex_swap, sizeof(ex_swap)) != sizeof(ex_swap))
896
		return(-1);
897
898
	(void)lseek(fd, (off_t) 0, SEEK_SET);
899
900
	mid = getMID(mid, N_GETMID (ex));
901
902
	if (mid == -1) {
903
		mid = getMID(mid, N_GETMID (ex_swap));
904
	}
905
906
	if (mid != -1) {
907
		return(0);
908
	} else {
909
		return(-1);
910
	}
911
#endif /* NOAOUT */
912
}
913
914
int
915
GetAOutFileInfo(struct dllist *dl, int info)
916
{
917
#ifdef NOAOUT
918
	return(-1);
919
#else
920
	struct exec ex, ex_swap;
921
	u_int32_t	mid = -1;
922
	u_int32_t	magic, clbytes, clofset;
923
924
	if (read(dl->ldfd, (char *)&ex, sizeof(ex)) != sizeof(ex))
925
		return(-1);
926
927
	(void)lseek(dl->ldfd, (off_t) 0, SEEK_SET);
928
929
	if (read(dl->ldfd, (char *)&ex_swap,
930
		 sizeof(ex_swap)) != sizeof(ex_swap))
931
		return(-1);
932
933
	mopFileSwapX((u_char *)&ex_swap, 0, 4);
934
935
	mid = getMID(mid, N_GETMID (ex));
936
937
	if (mid == (uint32_t)-1) {
938
		mid = getMID(mid, N_GETMID (ex_swap));
939
		if (mid != (uint32_t)-1) {
940
			mopFileSwapX((u_char *)&ex, 0, 4);
941
		}
942
	}
943
944
	if (mid == (uint32_t)-1) {
945
		return(-1);
946
	}
947
948
	if (N_BADMAG (ex)) {
949
		return(-1);
950
	}
951
952
	switch (mid) {
953
	case MID_I386:
954
#ifdef MID_NS32532
955
	case MID_NS32532:
956
#endif
957
#ifdef MID_PMAX
958
	case MID_PMAX:
959
#endif
960
#ifdef MID_VAX
961
	case MID_VAX:
962
#endif
963
#ifdef MID_ALPHA
964
	case MID_ALPHA:
965
#endif
966
#ifdef MID_ARM6
967
	case MID_ARM6:
968
#endif
969
		ex.a_text  = mopFileGetLX((u_char *)&ex_swap,  4, 4);
970
		ex.a_data  = mopFileGetLX((u_char *)&ex_swap,  8, 4);
971
		ex.a_bss   = mopFileGetLX((u_char *)&ex_swap, 12, 4);
972
		ex.a_syms  = mopFileGetLX((u_char *)&ex_swap, 16, 4);
973
		ex.a_entry = mopFileGetLX((u_char *)&ex_swap, 20, 4);
974
		ex.a_trsize= mopFileGetLX((u_char *)&ex_swap, 24, 4);
975
		ex.a_drsize= mopFileGetLX((u_char *)&ex_swap, 28, 4);
976
		break;
977
#ifdef MID_M68K
978
	case MID_M68K:
979
#endif
980
#ifdef MID_M68K4K
981
	case MID_M68K4K:
982
#endif
983
	case MID_SPARC:
984
#ifdef MID_MIPS
985
	case MID_MIPS:
986
#endif
987
		ex.a_text  = mopFileGetBX((u_char *)&ex_swap,  4, 4);
988
		ex.a_data  = mopFileGetBX((u_char *)&ex_swap,  8, 4);
989
		ex.a_bss   = mopFileGetBX((u_char *)&ex_swap, 12, 4);
990
		ex.a_syms  = mopFileGetBX((u_char *)&ex_swap, 16, 4);
991
		ex.a_entry = mopFileGetBX((u_char *)&ex_swap, 20, 4);
992
		ex.a_trsize= mopFileGetBX((u_char *)&ex_swap, 24, 4);
993
		ex.a_drsize= mopFileGetBX((u_char *)&ex_swap, 28, 4);
994
		break;
995
	default:
996
		break;
997
	}
998
999
	if (info == INFO_PRINT) {
1000
		printf("a.out image (");
1001
		switch (N_GETMID (ex)) {
1002
		case MID_I386:
1003
			printf("i386");
1004
			break;
1005
#ifdef MID_M68K
1006
		case MID_M68K:
1007
			printf("m68k");
1008
			break;
1009
#endif
1010
#ifdef MID_M68K4K
1011
		case MID_M68K4K:
1012
			printf("m68k 4k");
1013
			break;
1014
#endif
1015
#ifdef MID_NS32532
1016
		case MID_NS32532:
1017
			printf("pc532");
1018
			break;
1019
#endif
1020
		case MID_SPARC:
1021
			printf("sparc");
1022
			break;
1023
#ifdef MID_PMAX
1024
		case MID_PMAX:
1025
			printf("pmax");
1026
			break;
1027
#endif
1028
#ifdef MID_VAX
1029
		case MID_VAX:
1030
			printf("vax");
1031
			break;
1032
#endif
1033
#ifdef MID_ALPHA
1034
		case MID_ALPHA:
1035
			printf("alpha");
1036
			break;
1037
#endif
1038
#ifdef MID_MIPS
1039
		case MID_MIPS:
1040
			printf("mips");
1041
			break;
1042
#endif
1043
#ifdef MID_ARM6
1044
		case MID_ARM6:
1045
			printf("arm32");
1046
			break;
1047
#endif
1048
		default:
1049
			break;
1050
		}
1051
		printf(") Magic: ");
1052
		switch (N_GETMAGIC (ex)) {
1053
		case OMAGIC:
1054
			printf("OMAGIC");
1055
			break;
1056
		case NMAGIC:
1057
			printf("NMAGIC");
1058
			break;
1059
		case ZMAGIC:
1060
			printf("ZMAGIC");
1061
			break;
1062
		case QMAGIC:
1063
			printf("QMAGIC");
1064
			break;
1065
		default:
1066
			printf("Unknown %ld", (long) N_GETMAGIC (ex));
1067
		}
1068
		printf("\n");
1069
		printf("Size of text:       %08lx\n", (long)ex.a_text);
1070
		printf("Size of data:       %08lx\n", (long)ex.a_data);
1071
		printf("Size of bss:        %08lx\n", (long)ex.a_bss);
1072
		printf("Size of symbol tab: %08lx\n", (long)ex.a_syms);
1073
		printf("Transfer Address:   %08lx\n", (long)ex.a_entry);
1074
		printf("Size of reloc text: %08lx\n", (long)ex.a_trsize);
1075
		printf("Size of reloc data: %08lx\n", (long)ex.a_drsize);
1076
	}
1077
1078
	magic = N_GETMAGIC (ex);
1079
	clbytes = getCLBYTES(mid);
1080
	clofset = clbytes - 1;
1081
1082
	dl->image_type = IMAGE_TYPE_AOUT;
1083
	dl->loadaddr = 0;
1084
	dl->xferaddr = ex.a_entry;
1085
1086
	dl->a_text = ex.a_text;
1087
	if (magic == ZMAGIC || magic == NMAGIC) {
1088
		dl->a_text_fill = clbytes - (ex.a_text & clofset);
1089
		if (dl->a_text_fill == clbytes)
1090
			dl->a_text_fill = 0;
1091
	} else
1092
		dl->a_text_fill = 0;
1093
	dl->a_data = ex.a_data;
1094
	if (magic == ZMAGIC || magic == NMAGIC) {
1095
		dl->a_data_fill = clbytes - (ex.a_data & clofset);
1096
		if (dl->a_data_fill == clbytes)
1097
			dl->a_data_fill = 0;
1098
	} else
1099
		dl->a_data_fill = 0;
1100
	dl->a_bss = ex.a_bss;
1101
	if (magic == ZMAGIC || magic == NMAGIC) {
1102
		dl->a_bss_fill = clbytes - (ex.a_bss & clofset);
1103
		if (dl->a_bss_fill == clbytes)
1104
			dl->a_bss_fill = 0;
1105
	} else {
1106
		dl->a_bss_fill = clbytes -
1107
		    ((ex.a_text+ex.a_data+ex.a_bss) & clofset);
1108
		if (dl->a_bss_fill == clbytes)
1109
			dl->a_bss_fill = 0;
1110
	}
1111
	dl->a_mid = mid;
1112
1113
	return(0);
1114
#endif /* NOAOUT */
1115
}
1116
1117
int
1118
GetFileInfo(struct dllist *dl, int info)
1119
{
1120
	int error;
1121
1122
	error = CheckElfFile(dl->ldfd);
1123
	if (error == 0) {
1124
		error = GetElf32FileInfo(dl, info);
1125
		if (error != 0)
1126
			error = GetElf64FileInfo(dl, info);
1127
		if (error != 0) {
1128
			return(-1);
1129
		}
1130
		return (0);
1131
	}
1132
1133
	error = CheckAOutFile(dl->ldfd);
1134
	if (error == 0) {
1135
		error = GetAOutFileInfo(dl, info);
1136
		if (error != 0) {
1137
			return(-1);
1138
		}
1139
		return (0);
1140
	}
1141
1142
	error = CheckMopFile(dl->ldfd);
1143
	if (error == 0) {
1144
		error = GetMopFileInfo(dl, info);
1145
		if (error != 0) {
1146
			return(-1);
1147
		}
1148
		return (0);
1149
	}
1150
1151
	/* Unknown file format. */
1152
	return(-1);
1153
}
1154
1155
ssize_t
1156
mopFileRead(struct dllist *dlslot, u_char *buf)
1157
{
1158
	ssize_t len, outlen;
1159
	int	bsz, sec;
1160
	int32_t	pos, notdone, total;
1161
	uint32_t secoff;
1162
1163
	switch (dlslot->image_type) {
1164
	case IMAGE_TYPE_MOP:
1165
		len = read(dlslot->ldfd,buf,dlslot->dl_bsz);
1166
		break;
1167
1168
	case IMAGE_TYPE_ELF32:
1169
	case IMAGE_TYPE_ELF64:
1170
		sec = dlslot->e_cursec;
1171
1172
		/*
1173
		 * We're pretty simplistic here.  We do only file-backed
1174
		 * or only zero-fill.
1175
		 */
1176
1177
		/* Determine offset into section. */
1178
		secoff = dlslot->e_curpos - dlslot->e_sections[sec].s_loff;
1179
1180
		/*
1181
		 * If we're in the file-backed part of the section,
1182
		 * transmit some of the file.
1183
		 */
1184
		if (secoff < dlslot->e_sections[sec].s_fsize) {
1185
			bsz = dlslot->e_sections[sec].s_fsize - secoff;
1186
			if (bsz > dlslot->dl_bsz)
1187
				bsz = dlslot->dl_bsz;
1188
			if (lseek(dlslot->ldfd,
1189
			    dlslot->e_sections[sec].s_foff + secoff,
1190
			    SEEK_SET) == (off_t) -1)
1191
				return (-1);
1192
			len = read(dlslot->ldfd, buf, bsz);
1193
		}
1194
		/*
1195
		 * Otherwise, if we're in the zero-fill part of the
1196
		 * section, transmit some zeros.
1197
		 */
1198
		else if (secoff < (dlslot->e_sections[sec].s_fsize +
1199
				   dlslot->e_sections[sec].s_pad)) {
1200
			bsz = dlslot->e_sections[sec].s_pad -
1201
			    (secoff - dlslot->e_sections[sec].s_fsize);
1202
			if (bsz > dlslot->dl_bsz)
1203
				bsz = dlslot->dl_bsz;
1204
			memset(buf, 0, (len = bsz));
1205
		}
1206
		/*
1207
		 * ...and if we haven't hit either of those cases,
1208
		 * that's the end of the image.
1209
		 */
1210
		else {
1211
			return (0);
1212
		}
1213
		/*
1214
		 * Advance the logical image pointer.
1215
		 */
1216
		dlslot->e_curpos += bsz;
1217
		if (dlslot->e_curpos >= (dlslot->e_sections[sec].s_loff +
1218
					 dlslot->e_sections[sec].s_fsize +
1219
					 dlslot->e_sections[sec].s_pad))
1220
			if (++sec != dlslot->e_nsec)
1221
				dlslot->e_cursec = sec;
1222
		break;
1223
1224
	case IMAGE_TYPE_AOUT:
1225
		bsz = dlslot->dl_bsz;
1226
		pos = dlslot->a_lseek;
1227
		len = 0;
1228
1229
		total = dlslot->a_text;
1230
1231
		if (pos < total) {
1232
			notdone = total - pos;
1233
			if (notdone <= bsz) {
1234
				outlen = read(dlslot->ldfd,&buf[len],notdone);
1235
			} else {
1236
				outlen = read(dlslot->ldfd,&buf[len],bsz);
1237
			}
1238
			len = len + outlen;
1239
			pos = pos + outlen;
1240
			bsz = bsz - outlen;
1241
		}
1242
1243
		total = total + dlslot->a_text_fill;
1244
1245
		if ((bsz > 0) && (pos < total)) {
1246
			notdone = total - pos;
1247
			if (notdone <= bsz) {
1248
				outlen = notdone;
1249
			} else {
1250
				outlen = bsz;
1251
			}
1252
			memset(&buf[len], 0, outlen);
1253
			len = len + outlen;
1254
			pos = pos + outlen;
1255
			bsz = bsz - outlen;
1256
		}
1257
1258
		total = total + dlslot->a_data;
1259
1260
		if ((bsz > 0) && (pos < total)) {
1261
			notdone = total - pos;
1262
			if (notdone <= bsz) {
1263
				outlen = read(dlslot->ldfd,&buf[len],notdone);
1264
			} else {
1265
				outlen = read(dlslot->ldfd,&buf[len],bsz);
1266
			}
1267
			len = len + outlen;
1268
			pos = pos + outlen;
1269
			bsz = bsz - outlen;
1270
		}
1271
1272
		total = total + dlslot->a_data_fill;
1273
1274
		if ((bsz > 0) && (pos < total)) {
1275
			notdone = total - pos;
1276
			if (notdone <= bsz) {
1277
				outlen = notdone;
1278
			} else {
1279
				outlen = bsz;
1280
			}
1281
			memset(&buf[len], 0, outlen);
1282
			len = len + outlen;
1283
			pos = pos + outlen;
1284
			bsz = bsz - outlen;
1285
		}
1286
1287
		total = total + dlslot->a_bss;
1288
1289
		if ((bsz > 0) && (pos < total)) {
1290
			notdone = total - pos;
1291
			if (notdone <= bsz) {
1292
				outlen = notdone;
1293
			} else {
1294
				outlen = bsz;
1295
			}
1296
			memset(&buf[len], 0, outlen);
1297
			len = len + outlen;
1298
			pos = pos + outlen;
1299
			bsz = bsz - outlen;
1300
		}
1301
1302
		total = total + dlslot->a_bss_fill;
1303
1304
		if ((bsz > 0) && (pos < total)) {
1305
			notdone = total - pos;
1306
			if (notdone <= bsz) {
1307
				outlen = notdone;
1308
			} else {
1309
				outlen = bsz;
1310
			}
1311
			memset(&buf[len], 0, outlen);
1312
			len = len + outlen;
1313
			pos = pos + outlen;
1314
			bsz = bsz - outlen;
1315
		}
1316
1317
		dlslot->a_lseek = pos;
1318
		break;
1319
1320
	default:
1321
		abort();
1322
	}
1323
1324
	return(len);
1325
}