diff options
author | Konstantin Belousov <kib@freebsd.org> | 2012-04-23 13:51:55 +0300 |
---|---|---|
committer | Arun Sharma <asharma@fb.com> | 2012-05-14 23:07:52 -0700 |
commit | 5f440b4af2b5dcae2f15652999b9aca7db55d02c (patch) | |
tree | 4e104042d0b573f76b946919cea41db8143b34d8 | |
parent | f8858bacca33415577606f23f52569c1242337de (diff) | |
download | libunwind-5f440b4af2b5dcae2f15652999b9aca7db55d02c.tar.gz |
freebsd: Workaround for old FreeBSD kernels
Older kernels interpret the pid argument of the process information
sysctls as pid only. If libunwind UPT consumer passed tid to _UPT_create,
tdep_get_elf_image() returns error due to sysctls failure. Provide a
slow workaround by searching for a process owning the supplied tid if
sysctl returned ESRCH.
-rw-r--r-- | src/os-freebsd.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/src/os-freebsd.c b/src/os-freebsd.c index 203347ea..76cdd23c 100644 --- a/src/os-freebsd.c +++ b/src/os-freebsd.c @@ -28,6 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <sys/sysctl.h> #include <sys/user.h> #include <stdio.h> +#include <errno.h> #include "libunwind_i.h" @@ -48,6 +49,45 @@ free_mem(void *ptr, size_t sz) munmap(ptr, sz); } +static int +get_pid_by_tid(int tid) +{ + int mib[3], error; + size_t len, len1; + char *buf; + struct kinfo_proc *kv; + int i, pid; + + len = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ALL; + + error = sysctl(mib, 3, NULL, &len, NULL, 0); + if (error == -1) + return (-1); + len1 = len * 4 / 3; + buf = get_mem(len1); + if (buf == NULL) + return (-1); + len = len1; + error = sysctl(mib, 3, buf, &len, NULL, 0); + if (error == -1) { + free_mem(buf, len1); + return (-1); + } + pid = -1; + for (i = 0, kv = (struct kinfo_proc *)buf; i < len / sizeof(*kv); + i++, kv++) { + if (kv->ki_tid == tid) { + pid = kv->ki_pid; + break; + } + } + free_mem(buf, len1); + return (pid); +} + PROTECTED int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char *path, size_t pathlen) @@ -64,8 +104,16 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, mib[3] = pid; error = sysctl(mib, 4, NULL, &len, NULL, 0); - if (error) - return (-1); + if (error == -1) { + if (errno == ESRCH) { + mib[3] = get_pid_by_tid(pid); + if (mib[3] != -1) + error = sysctl(mib, 4, NULL, &len, NULL, 0); + if (error == -1) + return (-UNW_EUNSPEC); + } else + return (-UNW_EUNSPEC); + } len1 = len * 4 / 3; buf = get_mem(len1); if (buf == NULL) |