Home | History | Annotate | Download | only in ptrace
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2003-2005 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) hpl.hp.com>
      4    Copyright (C) 2010 Konstantin Belousov <kib (at) freebsd.org>
      5 
      6 This file is part of libunwind.
      7 
      8 Permission is hereby granted, free of charge, to any person obtaining
      9 a copy of this software and associated documentation files (the
     10 "Software"), to deal in the Software without restriction, including
     11 without limitation the rights to use, copy, modify, merge, publish,
     12 distribute, sublicense, and/or sell copies of the Software, and to
     13 permit persons to whom the Software is furnished to do so, subject to
     14 the following conditions:
     15 
     16 The above copyright notice and this permission notice shall be
     17 included in all copies or substantial portions of the Software.
     18 
     19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     26 
     27 #include "_UPT_internal.h"
     28 
     29 #if UNW_TARGET_IA64
     30 # include <elf.h>
     31 # ifdef HAVE_ASM_PTRACE_OFFSETS_H
     32 #   include <asm/ptrace_offsets.h>
     33 # endif
     34 # include "tdep-ia64/rse.h"
     35 #elif defined(__aarch64__)
     36 # include <sys/uio.h>
     37 #endif
     38 
     39 #if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
     40 int
     41 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
     42 		 int write, void *arg)
     43 {
     44   struct UPT_info *ui = arg;
     45   pid_t pid = ui->pid;
     46 
     47 #if UNW_DEBUG
     48   Debug(16, "using pokeuser: reg: %s [%u], val: %lx, write: %d\n", unw_regname(reg), (unsigned) reg, (long) val, write);
     49 
     50   if (write)
     51     Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val);
     52 #endif
     53 
     54 #if UNW_TARGET_IA64
     55   if ((unsigned) reg - UNW_IA64_NAT < 32)
     56     {
     57       unsigned long nat_bits, mask;
     58 
     59       /* The Linux ptrace represents the statc NaT bits as a single word.  */
     60       mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
     61       errno = 0;
     62 #ifdef HAVE_TTRACE
     63 #	warning No support for ttrace() yet.
     64 #else
     65       nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0);
     66       if (errno)
     67 	goto badreg;
     68 #endif
     69 
     70       if (write)
     71 	{
     72 	  if (*val)
     73 	    nat_bits |= mask;
     74 	  else
     75 	    nat_bits &= ~mask;
     76 #ifdef HAVE_TTRACE
     77 #	warning No support for ttrace() yet.
     78 #else
     79 	  errno = 0;
     80 	  ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits);
     81 	  if (errno)
     82 	    goto badreg;
     83 #endif
     84 	}
     85       goto out;
     86     }
     87   else
     88     switch (reg)
     89       {
     90       case UNW_IA64_GR + 0:
     91 	if (write)
     92 	  goto badreg;
     93 	*val = 0;
     94 	return 0;
     95 
     96       case UNW_REG_IP:
     97 	{
     98 	  unsigned long ip, psr;
     99 
    100 	  /* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR.  */
    101 #ifdef HAVE_TTRACE
    102 #	warning No support for ttrace() yet.
    103 #else
    104 	  errno = 0;
    105 	  psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0);
    106 	  if (errno)
    107 	    goto badreg;
    108 #endif
    109 	  if (write)
    110 	    {
    111 	      ip = *val & ~0xfUL;
    112 	      psr = (psr & ~0x3UL << 41) | (*val & 0x3);
    113 #ifdef HAVE_TTRACE
    114 #	warning No support for ttrace() yet.
    115 #else
    116 	      errno = 0;
    117 	      ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip);
    118 	      ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr);
    119 	      if (errno)
    120 		goto badreg;
    121 #endif
    122 	    }
    123 	  else
    124 	    {
    125 #ifdef HAVE_TTRACE
    126 #	warning No support for ttrace() yet.
    127 #else
    128 	      errno = 0;
    129 	      ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0);
    130 	      if (errno)
    131 		goto badreg;
    132 #endif
    133 	      *val = ip + ((psr >> 41) & 0x3);
    134 	    }
    135 	  goto out;
    136 	}
    137 
    138       case UNW_IA64_AR_BSPSTORE:
    139 	reg = UNW_IA64_AR_BSP;
    140 	break;
    141 
    142       case UNW_IA64_AR_BSP:
    143       case UNW_IA64_BSP:
    144 	{
    145 	  unsigned long sof, cfm, bsp;
    146 
    147 #ifdef HAVE_TTRACE
    148 #	warning No support for ttrace() yet.
    149 #else
    150 	  /* Account for the fact that ptrace() expects bsp to point
    151 	     _after_ the current register frame.  */
    152 	  errno = 0;
    153 	  cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
    154 	  if (errno)
    155 	    goto badreg;
    156 #endif
    157 	  sof = (cfm & 0x7f);
    158 
    159 	  if (write)
    160 	    {
    161 	      bsp = rse_skip_regs (*val, sof);
    162 #ifdef HAVE_TTRACE
    163 #	warning No support for ttrace() yet.
    164 #else
    165 	      errno = 0;
    166 	      ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp);
    167 	      if (errno)
    168 		goto badreg;
    169 #endif
    170 	    }
    171 	  else
    172 	    {
    173 #ifdef HAVE_TTRACE
    174 #	warning No support for ttrace() yet.
    175 #else
    176 	      errno = 0;
    177 	      bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
    178 	      if (errno)
    179 		goto badreg;
    180 #endif
    181 	      *val = rse_skip_regs (bsp, -sof);
    182 	    }
    183 	  goto out;
    184 	}
    185 
    186       case UNW_IA64_CFM:
    187 	/* If we change CFM, we need to adjust ptrace's notion of bsp
    188 	   accordingly, so that the real bsp remains unchanged.  */
    189 	if (write)
    190 	  {
    191 	    unsigned long new_sof, old_sof, cfm, bsp;
    192 
    193 #ifdef HAVE_TTRACE
    194 #	warning No support for ttrace() yet.
    195 #else
    196 	    errno = 0;
    197 	    bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
    198 	    cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
    199 #endif
    200 	    if (errno)
    201 	      goto badreg;
    202 	    old_sof = (cfm & 0x7f);
    203 	    new_sof = (*val & 0x7f);
    204 	    if (old_sof != new_sof)
    205 	      {
    206 		bsp = rse_skip_regs (bsp, -old_sof + new_sof);
    207 #ifdef HAVE_TTRACE
    208 #	warning No support for ttrace() yet.
    209 #else
    210 		errno = 0;
    211 		ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0);
    212 		if (errno)
    213 		  goto badreg;
    214 #endif
    215 	      }
    216 #ifdef HAVE_TTRACE
    217 #	warning No support for ttrace() yet.
    218 #else
    219 	    errno = 0;
    220 	    ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val);
    221 	    if (errno)
    222 	      goto badreg;
    223 #endif
    224 	    goto out;
    225 	  }
    226 	break;
    227       }
    228 #endif /* End of IA64 */
    229 
    230   if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset))
    231     {
    232 #if UNW_DEBUG
    233       Debug(2, "register out of range: >= %zu / %zu\n", sizeof(_UPT_reg_offset), sizeof(_UPT_reg_offset[0]));
    234 #endif
    235       errno = EINVAL;
    236       goto badreg;
    237     }
    238 
    239 #ifdef HAVE_TTRACE
    240 #	warning No support for ttrace() yet.
    241 #else
    242   errno = 0;
    243   if (write)
    244     /* ANDROID support update. */
    245     ptrace (PTRACE_POKEUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], (void*) *val);
    246     /* End of ANDROID update. */
    247   else {
    248 #if UNW_DEBUG
    249     Debug(16, "ptrace PEEKUSER pid: %lu , reg: %lu , offs: %lu\n", (unsigned long)pid, (unsigned long)reg,
    250         (unsigned long)_UPT_reg_offset[reg]);
    251 #endif
    252     /* ANDROID support update. */
    253     *val = ptrace (PTRACE_PEEKUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], 0);
    254     /* End of ANDROID update. */
    255   }
    256   if (errno) {
    257 #if UNW_DEBUG
    258     Debug(2, "ptrace failure\n");
    259 #endif
    260     goto badreg;
    261   }
    262 #endif
    263 
    264 #ifdef UNW_TARGET_IA64
    265  out:
    266 #endif
    267 #if UNW_DEBUG
    268   if (!write)
    269     Debug (16, "%s[%u] -> %lx\n", unw_regname (reg), (unsigned) reg, (long) *val);
    270 #endif
    271   return 0;
    272 
    273  badreg:
    274   Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno));
    275   return -UNW_EBADREG;
    276 }
    277 #elif HAVE_DECL_PT_GETREGS
    278 int
    279 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
    280 		 int write, void *arg)
    281 {
    282   struct UPT_info *ui = arg;
    283   pid_t pid = ui->pid;
    284 /* ANDROID support update. */
    285 #if defined(__mips__)
    286   struct
    287     {
    288       uint64_t regs[32];
    289       uint64_t lo;
    290       uint64_t hi;
    291       uint64_t epc;
    292       uint64_t badvaddr;
    293       uint64_t status;
    294       uint64_t cause;
    295     }
    296   regs;
    297 #else
    298   char *r;
    299   gregset_t regs;
    300 #endif
    301 
    302 #if UNW_DEBUG
    303   Debug(16, "using getregs: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write);
    304 
    305   if (write)
    306     Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val);
    307 #endif
    308 #if defined(__mips__)
    309   if (ptrace(PTRACE_GETREGS, pid, 0, (void*)&regs) == -1)
    310     goto badreg;
    311   if (write)
    312     {
    313       if (reg <= UNW_MIPS_R31)
    314         regs.regs[reg] = *val;
    315       else if (reg == UNW_MIPS_PC)
    316         regs.epc = *val;
    317       else
    318         goto badreg;
    319       if (ptrace(PTRACE_SETREGS, pid, 0, (void*)&regs) == -1)
    320         goto badreg;
    321     }
    322   else
    323     {
    324       if (reg <= UNW_MIPS_R31)
    325         *val = regs.regs[reg];
    326       else if (reg == UNW_MIPS_PC)
    327         *val = regs.epc;
    328       else
    329         goto badreg;
    330     }
    331 #else
    332   if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset))
    333     {
    334       errno = EINVAL;
    335       goto badreg;
    336     }
    337   r = (char *)&regs + _UPT_reg_offset[reg];
    338   if (ptrace(PT_GETREGS, pid, (caddr_t)&regs, 0) == -1)
    339     goto badreg;
    340   if (write) {
    341       memcpy(r, val, sizeof(unw_word_t));
    342       if (ptrace(PT_SETREGS, pid, (caddr_t)&regs, 0) == -1)
    343         goto badreg;
    344   } else
    345       memcpy(val, r, sizeof(unw_word_t));
    346 #endif
    347 /* End of ANDROID update. */
    348   return 0;
    349 
    350  badreg:
    351   Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno));
    352   return -UNW_EBADREG;
    353 }
    354 /* ANDROID support update. */
    355 #elif HAVE_DECL_PT_GETREGSET
    356 int
    357 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
    358 		 int write, void *arg)
    359 {
    360   struct UPT_info *ui = arg;
    361   pid_t pid = ui->pid;
    362 #if defined(__aarch64__)
    363   struct user_pt_regs regs;
    364   struct iovec io;
    365   io.iov_base = &regs;
    366   io.iov_len = sizeof(regs);
    367 
    368 #if UNW_DEBUG
    369   Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write);
    370 
    371   if (write)
    372     Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val);
    373 #endif
    374   if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1)
    375     goto badreg;
    376   if (write)
    377     {
    378       if (reg == UNW_AARCH64_SP)
    379         regs.sp = *val;
    380       else if (reg == UNW_AARCH64_PC)
    381         regs.pc = *val;
    382       else if (reg < UNW_AARCH64_SP)
    383         regs.regs[reg] = *val;
    384       else
    385         goto badreg;
    386       if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1)
    387         goto badreg;
    388     }
    389   else
    390     {
    391       if (reg == UNW_AARCH64_SP)
    392         *val = regs.sp;
    393       else if (reg == UNW_AARCH64_PC)
    394         *val = regs.pc;
    395       else if (reg < UNW_AARCH64_SP)
    396         *val = regs.regs[reg];
    397       else
    398         goto badreg;
    399     }
    400 #else
    401 #error Unsupported architecture for getregset
    402 #endif
    403   return 0;
    404 
    405  badreg:
    406   Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno));
    407   return -UNW_EBADREG;
    408 }
    409 /* End of ANDROID update. */
    410 #else
    411 #error Port me
    412 #endif
    413