2 * This file is part of the Valgrind port to L4Re.
4 * (c) 2009-2010 Aaron Pohle <apohle@os.inf.tu-dresden.de>,
5 * Bjoern Doebel <doebel@os.inf.tu-dresden.de>
6 * economic rights: Technische Universitaet Dresden (Germany)
8 #include <l4/re/util/cap_alloc>
10 #include <l4/re/util/region_mapping>
11 #include <l4/cxx/slab_alloc>
12 #include <l4/cxx/ipc_server>
15 #include "l4re/myelf.h"
16 #include "pub_core_basics.h"
18 #include "pub_l4re_consts.h"
19 #include "pub_tool_libcbase.h"
20 #include "pub_tool_libcfile.h"
21 #include "pub_core_libcprint.h"
23 #include "pub_core_vki.h"
25 #include "pub_core_tooliface.h"
26 #include "pub_core_libcassert.h" // VG_(exit)
27 #include "l4re_helper.h"
30 /***********************************************************************************
32 * L4Re kernel compatibility cruft
33 * -------------------------------
35 * L4Re executes the L4Re kernel within every application. The kernel's is respon-
36 * sible for loading the application (until startup of the main thread) and there-
37 * after acts as the application's region manager and page fault handler. Both of
38 * these tasks are in our case taken over by VCap. However, in order to do this,
39 * Valgrind needs info about the initial memory layout upon startup of its address
42 * Since there is no easy way to gain this information from the L4Re kernel (as it
43 * is deliberately kept private, because we don't want anyone messing aroung with
44 * the region map), we need to take the slightly fragile way of mirroring parts of
45 * the L4Re kernel's class declarations here in order to be able to use them later
49 * (1) Be careful, when to use this stuff. By now, only VG_(am_startup)() should
51 * ==> There is a check in vrm_get_lists() to make sure this won't work
52 * after VCap took over.
53 * (2) Be careful with copied class declarations.
54 * ==> Clearly mark where these decls come from.
56 ***********************************************************************************/
58 // l4re_kernel/server/src/page_alloc.h, revision 37866
61 class Single_page_alloc_base
64 static void init(L4::Cap<L4Re::Mem_alloc> alloc);
65 static void init_local_rm(Region_map *lrm);
67 Single_page_alloc_base();
68 static void *_alloc();
69 static void _free(void *p);
73 class Single_page_alloc : public Single_page_alloc_base
76 enum { can_free = true };
77 A *alloc() { return reinterpret_cast<A*>(_alloc()); }
78 void free(A *o) { _free(o); }
82 // l4re_kernel/server/src/slab_alloc.h, revision 37866
83 template< typename Type >
85 : public cxx::Slab_static<Type, L4_PAGESIZE, 2, Single_page_alloc>
89 // l4re_kernel/server/src/region.h, revision 37866
92 typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>, Region_ops> Region_handler;
97 typedef l4_umword_t Map_result;
98 static int map(Region_handler const *h, l4_addr_t addr,
99 L4Re::Util::Region const &r, bool writable,
100 l4_umword_t *result);
102 static void unmap(Region_handler const *h, l4_addr_t vaddr,
103 l4_addr_t offs, unsigned long size);
105 static void free(Region_handler const *h, l4_addr_t start, unsigned long size);
107 static void take(Region_handler const *h);
108 static void release(Region_handler const *h);
113 : public L4Re::Util::Region_map<Region_handler, Slab_alloc>
116 typedef L4Re::Util::Region_map<Region_handler, Slab_alloc> Base;
120 //void setup_wait(L4::Ipc_istream &istr);
121 int handle_pagefault(L4::Ipc_iostream &ios);
122 int handle_rm_request(L4::Ipc_iostream &ios);
123 virtual ~Region_map() {}
127 void debug_dump(unsigned long function) const;
129 int reply_err(L4::Ipc_iostream &ios);
133 EXTERN_C void* mmap(void *, size_t, int, int, int, off_t) throw();
134 EXTERN_C int munmap(void *, size_t) throw();
137 static Region_map *vrm_determine_local_rm_address()
140 * Determine the address of the RE kernel's local RM.
144 * 1. Try to find symbol in ELF image file
146 if (dbg_elf) VG_(printf)("opening rom/l4re\n");
147 SysRes res = VG_(open)((const Char*)"rom/l4re", VKI_O_RDONLY, 0);
148 if (dbg_elf) VG_(printf)("opened: %ld\n", sr_Res(res));
149 if (sr_isError(res)) {
150 VG_(printf)("Error opening file: %ld\n", sr_Err(res));
154 int fd = sr_Res(res);
156 struct vg_stat statbuf;
157 int err = VG_(fstat)(fd, &statbuf);
158 if (dbg_elf) VG_(printf)("stat: %d, size %d\n", err, (int)statbuf.size);
161 VG_(printf)("error on fstat(): %d\n", err);
166 a = mmap(a, statbuf.size, VKI_PROT_READ, VKI_MAP_PRIVATE, fd, 0);
167 if (dbg_elf) VG_(printf)("mmap to %p\n", a);
169 melf_global_elf_info i;
170 err = melf_parse_elf(a, &i);
171 if (dbg_elf) VG_(printf)("parsed: %d\n", err);
173 char *rm_addr = melf_find_symbol_by_name(&i, (char*)"__local_rm");
174 if (dbg_elf) VG_(printf)("Found symbol %s @ %p\n", (char*)"__local_rm", rm_addr);
176 munmap(a, VG_PGROUNDUP(statbuf.size));
180 return reinterpret_cast<Region_map*>(rm_addr);
183 * 2. If not successful parsing binary, try hard-coded value
185 VG_(printf)("Did not find local-rm, aborting\n");
192 EXTERN_C void vrm_get_lists(struct vrm_region_lists *rlist, unsigned num_regions,
196 * If we happen to need this function while vcap is running (which should not be
197 * the case), then implement it as a call to vcap in order to serialize segment
201 VG_(debugLog)(0, "vcap", "Attention: VCAP thread is already running.");
206 * ... otherwise we'll now assume that we are running single-threaded and
207 * vcap has not been started yet. (This is the case where am_startup() uses
208 * this function to populate the segment list initially.)
211 Region_map *lrm = vrm_determine_local_rm_address();
212 if (dbg_elf) VG_(printf)("LRM found @ %p\n", lrm);
215 /* LRM generic stats */
216 rlist->min_addr = lrm->min_addr();
217 rlist->max_addr = lrm->max_addr();
218 rlist->region_count = 0;
219 rlist->area_count = 0;
220 if (dbg_rm) VG_(debugLog)(2, "vcap", "rlist min: %08lx\n", rlist->min_addr);
221 if (dbg_rm) VG_(debugLog)(2, "vcap", "rlist max: %08lx\n", rlist->max_addr);
224 struct vrm_area *area = rlist->areas;
225 for (Region_map::Const_iterator i = lrm->area_begin();
226 i != lrm->area_end();
228 if (dbg_rm) VG_(debugLog)(2, "vcap", "AREA %08lx - %08lx\n", i->first.start(), i->first.end());
229 area->start = i->first.start();
230 area->end = i->first.end();
231 area->flags = i->second.flags();
237 /* Read LRM regions */
238 struct vrm_region *reg = rlist->regions;
239 for (Region_map::Const_iterator i = lrm->begin();
242 if (dbg_rm) VG_(debugLog)(2, "vcap", "REGION %08lx - %08lx\n", i->first.start(), i->first.end());
243 reg->start = i->first.start();
244 reg->end = i->first.end();
245 reg->flags = i->second.flags();
246 reg->offset_in_ds = i->second.offset();
247 reg->ds = i->second.memory().cap();
250 ++rlist->region_count;
254 VG_(printf)("implement probing fallback...\n");