mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-21 23:27: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/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)
|
||||
|
|
Loading…
Reference in a new issue