1d77787f2SJonathan Schleifer/* libunwind - a platform-independent unwind library
2d77787f2SJonathan Schleifer   Copyright (C) 2002-2004 Hewlett-Packard Co
3d77787f2SJonathan Schleifer        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4d77787f2SJonathan Schleifer
5d77787f2SJonathan SchleiferThis file is part of libunwind.
6d77787f2SJonathan Schleifer
7d77787f2SJonathan SchleiferPermission is hereby granted, free of charge, to any person obtaining
8d77787f2SJonathan Schleifera copy of this software and associated documentation files (the
9d77787f2SJonathan Schleifer"Software"), to deal in the Software without restriction, including
10d77787f2SJonathan Schleiferwithout limitation the rights to use, copy, modify, merge, publish,
11d77787f2SJonathan Schleiferdistribute, sublicense, and/or sell copies of the Software, and to
12d77787f2SJonathan Schleiferpermit persons to whom the Software is furnished to do so, subject to
13d77787f2SJonathan Schleiferthe following conditions:
14d77787f2SJonathan Schleifer
15d77787f2SJonathan SchleiferThe above copyright notice and this permission notice shall be
16d77787f2SJonathan Schleiferincluded in all copies or substantial portions of the Software.
17d77787f2SJonathan Schleifer
18d77787f2SJonathan SchleiferTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19d77787f2SJonathan SchleiferEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20d77787f2SJonathan SchleiferMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21d77787f2SJonathan SchleiferNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22d77787f2SJonathan SchleiferLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23d77787f2SJonathan SchleiferOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24d77787f2SJonathan SchleiferWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25d77787f2SJonathan Schleifer
26d77787f2SJonathan Schleifer#include "unwind_i.h"
27d77787f2SJonathan Schleifer#include "offsets.h"
28d77787f2SJonathan Schleifer
29d77787f2SJonathan SchleiferPROTECTED int
30d77787f2SJonathan Schleiferunw_is_signal_frame (unw_cursor_t *cursor)
31d77787f2SJonathan Schleifer{
32d77787f2SJonathan Schleifer  struct cursor *c = (struct cursor *) cursor;
33d77787f2SJonathan Schleifer  unw_word_t w0, w1, ip;
34d77787f2SJonathan Schleifer  unw_addr_space_t as;
35d77787f2SJonathan Schleifer  unw_accessors_t *a;
36d77787f2SJonathan Schleifer  void *arg;
37d77787f2SJonathan Schleifer  int ret;
38d77787f2SJonathan Schleifer
39d77787f2SJonathan Schleifer  as = c->dwarf.as;
40d77787f2SJonathan Schleifer  a = unw_get_accessors (as);
41d77787f2SJonathan Schleifer  arg = c->dwarf.as_arg;
42d77787f2SJonathan Schleifer
43d77787f2SJonathan Schleifer  /* Check if EIP points at sigreturn() sequence.  On Linux, this is:
44d77787f2SJonathan Schleifer
45d77787f2SJonathan Schleifer    __restore:
46d77787f2SJonathan Schleifer        0x58                            pop %eax
47d77787f2SJonathan Schleifer        0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
48d77787f2SJonathan Schleifer        0xcd 0x80                       int 0x80
49d77787f2SJonathan Schleifer
50d77787f2SJonathan Schleifer     without SA_SIGINFO, and
51d77787f2SJonathan Schleifer
52d77787f2SJonathan Schleifer    __restore_rt:
53d77787f2SJonathan Schleifer       0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
54d77787f2SJonathan Schleifer       0xcd 0x80                       int 0x80
55d77787f2SJonathan Schleifer       0x00
56d77787f2SJonathan Schleifer
57d77787f2SJonathan Schleifer     if SA_SIGINFO is specified.
58d77787f2SJonathan Schleifer  */
59d77787f2SJonathan Schleifer  ip = c->dwarf.ip;
60d77787f2SJonathan Schleifer  if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0
61d77787f2SJonathan Schleifer      || (*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0)
62d77787f2SJonathan Schleifer    ret = 0;
63d77787f2SJonathan Schleifer  else
64d77787f2SJonathan Schleifer    ret = ((w0 == 0x0077b858 && w1 == 0x80cd0000)
65d77787f2SJonathan Schleifer         || (w0 == 0x0000adb8 && (w1 & 0xffffff) == 0x80cd00));
66d77787f2SJonathan Schleifer  Debug (16, "returning %d\n", ret);
67d77787f2SJonathan Schleifer  return ret;
68d77787f2SJonathan Schleifer}
69d77787f2SJonathan Schleifer
70d77787f2SJonathan SchleiferPROTECTED int
71d77787f2SJonathan Schleiferunw_handle_signal_frame (unw_cursor_t *cursor)
72d77787f2SJonathan Schleifer{
73d77787f2SJonathan Schleifer  struct cursor *c = (struct cursor *) cursor;
74d77787f2SJonathan Schleifer  int ret;
75d77787f2SJonathan Schleifer
76d77787f2SJonathan Schleifer  /* c->esp points at the arguments to the handler.  Without
77d77787f2SJonathan Schleifer     SA_SIGINFO, the arguments consist of a signal number
78d77787f2SJonathan Schleifer     followed by a struct sigcontext.  With SA_SIGINFO, the
79d77787f2SJonathan Schleifer     arguments consist a signal number, a siginfo *, and a
80d77787f2SJonathan Schleifer     ucontext *. */
81d77787f2SJonathan Schleifer  unw_word_t sc_addr;
82d77787f2SJonathan Schleifer  unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4;
83d77787f2SJonathan Schleifer  unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8;
84d77787f2SJonathan Schleifer  unw_word_t siginfo_ptr, sigcontext_ptr;
85d77787f2SJonathan Schleifer  struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc;
86d77787f2SJonathan Schleifer
87d77787f2SJonathan Schleifer  siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0);
88d77787f2SJonathan Schleifer  sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0);
89d77787f2SJonathan Schleifer  ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr)
90d77787f2SJonathan Schleifer         | dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr));
91d77787f2SJonathan Schleifer  if (ret < 0)
92d77787f2SJonathan Schleifer    {
93d77787f2SJonathan Schleifer      Debug (2, "returning 0\n");
94d77787f2SJonathan Schleifer      return 0;
95d77787f2SJonathan Schleifer    }
96d77787f2SJonathan Schleifer  if (siginfo_ptr < c->dwarf.cfa
97d77787f2SJonathan Schleifer      || siginfo_ptr > c->dwarf.cfa + 256
98d77787f2SJonathan Schleifer      || sigcontext_ptr < c->dwarf.cfa
99d77787f2SJonathan Schleifer      || sigcontext_ptr > c->dwarf.cfa + 256)
100d77787f2SJonathan Schleifer    {
101d77787f2SJonathan Schleifer      /* Not plausible for SA_SIGINFO signal */
102d77787f2SJonathan Schleifer      c->sigcontext_format = X86_SCF_LINUX_SIGFRAME;
103d77787f2SJonathan Schleifer      c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4;
104d77787f2SJonathan Schleifer    }
105d77787f2SJonathan Schleifer  else
106d77787f2SJonathan Schleifer    {
107d77787f2SJonathan Schleifer      /* If SA_SIGINFO were not specified, we actually read
108d77787f2SJonathan Schleifer         various segment pointers instead.  We believe that at
109d77787f2SJonathan Schleifer         least fs and _fsh are always zero for linux, so it is
110d77787f2SJonathan Schleifer         not just unlikely, but impossible that we would end
111d77787f2SJonathan Schleifer         up here. */
112d77787f2SJonathan Schleifer      c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME;
113d77787f2SJonathan Schleifer      c->sigcontext_addr = sigcontext_ptr;
114d77787f2SJonathan Schleifer      sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF;
115d77787f2SJonathan Schleifer    }
116d77787f2SJonathan Schleifer  esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
117d77787f2SJonathan Schleifer  ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
118d77787f2SJonathan Schleifer  if (ret < 0)
119d77787f2SJonathan Schleifer    {
120d77787f2SJonathan Schleifer      Debug (2, "returning 0\n");
121d77787f2SJonathan Schleifer      return 0;
122d77787f2SJonathan Schleifer    }
123d77787f2SJonathan Schleifer
124d77787f2SJonathan Schleifer  c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0);
125d77787f2SJonathan Schleifer  c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0);
126d77787f2SJonathan Schleifer  c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0);
127d77787f2SJonathan Schleifer  c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0);
128d77787f2SJonathan Schleifer  c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
129d77787f2SJonathan Schleifer  c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0);
130d77787f2SJonathan Schleifer  c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0);
131d77787f2SJonathan Schleifer  c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC;
132d77787f2SJonathan Schleifer  c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
133d77787f2SJonathan Schleifer  c->dwarf.loc[ST0] = DWARF_NULL_LOC;
134d77787f2SJonathan Schleifer  c->dwarf.loc[EIP] = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0);
135d77787f2SJonathan Schleifer  c->dwarf.loc[ESP] = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
136d77787f2SJonathan Schleifer
137d77787f2SJonathan Schleifer  return 0;
138d77787f2SJonathan Schleifer}
139d77787f2SJonathan Schleifer
140d77787f2SJonathan SchleiferHIDDEN dwarf_loc_t
141d77787f2SJonathan Schleiferx86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
142d77787f2SJonathan Schleifer{
143d77787f2SJonathan Schleifer  unw_word_t addr = c->sigcontext_addr, fpstate_addr, off;
144d77787f2SJonathan Schleifer  int ret, is_fpstate = 0;
145d77787f2SJonathan Schleifer
146d77787f2SJonathan Schleifer  switch (c->sigcontext_format)
147d77787f2SJonathan Schleifer    {
148d77787f2SJonathan Schleifer    case X86_SCF_NONE:
149d77787f2SJonathan Schleifer      return DWARF_REG_LOC (&c->dwarf, reg);
150d77787f2SJonathan Schleifer
151d77787f2SJonathan Schleifer    case X86_SCF_LINUX_SIGFRAME:
152d77787f2SJonathan Schleifer      break;
153d77787f2SJonathan Schleifer
154d77787f2SJonathan Schleifer    case X86_SCF_LINUX_RT_SIGFRAME:
155d77787f2SJonathan Schleifer      addr += LINUX_UC_MCONTEXT_OFF;
156d77787f2SJonathan Schleifer      break;
157d77787f2SJonathan Schleifer
158d77787f2SJonathan Schleifer    default:
159d77787f2SJonathan Schleifer      return DWARF_NULL_LOC;
160d77787f2SJonathan Schleifer    }
161d77787f2SJonathan Schleifer
162d77787f2SJonathan Schleifer  switch (reg)
163d77787f2SJonathan Schleifer    {
164d77787f2SJonathan Schleifer    case UNW_X86_GS: off = LINUX_SC_GS_OFF; break;
165d77787f2SJonathan Schleifer    case UNW_X86_FS: off = LINUX_SC_FS_OFF; break;
166d77787f2SJonathan Schleifer    case UNW_X86_ES: off = LINUX_SC_ES_OFF; break;
167d77787f2SJonathan Schleifer    case UNW_X86_DS: off = LINUX_SC_DS_OFF; break;
168d77787f2SJonathan Schleifer    case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break;
169d77787f2SJonathan Schleifer    case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break;
170d77787f2SJonathan Schleifer    case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break;
171d77787f2SJonathan Schleifer    case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break;
172d77787f2SJonathan Schleifer    case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break;
173d77787f2SJonathan Schleifer    case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break;
174d77787f2SJonathan Schleifer    case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break;
175d77787f2SJonathan Schleifer    case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break;
176d77787f2SJonathan Schleifer    case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break;
177d77787f2SJonathan Schleifer    case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break;
178d77787f2SJonathan Schleifer    case UNW_X86_CS: off = LINUX_SC_CS_OFF; break;
179d77787f2SJonathan Schleifer    case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break;
180d77787f2SJonathan Schleifer    case UNW_X86_SS: off = LINUX_SC_SS_OFF; break;
181d77787f2SJonathan Schleifer
182d77787f2SJonathan Schleifer      /* The following is probably not correct for all possible cases.
183d77787f2SJonathan Schleifer         Somebody who understands this better should review this for
184d77787f2SJonathan Schleifer         correctness.  */
185d77787f2SJonathan Schleifer
186d77787f2SJonathan Schleifer    case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break;
187d77787f2SJonathan Schleifer    case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break;
188d77787f2SJonathan Schleifer    case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break;
189d77787f2SJonathan Schleifer    case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break;
190d77787f2SJonathan Schleifer    case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break;
191d77787f2SJonathan Schleifer    case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break;
192d77787f2SJonathan Schleifer    case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break;
193d77787f2SJonathan Schleifer    case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break;
194d77787f2SJonathan Schleifer
195d77787f2SJonathan Schleifer      /* stacked fp registers */
196d77787f2SJonathan Schleifer    case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
197d77787f2SJonathan Schleifer    case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
198d77787f2SJonathan Schleifer      is_fpstate = 1;
199d77787f2SJonathan Schleifer      off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0);
200d77787f2SJonathan Schleifer      break;
201d77787f2SJonathan Schleifer
202d77787f2SJonathan Schleifer     /* SSE fp registers */
203d77787f2SJonathan Schleifer    case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
204d77787f2SJonathan Schleifer    case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
205d77787f2SJonathan Schleifer    case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
206d77787f2SJonathan Schleifer    case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
207d77787f2SJonathan Schleifer    case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
208d77787f2SJonathan Schleifer    case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
209d77787f2SJonathan Schleifer    case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
210d77787f2SJonathan Schleifer    case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
211d77787f2SJonathan Schleifer      is_fpstate = 1;
212d77787f2SJonathan Schleifer      off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
213d77787f2SJonathan Schleifer      break;
214d77787f2SJonathan Schleifer    case UNW_X86_XMM0:
215d77787f2SJonathan Schleifer    case UNW_X86_XMM1:
216d77787f2SJonathan Schleifer    case UNW_X86_XMM2:
217d77787f2SJonathan Schleifer    case UNW_X86_XMM3:
218d77787f2SJonathan Schleifer    case UNW_X86_XMM4:
219d77787f2SJonathan Schleifer    case UNW_X86_XMM5:
220d77787f2SJonathan Schleifer    case UNW_X86_XMM6:
221d77787f2SJonathan Schleifer    case UNW_X86_XMM7:
222d77787f2SJonathan Schleifer      is_fpstate = 1;
223d77787f2SJonathan Schleifer      off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
224d77787f2SJonathan Schleifer      break;
225d77787f2SJonathan Schleifer
226d77787f2SJonathan Schleifer    case UNW_X86_FOP:
227d77787f2SJonathan Schleifer    case UNW_X86_TSS:
228d77787f2SJonathan Schleifer    case UNW_X86_LDT:
229d77787f2SJonathan Schleifer    default:
230d77787f2SJonathan Schleifer      return DWARF_REG_LOC (&c->dwarf, reg);
231d77787f2SJonathan Schleifer    }
232d77787f2SJonathan Schleifer
233d77787f2SJonathan Schleifer  if (is_fpstate)
234d77787f2SJonathan Schleifer    {
235d77787f2SJonathan Schleifer      if ((ret = dwarf_get (&c->dwarf,
236d77787f2SJonathan Schleifer                            DWARF_MEM_LOC (&c->dwarf,
237d77787f2SJonathan Schleifer                                           addr + LINUX_SC_FPSTATE_OFF),
238d77787f2SJonathan Schleifer                            &fpstate_addr)) < 0)
239d77787f2SJonathan Schleifer        return DWARF_NULL_LOC;
240d77787f2SJonathan Schleifer
241d77787f2SJonathan Schleifer      if (!fpstate_addr)
242d77787f2SJonathan Schleifer        return DWARF_NULL_LOC;
243d77787f2SJonathan Schleifer
244d77787f2SJonathan Schleifer      return DWARF_MEM_LOC (c, fpstate_addr + off);
245d77787f2SJonathan Schleifer    }
246d77787f2SJonathan Schleifer  else
247d77787f2SJonathan Schleifer    return DWARF_MEM_LOC (c, addr + off);
248d77787f2SJonathan Schleifer}
249d77787f2SJonathan Schleifer
250d77787f2SJonathan Schleifer#ifndef UNW_REMOTE_ONLY
251d77787f2SJonathan SchleiferHIDDEN void *
252d77787f2SJonathan Schleiferx86_r_uc_addr (ucontext_t *uc, int reg)
253d77787f2SJonathan Schleifer{
254d77787f2SJonathan Schleifer  void *addr;
255d77787f2SJonathan Schleifer
256d77787f2SJonathan Schleifer  switch (reg)
257d77787f2SJonathan Schleifer    {
258d77787f2SJonathan Schleifer    case UNW_X86_GS:  addr = &uc->uc_mcontext.gregs[REG_GS]; break;
259d77787f2SJonathan Schleifer    case UNW_X86_FS:  addr = &uc->uc_mcontext.gregs[REG_FS]; break;
260d77787f2SJonathan Schleifer    case UNW_X86_ES:  addr = &uc->uc_mcontext.gregs[REG_ES]; break;
261d77787f2SJonathan Schleifer    case UNW_X86_DS:  addr = &uc->uc_mcontext.gregs[REG_DS]; break;
262d77787f2SJonathan Schleifer    case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break;
263d77787f2SJonathan Schleifer    case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break;
264d77787f2SJonathan Schleifer    case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break;
265d77787f2SJonathan Schleifer    case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break;
266d77787f2SJonathan Schleifer    case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break;
267d77787f2SJonathan Schleifer    case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break;
268d77787f2SJonathan Schleifer    case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break;
269d77787f2SJonathan Schleifer    case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break;
270d77787f2SJonathan Schleifer    case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break;
271d77787f2SJonathan Schleifer    case UNW_X86_TRAPNO:  addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break;
272d77787f2SJonathan Schleifer    case UNW_X86_CS:  addr = &uc->uc_mcontext.gregs[REG_CS]; break;
273d77787f2SJonathan Schleifer    case UNW_X86_EFLAGS:  addr = &uc->uc_mcontext.gregs[REG_EFL]; break;
274d77787f2SJonathan Schleifer    case UNW_X86_SS:  addr = &uc->uc_mcontext.gregs[REG_SS]; break;
275d77787f2SJonathan Schleifer
276d77787f2SJonathan Schleifer    default:
277d77787f2SJonathan Schleifer      addr = NULL;
278d77787f2SJonathan Schleifer    }
279d77787f2SJonathan Schleifer  return addr;
280d77787f2SJonathan Schleifer}
281d77787f2SJonathan Schleifer
282d77787f2SJonathan SchleiferHIDDEN int
283d77787f2SJonathan Schleiferx86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
284d77787f2SJonathan Schleifer{
285d77787f2SJonathan Schleifer  struct cursor *c = (struct cursor *) cursor;
286d77787f2SJonathan Schleifer  ucontext_t *uc = c->uc;
287d77787f2SJonathan Schleifer
288d77787f2SJonathan Schleifer  /* Ensure c->pi is up-to-date.  On x86, it's relatively common to be
289d77787f2SJonathan Schleifer     missing DWARF unwind info.  We don't want to fail in that case,
290d77787f2SJonathan Schleifer     because the frame-chain still would let us do a backtrace at
291d77787f2SJonathan Schleifer     least.  */
292d77787f2SJonathan Schleifer  dwarf_make_proc_info (&c->dwarf);
293d77787f2SJonathan Schleifer
294d77787f2SJonathan Schleifer  if (unlikely (c->sigcontext_format != X86_SCF_NONE))
295d77787f2SJonathan Schleifer    {
296d77787f2SJonathan Schleifer      struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
297d77787f2SJonathan Schleifer
298d77787f2SJonathan Schleifer      Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
299d77787f2SJonathan Schleifer      sigreturn (sc);
300d77787f2SJonathan Schleifer    }
301d77787f2SJonathan Schleifer  else
302d77787f2SJonathan Schleifer    {
303d77787f2SJonathan Schleifer      Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
304d77787f2SJonathan Schleifer      setcontext (uc);
305d77787f2SJonathan Schleifer    }
306d77787f2SJonathan Schleifer  return -UNW_EINVAL;
307d77787f2SJonathan Schleifer}
308d77787f2SJonathan Schleifer#endif
309