os-freebsd.c revision 5f440b4af2b5dcae2f15652999b9aca7db55d02c
12646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov/* libunwind - a platform-independent unwind library
26f7b335e89e1b7f9c539fc0ebb3f789e34d0b7e4Konstantin Belousov   Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
32646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
42646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovThis file is part of libunwind.
52646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
62646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovPermission is hereby granted, free of charge, to any person obtaining
72646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousova copy of this software and associated documentation files (the
82646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov"Software"), to deal in the Software without restriction, including
92646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousovwithout limitation the rights to use, copy, modify, merge, publish,
102646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousovdistribute, sublicense, and/or sell copies of the Software, and to
112646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousovpermit persons to whom the Software is furnished to do so, subject to
122646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousovthe following conditions:
132646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
142646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovThe above copyright notice and this permission notice shall be
152646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousovincluded in all copies or substantial portions of the Software.
162646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
172646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin BelousovWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
242646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
25e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov#include <sys/param.h>
264de09a9c1569e17132973b801f77bcab8d927480Konstantin Belousov#include <sys/types.h>
27e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov#include <sys/mman.h>
28e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov#include <sys/sysctl.h>
294de09a9c1569e17132973b801f77bcab8d927480Konstantin Belousov#include <sys/user.h>
3063ae8ca8947c67aaa402abbe46a12d118366e1dfKonstantin Belousov#include <stdio.h>
315f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov#include <errno.h>
322646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
332646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov#include "libunwind_i.h"
342646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov
35e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousovstatic void *
36e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousovget_mem(size_t sz)
37e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov{
38e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  void *res;
39e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov
40e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  res = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
41e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  if (res == MAP_FAILED)
42e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov    return (NULL);
43e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  return (res);
44e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov}
45e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov
46e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousovstatic void
47e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousovfree_mem(void *ptr, size_t sz)
48e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov{
49e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  munmap(ptr, sz);
50e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov}
51e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov
525f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousovstatic int
535f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousovget_pid_by_tid(int tid)
545f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov{
555f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  int mib[3], error;
565f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  size_t len, len1;
575f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  char *buf;
585f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  struct kinfo_proc *kv;
595f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  int i, pid;
605f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov
615f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  len = 0;
625f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  mib[0] = CTL_KERN;
635f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  mib[1] = KERN_PROC;
645f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  mib[2] = KERN_PROC_ALL;
655f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov
665f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  error = sysctl(mib, 3, NULL, &len, NULL, 0);
675f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  if (error == -1)
685f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    return (-1);
695f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  len1 = len * 4 / 3;
705f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  buf = get_mem(len1);
715f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  if (buf == NULL)
725f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    return (-1);
735f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  len = len1;
745f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  error = sysctl(mib, 3, buf, &len, NULL, 0);
755f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  if (error == -1) {
765f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    free_mem(buf, len1);
775f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    return (-1);
785f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  }
795f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  pid = -1;
805f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  for (i = 0, kv = (struct kinfo_proc *)buf; i < len / sizeof(*kv);
815f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov   i++, kv++) {
825f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    if (kv->ki_tid == tid) {
835f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov      pid = kv->ki_pid;
845f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov      break;
855f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    }
865f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  }
875f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  free_mem(buf, len1);
885f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  return (pid);
895f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov}
905f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov
91bd2798805a68eac5491a4b096659a05e61e83580Konstantin BelousovPROTECTED int
922646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousovtdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
931787a2fd284a786b409af74047a12de02c644cd1Arun Sharma		    unsigned long *segbase, unsigned long *mapoff, char *path, size_t pathlen)
942646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov{
95e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  int mib[4], error, ret;
96e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  size_t len, len1;
97e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  char *buf, *bp, *eb;
98e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  struct kinfo_vmentry *kv;
99e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov
100e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  len = 0;
101e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  mib[0] = CTL_KERN;
102e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  mib[1] = KERN_PROC;
103e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  mib[2] = KERN_PROC_VMMAP;
104e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  mib[3] = pid;
105bd2798805a68eac5491a4b096659a05e61e83580Konstantin Belousov
106e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  error = sysctl(mib, 4, NULL, &len, NULL, 0);
1075f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  if (error == -1) {
1085f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    if (errno == ESRCH) {
1095f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov      mib[3] = get_pid_by_tid(pid);
1105f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov      if (mib[3] != -1)
1115f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov        error = sysctl(mib, 4, NULL, &len, NULL, 0);
1125f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov      if (error == -1)
1135f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov	return (-UNW_EUNSPEC);
1145f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov    } else
1155f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov      return (-UNW_EUNSPEC);
1165f440b4af2b5dcae2f15652999b9aca7db55d02cKonstantin Belousov  }
117e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  len1 = len * 4 / 3;
118e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  buf = get_mem(len1);
119e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  if (buf == NULL)
1200fac4c8109e23b5363fea3366e35ba17d9f7ea79Konstantin Belousov    return (-UNW_EUNSPEC);
12161f4345a9e812713287e9f04949100416180b38fKonstantin Belousov  len = len1;
122e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  error = sysctl(mib, 4, buf, &len, NULL, 0);
1230fac4c8109e23b5363fea3366e35ba17d9f7ea79Konstantin Belousov  if (error == -1) {
124e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov    free_mem(buf, len1);
1250fac4c8109e23b5363fea3366e35ba17d9f7ea79Konstantin Belousov    return (-UNW_EUNSPEC);
126e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  }
1270fac4c8109e23b5363fea3366e35ba17d9f7ea79Konstantin Belousov  ret = -UNW_EUNSPEC;
128e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  for (bp = buf, eb = buf + len; bp < eb; bp += kv->kve_structsize) {
129e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov     kv = (struct kinfo_vmentry *)(uintptr_t)bp;
130e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov     if (ip < kv->kve_start || ip >= kv->kve_end)
131e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov       continue;
132e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov     if (kv->kve_type != KVME_TYPE_VNODE)
133f8858bacca33415577606f23f52569c1242337deKonstantin Belousov       continue;
134e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov     *segbase = kv->kve_start;
135e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov     *mapoff = kv->kve_offset;
1361787a2fd284a786b409af74047a12de02c644cd1Arun Sharma     if (path)
1371787a2fd284a786b409af74047a12de02c644cd1Arun Sharma       {
138298e575f2cbb4616004717812f28879b2633a6acKonstantin Belousov         strncpy(path, kv->kve_path, pathlen);
1391787a2fd284a786b409af74047a12de02c644cd1Arun Sharma       }
14029dae2171e764b885553aa6c3b9a18448790fd12Konstantin Belousov     ret = elf_map_image (ei, kv->kve_path);
141e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov     break;
142e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  }
143e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  free_mem(buf, len1);
144e33fa9f73c8eefafc2c1b580e78a5c87bcc4dc44Konstantin Belousov  return (ret);
1452646e0fde8a5721ec7356dce38e5341b3080ca62Konstantin Belousov}
146