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