summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@freebsd.org>2012-04-23 13:51:55 +0300
committerArun Sharma <asharma@fb.com>2012-05-14 23:07:52 -0700
commit5f440b4af2b5dcae2f15652999b9aca7db55d02c (patch)
tree4e104042d0b573f76b946919cea41db8143b34d8
parentf8858bacca33415577606f23f52569c1242337de (diff)
downloadlibunwind-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.c52
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)