1 /*--------------------------------------------------------------------*/
2 /*--- Platform-specific syscalls stuff. syswrap-x86-l4re.c ---*/
3 /*--------------------------------------------------------------------*/
6 This file is part of Valgrind, a dynamic binary instrumentation
9 Copyright (C) 2000-2008 Nicholas Nethercote
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 The GNU General Public License is contained in the file COPYING.
30 /* TODO/FIXME jrs 20050207: assignments to the syscall return result
31 in interrupted_syscall() need to be reviewed. They don't seem
32 to assign the shadow state.
35 #include "pub_core_basics.h"
36 #include "pub_core_vki.h"
37 #include "pub_core_vkiscnums.h"
38 #include "pub_core_threadstate.h"
39 #include "pub_core_aspacemgr.h"
40 #include "pub_core_debuglog.h"
41 #include "pub_core_libcbase.h"
42 #include "pub_core_libcassert.h"
43 #include "pub_core_libcprint.h"
44 #include "pub_core_libcproc.h"
45 #include "pub_core_libcsignal.h"
46 #include "pub_core_mallocfree.h"
47 #include "pub_core_options.h"
48 #include "pub_core_scheduler.h"
49 #include "pub_core_sigframe.h" // For VG_(sigframe_destroy)()
50 #include "pub_core_signals.h"
51 #include "pub_core_syscall.h"
52 #include "pub_core_syswrap.h"
53 #include "pub_core_tooliface.h"
54 #include "pub_core_stacks.h" // VG_(register_stack)
56 #include "priv_types_n_macros.h"
57 #include "priv_syswrap-generic.h" /* for decls of generic wrappers */
58 #include "priv_syswrap-linux.h" /* for decls of linux-ish wrappers */
59 #include "priv_syswrap-linux-variants.h" /* decls of linux variant wrappers */
60 #include "priv_syswrap-main.h"
63 #include <l4/sys/types.h>
64 #include <l4/sys/thread.h>
65 #include <l4/sys/utcb.h>
66 #include <l4/sys/ipc.h>
67 #include <l4/util/util.h>
68 #include <l4/sys/consts.h>
69 #include <l4/sys/debugger.h>
72 /* ---------------------------------------------------------------------
74 ------------------------------------------------------------------ */
76 /* Call f(arg1), but first switch stacks, using 'stack' as the new
77 stack, and use 'retaddr' as f's return-to address. Also, clear all
78 the integer registers before entering f.*/
79 __attribute__((noreturn))
80 void ML_(call_on_new_stack_0_1) ( Addr stack,
90 ".globl vgModuleLocal_call_on_new_stack_0_1\n"
91 "vgModuleLocal_call_on_new_stack_0_1:\n"
92 " movl %esp, %esi\n" // remember old stack pointer
93 " movl 4(%esi), %esp\n" // set stack
94 " pushl 16(%esi)\n" // arg1 to stack
95 " pushl 8(%esi)\n" // retaddr to stack
96 " pushl 12(%esi)\n" // f to stack
97 " movl $0, %eax\n" // zero all GP regs
104 " ret\n" // jump to f
105 " ud2\n" // should never get here
109 // forward declarations
110 static void setup_child ( ThreadArchState*, ThreadArchState*, Bool, Word );
111 static SysRes sys_set_thread_area ( ThreadId, vki_modify_ldt_t* );
114 When a client creates a new thread, we need to keep track of the new thread. This means:
115 1. allocate a ThreadId+ThreadState+stack for the the thread
117 2. initialize the thread's new VCPU state
118 setting the initial instruction pointer to the right one
120 3. create the thread using the same args as the client requested,
121 but using the scheduler entrypoint for EIP, and a separate stack
124 static SysRes do_create_new_thread ( ThreadId ptid,
129 static const Bool debug = False;
131 ThreadId ctid = VG_(alloc_ThreadState)();
132 ThreadState* ptst = VG_(get_ThreadState)(ptid);
133 ThreadState* ctst = VG_(get_ThreadState)(ctid);
140 char *thread_name = VG_(malloc)("", 15); /* VG::threadXYZ */
141 vg_assert(VG_(is_running_thread)(ptid));
142 vg_assert(VG_(is_valid_tid)(ctid));
144 stack = (UWord*)ML_(allocstack)(ctid);
146 res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
150 /* Copy register state
152 Both parent and child return to the same place, and the code
153 following the clone syscall works out which is which, so we
154 don't need to worry about it.
156 The parent gets the child's new tid returned from clone, but the
159 If the clone call specifies a NULL esp for the new thread, then
160 it actually gets a copy of the parent's esp.
162 /* Note: the clone call done by the Quadrics Elan3 driver specifies
163 clone flags of 0xF00, and it seems to rely on the assumption
164 that the child inherits a copy of the parent's GDT.
165 setup_child takes care of setting that up. */
166 setup_child( &ctst->arch, &ptst->arch, True, client_ip );
168 /* Make sys_clone appear to have returned Success(0) in the
171 // TODO ctst->arch.vex.guest_EAX = 0;
174 ctst->arch.vex.guest_ESP = esp;
176 ctst->os_state.parent = ptid;
178 /* We don't really know where the client stack is, because its
179 allocated by the client. The best we can do is look at the
180 memory mappings and try to derive some useful information. We
181 assume that esp starts near its highest possible value, and can
182 only go down to the start of the mmaped segment. */
183 seg = VG_(am_find_nsegment)((Addr)esp);
184 if (seg && seg->kind != SkResvn) {
185 ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(esp);
186 ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;
188 VG_(register_stack)(seg->start, ctst->client_stack_highest_word);
191 VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
192 ctid, seg->start, VG_PGROUNDUP(esp));
194 VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%#lx) unmapped\n",
196 ctst->client_stack_szB = 0;
199 /* Assume the clone will succeed, and tell any tool that wants to
200 know that this thread has come into existence. We cannot defer
201 it beyond this point because sys_set_thread_area, just below,
202 causes tCheck to assert by making references to the new ThreadId
203 if we don't state the new thread exists prior to that point.
204 If the clone fails, we'll send out a ll_exit notification for it
205 at the out: label below, to clean up. */
206 VG_TRACK ( pre_thread_ll_create, ptid, ctid );
208 /* Create the new thread */
209 /* eax = do_syscall_clone_x86_linux(
210 ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
211 child_tidptr, parent_tidptr, NULL
213 /* l4_thread_ex_regs_u( ptst->arch.vex.guest_EDX, // cap
214 ML_(start_thread_NORETURN), // ip
219 /* Therefore Valgrind doesn't lose control over the client thread
220 * a special function is called in valgrinds context */
221 vg_eip = (l4_umword_t) &ML_(start_thread_NORETURN);
223 *stack = (UWord) &VG_(threads)[ctid];
226 vg_stack = (l4_umword_t) stack;
228 VG_(debugLog)(0, "syswrap", "creating new thread\n"
229 "\t\t\t (vg) ip = 0x%08lx\n"
230 "\t\t\t (vg) stack = 0x%08x\n"
231 "\t\t\t (cl) ip = 0x%08x\n"
232 "\t\t\t (cl) stack = 0x%08x\n"
233 "\t\t\t flags = 0x%08x\n",
236 ctst->arch.vex.guest_EIP,
237 ctst->arch.vex.guest_ESP,
240 l4_thread_ex_regs_ret_u( ptst->arch.vex.guest_EDX, /* capability */
241 &vg_eip, /* instruction pointer (vg context) */
242 &vg_stack, /* stack pointer (vg context) */
243 (l4_umword_t *) &flags, /* flags */
246 /* Every thread in Valgrind gets a name - a nice feature
247 * of the fiasco micro kernel, good for debugging */
249 if (VG_(snprintf)(thread_name, 15, "VG::thread%d", ctid) > 0)
250 l4_debugger_set_object_name(ptst->arch.vex.guest_EDX, thread_name);
253 res = VG_(mk_SysRes_x86_l4re)( eax );
255 if (sr_isError(res)) {
257 VG_(cleanup_thread)(&ctst->arch);
258 ctst->status = VgTs_Empty;
259 /* oops. Better tell the tool the thread exited in a hurry :-) */
260 VG_TRACK( pre_thread_ll_exit, ctid );
266 /* ---------------------------------------------------------------------
268 ------------------------------------------------------------------ */
270 void VG_(cleanup_thread) ( ThreadArchState* arch )
272 /* Release arch-specific resources held by this thread. */
276 static void setup_child ( /*OUT*/ ThreadArchState *child,
277 /*IN*/ ThreadArchState *parent,
278 Bool inherit_parents_GDT,
281 /* We inherit our parent's guest state. */
282 child->vex = parent->vex;
283 child->vex_shadow1 = parent->vex_shadow1;
284 child->vex_shadow2 = parent->vex_shadow2;
285 /* In L4Re creating a new thread means not cloning like in linux,
286 * instead a new instruction pointer is required */
287 child->vex.guest_EIP = client_ip;
291 /* ---------------------------------------------------------------------
292 PRE/POST wrappers for x86/Linux-specific syscalls
293 ------------------------------------------------------------------ */
295 #define PRE(name) DEFN_PRE_TEMPLATE(x86_l4re, name)
296 #define POST(name) DEFN_POST_TEMPLATE(x86_l4re, name)
298 #define FOO(name) case L4_PROTO_##name : VG_(printf)(#name); break;
301 L4_PROTO_DATASPACE = 0x4000,
310 * print some informations about current syscall
311 * see also l4sys/include/err.h
312 * l4sys/include/types.h
315 void print_infos_to_syscall(l4_msgtag_t *tag, ThreadId tid) {
316 VG_(printf)("msgtag_label = %lx\n", l4_msgtag_label(*tag));
318 VG_(printf)(" Protocol: ");
319 switch(l4_msgtag_label(*tag)) {
321 case L4_PROTO_ALLOW_SYSCALL: // =L4_PROTO_PF_EXCEPTION
322 VG_(printf)("ALLOW_SYSCALL/PF_EXCEPTION");
343 default: VG_(printf)("unknown");
354 #define DEBUG_MYSELF 0
359 if (0) VG_(printf)("PRE_generic: sysno = %08lx arg0 = %8lx arg1 = %8lx arg2 = %8lx\n"
360 " arg3 = %8lx arg4 = %8lx arg5 = %8lx arg6 = %8lx\n",
361 arrghs->sysno, arrghs->arg1, arrghs->arg2, arrghs->arg3, arrghs->arg4,
362 arrghs->arg5, arrghs->arg6, arrghs->arg7);
363 /* get access to virtual utcb of client */
364 u = ts_utcb(&VG_(threads)[tid]);
367 tag = (l4_msgtag_t *) &(arrghs->arg1);
368 tst = VG_(get_ThreadState)(tid);
371 print_infos_to_syscall(tag, tid);
372 VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
374 if ((arrghs->arg4 /* EDX */ == (L4_INVALID_CAP | L4_SYSF_RECV)) &&
375 (arrghs->arg3 /* ECX */ == L4_IPC_NEVER.raw ) ) {
376 /* l4_sleep_forever */
377 tst->exitreason = VgSrc_ExitThread;
378 tst->os_state.exitcode = 1;
379 SET_STATUS_Success(0);
380 //enter_kdebug("l4_sleep_forever");
383 if ((l4_msgtag_label(*tag) == L4_PROTO_THREAD) &&
384 (v->mr[0] & L4_THREAD_EX_REGS_OP) )
386 // TODO is this really a thread-create??
387 // TODO store thread cap
388 // catch cap mappings
390 /* the guest wants to create a new thread */
392 VG_(debugLog)(1, "syswrap", "The client wants to create a new thread\n"
393 "\t\t\tcollected infos (from virt utcb):\n"
394 "\t\t\t (cl) ip = 0x%x\n"
395 "\t\t\t (cl) sp = 0x%x\n"
396 "\t\t\t flags = 0x%x\n",
397 (unsigned int) v->mr[1],
398 (unsigned int) v->mr[2],
399 (unsigned int) v->mr[0]);
401 if (0) enter_kdebug("before thread create");
403 do_create_new_thread ( tid,
404 v->mr[2], /*stack pointer*/
406 v->mr[1] /*instruction pointer*/
409 if (0) enter_kdebug("after thread create");
410 SET_STATUS_Success(0);
411 *flags |= SfYieldAfter;
412 } else if ((l4_msgtag_label(*tag) == L4_PROTO_PARENT) &&
414 /* the guest signals his parent that he would exit now */
416 VG_(debugLog)(0, "syswrap", "The client would like to exit\n");
417 VG_(debugLog)(0, "syswrap", "exit code = 0x%x\n", (unsigned int) v->mr[2]);
419 tst->exitreason = VgSrc_ExitThread;
420 tst->os_state.exitcode = v->mr[2];
422 /* For a correct exit we must "kill" all threads, but i don't
423 * know if this is the right solution.
428 for (_tid = 1; _tid < VG_N_THREADS; _tid++) {
429 if ( VG_(threads)[_tid].status != VgTs_Empty &&
430 VG_(threads)[_tid].status != VgTs_Zombie &&
432 _tst = VG_(get_ThreadState)(_tid);
433 VG_(threads)[_tid].status = VgTs_Zombie;
434 tst->exitreason = VgSrc_ExitThread;
438 SET_STATUS_Success(0);
440 *flags |= SfMayBlock;
447 if (0) VG_(printf)("\
448 POST_generic: sysno %8lx arg0 = %8lx arg1 = %8lx arg2 = %8lx\n"
449 " arg3 = %8lx arg4 = %8lx arg5 = %8lx arg6 = %8lx\n",
450 arrghs->sysno, arrghs->arg1, arrghs->arg2,
451 arrghs->arg3, arrghs->arg4, arrghs->arg5, arrghs->arg6, arrghs->arg7);
462 /* ---------------------------------------------------------------------
463 The x86/l4re syscall table
464 ------------------------------------------------------------------ */
466 /* Add an x86-l4re specific wrapper to a syscall table. */
467 #define PLAX_(sysno, name) WRAPPER_ENTRY_X_(x86_l4re, sysno, name)
468 #define PLAXY(sysno, name) WRAPPER_ENTRY_XY(x86_l4re, sysno, name)
471 // This table maps from __NR_xxx syscall numbers (from
472 // linux/include/asm-i386/unistd.h) to the appropriate PRE/POST sys_foo()
473 // wrappers on x86 (as per sys_call_table in linux/arch/i386/kernel/entry.S).
475 // For those syscalls not handled by Valgrind, the annotation indicate its
476 // arch/OS combination, eg. */* (generic), */Linux (Linux only), ?/?
479 const SyscallTableEntry ML_(syscall_table)[] = {
480 PLAXY(SYS_INVOKE, generic),
481 PLAXY(SYS_DEBUG, dummy),
482 PLAXY(SYS_ENTER_KDEBUG, dummy),
483 PLAXY(SYS_LINUX_INT80, dummy),
484 PLAXY(SYS_UD2, dummy),
485 PLAXY(SYS_ARTIFICIAL, dummy),
488 const UInt ML_(syscall_table_size) =
489 sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]);
491 /*--------------------------------------------------------------------*/
493 /*--------------------------------------------------------------------*/