mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-26 00:57:39 +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:
parent
f8858bacca
commit
5f440b4af2
1 changed files with 50 additions and 2 deletions
|
@ -28,6 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "libunwind_i.h"
|
#include "libunwind_i.h"
|
||||||
|
|
||||||
|
@ -48,6 +49,45 @@ free_mem(void *ptr, size_t sz)
|
||||||
munmap(ptr, 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
|
PROTECTED int
|
||||||
tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
|
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)
|
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;
|
mib[3] = pid;
|
||||||
|
|
||||||
error = sysctl(mib, 4, NULL, &len, NULL, 0);
|
error = sysctl(mib, 4, NULL, &len, NULL, 0);
|
||||||
if (error)
|
if (error == -1) {
|
||||||
return (-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;
|
len1 = len * 4 / 3;
|
||||||
buf = get_mem(len1);
|
buf = get_mem(len1);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
|
|
Loading…
Reference in a new issue