elf2ecoff.c revision 1.5 1 1.5 thorpej /* $NetBSD: elf2ecoff.c,v 1.5 1997/06/16 22:10:27 thorpej Exp $ */
2 1.2 jonathan
3 1.1 jonathan /*
4 1.1 jonathan * Copyright (c) 1995
5 1.1 jonathan * Ted Lemon (hereinafter referred to as the author)
6 1.1 jonathan *
7 1.1 jonathan * Redistribution and use in source and binary forms, with or without
8 1.1 jonathan * modification, are permitted provided that the following conditions
9 1.1 jonathan * are met:
10 1.1 jonathan * 1. Redistributions of source code must retain the above copyright
11 1.1 jonathan * notice, this list of conditions and the following disclaimer.
12 1.1 jonathan * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jonathan * notice, this list of conditions and the following disclaimer in the
14 1.1 jonathan * documentation and/or other materials provided with the distribution.
15 1.1 jonathan * 3. The name of the author may not be used to endorse or promote products
16 1.1 jonathan * derived from this software without specific prior written permission.
17 1.1 jonathan *
18 1.1 jonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
19 1.1 jonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 1.1 jonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 1.1 jonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
22 1.1 jonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 1.1 jonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 1.1 jonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 1.1 jonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 1.1 jonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 1.1 jonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 1.1 jonathan * SUCH DAMAGE.
29 1.1 jonathan */
30 1.1 jonathan
31 1.1 jonathan /* elf2ecoff.c
32 1.1 jonathan
33 1.1 jonathan This program converts an elf executable to an ECOFF executable.
34 1.1 jonathan No symbol table is retained. This is useful primarily in building
35 1.1 jonathan net-bootable kernels for machines (e.g., DECstation and Alpha) which
36 1.1 jonathan only support the ECOFF object file format. */
37 1.1 jonathan
38 1.1 jonathan #include <sys/types.h>
39 1.1 jonathan #include <fcntl.h>
40 1.1 jonathan #include <unistd.h>
41 1.5 thorpej #include <sys/exec.h>
42 1.3 jonathan #include <sys/exec_elf.h>
43 1.3 jonathan #include <sys/exec_aout.h>
44 1.1 jonathan #include <stdio.h>
45 1.1 jonathan #include <sys/exec_ecoff.h>
46 1.1 jonathan #include <sys/errno.h>
47 1.1 jonathan #include <string.h>
48 1.1 jonathan #include <limits.h>
49 1.1 jonathan
50 1.3 jonathan
51 1.3 jonathan /* Elf Program segment permissions, in program header flags field */
52 1.3 jonathan
53 1.3 jonathan #define PF_X (1 << 0) /* Segment is executable */
54 1.3 jonathan #define PF_W (1 << 1) /* Segment is writable */
55 1.3 jonathan #define PF_R (1 << 2) /* Segment is readable */
56 1.3 jonathan #define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */
57 1.3 jonathan
58 1.1 jonathan struct sect {
59 1.1 jonathan unsigned long vaddr;
60 1.1 jonathan unsigned long len;
61 1.1 jonathan };
62 1.1 jonathan
63 1.1 jonathan int phcmp ();
64 1.1 jonathan char *saveRead (int file, off_t offset, off_t len, char *name);
65 1.1 jonathan int copy (int, int, off_t, off_t);
66 1.1 jonathan int translate_syms (int, int, off_t, off_t, off_t, off_t);
67 1.1 jonathan extern int errno;
68 1.1 jonathan int *symTypeTable;
69 1.1 jonathan
70 1.1 jonathan main (int argc, char **argv, char **envp)
71 1.1 jonathan {
72 1.3 jonathan Elf32_Ehdr ex;
73 1.3 jonathan Elf32_Phdr *ph;
74 1.3 jonathan Elf32_Shdr *sh;
75 1.3 jonathan Elf32_Sym *symtab;
76 1.1 jonathan char *shstrtab;
77 1.1 jonathan int strtabix, symtabix;
78 1.1 jonathan int i, pad;
79 1.1 jonathan struct sect text, data, bss;
80 1.2 jonathan struct ecoff_exechdr ep;
81 1.1 jonathan struct ecoff_scnhdr esecs [3];
82 1.1 jonathan int infile, outfile;
83 1.1 jonathan unsigned long cur_vma = ULONG_MAX;
84 1.1 jonathan int symflag = 0;
85 1.1 jonathan
86 1.1 jonathan text.len = data.len = bss.len = 0;
87 1.1 jonathan text.vaddr = data.vaddr = bss.vaddr = 0;
88 1.1 jonathan
89 1.1 jonathan /* Check args... */
90 1.1 jonathan if (argc < 3 || argc > 4)
91 1.1 jonathan {
92 1.1 jonathan usage:
93 1.1 jonathan fprintf (stderr,
94 1.1 jonathan "usage: elf2aout <elf executable> <a.out executable> [-s]\n");
95 1.1 jonathan exit (1);
96 1.1 jonathan }
97 1.1 jonathan if (argc == 4)
98 1.1 jonathan {
99 1.1 jonathan if (strcmp (argv [3], "-s"))
100 1.1 jonathan goto usage;
101 1.1 jonathan symflag = 1;
102 1.1 jonathan }
103 1.1 jonathan
104 1.1 jonathan /* Try the input file... */
105 1.1 jonathan if ((infile = open (argv [1], O_RDONLY)) < 0)
106 1.1 jonathan {
107 1.1 jonathan fprintf (stderr, "Can't open %s for read: %s\n",
108 1.1 jonathan argv [1], strerror (errno));
109 1.1 jonathan exit (1);
110 1.1 jonathan }
111 1.1 jonathan
112 1.1 jonathan /* Read the header, which is at the beginning of the file... */
113 1.1 jonathan i = read (infile, &ex, sizeof ex);
114 1.1 jonathan if (i != sizeof ex)
115 1.1 jonathan {
116 1.1 jonathan fprintf (stderr, "ex: %s: %s.\n",
117 1.1 jonathan argv [1], i ? strerror (errno) : "End of file reached");
118 1.1 jonathan exit (1);
119 1.1 jonathan }
120 1.1 jonathan
121 1.1 jonathan /* Read the program headers... */
122 1.3 jonathan ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
123 1.3 jonathan ex.e_phnum * sizeof (Elf32_Phdr), "ph");
124 1.1 jonathan /* Read the section headers... */
125 1.3 jonathan sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
126 1.3 jonathan ex.e_shnum * sizeof (Elf32_Shdr), "sh");
127 1.1 jonathan /* Read in the section string table. */
128 1.3 jonathan shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
129 1.3 jonathan sh [ex.e_shstrndx].sh_size, "shstrtab");
130 1.1 jonathan
131 1.1 jonathan /* Figure out if we can cram the program header into an ECOFF
132 1.1 jonathan header... Basically, we can't handle anything but loadable
133 1.1 jonathan segments, but we can ignore some kinds of segments. We can't
134 1.1 jonathan handle holes in the address space. Segments may be out of order,
135 1.1 jonathan so we sort them first. */
136 1.1 jonathan
137 1.3 jonathan qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);
138 1.1 jonathan
139 1.3 jonathan for (i = 0; i < ex.e_phnum; i++)
140 1.1 jonathan {
141 1.1 jonathan /* Section types we can ignore... */
142 1.3 jonathan if (ph [i].p_type == Elf_pt_null || ph [i].p_type == Elf_pt_note ||
143 1.3 jonathan ph [i].p_type == Elf_pt_phdr || ph [i].p_type == Elf_pt_mips_reginfo)
144 1.1 jonathan continue;
145 1.1 jonathan /* Section types we can't handle... */
146 1.3 jonathan else if (ph [i].p_type != Elf_pt_load)
147 1.1 jonathan {
148 1.1 jonathan fprintf (stderr, "Program header %d type %d can't be converted.\n");
149 1.1 jonathan exit (1);
150 1.1 jonathan }
151 1.1 jonathan /* Writable (data) segment? */
152 1.3 jonathan if (ph [i].p_flags & PF_W)
153 1.1 jonathan {
154 1.1 jonathan struct sect ndata, nbss;
155 1.1 jonathan
156 1.3 jonathan ndata.vaddr = ph [i].p_vaddr;
157 1.3 jonathan ndata.len = ph [i].p_filesz;
158 1.3 jonathan nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
159 1.3 jonathan nbss.len = ph [i].p_memsz - ph [i].p_filesz;
160 1.1 jonathan
161 1.1 jonathan combine (&data, &ndata, 0);
162 1.1 jonathan combine (&bss, &nbss, 1);
163 1.1 jonathan }
164 1.1 jonathan else
165 1.1 jonathan {
166 1.1 jonathan struct sect ntxt;
167 1.1 jonathan
168 1.3 jonathan ntxt.vaddr = ph [i].p_vaddr;
169 1.3 jonathan ntxt.len = ph [i].p_filesz;
170 1.1 jonathan
171 1.1 jonathan combine (&text, &ntxt);
172 1.1 jonathan }
173 1.1 jonathan /* Remember the lowest segment start address. */
174 1.3 jonathan if (ph [i].p_vaddr < cur_vma)
175 1.3 jonathan cur_vma = ph [i].p_vaddr;
176 1.1 jonathan }
177 1.1 jonathan
178 1.1 jonathan /* Sections must be in order to be converted... */
179 1.1 jonathan if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
180 1.1 jonathan text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
181 1.1 jonathan {
182 1.1 jonathan fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
183 1.1 jonathan exit (1);
184 1.1 jonathan }
185 1.1 jonathan
186 1.1 jonathan /* If there's a data section but no text section, then the loader
187 1.1 jonathan combined everything into one section. That needs to be the
188 1.1 jonathan text section, so just make the data section zero length following
189 1.1 jonathan text. */
190 1.1 jonathan if (data.len && !text.len)
191 1.1 jonathan {
192 1.1 jonathan text = data;
193 1.1 jonathan data.vaddr = text.vaddr + text.len;
194 1.1 jonathan data.len = 0;
195 1.1 jonathan }
196 1.1 jonathan
197 1.1 jonathan /* If there is a gap between text and data, we'll fill it when we copy
198 1.1 jonathan the data, so update the length of the text segment as represented in
199 1.1 jonathan a.out to reflect that, since a.out doesn't allow gaps in the program
200 1.1 jonathan address space. */
201 1.1 jonathan if (text.vaddr + text.len < data.vaddr)
202 1.1 jonathan text.len = data.vaddr - text.vaddr;
203 1.1 jonathan
204 1.1 jonathan /* We now have enough information to cons up an a.out header... */
205 1.2 jonathan ep.a.magic = ECOFF_OMAGIC;
206 1.2 jonathan ep.a.vstamp = 200;
207 1.2 jonathan ep.a.tsize = text.len;
208 1.2 jonathan ep.a.dsize = data.len;
209 1.2 jonathan ep.a.bsize = bss.len;
210 1.3 jonathan ep.a.entry = ex.e_entry;
211 1.2 jonathan ep.a.text_start = text.vaddr;
212 1.2 jonathan ep.a.data_start = data.vaddr;
213 1.2 jonathan ep.a.bss_start = bss.vaddr;
214 1.2 jonathan ep.a.gprmask = 0xf3fffffe;
215 1.2 jonathan bzero (&ep.a.cprmask, sizeof ep.a.cprmask);
216 1.2 jonathan ep.a.gp_value = 0; /* unused. */
217 1.2 jonathan
218 1.2 jonathan ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
219 1.2 jonathan ep.f.f_nscns = 3;
220 1.2 jonathan ep.f.f_timdat = 0; /* bogus */
221 1.2 jonathan ep.f.f_symptr = 0;
222 1.2 jonathan ep.f.f_nsyms = 0;
223 1.2 jonathan ep.f.f_opthdr = sizeof ep.a;
224 1.2 jonathan ep.f.f_flags = 0x100f; /* Stripped, not sharable. */
225 1.2 jonathan
226 1.2 jonathan strcpy (esecs [0].s_name, ".text");
227 1.2 jonathan strcpy (esecs [1].s_name, ".data");
228 1.2 jonathan strcpy (esecs [2].s_name, ".bss");
229 1.2 jonathan esecs [0].s_paddr = esecs [0].s_vaddr = ep.a.text_start;
230 1.2 jonathan esecs [1].s_paddr = esecs [1].s_vaddr = ep.a.data_start;
231 1.2 jonathan esecs [2].s_paddr = esecs [2].s_vaddr = ep.a.bss_start;
232 1.2 jonathan esecs [0].s_size = ep.a.tsize;
233 1.2 jonathan esecs [1].s_size = ep.a.dsize;
234 1.2 jonathan esecs [2].s_size = ep.a.bsize;
235 1.2 jonathan
236 1.2 jonathan esecs [0].s_scnptr = ECOFF_TXTOFF (&ep);
237 1.2 jonathan esecs [1].s_scnptr = ECOFF_DATOFF (&ep);
238 1.2 jonathan esecs [2].s_scnptr = esecs [1].s_scnptr +
239 1.2 jonathan ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&ep));
240 1.2 jonathan esecs [0].s_relptr = esecs [1].s_relptr
241 1.2 jonathan = esecs [2].s_relptr = 0;
242 1.2 jonathan esecs [0].s_lnnoptr = esecs [1].s_lnnoptr
243 1.2 jonathan = esecs [2].s_lnnoptr = 0;
244 1.2 jonathan esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;
245 1.2 jonathan esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;
246 1.2 jonathan esecs [0].s_flags = 0x20;
247 1.2 jonathan esecs [1].s_flags = 0x40;
248 1.2 jonathan esecs [2].s_flags = 0x82;
249 1.1 jonathan
250 1.1 jonathan /* Make the output file... */
251 1.1 jonathan if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
252 1.1 jonathan {
253 1.1 jonathan fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
254 1.1 jonathan exit (1);
255 1.1 jonathan }
256 1.1 jonathan
257 1.1 jonathan /* Write the headers... */
258 1.2 jonathan i = write (outfile, &ep.f, sizeof ep.f);
259 1.2 jonathan if (i != sizeof ep.f)
260 1.1 jonathan {
261 1.2 jonathan perror ("ep.f: write");
262 1.1 jonathan exit (1);
263 1.1 jonathan
264 1.1 jonathan for (i = 0; i < 6; i++)
265 1.1 jonathan {
266 1.1 jonathan printf ("Section %d: %s phys %x size %x file offset %x\n",
267 1.2 jonathan i, esecs [i].s_name, esecs [i].s_paddr,
268 1.2 jonathan esecs [i].s_size, esecs [i].s_scnptr);
269 1.1 jonathan }
270 1.1 jonathan }
271 1.1 jonathan fprintf (stderr, "wrote %d byte file header.\n", i);
272 1.1 jonathan
273 1.2 jonathan i = write (outfile, &ep.a, sizeof ep.a);
274 1.2 jonathan if (i != sizeof ep.a)
275 1.1 jonathan {
276 1.2 jonathan perror ("ep.a: write");
277 1.1 jonathan exit (1);
278 1.1 jonathan }
279 1.1 jonathan fprintf (stderr, "wrote %d byte a.out header.\n", i);
280 1.1 jonathan
281 1.1 jonathan i = write (outfile, &esecs, sizeof esecs);
282 1.1 jonathan if (i != sizeof esecs)
283 1.1 jonathan {
284 1.1 jonathan perror ("esecs: write");
285 1.1 jonathan exit (1);
286 1.1 jonathan }
287 1.1 jonathan fprintf (stderr, "wrote %d bytes of section headers.\n", i);
288 1.1 jonathan
289 1.2 jonathan if (pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15))
290 1.1 jonathan {
291 1.1 jonathan pad = 16 - pad;
292 1.1 jonathan i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
293 1.1 jonathan if (i < 0)
294 1.1 jonathan {
295 1.1 jonathan perror ("ipad: write");
296 1.1 jonathan exit (1);
297 1.1 jonathan }
298 1.1 jonathan fprintf (stderr, "wrote %d byte pad.\n", i);
299 1.1 jonathan }
300 1.1 jonathan
301 1.1 jonathan /* Copy the loadable sections. Zero-fill any gaps less than 64k;
302 1.1 jonathan complain about any zero-filling, and die if we're asked to zero-fill
303 1.1 jonathan more than 64k. */
304 1.3 jonathan for (i = 0; i < ex.e_phnum; i++)
305 1.1 jonathan {
306 1.1 jonathan /* Unprocessable sections were handled above, so just verify that
307 1.1 jonathan the section can be loaded before copying. */
308 1.3 jonathan if (ph [i].p_type == Elf_pt_load && ph [i].p_filesz)
309 1.1 jonathan {
310 1.3 jonathan if (cur_vma != ph [i].p_vaddr)
311 1.1 jonathan {
312 1.3 jonathan unsigned long gap = ph [i].p_vaddr - cur_vma;
313 1.1 jonathan char obuf [1024];
314 1.1 jonathan if (gap > 65536)
315 1.1 jonathan {
316 1.1 jonathan fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
317 1.1 jonathan gap);
318 1.1 jonathan exit (1);
319 1.1 jonathan }
320 1.1 jonathan fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
321 1.1 jonathan memset (obuf, 0, sizeof obuf);
322 1.1 jonathan while (gap)
323 1.1 jonathan {
324 1.1 jonathan int count = write (outfile, obuf, (gap > sizeof obuf
325 1.1 jonathan ? sizeof obuf : gap));
326 1.1 jonathan if (count < 0)
327 1.1 jonathan {
328 1.1 jonathan fprintf (stderr, "Error writing gap: %s\n",
329 1.1 jonathan strerror (errno));
330 1.1 jonathan exit (1);
331 1.1 jonathan }
332 1.1 jonathan gap -= count;
333 1.1 jonathan }
334 1.1 jonathan }
335 1.3 jonathan fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);
336 1.3 jonathan copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
337 1.3 jonathan cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
338 1.1 jonathan }
339 1.1 jonathan }
340 1.1 jonathan
341 1.1 jonathan /* Looks like we won... */
342 1.1 jonathan exit (0);
343 1.1 jonathan }
344 1.1 jonathan
345 1.1 jonathan copy (out, in, offset, size)
346 1.1 jonathan int out, in;
347 1.1 jonathan off_t offset, size;
348 1.1 jonathan {
349 1.1 jonathan char ibuf [4096];
350 1.1 jonathan int remaining, cur, count;
351 1.1 jonathan
352 1.1 jonathan /* Go the the start of the ELF symbol table... */
353 1.1 jonathan if (lseek (in, offset, SEEK_SET) < 0)
354 1.1 jonathan {
355 1.1 jonathan perror ("copy: lseek");
356 1.1 jonathan exit (1);
357 1.1 jonathan }
358 1.1 jonathan
359 1.1 jonathan remaining = size;
360 1.1 jonathan while (remaining)
361 1.1 jonathan {
362 1.1 jonathan cur = remaining;
363 1.1 jonathan if (cur > sizeof ibuf)
364 1.1 jonathan cur = sizeof ibuf;
365 1.1 jonathan remaining -= cur;
366 1.1 jonathan if ((count = read (in, ibuf, cur)) != cur)
367 1.1 jonathan {
368 1.1 jonathan fprintf (stderr, "copy: read: %s\n",
369 1.1 jonathan count ? strerror (errno) : "premature end of file");
370 1.1 jonathan exit (1);
371 1.1 jonathan }
372 1.1 jonathan if ((count = write (out, ibuf, cur)) != cur)
373 1.1 jonathan {
374 1.1 jonathan perror ("copy: write");
375 1.1 jonathan exit (1);
376 1.1 jonathan }
377 1.1 jonathan }
378 1.1 jonathan }
379 1.1 jonathan
380 1.1 jonathan /* Combine two segments, which must be contiguous. If pad is true, it's
381 1.1 jonathan okay for there to be padding between. */
382 1.1 jonathan combine (base, new, pad)
383 1.1 jonathan struct sect *base, *new;
384 1.1 jonathan int pad;
385 1.1 jonathan {
386 1.1 jonathan if (!base -> len)
387 1.1 jonathan *base = *new;
388 1.1 jonathan else if (new -> len)
389 1.1 jonathan {
390 1.1 jonathan if (base -> vaddr + base -> len != new -> vaddr)
391 1.1 jonathan {
392 1.1 jonathan if (pad)
393 1.1 jonathan base -> len = new -> vaddr - base -> vaddr;
394 1.1 jonathan else
395 1.1 jonathan {
396 1.1 jonathan fprintf (stderr,
397 1.1 jonathan "Non-contiguous data can't be converted.\n");
398 1.1 jonathan exit (1);
399 1.1 jonathan }
400 1.1 jonathan }
401 1.1 jonathan base -> len += new -> len;
402 1.1 jonathan }
403 1.1 jonathan }
404 1.1 jonathan
405 1.3 jonathan int
406 1.1 jonathan phcmp (h1, h2)
407 1.3 jonathan Elf32_Phdr *h1, *h2;
408 1.1 jonathan {
409 1.3 jonathan if (h1 -> p_vaddr > h2 -> p_vaddr)
410 1.1 jonathan return 1;
411 1.3 jonathan else if (h1 -> p_vaddr < h2 -> p_vaddr)
412 1.1 jonathan return -1;
413 1.1 jonathan else
414 1.1 jonathan return 0;
415 1.1 jonathan }
416 1.1 jonathan
417 1.1 jonathan char *saveRead (int file, off_t offset, off_t len, char *name)
418 1.1 jonathan {
419 1.1 jonathan char *tmp;
420 1.1 jonathan int count;
421 1.1 jonathan off_t off;
422 1.1 jonathan if ((off = lseek (file, offset, SEEK_SET)) < 0)
423 1.1 jonathan {
424 1.1 jonathan fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
425 1.1 jonathan exit (1);
426 1.1 jonathan }
427 1.1 jonathan if (!(tmp = (char *)malloc (len)))
428 1.1 jonathan {
429 1.1 jonathan fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
430 1.1 jonathan exit (1);
431 1.1 jonathan }
432 1.1 jonathan count = read (file, tmp, len);
433 1.1 jonathan if (count != len)
434 1.1 jonathan {
435 1.1 jonathan fprintf (stderr, "%s: read: %s.\n",
436 1.1 jonathan name, count ? strerror (errno) : "End of file reached");
437 1.1 jonathan exit (1);
438 1.1 jonathan }
439 1.1 jonathan return tmp;
440 1.1 jonathan }
441