Pristine Ack-5.5
[Ack-5.5.git] / util / grind / rd.c
1 /* $Id: rd.c,v 1.7 1994/06/24 11:00:57 ceriel Exp $ */
2
3 /* a.out file reading ... */
4
5 #include "rd.h"
6 #include "misc.h"
7 #include <assert.h>
8 #include <alloc.h>
9
10 #if defined(__sun)
11 #if ! defined(sun)
12 #define sun
13 #endif
14 #endif
15
16 #if defined(__i386)
17 #define i386
18 #endif
19
20 #if defined(__mc68020)
21 #define mc68020
22 #endif
23
24 #if defined(__sparc)
25 #if ! defined(sparc)
26 #define sparc
27 #endif
28 #endif
29
30 #if defined(__vax)
31 #define vax
32 #endif
33
34 #if defined(__solaris) || defined(__solaris__)
35 #define solaris
36 #endif
37
38 #if ! defined(solaris)
39 #if defined(sun) || defined(vax)
40
41 struct exec {
42 #ifdef sun
43         short a_x;
44         unsigned short  a_magic;
45 #else
46         unsigned long   a_magic;
47 #endif
48         unsigned long   a_text;
49         unsigned long   a_data;
50         unsigned long   a_bss;
51         unsigned long   a_syms;
52         unsigned long   a_entry;
53         unsigned long   a_trsize;
54         unsigned long   a_drsize;
55 };
56
57 #define OMAGIC  0407
58 #define NMAGIC  0410
59 #define ZMAGIC  0413
60
61 #define N_BADMAG(x) \
62         ((x).a_magic!=OMAGIC && (x).a_magic!=NMAGIC && (x).a_magic!=ZMAGIC)
63 #ifdef sun
64 #define N_TXTOFF(x)     ((x).a_magic == ZMAGIC ? 0 : sizeof(struct exec))
65 #else
66 #define N_TXTOFF(x)     (sizeof(struct exec))
67 #endif
68 #define N_STROFF(x)     (N_TXTOFF(x)+(x).a_text+(x).a_data+(x).a_trsize+(x).a_drsize+(x).a_syms)
69
70 #ifdef sparc
71 #define RELOC_SIZE      12
72 #else
73 #define RELOC_SIZE      8
74 #endif
75
76 struct nlist {
77         union {
78                 char    *n_name;
79                 long    n_strx;
80         } n_un;
81         unsigned char n_type;
82         char    n_other;
83         short   n_desc;
84         unsigned long n_value;
85 };
86
87 #define N_UNDF  0
88 #define N_ABS   2
89 #define N_TEXT  4
90 #define N_DATA  6
91 #define N_BSS   8
92 #define N_FN    0x1e
93
94 #define N_EXT   01
95
96 #define N_STAB  0xe0
97
98 #include <stdio.h>
99
100 static FILE *inf;
101 static struct exec bh;
102 static long seg_strings;
103 static struct outhead hh;
104
105 #define readf(a, b, c)  (fread((char *)(a), (b), (int)(c), inf))
106
107 int
108 rd_open(f)
109   char  *f;
110 {
111   if ((inf = fopen(f, "r")) == NULL) return 0;
112   return 1;
113 }
114
115 rd_ohead(h)
116   struct outhead        *h;
117 {
118   if (! readf(&bh, sizeof(struct exec), 1)) rd_fatal();
119   if (N_BADMAG(bh)) rd_fatal();
120
121   h->oh_magic = O_CONVERTED;
122   h->oh_stamp = 0;
123   h->oh_nsect = 4;
124   h->oh_nname = 3 + bh.a_syms / sizeof(struct nlist);
125   h->oh_nrelo = (bh.a_trsize + bh.a_drsize) / RELOC_SIZE;
126   h->oh_flags = h->oh_nrelo ? HF_LINK : 0;
127 #if defined(sun)
128   if (bh.a_magic == ZMAGIC) bh.a_text -= sizeof(struct exec);
129 #endif
130   h->oh_nemit = bh.a_text + bh.a_data;
131 #if defined(sun)
132   if (bh.a_magic == ZMAGIC) bh.a_text += sizeof(struct exec);
133 #endif
134   fseek(inf, N_STROFF(bh), 0);
135   h->oh_nchar = getw(inf) + 6 + 6 + 5 - 4; /* ".text", ".data", ".bss",
136                                               minus the size word */
137   seg_strings = h->oh_nchar - 17;
138   fseek(inf, N_TXTOFF(bh)+bh.a_text+bh.a_data, 0);
139   hh = *h;
140 #if defined(sun)
141   if (bh.a_magic == ZMAGIC) bh.a_text -= sizeof(struct exec);
142 #endif
143 }
144
145 /*ARGSUSED1*/
146 rd_name(names, count)
147   register struct outname       *names;
148   unsigned int          count;  /* ignored; complete namelist is read */
149 {
150   names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh);
151   names->on_desc = 0; names->on_type = S_MIN | S_SCT;
152   names++;
153   names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh) + 6;
154   names->on_desc = 0; names->on_type = (S_MIN+2) | S_SCT;
155   names++;
156   names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh) + 12;
157   names->on_desc = 0; names->on_type = (S_MIN+3) | S_SCT;
158   names++;
159   count = bh.a_syms / sizeof(struct nlist);
160   while (count > 0) {
161         struct nlist n;
162
163         if (! readf(&n, sizeof(struct nlist), 1)) rd_fatal();
164         count--;
165         names->on_desc = n.n_desc;
166         if (n.n_un.n_strx - 4 < 0) names->on_foff = 0;
167         else names->on_foff = OFF_CHAR(hh) - 4 + n.n_un.n_strx;
168         names->on_valu = n.n_value;
169
170         if (n.n_type & N_STAB) {
171                 names->on_type = n.n_type << 8;
172                 names++;
173                 continue;
174         }
175         switch(n.n_type & ~N_EXT) {
176         case N_ABS:
177                 names->on_type = S_ABS;
178                 break;
179         case N_TEXT:
180                 names->on_type = S_MIN;
181                 break;
182         case N_DATA:
183                 names->on_type = S_MIN + 2;
184                 names->on_valu -= bh.a_text;
185                 break;
186         case N_BSS:
187                 names->on_type = S_MIN + 3;
188                 names->on_valu -= bh.a_text + bh.a_data;
189                 break;
190         case N_UNDF:
191                 if (! names->on_valu) {
192                         names->on_type = S_UND;
193                         break;
194                 }
195                 names->on_type = (S_MIN + 3) | S_COM;
196                 break;
197         case N_FN:
198                 names->on_type = S_FIL;
199                 break;
200         default:
201                 rd_fatal();
202         }
203         if (n.n_type & N_EXT) names->on_type |= S_EXT;
204         names++;
205   }
206 }
207
208 extern char     *strcpy();
209
210 rd_string(strings, count)
211   register char *strings;
212   long  count;
213 {
214 #if defined(sun)
215   if (bh.a_magic == ZMAGIC) bh.a_text += sizeof(struct exec);
216 #endif
217   fseek(inf, N_STROFF(bh)+4, 0);
218   if (! readf(strings, (int)count-17, 1)) rd_fatal();
219   strings += count-17;
220   strcpy(strings, ".text"); strings += 6;
221   strcpy(strings, ".data"); strings += 6;
222   strcpy(strings, ".bss");
223 }
224
225 rd_close()
226 {
227   fclose(inf);
228 }
229
230 #endif
231 #endif
232
233 #if defined(i386)
234 #include <stdio.h>
235 #include <alloc.h>
236
237 struct xexec {
238         unsigned short  x_magic;
239 #define XMAGIC  01006
240         unsigned short  x_ext;
241         long            x_text;
242         long            x_data;
243         long            x_bss;
244         long            x_syms;
245         long            x_reloc;
246         long            x_entry;
247         char            x_cpu;
248         char            x_relsym;
249         unsigned short  x_renv;
250 };
251
252 struct xseg {
253         unsigned short  xs_type;
254         unsigned short  xs_attr;
255         unsigned short  xs_seg;
256         unsigned short  xs_sres;
257         long            xs_filpos;
258         long            xs_psize;
259         long            xs_vsize;
260         long            xs_rbase;
261         long            xs_lres;
262         long            xs_lres2;
263 };
264
265 static FILE *inf;
266 static struct outname *names;
267 static char *strings;
268
269 #define readf(a, b, c)  (fread((char *)(a), (b), (int)(c), inf))
270
271 #define getshort(val, p)        (val = (*p++ & 0377), val |= (*p++ & 0377) << 8)
272 #define getlong(val, p)         (val = (*p++ & 0377), \
273                                  val |= (*p++ & 0377) << 8, \
274                                  val |= (*p++ & 0377L) << 16, \
275                                  val |= (*p++ & 0377L) << 24)
276 static 
277 get_names(h, sz)
278   struct outhead        *h;
279   long sz;
280 {
281   register char *xnms = malloc((unsigned) sz);
282   register char *p;
283   register struct outname *onm = (struct outname *) malloc((((unsigned)sz+8)/9)*sizeof(struct outname));
284   struct  xnm {
285         unsigned short s_type, s_seg;
286         long    s_value;
287   } xnm;
288
289   if (xnms == 0 || onm == 0) No_Mem();
290   if (!readf(xnms, (unsigned) sz, 1)) rd_fatal();
291
292   names = onm;
293   strings = p = xnms;
294   while (sz > 0) {
295         getshort(xnm.s_type, xnms);
296         getshort(xnm.s_seg, xnms);
297         getlong(xnm.s_value, xnms);
298         onm->on_desc = 0;
299         if (xnm.s_type & S_STB) {
300                 onm->on_type = xnm.s_type;
301                 onm->on_desc = xnm.s_seg;
302         }
303         else {
304                 switch(xnm.s_type & 0x1f) {
305                 case 0x1f:
306                         onm->on_type = S_FIL;
307                         break;
308                 case 0x8:
309                         onm->on_type = S_SCT;
310                         break;
311                 case 0:
312                         onm->on_type = S_UND;
313                         break;
314                 case 1:
315                         onm->on_type = S_ABS;
316                         break;
317                 default:
318                         onm->on_type = xnm.s_type & 0x1f;
319                         break;
320                 }
321         }
322         if (xnm.s_type & 0x20) onm->on_type |= S_EXT;
323         onm->on_valu = xnm.s_value;
324         sz -= 9;
325         if (*xnms == '\0') {
326                 onm->on_foff = -1;
327                 xnms++;
328         }
329         else {
330                 onm->on_foff = p - strings;
331                 while (*p++ = *xnms++)  sz--;
332         }
333         onm++;
334   }
335   h->oh_nname = onm - names;
336   h->oh_nchar = p - strings;
337   while (--onm >= names) {
338         if (onm->on_foff == -1) onm->on_foff = 0;
339         else onm->on_foff += OFF_CHAR(*h);
340   }
341   names = (struct outname *) realloc((char *) names, h->oh_nname * sizeof(struct outname));
342   strings = realloc(strings, (unsigned) h->oh_nchar);
343 }
344
345 int
346 rd_open(f)
347   char  *f;
348 {
349   if ((inf = fopen(f, "r")) == NULL) return 0;
350   return 1;
351 }
352
353 rd_ohead(h)
354   struct outhead        *h;
355 {
356   int sepid;
357   struct xexec xhdr;
358   struct xseg xseg[3];
359
360   if (! readf(&xhdr, sizeof(xhdr), 1)) rd_fatal();
361   if (xhdr.x_magic != XMAGIC) rd_fatal();
362   h->oh_magic = O_CONVERTED;
363   h->oh_stamp = 0;
364   h->oh_nsect = 4;
365   h->oh_nrelo = 0;
366   h->oh_flags = 0;
367   h->oh_nemit = xhdr.x_text+xhdr.x_data;
368   sepid = (xhdr.x_renv & 02) ? 1 : 0;
369   fseek(inf, 0140L, 0);
370   if (! readf(&xseg[0], sizeof(xseg[0]), sepid + 2)) rd_fatal();
371   fseek(inf, xseg[sepid+1].xs_filpos, 0);
372   get_names(h, xhdr.x_syms);
373   fclose(inf);
374 }
375
376 rd_name(nm, count)
377   struct outname        *nm;
378   unsigned int          count;
379 {
380   memcpy(nm, names, (int) count * sizeof(struct outname));
381   free((char *) names);
382 }
383
384 rd_string(nm, count)
385   char          *nm;
386   long          count;
387 {
388   memcpy(nm, strings, (int) count);
389   free((char *) strings);
390 }
391
392 rd_close()
393 {
394 }
395 #endif
396
397 #if defined(solaris)
398 #include <libelf.h>
399 #include <sys/elf_M32.h>
400 #include <stb.h>
401
402 struct nlist {
403         union {
404                 char    *n_name;
405                 long    n_strx;
406         } n_un;
407         unsigned char n_type;
408         char    n_other;
409         short   n_desc;
410         unsigned long n_value;
411 };
412
413 static int fildes;
414 static Elf *elf;
415 static Elf32_Ehdr *ehdr;
416 static struct nlist *dbtab;
417 static char *dbstringtab;
418 static Elf32_Sym *tab;
419 static char *stringtab;
420 static struct outhead hh;
421 static struct nlist *maxdn;
422
423 #define N_STAB  0xe0
424
425 int
426 rd_open(f)
427   char  *f;
428 {
429   if ((fildes = open(f, 0)) < 0) return 0;
430   elf_version(EV_CURRENT);
431   if ((elf = elf_begin(fildes, ELF_C_READ, (Elf *) 0)) == 0) {
432         close(fildes);
433         return 0;
434   }
435   if ((ehdr = elf32_getehdr(elf)) == NULL) {
436         elf_end(elf);
437         close(fildes);
438         return 0;
439   }
440   return 1;
441 }
442
443 rd_ohead(h)
444   struct outhead        *h;
445 {
446   Elf_Scn *scn = 0;
447   Elf32_Shdr *shdr;
448   Elf_Data *sectnames;
449   Elf_Data *dt;
450   register struct nlist *dn;
451   register Elf32_Sym *n;
452   long text_offset, data_offset, bss_offset, fun_offset;
453   int fixnamoff = 0, newfixnamoff = 0;
454
455   h->oh_magic = O_CONVERTED;
456   h->oh_stamp = 0;
457   h->oh_nsect = 4;
458   h->oh_nrelo = 0;
459   h->oh_flags = 0;
460   h->oh_nemit = 0;
461   h->oh_nname = 0;
462
463   scn = elf_getscn(elf, (size_t) ehdr->e_shstrndx);
464   sectnames = elf_getdata(scn, (Elf_Data *) 0);
465
466   scn = 0;
467   while ((scn = elf_nextscn(elf, scn)) != 0) {
468         shdr = elf32_getshdr(scn);
469         switch(shdr->sh_type) {
470         case SHT_PROGBITS:
471                 /* Get stab symbol table. Elf does not know about it,
472                    and, unfortunately, no relocation is done on it.
473                 */
474                 h->oh_nemit += shdr->sh_size;
475                 if (! strcmp(".stab", (char *)(sectnames->d_buf)+shdr->sh_name)) {
476                         dt = elf_getdata(scn, (Elf_Data *) 0);
477                         if (dt->d_size == 0) {
478                                 fatal("(part of) symbol table is missing");
479                         }
480                         dbtab = (struct nlist *) Malloc(dt->d_size);
481                         memcpy((char *) dbtab, (char *) dt->d_buf, dt->d_size);
482                         maxdn = (struct nlist *)((char *)dbtab+dt->d_size);
483                         break;
484                 }
485                 break;
486
487         case SHT_STRTAB:
488                 /* Get the stab string table, as well as the usual string
489                    table.
490                 */
491                 if (! strcmp(".stabstr", (char *)(sectnames->d_buf)+shdr->sh_name)) {
492                         dt = elf_getdata(scn, (Elf_Data *) 0);
493                         if (dt->d_size == 0) {
494                                 fatal("(part of) symbol table is missing");
495                         }
496                         dbstringtab = dt->d_buf;
497                         h->oh_nchar = dt->d_size;
498                         break;
499                 }
500                 if (! strcmp(".strtab", (char *)(sectnames->d_buf)+shdr->sh_name)) {
501                         dt = elf_getdata(scn, (Elf_Data *) 0);
502                         if (dt->d_size == 0) {
503                                 fatal("(part of) symbol table is missing");
504                         }
505                         stringtab = dt->d_buf;
506                 }
507                 break;
508
509         case SHT_SYMTAB:
510                 /* Get the symbol table. */
511                 if (! strcmp(".symtab", (char *)(sectnames->d_buf)+shdr->sh_name)) {
512                         dt = elf_getdata(scn, (Elf_Data *) 0);
513                         if (dt->d_size == 0) {
514                                 fatal("(part of) symbol table is missing");
515                         }
516                         tab = dt->d_buf;
517                 }
518                 break;
519         }
520   }
521
522   /* Convert offsets in stab symbol table. */
523   n = tab;
524   dn = dbtab;
525   while (dn < maxdn) {
526         int i;
527
528         if (dn->n_un.n_strx) {
529                 dn->n_un.n_strx += fixnamoff;
530         }
531         switch(dn->n_type) {
532         case 0:
533                 fixnamoff = newfixnamoff;
534                 newfixnamoff += dn->n_value;
535                 break;
536
537         case N_SO:
538                 h->oh_nname++;
539                 i = 0;
540                 while (i < 3) {
541                         while (stringtab[n->st_name] != 'B') n++;
542                         if (! strcmp("Btext.text", &(stringtab[n->st_name]))) {
543                                 text_offset = n->st_value; i++;
544                         }
545                         else if (! strcmp("Bdata.data", &(stringtab[n->st_name]))) {
546                                 data_offset = n->st_value; i++;
547                         }
548                         else if (! strcmp("Bbss.bss", &(stringtab[n->st_name]))) {
549                                 bss_offset = n->st_value; i++;
550                         }
551                         n++;
552                 }
553                 break;
554
555         case N_GSYM:
556                 h->oh_nname++;
557                 /* Fortunately, we don't use this in ACK, so we don't
558                    have to handle it here. The problem is that we don't know
559                    which segment it comes from.
560                 */
561                 break;
562
563         case N_STSYM:
564                 h->oh_nname++;
565                 dn->n_value += data_offset;
566                 break;
567
568         case N_LCSYM:
569                 h->oh_nname++;
570                 dn->n_value += bss_offset;
571                 break;
572
573         case N_FUN:
574                 h->oh_nname++;
575                 dn->n_value += text_offset;
576                 fun_offset = dn->n_value;
577                 break;
578
579         case N_MAIN:
580                 dn->n_value += text_offset;
581                 break;
582
583         case N_LBRAC:
584         case N_RBRAC:
585         case N_SLINE:
586                 h->oh_nname++;
587                 dn->n_value += fun_offset;
588                 break;
589
590         case N_SOL:
591         case N_EINCL:
592         case N_BINCL:
593         case N_PSYM:
594         case N_SSYM:
595         case N_SCOPE:
596         case N_RSYM:
597         case N_LSYM:
598                 h->oh_nname++;
599                 /* Nothing to be done. */
600                 break;
601         }
602         dn++;
603   }
604   hh = *h;
605 }
606
607 rd_name(nm, count)
608   struct outname        *nm;
609   unsigned int          count;
610 {
611   register struct nlist *dn = dbtab;
612   register struct outname *n = nm;
613   while (dn < maxdn) {
614         if (dn->n_type & N_STAB) {
615                 n->on_type = dn->n_type << 8;
616                 n->on_valu = dn->n_value;
617                 n->on_desc = dn->n_desc;
618                 if (dn->n_un.n_strx == 0) n->on_foff = 0;
619                 else n->on_foff = OFF_CHAR(hh) + dn->n_un.n_strx;
620                 n++;
621         }
622         dn++;
623   }
624   free(dbtab);
625 }
626
627 rd_string(nm, count)
628   char          *nm;
629   long          count;
630 {
631   memcpy(nm, dbstringtab, count);
632 }
633
634 rd_close()
635 {
636   elf_end(elf);
637   close(fildes);
638 }
639
640 #endif