4 * This file is part of the Valgrind port to L4Re.
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)
11 #include <l4/sys/compiler.h>
12 // C++'s definition of NULL disagrees with Valgrind's
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>
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>
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"
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"
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"
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;
74 L4::Cap<L4::Thread> vcap_thread;
75 char vcap_stack[1 << 13]; // 8 kB
77 #include "l4re/allocator"
80 #include "l4re/loop_hooks"
88 // see l4/pkg/loader/server/src/region.cc:Rm_server
92 typedef L4::Cap<L4Re::Dataspace> Dataspace;
94 enum { Have_find = true };
96 static int validate_ds(L4::Snd_fpage const & ds_cap, unsigned flags,
97 L4::Cap<L4Re::Dataspace> *ds)
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());
105 static l4_umword_t find_res(L4::Cap<void> const &ds) { return ds.cap(); }
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;
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.
116 L4::Cap<L4Re::Rm> set_environment_rm(L4::Cap<void> cap)
118 L4::Cap<L4Re::Rm> ret = L4Re::Env::env()->rm();
120 L4::Cap<L4Re::Rm> rm(cap.cap());
121 const_cast<L4Re::Env*>(L4Re::Env::env())->rm(rm);
128 // see: loader/server/src/region.cc
132 typedef L4::Snd_fpage Map_result;
133 typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
134 Vcap::Rm::Region_ops> MyRegion_handler;
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
145 unsigned flags = VKI_MAP_ANONYMOUS;
147 VG_(am_notify_valgrind_mmap)((Addr)the_map_area,
148 VG_PGROUNDUP(the_map_area_end - the_map_area),
151 VG_(debugLog)(1, "vcap", "Region ops map area: 0x%lx - 0x%lx\n",
152 the_map_area, the_map_area_end);
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)
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");
163 if ((h->flags() & L4Re::Rm::Reserved) || !h->memory().is_valid()) {
164 VG_(debugLog)(4, "vcap", "Reserved || invalid\n");
169 if (h->flags() & L4Re::Rm::Pager) {
170 VG_(debugLog)(4, "vcap", "pager\n");
175 if (h->is_ro() && writable)
176 Dbg(Dbg::Warn).printf("WARNING: Writable mapping request on read-only region at 0x%lx!\n",
179 l4_addr_t offset = local_addr - r.start() + h->offset();
180 L4::Cap<L4Re::Dataspace> ds = L4::cap_cast<L4Re::Dataspace>(h->memory());
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");
193 if (dbg_ds) VG_(debugLog)(4, "vcap", "ds->map(): %d\n", err);
195 *result = L4::Snd_fpage::mem(the_map_area, L4_PAGESHIFT, L4_FPAGE_RWX,
196 local_addr, L4::Snd_fpage::Grant);
200 static void unmap(MyRegion_handler const *h, l4_addr_t vaddr,
201 l4_addr_t offs, unsigned long size)
203 (void)h; (void)vaddr; (void)offs; (void)size;
204 VG_(debugLog)(0, "vcap", "\n");
205 enter_kdebug("Region_ops::unmap()");
208 static void take(MyRegion_handler const *h)
211 VG_(debugLog)(0, "vcap", "\n");
212 enter_kdebug("Region_ops::take()");
215 static void release(MyRegion_handler const *h)
218 VG_(debugLog)(0, "vcap", "\n");
219 enter_kdebug("Region_ops::release()");
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.
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)
239 L4Re::Util::Region first;
240 L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
241 Vcap::Rm::Region_ops> second;
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.
256 area_info(Addr start, Addr end)
257 :_start(start), _end(end)
261 bool match_resvn(NSegment const * const seg) const
263 return ((seg->kind == SkResvn) &&
264 (seg->start == _start) &&
269 bool contains_nsegment(NSegment const * const seg) const
271 return ((seg->start >= _start) &&
277 #define DEBUG_RM_LAYOUT do { VG_(am_show_nsegments)(0, (HChar*)"current AS layout"); } while (0)
279 #define RM_ERROR do { DEBUG_RM_LAYOUT; enter_kdebug("rm error"); } while (0)
282 * VCap::rm -- virtual region manager.
284 * This class implements a region manager on top of Valgrind's segment array.
285 * We map L4RM functionality as follows:
287 * 1) attach/detach -> create/delete new segments
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
296 * 2) attach_area -> create new reservation and add to list
297 * 3) detach_area -> remove all reservations in area and list entry
302 cxx::List<struct area_info *, Valgrind_allocator> _areas;
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;
314 Search = L4Re::Rm::Search_addr,
315 In_area = L4Re::Rm::In_area,
318 rm(unsigned id) : _id(id) { }
320 int dispatch(l4_msgtag_t tag, l4_umword_t obj, L4::Ipc_iostream &ios)
325 switch(tag.label()) {
326 case L4_PROTO_PAGE_FAULT:
327 return L4Re::Util::region_pf_handler<Vcap::Dbg>(this, ios);
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);
335 return -L4_EBADPROTO;
343 * Find area info for addr.
345 struct area_info *__find_area_info(void *addr)
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)
358 * Remove area info for addr.
360 bool __remove_area_info(void *addr) {
361 typedef cxx::List<struct area_info *, Valgrind_allocator> LIST;
362 LIST::Iter i = _areas.items();
364 struct area_info *inf = *i;
365 if (inf->_start <= (Addr)addr && inf->_end >= (Addr)addr)
379 * Do what is necessary to attach a region into an already existing area.
381 * \return L4_INVALID_PTR on error
382 * start address on success
384 void *__handle_attach_in_area(void *addr, unsigned long size, unsigned flags)
386 if (dbg_rm) VG_(debugLog)(4, "vcap", "%s: %p %lx %x\n", __func__, addr, size, flags);
388 /* We need to find the reservation for this area.
390 * Case A: The area is still empty, then we'll find the resvn by simply
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.
397 NSegment *seg = const_cast<NSegment*>(VG_(am_find_nsegment)((Addr)addr));
400 VG_(printf)("No reservation found for attach in area. Addr %p, size %ld\n",
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));
408 struct area_info *info = __find_area_info(addr);
410 VG_(printf)("ERROR: could not find area for address %p\n", addr);
413 if (dbg_rm) VG_(debugLog)(4, "vcap", "Area @ %p (%08lx - %08lx)\n",
414 info, info->_start, info->_end);
419 if (!info->match_resvn(seg) && seg->kind != SkResvn) {
420 enter_kdebug("resvn not matching");
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.
428 Addr old_start = seg->start;
429 Addr old_end = seg->end;
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);
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);
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);
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
464 * \return L4_INVALID_PTR on error
465 * valid segment start on success
467 void *__find_free_segment(void *start, unsigned size)
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);
477 // should not happen!
478 VG_(printf)("Cannot determine the type of mapping here: %lx\n", _id);
483 VG_(debugLog)(0, "vcap", "Advisor has no free area for us!\n");
485 enter_kdebug("error looking up free segment");
486 return L4_INVALID_PTR;
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!).
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.
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.
512 void __notify_tool_of_mapping(Addr addr, size_t size, unsigned prot)
514 L4::Cap<L4Re::Rm> __rm__ = Vcap::Rm::set_environment_rm(Vcap::Rm::real_rm);
517 VG_TRACK(new_mem_mmap, (Addr)addr, size, prot & VKI_PROT_READ,
518 prot & VKI_PROT_WRITE, prot & VKI_PROT_EXEC, 0);
520 Vcap::Rm::set_environment_rm(__rm__);
524 void *attach(void *addr, unsigned long size, Region_handler const &hdlr,
525 unsigned flags = None,
526 unsigned char align = L4_PAGESHIFT) throw()
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" : ""
535 * Special case 1: In_area flag is set -> we need to lookup the area and then
536 * find a free reservation inside it.
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)
546 * Special case 2: Search_addr flag is set -> we need to find a free, unreserved
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);
553 return L4_INVALID_PTR;
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.
562 unsigned prot = VKI_PROT_READ;
564 prot |= VKI_PROT_WRITE;
566 Off64T offs = hdlr.offset();
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.
574 unsigned vgflags = VKI_MAP_ANONYMOUS;
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",
580 VG_(am_notify_valgrind_mmap)((Addr)addr, size, prot, vgflags, -1, 0);
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);
588 VG_(printf)("I can't determine what kind of mapping this is -- id = %lX\n", _id);
593 * Aspacemgr now added the reservation/mapping to the segment array. Now we need to
594 * add a RM handler to this segment.
596 vrm_segment_notify((Addr)addr, (Addr)addr + size - 1, hdlr.client_cap_idx(), offs, flags);
598 if (dbg_rm) VG_(debugLog)(4, "vcap", "returning %p\n", addr);
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.
609 l4_addr_t attach_area(l4_addr_t addr, unsigned long size,
610 unsigned flags = None,
611 unsigned char align = L4_PAGESHIFT) throw()
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);
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);
620 return (l4_addr_t)L4_INVALID_PTR;
623 // Now we mark this area as reserved.
624 Bool ok = VG_(am_create_reservation)(addr, VG_PGROUNDUP(size), SmFixed, 0);
627 * Failing here is ok. This just means, there is already
628 * another reservation existing. L4Re apps must handle this
631 if (dbg_rm) VG_(debugLog)(4, "vcap", "Error creating reservation for area 0x%lx, size 0x%lx\n",
633 return L4_INVALID_ADDR;
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);
641 _areas.push_back(info);
647 bool detach_area(l4_addr_t addr) throw()
649 if (dbg_rm) VG_(debugLog)(3, "vcap", "%s: addr 0x%lx\n", __func__, addr);
651 struct area_info *info = __find_area_info((void*)addr);
653 VG_(printf)("Cannot find area for address %p\n", (void*)addr);
655 enter_kdebug("detach_area");
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));
661 * Run through all segments within the area and unmap them if they are
662 * only reservations for this area.
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);
672 * we need to re-lookup the segment, because by removing
673 * the mapping above, we invalidated our seg pointer
681 if (dbg_rm) VG_(debugLog)(4, "vcap", "removed all reservations. Deleting area_info\n");
682 __remove_area_info((void*)addr);
687 int detach(void *addr, unsigned long sz, unsigned flags,
688 Region *reg /* OUT */,
689 Region_handler *hdlr /* OUT */) throw()
691 // XXX: overlapping detach?
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);
696 NSegment const * seg = VG_(am_find_nsegment)((Addr)addr);
697 if (!seg ||(seg && seg->kind==SkResvn))
700 unsigned size = l4_round_page(seg->end - seg->start);
701 Node n = reinterpret_cast<Node>(seg->dsNodePtr);
708 Bool needDiscard = VG_(am_notify_munmap)(seg->start, size);
709 if (dbg_rm) VG_(debugLog)(4, "vcap", "unmapped, need discard? %d\n", needDiscard);
711 return L4Re::Rm::Detached_ds;
715 Node find(Region const ®) const throw()
717 if (dbg_pf) VG_(debugLog)(4, "vcap", "Find start 0x%lx, end 0x%lx\n", reg.start(),
721 NSegment const * vg_seg = VG_(am_find_nsegment)(reg.start());
723 VG_(debugLog)(1, "vcap", "Error looking up segment for 0x%lx\n",
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));
731 * If there's no node ptr, something went wrong
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());
739 n = (Node)vg_seg->dsNodePtr;
741 if (dbg_pf) VG_(debugLog)(4, "vcap", "Node ptr: %p\n", n);
747 Node area_find(Region const &) const throw()
749 enter_kdebug("area_find");
753 Node lower_bound(Region const &) const throw()
755 enter_kdebug("lower_bound");
759 Node lower_bound_area(Region const &) const throw()
761 enter_kdebug("lower_bound_area");
765 void get_lists( l4_addr_t) const throw()
767 enter_kdebug("get_lists");
770 l4_addr_t max_addr() const { return ~0UL; }
779 class Vcap_object : public L4::Server_object
788 Vcap_object(unsigned id) : _rm(id), _id(id)
792 int handle_exception()
794 VG_(printf)("\033[31mEXCEPTION\033[0m\n");
799 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios) L4_NOTHROW
801 if (dbg_vcap) VG_(debugLog)(4, "vcap", "dispatch\n");
807 VG_(debugLog)(4, "vcap", "label: %lx (%ld)\n", t.label(), t.label());
813 VG_(debugLog)(2, "vcap", "log protocol\n");
815 return _log.dispatch(obj, ios);
817 case L4_PROTO_PAGE_FAULT:
818 //if (dbg_vcap) VG_(debugLog)(2, "vcap", "page fault\n");
819 return _rm.dispatch(t, obj, ios);
821 case L4Re::Protocol::Rm:
822 return _rm.dispatch(t, obj, ios);
824 case L4Re::Protocol::Parent:
825 if (dbg_vcap) VG_(debugLog)(2, "vcap", "parent protocol\n");
826 enter_kdebug("parent");
830 if (dbg_vcap) VG_(debugLog)(2, "vcap", "irq protocol\n");
831 return _rm.dispatch(t, obj, ios);
833 case L4_PROTO_EXCEPTION:
834 return handle_exception();
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");
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
852 int vcap_running = 0;
855 * We use 2 server objects for handling RM requests -- one for the client and one for
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;
865 static void vcap_thread_fn(void *) L4_NOTHROW
867 VG_(debugLog)(1, "vcap", "%s: Here, vcap_running @ %p (%d)\n", __func__,
868 &vcap_running, vcap_running);
870 Vcap::Rm::Region_ops::init();
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");
878 VG_(debugLog)(1, "vcap","Global rcv cap: %lx\n",
879 Vcap::Loop_hooks::rcv_cap.cap());
882 L4Re::Util::Object_registry registry(vcap_thread,
883 L4Re::Env::env()->factory());
885 L4Re::Util::Registry_server<Vcap::Loop_hooks> server(l4_utcb(), vcap_thread,
886 L4Re::Env::env()->factory());
888 server.registry()->register_obj(&valgrind_obj);
889 server.registry()->register_obj(&client_obj);
893 VG_(debugLog)(0, "vcap", "server.loop()\n");
899 * Store info about the real Region Manager before switching everything
904 Vcap::Rm::real_rm = L4Re::Env::env()->rm();
905 VG_(debugLog)(2, "vcap", "real rm %lx\n", Vcap::Rm::real_rm.cap());
910 * Allocate capability and use it to create a thread.
912 L4::Cap<L4::Thread> allocate_new_thread()
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.",
918 enter_kdebug("ERROR");
921 if (dbg_vcap) VG_(debugLog)(1, "vcap", "vcap cap: %lx\n", ret.cap());
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");
934 * Basic VRM thread setup
936 void init_vcap_thread(L4::Cap<L4::Thread>& threadcap)
938 l4_utcb_t *new_utcb = reinterpret_cast<l4_utcb_t*>(
939 L4Re::Env::env()->first_free_utcb());
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?
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");
953 // scheduling defaults, copied from loader/server/src/loader.cc
956 sp.affinity = l4_sched_cpu_set(0, ~0, 1);
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");
965 void run_vcap_thread(L4::Cap<L4::Thread>& threadcap)
967 // XXX: is memset to 0 necessary or does this modify our test results?
968 VG_(memset)(vcap_stack, 0, sizeof(vcap_stack));
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));
978 l4_msgtag_t tag = threadcap->ex_regs((l4_umword_t)vcap_thread_fn,
979 (l4_umword_t)vcap_stack + sizeof(vcap_stack),
981 if (l4_msgtag_has_error(tag)) {
982 VG_(debugLog)(0, "vcap-thread", "Error enabling vcap thread.\n");
985 while (!vcap_running)
990 void main_thread_modify_rm(L4::Cap<void> cap)
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.
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();
1001 attr.exc_handler(cap);
1002 self->control(attr);
1005 * And now vcap becomes everyone's region manager
1007 Vcap::Rm::set_environment_rm(cap);
1011 void vrm_track_utcb_area()
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);
1021 EXTERN_C void l4re_vcap_start_thread(void)
1023 VG_(debugLog)(2, "vcap", "%s: Here\n", __func__);
1027 vcap_thread = allocate_new_thread();
1028 init_vcap_thread(vcap_thread);
1029 run_vcap_thread(vcap_thread);
1031 l4_debugger_set_object_name(vcap_thread.cap(), "VG::vcap");
1032 l4_debugger_set_object_name(L4Re::Env::env()->main_thread().cap(),
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");
1037 main_thread_modify_rm(valgrind_obj.obj_cap());
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
1044 EXTERN_C size_t l4re_env_env_size()
1046 return sizeof(L4Re::Env);
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.
1056 static L4Re::Env::Cap_entry* __copy_init_caps(L4Re::Env const * const e)
1058 if (dbg_vcap) VG_(debugLog)(4, "vcap", "counting caps\n");
1059 L4Re::Env::Cap_entry const *c = e->initial_caps();
1062 for ( ; c->flags != ~0UL; ++c, ++cnt)
1065 if (dbg_vcap) VG_(debugLog)(4, "vcap", "count: %x\n", cnt+1);
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");
1073 VG_(memcpy)((void*)sr_Res(res), e->initial_caps(), (cnt+1) * sizeof(L4Re::Env::Cap_entry));
1075 return reinterpret_cast<L4Re::Env::Cap_entry*>(sr_Res(res));
1080 * Modify client environment and make VRM be the handler for all
1081 * interesting events.
1083 EXTERN_C void *l4re_vcap_modify_env(struct ume_auxv *envp, Addr client_l4re_env_addr)
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());
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());
1096 e->initial_caps(__copy_init_caps(e));
1098 client_env = (void *) e;
1099 client_env_size = l4re_env_env_size();
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.
1110 void vrm_segment_notify(Addr start, Addr end, l4_cap_idx_t dscap, unsigned offset, unsigned flags)
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);
1117 VG_(printf)("Segment mismatch: args %08lx-%08lx; found %08lx-%08lx\n",
1118 start, end, seg->start, seg->end);
1119 enter_kdebug("error");
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
1131 void vrm_segment_fixup(NSegment *seg)
1136 if (seg->kind == SkResvn)
1139 L4::Cap<L4Re::Rm> _rm;
1140 if (Vcap::Rm::real_rm.is_valid())
1141 _rm = Vcap::Rm::real_rm;
1143 _rm = L4Re::Env::env()->rm();
1145 l4_addr_t addr = seg->start;
1146 unsigned long size = seg->end - seg->start + 1;
1147 l4_addr_t offset = 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");
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);
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);
1163 * Update node pointer information on an exisitng NSegment
1165 void vrm_update_segptr(NSegment *seg, l4_cap_idx_t dscap, unsigned offset, unsigned flags)
1167 typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
1168 Vcap::Rm::Region_ops> Region_handler;
1170 L4::Cap<L4Re::Dataspace> dummy(dscap);
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.
1176 * -> exists for calls from vrm_segment_fixup() that end up here
1178 static unsigned _mbuf_index = 0; //< next index into early placement buf
1179 static char _early_malloc_buf[8192]; //< early placement buf
1184 n = new Vcap::Rm::node(L4Re::Util::Region(seg->start, seg->end),
1185 Region_handler(dummy, dummy.cap(),
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(),
1192 _mbuf_index += sizeof(Vcap::Rm::node);
1195 VG_(am_set_nodeptr)(seg, (Addr)n);
1197 VG_(debugLog)(4, "vcap", "\033[32mupdate_segment %lx (%lx): node %p\033[0m\n",
1198 seg->start, seg, seg->dsNodePtr);