1
2/*--------------------------------------------------------------------*/
3/*--- Create/destroy signal delivery frames.                       ---*/
4/*---                                       sigframe-amd64-linux.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8   This file is part of Valgrind, a dynamic binary instrumentation
9   framework.
10
11   Copyright (C) 2000-2013 Nicholas Nethercote
12      njn@valgrind.org
13
14   This program is free software; you can redistribute it and/or
15   modify it under the terms of the GNU General Public License as
16   published by the Free Software Foundation; either version 2 of the
17   License, or (at your option) any later version.
18
19   This program is distributed in the hope that it will be useful, but
20   WITHOUT ANY WARRANTY; without even the implied warranty of
21   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22   General Public License for more details.
23
24   You should have received a copy of the GNU General Public License
25   along with this program; if not, write to the Free Software
26   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27   02111-1307, USA.
28
29   The GNU General Public License is contained in the file COPYING.
30*/
31
32#if defined(VGP_amd64_linux)
33
34#include "pub_core_basics.h"
35#include "pub_core_vki.h"
36#include "pub_core_libcsetjmp.h"    // to keep _threadstate.h happy
37#include "pub_core_threadstate.h"
38#include "pub_core_aspacemgr.h"
39#include "pub_core_libcbase.h"
40#include "pub_core_libcassert.h"
41#include "pub_core_libcprint.h"
42#include "pub_core_machine.h"
43#include "pub_core_options.h"
44#include "pub_core_signals.h"
45#include "pub_core_tooliface.h"
46#include "pub_core_trampoline.h"
47#include "pub_core_sigframe.h"   /* self */
48
49/* This module creates and removes signal frames for signal deliveries
50   on amd64-linux.
51
52   Note, this file contains kernel-specific knowledge in the form of
53   'struct rt_sigframe'.  How does that relate to the vki kernel
54   interface stuff?
55
56   A 'struct rtsigframe' is pushed onto the client's stack.  This
57   contains a subsidiary vki_ucontext.  That holds the vcpu's state
58   across the signal, so that the sighandler can mess with the vcpu
59   state if it really wants.
60
61   FIXME: sigcontexting is basically broken for the moment.  When
62   delivering a signal, the integer registers and %rflags are
63   correctly written into the sigcontext, however the FP and SSE state
64   is not.  When returning from a signal, only the integer registers
65   are restored from the sigcontext; the rest of the CPU state is
66   restored to what it was before the signal.
67
68   This will be fixed.
69*/
70
71
72/*------------------------------------------------------------*/
73/*--- Signal frame layouts                                 ---*/
74/*------------------------------------------------------------*/
75
76// A structure in which to save the application's registers
77// during the execution of signal handlers.
78
79// In theory, so long as we get the arguments to the handler function
80// right, it doesn't matter what the exact layout of the rest of the
81// frame is.  Unfortunately, things like gcc's exception unwinding
82// make assumptions about the locations of various parts of the frame,
83// so we need to duplicate it exactly.
84
85/* Valgrind-specific parts of the signal frame */
86struct vg_sigframe
87{
88   /* Sanity check word. */
89   UInt magicPI;
90
91   UInt handlerflags;	/* flags for signal handler */
92
93
94   /* Safely-saved version of sigNo, as described above. */
95   Int  sigNo_private;
96
97   /* XXX This is wrong.  Surely we should store the shadow values
98      into the shadow memory behind the actual values? */
99   VexGuestAMD64State vex_shadow1;
100   VexGuestAMD64State vex_shadow2;
101
102   /* HACK ALERT */
103   VexGuestAMD64State vex;
104   /* end HACK ALERT */
105
106   /* saved signal mask to be restored when handler returns */
107   vki_sigset_t	mask;
108
109   /* Sanity check word.  Is the highest-addressed word; do not
110      move!*/
111   UInt magicE;
112};
113
114struct rt_sigframe
115{
116   /* Sig handler's return address */
117   Addr retaddr;
118
119   /* ucontext */
120   struct vki_ucontext uContext;
121
122   /* siginfo */
123   vki_siginfo_t sigInfo;
124   struct _vki_fpstate fpstate;
125
126   struct vg_sigframe vg;
127};
128
129
130//:: /*------------------------------------------------------------*/
131//:: /*--- Signal operations                                    ---*/
132//:: /*------------------------------------------------------------*/
133//::
134//:: /*
135//::    Great gobs of FP state conversion taken wholesale from
136//::    linux/arch/i386/kernel/i387.c
137//::  */
138//::
139//:: /*
140//::  * FXSR floating point environment conversions.
141//::  */
142//:: #define X86_FXSR_MAGIC		0x0000
143//::
144//:: /*
145//::  * FPU tag word conversions.
146//::  */
147//::
148//:: static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
149//:: {
150//::    unsigned int tmp; /* to avoid 16 bit prefixes in the code */
151//::
152//::    /* Transform each pair of bits into 01 (valid) or 00 (empty) */
153//::    tmp = ~twd;
154//::    tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
155//::    /* and move the valid bits to the lower byte. */
156//::    tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
157//::    tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
158//::    tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
159//::    return tmp;
160//:: }
161//::
162//:: static unsigned long twd_fxsr_to_i387( const struct i387_fxsave_struct *fxsave )
163//:: {
164//::    struct _vki_fpxreg *st = NULL;
165//::    unsigned long twd = (unsigned long) fxsave->twd;
166//::    unsigned long tag;
167//::    unsigned long ret = 0xffff0000u;
168//::    int i;
169//::
170//:: #define FPREG_ADDR(f, n)	((char *)&(f)->st_space + (n) * 16);
171//::
172//::    for ( i = 0 ; i < 8 ; i++ ) {
173//::       if ( twd & 0x1 ) {
174//:: 	 st = (struct _vki_fpxreg *) FPREG_ADDR( fxsave, i );
175//::
176//:: 	 switch ( st->exponent & 0x7fff ) {
177//:: 	 case 0x7fff:
178//:: 	    tag = 2;		/* Special */
179//:: 	    break;
180//:: 	 case 0x0000:
181//:: 	    if ( !st->significand[0] &&
182//:: 		 !st->significand[1] &&
183//:: 		 !st->significand[2] &&
184//:: 		 !st->significand[3] ) {
185//:: 	       tag = 1;	/* Zero */
186//:: 	    } else {
187//:: 	       tag = 2;	/* Special */
188//:: 	    }
189//:: 	    break;
190//:: 	 default:
191//:: 	    if ( st->significand[3] & 0x8000 ) {
192//:: 	       tag = 0;	/* Valid */
193//:: 	    } else {
194//:: 	       tag = 2;	/* Special */
195//:: 	    }
196//:: 	    break;
197//:: 	 }
198//::       } else {
199//:: 	 tag = 3;			/* Empty */
200//::       }
201//::       ret |= (tag << (2 * i));
202//::       twd = twd >> 1;
203//::    }
204//::    return ret;
205//:: }
206//::
207//:: static void convert_fxsr_to_user( struct _vki_fpstate *buf,
208//:: 				  const struct i387_fxsave_struct *fxsave )
209//:: {
210//::    unsigned long env[7];
211//::    struct _vki_fpreg *to;
212//::    struct _vki_fpxreg *from;
213//::    int i;
214//::
215//::    env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
216//::    env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
217//::    env[2] = twd_fxsr_to_i387(fxsave);
218//::    env[3] = fxsave->fip;
219//::    env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
220//::    env[5] = fxsave->foo;
221//::    env[6] = fxsave->fos;
222//::
223//::    VG_(memcpy)(buf, env, 7 * sizeof(unsigned long));
224//::
225//::    to = &buf->_st[0];
226//::    from = (struct _vki_fpxreg *) &fxsave->st_space[0];
227//::    for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
228//::       unsigned long __user *t = (unsigned long __user *)to;
229//::       unsigned long *f = (unsigned long *)from;
230//::
231//::       t[0] = f[0];
232//::       t[1] = f[1];
233//::       to->exponent = from->exponent;
234//::    }
235//:: }
236//::
237//:: static void convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
238//:: 				    const struct _vki_fpstate *buf )
239//:: {
240//::    unsigned long env[7];
241//::    struct _vki_fpxreg *to;
242//::    const struct _vki_fpreg *from;
243//::    int i;
244//::
245//::    VG_(memcpy)(env, buf, 7 * sizeof(long));
246//::
247//::    fxsave->cwd = (unsigned short)(env[0] & 0xffff);
248//::    fxsave->swd = (unsigned short)(env[1] & 0xffff);
249//::    fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
250//::    fxsave->fip = env[3];
251//::    fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
252//::    fxsave->fcs = (env[4] & 0xffff);
253//::    fxsave->foo = env[5];
254//::    fxsave->fos = env[6];
255//::
256//::    to = (struct _vki_fpxreg *) &fxsave->st_space[0];
257//::    from = &buf->_st[0];
258//::    for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
259//::       unsigned long *t = (unsigned long *)to;
260//::       unsigned long __user *f = (unsigned long __user *)from;
261//::
262//::       t[0] = f[0];
263//::       t[1] = f[1];
264//::       to->exponent = from->exponent;
265//::    }
266//:: }
267//::
268//:: static inline void save_i387_fsave( arch_thread_t *regs, struct _vki_fpstate *buf )
269//:: {
270//::    struct i387_fsave_struct *fs = &regs->m_sse.fsave;
271//::
272//::    fs->status = fs->swd;
273//::    VG_(memcpy)(buf, fs, sizeof(*fs));
274//:: }
275//::
276//:: static void save_i387_fxsave( arch_thread_t *regs, struct _vki_fpstate *buf )
277//:: {
278//::    const struct i387_fxsave_struct *fx = &regs->m_sse.fxsave;
279//::    convert_fxsr_to_user( buf, fx );
280//::
281//::    buf->status = fx->swd;
282//::    buf->magic = X86_FXSR_MAGIC;
283//::    VG_(memcpy)(buf->_fxsr_env, fx, sizeof(struct i387_fxsave_struct));
284//:: }
285//::
286//:: static void save_i387( arch_thread_t *regs, struct _vki_fpstate *buf )
287//:: {
288//::    if ( VG_(have_ssestate) )
289//::       save_i387_fxsave( regs, buf );
290//::    else
291//::       save_i387_fsave( regs, buf );
292//:: }
293//::
294//:: static inline void restore_i387_fsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
295//:: {
296//::    VG_(memcpy)( &regs->m_sse.fsave, buf, sizeof(struct i387_fsave_struct) );
297//:: }
298//::
299//:: static void restore_i387_fxsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
300//:: {
301//::    VG_(memcpy)(&regs->m_sse.fxsave, &buf->_fxsr_env[0],
302//:: 	       sizeof(struct i387_fxsave_struct) );
303//::    /* mxcsr reserved bits must be masked to zero for security reasons */
304//::    regs->m_sse.fxsave.mxcsr &= 0xffbf;
305//::    convert_fxsr_from_user( &regs->m_sse.fxsave, buf );
306//:: }
307//::
308//:: static void restore_i387( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
309//:: {
310//::    if ( VG_(have_ssestate) ) {
311//::       restore_i387_fxsave( regs, buf );
312//::    } else {
313//::       restore_i387_fsave( regs, buf );
314//::    }
315//:: }
316
317
318/*------------------------------------------------------------*/
319/*--- Creating signal frames                               ---*/
320/*------------------------------------------------------------*/
321
322/* Create a plausible-looking sigcontext from the thread's
323   Vex guest state.  NOTE: does not fill in the FP or SSE
324   bits of sigcontext at the moment.
325*/
326static
327void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
328                    UWord trapno, UWord err, const vki_sigset_t *set,
329                    struct vki_ucontext *uc, struct _vki_fpstate *fpstate)
330{
331   ThreadState *tst = VG_(get_ThreadState)(tid);
332   struct vki_sigcontext *sc = &uc->uc_mcontext;
333
334   VG_(memset)(uc, 0, sizeof(*uc));
335
336   uc->uc_flags = 0;
337   uc->uc_link = 0;
338   uc->uc_sigmask = *set;
339   uc->uc_stack = tst->altstack;
340   sc->fpstate = fpstate;
341
342   // FIXME: save_i387(&tst->arch, fpstate);
343
344#  define SC2(reg,REG)  sc->reg = tst->arch.vex.guest_##REG
345   SC2(r8,R8);
346   SC2(r9,R9);
347   SC2(r10,R10);
348   SC2(r11,R11);
349   SC2(r12,R12);
350   SC2(r13,R13);
351   SC2(r14,R14);
352   SC2(r15,R15);
353   SC2(rdi,RDI);
354   SC2(rsi,RSI);
355   SC2(rbp,RBP);
356   SC2(rbx,RBX);
357   SC2(rdx,RDX);
358   SC2(rax,RAX);
359   SC2(rcx,RCX);
360   SC2(rsp,RSP);
361
362   SC2(rip,RIP);
363   sc->eflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex);
364   // FIXME: SC2(cs,CS);
365   // FIXME: SC2(gs,GS);
366   // FIXME: SC2(fs,FS);
367   sc->trapno = trapno;
368   sc->err = err;
369#  undef SC2
370
371   sc->cr2 = (UWord)si->_sifields._sigfault._addr;
372}
373
374
375/* Extend the stack segment downwards if needed so as to ensure the
376   new signal frames are mapped to something.  Return a Bool
377   indicating whether or not the operation was successful.
378*/
379static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
380{
381   ThreadId        tid = tst->tid;
382   NSegment const* stackseg = NULL;
383
384   if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
385      stackseg = VG_(am_find_nsegment)(addr);
386      if (0 && stackseg)
387	 VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
388		     addr, stackseg->start, stackseg->end);
389   }
390
391   if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
392      VG_(message)(
393         Vg_UserMsg,
394         "Can't extend stack to %#lx during signal delivery for thread %d:\n",
395         addr, tid);
396      if (stackseg == NULL)
397         VG_(message)(Vg_UserMsg, "  no stack segment\n");
398      else
399         VG_(message)(Vg_UserMsg, "  too small or bad protection modes\n");
400
401      /* set SIGSEGV to default handler */
402      VG_(set_default_handler)(VKI_SIGSEGV);
403      VG_(synth_fault_mapping)(tid, addr);
404
405      /* The whole process should be about to die, since the default
406	 action of SIGSEGV to kill the whole process. */
407      return False;
408   }
409
410   /* For tracking memory events, indicate the entire frame has been
411      allocated. */
412   VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB,
413             size + VG_STACK_REDZONE_SZB, tid );
414
415   return True;
416}
417
418
419/* Build the Valgrind-specific part of a signal frame. */
420
421static void build_vg_sigframe(struct vg_sigframe *frame,
422			      ThreadState *tst,
423			      const vki_sigset_t *mask,
424			      UInt flags,
425			      Int sigNo)
426{
427   frame->sigNo_private = sigNo;
428   frame->magicPI       = 0x31415927;
429   frame->vex_shadow1   = tst->arch.vex_shadow1;
430   frame->vex_shadow2   = tst->arch.vex_shadow2;
431   /* HACK ALERT */
432   frame->vex           = tst->arch.vex;
433   /* end HACK ALERT */
434   frame->mask          = tst->sig_mask;
435   frame->handlerflags  = flags;
436   frame->magicE        = 0x27182818;
437}
438
439
440static Addr build_rt_sigframe(ThreadState *tst,
441			      Addr rsp_top_of_frame,
442			      const vki_siginfo_t *siginfo,
443                              const struct vki_ucontext *siguc,
444			      void *handler, UInt flags,
445			      const vki_sigset_t *mask,
446			      void *restorer)
447{
448   struct rt_sigframe *frame;
449   Addr rsp = rsp_top_of_frame;
450   Int	sigNo = siginfo->si_signo;
451   UWord trapno;
452   UWord err;
453
454   rsp -= sizeof(*frame);
455   rsp = VG_ROUNDDN(rsp, 16) - 8;
456   frame = (struct rt_sigframe *)rsp;
457
458   if (!extend(tst, rsp, sizeof(*frame)))
459      return rsp_top_of_frame;
460
461   /* retaddr, siginfo, uContext fields are to be written */
462   VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "rt signal handler frame",
463	     rsp, offsetof(struct rt_sigframe, vg) );
464
465   if (flags & VKI_SA_RESTORER)
466      frame->retaddr = (Addr)restorer;
467   else
468      frame->retaddr = (Addr)&VG_(amd64_linux_SUBST_FOR_rt_sigreturn);
469
470   if (siguc) {
471      trapno = siguc->uc_mcontext.trapno;
472      err = siguc->uc_mcontext.err;
473   } else {
474      trapno = 0;
475      err = 0;
476   }
477
478   VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
479
480   /* SIGILL defines addr to be the faulting address */
481   if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
482      frame->sigInfo._sifields._sigfault._addr
483         = (void*)tst->arch.vex.guest_RIP;
484
485   synth_ucontext(tst->tid, siginfo, trapno, err, mask,
486                  &frame->uContext, &frame->fpstate);
487
488   VG_TRACK( post_mem_write,  Vg_CoreSignal, tst->tid,
489             rsp, offsetof(struct rt_sigframe, vg) );
490
491   build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
492
493   return rsp;
494}
495
496
497void VG_(sigframe_create)( ThreadId tid,
498                            Addr rsp_top_of_frame,
499                            const vki_siginfo_t *siginfo,
500                            const struct vki_ucontext *siguc,
501                            void *handler,
502                            UInt flags,
503                            const vki_sigset_t *mask,
504                            void *restorer )
505{
506   Addr rsp;
507   struct rt_sigframe *frame;
508   ThreadState* tst = VG_(get_ThreadState)(tid);
509
510   rsp = build_rt_sigframe(tst, rsp_top_of_frame, siginfo, siguc,
511                                handler, flags, mask, restorer);
512   frame = (struct rt_sigframe *)rsp;
513
514   /* Set the thread so it will next run the handler. */
515   /* tst->m_rsp  = rsp;  also notify the tool we've updated RSP */
516   VG_(set_SP)(tid, rsp);
517   VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr));
518
519   //VG_(printf)("handler = %p\n", handler);
520   tst->arch.vex.guest_RIP = (Addr) handler;
521   tst->arch.vex.guest_RDI = (ULong) siginfo->si_signo;
522   tst->arch.vex.guest_RSI = (Addr) &frame->sigInfo;
523   tst->arch.vex.guest_RDX = (Addr) &frame->uContext;
524   /* And tell the tool that these registers have been written. */
525   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
526             offsetof(VexGuestAMD64State,guest_RIP), sizeof(UWord) );
527   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
528             offsetof(VexGuestAMD64State,guest_RDI), sizeof(UWord) );
529   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
530             offsetof(VexGuestAMD64State,guest_RSI), sizeof(UWord) );
531   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
532             offsetof(VexGuestAMD64State,guest_RDX), sizeof(UWord) );
533
534   /* This thread needs to be marked runnable, but we leave that the
535      caller to do. */
536
537   if (0)
538      VG_(printf)("pushed signal frame; %%RSP now = %#lx, "
539                  "next %%RIP = %#llx, status=%d\n",
540		  rsp, tst->arch.vex.guest_RIP, tst->status);
541}
542
543
544/*------------------------------------------------------------*/
545/*--- Destroying signal frames                             ---*/
546/*------------------------------------------------------------*/
547
548/* Return False and don't do anything, just set the client to take a
549   segfault, if it looks like the frame is corrupted. */
550static
551Bool restore_vg_sigframe ( ThreadState *tst,
552                           struct vg_sigframe *frame, Int *sigNo )
553{
554   if (frame->magicPI != 0x31415927 ||
555       frame->magicE  != 0x27182818) {
556      VG_(message)(Vg_UserMsg, "Thread %d return signal frame "
557                               "corrupted.  Killing process.\n",
558		   tst->tid);
559      VG_(set_default_handler)(VKI_SIGSEGV);
560      VG_(synth_fault)(tst->tid);
561      *sigNo = VKI_SIGSEGV;
562      return False;
563   }
564   tst->sig_mask         = frame->mask;
565   tst->tmp_sig_mask     = frame->mask;
566   tst->arch.vex_shadow1 = frame->vex_shadow1;
567   tst->arch.vex_shadow2 = frame->vex_shadow2;
568   /* HACK ALERT */
569   tst->arch.vex         = frame->vex;
570   /* end HACK ALERT */
571   *sigNo                = frame->sigNo_private;
572   return True;
573}
574
575static
576void restore_sigcontext( ThreadState *tst,
577                         struct vki_sigcontext *sc,
578                         struct _vki_fpstate *fpstate )
579{
580   tst->arch.vex.guest_RAX     = sc->rax;
581   tst->arch.vex.guest_RCX     = sc->rcx;
582   tst->arch.vex.guest_RDX     = sc->rdx;
583   tst->arch.vex.guest_RBX     = sc->rbx;
584   tst->arch.vex.guest_RBP     = sc->rbp;
585   tst->arch.vex.guest_RSP     = sc->rsp;
586   tst->arch.vex.guest_RSI     = sc->rsi;
587   tst->arch.vex.guest_RDI     = sc->rdi;
588   tst->arch.vex.guest_R8      = sc->r8;
589   tst->arch.vex.guest_R9      = sc->r9;
590   tst->arch.vex.guest_R10     = sc->r10;
591   tst->arch.vex.guest_R11     = sc->r11;
592   tst->arch.vex.guest_R12     = sc->r12;
593   tst->arch.vex.guest_R13     = sc->r13;
594   tst->arch.vex.guest_R14     = sc->r14;
595   tst->arch.vex.guest_R15     = sc->r15;
596//::    tst->arch.vex.guest_rflags  = sc->rflags;
597   tst->arch.vex.guest_RIP     = sc->rip;
598
599//::    tst->arch.vex.guest_CS      = sc->cs;
600//::    tst->arch.vex.guest_FS      = sc->fs;
601//::    tst->arch.vex.guest_GS      = sc->gs;
602
603//::    restore_i387(&tst->arch, fpstate);
604}
605
606
607static
608SizeT restore_rt_sigframe ( ThreadState *tst,
609                            struct rt_sigframe *frame, Int *sigNo )
610{
611   if (restore_vg_sigframe(tst, &frame->vg, sigNo))
612      restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate);
613
614   return sizeof(*frame);
615}
616
617
618void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
619{
620   Addr          rsp;
621   ThreadState*  tst;
622   SizeT	 size;
623   Int		 sigNo;
624
625   vg_assert(isRT);
626
627   tst = VG_(get_ThreadState)(tid);
628
629   /* Correctly reestablish the frame base address. */
630   rsp   = tst->arch.vex.guest_RSP;
631
632   size = restore_rt_sigframe(tst, (struct rt_sigframe *)rsp, &sigNo);
633
634   VG_TRACK( die_mem_stack_signal, rsp - VG_STACK_REDZONE_SZB,
635             size + VG_STACK_REDZONE_SZB );
636
637   if (VG_(clo_trace_signals))
638      VG_(message)(
639         Vg_DebugMsg,
640         "VG_(signal_return) (thread %d): isRT=%d valid magic; RIP=%#llx\n",
641         tid, isRT, tst->arch.vex.guest_RIP);
642
643   /* tell the tools */
644   VG_TRACK( post_deliver_signal, tid, sigNo );
645}
646
647#endif // defined(VGP_amd64_linux)
648
649/*--------------------------------------------------------------------*/
650/*--- end                                                          ---*/
651/*--------------------------------------------------------------------*/
652