]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_syswrap/syswrap-x86-l4re.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_syswrap / syswrap-x86-l4re.c
1 /*--------------------------------------------------------------------*/
2 /*--- Platform-specific syscalls stuff.         syswrap-x86-l4re.c ---*/
3 /*--------------------------------------------------------------------*/
4
5 /*
6    This file is part of Valgrind, a dynamic binary instrumentation
7    framework.
8
9    Copyright (C) 2000-2008 Nicholas Nethercote
10       njn@valgrind.org
11
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.
16
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.
21
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
25    02111-1307, USA.
26
27    The GNU General Public License is contained in the file COPYING.
28 */
29
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.
33 */
34
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)
55
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"
61
62 #if defined(VGO_l4re)
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>
70 #endif
71
72 /* ---------------------------------------------------------------------
73    clone() handling
74    ------------------------------------------------------------------ */
75
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,
81                       Addr retaddr,
82                       void (*f)(Word),
83                                   Word arg1 );
84 //  4(%esp) == stack
85 //  8(%esp) == retaddr
86 // 12(%esp) == f
87 // 16(%esp) == arg1
88 asm(
89 ".text\n"
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
98 "   movl $0, %ebx\n"
99 "   movl $0, %ecx\n"
100 "   movl $0, %edx\n"
101 "   movl $0, %esi\n"
102 "   movl $0, %edi\n"
103 "   movl $0, %ebp\n"
104 "   ret\n"                 // jump to f
105 "   ud2\n"                 // should never get here
106 ".previous\n"
107 );
108
109 // forward declarations
110 static void setup_child ( ThreadArchState*, ThreadArchState*, Bool, Word );
111 static SysRes sys_set_thread_area ( ThreadId, vki_modify_ldt_t* );
112
113 /* 
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
116
117    2. initialize the thread's new VCPU state
118       setting the initial instruction pointer to the right one
119
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
122    for ESP.
123  */
124 static SysRes do_create_new_thread ( ThreadId ptid, 
125                                      Addr esp, 
126                                      l4_umword_t flags,
127                                      Word client_ip)
128 {
129    static const Bool debug = False;
130
131    ThreadId     ctid = VG_(alloc_ThreadState)();
132    ThreadState* ptst = VG_(get_ThreadState)(ptid);
133    ThreadState* ctst = VG_(get_ThreadState)(ctid);
134    UWord*       stack;
135    UWord        vg_stack;
136    NSegment const* seg;
137    SysRes       res;
138    Int          eax;
139    UWord         vg_eip;
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));
143
144    stack = (UWord*)ML_(allocstack)(ctid);
145    if (stack == NULL) {
146       res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
147       goto out;
148    }
149
150    /* Copy register state
151
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.
155
156       The parent gets the child's new tid returned from clone, but the
157       child gets 0.
158
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.
161    */
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 );
167
168    /* Make sys_clone appear to have returned Success(0) in the
169       child. */
170
171    // TODO ctst->arch.vex.guest_EAX = 0;
172
173    if (esp != 0)
174       ctst->arch.vex.guest_ESP = esp;
175
176    ctst->os_state.parent = ptid;
177
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;
187
188       VG_(register_stack)(seg->start, ctst->client_stack_highest_word);
189
190       if (debug)
191      VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
192              ctid, seg->start, VG_PGROUNDUP(esp));
193    } else {
194       VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%#lx) unmapped\n",
195            ctid, esp);
196       ctst->client_stack_szB  = 0;
197    }
198
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 );
207
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
212          );*/
213 /*   l4_thread_ex_regs_u( ptst->arch.vex.guest_EDX, // cap
214                         ML_(start_thread_NORETURN), // ip
215                         stack, //esp
216                         0, //flags
217                         l4_utcb_wrap());*/
218
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);
222    
223    *stack =  (UWord) &VG_(threads)[ctid]; 
224    stack--;
225  
226    vg_stack = (l4_umword_t) stack;
227
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",
234                                vg_eip,
235                                (unsigned int)stack,
236                                ctst->arch.vex.guest_EIP,
237                                ctst->arch.vex.guest_ESP,
238                                flags);
239
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 */
244                             l4_utcb_wrap());
245
246    /* Every thread in Valgrind gets a name - a nice feature 
247     * of the fiasco micro kernel, good for debugging */
248
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);
251    
252    eax = 1;
253    res = VG_(mk_SysRes_x86_l4re)( eax );
254   out:
255    if (sr_isError(res)) {
256       /* clone failed */
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 );
261    }
262
263    return res;
264 }
265
266 /* ---------------------------------------------------------------------
267    More thread stuff
268    ------------------------------------------------------------------ */
269
270 void VG_(cleanup_thread) ( ThreadArchState* arch )
271 {
272    /* Release arch-specific resources held by this thread. */
273 }  
274
275
276 static void setup_child ( /*OUT*/ ThreadArchState *child, 
277                           /*IN*/  ThreadArchState *parent,
278                           Bool inherit_parents_GDT,
279                           Word client_ip)
280 {
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;
288 }  
289
290
291 /* ---------------------------------------------------------------------
292    PRE/POST wrappers for x86/Linux-specific syscalls
293    ------------------------------------------------------------------ */
294
295 #define PRE(name)       DEFN_PRE_TEMPLATE(x86_l4re, name)
296 #define POST(name)      DEFN_POST_TEMPLATE(x86_l4re, name)
297
298 #define FOO(name)       case L4_PROTO_##name : VG_(printf)(#name); break;
299 enum
300 {
301         L4_PROTO_DATASPACE = 0x4000,
302         L4_PROTO_NAMESPACE,
303         L4_PROTO_PARENT,
304         L4_PROTO_GOOS,
305         L4_PROTO_MEMALLOC,
306         L4_PROTO_RM,
307         L4_PROTO_EVENT,
308 };
309 /*
310  * print some informations about current syscall
311  * see also l4sys/include/err.h
312  *          l4sys/include/types.h
313  */
314
315 void print_infos_to_syscall(l4_msgtag_t *tag, ThreadId tid) {
316     VG_(printf)("msgtag_label = %lx\n", l4_msgtag_label(*tag));
317     {
318         VG_(printf)("  Protocol: ");
319         switch(l4_msgtag_label(*tag)) {
320             FOO(NONE);
321             case L4_PROTO_ALLOW_SYSCALL: // =L4_PROTO_PF_EXCEPTION
322             VG_(printf)("ALLOW_SYSCALL/PF_EXCEPTION");
323             FOO(IRQ);
324             FOO(PAGE_FAULT);
325             FOO(PREEMPTION);
326             FOO(SYS_EXCEPTION);
327             FOO(EXCEPTION);
328             FOO(SIGMA0);
329             FOO(IO_PAGE_FAULT);
330             FOO(FACTORY);
331             FOO(TASK);
332             FOO(THREAD);
333             FOO(LOG);
334             FOO(SCHEDULER);
335                         FOO(DATASPACE);
336                         FOO(NAMESPACE);
337                         FOO(PARENT);
338                         FOO(GOOS);
339                         FOO(RM);
340                         FOO(MEMALLOC);
341                         FOO(EVENT);
342             default:               VG_(printf)("unknown");
343                                    break;
344         }
345         VG_(printf)("\n");
346     }
347 }
348
349 #undef FOO
350
351 PRE(generic)
352 {
353 #define DEBUG_MYSELF 0
354     ThreadState* tst;
355     l4_utcb_t *u;
356     l4_msg_regs_t *v;
357     l4_msgtag_t *tag;
358     if (0) VG_(printf)("PRE_generic: sysno = %08lx arg0 = %8lx arg1 = %8lx arg2 = %8lx\n"
359                        "             arg3  = %8lx arg4 = %8lx arg5 = %8lx arg6 = %8lx\n",
360             arrghs->sysno, arrghs->arg1, arrghs->arg2, arrghs->arg3, arrghs->arg4,
361             arrghs->arg5, arrghs->arg6, arrghs->arg7);
362     /* get access to virtual utcb of client */
363     u = ts_utcb(&VG_(threads)[tid]);
364     v = l4_utcb_mr_u(u);
365
366     tag = (l4_msgtag_t *) &(arrghs->arg1);
367     tst = VG_(get_ThreadState)(tid);
368
369 #if DEBUG_MYSELF
370     print_infos_to_syscall(tag, tid);
371     VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
372 #endif
373     if ((arrghs->arg4 /* EDX */ == (L4_INVALID_CAP | L4_SYSF_RECV)) &&
374         (arrghs->arg3 /* ECX */ == L4_IPC_NEVER.raw ) ) {
375         /* l4_sleep_forever */
376         tst->exitreason = VgSrc_ExitThread;
377         tst->os_state.exitcode = 1;
378         SET_STATUS_Success(0);
379         //enter_kdebug("l4_sleep_forever");
380     } else
381
382     if ((l4_msgtag_label(*tag) == L4_PROTO_THREAD) &&
383         (v->mr[0] & L4_THREAD_EX_REGS_OP) )
384     {
385         // TODO is this really a thread-create??
386         // TODO store thread cap
387         // catch cap mappings
388
389         /* the guest wants to create a new thread */
390 #if DEBUG_MYSELF
391         VG_(debugLog)(1, "syswrap", "The client wants to create a new thread\n"
392                                     "\t\t\tcollected infos (from virt utcb):\n"
393                                     "\t\t\t  (cl) ip = 0x%x\n"
394                                     "\t\t\t  (cl) sp = 0x%x\n"
395                                     "\t\t\t    flags = 0x%x\n",
396                                     (unsigned int) v->mr[1], 
397                                     (unsigned int) v->mr[2],
398                                     (unsigned int) v->mr[0]);
399 #endif
400         if (0) enter_kdebug("before thread create");
401         
402         do_create_new_thread ( tid, 
403                                v->mr[2], /*stack pointer*/
404                                v->mr[0], /*flags*/
405                                v->mr[1]  /*instruction pointer*/
406                              );
407         
408         if (0) enter_kdebug("after thread create");
409         SET_STATUS_Success(0);
410         *flags |= SfYieldAfter;
411    } else if ((l4_msgtag_label(*tag) == L4_PROTO_PARENT) &&
412               (v->mr[1] == 0)) {
413         /* the guest signals his parent that he would exit now */
414 #if DEBUG_MYSELF
415         VG_(debugLog)(0, "syswrap", "The client would like to exit\n"); 
416         VG_(debugLog)(0, "syswrap", "exit code = 0x%x\n", (unsigned int) v->mr[2]); 
417 #endif
418         tst->exitreason = VgSrc_ExitThread;
419         tst->os_state.exitcode = v->mr[2];
420
421         /* For a correct exit we must "kill" all threads, but i don't
422          * know if this is the right solution.
423          */
424         {
425             ThreadId _tid;
426             ThreadState *_tst;
427             for (_tid = 1; _tid < VG_N_THREADS; _tid++) {
428                 if ( VG_(threads)[_tid].status != VgTs_Empty &&
429                      VG_(threads)[_tid].status != VgTs_Zombie &&
430                      _tid != tid) {
431                     _tst =  VG_(get_ThreadState)(_tid);
432                     VG_(threads)[_tid].status = VgTs_Zombie;
433                     tst->exitreason = VgSrc_ExitThread;
434                 }
435             }
436         }
437         SET_STATUS_Success(0);
438     } else {
439         *flags |= SfMayBlock;
440     }
441 #undef DEBUG_MYSELF
442 }
443
444 POST(generic)
445 {
446   if (0) VG_(printf)("\
447       POST_generic: sysno %8lx arg0 = %8lx arg1 = %8lx arg2 = %8lx\n"
448      "              arg3 =  %8lx arg4 = %8lx arg5 = %8lx arg6 = %8lx\n",
449       arrghs->sysno, arrghs->arg1, arrghs->arg2,
450       arrghs->arg3, arrghs->arg4, arrghs->arg5, arrghs->arg6, arrghs->arg7);
451 }
452
453
454 PRE(dummy) { }
455 POST(dummy) { }
456
457 #undef PRE
458 #undef POST
459
460
461 /* ---------------------------------------------------------------------
462    The x86/l4re syscall table
463    ------------------------------------------------------------------ */
464
465 /* Add an x86-l4re specific wrapper to a syscall table. */
466 #define PLAX_(sysno, name)    WRAPPER_ENTRY_X_(x86_l4re, sysno, name) 
467 #define PLAXY(sysno, name)    WRAPPER_ENTRY_XY(x86_l4re, sysno, name)
468
469
470 // This table maps from __NR_xxx syscall numbers (from
471 // linux/include/asm-i386/unistd.h) to the appropriate PRE/POST sys_foo()
472 // wrappers on x86 (as per sys_call_table in linux/arch/i386/kernel/entry.S).
473 //
474 // For those syscalls not handled by Valgrind, the annotation indicate its
475 // arch/OS combination, eg. */* (generic), */Linux (Linux only), ?/?
476 // (unknown).
477
478 const SyscallTableEntry ML_(syscall_table)[] = {
479   PLAXY(SYS_INVOKE, generic),
480   PLAXY(SYS_DEBUG, dummy),
481   PLAXY(SYS_ENTER_KDEBUG, dummy),
482   PLAXY(SYS_LINUX_INT80, dummy),
483   PLAXY(SYS_UD2, dummy),
484   PLAXY(SYS_ARTIFICIAL, dummy),
485 };
486
487 const UInt ML_(syscall_table_size) = 
488             sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]);
489
490 /*--------------------------------------------------------------------*/
491 /*--- end                                                          ---*/
492 /*--------------------------------------------------------------------*/