darwin-fallback.c revision 169689
1218887Sdim/* Fallback frame-state unwinder for Darwin.
2218887Sdim   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3218887Sdim
4218887Sdim   This file is part of GCC.
5218887Sdim
6218887Sdim   GCC is free software; you can redistribute it and/or modify it
7218887Sdim   under the terms of the GNU General Public License as published by
8218887Sdim   the Free Software Foundation; either version 2, or (at your option)
9218887Sdim   any later version.
10221345Sdim
11218887Sdim   In addition to the permissions in the GNU General Public License, the
12218887Sdim   Free Software Foundation gives you unlimited permission to link the
13218887Sdim   compiled version of this file into combinations with other programs,
14218887Sdim   and to distribute those combinations without any restriction coming
15218887Sdim   from the use of this file.  (The General Public License restrictions
16249423Sdim   do apply in other respects; for example, they cover modification of
17218887Sdim   the file, and distribution when not linked into a combined
18263508Sdim   executable.)
19218887Sdim
20218887Sdim   GCC is distributed in the hope that it will be useful, but WITHOUT
21218887Sdim   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22218887Sdim   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
23218887Sdim   License for more details.
24218887Sdim
25243830Sdim   You should have received a copy of the GNU General Public License
26263508Sdim   along with GCC; see the file COPYING.  If not, write to the Free
27263508Sdim   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28239462Sdim   02110-1301, USA.  */
29218887Sdim
30218887Sdim#include "tconfig.h"
31218887Sdim#include "tsystem.h"
32218887Sdim#include "coretypes.h"
33263508Sdim#include "tm.h"
34263508Sdim#include "dwarf2.h"
35263508Sdim#include "unwind.h"
36263508Sdim#include "unwind-dw2.h"
37263508Sdim#include <stdint.h>
38263508Sdim#include <stdbool.h>
39263508Sdim#include <sys/types.h>
40263508Sdim#include <signal.h>
41263508Sdim
42263508Sdimtypedef unsigned long reg_unit;
43263508Sdim
44263508Sdim/* Place in GPRS the parameters to the first 'sc' instruction that would
45263508Sdim   have been executed if we were returning from this CONTEXT, or
46263508Sdim   return false if an unexpected instruction is encountered.  */
47263508Sdim
48263508Sdimstatic bool
49263508Sdiminterpret_libc (reg_unit gprs[32], struct _Unwind_Context *context)
50263508Sdim{
51263508Sdim  uint32_t *pc = (uint32_t *)_Unwind_GetIP (context);
52263508Sdim  uint32_t cr;
53263508Sdim  reg_unit lr = (reg_unit) pc;
54263508Sdim  reg_unit ctr = 0;
55263508Sdim  uint32_t *invalid_address = NULL;
56263508Sdim
57263508Sdim  int i;
58263508Sdim
59263508Sdim  for (i = 0; i < 13; i++)
60263508Sdim    gprs[i] = 1;
61263508Sdim  gprs[1] = _Unwind_GetCFA (context);
62263508Sdim  for (; i < 32; i++)
63263508Sdim    gprs[i] = _Unwind_GetGR (context, i);
64263508Sdim  cr = _Unwind_GetGR (context, CR2_REGNO);
65263508Sdim
66263508Sdim  /* For each supported Libc, we have to track the code flow
67249423Sdim     all the way back into the kernel.
68249423Sdim
69249423Sdim     This code is believed to support all released Libc/Libsystem builds since
70249423Sdim     Jaguar 6C115, including all the security updates.  To be precise,
71249423Sdim
72249423Sdim     Libc	Libsystem	Build(s)
73249423Sdim     262~1	60~37		6C115
74218887Sdim     262~1	60.2~4		6D52
75218887Sdim     262~1	61~3		6F21-6F22
76218887Sdim     262~1	63~24		6G30-6G37
77218887Sdim     262~1	63~32		6I34-6I35
78226633Sdim     262~1	63~64		6L29-6L60
79218887Sdim     262.4.1~1	63~84		6L123-6R172
80249423Sdim
81249423Sdim     320~1	71~101		7B85-7D28
82249423Sdim     320~1	71~266		7F54-7F56
83249423Sdim     320~1	71~288		7F112
84249423Sdim     320~1	71~289		7F113
85249423Sdim     320.1.3~1	71.1.1~29	7H60-7H105
86263508Sdim     320.1.3~1	71.1.1~30	7H110-7H113
87239462Sdim     320.1.3~1	71.1.1~31	7H114
88239462Sdim
89239462Sdim     That's a big table!  It would be insane to try to keep track of
90239462Sdim     every little detail, so we just read the code itself and do what
91239462Sdim     it would do.
92239462Sdim  */
93218887Sdim
94218887Sdim  for (;;)
95263508Sdim    {
96263508Sdim      uint32_t ins = *pc++;
97263508Sdim
98263508Sdim      if ((ins & 0xFC000003) == 0x48000000)  /* b instruction */
99218887Sdim	{
100251662Sdim	  pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
101251662Sdim	  continue;
102226633Sdim	}
103249423Sdim      if ((ins & 0xFC600000) == 0x2C000000)  /* cmpwi */
104249423Sdim	{
105263508Sdim	  int32_t val1 = (int16_t) ins;
106263508Sdim	  int32_t val2 = gprs[ins >> 16 & 0x1F];
107263508Sdim	  /* Only beq and bne instructions are supported, so we only
108218887Sdim	     need to set the EQ bit.  */
109249423Sdim	  uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C);
110249423Sdim	  if (val1 == val2)
111249423Sdim	    cr |= mask;
112249423Sdim	  else
113263508Sdim	    cr &= ~mask;
114263508Sdim	  continue;
115263508Sdim	}
116249423Sdim      if ((ins & 0xFEC38003) == 0x40820000)  /* forwards beq/bne */
117239462Sdim	{
118239462Sdim	  if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1))
119239462Sdim	    pc += (ins & 0x7FFC) / 4 - 1;
120218887Sdim	  continue;
121263508Sdim	}
122218887Sdim      if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */
123218887Sdim	{
124218887Sdim	  gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F]
125251662Sdim				     | gprs [ins >> 21 & 0x1F]);
126251662Sdim	  continue;
127263508Sdim	}
128263508Sdim      if (ins >> 26 == 0x0E)  /* addi, including li */
129263508Sdim	{
130218887Sdim	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
131218887Sdim	  gprs [ins >> 21 & 0x1F] = src + (int16_t) ins;
132239462Sdim	  continue;
133218887Sdim	}
134218887Sdim      if (ins >> 26 == 0x0F)  /* addis, including lis */
135218887Sdim	{
136218887Sdim	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
137263508Sdim	  gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16);
138239462Sdim	  continue;
139249423Sdim	}
140218887Sdim      if (ins >> 26 == 0x20)  /* lwz */
141243830Sdim	{
142218887Sdim	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
143239462Sdim	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
144239462Sdim	  if (p == invalid_address)
145249423Sdim	    return false;
146218887Sdim	  gprs [ins >> 21 & 0x1F] = *p;
147239462Sdim	  continue;
148218887Sdim	}
149243830Sdim      if (ins >> 26 == 0x21)  /* lwzu */
150239462Sdim	{
151218887Sdim	  uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins);
152218887Sdim	  if (p == invalid_address)
153218887Sdim	    return false;
154239462Sdim	  gprs [ins >> 21 & 0x1F] = *p;
155239462Sdim	  continue;
156218887Sdim	}
157239462Sdim      if (ins >> 26 == 0x24)  /* stw */
158239462Sdim	/* What we hope this is doing is '--in_sigtramp'.  We don't want
159239462Sdim	   to actually store to memory, so just make a note of the
160218887Sdim	   address and refuse to load from it.  */
161263508Sdim	{
162263508Sdim	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
163263508Sdim	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
164218887Sdim	  if (p == NULL || invalid_address != NULL)
165263508Sdim	    return false;
166249423Sdim	  invalid_address = p;
167243830Sdim	  continue;
168218887Sdim	}
169218887Sdim      if (ins >> 26 == 0x2E) /* lmw */
170249423Sdim	{
171249423Sdim	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
172263508Sdim	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
173218887Sdim	  int i;
174218887Sdim
175263508Sdim	  for (i = (ins >> 21 & 0x1F); i < 32; i++)
176218887Sdim	    {
177263508Sdim	      if (p == invalid_address)
178218887Sdim		return false;
179263508Sdim	      gprs[i] = *p++;
180263508Sdim	    }
181263508Sdim	  continue;
182263508Sdim	}
183263508Sdim      if ((ins & 0xFC1FFFFF) == 0x7c0803a6)  /* mtlr */
184263508Sdim	{
185263508Sdim	  lr = gprs [ins >> 21 & 0x1F];
186218887Sdim	  continue;
187218887Sdim	}
188226633Sdim      if ((ins & 0xFC1FFFFF) == 0x7c0802a6)  /* mflr */
189218887Sdim	{
190218887Sdim	  gprs [ins >> 21 & 0x1F] = lr;
191226633Sdim	  continue;
192263508Sdim	}
193263508Sdim      if ((ins & 0xFC1FFFFF) == 0x7c0903a6)  /* mtctr */
194263508Sdim	{
195263508Sdim	  ctr = gprs [ins >> 21 & 0x1F];
196263508Sdim	  continue;
197263508Sdim	}
198226633Sdim      /* The PowerPC User's Manual says that bit 11 of the mtcrf
199226633Sdim	 instruction is reserved and should be set to zero, but it
200263508Sdim	 looks like the Darwin assembler doesn't do that... */
201218887Sdim      if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */
202226633Sdim	{
203218887Sdim	  int i;
204226633Sdim	  uint32_t mask = 0;
205263508Sdim	  for (i = 0; i < 8; i++)
206263508Sdim	    mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i;
207263508Sdim	  cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask);
208263508Sdim	  continue;
209263508Sdim	}
210263508Sdim      if (ins == 0x429f0005)  /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
211263508Sdim	{
212263508Sdim	  lr = (reg_unit) pc;
213218887Sdim	  continue;
214218887Sdim	}
215218887Sdim      if (ins == 0x4e800420) /* bctr */
216218887Sdim	{
217263508Sdim	  pc = (uint32_t *) ctr;
218263508Sdim	  continue;
219263508Sdim	}
220263508Sdim      if (ins == 0x44000002) /* sc */
221263508Sdim	return true;
222263508Sdim
223218887Sdim      return false;
224263508Sdim    }
225263508Sdim}
226263508Sdim
227263508Sdim/* We used to include <ucontext.h> and <mach/thread_status.h>,
228263508Sdim   but they change so much between different Darwin system versions
229263508Sdim   that it's much easier to just write the structures involved here
230263508Sdim   directly.  */
231263508Sdim
232263508Sdim/* These defines are from the kernel's bsd/dev/ppc/unix_signal.c.  */
233263508Sdim#define UC_TRAD                 1
234263508Sdim#define UC_TRAD_VEC             6
235218887Sdim#define UC_TRAD64               20
236263508Sdim#define UC_TRAD64_VEC           25
237263508Sdim#define UC_FLAVOR               30
238263508Sdim#define UC_FLAVOR_VEC           35
239263508Sdim#define UC_FLAVOR64             40
240218887Sdim#define UC_FLAVOR64_VEC         45
241263508Sdim#define UC_DUAL                 50
242263508Sdim#define UC_DUAL_VEC             55
243263508Sdim
244263508Sdimstruct gcc_ucontext
245218887Sdim{
246218887Sdim  int onstack;
247234353Sdim  sigset_t sigmask;
248218887Sdim  void * stack_sp;
249218887Sdim  size_t stack_sz;
250263508Sdim  int stack_flags;
251263508Sdim  struct gcc_ucontext *link;
252263508Sdim  size_t mcsize;
253218887Sdim  struct gcc_mcontext32 *mcontext;
254263508Sdim};
255263508Sdim
256263508Sdimstruct gcc_float_vector_state
257263508Sdim{
258263508Sdim  double fpregs[32];
259263508Sdim  uint32_t fpscr_pad;
260263508Sdim  uint32_t fpscr;
261263508Sdim  uint32_t save_vr[32][4];
262263508Sdim  uint32_t save_vscr[4];
263263508Sdim};
264263508Sdim
265218887Sdimstruct gcc_mcontext32 {
266218887Sdim  uint32_t dar;
267218887Sdim  uint32_t dsisr;
268218887Sdim  uint32_t exception;
269218887Sdim  uint32_t padding1[5];
270218887Sdim  uint32_t srr0;
271226633Sdim  uint32_t srr1;
272218887Sdim  uint32_t gpr[32];
273218887Sdim  uint32_t cr;
274239462Sdim  uint32_t xer;
275239462Sdim  uint32_t lr;
276239462Sdim  uint32_t ctr;
277218887Sdim  uint32_t mq;
278218887Sdim  uint32_t vrsave;
279218887Sdim  struct gcc_float_vector_state fvs;
280218887Sdim};
281218887Sdim
282218887Sdim/* These are based on /usr/include/ppc/ucontext.h and
283218887Sdim   /usr/include/mach/ppc/thread_status.h, but rewritten to be more
284218887Sdim   convenient, to compile on Jaguar, and to work around Radar 3712064
285239462Sdim   on Panther, which is that the 'es' field of 'struct mcontext64' has
286239462Sdim   the wrong type (doh!).  */
287239462Sdim
288239462Sdimstruct gcc_mcontext64 {
289239462Sdim  uint64_t dar;
290239462Sdim  uint32_t dsisr;
291239462Sdim  uint32_t exception;
292239462Sdim  uint32_t padding1[4];
293239462Sdim  uint64_t srr0;
294218887Sdim  uint64_t srr1;
295218887Sdim  uint32_t gpr[32][2];
296218887Sdim  uint32_t cr;
297218887Sdim  uint32_t xer[2];  /* These are arrays because the original structure has them misaligned.  */
298218887Sdim  uint32_t lr[2];
299263508Sdim  uint32_t ctr[2];
300263508Sdim  uint32_t vrsave;
301263508Sdim  struct gcc_float_vector_state fvs;
302263508Sdim};
303263508Sdim
304218887Sdim#define UC_FLAVOR_SIZE \
305218887Sdim  (sizeof (struct gcc_mcontext32) - 33*16)
306239462Sdim
307218887Sdim#define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32))
308263508Sdim
309263508Sdim#define UC_FLAVOR64_SIZE \
310263508Sdim  (sizeof (struct gcc_mcontext64) - 33*16)
311263508Sdim
312263508Sdim#define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
313263508Sdim
314218887Sdim/* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS
315263508Sdim   to represent the execution of a signal return; or, if not a signal
316263508Sdim   return, return false.  */
317263508Sdim
318218887Sdimstatic bool
319218887Sdimhandle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32],
320218887Sdim		_Unwind_Ptr old_cfa)
321218887Sdim{
322218887Sdim  struct gcc_ucontext *uctx;
323218887Sdim  bool is_64, is_vector;
324218887Sdim  struct gcc_float_vector_state * float_vector_state;
325218887Sdim  _Unwind_Ptr new_cfa;
326218887Sdim  int i;
327218887Sdim  static _Unwind_Ptr return_addr;
328218887Sdim
329218887Sdim  /* Yay!  We're in a Libc that we understand, and it's made a
330218887Sdim     system call.  It'll be one of two kinds: either a Jaguar-style
331218887Sdim     SYS_sigreturn, or a Panther-style 'syscall' call with 184, which
332218887Sdim     is also SYS_sigreturn.  */
333218887Sdim
334218887Sdim  if (gprs[0] == 0x67 /* SYS_SIGRETURN */)
335218887Sdim    {
336218887Sdim      uctx = (struct gcc_ucontext *) gprs[3];
337218887Sdim      is_vector = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE
338218887Sdim		   || uctx->mcsize == UC_FLAVOR_VEC_SIZE);
339218887Sdim      is_64 = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE
340218887Sdim	       || uctx->mcsize == UC_FLAVOR64_SIZE);
341218887Sdim    }
342218887Sdim  else if (gprs[0] == 0 && gprs[3] == 184)
343218887Sdim    {
344243830Sdim      int ctxstyle = gprs[5];
345218887Sdim      uctx = (struct gcc_ucontext *) gprs[4];
346218887Sdim      is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
347239462Sdim		   || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
348239462Sdim      is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
349263508Sdim	       || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
350263508Sdim    }
351251662Sdim  else
352263508Sdim    return false;
353263508Sdim
354263508Sdim#define set_offset(r, addr)					\
355263508Sdim  (fs->regs.reg[r].how = REG_SAVED_OFFSET,			\
356263508Sdim   fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
357263508Sdim
358263508Sdim  /* Restore even the registers that are not call-saved, since they
359263508Sdim     might be being used in the prologue to save other registers,
360263508Sdim     for instance GPR0 is sometimes used to save LR.  */
361239462Sdim
362218887Sdim  /* Handle the GPRs, and produce the information needed to do the rest.  */
363263508Sdim  if (is_64)
364251662Sdim    {
365251662Sdim      /* The context is 64-bit, but it doesn't carry any extra information
366251662Sdim	 for us because only the low 32 bits of the registers are
367251662Sdim	 call-saved.  */
368218887Sdim      struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->mcontext;
369251662Sdim      int i;
370218887Sdim
371218887Sdim      float_vector_state = &m64->fvs;
372218887Sdim
373218887Sdim      new_cfa = m64->gpr[1][1];
374218887Sdim
375218887Sdim      set_offset (CR2_REGNO, &m64->cr);
376218887Sdim      for (i = 0; i < 32; i++)
377218887Sdim	set_offset (i, m64->gpr[i] + 1);
378218887Sdim      set_offset (XER_REGNO, m64->xer + 1);
379218887Sdim      set_offset (LINK_REGISTER_REGNUM, m64->lr + 1);
380218887Sdim      set_offset (COUNT_REGISTER_REGNUM, m64->ctr + 1);
381218887Sdim      if (is_vector)
382218887Sdim	set_offset (VRSAVE_REGNO, &m64->vrsave);
383218887Sdim
384218887Sdim      /* Sometimes, srr0 points to the instruction that caused the exception,
385218887Sdim	 and sometimes to the next instruction to be executed; we want
386218887Sdim	 the latter.  */
387218887Sdim      if (m64->exception == 3 || m64->exception == 4
388218887Sdim	  || m64->exception == 6
389218887Sdim	  || (m64->exception == 7 && !(m64->srr1 & 0x10000)))
390218887Sdim	return_addr = m64->srr0 + 4;
391218887Sdim      else
392218887Sdim	return_addr = m64->srr0;
393218887Sdim    }
394263508Sdim  else
395263508Sdim    {
396263508Sdim      struct gcc_mcontext32 *m = uctx->mcontext;
397263508Sdim      int i;
398263508Sdim
399243830Sdim      float_vector_state = &m->fvs;
400263508Sdim
401263508Sdim      new_cfa = m->gpr[1];
402263508Sdim
403239462Sdim      set_offset (CR2_REGNO, &m->cr);
404239462Sdim      for (i = 0; i < 32; i++)
405263508Sdim	set_offset (i, m->gpr + i);
406263508Sdim      set_offset (XER_REGNO, &m->xer);
407263508Sdim      set_offset (LINK_REGISTER_REGNUM, &m->lr);
408263508Sdim      set_offset (COUNT_REGISTER_REGNUM, &m->ctr);
409263508Sdim
410263508Sdim      if (is_vector)
411263508Sdim	set_offset (VRSAVE_REGNO, &m->vrsave);
412263508Sdim
413263508Sdim      /* Sometimes, srr0 points to the instruction that caused the exception,
414263508Sdim	 and sometimes to the next instruction to be executed; we want
415263508Sdim	 the latter.  */
416263508Sdim      if (m->exception == 3 || m->exception == 4
417263508Sdim	  || m->exception == 6
418263508Sdim	  || (m->exception == 7 && !(m->srr1 & 0x10000)))
419263508Sdim	return_addr = m->srr0 + 4;
420218887Sdim      else
421218887Sdim	return_addr = m->srr0;
422218887Sdim    }
423218887Sdim
424239462Sdim  fs->cfa_how = CFA_REG_OFFSET;
425249423Sdim  fs->cfa_reg = STACK_POINTER_REGNUM;
426239462Sdim  fs->cfa_offset = new_cfa - old_cfa;;
427239462Sdim
428239462Sdim  /* The choice of column for the return address is somewhat tricky.
429249423Sdim     Fortunately, the actual choice is private to this file, and
430239462Sdim     the space it's reserved from is the GCC register space, not the
431239462Sdim     DWARF2 numbering.  So any free element of the right size is an OK
432239462Sdim     choice.  Thus: */
433239462Sdim  fs->retaddr_column = ARG_POINTER_REGNUM;
434239462Sdim  /* FIXME: this should really be done using a DWARF2 location expression,
435239462Sdim     not using a static variable.  In fact, this entire file should
436249423Sdim     be implemented in DWARF2 expressions.  */
437249423Sdim  set_offset (ARG_POINTER_REGNUM, &return_addr);
438239462Sdim
439239462Sdim  for (i = 0; i < 32; i++)
440239462Sdim    set_offset (32 + i, float_vector_state->fpregs + i);
441239462Sdim  set_offset (SPEFSCR_REGNO, &float_vector_state->fpscr);
442239462Sdim
443239462Sdim  if (is_vector)
444218887Sdim    {
445218887Sdim      for (i = 0; i < 32; i++)
446218887Sdim	set_offset (FIRST_ALTIVEC_REGNO + i, float_vector_state->save_vr + i);
447218887Sdim      set_offset (VSCR_REGNO, float_vector_state->save_vscr);
448218887Sdim    }
449218887Sdim
450239462Sdim  return true;
451249423Sdim}
452239462Sdim
453249423Sdim/* This is also prototyped in rs6000/darwin.h, inside the
454239462Sdim   MD_FALLBACK_FRAME_STATE_FOR macro.  */
455263508Sdimextern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
456263508Sdim					      _Unwind_FrameState *fs);
457263508Sdim
458263508Sdim/* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
459263508Sdim   returning true iff the frame was a sigreturn() frame that we
460263508Sdim   can understand.  */
461263508Sdim
462263508Sdimbool
463263508Sdim_Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
464263508Sdim				  _Unwind_FrameState *fs)
465239462Sdim{
466239462Sdim  reg_unit gprs[32];
467239462Sdim
468239462Sdim  if (!interpret_libc (gprs, context))
469239462Sdim    return false;
470239462Sdim  return handle_syscall (fs, gprs, _Unwind_GetCFA (context));
471239462Sdim}
472239462Sdim