1/* _Unwind_Frames_Extra with shadow stack for x86-64 and x86.
2   Copyright (C) 2017-2022 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23<http://www.gnu.org/licenses/>.  */
24
25#include <x86gprintrin.h>
26
27/* Unwind the shadow stack for EH.  */
28#undef _Unwind_Frames_Extra
29#define _Unwind_Frames_Extra(x)			\
30  do						\
31    {						\
32      _Unwind_Word ssp = _get_ssp ();		\
33      if (ssp != 0)				\
34	{					\
35	  _Unwind_Word tmp = (x);		\
36	  while (tmp > 255)			\
37	    {					\
38	      _inc_ssp (255);			\
39	      tmp -= 255;			\
40	    }					\
41	  _inc_ssp (tmp);			\
42	}					\
43    }						\
44    while (0)
45
46/* Linux CET kernel places a restore token on shadow stack for signal
47   handler to enhance security.  The restore token is 8 byte and aligned
48   to 8 bytes.  It is usually transparent to user programs since kernel
49   will pop the restore token when signal handler returns.  But when an
50   exception is thrown from a signal handler, now we need to pop the
51   restore token from shadow stack.  For x86-64, we just need to treat
52   the signal frame as normal frame.  For i386, we need to search for
53   the restore token to check if the original shadow stack is 8 byte
54   aligned.  If the original shadow stack is 8 byte aligned, we just
55   need to pop 2 slots, one restore token, from shadow stack.  Otherwise,
56   we need to pop 3 slots, one restore token + 4 byte padding, from
57   shadow stack.  */
58#ifndef __x86_64__
59#undef _Unwind_Frames_Increment
60#define _Unwind_Frames_Increment(context, frames)	\
61  if (_Unwind_IsSignalFrame (context))			\
62    do							\
63      {							\
64	_Unwind_Word ssp, prev_ssp, token;		\
65	ssp = _get_ssp ();				\
66	if (ssp != 0)					\
67	  {						\
68	    /* Align shadow stack pointer to the next	\
69	       8 byte aligned boundary.  */		\
70	    ssp = (ssp + 4) & ~7;			\
71	    do						\
72	      {						\
73		/* Look for a restore token.  */	\
74		token = (*(_Unwind_Word *) (ssp - 8));	\
75		prev_ssp = token & ~7;			\
76		if (prev_ssp == ssp)			\
77		  break;				\
78		ssp += 8;				\
79	      }						\
80	    while (1);					\
81	    frames += (token & 0x4) ? 3 : 2;		\
82	  }						\
83      }							\
84    while (0);						\
85  else							\
86    frames++;
87#endif
88