]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/l4re/vcap.cpp
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / l4re / vcap.cpp
1 // vim: expandtab
2
3 /*
4  * This file is part of the Valgrind port to L4Re.
5  *
6  * (c) 2009-2010 Aaron Pohle <apohle@os.inf.tu-dresden.de>,
7  *               Bjoern Doebel <doebel@os.inf.tu-dresden.de>
8  *     economic rights: Technische Universitaet Dresden (Germany)
9  */
10
11 #include <l4/sys/compiler.h>
12 // C++'s definition of NULL disagrees with Valgrind's
13 #undef NULL
14 #define NULL 0
15
16 #include <l4/re/env.h>
17 #include <l4/re/c/util/cap_alloc.h>
18 #include <l4/util/bitops.h>
19 #include <l4/re/c/rm.h>
20 #include <l4/re/util/object_registry>
21 #include <l4/sys/factory>
22 #include <l4/sys/ipc.h>
23 #include <l4/sys/utcb.h>
24 #include <l4/sys/vcon.h>
25 #include <l4/sys/scheduler.h>
26 #include <l4/sys/kdebug.h>
27 #include <l4/sys/debugger.h>
28 #include <l4/cxx/list>
29 #include <l4/sys/thread>
30 #include <l4/sys/scheduler>
31 #include <l4/re/util/cap_alloc>
32 #include <l4/re/env>
33 #include <l4/re/protocols>
34 #include <l4/re/dataspace>
35 #include <l4/cxx/ipc_server>
36 #include <l4/re/util/vcon_svr>
37 #include <l4/re/util/region_mapping_svr>
38 #include <l4/re/util/region_mapping>
39 #include <l4/re/util/debug>
40
41
42 __BEGIN_DECLS
43 #include "pub_l4re.h"
44 #include "pub_l4re_consts.h"
45 #include "pub_core_basics.h"
46 #include "pub_core_ume.h"
47 #include "pub_core_aspacemgr.h"
48 #include "pub_core_debuginfo.h"  //DebugInfo
49 #include "pub_tool_libcbase.h"
50 #include "pub_tool_libcfile.h"
51 #include "pub_core_libcprint.h"
52 __END_DECLS
53 // HACK:
54 // We include all the pub* headers as C declarations to work around a huge
55 //   bunch of C++ warnings. However, pub_core_vki.h really contains a template
56 //   definition, so we need to include it as proper C++ header.
57 #include "pub_core_vki.h"
58 __BEGIN_DECLS
59 #include "pub_core_libcsetjmp.h"
60 #include "pub_core_threadstate.h"
61 #include "pub_core_scheduler.h"
62 #include "pub_core_tooliface.h"
63 #include "pub_tool_mallocfree.h"
64 #include "pub_core_libcassert.h" // VG_(show_sched_status)
65 #include "l4re/myelf.h"
66 __END_DECLS
67
68 extern const Bool dbg_pf   = DEBUG_OFF;
69 extern const Bool dbg_elf  = DEBUG_OFF;
70 extern const Bool dbg_rm   = DEBUG_OFF;
71 extern const Bool dbg_ds   = DEBUG_OFF;
72 extern const Bool dbg_vcap = DEBUG_OFF;
73
74 L4::Cap<L4::Thread> vcap_thread;
75 char vcap_stack[1 << 13]; // 8 kB
76
77 #include "l4re/allocator"
78 #include "l4re/dbg"
79 #include "l4re/vcon"
80 #include "l4re/loop_hooks"
81
82 namespace Vcap
83 {
84
85 namespace Rm
86 {
87
88 // see l4/pkg/loader/server/src/region.cc:Rm_server
89 class svr
90 {
91     public:
92         typedef L4::Cap<L4Re::Dataspace> Dataspace;
93
94         enum { Have_find = true };
95
96         static int validate_ds(L4::Snd_fpage const & ds_cap, unsigned flags,
97                                L4::Cap<L4Re::Dataspace> *ds)
98         {
99             if (dbg_ds) VG_(debugLog)(4, "vcap", "flags 0x%x\n", flags);
100             if (dbg_ds) VG_(debugLog)(4, "vcap", "ds @ %p\n", ds);
101             if (dbg_ds) VG_(debugLog)(4, "vcap", "ds_cap received: %d\n", ds_cap.id_received());
102             return L4_EOK;
103         }
104
105         static l4_umword_t find_res(L4::Cap<void> const &ds) { return ds.cap(); }
106 };
107
108 static l4_addr_t the_map_area;
109 static l4_addr_t the_map_area_end;
110 static L4::Cap<L4Re::Rm> real_rm;
111
112 /*
113  * Modify the current environment's region manager and return the old one.
114  * This is used when switching into non-VRM mode in __notify_tool_of_mapping.
115  */
116 L4::Cap<L4Re::Rm> set_environment_rm(L4::Cap<void> cap)
117 {
118     L4::Cap<L4Re::Rm> ret = L4Re::Env::env()->rm();
119
120     L4::Cap<L4Re::Rm> rm(cap.cap());
121     const_cast<L4Re::Env*>(L4Re::Env::env())->rm(rm);
122
123     return ret;
124 }
125
126
127
128 // see: loader/server/src/region.cc
129 class Region_ops
130 {
131     public:
132         typedef L4::Snd_fpage Map_result;
133         typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
134                 Vcap::Rm::Region_ops> MyRegion_handler;
135
136         static void init()
137         {
138             real_rm->reserve_area(&the_map_area, L4_PAGESIZE,
139                                   L4Re::Rm::Reserved | L4Re::Rm::Search_addr);
140             the_map_area_end = the_map_area + L4_PAGESIZE -1;
141             unsigned prot =   VKI_PROT_READ
142                             | VKI_PROT_WRITE
143                             | VKI_PROT_EXEC;
144
145             unsigned flags = VKI_MAP_ANONYMOUS;
146
147             VG_(am_notify_valgrind_mmap)((Addr)the_map_area,
148                                          VG_PGROUNDUP(the_map_area_end - the_map_area),
149                                          prot, flags, -1, 0);
150
151             VG_(debugLog)(1, "vcap", "Region ops map area: 0x%lx - 0x%lx\n",
152                           the_map_area, the_map_area_end);
153         }
154
155         static int map(MyRegion_handler const *h,
156                        l4_addr_t local_addr, L4Re::Util::Region const &r, bool writable,
157                        L4::Snd_fpage *result)
158         {
159             int err;
160             if (dbg_ds) VG_(debugLog)(4, "vcap", "%s handler %p, local_addr 0x%lx, writable %s\n",
161                           __func__, (void * )h, local_addr, writable ? "true" : "false");
162
163             if ((h->flags() & L4Re::Rm::Reserved) || !h->memory().is_valid()) {
164                 VG_(debugLog)(4, "vcap", "Reserved || invalid\n");
165                 enter_kdebug();
166                 return -L4_ENOENT;
167             }
168
169             if (h->flags() & L4Re::Rm::Pager) {
170                 VG_(debugLog)(4, "vcap", "pager\n");
171                 enter_kdebug();
172                 return -L4_ENOENT;
173             }
174
175             if (h->is_ro() && writable)
176                 Dbg(Dbg::Warn).printf("WARNING: Writable mapping request on read-only region at 0x%lx!\n",
177                                       local_addr);
178
179             l4_addr_t offset = local_addr - r.start() + h->offset();
180             L4::Cap<L4Re::Dataspace> ds = L4::cap_cast<L4Re::Dataspace>(h->memory());
181
182             if (dbg_ds) VG_(debugLog)(4, "vcap", "Dataspace size 0x%lx\n", ds->size());
183             if (dbg_ds) VG_(debugLog)(4, "vcap", "Region: 0x%lx - 0x%lx\n", r.start(), r.end());
184             if (dbg_ds) VG_(debugLog)(4, "vcap", "map(0x%lx, 0x%x, 0x%lx, 0x%lx, 0x%lx)\n", offset, writable,
185                           the_map_area, the_map_area, the_map_area_end);
186             if (err = ds->map(offset, writable, the_map_area, the_map_area, the_map_area_end)) {
187                 VG_(debugLog)(0, "vcap", "map failed: %d %s\n", err, l4sys_errtostr(err));
188                 l4re_rm_show_lists();
189                 enter_kdebug("map error");
190                 return err;
191             }
192
193             if (dbg_ds) VG_(debugLog)(4, "vcap", "ds->map(): %d\n", err);
194
195             *result = L4::Snd_fpage::mem(the_map_area, L4_PAGESHIFT, L4_FPAGE_RWX,
196                                          local_addr, L4::Snd_fpage::Grant);
197             return L4_EOK;
198         }
199
200         static void unmap(MyRegion_handler const *h, l4_addr_t vaddr,
201                         l4_addr_t offs, unsigned long size)
202         {
203             (void)h; (void)vaddr; (void)offs; (void)size;
204             VG_(debugLog)(0, "vcap", "\n");
205             enter_kdebug("Region_ops::unmap()");
206         }
207
208         static void take(MyRegion_handler const *h)
209         {
210             (void)h;
211             VG_(debugLog)(0, "vcap", "\n");
212             enter_kdebug("Region_ops::take()");
213         }
214
215         static void release(MyRegion_handler const *h)
216         {
217             (void)h;
218             VG_(debugLog)(0, "vcap", "\n");
219             enter_kdebug("Region_ops::release()");
220         }
221 };
222
223
224 /* Explanation: region_mapping_svr relies on the region map consisting of Nodes.
225  *              In fact it relies on an implementation using the cxx avl tree
226  *              and the underlying node types. However, we handle regions using
227  *              Valgrind's data types here, but need an adaptor node type.
228  */
229 class node
230 {
231     public:
232         node() { }
233
234         node(L4Re::Util::Region const &f,
235              L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>, Vcap::Rm::Region_ops> rh)
236             : first(f), second(rh)
237         { }
238
239         L4Re::Util::Region first;
240         L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
241                                         Vcap::Rm::Region_ops> second;
242 };
243
244
245 /*
246  * For reserved areas, we need to store information about their original size, because
247  * during runtime regions may be attached into areas and these reserved regions may
248  * be split into pieces that need to be rejoined if the regions get detached.
249  */
250 struct area_info
251 {
252     public:
253         Addr _start;
254         Addr _end;
255
256         area_info(Addr start, Addr end)
257             :_start(start), _end(end)
258         { }
259
260
261         bool match_resvn(NSegment const * const seg) const
262         {
263             return ((seg->kind == SkResvn) &&
264                     (seg->start == _start) &&
265                     (seg->end   == _end));
266         }
267
268
269         bool contains_nsegment(NSegment const * const seg) const
270         {
271             return ((seg->start >= _start) &&
272                     (seg->end   <= _end));
273         }
274 };
275
276
277 #define DEBUG_RM_LAYOUT do { VG_(am_show_nsegments)(0, (HChar*)"current AS layout"); } while (0)
278
279 #define RM_ERROR do { DEBUG_RM_LAYOUT; enter_kdebug("rm error"); } while (0)
280
281 /*
282  * VCap::rm -- virtual region manager.
283  *
284  * This class implements a region manager on top of Valgrind's segment array.
285  * We map L4RM functionality as follows:
286  *
287  *  1) attach/detach -> create/delete new segments
288  *
289  * Area creation is harder. First, we create a reservation in the segment
290  * array. However, we need to keep track of this area for later attach()es and
291  * therefore keep an additional list of all known regions. This is because the
292  * reservations in the segment array don't suffice -- the area may be
293  * completely mapped with regions and therefore unobtainable from the segment
294  * array reservation.
295  *
296  *  2) attach_area   -> create new reservation and add to list
297  *  3) detach_area   -> remove all reservations in area and list entry
298  */
299 class rm
300 {
301     private:
302         cxx::List<struct area_info *, Valgrind_allocator> _areas;
303         unsigned _id;
304
305     public:
306         typedef Vcap::Rm::node          * Node;
307         typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
308                                            Vcap::Rm::Region_ops>  Region_handler;
309         typedef L4Re::Util::Region        Region;
310
311         enum Attach_flags
312         {
313             None      = 0,
314             Search    = L4Re::Rm::Search_addr,
315             In_area   = L4Re::Rm::In_area,
316         };
317
318         rm(unsigned id) : _id(id) { }
319
320         int dispatch(l4_msgtag_t tag, l4_umword_t obj, L4::Ipc_iostream &ios)
321             throw()
322         {
323             int err;
324
325             switch(tag.label()) {
326                 case L4_PROTO_PAGE_FAULT:
327                     return L4Re::Util::region_pf_handler<Vcap::Dbg>(this, ios);
328
329                 case L4Re::Protocol::Rm:
330                     err = L4Re::Util::region_map_server<Vcap::Rm::svr>(this, ios);
331                     if (dbg_rm) VG_(debugLog)(4, "vcap", "rm_server() returns %d\n", err);
332                     return err;
333
334                 default:
335                     return -L4_EBADPROTO;
336             }
337         }
338
339
340     private:
341
342         /*
343          * Find area info for addr.
344          */
345         struct area_info *__find_area_info(void *addr)
346         {
347             typedef cxx::List<struct area_info *, Valgrind_allocator> LIST;
348             for (LIST::Iter i = _areas.items(); *i; ++i) {
349                 struct area_info *inf = *i;
350                 if (inf->_start <= (Addr)addr && inf->_end >= (Addr)addr)
351                     return inf;
352             }
353             return NULL;
354         }
355
356
357         /*
358          * Remove area info for addr.
359          */
360         bool __remove_area_info(void *addr) {
361             typedef cxx::List<struct area_info *, Valgrind_allocator> LIST;
362             LIST::Iter i = _areas.items();
363             for (; *i; ++i) {
364                 struct area_info *inf = *i;
365                 if (inf->_start <= (Addr)addr && inf->_end >= (Addr)addr)
366                     break;
367             }
368
369             if (*i) {
370                 _areas.remove(i);
371                 return true;
372             }
373
374             return false;
375         }
376
377
378         /*
379          * Do what is necessary to attach a region into an already existing area.
380          *
381          * \return L4_INVALID_PTR   on error
382          *         start address    on success
383          */
384         void *__handle_attach_in_area(void *addr, unsigned long size, unsigned flags)
385         {
386             if (dbg_rm) VG_(debugLog)(4, "vcap", "%s: %p %lx %x\n", __func__, addr, size, flags);
387
388             /* We need to find the reservation for this area.
389              *
390              * Case A: The area is still empty, then we'll find the resvn by simply
391              *         looking it up.
392              *
393              * Case B: There are already areas attached to this resvn. In this case
394              *         a simple lookup may give us an area. Hence, we need to search
395              *         forwards and backwards in the segment array to find the resvn.
396              */
397             NSegment *seg = const_cast<NSegment*>(VG_(am_find_nsegment)((Addr)addr));
398
399             if (!seg) {
400                 VG_(printf)("No reservation found for attach in area. Addr %p, size %ld\n",
401                             addr, size);
402                 RM_ERROR;
403             }
404
405             if (dbg_rm) VG_(debugLog)(4, "vcap", "Segment @ %p (%08lx - %08lx, type: %s)\n",
406                         seg, seg->start, seg->end, vcap_segknd_str(seg->kind));
407
408             struct area_info *info = __find_area_info(addr);
409             if (!info) {
410                 VG_(printf)("ERROR: could not find area for address %p\n", addr);
411                 RM_ERROR;
412             }
413             if (dbg_rm) VG_(debugLog)(4, "vcap", "Area @ %p (%08lx - %08lx)\n",
414                           info, info->_start, info->_end);
415
416             /*
417              * Case B
418              */
419             if (!info->match_resvn(seg) && seg->kind != SkResvn) {
420                 enter_kdebug("resvn not matching");
421             }
422
423             /*
424              * Now we found a reservation suiting the new region. We now go and unmap
425              * the reservation, create a new region and if necessary mark chunks before
426              * and after the region as reservations.
427              */
428             Addr old_start = seg->start;
429             Addr old_end   = seg->end;
430
431             void *ret      = addr;
432
433             /* unmap all */
434             Bool needDiscard = VG_(am_notify_munmap)(seg->start, seg->end - seg->start + 1);
435             if (dbg_rm) VG_(debugLog)(4, "vcap", "unmapped, need discard? %d\n", needDiscard);
436
437             /* new reservation before this area? */
438             if (old_start < (Addr)addr) {
439                 if (dbg_rm) VG_(debugLog)(4, "vcap", "in area: split before");
440                 Addr new_start    = old_start;
441                 unsigned new_size = (Addr)addr - old_start + 1;
442                 if (dbg_rm) VG_(debugLog)(4, "vcap", "new resvn @ %p, size %lx\n", new_start, new_size);
443                 attach_area(new_start, new_size);
444             }
445
446             /* new reservation after this area? */
447             if (old_end > (Addr)addr + size - 1) {
448                 if (dbg_rm) VG_(debugLog)(4, "vcap", "in area: split after");
449                 Addr new_start    = (Addr)addr + size;
450                 unsigned new_size = old_end - new_start + 1;
451                 if (dbg_rm) VG_(debugLog)(4, "vcap", "new resvn @ %p, size %lx\n", new_start, new_size);
452                 attach_area(new_start, new_size);
453             }
454
455             return ret;
456         }
457
458
459         /*
460          * Find a free segment with start address >= start and a given size.
461          * We use Valgrind's dynamic memory manager to determine such an
462          * address.
463          *
464          * \return L4_INVALID_PTR      on error
465          *         valid segment start on success
466          */
467         void *__find_free_segment(void *start, unsigned size)
468         {
469             Bool ok;
470             void *ret;
471
472             if (_id == VRMcap_client)
473                 ret = (void*)VG_(am_get_advisory_client_simple)((Addr)start, size, &ok);
474             else if (_id == VRMcap_valgrind)
475                 ret = (void*)VG_(am_get_advisory_valgrind_simple)((Addr)start, size, &ok);
476             else {
477                 // should not happen!
478                 VG_(printf)("Cannot determine the type of mapping here: %lx\n", _id);
479                 enter_kdebug();
480             }
481
482             if (!ok) {
483                 VG_(debugLog)(0, "vcap", "Advisor has no free area for us!\n");
484                 RM_ERROR;
485                 enter_kdebug("error looking up free segment");
486                 return L4_INVALID_PTR;
487             }
488
489             return ret;
490         }
491
492
493         /*
494          * Valgrind notifies tools about successful mmap() using the VG_TRACK
495          * functionality. The only place where we can keep track of all
496          * mappings is inside VRM, which means in the tool's page fault
497          * handler. Unfortunately, tools tend to do arbitrary things (such as
498          * allocating memory) in response to such notifications and we cannot
499          * simply execute Valgrind code here, because it may try calling the
500          * pager (ourselves!).
501          *
502          * Therefore, for sending such notifications, we switch back to the
503          * mode, where we pretend that VRM is not there yet. This means, memory
504          * allocations are redirected to the original RM and segments are
505          * updated internally.
506          *
507          * A word on thread-safety: We don't need additional locking here,
508          * because we are sure that the tool code is currently waiting for us
509          * to handle its page fault or RM request. So this is as thread-safe as
510          * the tool was before.
511          */
512         void __notify_tool_of_mapping(Addr addr, size_t size, unsigned prot)
513         {
514             L4::Cap<L4Re::Rm> __rm__ = Vcap::Rm::set_environment_rm(Vcap::Rm::real_rm);
515
516             vcap_running = 0;
517             VG_TRACK(new_mem_mmap, (Addr)addr, size, prot & VKI_PROT_READ,
518                      prot & VKI_PROT_WRITE, prot & VKI_PROT_EXEC, 0);
519             vcap_running = 1;
520             Vcap::Rm::set_environment_rm(__rm__);
521         }
522
523     public:
524         void *attach(void *addr, unsigned long size, Region_handler const &hdlr,
525                      unsigned flags = None,
526                      unsigned char align = L4_PAGESHIFT) throw()
527         {
528             if (dbg_rm) VG_(debugLog)(3, "vcap", "%s: addr %p, size 0x%lx, flags 0x%x=%s%s\n",
529                           __func__, addr, size, flags,
530                           flags & L4Re::Rm::In_area ? "|In_area" : "",
531                           flags & L4Re::Rm::Search_addr ? "|Search_addr" : ""
532                           );
533
534             /*
535              * Special case 1: In_area flag is set -> we need to lookup the area and then
536              *                 find a free reservation inside it.
537              */
538             if (flags & L4Re::Rm::In_area) {
539                 addr = __handle_attach_in_area(addr, size, flags);
540                 if (dbg_rm) VG_(debugLog)(4, "vcap", "__handle_attach_in_area: %p\n", addr);
541                 if (addr == L4_INVALID_PTR)
542                     return addr;
543             }
544
545             /*
546              * Special case 2: Search_addr flag is set -> we need to find a free, unreserved
547              *                 segment.
548              */
549             if (flags & L4Re::Rm::Search_addr) {
550                 addr = __find_free_segment(0, size);
551                 if (dbg_rm) VG_(debugLog)(4, "vcap", "__find_free_segment: %p\n", addr);
552                 if (!addr)
553                     return L4_INVALID_PTR;
554             }
555
556             /*
557              * Next we need to establish the necessary information. Depending on which VRM
558              * instance this is, we either mark the mapping as Valgrind or Client. Access
559              * rights are determined from the RM handler info.
560              */
561
562             unsigned prot = VKI_PROT_READ;
563             if (!hdlr.is_ro())
564                 prot |= VKI_PROT_WRITE;
565
566             Off64T offs = hdlr.offset();
567
568             /*
569              * By default, we register all memory mappings as anonymous, because at this
570              * point in the MM chain all we know is data spaces and these are equivalent
571              * to anonymous memory. Valgrind however needs more detailed information for
572              * file mappings. This is handled outside, e.g., in the _dl_mmap trap handler.
573              */
574             unsigned vgflags = VKI_MAP_ANONYMOUS;
575
576             // Notify aspacemgr of Valgrind ...
577             if (_id == VRMcap_valgrind) {
578                 if (dbg_rm) VG_(debugLog)(4, "vcap", "am_notify_valgrind_mmap(a=%08lx, size %lx)\n",
579                                           addr, size);
580                 VG_(am_notify_valgrind_mmap)((Addr)addr, size, prot, vgflags, -1, 0);
581             }
582             else if (_id == VRMcap_client) { // ... or client mapping
583                     VG_(am_notify_client_mmap)((Addr)addr, size, prot, vgflags, -1, 0);
584                     __notify_tool_of_mapping((Addr)addr, size, prot);
585             }
586             else {
587                 // should not happen
588                 VG_(printf)("I can't determine what kind of mapping this is -- id = %lX\n", _id);
589                 enter_kdebug();
590             }
591
592             /*
593              * Aspacemgr now added the reservation/mapping to the segment array. Now we need to
594              * add a RM handler to this segment.
595              */
596             vrm_segment_notify((Addr)addr, (Addr)addr + size - 1, hdlr.client_cap_idx(), offs, flags);
597
598             if (dbg_rm) VG_(debugLog)(4, "vcap", "returning %p\n", addr);
599             return addr;
600         }
601
602
603         /*
604          * Reserve a region. We do this using Valgrind's RSVN segment type. When attaching areas to
605          * these reservations, we adapt accordingly. This may lead to a point, where no RSVN segment
606          * is there anymore. Hence, we cannot rely only on the segment array to store information on
607          * segments, but need to additionally keep track of regions in an area_info list.
608          */
609         l4_addr_t attach_area(l4_addr_t addr, unsigned long size,
610                               unsigned flags = None,
611                               unsigned char align = L4_PAGESHIFT) throw()
612         {
613             if (dbg_rm) VG_(debugLog)(3, "vcap", "%s: addr 0x%lx, size 0x%lx, flags 0x%x, align 0x%x\n",
614                     __func__, addr, size, flags, align);
615
616             if (flags & L4Re::Rm::Search_addr) {
617                 addr = (l4_addr_t)__find_free_segment((void*)addr, size);
618                 if (dbg_rm) VG_(debugLog)(4, "vcap", "__find_free_segment: %08lx\n", addr);
619                 if (!addr)
620                     return (l4_addr_t)L4_INVALID_PTR;
621             }
622
623             // Now we mark this area as reserved.
624             Bool ok = VG_(am_create_reservation)(addr, VG_PGROUNDUP(size), SmFixed, 0);
625             if (!ok) {
626                 /* 
627                  * Failing here is ok. This just means, there is already
628                  * another reservation existing. L4Re apps must handle this
629                  * themselves.
630                  */
631                 if (dbg_rm) VG_(debugLog)(4, "vcap", "Error creating reservation for area 0x%lx, size 0x%lx\n",
632                              addr, size);
633                 return L4_INVALID_ADDR;
634             }
635
636             NSegment *seg = const_cast<NSegment*>(VG_(am_find_nsegment)((Addr)addr));
637             area_info *info = new area_info(addr, addr + VG_PGROUNDUP(size) - 1);
638             VG_(am_set_nodeptr)(seg, (Addr)info);
639             if (dbg_rm) VG_(debugLog)(3, "vcap", "AREA segment %08lx node %p\n", (Addr)seg, info);
640
641             _areas.push_back(info);
642
643             return addr;
644         }
645
646
647         bool detach_area(l4_addr_t addr) throw()
648         {
649             if (dbg_rm) VG_(debugLog)(3, "vcap", "%s: addr 0x%lx\n", __func__, addr);
650
651             struct area_info *info = __find_area_info((void*)addr);
652             if (!info) {
653                 VG_(printf)("Cannot find area for address %p\n", (void*)addr);
654                 RM_ERROR;
655                 enter_kdebug("detach_area");
656             }
657
658             VG_(debugLog)(4, "vcap", "detach area: %08lx - %08lx\n", info->_start, info->_end);
659             NSegment *seg = const_cast<NSegment*>(VG_(am_find_nsegment)(info->_start));
660             /*
661              * Run through all segments within the area and unmap them if they are
662              * only reservations for this area.
663              */
664             while (seg->start < info->_end) {
665                 if (seg->kind == SkResvn && seg->dsNodePtr != NULL) {
666                     if (dbg_rm) VG_(debugLog)(4, "vcap", "unmapping resvn %08lx - %08lx\n",
667                                   seg->start, seg->end);
668                     NSegment *next_seg = seg + 1;
669                     Bool needDiscard = VG_(am_notify_munmap)(seg->start,
670                                                              seg->end - seg->start + 1);
671                     /*
672                      * we need to re-lookup the segment, because by removing
673                      * the mapping above, we invalidated our seg pointer
674                      */
675                     seg = next_seg;
676                 }
677                 else
678                     seg++;
679             }
680
681             if (dbg_rm) VG_(debugLog)(4, "vcap", "removed all reservations. Deleting area_info\n");
682             __remove_area_info((void*)addr);
683
684             return true;
685         }
686
687         int detach(void *addr, unsigned long sz, unsigned flags,
688                    Region *reg /* OUT */,
689                    Region_handler *hdlr /* OUT */) throw()
690         {
691             // XXX: overlapping detach?
692
693             if (dbg_rm) VG_(debugLog)(3, "vcap", "%s: addr %p, size 0x%lx, flags 0x%x, region %p, hdlr %p\n",
694                           __func__, addr, sz, flags, reg, hdlr);
695
696             NSegment const * seg = VG_(am_find_nsegment)((Addr)addr);
697             if (!seg ||(seg && seg->kind==SkResvn))
698                 return -L4_ENOENT;
699
700             unsigned size = l4_round_page(seg->end - seg->start);
701             Node n = reinterpret_cast<Node>(seg->dsNodePtr);
702             if (n) {
703                 *reg = n->first;
704                 *hdlr = n->second;
705                 delete n;
706             }
707
708             Bool needDiscard = VG_(am_notify_munmap)(seg->start, size);
709             if (dbg_rm) VG_(debugLog)(4, "vcap", "unmapped, need discard? %d\n", needDiscard);
710
711             return L4Re::Rm::Detached_ds;
712         }
713
714
715         Node find(Region const &reg) const throw()
716         {
717             if (dbg_pf) VG_(debugLog)(4, "vcap", "Find start 0x%lx, end 0x%lx\n", reg.start(),
718                           reg.end());
719
720             Node n;
721             NSegment const * vg_seg = VG_(am_find_nsegment)(reg.start());
722             if (!vg_seg) {
723                 VG_(debugLog)(1, "vcap", "Error looking up segment for 0x%lx\n",
724                               reg.start());
725                 return Node();
726             }
727             if (dbg_pf) VG_(debugLog)(4, "vcap", "Found segment: %p (0x%lx - 0x%lx) nptr %08lx, type %s\n",
728                           vg_seg, vg_seg->start, vg_seg->end, vg_seg->dsNodePtr, vcap_segknd_str(vg_seg->kind));
729
730             /*
731              * If there's no node ptr, something went wrong
732              */
733             if (!vg_seg->dsNodePtr) {
734                 VG_(debugLog)(0, "vcap", "ERROR: no node ptr found for region %lx - %lx\n",
735                               reg.start(), reg.end());
736                 RM_ERROR;
737             }
738             else
739                 n = (Node)vg_seg->dsNodePtr;
740
741             if (dbg_pf) VG_(debugLog)(4, "vcap", "Node ptr: %p\n", n);
742
743             return n;
744         }
745
746
747         Node area_find(Region const &) const throw()
748         {
749             enter_kdebug("area_find");
750             return NULL;
751         }
752
753         Node lower_bound(Region const &) const throw()
754         {
755             enter_kdebug("lower_bound");
756             return NULL;
757         }
758
759         Node lower_bound_area(Region const &) const throw()
760         {
761             enter_kdebug("lower_bound_area");
762             return NULL;
763         }
764
765         void get_lists( l4_addr_t) const throw()
766         {
767             enter_kdebug("get_lists");
768         }
769
770         l4_addr_t max_addr() const { return ~0UL; }
771
772
773 };
774
775 }; // Namespace Rm
776 }; // Namespace Vcap
777
778
779 class Vcap_object : public L4::Server_object
780 {
781     private:
782         Vcap::vcon_srv _log;
783         Vcap::Rm::rm   _rm;
784
785         unsigned _id;
786
787     public:
788         Vcap_object(unsigned id) : _rm(id), _id(id)
789         {}
790
791
792         int handle_exception()
793         {
794             VG_(printf)("\033[31mEXCEPTION\033[0m\n");
795             enter_kdebug();
796             return -L4_EOK;
797         }
798
799         int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios) L4_NOTHROW
800         {
801             if (dbg_vcap) VG_(debugLog)(4, "vcap", "dispatch\n");
802
803             l4_msgtag_t t;
804             ios >> t;
805
806             if (dbg_vcap) {
807                 VG_(debugLog)(4, "vcap", "label: %lx (%ld)\n", t.label(), t.label());
808             }
809
810             switch(t.label()) {
811                 case L4_PROTO_LOG:
812                     if (dbg_vcap) {
813                         VG_(debugLog)(2, "vcap", "log protocol\n");
814                     }
815                     return _log.dispatch(obj, ios);
816
817                 case L4_PROTO_PAGE_FAULT:
818                     //if (dbg_vcap) VG_(debugLog)(2, "vcap", "page fault\n");
819                     return _rm.dispatch(t, obj, ios);
820
821                 case L4Re::Protocol::Rm:
822                     return _rm.dispatch(t, obj, ios);
823
824                 case L4Re::Protocol::Parent:
825                     if (dbg_vcap) VG_(debugLog)(2, "vcap", "parent protocol\n");
826                     enter_kdebug("parent");
827                     return -L4_ENOSYS;
828
829                 case L4_PROTO_IRQ:
830                     if (dbg_vcap) VG_(debugLog)(2, "vcap", "irq protocol\n");
831                     return _rm.dispatch(t, obj, ios);
832
833                 case L4_PROTO_EXCEPTION:
834                     return handle_exception();
835
836                 default:
837                     VG_(debugLog)(2, "vcap", "Unknown protocol: %lx (%ld)\n",
838                                   t.label(), t.label());
839                     VG_(show_sched_status)();
840                     enter_kdebug("Unknown protocol");
841                     return -L4_ENOSYS;
842             }
843         }
844 };
845
846
847 /*
848  * Flag determining whether VRM is running atm. If this is true, we use VRM's normal
849  * memory management functions, otherwise (before VRM is started) we fall back to local
850  * implementations.
851  */
852 int vcap_running = 0;
853
854 /*
855  * We use 2 server objects for handling RM requests -- one for the client and one for
856  * Valgrind mappings.
857  */
858 static Vcap_object valgrind_obj(VRMcap_valgrind);
859 static Vcap_object client_obj(VRMcap_client);
860 L4::Cap<void> Vcap::Loop_hooks::rcv_cap;
861
862 /*
863  * Main VRM function
864  */
865 static void vcap_thread_fn(void *) L4_NOTHROW
866 {
867     VG_(debugLog)(1, "vcap", "%s: Here, vcap_running @ %p (%d)\n", __func__,
868                   &vcap_running, vcap_running);
869
870     Vcap::Rm::Region_ops::init();
871
872     Vcap::Loop_hooks::rcv_cap = L4Re::Util::cap_alloc.alloc<void>();
873     if (!Vcap::Loop_hooks::rcv_cap.is_valid()) {
874         VG_(debugLog)(0, "vcap","Error allocating rcv cap.\n");
875         enter_kdebug("ERROR");
876     }
877     else {
878         VG_(debugLog)(1, "vcap","Global rcv cap: %lx\n",
879                       Vcap::Loop_hooks::rcv_cap.cap());
880     }
881
882     L4Re::Util::Object_registry registry(vcap_thread,
883                                          L4Re::Env::env()->factory());
884
885     L4Re::Util::Registry_server<Vcap::Loop_hooks> server(l4_utcb(), vcap_thread,
886                                                          L4Re::Env::env()->factory());
887
888     server.registry()->register_obj(&valgrind_obj);
889     server.registry()->register_obj(&client_obj);
890
891     vcap_running = 1;
892
893     VG_(debugLog)(0, "vcap", "server.loop()\n");
894     server.loop();
895 }
896
897
898 /*
899  * Store info about the real Region Manager before switching everything
900  * into VRM mode.
901  */
902 void setup_real_rm()
903 {
904     Vcap::Rm::real_rm = L4Re::Env::env()->rm();
905     VG_(debugLog)(2, "vcap", "real rm %lx\n", Vcap::Rm::real_rm.cap());
906 }
907
908
909 /*
910  * Allocate capability and use it to create a thread.
911  */
912 L4::Cap<L4::Thread> allocate_new_thread()
913 {
914     L4::Cap<L4::Thread> ret = L4Re::Util::cap_alloc.alloc<L4::Thread>();
915     if (!ret.is_valid()) {
916         VG_(debugLog)(0, "vcap", "%s: Error allocating thread cap.",
917                       __func__);
918         enter_kdebug("ERROR");
919     }
920
921     if (dbg_vcap) VG_(debugLog)(1, "vcap", "vcap cap: %lx\n", ret.cap());
922
923     l4_msgtag_t tag = L4Re::Env::env()->factory()->create_thread(ret);
924     if (l4_msgtag_has_error(tag)) {
925         VG_(debugLog)(0, "vcap", "Error creating vcap thread from factory.\n");
926         enter_kdebug("ERROR");
927     }
928
929     return ret;
930 }
931
932
933 /*
934  * Basic VRM thread setup
935  */
936 void init_vcap_thread(L4::Cap<L4::Thread>& threadcap)
937 {
938     l4_utcb_t *new_utcb = reinterpret_cast<l4_utcb_t*>(
939                             L4Re::Env::env()->first_free_utcb());
940
941     L4::Thread::Attr a;
942     a.pager(L4Re::Env::env()->rm());
943     a.exc_handler(L4Re::Env::env()->rm());
944     a.bind(new_utcb, L4Re::This_task);
945     // XXX: do we need to increment first_free_utcb here?
946
947     l4_msgtag_t tag = threadcap->control(a);
948     if (l4_msgtag_has_error(tag)) {
949         VG_(debugLog)(0, "vcap-thread", "Error committing vcap thread.\n");
950     }
951
952     l4_sched_param_t sp;
953     // scheduling defaults, copied from loader/server/src/loader.cc
954     sp.prio     = 2;
955     sp.quantum  = 0;
956     sp.affinity = l4_sched_cpu_set(0, ~0, 1);
957
958     tag = L4Re::Env::env()->scheduler()->run_thread(threadcap, sp);
959     if (l4_msgtag_has_error(tag)) {
960         VG_(debugLog)(0, "vcap-thread", "Error setting scheduling attributes.\n");
961     }
962 }
963
964
965 void run_vcap_thread(L4::Cap<L4::Thread>& threadcap)
966 {
967     // XXX: is memset to 0 necessary or does this modify our test results?
968     VG_(memset)(vcap_stack, 0, sizeof(vcap_stack));
969
970     if (dbg_vcap) {
971         VG_(debugLog)(2, "vcap", "new stack: %p - %p\n", vcap_stack,
972                       vcap_stack + sizeof(vcap_stack));
973         VG_(debugLog)(2, "vcap", "ex_regs(0x%lx, 0x%lx, 0x%lx, 0)\n",
974                       threadcap.cap(), (l4_umword_t)vcap_thread_fn,
975                       (l4_umword_t)vcap_stack + sizeof(vcap_stack));
976     }
977
978     l4_msgtag_t tag = threadcap->ex_regs((l4_umword_t)vcap_thread_fn,
979                               (l4_umword_t)vcap_stack + sizeof(vcap_stack),
980                               0);
981     if (l4_msgtag_has_error(tag)) {
982             VG_(debugLog)(0, "vcap-thread", "Error enabling vcap thread.\n");
983     }
984
985     while (!vcap_running)
986         l4_sleep(100);
987 }
988
989
990 void main_thread_modify_rm(L4::Cap<void> cap)
991 {
992     /*
993      * Now that the VCap thread is started, we also want it to become _our_
994      * pager, so that it can take care of all region mapping duties.
995      */
996     L4::Thread::Attr    attr;
997     // we assume, we're always executed by the main thread!
998     L4::Cap<L4::Thread> self = L4Re::Env::env()->main_thread();
999
1000     attr.pager(cap);
1001     attr.exc_handler(cap);
1002     self->control(attr);
1003
1004     /*
1005      * And now vcap becomes everyone's region manager
1006      */
1007     Vcap::Rm::set_environment_rm(cap);
1008 }
1009
1010
1011 void vrm_track_utcb_area()
1012 {
1013     l4_fpage_t fp = L4Re::Env::env()->utcb_area();
1014     Addr start = l4_fpage_page(fp) << L4_PAGESHIFT;
1015     Addr end = start + (l4_fpage_size(fp) << L4_PAGESHIFT);
1016     VG_(debugLog)(4, "vcap", "TRACK(%lx, %lx, 1, 1, 0, 0)\n", start, end-start);
1017     VG_TRACK(new_mem_startup, start, end-start, True, True, False, 0);
1018 }
1019
1020
1021 EXTERN_C void l4re_vcap_start_thread(void)
1022 {
1023     VG_(debugLog)(2, "vcap", "%s: Here\n", __func__);
1024
1025     setup_real_rm();
1026
1027     vcap_thread = allocate_new_thread();
1028     init_vcap_thread(vcap_thread);
1029     run_vcap_thread(vcap_thread);
1030
1031     l4_debugger_set_object_name(vcap_thread.cap(), "VG::vcap");
1032     l4_debugger_set_object_name(L4Re::Env::env()->main_thread().cap(),
1033                                 "VG::main");
1034     l4_debugger_set_object_name(valgrind_obj.obj_cap().cap(), "VRMcap::valgrind");
1035     l4_debugger_set_object_name(client_obj.obj_cap().cap(), "VRMcap::client");
1036
1037     main_thread_modify_rm(valgrind_obj.obj_cap());
1038 }
1039
1040 /* The size of an L4Re::Env object is needed in setup_client_stack() which is
1041    part of a C source code file and thus cannot determine the size of a C++ class
1042    itself.
1043  */
1044 EXTERN_C size_t l4re_env_env_size()
1045 {
1046     return sizeof(L4Re::Env);
1047 }
1048
1049
1050 /*
1051  * Currently, the client sees all init caps Valgrind sees. In future versions we might
1052  * want to modify this as well. Therefore we create a copy of all init caps here and 
1053  * pass the client this copy for usage. This is the place to filter out or modify these
1054  * caps before starting the client.
1055  */
1056 static L4Re::Env::Cap_entry* __copy_init_caps(L4Re::Env const * const e)
1057 {
1058     if (dbg_vcap) VG_(debugLog)(4, "vcap", "counting caps\n");
1059     L4Re::Env::Cap_entry const *c = e->initial_caps();
1060
1061     unsigned cnt = 0;
1062     for ( ; c->flags != ~0UL; ++c, ++cnt)
1063         ;
1064
1065     if (dbg_vcap) VG_(debugLog)(4, "vcap", "count: %x\n", cnt+1);
1066
1067     SysRes res = VG_(am_mmap_anon_float_client)((cnt+1) * sizeof(L4Re::Env::Cap_entry),
1068                                                 VKI_PROT_READ | VKI_PROT_WRITE);
1069     if (sr_isError(res)) {
1070         VG_(debugLog)(0, "vcap", "Error allocating memory for client initial caps.\n");
1071         enter_kdebug();
1072     }
1073     VG_(memcpy)((void*)sr_Res(res), e->initial_caps(), (cnt+1) * sizeof(L4Re::Env::Cap_entry));
1074
1075     return reinterpret_cast<L4Re::Env::Cap_entry*>(sr_Res(res));
1076 }
1077
1078
1079 /*
1080  * Modify client environment and make VRM be the handler for all
1081  * interesting events.
1082  */
1083 EXTERN_C void *l4re_vcap_modify_env(struct ume_auxv *envp, Addr client_l4re_env_addr)
1084 {
1085     L4Re::Env *e = new ((void*)client_l4re_env_addr) L4Re::Env(*L4Re::Env::env());
1086     VG_(debugLog)(0, "vcap", "  New env @ %p\n", e);
1087     VG_(debugLog)(0, "vcap", "  Orig env @ %p\n", L4Re::Env::env());
1088
1089     e->parent(L4::cap_cast<L4Re::Parent>(client_obj.obj_cap()));
1090     e->rm(L4::cap_cast<L4Re::Rm>(client_obj.obj_cap()));
1091     e->log(L4::cap_cast<L4Re::Log>(client_obj.obj_cap()));
1092     e->first_free_cap(MAX_LOCAL_RM_CAPS + MAX_VG_CAPS);
1093     e->first_free_utcb(L4Re::Env::env()->first_free_utcb() + VG_UTCB_OFFSET);
1094     VG_(debugLog)(0, "vcap", "  new RM @ %lx\n", e->rm().cap());
1095
1096     e->initial_caps(__copy_init_caps(e));
1097
1098     client_env = (void *) e;
1099     client_env_size = l4re_env_env_size();
1100
1101     return e;
1102 }
1103
1104
1105 /*
1106  * When parsing the early region list from RM, we need to add Node descriptors
1107  * for the segments found.  Therefore this callback exists for the aspacemgr
1108  * code to notify us about a found segment.
1109  */
1110 void vrm_segment_notify(Addr start, Addr end, l4_cap_idx_t dscap, unsigned offset, unsigned flags)
1111 {
1112     NSegment *seg = const_cast<NSegment*>(VG_(am_find_nsegment)((Addr)start));
1113     if (seg->start == start && seg->end == end) {
1114         vrm_update_segptr(seg, dscap, offset, flags);
1115     }
1116     else {
1117         VG_(printf)("Segment mismatch: args %08lx-%08lx; found %08lx-%08lx\n",
1118                     start, end, seg->start, seg->end);
1119         enter_kdebug("error");
1120     }
1121 }
1122
1123
1124 /*
1125  * This function actually exists for exactly one region: When starting the
1126  * dynamic memory manager, Valgrind allocates a malloc pool. This is still done
1127  * using the "old" RM in place, therefore at this point we need to go to RM and
1128  * request all information necessary to register a node pointer for this
1129  * region.
1130  */
1131 void vrm_segment_fixup(NSegment *seg)
1132 {
1133     if (seg->dsNodePtr)
1134         return;
1135
1136     if (seg->kind == SkResvn)
1137         return;
1138
1139     L4::Cap<L4Re::Rm> _rm;
1140     if (Vcap::Rm::real_rm.is_valid())
1141         _rm = Vcap::Rm::real_rm;
1142     else
1143         _rm = L4Re::Env::env()->rm();
1144
1145     l4_addr_t addr     = seg->start;
1146     unsigned long size = seg->end - seg->start + 1;
1147     l4_addr_t offset   = 0;
1148     unsigned flags     = 0;
1149     L4::Cap<L4Re::Dataspace> ds;
1150     int i = _rm->find(&addr, &size, &offset, &flags, &ds);
1151     if (i && dbg_rm) VG_(debugLog)(2, "vcap", "vailed rm-find\n");
1152
1153     if (dbg_rm) VG_(debugLog)(2, "vcap", "%s: addr %lx size %lx, cap %lx, offs %lx\n",
1154                   __func__, addr, size, ds.cap(), offset);
1155
1156     if (ds.is_valid())
1157         vrm_update_segptr(seg, ds.cap(), offset, flags);
1158     if (dbg_rm) VG_(debugLog)(2, "vcap", "ds %lx node ptr @ %lx\n", ds.cap(), seg->dsNodePtr);
1159 }
1160
1161
1162 /*
1163  * Update node pointer information on an exisitng NSegment
1164  */
1165 void vrm_update_segptr(NSegment *seg, l4_cap_idx_t dscap, unsigned offset, unsigned flags)
1166 {
1167     typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
1168                                        Vcap::Rm::Region_ops>  Region_handler;
1169
1170     L4::Cap<L4Re::Dataspace> dummy(dscap);
1171     /*
1172      * If vcap is not yet running, we may assume, that Valgrind's dynamic memory
1173      * manager is not running yet as well. Therefore, using new() to create a node
1174      * would not work. Instead, we use a placement allocator in the early stages.
1175      *
1176      * -> exists for calls from vrm_segment_fixup() that end up here
1177      */
1178     static unsigned _mbuf_index = 0;     //< next index into early placement buf
1179     static char _early_malloc_buf[8192]; //< early placement buf
1180
1181     Vcap::Rm::node *n;
1182
1183     if (vcap_running)
1184         n = new Vcap::Rm::node(L4Re::Util::Region(seg->start, seg->end),
1185                                            Region_handler(dummy, dummy.cap(),
1186                                                           offset, flags));
1187     else {
1188         n = new (_early_malloc_buf + _mbuf_index) 
1189                 Vcap::Rm::node(L4Re::Util::Region(seg->start, seg->end),
1190                                                   Region_handler(dummy, dummy.cap(),
1191                                                                  offset, flags));
1192         _mbuf_index += sizeof(Vcap::Rm::node);
1193     }
1194
1195     VG_(am_set_nodeptr)(seg, (Addr)n);
1196     if (dbg_rm) {
1197         VG_(debugLog)(4, "vcap", "\033[32mupdate_segment %lx (%lx): node %p\033[0m\n",
1198                       seg->start, seg, seg->dsNodePtr);
1199     }
1200 }