Gstep.c revision 649f1fb3449a65dd0626a709432d8b02a7c56bbc
1a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock/* libunwind - a platform-independent unwind library
217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm   Copyright (C) 2002-2004 Hewlett-Packard Co
3a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
5a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
6a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
7a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockThis file is part of libunwind.
8a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
9a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockPermission is hereby granted, free of charge, to any person obtaining
10a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbocka copy of this software and associated documentation files (the
11a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock"Software"), to deal in the Software without restriction, including
12a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockwithout limitation the rights to use, copy, modify, merge, publish,
13a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockdistribute, sublicense, and/or sell copies of the Software, and to
14a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockpermit persons to whom the Software is furnished to do so, subject to
15a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockthe following conditions:
16a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
17a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockThe above copyright notice and this permission notice shall be
18a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockincluded in all copies or substantial portions of the Software.
19a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
20a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
27a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
28a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock#include "unwind_i.h"
2951ef1210e84bfba2bfaa64432424d0668dbc95d8homeip.net!davidm#include "ucontext_i.h"
30a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock#include <signal.h>
31a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
32a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockPROTECTED int
33a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbockunw_step (unw_cursor_t *cursor)
34a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock{
35a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock  struct cursor *c = (struct cursor *) cursor;
36a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock  int ret, i;
37a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
3817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm  Debug (1, "(cursor=%p, ip=0x%016llx)\n",
3917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	 c, (unsigned long long) c->dwarf.ip);
4017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
416058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm  /* Try DWARF-based unwinding... */
426058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm  ret = dwarf_step (&c->dwarf);
43a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
4417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm  if (ret < 0 && ret != -UNW_ENOINFO)
4517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm    {
4617bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm      Debug (2, "returning %d\n", ret);
4717bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm      return ret;
4817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm    }
496058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm
506058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm  if (likely (ret >= 0))
51a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock    {
526058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm      /* x86_64 ABI specifies that end of call-chain is marked with a
536058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	 NULL RBP.  */
546058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm      if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
556058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	c->dwarf.ip = 0;
56a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock    }
57a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock  else
58a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock    {
5917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm      /* DWARF failed.  There isn't much of a usable frame-chain on x86-64,
6017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	 but we do need to handle two special-cases:
6117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
6217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  (i) signal trampoline: Old kernels and older libcs don't
6317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      export the vDSO needed to get proper unwind info for the
6417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      trampoline.  Recognize that case by looking at the code
6517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      and filling in things by hand.
6617bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
6717bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  (ii) PLT (shared-library) call-stubs: PLT stubs are invoked
6817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      via CALLQ.  Try this for all non-signal trampoline
6917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      code.  */
7017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
7117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm      unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
72a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
73a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
74649f1fb3449a65dd0626a709432d8b02a7c56bbcArun Sharma      /* We could get here because of missing/bad unwind information.
75649f1fb3449a65dd0626a709432d8b02a7c56bbcArun Sharma         Validate all addresses before dereferencing. */
76649f1fb3449a65dd0626a709432d8b02a7c56bbcArun Sharma      c->validate = 1;
77649f1fb3449a65dd0626a709432d8b02a7c56bbcArun Sharma
786058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm      Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
796058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm
806058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm      if (unw_is_signal_frame (cursor))
816058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	{
826058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  unw_word_t ucontext = c->dwarf.cfa;
836058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm
846058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  Debug(1, "signal frame, skip over trampoline\n");
85a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
866058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
876058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  c->sigcontext_addr = c->dwarf.cfa;
88a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
896058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
906058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  rbp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
916058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  rip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
92a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
936058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
946058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	  if (ret < 0)
9517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    {
9617bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      Debug (2, "returning %d\n", ret);
9717bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      return ret;
9817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    }
9917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
10017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
10117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
10217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
10317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
10417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
10517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
10617bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
10717bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
10817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
10917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
11017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
11117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
11217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
11317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
11417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
11517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
1166058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	}
1176058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm      else
1186058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	{
11917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  unw_word_t rbp;
1206058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm
12117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
12217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  if (ret < 0)
12317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    {
12417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      Debug (2, "returning %d\n", ret);
12517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      return ret;
12617bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    }
12717bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
12817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  if (!rbp)
12917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    {
13017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      /* Looks like we may have reached the end of the call-chain.  */
13117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      rbp_loc = DWARF_NULL_LOC;
13217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      rsp_loc = DWARF_NULL_LOC;
13317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      rip_loc = DWARF_NULL_LOC;
13417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    }
13517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  else
13617bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    {
13706d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma	      unw_word_t rbp1;
13817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      Debug (1, "[RBP=0x%Lx] = 0x%Lx (cfa = 0x%Lx)\n",
13917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm		     (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
14017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm		     (unsigned long long) rbp,
14117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm		     (unsigned long long) c->dwarf.cfa);
14217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
14306d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma	      rbp_loc = DWARF_LOC(rbp, 0);
14417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      rsp_loc = DWARF_NULL_LOC;
14506d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma	      rip_loc = DWARF_LOC (rbp + 8, 0);
14606d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma              /* Heuristic to recognize a bogus frame pointer */
14706d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma	      ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
1488297866bd4dbe239fc778ac5a971aca9b80325d7Arun Sharma              if (ret || ((rbp1 - rbp) > 0x4000))
14906d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma                rbp_loc = DWARF_NULL_LOC;
1508297866bd4dbe239fc778ac5a971aca9b80325d7Arun Sharma	      c->dwarf.cfa += 16;
15117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    }
15217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
15317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  /* Mark all registers unsaved */
15417bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
15517bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    c->dwarf.loc[i] = DWARF_NULL_LOC;
1566058013abe5b60291211458b0b71b87fad053ab9homeip.net!davidm	}
157a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
158a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      c->dwarf.loc[RBP] = rbp_loc;
159a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      c->dwarf.loc[RSP] = rsp_loc;
160a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      c->dwarf.loc[RIP] = rip_loc;
161a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      c->dwarf.ret_addr_column = RIP;
162a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock
163a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
164a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock	{
165a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
16606d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma	  Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
16706d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma		     (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
16806d2ffa41abd7a13a0580492fb2ae76dc0f728e6Arun Sharma		     (unsigned long long) c->dwarf.ip);
169a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock	  if (ret < 0)
17017bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    {
17117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      Debug (2, "returning %d\n", ret);
17217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	      return ret;
17317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	    }
174a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock	}
175a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock      else
176a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock	c->dwarf.ip = 0;
17717bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm
17817bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm      if (c->dwarf.ip == prev_ip && c->dwarf.cfa == prev_cfa)
17917bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm	return -UNW_EBADFRAME;
180a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock    }
18117bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm  ret = (c->dwarf.ip == 0) ? 0 : 1;
18217bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm  Debug (2, "returning %d\n", ret);
18317bf4d0af84466787d06f90c832dc93d3cd8843amostang.com!davidm  return ret;
184a766efd844260866e0d216f6eeef87f4593f60b2ibm.com!masbock}
185