1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2002-2004 Hewlett-Packard Co
3	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
6
7This file is part of libunwind.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26WITH 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> */
35static int
36is_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
55PROTECTED int
56unw_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