Home | History | Annotate | Download | only in x86_64
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2002-2004 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) hpl.hp.com>
      4 
      5    Modified for x86_64 by Max Asbock <masbock (at) us.ibm.com>
      6 
      7 This file is part of libunwind.
      8 
      9 Permission is hereby granted, free of charge, to any person obtaining
     10 a copy of this software and associated documentation files (the
     11 "Software"), to deal in the Software without restriction, including
     12 without limitation the rights to use, copy, modify, merge, publish,
     13 distribute, sublicense, and/or sell copies of the Software, and to
     14 permit persons to whom the Software is furnished to do so, subject to
     15 the following conditions:
     16 
     17 The above copyright notice and this permission notice shall be
     18 included in all copies or substantial portions of the Software.
     19 
     20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     27 
     28 #include "unwind_i.h"
     29 #include <signal.h>
     30 
     31 /* Recognise PLT entries such as:
     32      3bdf0: ff 25 e2 49 13 00 jmpq   *0x1349e2(%rip)
     33      3bdf6: 68 ae 03 00 00    pushq  $0x3ae
     34      3bdfb: e9 00 c5 ff ff    jmpq   38300 <_init+0x18> */
     35 static int
     36 is_plt_entry (struct dwarf_cursor *c)
     37 {
     38   unw_word_t w0, w1;
     39   unw_accessors_t *a;
     40   int ret;
     41 
     42   a = unw_get_accessors (c->as);
     43   if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0
     44       || (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0)
     45     return 0;
     46 
     47   ret = (((w0 & 0xffff) == 0x25ff)
     48 	 && (((w0 >> 48) & 0xff) == 0x68)
     49 	 && (((w1 >> 24) & 0xff) == 0xe9));
     50 
     51   Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
     52   return ret;
     53 }
     54 
     55 PROTECTED int
     56 unw_step (unw_cursor_t *cursor)
     57 {
     58   struct cursor *c = (struct cursor *) cursor;
     59   int ret, i;
     60 
     61 #if CONSERVATIVE_CHECKS
     62   int val = c->validate;
     63   c->validate = 1;
     64 #endif
     65 
     66   Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
     67 	 c, c->dwarf.ip, c->dwarf.cfa);
     68 
     69   unw_word_t old_ip = c->dwarf.ip;
     70   unw_word_t old_cfa = c->dwarf.cfa;
     71 
     72   /* Try DWARF-based unwinding... */
     73   c->sigcontext_format = X86_64_SCF_NONE;
     74   ret = dwarf_step (&c->dwarf);
     75 
     76 #if CONSERVATIVE_CHECKS
     77   c->validate = val;
     78 #endif
     79 
     80   if (ret < 0 && ret != -UNW_ENOINFO)
     81     {
     82       Debug (2, "returning %d\n", ret);
     83       return ret;
     84     }
     85 
     86   if (likely (ret >= 0))
     87     {
     88       /* x86_64 ABI specifies that end of call-chain is marked with a
     89 	 NULL RBP.  */
     90       if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
     91 	{
     92 	  c->dwarf.ip = 0;
     93 	  ret = 0;
     94 	}
     95     }
     96   else
     97     {
     98       /* DWARF failed.  There isn't much of a usable frame-chain on x86-64,
     99 	 but we do need to handle two special-cases:
    100 
    101 	  (i) signal trampoline: Old kernels and older libcs don't
    102 	      export the vDSO needed to get proper unwind info for the
    103 	      trampoline.  Recognize that case by looking at the code
    104 	      and filling in things by hand.
    105 
    106 	  (ii) PLT (shared-library) call-stubs: PLT stubs are invoked
    107 	      via CALLQ.  Try this for all non-signal trampoline
    108 	      code.  */
    109 
    110       unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
    111       struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
    112 
    113       /* We could get here because of missing/bad unwind information.
    114          Validate all addresses before dereferencing. */
    115       c->validate = 1;
    116 
    117       Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
    118 
    119       if (unw_is_signal_frame (cursor))
    120 	{
    121           ret = unw_handle_signal_frame(cursor);
    122 	  if (ret < 0)
    123 	    {
    124 	      Debug (2, "returning 0\n");
    125 	      return 0;
    126 	    }
    127 	}
    128       else if (is_plt_entry (&c->dwarf))
    129 	{
    130           /* Like regular frame, CFA = RSP+8, RA = [CFA-8], no regs saved. */
    131 	  Debug (2, "found plt entry\n");
    132           c->frame_info.cfa_reg_offset = 8;
    133           c->frame_info.cfa_reg_rsp = -1;
    134           c->frame_info.frame_type = UNW_X86_64_FRAME_STANDARD;
    135           c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
    136           c->dwarf.cfa += 8;
    137 	}
    138       else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
    139         {
    140 	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
    141 	    c->dwarf.loc[i] = DWARF_NULL_LOC;
    142 	}
    143       else
    144 	{
    145 	  unw_word_t rbp;
    146 
    147 	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
    148 	  if (ret < 0)
    149 	    {
    150 	      Debug (2, "returning %d [RBP=0x%lx]\n", ret,
    151 		     DWARF_GET_LOC (c->dwarf.loc[RBP]));
    152 	      return ret;
    153 	    }
    154 
    155 	  if (!rbp)
    156 	    {
    157 	      /* Looks like we may have reached the end of the call-chain.  */
    158 	      rbp_loc = DWARF_NULL_LOC;
    159 	      rsp_loc = DWARF_NULL_LOC;
    160 	      rip_loc = DWARF_NULL_LOC;
    161 	    }
    162 	  else
    163 	    {
    164 	      unw_word_t rbp1 = 0;
    165 	      rbp_loc = DWARF_LOC(rbp, 0);
    166 	      rsp_loc = DWARF_NULL_LOC;
    167 	      rip_loc = DWARF_LOC (rbp + 8, 0);
    168 	      ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
    169 	      Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n",
    170 		     (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
    171 		     rbp, c->dwarf.cfa, rbp1);
    172 
    173 	      /* Heuristic to determine incorrect guess.  For RBP to be a
    174 	         valid frame it needs to be above current CFA, but don't
    175 		 let it go more than a little.  Note that we can't deduce
    176 		 anything about new RBP (rbp1) since it may not be a frame
    177 		 pointer in the frame above.  Just check we get the value. */
    178               if (ret < 0
    179 		  || rbp <= c->dwarf.cfa
    180 		  || (rbp - c->dwarf.cfa) > 0x4000)
    181 	        {
    182                   rip_loc = DWARF_NULL_LOC;
    183                   rbp_loc = DWARF_NULL_LOC;
    184 		}
    185 
    186               c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
    187               c->frame_info.cfa_reg_rsp = 0;
    188               c->frame_info.cfa_reg_offset = 16;
    189               c->frame_info.rbp_cfa_offset = -16;
    190 	      c->dwarf.cfa += 16;
    191 	    }
    192 
    193 	  /* Mark all registers unsaved */
    194 	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
    195 	    c->dwarf.loc[i] = DWARF_NULL_LOC;
    196 
    197           c->dwarf.loc[RBP] = rbp_loc;
    198           c->dwarf.loc[RSP] = rsp_loc;
    199           c->dwarf.loc[RIP] = rip_loc;
    200 	}
    201 
    202       c->dwarf.ret_addr_column = RIP;
    203 
    204       if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
    205         {
    206 	  ret = 0;
    207 	  Debug (2, "NULL %%rbp loc, returning %d\n", ret);
    208 	  return ret;
    209         }
    210       if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP]))
    211 	{
    212 	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
    213 	  Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
    214 		     (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
    215 		     (unsigned long long) c->dwarf.ip);
    216 	  if (ret < 0)
    217 	    {
    218 	      Debug (2, "returning %d\n", ret);
    219 	      return ret;
    220 	    }
    221 	  ret = 1;
    222 	}
    223       else
    224 	c->dwarf.ip = 0;
    225 
    226       if (c->dwarf.ip == prev_ip && c->dwarf.cfa == prev_cfa)
    227 	return -UNW_EBADFRAME;
    228     }
    229   /* ANDROID support update. */
    230   /* Adjust the pc to the instruction before. */
    231   if (c->dwarf.ip)
    232     c->dwarf.ip--;
    233   /* If the decode yields the exact same ip/cfa as before, then indicate
    234      the unwind is complete. */
    235   if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
    236     {
    237       Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
    238                __FUNCTION__, (long) c->dwarf.ip);
    239       return -UNW_EBADFRAME;
    240     }
    241   /* End of ANDROID update. */
    242   Debug (2, "returning %d\n", ret);
    243   return ret;
    244 }
    245