1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-22 07:37:38 +01:00

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.
This commit is contained in:
Konstantin Belousov 2012-04-23 13:51:55 +03:00 committed by Arun Sharma
parent f8858bacca
commit 5f440b4af2

View file

@ -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)