4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
28 #include <sys/types.h>
30 #include <sys/regset.h>
31 #include <sys/frame.h>
44 static Elist
*bindto_list
= NULL
;
45 static Elist
*bindfrom_list
= NULL
;
47 static bindhead
*bhp
= NULL
;
48 static unsigned int current_map_len
= 0;
49 static char *buffer_name
;
50 static const sigset_t iset
= { ~0U, ~0U, ~0U, ~0U };
51 static lwp_mutex_t sharedmutex
= SHAREDMUTEX
;
54 * This routine was stolen from libelf.so.1
57 ehash(const char *name
)
59 unsigned int g
, h
= 0;
60 const unsigned char *nm
= (unsigned char *)name
;
65 if ((g
= (unsigned int)(h
& MASK
)) != 0)
69 return ((unsigned long)h
);
74 output_err_message(const char *msg
)
77 if ((fd
= open("/tmp/bind_err", O_RDWR
| O_CREAT
, 0666)) == -1) {
78 (void) fprintf(stderr
, "bindings.so: unable to open err_log\n");
81 (void) lseek(fd
, 0, SEEK_END
);
82 (void) write(fd
, msg
, strlen(msg
));
87 * common mutex locking & unlocking routines for this module. This is to
88 * control the setting of 'lock_held'.
91 bt_lock(lwp_mutex_t
*lock
)
93 if (_lwp_mutex_lock(lock
) != 0) {
94 output_err_message("bt_lock failed!!\n");
95 (void) fprintf(stderr
, "bindings.so: unable to obtain lock\n");
96 perror("_lwp_mutex_lock");
101 bt_unlock(lwp_mutex_t
*lock
)
103 if (_lwp_mutex_unlock(lock
) != 0) {
104 output_err_message("bt_unlock failed!!\n");
105 (void) fprintf(stderr
, "bindings.so: unable to unlock lock\n");
106 perror("_lwp_mutex_unlock");
113 * It's always possible that another process sharing our buffer
114 * has caused it to grow. If this is the case we must adjust our
115 * mappings to compensate.
121 if ((new_bhp
= mmap(0, bhp
->bh_size
, PROT_READ
| PROT_WRITE
,
122 MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
123 (void) fprintf(stderr
, "bindings: remap: mmap failed\n");
126 bt_unlock(&bhp
->bh_lock
);
130 * clean up old mapping
132 (void) munmap((caddr_t
)bhp
, current_map_len
);
133 bhp
= (bindhead
*)new_bhp
;
134 current_map_len
= bhp
->bh_size
;
141 if ((fd
= open(buffer_name
, O_RDWR
)) == -1) {
142 (void) fprintf(stderr
,
143 "bidings: grow_buffer: open failed: %s\n", buffer_name
);
145 bt_unlock(&bhp
->bh_lock
);
148 if (ftruncate(fd
, bhp
->bh_size
+ BLKSIZE
) == -1) {
149 (void) fprintf(stderr
, "grow_buffer failed\n");
151 bt_unlock(&bhp
->bh_lock
);
154 bhp
->bh_size
+= BLKSIZE
;
162 bt_lock(&bhp
->bh_lock
);
163 while (bhp
->bh_end
+ STRBLKSIZE
> bhp
->bh_size
)
166 bhp
->bh_strcur
= bhp
->bh_end
;
167 bhp
->bh_end
= bhp
->bh_strend
= bhp
->bh_strcur
+ STRBLKSIZE
;
168 bt_unlock(&bhp
->bh_lock
);
172 save_str(const char *str
)
178 bt_lock(&bhp
->bh_strlock
);
180 slen
= (unsigned int)strlen(str
);
183 * will string fit into our current string buffer?
185 if ((slen
+ 1) > (bhp
->bh_strend
- bhp
->bh_strcur
))
187 bptr
= bhp
->bh_strcur
;
188 sptr
= (char *)bhp
+ bhp
->bh_strcur
;
189 bhp
->bh_strcur
+= slen
+ 1;
190 (void) strncpy(sptr
, str
, slen
);
192 bt_unlock(&bhp
->bh_strlock
);
200 unsigned int new_ent
;
201 bt_lock(&bhp
->bh_lock
);
202 while ((sizeof (binding_entry
) + bhp
->bh_end
) > bhp
->bh_size
)
204 new_ent
= bhp
->bh_end
;
205 bhp
->bh_end
+= sizeof (binding_entry
);
206 bt_unlock(&bhp
->bh_lock
);
217 (void) memcpy(&bhp
->bh_lock
, &sharedmutex
, sizeof (lwp_mutex_t
));
218 for (i
= 0; i
< DEFBKTS
; i
++)
219 (void) memcpy(&bhp
->bh_bkts
[i
].bb_lock
, &sharedmutex
,
220 sizeof (lwp_mutex_t
));
222 (void) memcpy(&bhp
->bh_strlock
, &sharedmutex
, sizeof (lwp_mutex_t
));
226 la_version(uint_t version
)
231 if (version
< LAV_CURRENT
) {
232 (void) fprintf(stderr
,
233 "bindings.so: unexpected link_audit version: %d\n",
238 build_env_list(&bindto_list
, (const char *)"BT_BINDTO");
239 build_env_list(&bindfrom_list
, (const char *)"BT_BINDFROM");
241 if ((buffer_name
= getenv(FILEENV
)) == NULL
)
242 buffer_name
= DEFFILE
;
244 (void) sigprocmask(SIG_BLOCK
, &iset
, &omask
);
245 if ((fd
= open(buffer_name
, O_RDWR
| O_CREAT
| O_EXCL
, 0666)) != -1) {
246 int init_size
= sizeof (bindhead
) + BLKSIZE
;
248 if (ftruncate(fd
, init_size
) == -1) {
254 if ((bhp
= (bindhead
*)mmap(0, init_size
,
255 PROT_READ
| PROT_WRITE
,
256 MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
257 perror("bindings.so: mmap");
265 * Lock our structure and then initialize the data
267 bt_lock(&bhp
->bh_lock
);
268 bhp
->bh_vers
= BINDCURVERS
;
269 current_map_len
= bhp
->bh_size
= init_size
;
270 bhp
->bh_end
= sizeof (bindhead
);
271 bhp
->bh_bktcnt
= DEFBKTS
;
272 bt_unlock(&bhp
->bh_lock
);
274 * Set up our initial string buffer
277 } else if ((fd
= open(buffer_name
, O_RDWR
)) != -1) {
280 for (i
= 0; i
< 4; i
++) {
281 if (fstat(fd
, &stbuf
) == -1) {
285 if (stbuf
.st_size
< sizeof (bindhead
)) {
290 if ((bhp
= (bindhead
*)mmap(0, stbuf
.st_size
,
291 PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0)) ==
293 (void) fprintf(stderr
,
294 "bindings: mmap failed\n");
300 current_map_len
= (unsigned int)stbuf
.st_size
;
303 (void) fprintf(stderr
,
304 "bindings: buffer mapping timed out\n");
307 for (i
= 0; i
< 4; i
++) {
308 if (bhp
->bh_vers
== 0) {
313 if (bhp
->bh_vers
== 0) {
314 (void) fprintf(stderr
,
315 "bindings: %s not initialized\n", buffer_name
);
319 bt_lock(&bhp
->bh_lock
);
321 if (bhp
->bh_size
!= current_map_len
)
325 (void) fprintf(stderr
, "bindings: unable to open %s\n",
331 (void) sigprocmask(SIG_SETMASK
, &omask
, NULL
);
332 bt_unlock(&bhp
->bh_lock
);
334 return (LAV_CURRENT
);
339 la_objopen(Link_map
*lmp
, Lmid_t lmid
, uintptr_t *cookie
)
343 if ((bindto_list
== NULL
) ||
344 (check_list(bindto_list
, lmp
->l_name
)))
345 flags
= LA_FLG_BINDTO
;
349 if ((bindfrom_list
== NULL
) ||
350 (check_list(bindfrom_list
, lmp
->l_name
)))
351 flags
|= LA_FLG_BINDFROM
;
358 #if defined(__sparcv9)
360 la_sparcv9_pltenter(Elf64_Sym
*symp
, uint_t symndx
, uintptr_t *refcooke
,
361 uintptr_t *defcook
, La_sparcv9_regs
*regset
, uint_t
*sb_flags
,
362 const char *sym_name
)
363 #elif defined(__sparc)
365 la_sparcv8_pltenter(Elf32_Sym
*symp
, uint_t symndx
, uintptr_t *refcooke
,
366 uintptr_t *defcook
, La_sparcv8_regs
*regset
, uint_t
*sb_flags
)
367 #elif defined(__amd64)
369 la_amd64_pltenter(Elf64_Sym
*symp
, uint_t symndx
, uintptr_t *refcooke
,
370 uintptr_t *defcook
, La_amd64_regs
*regset
, uint_t
*sb_flags
,
371 const char *sym_name
)
372 #elif defined(__i386)
374 la_i86_pltenter(Elf32_Sym
*symp
, uint_t symndx
, uintptr_t *refcooke
,
375 uintptr_t *defcook
, La_i86_regs
*regset
, uint_t
*sb_flags
)
379 Link_map
*dlmp
= (Link_map
*)*defcook
;
380 const char *lib_name
;
383 const char *sym_name
= (const char *)symp
->st_name
;
387 lib_name
= dlmp
->l_name
;
389 (void) sigprocmask(SIG_BLOCK
, &iset
, &omask
);
390 if (sym_name
== NULL
) {
391 output_err_message("null symname\n");
392 return (symp
->st_value
);
395 bktno
= ehash(sym_name
) % bhp
->bh_bktcnt
;
397 bt_lock(&bhp
->bh_bkts
[bktno
].bb_lock
);
400 * The buffer has been grown (by another process) and
401 * we need to remap it into memory.
403 if (bhp
->bh_size
!= current_map_len
) {
405 if ((fd
= open(buffer_name
, O_RDWR
)) == -1) {
406 (void) fprintf(stderr
,
407 "bidings: plt_enter: open failed: %s\n",
410 bt_unlock(&bhp
->bh_lock
);
413 bt_lock(&bhp
->bh_lock
);
415 bt_unlock(&bhp
->bh_lock
);
419 if (bhp
->bh_bkts
[bktno
].bb_head
== NULL
) {
422 unsigned int sym_off
;
423 unsigned int lib_off
;
425 be_off
= get_new_entry();
426 sym_off
= save_str(sym_name
);
427 lib_off
= save_str(lib_name
);
429 bep
= (binding_entry
*)((char *)bhp
+ be_off
);
431 bep
->be_sym_name
= sym_off
;
432 bep
->be_lib_name
= lib_off
;
434 bhp
->bh_bkts
[bktno
].bb_head
= be_off
;
437 unsigned int prev_off
= 0;
438 binding_entry
*prev_bep
= NULL
;
439 unsigned int cur_off
;
440 binding_entry
*cur_bep
;
441 unsigned int lib_off
= 0;
444 * Once we get to the bucket, we do a two tiered
445 * search. First we search for a library match, then
446 * we search for a symbol match.
448 cur_off
= bhp
->bh_bkts
[bktno
].bb_head
;
450 cur_bep
= (binding_entry
*)((char *)bhp
+
452 while (cur_off
&& (strcmp_res
= strcmp((char *)bhp
+
453 cur_bep
->be_lib_name
, lib_name
)) < 0) {
455 cur_off
= cur_bep
->be_next
;
457 cur_bep
= (binding_entry
*)((char *)bhp
+
460 if (cur_off
&& (strcmp_res
== 0)) {
462 * This is a small optimization. For
463 * each bucket we will only record a library
464 * name once. Once it has been recorded in
465 * a bucket we will just re-use the same
468 lib_off
= cur_bep
->be_lib_name
;
469 while (cur_off
&& (strcmp_res
= strcmp((char *)bhp
+
470 cur_bep
->be_sym_name
, sym_name
)) < 0) {
472 cur_off
= cur_bep
->be_next
;
474 cur_bep
= (binding_entry
*)((char *)bhp
+
478 if (strcmp_res
== 0) {
484 unsigned int new_off
;
485 binding_entry
* new_bep
;
486 unsigned int sym_off
;
488 new_off
= get_new_entry();
490 lib_off
= save_str(lib_name
);
491 sym_off
= save_str(sym_name
);
494 new_bep
= (binding_entry
*)((char *)bhp
+
496 new_bep
->be_sym_name
= sym_off
;
497 new_bep
->be_lib_name
= lib_off
;
498 new_bep
->be_count
= 1;
499 new_bep
->be_next
= cur_off
;
502 prev_bep
= (binding_entry
*)((char *)bhp
+
504 prev_bep
->be_next
= new_off
;
507 * Insert at head of list.
509 bhp
->bh_bkts
[bktno
].bb_head
= new_off
;
513 bt_unlock(&bhp
->bh_bkts
[bktno
].bb_lock
);
514 (void) sigprocmask(SIG_SETMASK
, &omask
, NULL
);
515 return (symp
->st_value
);