_UPT_access_reg.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* libunwind - a platform-independent unwind library
  2. Copyright (C) 2003-2005 Hewlett-Packard Co
  3. Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
  4. Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
  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 "_UPT_internal.h"
  23. #if UNW_TARGET_IA64
  24. # include <elf.h>
  25. # ifdef HAVE_ASM_PTRACE_OFFSETS_H
  26. # include <asm/ptrace_offsets.h>
  27. # endif
  28. # include "tdep-ia64/rse.h"
  29. #endif
  30. #if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
  31. int
  32. _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
  33. int write, void *arg)
  34. {
  35. struct UPT_info *ui = arg;
  36. pid_t pid = ui->pid;
  37. #if UNW_DEBUG
  38. if (write)
  39. Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val);
  40. #endif
  41. #if UNW_TARGET_IA64
  42. if ((unsigned) reg - UNW_IA64_NAT < 32)
  43. {
  44. unsigned long nat_bits, mask;
  45. /* The Linux ptrace represents the statc NaT bits as a single word. */
  46. mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
  47. errno = 0;
  48. #ifdef HAVE_TTRACE
  49. # warning No support for ttrace() yet.
  50. #else
  51. nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0);
  52. if (errno)
  53. goto badreg;
  54. #endif
  55. if (write)
  56. {
  57. if (*val)
  58. nat_bits |= mask;
  59. else
  60. nat_bits &= ~mask;
  61. #ifdef HAVE_TTRACE
  62. # warning No support for ttrace() yet.
  63. #else
  64. errno = 0;
  65. ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits);
  66. if (errno)
  67. goto badreg;
  68. #endif
  69. }
  70. goto out;
  71. }
  72. else
  73. switch (reg)
  74. {
  75. case UNW_IA64_GR + 0:
  76. if (write)
  77. goto badreg;
  78. *val = 0;
  79. return 0;
  80. case UNW_REG_IP:
  81. {
  82. unsigned long ip, psr;
  83. /* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR. */
  84. #ifdef HAVE_TTRACE
  85. # warning No support for ttrace() yet.
  86. #else
  87. errno = 0;
  88. psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0);
  89. if (errno)
  90. goto badreg;
  91. #endif
  92. if (write)
  93. {
  94. ip = *val & ~0xfUL;
  95. psr = (psr & ~0x3UL << 41) | (*val & 0x3);
  96. #ifdef HAVE_TTRACE
  97. # warning No support for ttrace() yet.
  98. #else
  99. errno = 0;
  100. ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip);
  101. ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr);
  102. if (errno)
  103. goto badreg;
  104. #endif
  105. }
  106. else
  107. {
  108. #ifdef HAVE_TTRACE
  109. # warning No support for ttrace() yet.
  110. #else
  111. errno = 0;
  112. ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0);
  113. if (errno)
  114. goto badreg;
  115. #endif
  116. *val = ip + ((psr >> 41) & 0x3);
  117. }
  118. goto out;
  119. }
  120. case UNW_IA64_AR_BSPSTORE:
  121. reg = UNW_IA64_AR_BSP;
  122. break;
  123. case UNW_IA64_AR_BSP:
  124. case UNW_IA64_BSP:
  125. {
  126. unsigned long sof, cfm, bsp;
  127. #ifdef HAVE_TTRACE
  128. # warning No support for ttrace() yet.
  129. #else
  130. /* Account for the fact that ptrace() expects bsp to point
  131. _after_ the current register frame. */
  132. errno = 0;
  133. cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
  134. if (errno)
  135. goto badreg;
  136. #endif
  137. sof = (cfm & 0x7f);
  138. if (write)
  139. {
  140. bsp = rse_skip_regs (*val, sof);
  141. #ifdef HAVE_TTRACE
  142. # warning No support for ttrace() yet.
  143. #else
  144. errno = 0;
  145. ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp);
  146. if (errno)
  147. goto badreg;
  148. #endif
  149. }
  150. else
  151. {
  152. #ifdef HAVE_TTRACE
  153. # warning No support for ttrace() yet.
  154. #else
  155. errno = 0;
  156. bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
  157. if (errno)
  158. goto badreg;
  159. #endif
  160. *val = rse_skip_regs (bsp, -sof);
  161. }
  162. goto out;
  163. }
  164. case UNW_IA64_CFM:
  165. /* If we change CFM, we need to adjust ptrace's notion of bsp
  166. accordingly, so that the real bsp remains unchanged. */
  167. if (write)
  168. {
  169. unsigned long new_sof, old_sof, cfm, bsp;
  170. #ifdef HAVE_TTRACE
  171. # warning No support for ttrace() yet.
  172. #else
  173. errno = 0;
  174. bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
  175. cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
  176. #endif
  177. if (errno)
  178. goto badreg;
  179. old_sof = (cfm & 0x7f);
  180. new_sof = (*val & 0x7f);
  181. if (old_sof != new_sof)
  182. {
  183. bsp = rse_skip_regs (bsp, -old_sof + new_sof);
  184. #ifdef HAVE_TTRACE
  185. # warning No support for ttrace() yet.
  186. #else
  187. errno = 0;
  188. ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0);
  189. if (errno)
  190. goto badreg;
  191. #endif
  192. }
  193. #ifdef HAVE_TTRACE
  194. # warning No support for ttrace() yet.
  195. #else
  196. errno = 0;
  197. ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val);
  198. if (errno)
  199. goto badreg;
  200. #endif
  201. goto out;
  202. }
  203. break;
  204. }
  205. #endif
  206. if ((unsigned) reg >= sizeof (_UPT_reg_offset) / sizeof (_UPT_reg_offset[0]))
  207. {
  208. errno = EINVAL;
  209. goto badreg;
  210. }
  211. #ifdef HAVE_TTRACE
  212. # warning No support for ttrace() yet.
  213. #else
  214. errno = 0;
  215. if (write)
  216. ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val);
  217. else
  218. *val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0);
  219. if (errno)
  220. goto badreg;
  221. #endif
  222. #ifdef UNW_TARGET_IA64
  223. out:
  224. #endif
  225. #if UNW_DEBUG
  226. if (!write)
  227. Debug (16, "%s -> %lx\n", unw_regname (reg), (long) *val);
  228. #endif
  229. return 0;
  230. badreg:
  231. Debug (1, "bad register number %u (error: %s)\n", reg, strerror (errno));
  232. return -UNW_EBADREG;
  233. }
  234. #elif HAVE_DECL_PT_GETREGS
  235. int
  236. _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
  237. int write, void *arg)
  238. {
  239. struct UPT_info *ui = arg;
  240. pid_t pid = ui->pid;
  241. gregset_t regs;
  242. char *r;
  243. #if UNW_DEBUG
  244. if (write)
  245. Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val);
  246. #endif
  247. if ((unsigned) reg >= sizeof (_UPT_reg_offset) / sizeof (_UPT_reg_offset[0]))
  248. {
  249. errno = EINVAL;
  250. goto badreg;
  251. }
  252. r = (char *)&regs + _UPT_reg_offset[reg];
  253. if (ptrace(PT_GETREGS, pid, (caddr_t)&regs, 0) == -1)
  254. goto badreg;
  255. if (write) {
  256. memcpy(r, val, sizeof(unw_word_t));
  257. if (ptrace(PT_SETREGS, pid, (caddr_t)&regs, 0) == -1)
  258. goto badreg;
  259. } else
  260. memcpy(val, r, sizeof(unw_word_t));
  261. return 0;
  262. badreg:
  263. Debug (1, "bad register number %u (error: %s)\n", reg, strerror (errno));
  264. return -UNW_EBADREG;
  265. }
  266. #else
  267. #error Port me
  268. #endif