1 /* $OpenBSD: dl_prebind.c,v 1.1 2006/05/12 23:20:52 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/mman.h>
21 #include <sys/exec.h>
22 #include <sys/param.h>
23 #include <sys/sysctl.h>
24 #include <nlist.h>
25 #include <string.h>
26 #include <link.h>
27 #include <dlfcn.h>
28 #include <unistd.h>
29 
30 #include "syscall.h"
31 #include "archdep.h"
32 #include "resolve.h"
33 #include "sod.h"
34 #include "stdlib.h"
35 #include "dl_prebind.h"
36 
37 void elf_dump_footer(struct prebind_footer *footer);
38 void dump_prelink(Elf_Addr base, u_long size);
39 void prebind_dump_footer(struct prebind_footer *footer, char *file);
40 void prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt);
41 void prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numblibs,
42     char *nametab);
43 void prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups);
44 void prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs);
45 struct prebind_footer *_dl_prebind_data_to_footer(void *data);
46 
47 void *_dl_prog_prebind_map;
48 struct prebind_footer *prog_footer;
49 extern char *_dl_noprebind;
50 extern char *_dl_prebind_validate;
51 
52 int _dl_prebind_match_failed; /* = 0 */
53 
54 char *prebind_bind_now = "prebind";
55 
56 struct prebind_footer *
_dl_prebind_data_to_footer(void * prebind_data)57 _dl_prebind_data_to_footer(void *prebind_data)
58 {
59 	u_int32_t *poffset, offset;
60 	struct prebind_footer *footer;
61 	char *c;
62 
63 	poffset = prebind_data;
64 	c = prebind_data;
65 	offset = *poffset;
66 	c += offset;
67 	footer = (void *)c;
68 	return footer;
69 }
70 
71 void
prebind_load_exe(Elf_Phdr * phdp,elf_object_t * exe_obj)72 prebind_load_exe(Elf_Phdr *phdp, elf_object_t *exe_obj)
73 {
74 	struct prebind_footer *footer;
75 
76 	exe_obj->prebind_data = (void *)phdp->p_vaddr;
77 	_dl_prog_prebind_map = exe_obj->prebind_data;
78 
79 	footer = _dl_prebind_data_to_footer(_dl_objects->prebind_data);
80 
81 	if (footer->bind_id[0] == BIND_ID0 &&
82 	    footer->bind_id[1] == BIND_ID1 &&
83 	    footer->bind_id[2] == BIND_ID2 &&
84 	    footer->bind_id[3] == BIND_ID3 &&
85 	    footer->prebind_version == PREBIND_VERSION) {
86 		prog_footer = footer;
87 		if (_dl_bindnow == NULL)
88 			_dl_bindnow = prebind_bind_now;
89 	} else {
90 		DL_DEB(("prebind data missing\n"));
91 		_dl_prog_prebind_map = NULL;
92 	}
93 	if (_dl_noprebind != NULL) {
94 		/*prog_footer is valid, we should free it */
95 		_dl_prog_prebind_map = NULL;
96 		prog_footer = NULL;
97 		exe_obj->prebind_data = NULL;
98 		if (_dl_bindnow == prebind_bind_now)
99 			_dl_bindnow = NULL;
100 	}
101 #if 0
102 	else if (_dl_debug)
103 		dump_prelink((long)_dl_prog_prebind_map,
104 		    prog_footer->prebind_size);
105 #endif
106 }
107 
108 void *
prebind_load_fd(int fd,const char * name)109 prebind_load_fd(int fd, const char *name)
110 {
111 	struct prebind_footer footer;
112 	struct nameidx *nameidx;
113 	void *prebind_data;
114 	char *nametab;
115 	ssize_t len;
116 	int idx;
117 
118 	if (_dl_prog_prebind_map == NULL || _dl_prebind_match_failed)
119 		return 0;
120 
121 	_dl_lseek(fd, -(off_t)sizeof(struct prebind_footer), SEEK_END);
122 	len = _dl_read(fd, (void *)&footer, sizeof(struct prebind_footer));
123 
124 	if (len != sizeof(struct prebind_footer) ||
125 	    footer.bind_id[0] != BIND_ID0 ||
126 	    footer.bind_id[1] != BIND_ID1 ||
127 	    footer.bind_id[2] != BIND_ID2 ||
128 	    footer.bind_id[3] != BIND_ID3 ||
129 	    footer.prebind_version != PREBIND_VERSION) {
130 		_dl_prebind_match_failed = 1;
131 		DL_DEB(("prebind match failed %s\n", name));
132 		return (NULL);
133 	}
134 
135 	prebind_data = _dl_mmap(0, footer.prebind_size, PROT_READ,
136 	    MAP_FILE, fd, footer.prebind_base);
137 	DL_DEB(("prebind_load_fd for lib %s\n", name));
138 
139 	nameidx = _dl_prog_prebind_map + prog_footer->nameidx_idx;
140 	nametab = _dl_prog_prebind_map + prog_footer->nametab_idx;
141 
142 	/* libraries are loaded in random order, so we just have
143 	 * to look thru the list to find ourselves
144 	 */
145 	for (idx = 0; idx < prog_footer->numlibs; idx++) {
146 		if (_dl_strcmp(nametab + nameidx[idx].name, name) == 0)
147 			break;
148 	}
149 
150 	if (idx == prog_footer->numlibs) {
151 		_dl_prebind_match_failed = 1; /* not found */
152 	} else if (footer.id0 != nameidx[idx].id0 ||
153 	    footer.id1 != nameidx[idx].id1) {
154 		_dl_prebind_match_failed = 1;
155 		DL_DEB(("prebind match id0 %d pid0 %d id1 %d pid1 %d\n",
156 		    footer.id0, nameidx[idx].id0,
157 		    footer.id1, nameidx[idx].id1));
158 	}
159 
160 	if (_dl_prebind_match_failed == 1) {
161 		DL_DEB(("prebind match failed for %s\n", name));
162 	}
163 
164 	return prebind_data;
165 }
166 #define NUM_STATIC_OBJS 10
167 elf_object_t *objarray_static[NUM_STATIC_OBJS];
168 elf_object_t **objarray;
169 
170 void
prebind_symcache(elf_object_t * object,int plt)171 prebind_symcache(elf_object_t *object, int plt)
172 {
173 	u_int32_t *fixupidx, *fixupcnt, *libmap, *idxtolib;
174 	u_int32_t *poffset, offset, symcache_cnt;
175 	struct symcachetab *symcachetab;
176 	struct prebind_footer *footer;
177 	int i = 0, cur_obj = -1, idx;
178 	void *prebind_map;
179 	struct nameidx *nameidx;
180 	char *nametab, *c;
181 	struct fixup *fixup;
182 	elf_object_t *obj;
183 
184 	struct symcachetab *s;
185 
186 	if (object->prebind_data == NULL)
187 		return;
188 //	DL_DEB(("prebind symcache %s\n", object->load_name));
189 
190 	obj = _dl_objects;
191 	while (obj != NULL) {
192 		if (obj == object)
193 			cur_obj = i;
194 		i++;
195 		obj = obj->next;
196 	}
197 
198 	if (cur_obj == -1)
199 		return;	/* unable to find object ? */
200 
201 	if (objarray == NULL) {
202 		if (i <= NUM_STATIC_OBJS) {
203 			objarray = &objarray_static[0];
204 		} else {
205 			objarray = _dl_malloc(sizeof(elf_object_t *) * i);
206 		}
207 
208 		obj = _dl_objects;
209 		i = 0;
210 		while (obj != NULL) {
211 			objarray[i] = obj;
212 			i++;
213 			obj = obj->next;
214 		}
215 	}
216 
217 	poffset = (u_int32_t *)object->prebind_data;
218 	c = object->prebind_data;
219 	offset = *poffset;
220 	c += offset;
221 
222 	footer = (void *)c;
223 	prebind_map = (void *)object->prebind_data;
224 	nameidx = prebind_map + footer->nameidx_idx;;
225 	if (plt) {
226 		symcachetab = prebind_map + footer->pltsymcache_idx;
227 		symcache_cnt = footer->pltsymcache_cnt;
228 //		DL_DEB(("loading plt %d\n", symcache_cnt));
229 	} else {
230 		symcachetab = prebind_map + footer->symcache_idx;
231 		symcache_cnt = footer->symcache_cnt;
232 //		DL_DEB(("loading got %d\n", symcache_cnt));
233 	}
234 	nametab = prebind_map + footer->nametab_idx;
235 
236 	libmap = _dl_prog_prebind_map + prog_footer->libmap_idx;
237 	idxtolib = _dl_prog_prebind_map + libmap[cur_obj];
238 
239 	for (i = 0; i < symcache_cnt; i++) {
240 		struct elf_object *tobj;
241 		const Elf_Sym *sym;
242 		const char *str;
243 
244 		s = &(symcachetab[i]);
245 		if (cur_obj == 0)
246 			idx = s->obj_idx;
247 		else
248 			idx = idxtolib[s->obj_idx];
249 
250 		if (idx == -1) /* somehow an invalid object ref happend */
251 			continue;
252 #if 0
253 		DL_DEB(("%s:", object->load_name));
254 		DL_DEB(("symidx %d: obj %d %d sym %d flags %x\n",
255 		    s->idx, s->obj_idx, idx, s->sym_idx,
256 		    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt));
257 #endif
258 		tobj = objarray[idx];
259 		sym = tobj->dyn.symtab + s->sym_idx;
260 		str = tobj->dyn.strtab + sym->st_name;
261 #ifdef DEBUG2
262 		DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
263 		    s->idx, s->obj_idx, tobj->load_name,
264 		    s->sym_idx, str, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
265 		    object->load_addr + sym->st_value));
266 #endif
267 		_dl_symcache[s->idx].obj = tobj;
268 		_dl_symcache[s->idx].sym = sym;
269 		_dl_symcache[s->idx].flags =
270 		    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
271 	}
272 
273 	if (!plt) {
274 		fixupidx = _dl_prog_prebind_map + prog_footer->fixup_idx;
275 		fixup = _dl_prog_prebind_map + fixupidx[2*cur_obj];
276 		fixupcnt = _dl_prog_prebind_map + prog_footer->fixupcnt_idx;
277 
278 		for (i = 0; i < fixupcnt[2*cur_obj]; i++) {
279 			struct fixup *f;
280 			struct elf_object *tobj;
281 			const Elf_Sym *sym;
282 			const char *str;
283 
284 			f = &(fixup[i]);
285 #if 0
286 			DL_DEB(("symidx %d: obj %d sym %d flags %x\n",
287 			    f->sym, f->obj_idx, f->sym_idx, f->flags));
288 #endif
289 			tobj = objarray[f->obj_idx];
290 			sym = tobj->dyn.symtab + f->sym_idx;
291 			str = tobj->dyn.strtab + sym->st_name;
292 #ifdef DEBUG2
293 			DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
294 			    f->sym, f->obj_idx, tobj->load_name,
295 			    f->sym_idx, str, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
296 			    object->load_addr + sym->st_value));
297 #endif
298 			_dl_symcache[f->sym].obj = tobj;
299 			_dl_symcache[f->sym].sym = sym;
300 			_dl_symcache[f->sym].flags =
301 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
302 		}
303 	} else {
304 
305 		fixupidx = _dl_prog_prebind_map + prog_footer->fixup_idx;
306 		fixup = _dl_prog_prebind_map + fixupidx[2*cur_obj+1];
307 		fixupcnt = _dl_prog_prebind_map + prog_footer->fixupcnt_idx;
308 
309 #if 0
310 		DL_DEB(("prebind loading symbols fixup plt %s\n",
311 		    object->load_name));
312 #endif
313 		for (i = 0; i < fixupcnt[2*cur_obj+1]; i++) {
314 			struct fixup *f;
315 			struct elf_object *tobj;
316 			const Elf_Sym *sym;
317 			const char *str;
318 
319 			f = &(fixup[i]);
320 #if 0
321 			DL_DEB(("symidx %d: obj %d sym %d flags %x\n",
322 			    f->sym, f->obj_idx, f->sym_idx,
323 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt));
324 #endif
325 			tobj = objarray[f->obj_idx];
326 			sym = tobj->dyn.symtab + f->sym_idx;
327 			str = tobj->dyn.strtab + sym->st_name;
328 #ifdef DEBUG2
329 			DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
330 			    f->sym, f->obj_idx, tobj->load_name,
331 			    f->sym_idx, str, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
332 			    object->load_addr + sym->st_value));
333 #endif
334 			_dl_symcache[f->sym].obj = tobj;
335 			_dl_symcache[f->sym].sym = sym;
336 			_dl_symcache[f->sym].flags =
337 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
338 		}
339 	}
340 //	DL_DEB(("prebind_data loaded\n"));
341 }
342 
343 void
prebind_free(elf_object_t * object)344 prebind_free(elf_object_t *object)
345 {
346 	struct prebind_footer *footer;
347 
348 	if (object->prebind_data == NULL)
349 		return;
350 #ifdef DEBUG1
351 	DL_DEB(("prebind_free for %s %p\n", object->load_name,
352 	    object->prebind_data));
353 #endif
354 	if (object->prebind_data != 0) {
355 		footer = _dl_prebind_data_to_footer(object->prebind_data);
356 
357 #ifdef DEBUG1
358 		DL_DEB(("freeing prebind data sz %x\n", footer->prebind_size));
359 #endif
360 
361 		_dl_munmap((void *)ELF_TRUNC((long)object->prebind_data, _dl_pagesz),
362 		    ELF_ROUND((long)object->prebind_data+footer->prebind_size,
363 		    _dl_pagesz) - ELF_TRUNC((long)object->prebind_data, _dl_pagesz));
364 
365 		object->prebind_data = NULL;
366 		_dl_prog_prebind_map = NULL;
367 
368 		if (_dl_bindnow == prebind_bind_now)
369 			_dl_bindnow = NULL;
370 	}
371 }
372 
373 int validate_errs;
374 
375 struct timeval beforetp;
376 
377 void
_dl_prebind_pre_resolve()378 _dl_prebind_pre_resolve()
379 {
380 	struct prebind_footer *footer;
381 	elf_object_t *object;
382 	struct nameidx *nameidx;
383 	char *nametab, *name;
384 	int idx;
385 
386 	if (_dl_prog_prebind_map != NULL) {
387 		nameidx = _dl_prog_prebind_map + prog_footer->nameidx_idx;
388 		nametab = _dl_prog_prebind_map + prog_footer->nametab_idx;
389 		for (idx = 1, object = _dl_objects->next; object != NULL;
390 		    object = object->next, idx++) {
391 			if (object->prebind_data == NULL) {
392 				/* ld.so doesn't have prebind data */
393 				if (object->next == NULL)
394 					continue;
395 				DL_DEB(("missing prebind data %s\n",
396 				    object->load_name));
397 				_dl_prebind_match_failed = 1;
398 				break;
399 			}
400 			footer = _dl_prebind_data_to_footer(
401 			    object->prebind_data);
402 			if (footer == NULL ||
403 			    nameidx[idx].id0 != footer->id0 ||
404 			    nameidx[idx].id1 != footer->id1) {
405 				DL_DEB(("invalid prebind data %s\n",
406 				    object->load_name));
407 				_dl_prebind_match_failed = 1;
408 				break;
409 			}
410 			name = object->load_name;
411 			if (_dl_strcmp(nametab + nameidx[idx].name, name)
412 			    != 0) {
413 				DL_DEB(("invalid prebind name %s\n",
414 				    object->load_name));
415 				_dl_prebind_match_failed = 1;
416 				break;
417 			}
418 		}
419 	}
420 
421 	if (_dl_prebind_match_failed) {
422 		for (object = _dl_objects; object != NULL;
423 		    object = object->next)
424 			prebind_free(object);
425 		if (_dl_bindnow == prebind_bind_now)
426 			_dl_bindnow = NULL;
427 	}
428 
429 	if (_dl_debug)
430 		_dl_gettimeofday(&beforetp, NULL);
431 }
432 
433 void
_dl_prebind_post_resolve()434 _dl_prebind_post_resolve()
435 {
436 	char buf[7];
437 	int i;
438 	struct timeval after_tp;
439 	struct timeval diff_tp;
440 	elf_object_t *object;
441 
442 	if (_dl_debug) {
443 		_dl_gettimeofday(&after_tp, NULL);
444 
445 		timersub(&after_tp, &beforetp, &diff_tp);
446 
447 		for (i = 0; i < 6; i++) {
448 			buf[5-i] = (diff_tp.tv_usec % 10) + '0';
449 			diff_tp.tv_usec /= 10;
450 		}
451 		buf[6] = '\0';
452 
453 		_dl_printf("relocation took %d.%s\n", diff_tp.tv_sec, buf);
454 	}
455 
456 	for (object = _dl_objects; object != NULL; object = object->next)
457 		prebind_free(object);
458 
459 	if (_dl_prebind_validate) {
460 		if (validate_errs) {
461 			_dl_printf("validate_errs %d\n", validate_errs);
462 			_dl_exit(20);
463 		} else {
464 			_dl_exit(0);
465 		}
466 	}
467 }
468 
469 void
prebind_validate(elf_object_t * req_obj,unsigned int symidx,int flags,const Elf_Sym * ref_sym)470 prebind_validate(elf_object_t *req_obj, unsigned int symidx, int flags,
471     const Elf_Sym *ref_sym)
472 {
473 	const Elf_Sym *sym, **this;
474 	const elf_object_t *sobj;
475 	const char *symn;
476 	Elf_Addr ret;
477 
478 	/* Don't verify non-matching flags*/
479 
480 	sym = req_obj->dyn.symtab;
481 	sym += symidx;
482 	symn = req_obj->dyn.strtab + sym->st_name;
483 	this = &sym;
484 
485 	//_dl_printf("checking %s\n", symn);
486 	ret = _dl_find_symbol(symn, this, flags, ref_sym, req_obj, &sobj);
487 
488 	if (_dl_symcache[symidx].sym != *this ||
489 	    _dl_symcache[symidx].obj != sobj) {
490 		_dl_printf("symbol %d mismatch on sym %s req_obj %s,\n"
491 		    "should be obj %s is obj %s\n",
492 		    symidx, symn, req_obj->load_name, sobj->load_name,
493 		    _dl_symcache[symidx].obj->load_name);
494 		if (req_obj == sobj)
495 			_dl_printf("obj %p %p\n", _dl_symcache[symidx].obj, sobj);
496 		sym = _dl_symcache[symidx].obj->dyn.symtab;
497 		sym += symidx;
498 		symn = _dl_symcache[symidx].obj->dyn.strtab + sym->st_name;
499 		_dl_printf("obj %s name %s\n",
500 		    _dl_symcache[symidx].obj->load_name,
501 		    symn);
502 	}
503 }
504 
505 #ifdef DEBUG1
506 void
prebind_dump_symcache(struct symcachetab * symcachetab,u_int32_t cnt)507 prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt)
508 {
509 	struct symcachetab *s;
510 	int i;
511 
512 	_dl_printf("cache: cnt %d\n", cnt);
513 	for (i = 0; i < cnt; i++) {
514 		s = &(symcachetab[i]);
515 		_dl_printf("symidx %d: obj %d sym %d\n",
516 		    s->idx, s->obj_idx, s->sym_idx);
517 	}
518 }
519 
520 void
prebind_dump_nameidx(struct nameidx * nameidx,u_int32_t numlibs,char * nametab)521 prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numlibs, char *nametab)
522 {
523 	struct nameidx *n;
524 	int i;
525 
526 	_dl_printf("libs:\n");
527 	for (i = 0; i < numlibs; i++) {
528 		_dl_printf("lib %d offset %d id0 %d, id1 %d\n", i,
529 		    nameidx[i].name, nameidx[i].id0, nameidx[i].id1);
530 	}
531 	for (i = 0; i < numlibs; i++) {
532 		n = &(nameidx[i]);
533 		_dl_printf("nametab %p n %d\n", nametab, n->name);
534 		_dl_printf("lib %s %x %x\n", nametab + n->name, n->id0, n->id1);
535 	}
536 }
537 
538 void
prebind_dump_fixup(struct fixup * fixup,u_int32_t numfixups)539 prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups)
540 {
541 	struct fixup *f;
542 	int i;
543 
544 	_dl_printf("fixup: %d\n", numfixups);
545 	for (i = 0; i < numfixups; i++) {
546 		f = &(fixup[i]);
547 
548 		_dl_printf("idx %d obj %d sym idx %d\n",
549 		    f->sym, f->obj_idx, f->sym_idx);
550 
551 	}
552 }
553 
554 void
prebind_dump_libmap(u_int32_t * libmap,u_int32_t numlibs)555 prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs)
556 {
557 	int i;
558 
559 	for (i = 0; i < numlibs; i++) {
560 		//_dl_printf("lib%d off %d %s\n", i, libmap[i], strtab+libmap[i]);
561 		_dl_printf("lib%d off %d\n", i, libmap[i]);
562 	}
563 }
564 
565 void
dl_dump_footer(struct prebind_footer * footer)566 dl_dump_footer(struct prebind_footer *footer)
567 {
568 //	_dl_printf("base %qd\n", (long long)footer->prebind_base);
569 	_dl_printf("nameidx_idx %d\n", footer->nameidx_idx);
570 	_dl_printf("symcache_idx %d\n", footer->symcache_idx);
571 	_dl_printf("fixupcnt_idx %d\n", footer->fixupcnt_idx);
572 	_dl_printf("fixup_cnt %d\n", footer->fixup_cnt);
573 	_dl_printf("nametab_idx %d\n", footer->nametab_idx);
574 	_dl_printf("symcache_cnt %d\n", footer->symcache_cnt);
575 	_dl_printf("fixup_cnt %d\n", footer->fixup_cnt);
576 	_dl_printf("numlibs %d\n", footer->numlibs);
577 	_dl_printf("id0 %d\n", footer->id0);
578 	_dl_printf("id1 %d\n", footer->id1);
579 //	_dl_printf("orig_size %lld\n", (long long)footer->orig_size);
580 	_dl_printf("version %d\n", footer->prebind_version);
581 	_dl_printf("bind_id %c%c%c%c\n", footer->bind_id[0],
582 	    footer->bind_id[1], footer->bind_id[2], footer->bind_id[3]);
583 }
584 void
dump_prelink(Elf_Addr base,u_long size)585 dump_prelink(Elf_Addr base, u_long size)
586 {
587 	u_int32_t *fixupidx, *fixupcnt, *libmap;
588 	struct symcachetab *symcachetab;
589 	struct prebind_footer *footer;
590 	struct nameidx *nameidx;
591 	struct fixup *fixup;
592 	char *nametab, *id;
593 	void *prebind_map;
594 	int i;
595 
596 	id = (char *) (base+size);
597 	id -= 4;
598 	DL_DEB(("id %c %c %c %c\n", id[0], id[1], id[2], id[3]));
599 	footer = (void *) (base+size - sizeof (struct prebind_footer));
600 	dl_dump_footer(footer);
601 
602 	prebind_map = (void *)base;
603 	nameidx = prebind_map + footer->nameidx_idx;;
604 	symcachetab = prebind_map + footer->symcache_idx;
605 	fixupidx = prebind_map + footer->fixup_idx;
606 	nametab = prebind_map + footer->nametab_idx;
607 	fixupcnt = prebind_map + footer->fixupcnt_idx;
608 	libmap = prebind_map + footer->libmap_idx;
609 
610 	prebind_dump_symcache(symcachetab, footer->symcache_cnt);
611 	prebind_dump_nameidx(nameidx, footer->numlibs, nametab);
612 	for (i = 0; i < footer->fixup_cnt; i++) {
613 		_dl_printf("fixup %d cnt %d idx %d\n", i, fixupcnt[i], fixupidx[i]);
614 		fixup = prebind_map + fixupidx[i];
615 		prebind_dump_fixup(fixup, fixupcnt[i]);
616 	}
617 	prebind_dump_libmap(libmap, footer->numlibs);
618 }
619 #endif /* DEBUG1 */
620