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  /* Try DWARF-based unwinding... */
70  c->sigcontext_format = X86_64_SCF_NONE;
71  ret = dwarf_step (&c->dwarf);
72
73#if CONSERVATIVE_CHECKS
74  c->validate = val;
75#endif
76
77  if (ret < 0 && ret != -UNW_ENOINFO)
78    {
79      Debug (2, "returning %d\n", ret);
80      return ret;
81    }
82
83  if (likely (ret >= 0))
84    {
85      /* x86_64 ABI specifies that end of call-chain is marked with a
86	 NULL RBP.  */
87      if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
88	{
89	  c->dwarf.ip = 0;
90	  ret = 0;
91	}
92    }
93  else
94    {
95      /* DWARF failed.  There isn't much of a usable frame-chain on x86-64,
96	 but we do need to handle two special-cases:
97
98	  (i) signal trampoline: Old kernels and older libcs don't
99	      export the vDSO needed to get proper unwind info for the
100	      trampoline.  Recognize that case by looking at the code
101	      and filling in things by hand.
102
103	  (ii) PLT (shared-library) call-stubs: PLT stubs are invoked
104	      via CALLQ.  Try this for all non-signal trampoline
105	      code.  */
106
107      unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
108      struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
109
110      /* We could get here because of missing/bad unwind information.
111         Validate all addresses before dereferencing. */
112      c->validate = 1;
113
114      Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
115
116      if (unw_is_signal_frame (cursor))
117	{
118          ret = unw_handle_signal_frame(cursor);
119	  if (ret < 0)
120	    {
121	      Debug (2, "returning 0\n");
122	      return 0;
123	    }
124	}
125      else if (is_plt_entry (&c->dwarf))
126	{
127          /* Like regular frame, CFA = RSP+8, RA = [CFA-8], no regs saved. */
128	  Debug (2, "found plt entry\n");
129          c->frame_info.cfa_reg_offset = 8;
130          c->frame_info.cfa_reg_rsp = -1;
131          c->frame_info.frame_type = UNW_X86_64_FRAME_STANDARD;
132          c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
133          c->dwarf.cfa += 8;
134	}
135      else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
136        {
137	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
138	    c->dwarf.loc[i] = DWARF_NULL_LOC;
139	}
140      else
141	{
142	  unw_word_t rbp;
143
144	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
145	  if (ret < 0)
146	    {
147	      Debug (2, "returning %d [RBP=0x%lx]\n", ret,
148		     DWARF_GET_LOC (c->dwarf.loc[RBP]));
149	      return ret;
150	    }
151
152	  if (!rbp)
153	    {
154	      /* Looks like we may have reached the end of the call-chain.  */
155	      rbp_loc = DWARF_NULL_LOC;
156	      rsp_loc = DWARF_NULL_LOC;
157	      rip_loc = DWARF_NULL_LOC;
158	    }
159	  else
160	    {
161	      unw_word_t rbp1 = 0;
162	      rbp_loc = DWARF_LOC(rbp, 0);
163	      rsp_loc = DWARF_NULL_LOC;
164	      rip_loc = DWARF_LOC (rbp + 8, 0);
165	      ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
166	      Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n",
167		     (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
168		     rbp, c->dwarf.cfa, rbp1);
169
170	      /* Heuristic to determine incorrect guess.  For RBP to be a
171	         valid frame it needs to be above current CFA, but don't
172		 let it go more than a little.  Note that we can't deduce
173		 anything about new RBP (rbp1) since it may not be a frame
174		 pointer in the frame above.  Just check we get the value. */
175              if (ret < 0
176		  || rbp <= c->dwarf.cfa
177		  || (rbp - c->dwarf.cfa) > 0x4000)
178	        {
179                  rip_loc = DWARF_NULL_LOC;
180                  rbp_loc = DWARF_NULL_LOC;
181		}
182
183              c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
184              c->frame_info.cfa_reg_rsp = 0;
185              c->frame_info.cfa_reg_offset = 16;
186              c->frame_info.rbp_cfa_offset = -16;
187	      c->dwarf.cfa += 16;
188	    }
189
190	  /* Mark all registers unsaved */
191	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
192	    c->dwarf.loc[i] = DWARF_NULL_LOC;
193
194          c->dwarf.loc[RBP] = rbp_loc;
195          c->dwarf.loc[RSP] = rsp_loc;
196          c->dwarf.loc[RIP] = rip_loc;
197	}
198
199      c->dwarf.ret_addr_column = RIP;
200
201      if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
202        {
203	  ret = 0;
204	  Debug (2, "NULL %%rbp loc, returning %d\n", ret);
205	  return ret;
206        }
207      if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP]))
208	{
209	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
210	  Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
211		     (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
212		     (unsigned long long) c->dwarf.ip);
213	  if (ret < 0)
214	    {
215	      Debug (2, "returning %d\n", ret);
216	      return ret;
217	    }
218	  ret = 1;
219	}
220      else
221	c->dwarf.ip = 0;
222
223      if (c->dwarf.ip == prev_ip && c->dwarf.cfa == prev_cfa)
224	return -UNW_EBADFRAME;
225    }
226  /* ANDROID support update. */
227  /* Adjust the pc to the instruction before. */
228  if (c->dwarf.ip)
229    c->dwarf.ip--;
230  /* End of ANDROID update. */
231  Debug (2, "returning %d\n", ret);
232  return ret;
233}
234