Ginit.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /* libunwind - a platform-independent unwind library
  2. Copyright (C) 2001-2005 Hewlett-Packard Co
  3. Copyright (C) 2007 David Mosberger-Tang
  4. Contributed by David Mosberger-Tang <dmosberger@gmail.com>
  5. This file is part of libunwind.
  6. Permission is hereby granted, free of charge, to any person obtaining
  7. a copy of this software and associated documentation files (the
  8. "Software"), to deal in the Software without restriction, including
  9. without limitation the rights to use, copy, modify, merge, publish,
  10. distribute, sublicense, and/or sell copies of the Software, and to
  11. permit persons to whom the Software is furnished to do so, subject to
  12. the following conditions:
  13. The above copyright notice and this permission notice shall be
  14. included in all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  22. #include "unwind_i.h"
  23. #ifdef HAVE_SYS_UC_ACCESS_H
  24. # include <sys/uc_access.h>
  25. #endif
  26. #ifdef UNW_REMOTE_ONLY
  27. /* unw_local_addr_space is a NULL pointer in this case. */
  28. PROTECTED unw_addr_space_t unw_local_addr_space;
  29. #else /* !UNW_REMOTE_ONLY */
  30. static struct unw_addr_space local_addr_space;
  31. PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
  32. #ifdef HAVE_SYS_UC_ACCESS_H
  33. #else /* !HAVE_SYS_UC_ACCESS_H */
  34. HIDDEN void *
  35. tdep_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr)
  36. {
  37. return inlined_uc_addr (uc, reg, nat_bitnr);
  38. }
  39. #endif /* !HAVE_SYS_UC_ACCESS_H */
  40. static void
  41. put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
  42. {
  43. /* it's a no-op */
  44. }
  45. static int
  46. get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
  47. void *arg)
  48. {
  49. #ifndef UNW_LOCAL_ONLY
  50. # pragma weak _U_dyn_info_list_addr
  51. if (!_U_dyn_info_list_addr)
  52. return -UNW_ENOINFO;
  53. #endif
  54. *dyn_info_list_addr = _U_dyn_info_list_addr ();
  55. return 0;
  56. }
  57. static int
  58. access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
  59. void *arg)
  60. {
  61. if (write)
  62. {
  63. Debug (12, "mem[%lx] <- %lx\n", addr, *val);
  64. *(unw_word_t *) addr = *val;
  65. }
  66. else
  67. {
  68. *val = *(unw_word_t *) addr;
  69. Debug (12, "mem[%lx] -> %lx\n", addr, *val);
  70. }
  71. return 0;
  72. }
  73. #ifdef HAVE_SYS_UC_ACCESS_H
  74. #define SYSCALL_CFM_SAVE_REG 11 /* on a syscall, ar.pfs is saved in r11 */
  75. #define REASON_SYSCALL 0
  76. static int
  77. access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
  78. void *arg)
  79. {
  80. ucontext_t *uc = arg;
  81. unsigned int nat, mask;
  82. uint64_t value;
  83. uint16_t reason;
  84. int ret;
  85. __uc_get_reason (uc, &reason);
  86. switch (reg)
  87. {
  88. case UNW_IA64_GR ... UNW_IA64_GR + 31:
  89. if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat)))
  90. break;
  91. if (write)
  92. ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, val, nat);
  93. else
  94. *val = value;
  95. break;
  96. case UNW_IA64_NAT ... UNW_IA64_NAT + 31:
  97. if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat)))
  98. break;
  99. mask = 1 << (reg - UNW_IA64_GR);
  100. if (write)
  101. {
  102. if (*val)
  103. nat |= mask;
  104. else
  105. nat &= ~mask;
  106. ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, &value, nat);
  107. }
  108. else
  109. *val = (nat & mask) != 0;
  110. break;
  111. case UNW_IA64_AR ... UNW_IA64_AR + 127:
  112. if (reg == UNW_IA64_AR_BSP)
  113. {
  114. if (write)
  115. ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val);
  116. else
  117. ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val);
  118. }
  119. else if (reg == UNW_IA64_AR_PFS && reason == REASON_SYSCALL)
  120. {
  121. /* As of HP-UX 11.22, getcontext() does not have unwind info
  122. and because of that, we need to hack thins manually here.
  123. Hopefully, this is OK because the HP-UX kernel also needs
  124. to know where AR.PFS has been saved, so the use of
  125. register r11 for this purpose is pretty much nailed
  126. down. */
  127. if (write)
  128. ret = __uc_set_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, 0);
  129. else
  130. ret = __uc_get_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, &nat);
  131. }
  132. else
  133. {
  134. if (write)
  135. ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val);
  136. else
  137. ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val);
  138. }
  139. break;
  140. case UNW_IA64_BR ... UNW_IA64_BR + 7:
  141. if (write)
  142. ret = __uc_set_brs (uc, (reg - UNW_IA64_BR), 1, val);
  143. else
  144. ret = __uc_get_brs (uc, (reg - UNW_IA64_BR), 1, val);
  145. break;
  146. case UNW_IA64_PR:
  147. if (write)
  148. ret = __uc_set_prs (uc, *val);
  149. else
  150. ret = __uc_get_prs (uc, val);
  151. break;
  152. case UNW_IA64_IP:
  153. if (write)
  154. ret = __uc_set_ip (uc, *val);
  155. else
  156. ret = __uc_get_ip (uc, val);
  157. break;
  158. case UNW_IA64_CFM:
  159. if (write)
  160. ret = __uc_set_cfm (uc, *val);
  161. else
  162. ret = __uc_get_cfm (uc, val);
  163. break;
  164. case UNW_IA64_FR ... UNW_IA64_FR + 127:
  165. default:
  166. ret = EINVAL;
  167. break;
  168. }
  169. if (ret != 0)
  170. {
  171. Debug (1, "failed to %s %s (ret = %d)\n",
  172. write ? "write" : "read", unw_regname (reg), ret);
  173. return -UNW_EBADREG;
  174. }
  175. if (write)
  176. Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
  177. else
  178. Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
  179. return 0;
  180. }
  181. static int
  182. access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
  183. int write, void *arg)
  184. {
  185. ucontext_t *uc = arg;
  186. fp_regval_t fp_regval;
  187. int ret;
  188. switch (reg)
  189. {
  190. case UNW_IA64_FR ... UNW_IA64_FR + 127:
  191. if (write)
  192. {
  193. memcpy (&fp_regval, val, sizeof (fp_regval));
  194. ret = __uc_set_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval);
  195. }
  196. else
  197. {
  198. ret = __uc_get_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval);
  199. memcpy (val, &fp_regval, sizeof (*val));
  200. }
  201. break;
  202. default:
  203. ret = EINVAL;
  204. break;
  205. }
  206. if (ret != 0)
  207. return -UNW_EBADREG;
  208. return 0;
  209. }
  210. #else /* !HAVE_SYS_UC_ACCESS_H */
  211. static int
  212. access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
  213. void *arg)
  214. {
  215. unw_word_t *addr, mask;
  216. ucontext_t *uc = arg;
  217. if (reg >= UNW_IA64_NAT + 4 && reg <= UNW_IA64_NAT + 7)
  218. {
  219. mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
  220. if (write)
  221. {
  222. if (*val)
  223. uc->uc_mcontext.sc_nat |= mask;
  224. else
  225. uc->uc_mcontext.sc_nat &= ~mask;
  226. }
  227. else
  228. *val = (uc->uc_mcontext.sc_nat & mask) != 0;
  229. if (write)
  230. Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
  231. else
  232. Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
  233. return 0;
  234. }
  235. addr = tdep_uc_addr (uc, reg, NULL);
  236. if (!addr)
  237. goto badreg;
  238. if (write)
  239. {
  240. if (ia64_read_only_reg (addr))
  241. {
  242. Debug (16, "attempt to write read-only register\n");
  243. return -UNW_EREADONLYREG;
  244. }
  245. *addr = *val;
  246. Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
  247. }
  248. else
  249. {
  250. *val = *(unw_word_t *) addr;
  251. Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
  252. }
  253. return 0;
  254. badreg:
  255. Debug (1, "bad register number %u\n", reg);
  256. return -UNW_EBADREG;
  257. }
  258. static int
  259. access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
  260. int write, void *arg)
  261. {
  262. ucontext_t *uc = arg;
  263. unw_fpreg_t *addr;
  264. if (reg < UNW_IA64_FR || reg >= UNW_IA64_FR + 128)
  265. goto badreg;
  266. addr = tdep_uc_addr (uc, reg, NULL);
  267. if (!addr)
  268. goto badreg;
  269. if (write)
  270. {
  271. if (ia64_read_only_reg (addr))
  272. {
  273. Debug (16, "attempt to write read-only register\n");
  274. return -UNW_EREADONLYREG;
  275. }
  276. *addr = *val;
  277. Debug (12, "%s <- %016lx.%016lx\n",
  278. unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
  279. }
  280. else
  281. {
  282. *val = *(unw_fpreg_t *) addr;
  283. Debug (12, "%s -> %016lx.%016lx\n",
  284. unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
  285. }
  286. return 0;
  287. badreg:
  288. Debug (1, "bad register number %u\n", reg);
  289. /* attempt to access a non-preserved register */
  290. return -UNW_EBADREG;
  291. }
  292. #endif /* !HAVE_SYS_UC_ACCESS_H */
  293. static int
  294. get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
  295. char *buf, size_t buf_len, unw_word_t *offp,
  296. void *arg)
  297. {
  298. return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
  299. }
  300. HIDDEN void
  301. ia64_local_addr_space_init (void)
  302. {
  303. memset (&local_addr_space, 0, sizeof (local_addr_space));
  304. local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
  305. #if defined(__linux)
  306. local_addr_space.abi = ABI_LINUX;
  307. #elif defined(__hpux)
  308. local_addr_space.abi = ABI_HPUX;
  309. #endif
  310. local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
  311. local_addr_space.acc.find_proc_info = tdep_find_proc_info;
  312. local_addr_space.acc.put_unwind_info = put_unwind_info;
  313. local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
  314. local_addr_space.acc.access_mem = access_mem;
  315. local_addr_space.acc.access_reg = access_reg;
  316. local_addr_space.acc.access_fpreg = access_fpreg;
  317. local_addr_space.acc.resume = ia64_local_resume;
  318. local_addr_space.acc.get_proc_name = get_static_proc_name;
  319. unw_flush_cache (&local_addr_space, 0, 0);
  320. }
  321. #endif /* !UNW_REMOTE_ONLY */
  322. #ifndef UNW_LOCAL_ONLY
  323. HIDDEN int
  324. ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, unw_word_t *valp,
  325. int write)
  326. {
  327. #ifdef HAVE_SYS_UC_ACCESS_H
  328. unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc);
  329. ucontext_t *ucp;
  330. int ret;
  331. Debug (16, "%s location %s\n",
  332. write ? "writing" : "reading", ia64_strloc (loc));
  333. if (c->as == unw_local_addr_space)
  334. ucp = (ucontext_t *) uc_addr;
  335. else
  336. {
  337. unw_word_t *dst, src;
  338. /* Need to copy-in ucontext_t first. */
  339. ucp = alloca (sizeof (ucontext_t));
  340. if (!ucp)
  341. return -UNW_ENOMEM;
  342. /* For now, there is no non-HP-UX implementation of the
  343. uc_access(3) interface. Because of that, we cannot, e.g.,
  344. unwind an HP-UX program from a Linux program. Should that
  345. become possible at some point in the future, the
  346. copy-in/copy-out needs to be adjusted to do byte-swapping if
  347. necessary. */
  348. assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN));
  349. dst = (unw_word_t *) ucp;
  350. for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8)
  351. if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg))
  352. < 0)
  353. return ret;
  354. }
  355. if (IA64_IS_REG_LOC (loc))
  356. ret = access_reg (unw_local_addr_space, IA64_GET_REG (loc), valp, write,
  357. ucp);
  358. else
  359. {
  360. /* Must be an access to the RSE backing store in ucontext_t. */
  361. unw_word_t addr = IA64_GET_ADDR (loc);
  362. if (write)
  363. ret = __uc_set_rsebs (ucp, (uint64_t *) addr, 1, valp);
  364. else
  365. ret = __uc_get_rsebs (ucp, (uint64_t *) addr, 1, valp);
  366. if (ret != 0)
  367. ret = -UNW_EBADREG;
  368. }
  369. if (ret < 0)
  370. return ret;
  371. if (write && c->as != unw_local_addr_space)
  372. {
  373. /* need to copy-out ucontext_t: */
  374. unw_word_t dst, *src = (unw_word_t *) ucp;
  375. for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8)
  376. if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg))
  377. < 0)
  378. return ret;
  379. }
  380. return 0;
  381. #else /* !HAVE_SYS_UC_ACCESS_H */
  382. return -UNW_EINVAL;
  383. #endif /* !HAVE_SYS_UC_ACCESS_H */
  384. }
  385. HIDDEN int
  386. ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *valp,
  387. int write)
  388. {
  389. #ifdef HAVE_SYS_UC_ACCESS_H
  390. unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc);
  391. ucontext_t *ucp;
  392. int ret;
  393. if (c->as == unw_local_addr_space)
  394. ucp = (ucontext_t *) uc_addr;
  395. else
  396. {
  397. unw_word_t *dst, src;
  398. /* Need to copy-in ucontext_t first. */
  399. ucp = alloca (sizeof (ucontext_t));
  400. if (!ucp)
  401. return -UNW_ENOMEM;
  402. /* For now, there is no non-HP-UX implementation of the
  403. uc_access(3) interface. Because of that, we cannot, e.g.,
  404. unwind an HP-UX program from a Linux program. Should that
  405. become possible at some point in the future, the
  406. copy-in/copy-out needs to be adjusted to do byte-swapping if
  407. necessary. */
  408. assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN));
  409. dst = (unw_word_t *) ucp;
  410. for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8)
  411. if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg))
  412. < 0)
  413. return ret;
  414. }
  415. if ((ret = access_fpreg (unw_local_addr_space, IA64_GET_REG (loc), valp,
  416. write, ucp)) < 0)
  417. return ret;
  418. if (write && c->as != unw_local_addr_space)
  419. {
  420. /* need to copy-out ucontext_t: */
  421. unw_word_t dst, *src = (unw_word_t *) ucp;
  422. for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8)
  423. if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg))
  424. < 0)
  425. return ret;
  426. }
  427. return 0;
  428. #else /* !HAVE_SYS_UC_ACCESS_H */
  429. return -UNW_EINVAL;
  430. #endif /* !HAVE_SYS_UC_ACCESS_H */
  431. }
  432. #endif /* UNW_LOCAL_ONLY */