diff options
author | kib <kib@FreeBSD.org> | 2010-12-25 08:51:20 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2010-12-25 08:51:20 +0000 |
commit | cefd8b2a41e4b4bf7a16e2dea1e0c719a30d56a3 (patch) | |
tree | 487c080e0cb090d960945a4f112301253d4a6e9f /libexec/rtld-elf/rtld_lock.c | |
parent | 377233e6cca2d48c8ecba755aa46304a8ae7731b (diff) | |
download | FreeBSD-src-cefd8b2a41e4b4bf7a16e2dea1e0c719a30d56a3.zip FreeBSD-src-cefd8b2a41e4b4bf7a16e2dea1e0c719a30d56a3.tar.gz |
Implement support for ELF filters in rtld. Both normal and auxillary
filters are implemented.
Filtees are loaded on demand, unless LD_LOADFLTR environment variable
is set or -z loadfltr was specified during the linking. This forces
rtld to upgrade read-locked rtld_bind_lock to write lock when it
encounters an object with filter during symbol lookup.
Consolidate common arguments of the symbol lookup functions in the
SymLook structure. Track the state of the rtld locks in the
RtldLockState structure. Pass local RtldLockState through the rtld
symbol lookup calls to allow lock upgrades.
Reviewed by: kan
Tested by: Mykola Dzham <i levsha me>, nwhitehorn (powerpc)
Diffstat (limited to 'libexec/rtld-elf/rtld_lock.c')
-rw-r--r-- | libexec/rtld-elf/rtld_lock.c | 102 |
1 files changed, 77 insertions, 25 deletions
diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c index c5e582e..e76a4da 100644 --- a/libexec/rtld-elf/rtld_lock.c +++ b/libexec/rtld-elf/rtld_lock.c @@ -43,7 +43,6 @@ */ #include <sys/param.h> - #include <signal.h> #include <stdlib.h> #include <time.h> @@ -183,44 +182,88 @@ rtld_lock_t rtld_bind_lock = &rtld_locks[0]; rtld_lock_t rtld_libc_lock = &rtld_locks[1]; rtld_lock_t rtld_phdr_lock = &rtld_locks[2]; -int -rlock_acquire(rtld_lock_t lock) +#define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0) + +void +rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate) { + + if (lockstate == NULL) + return; + if (thread_mask_set(lock->mask) & lock->mask) { - dbg("rlock_acquire: recursed"); - return (0); + dbg("rlock_acquire: recursed"); + lockstate->lockstate = RTLD_LOCK_UNLOCKED; + return; } lockinfo.rlock_acquire(lock->handle); - return (1); + lockstate->lockstate = RTLD_LOCK_RLOCKED; } -int -wlock_acquire(rtld_lock_t lock) +void +wlock_acquire(rtld_lock_t lock, RtldLockState *lockstate) { + + if (lockstate == NULL) + return; + if (thread_mask_set(lock->mask) & lock->mask) { - dbg("wlock_acquire: recursed"); - return (0); + dbg("wlock_acquire: recursed"); + lockstate->lockstate = RTLD_LOCK_UNLOCKED; + return; } lockinfo.wlock_acquire(lock->handle); - return (1); + lockstate->lockstate = RTLD_LOCK_WLOCKED; } void -rlock_release(rtld_lock_t lock, int locked) +lock_release(rtld_lock_t lock, RtldLockState *lockstate) { - if (locked == 0) - return; - thread_mask_clear(lock->mask); - lockinfo.lock_release(lock->handle); + + if (lockstate == NULL) + return; + + switch (lockstate->lockstate) { + case RTLD_LOCK_UNLOCKED: + break; + case RTLD_LOCK_RLOCKED: + case RTLD_LOCK_WLOCKED: + thread_mask_clear(lock->mask); + lockinfo.lock_release(lock->handle); + break; + default: + assert(0); + } } void -wlock_release(rtld_lock_t lock, int locked) +lock_upgrade(rtld_lock_t lock, RtldLockState *lockstate) { - if (locked == 0) - return; - thread_mask_clear(lock->mask); - lockinfo.lock_release(lock->handle); + + if (lockstate == NULL) + return; + + lock_release(lock, lockstate); + wlock_acquire(lock, lockstate); +} + +void +lock_restart_for_upgrade(RtldLockState *lockstate) +{ + + if (lockstate == NULL) + return; + + switch (lockstate->lockstate) { + case RTLD_LOCK_UNLOCKED: + case RTLD_LOCK_WLOCKED: + break; + case RTLD_LOCK_RLOCKED: + longjmp(lockstate->env, 1); + break; + default: + assert(0); + } } void @@ -322,15 +365,24 @@ _rtld_thread_init(struct RtldLockInfo *pli) void _rtld_atfork_pre(int *locks) { + RtldLockState ls[2]; + + wlock_acquire(rtld_phdr_lock, &ls[0]); + rlock_acquire(rtld_bind_lock, &ls[1]); - locks[2] = wlock_acquire(rtld_phdr_lock); - locks[0] = rlock_acquire(rtld_bind_lock); + /* XXXKIB: I am really sorry for this. */ + locks[0] = ls[1].lockstate; + locks[2] = ls[0].lockstate; } void _rtld_atfork_post(int *locks) { + RtldLockState ls[2]; - rlock_release(rtld_bind_lock, locks[0]); - wlock_release(rtld_phdr_lock, locks[2]); + bzero(ls, sizeof(ls)); + ls[0].lockstate = locks[2]; + ls[1].lockstate = locks[0]; + lock_release(rtld_bind_lock, &ls[1]); + lock_release(rtld_phdr_lock, &ls[0]); } |