libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] [PATCH 4/6] Workaround for old FreeBSD kernels not und


From: Konstantin Belousov
Subject: [Libunwind-devel] [PATCH 4/6] Workaround for old FreeBSD kernels not understanding tid for procinfo sysctls.
Date: Mon, 23 Apr 2012 13:51:55 +0300

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.
---
 src/os-freebsd.c |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/src/os-freebsd.c b/src/os-freebsd.c
index 203347e..76cdd23 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)
-- 
1.7.9.6




reply via email to

[Prev in Thread] Current Thread [Next in Thread]