Home | History | Annotate | Download | only in debuggerd
      1 /* ARM EABI compliant unwinding routines
      2    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
      3    Contributed by Paul Brook
      4 
      5    This file is free software; you can redistribute it and/or modify it
      6    under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; either version 2, or (at your option) any
      8    later version.
      9 
     10    In addition to the permissions in the GNU General Public License, the
     11    Free Software Foundation gives you unlimited permission to link the
     12    compiled version of this file into combinations with other programs,
     13    and to distribute those combinations without any restriction coming
     14    from the use of this file.  (The General Public License restrictions
     15    do apply in other respects; for example, they cover modification of
     16    the file, and distribution when not linked into a combine
     17    executable.)
     18 
     19    This file is distributed in the hope that it will be useful, but
     20    WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22    General Public License for more details.
     23 
     24    You should have received a copy of the GNU General Public License
     25    along with this program; see the file COPYING.  If not, write to
     26    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
     27    Boston, MA 02110-1301, USA.  */
     28 
     29 /****************************************************************************
     30  * The functions here are derived from gcc/config/arm/pr-support.c from the
     31  * 4.3.x release. The main changes here involve the use of ptrace to retrieve
     32  * memory/processor states from a remote process.
     33  ****************************************************************************/
     34 
     35 #include <sys/types.h>
     36 #include <unwind.h>
     37 
     38 #include "utility.h"
     39 
     40 /* We add a prototype for abort here to avoid creating a dependency on
     41    target headers.  */
     42 extern void abort (void);
     43 
     44 /* Derived from _Unwind_VRS_Pop to use ptrace */
     45 extern _Unwind_VRS_Result
     46 unwind_VRS_Pop_with_ptrace (_Unwind_Context *context,
     47                             _Unwind_VRS_RegClass regclass,
     48                             _uw discriminator,
     49                             _Unwind_VRS_DataRepresentation representation,
     50                             pid_t pid);
     51 
     52 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
     53 
     54 /* Misc constants.  */
     55 #define R_IP    12
     56 #define R_SP    13
     57 #define R_LR    14
     58 #define R_PC    15
     59 
     60 #define uint32_highbit (((_uw) 1) << 31)
     61 
     62 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
     63 
     64 /* Unwind descriptors.  */
     65 
     66 typedef struct
     67 {
     68   _uw16 length;
     69   _uw16 offset;
     70 } EHT16;
     71 
     72 typedef struct
     73 {
     74   _uw length;
     75   _uw offset;
     76 } EHT32;
     77 
     78 /* Personality routine helper functions.  */
     79 
     80 #define CODE_FINISH (0xb0)
     81 
     82 /* Derived from next_unwind_byte to use ptrace */
     83 /* Return the next byte of unwinding information, or CODE_FINISH if there is
     84    no data remaining.  */
     85 static inline _uw8
     86 next_unwind_byte_with_ptrace (__gnu_unwind_state * uws, pid_t pid)
     87 {
     88   _uw8 b;
     89 
     90   if (uws->bytes_left == 0)
     91     {
     92       /* Load another word */
     93       if (uws->words_left == 0)
     94 	return CODE_FINISH; /* Nothing left.  */
     95       uws->words_left--;
     96       uws->data = get_remote_word(pid, uws->next);
     97       uws->next++;
     98       uws->bytes_left = 3;
     99     }
    100   else
    101     uws->bytes_left--;
    102 
    103   /* Extract the most significant byte.  */
    104   b = (uws->data >> 24) & 0xff;
    105   uws->data <<= 8;
    106   return b;
    107 }
    108 
    109 /* Execute the unwinding instructions described by UWS.  */
    110 _Unwind_Reason_Code
    111 unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws,
    112                            pid_t pid)
    113 {
    114   _uw op;
    115   int set_pc;
    116   _uw reg;
    117 
    118   set_pc = 0;
    119   for (;;)
    120     {
    121       op = next_unwind_byte_with_ptrace (uws, pid);
    122       if (op == CODE_FINISH)
    123 	{
    124 	  /* If we haven't already set pc then copy it from lr.  */
    125 	  if (!set_pc)
    126 	    {
    127 	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
    128 			       &reg);
    129 	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
    130 			       &reg);
    131 	      set_pc = 1;
    132 	    }
    133 	  /* Drop out of the loop.  */
    134 	  break;
    135 	}
    136       if ((op & 0x80) == 0)
    137 	{
    138 	  /* vsp = vsp +- (imm6 << 2 + 4).  */
    139 	  _uw offset;
    140 
    141 	  offset = ((op & 0x3f) << 2) + 4;
    142 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
    143 	  if (op & 0x40)
    144 	    reg -= offset;
    145 	  else
    146 	    reg += offset;
    147 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
    148 	  continue;
    149 	}
    150 
    151       if ((op & 0xf0) == 0x80)
    152 	{
    153 	  op = (op << 8) | next_unwind_byte_with_ptrace (uws, pid);
    154 	  if (op == 0x8000)
    155 	    {
    156 	      /* Refuse to unwind.  */
    157 	      return _URC_FAILURE;
    158 	    }
    159 	  /* Pop r4-r15 under mask.  */
    160 	  op = (op << 4) & 0xfff0;
    161 	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, _UVRSD_UINT32,
    162                                       pid)
    163 	      != _UVRSR_OK)
    164 	    return _URC_FAILURE;
    165 	  if (op & (1 << R_PC))
    166 	    set_pc = 1;
    167 	  continue;
    168 	}
    169       if ((op & 0xf0) == 0x90)
    170 	{
    171 	  op &= 0xf;
    172 	  if (op == 13 || op == 15)
    173 	    /* Reserved.  */
    174 	    return _URC_FAILURE;
    175 	  /* vsp = r[nnnn].  */
    176 	  _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
    177 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
    178 	  continue;
    179 	}
    180       if ((op & 0xf0) == 0xa0)
    181 	{
    182 	  /* Pop r4-r[4+nnn], [lr].  */
    183 	  _uw mask;
    184 
    185 	  mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
    186 	  if (op & 8)
    187 	    mask |= (1 << R_LR);
    188 	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, mask, _UVRSD_UINT32,
    189                                       pid)
    190 	      != _UVRSR_OK)
    191 	    return _URC_FAILURE;
    192 	  continue;
    193 	}
    194       if ((op & 0xf0) == 0xb0)
    195 	{
    196 	  /* op == 0xb0 already handled.  */
    197 	  if (op == 0xb1)
    198 	    {
    199 	      op = next_unwind_byte_with_ptrace (uws, pid);
    200 	      if (op == 0 || ((op & 0xf0) != 0))
    201 		/* Spare.  */
    202 		return _URC_FAILURE;
    203 	      /* Pop r0-r4 under mask.  */
    204 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op,
    205                                           _UVRSD_UINT32, pid)
    206 		  != _UVRSR_OK)
    207 		return _URC_FAILURE;
    208 	      continue;
    209 	    }
    210 	  if (op == 0xb2)
    211 	    {
    212 	      /* vsp = vsp + 0x204 + (uleb128 << 2).  */
    213 	      int shift;
    214 
    215 	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
    216 			       &reg);
    217 	      op = next_unwind_byte_with_ptrace (uws, pid);
    218 	      shift = 2;
    219 	      while (op & 0x80)
    220 		{
    221 		  reg += ((op & 0x7f) << shift);
    222 		  shift += 7;
    223 		  op = next_unwind_byte_with_ptrace (uws, pid);
    224 		}
    225 	      reg += ((op & 0x7f) << shift) + 0x204;
    226 	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
    227 			       &reg);
    228 	      continue;
    229 	    }
    230 	  if (op == 0xb3)
    231 	    {
    232 	      /* Pop VFP registers with fldmx.  */
    233 	      op = next_unwind_byte_with_ptrace (uws, pid);
    234 	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
    235 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX,
    236                                           pid)
    237 		  != _UVRSR_OK)
    238 		return _URC_FAILURE;
    239 	      continue;
    240 	    }
    241 	  if ((op & 0xfc) == 0xb4)
    242 	    {
    243 	      /* Pop FPA E[4]-E[4+nn].  */
    244 	      op = 0x40000 | ((op & 3) + 1);
    245 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
    246                                           pid)
    247 		  != _UVRSR_OK)
    248 		return _URC_FAILURE;
    249 	      continue;
    250 	    }
    251 	  /* op & 0xf8 == 0xb8.  */
    252 	  /* Pop VFP D[8]-D[8+nnn] with fldmx.  */
    253 	  op = 0x80000 | ((op & 7) + 1);
    254 	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, pid)
    255 	      != _UVRSR_OK)
    256 	    return _URC_FAILURE;
    257 	  continue;
    258 	}
    259       if ((op & 0xf0) == 0xc0)
    260 	{
    261 	  if (op == 0xc6)
    262 	    {
    263 	      /* Pop iWMMXt D registers.  */
    264 	      op = next_unwind_byte_with_ptrace (uws, pid);
    265 	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
    266 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op,
    267                                           _UVRSD_UINT64, pid)
    268 		  != _UVRSR_OK)
    269 		return _URC_FAILURE;
    270 	      continue;
    271 	    }
    272 	  if (op == 0xc7)
    273 	    {
    274 	      op = next_unwind_byte_with_ptrace (uws, pid);
    275 	      if (op == 0 || (op & 0xf0) != 0)
    276 		/* Spare.  */
    277 		return _URC_FAILURE;
    278 	      /* Pop iWMMXt wCGR{3,2,1,0} under mask.  */
    279 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXC, op,
    280                                           _UVRSD_UINT32, pid)
    281 		  != _UVRSR_OK)
    282 		return _URC_FAILURE;
    283 	      continue;
    284 	    }
    285 	  if ((op & 0xf8) == 0xc0)
    286 	    {
    287 	      /* Pop iWMMXt wR[10]-wR[10+nnn].  */
    288 	      op = 0xa0000 | ((op & 0xf) + 1);
    289 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op,
    290                                           _UVRSD_UINT64, pid)
    291 		  != _UVRSR_OK)
    292 		return _URC_FAILURE;
    293 	      continue;
    294 	    }
    295 	  if (op == 0xc8)
    296 	    {
    297 #ifndef __VFP_FP__
    298  	      /* Pop FPA registers.  */
    299  	      op = next_unwind_byte_with_ptrace (uws, pid);
    300 	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
    301  	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
    302                                           pid)
    303  		  != _UVRSR_OK)
    304  		return _URC_FAILURE;
    305  	      continue;
    306 #else
    307               /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm.  */
    308               op = next_unwind_byte_with_ptrace (uws, pid);
    309               op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
    310               if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op,
    311                                               _UVRSD_DOUBLE, pid)
    312                   != _UVRSR_OK)
    313                 return _URC_FAILURE;
    314               continue;
    315 #endif
    316 	    }
    317 	  if (op == 0xc9)
    318 	    {
    319 	      /* Pop VFP registers with fldmd.  */
    320 	      op = next_unwind_byte_with_ptrace (uws, pid);
    321 	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
    322 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op,
    323                                           _UVRSD_DOUBLE, pid)
    324 		  != _UVRSR_OK)
    325 		return _URC_FAILURE;
    326 	      continue;
    327 	    }
    328 	  /* Spare.  */
    329 	  return _URC_FAILURE;
    330 	}
    331       if ((op & 0xf8) == 0xd0)
    332 	{
    333 	  /* Pop VFP D[8]-D[8+nnn] with fldmd.  */
    334 	  op = 0x80000 | ((op & 7) + 1);
    335 	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_DOUBLE,
    336                                       pid)
    337 	      != _UVRSR_OK)
    338 	    return _URC_FAILURE;
    339 	  continue;
    340 	}
    341       /* Spare.  */
    342       return _URC_FAILURE;
    343     }
    344   return _URC_OK;
    345 }
    346