Handle gcc __builtin_strcmp using 128/256 bit vectors with sse4.1, avx/avx2
[valgrind.git] / coregrind / m_sigframe / sigframe-solaris.c
blob1afb277d334583a8bbbcb1d8313701a226b8a606
2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-solaris.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2011-2017 Petr Pavlu
12 setup@dagobah.cz
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.
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.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
32 #include "pub_core_basics.h"
33 #include "pub_core_vki.h"
34 #include "pub_core_threadstate.h"
35 #include "pub_core_aspacemgr.h"
36 #include "pub_core_libcassert.h"
37 #include "pub_core_libcbase.h"
38 #include "pub_core_libcprint.h"
39 #include "pub_core_machine.h"
40 #include "pub_core_options.h"
41 #include "pub_core_signals.h"
42 #include "pub_core_tooliface.h"
43 #include "pub_core_sigframe.h" /* Self */
44 #include "pub_core_syswrap.h"
45 #include "priv_sigframe.h"
47 /* This module creates and removes signal frames for signal deliveries
48 on x86/amd64-solaris. */
50 /* Create a signal frame for thread 'tid'. Make a 3-arg frame regardless of
51 whether the client originally requested a 1-arg version (no SA_SIGINFO) or
52 a 3-arg one (SA_SIGINFO) since in the former case, the x86/amd64 calling
53 conventions will simply cause the extra 2 args to be ignored (inside the
54 handler). */
55 void VG_(sigframe_create)(ThreadId tid, Bool on_altstack,
56 Addr sp_top_of_frame, const vki_siginfo_t *siginfo,
57 const struct vki_ucontext *siguc,
58 void *handler, UInt flags, const vki_sigset_t *mask,
59 void *restorer)
61 ThreadState *tst = VG_(get_ThreadState)(tid);
62 Addr esp;
63 vki_sigframe_t *frame;
64 Int signo = siginfo->si_signo;
66 /* Calculate new stack pointer. */
67 esp = sp_top_of_frame - sizeof(vki_sigframe_t);
68 esp = VG_ROUNDDN(esp, 16) - sizeof(UWord);
70 if (!ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
71 return;
73 /* Fill in the frame. */
74 frame = (vki_sigframe_t*)esp;
76 /* Set a bogus return address. This return address should be never used
77 because to return from a signal handler a program has to call
78 setcontext() explicitly. */
79 frame->return_addr = (void*)~0UL;
81 /* Save current context. (This has to be done before the thread state is
82 modified in any way.) */
83 VG_(save_context)(tid, &frame->ucontext, Vg_CoreSignal);
85 /* Fill in the siginfo. */
86 frame->siginfo = *siginfo;
87 /* Set expected si_addr value.
89 Manual page siginfo.h(3HEAD) describes that some signals define si_addr
90 to be an address of the faulting instruction (SIGILL). Then it is needed
91 to change the real CPU address to the VCPU address. Some signals define
92 si_addr to be an address of the faulting memory reference (SIGSEGV,
93 SIGBUS). Then the address should be passed unmodified.
95 However documentation contained in the manpage does not reflect the
96 reality found in the Solaris kernel - uts/<arch>/os/trap.c. Here one can
97 observe that in some cases si_addr is set to address provided by the
98 underlying subsystem. In some cases si_addr is set to the current
99 program counter. Other signals are missing documentation altogether.
100 It is almost impossible to determine what value is stored in si_addr
101 based on the information provided by kernel to the signal handler.
103 POSIX.1-2008 says about si_addr:
104 SIGILL, SIGFPE ... Address of faulting instruction.
105 SIGSEGV, SIGBUS ... Address of faulting memory reference.
106 For some implementations, the value of si_addr may be inaccurate.
108 See tests none/tests/faultstatus and none/tests/x86/badseg for examples.
109 The code below simply follows the POSIX standard, but propagates any
110 possibly incorrect values from the kernel to the user.
112 switch (signo) {
113 case VKI_SIGSEGV:
114 switch (siginfo->si_code) {
115 case VKI_SEGV_ACCERR:
116 case VKI_SEGV_MAPERR:
117 default:
118 break;
119 case VKI_SEGV_MADE_UP_GPF:
120 /* Translate si_code synthesized by Valgrind to SEGV_MAPPER. */
121 frame->siginfo.si_code = VKI_SEGV_MAPERR;
122 break;
124 break;
125 case VKI_SIGBUS:
126 break;
127 case VKI_SIGFPE:
128 case VKI_SIGILL:
129 case VKI_SIGTRAP:
130 frame->siginfo.si_addr = (void*)VG_(get_IP)(tid);
131 break;
132 case VKI_SIGPROF:
133 frame->siginfo.si_faddr = (void*)VG_(get_IP)(tid);
134 break;
135 default:
136 break;
138 VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->siginfo,
139 sizeof(frame->siginfo));
141 /* Save the signal number in an unused slot. Later, when a return from the
142 signal is made, this value is used to inform the tool that the
143 processing for the given signal has ended. */
144 VKI_UC_SIGNO(&frame->ucontext) = signo | ((~(UWord)signo & 0xFFFF) << 16);
145 /* Old context has to point to the saved ucontext. */
146 tst->os_state.oldcontext = &frame->ucontext;
147 /* Save ERR and TRAPNO if siguc is present. */
148 if (siguc) {
149 frame->ucontext.uc_mcontext.gregs[VKI_REG_ERR]
150 = siguc->uc_mcontext.gregs[VKI_REG_ERR];
151 VG_TRACK(post_mem_write, Vg_CoreSignal, tid,
152 (Addr)&frame->ucontext.uc_mcontext.gregs[VKI_REG_ERR],
153 sizeof(UWord));
154 frame->ucontext.uc_mcontext.gregs[VKI_REG_TRAPNO]
155 = siguc->uc_mcontext.gregs[VKI_REG_TRAPNO];
156 VG_TRACK(post_mem_write, Vg_CoreSignal, tid,
157 (Addr)&frame->ucontext.uc_mcontext.gregs[VKI_REG_TRAPNO],
158 sizeof(UWord));
161 /* Prepare parameters for a signal handler. */
162 frame->a1_signo = signo;
163 /* The first parameter has to be 16-byte aligned, resembling function
164 calls. */
166 /* Using
167 vg_assert(VG_IS_16_ALIGNED(&frame->a1_signo));
168 seems to get miscompiled on amd64 with GCC 4.7.2. */
169 Addr signo_addr = (Addr)&frame->a1_signo;
170 vg_assert(VG_IS_16_ALIGNED(signo_addr));
172 frame->a2_siginfo = &frame->siginfo;
173 VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->a1_signo,
174 sizeof(frame->a1_signo) + sizeof(frame->a2_siginfo));
175 #if defined(VGP_x86_solaris)
176 frame->a3_ucontext = &frame->ucontext;
177 VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->a3_ucontext,
178 sizeof(frame->a3_ucontext));
179 #elif defined(VGP_amd64_solaris)
180 tst->arch.vex.guest_RDI = signo;
181 VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
182 guest_RDI), sizeof(ULong));
183 tst->arch.vex.guest_RSI = (Addr)&frame->siginfo;
184 VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
185 guest_RSI), sizeof(ULong));
186 tst->arch.vex.guest_RDX = (Addr)&frame->ucontext;
187 VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
188 guest_RDX), sizeof(ULong));
189 #endif
191 /* Set up the stack pointer. */
192 vg_assert(esp == (Addr)&frame->return_addr);
193 VG_(set_SP)(tid, esp);
194 VG_TRACK(post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr));
196 /* Set up the program counter. Note that we don't inform a tool about IP
197 write because IP is always defined. */
198 VG_(set_IP)(tid, (Addr)handler);
200 /* If the signal is delivered on the alternate stack, copy it out to
201 ustack. This has to be done after setting a new IP so the SS_ONSTACK
202 flag is set by VG_(do_sys_sigaltstack)(). */
203 if (on_altstack && tst->os_state.ustack
204 && VG_(am_is_valid_for_client)((Addr)tst->os_state.ustack,
205 sizeof(*tst->os_state.ustack),
206 VKI_PROT_WRITE)) {
207 SysRes res;
208 vki_stack_t altstack;
210 /* Get information about alternate stack. */
211 res = VG_(do_sys_sigaltstack)(tid, NULL, &altstack);
212 vg_assert(!sr_isError(res));
214 /* Copy it to ustack. */
215 *tst->os_state.ustack = altstack;
216 VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)tst->os_state.ustack,
217 sizeof(*tst->os_state.ustack));
220 if (VG_(clo_trace_signals))
221 VG_(message)(Vg_DebugMsg,
222 "sigframe_create (thread %u): next IP=%#lx, "
223 "next SP=%#lx\n",
224 tid, (Addr)handler, (Addr)frame);
227 void VG_(sigframe_destroy)(ThreadId tid, Bool isRT)
229 /* Not used on Solaris. */
230 vg_assert(0);
233 void VG_(sigframe_return)(ThreadId tid, const vki_ucontext_t *uc)
235 Int signo;
237 /* Check if a signal number was saved in the restored context. */
238 signo = VKI_UC_SIGNO_CONST(uc) & 0xFFFF;
239 if (!signo || signo != ((~VKI_UC_SIGNO_CONST(uc) >> 16) & 0xFFFF))
240 return;
242 /* Note: The active tool should be informed here about the dead stack area.
243 However, this was already done when the original context was restored (in
244 VG_(restore_context)()) so it is not necessary to do it here again.
246 There is a small nuance though, VG_(restore_context)() triggers the
247 die_mem_stack event while in this case, it should really trigger the
248 die_mem_stack_signal event. This is not currently a problem because all
249 official tools handle these two events in the same way.
251 If a return from an alternate stack is made then no die_mem_stack event
252 is currently triggered. */
254 /* Returning from a signal handler. */
255 if (VG_(clo_trace_signals))
256 VG_(message)(Vg_DebugMsg,
257 "VG_(sigframe_return) (thread %u): IP=%#lx\n",
258 tid, VG_(get_IP)(tid));
260 /* Tell the tool. */
261 VG_TRACK(post_deliver_signal, tid, signo);
264 #endif // defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
266 /*--------------------------------------------------------------------*/
267 /*--- end ---*/
268 /*--------------------------------------------------------------------*/