1 (* Memory info command for virtual domains.
2 (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 Functions for making a memory map of a virtual machine from
20 various sources. The memory map will most certainly have holes.
34 (* A range of addresses (start and start+size). *)
35 type interval = addr * addr
41 (* Bigarray mmap(2)'d region with byte addressing: *)
42 arr : (char,int8_unsigned_elt,c_layout) Array1.t;
43 (* The order that the mappings were added, 0 for the first mapping,
44 * 1 for the second mapping, etc.
50 type ('ws,'e,'hm) t = {
51 (* List of mappings, kept in reverse order they were added (new
52 * mappings are added at the head of this list).
54 mappings : mapping list;
56 (* Segment tree for fast access to a mapping at a particular address.
57 * This is rebuilt each time a new mapping is added.
58 * NB! If mappings = [], ignore contents of this field. (This is
59 * enforced by the 'hm phantom type).
61 tree : (interval * mapping option, interval * mapping option) binary_tree;
63 (* Word size, endianness.
64 * Phantom types enforce that these are set before being used.
67 endian : Bitstring.endian;
72 tree = Leaf ((0L,0L),None);
74 endian = Bitstring.LittleEndian;
77 let set_wordsize t ws = { t with wordsize = ws }
79 let set_endian t e = { t with endian = e }
81 let get_wordsize t = t.wordsize
83 let get_endian t = t.endian
85 (* Build the segment tree from the list of mappings. This code
86 * is taken from virt-df. For an explanation of the process see:
87 * http://en.wikipedia.org/wiki/Segment_tree
89 * See also the 'get_mapping' function below which uses this tree
92 let tree_of_mappings mappings =
93 (* Construct the list of distinct endpoints. *)
96 (fun { start = start; size = size } -> [start; start +^ size])
98 let eps = sort_uniq (List.concat eps) in
100 (* Construct the elementary intervals. *)
102 let elints, lastpoint =
104 fun (elints, prevpoint) point ->
105 ((point, point) :: (prevpoint, point) :: elints), point
107 let elints = (lastpoint, Int64.max_int(*XXX*)) :: elints in
111 eprintf "elementary intervals (%d in total):\n" (List.length elints);
113 fun (startpoint, endpoint) ->
114 eprintf " %Lx %Lx\n" startpoint endpoint
118 (* Construct the binary tree of elementary intervals. *)
120 (* Each elementary interval becomes a leaf. *)
121 let elints = List.map (fun elint -> Leaf elint) elints in
122 (* Recursively build this into a binary tree. *)
123 let rec make_layer = function
126 (* Turn pairs of leaves at the bottom level into nodes. *)
127 | (Leaf _ as a) :: (Leaf _ as b) :: xs ->
128 let xs = make_layer xs in
129 Node (a, (), b) :: xs
130 (* Turn pairs of nodes at higher levels into nodes. *)
131 | (Node _ as left) :: ((Node _|Leaf _) as right) :: xs ->
132 let xs = make_layer xs in
133 Node (left, (), right) :: xs
134 | Leaf _ :: _ -> assert false (* never happens??? (I think) *)
136 let rec loop = function
139 | xs -> loop (make_layer xs)
144 let leaf_printer (startpoint, endpoint) =
145 sprintf "%Lx-%Lx" startpoint endpoint
147 let node_printer () = "" in
148 print_binary_tree leaf_printer node_printer tree
151 (* Insert the mappings into the tree one by one. *)
153 (* For each node/leaf in the tree, add its interval and an
154 * empty list which will be used to store the mappings.
156 let rec interval_tree = function
157 | Leaf elint -> Leaf (elint, None)
158 | Node (left, (), right) ->
159 let left = interval_tree left in
160 let right = interval_tree right in
161 let (leftstart, _) = interval_of_node left in
162 let (_, rightend) = interval_of_node right in
163 let interval = leftstart, rightend in
164 Node (left, (interval, None), right)
165 and interval_of_node = function
166 | Leaf (elint, _) -> elint
167 | Node (_, (interval, _), _) -> interval
170 let tree = interval_tree tree in
171 (* This should always be true: *)
172 assert (interval_of_node tree = (0L, Int64.max_int(*XXX*)));
174 (* "Contained in" operator.
175 * 'a <-< b' iff 'a' is a subinterval of 'b'.
177 * |<----------- b ----------->|
179 let (<-<) (a1, a2) (b1, b2) = b1 <= a1 && a2 <= b2 in
181 (* "Intersects" operator.
182 * 'a /\ b' iff intervals 'a' and 'b' overlap, eg:
184 * |<----------- b ----------->|
186 let ( /\ ) (a1, a2) (b1, b2) = a2 > b1 || b2 > a1 in
188 let rec insert_mapping tree mapping =
189 let { start = start; size = size } = mapping in
190 let seginterval = start, start +^ size in
193 (* Test if we should insert into this leaf or node: *)
194 | Leaf (interval, None) when interval <-< seginterval ->
195 Leaf (interval, Some mapping)
196 | Leaf (interval, Some oldmapping) when interval <-< seginterval ->
198 if oldmapping.order > mapping.order then oldmapping else mapping in
199 Leaf (interval, Some mapping)
201 | Node (left, (interval, None), right) when interval <-< seginterval ->
202 Node (left, (interval, Some mapping), right)
204 | Node (left, (interval, Some oldmapping), right)
205 when interval <-< seginterval ->
207 if oldmapping.order > mapping.order then oldmapping else mapping in
208 Node (left, (interval, Some mapping), right)
210 | (Leaf _) as leaf -> leaf
212 (* Else, should we insert into left or right subtrees? *)
213 | Node (left, i, right) ->
215 if seginterval /\ interval_of_node left then
216 insert_mapping left mapping
220 if seginterval /\ interval_of_node right then
221 insert_mapping right mapping
224 Node (left, i, right)
226 let tree = List.fold_left insert_mapping tree mappings in
230 let printer ((sp, ep), mapping) =
231 sprintf "[%Lx-%Lx] " sp ep ^
234 | Some { start = start; size = size; order = order } ->
235 sprintf "%Lx..%Lx(%d)" start (start+^size-^1L) order
237 print_binary_tree printer printer tree
242 let add_mapping ({ mappings = mappings } as t) start size arr =
243 let order = List.length mappings in
244 let mapping = { start = start; size = size; arr = arr; order = order } in
245 let mappings = mapping :: mappings in
246 let tree = tree_of_mappings mappings in
247 { t with mappings = mappings; tree = tree }
249 let add_file t fd addr =
250 let size = (fstat fd).st_size in
251 (* mmap(2) the file using Bigarray module. *)
252 let arr = Array1.map_file fd char c_layout false size in
253 (* Create the mapping entry. *)
254 add_mapping t addr (Int64.of_int size) arr
256 let add_string ({ mappings = mappings } as t) str addr =
257 let size = String.length str in
258 (* Copy the string data to a Bigarray. *)
259 let arr = Array1.create char c_layout size in
260 for i = 0 to size-1 do
261 Array1.set arr i (String.unsafe_get str i)
263 (* Create the mapping entry. *)
264 add_mapping t addr (Int64.of_int size) arr
266 let of_file fd addr =
270 let of_string str addr =
272 add_string t str addr
274 (* 'get_mapping' is the crucial, fast lookup function for address -> mapping.
275 * It searches the tree (hence fast) to work out the topmost mapping which
276 * applies to an address.
278 * Returns (rightend * mapping option)
279 * where 'mapping option' is the mapping (or None if it's a hole)
280 * and 'rightend' is the next address at which there is a different
281 * mapping/hole. In other words, this mapping result is good for
282 * addresses [addr .. rightend-1].
284 let rec get_mapping addr = function
285 | Leaf ((_, rightend), mapping) -> rightend, mapping
287 | Node ((Leaf ((_, leftend), _) | Node (_, ((_, leftend), _), _) as left),
290 let subrightend, submapping =
291 if addr < leftend then get_mapping addr left
292 else get_mapping addr right in
293 subrightend, submapping
295 | Node ((Leaf ((_, leftend), _) | Node (_, ((_, leftend), _), _) as left),
298 let subrightend, submapping =
299 if addr < leftend then get_mapping addr left
300 else get_mapping addr right in
301 (match submapping with
302 | None -> subrightend, Some mapping
305 Some (if mapping.order > submapping.order then mapping
309 (* Use the tree to quickly check if an address is mapped (returns false
312 let is_mapped { mappings = mappings; tree = tree } addr =
313 (* NB: No [`HasMapping] in the type so we have to check mappings <> []. *)
317 let _, mapping = get_mapping addr tree in
320 (* Get a single byte. *)
321 let get_byte { tree = tree } addr =
322 (* Get the mapping which applies to this address: *)
323 let _, mapping = get_mapping addr tree in
325 | Some { start = start; size = size; arr = arr } ->
326 let offset = Int64.to_int (addr -^ start) in
327 Char.code (Array1.get arr offset)
329 invalid_arg "get_byte"
331 (* Get a range of bytes, possibly across several intervals. *)
332 let get_bytes { tree = tree } addr len =
333 let str = String.create len in
335 let rec loop addr pos len =
337 let rightend, mapping = get_mapping addr tree in
339 | Some { start = start; size = size; arr = arr } ->
340 (* Offset within this mapping. *)
341 let offset = Int64.to_int (addr -^ start) in
342 (* Number of bytes to read before we either get to the end
343 * of our 'len' or we fall off the end of this interval.
345 let n = min len (Int64.to_int (rightend -^ addr)) in
347 String.unsafe_set str (pos + i) (Array1.get arr (offset + i))
350 loop (addr +^ Int64.of_int n) (pos + n) len
353 invalid_arg "get_bytes"
360 let get_int32 t addr =
361 let e = get_endian t in
362 let str = get_bytes t addr 4 in
363 let bs = Bitstring.bitstring_of_string str in
365 | { addr : 32 : endian (e) } -> addr
366 | { _ } -> invalid_arg "get_int32"
368 let get_int64 t addr =
369 let e = get_endian t in
370 let str = get_bytes t addr 8 in
371 let bs = Bitstring.bitstring_of_string str in
373 | { addr : 64 : endian (e) } -> addr
374 | { _ } -> invalid_arg "get_int64"
376 let get_C_int = get_int32
378 let get_C_long t addr =
379 let ws = get_wordsize t in
381 | W32 -> Int64.of_int32 (get_int32 t addr)
382 | W64 -> get_int64 t addr
384 (* Take bytes until a condition is not met. This is efficient
385 * in that we stay within the same mapping as long as we can.
387 * If we hit a hole, raises Invalid_argument "dowhile".
389 let dowhile { tree = tree } addr cond =
391 let rightend, mapping = get_mapping addr tree in
393 | Some { start = start; size = size; arr = arr } ->
394 (* Offset within this mapping. *)
395 let offset = Int64.to_int (addr -^ start) in
396 (* Number of bytes before we fall off the end of this interval. *)
397 let n = Int64.to_int (rightend -^ addr) in
399 let rec loop2 addr offset n =
401 let c = Array1.get arr offset in
403 loop2 (addr +^ 1L) (offset + 1) (n - 1)
405 false (* stop now, finish outer loop too *)
407 else true (* fell off the end, so continue outer loop *)
409 if loop2 addr offset n then
410 loop (addr +^ Int64.of_int n)
413 invalid_arg "dowhile"
417 let is_mapped_range ({ mappings = mappings } as t) addr size =
419 (* NB: No [`HasMapping] in the type so we have to check mappings <> []. *)
422 (* Quick and dirty. It's possible to make a much faster
423 * implementation of this which doesn't call the closure for every
426 let size = ref size in
427 try dowhile t addr (fun _ _ -> decr size; !size > 0); true
428 with Invalid_argument "dowhile" -> false
430 (* Get a string, ending at ASCII NUL character. *)
431 let get_string t addr =
432 let chars = ref [] in
436 if c <> '\000' then (
437 chars := c :: !chars;
441 let chars = List.rev !chars in
442 let len = List.length chars in
443 let str = String.create len in
445 List.iter (fun c -> String.unsafe_set str !i c; incr i) chars;
448 Invalid_argument _ -> invalid_arg "get_string"
450 let is_string t addr =
451 try dowhile t addr (fun _ c -> c <> '\000'); true
452 with Invalid_argument _ -> false
454 let is_C_identifier t addr =
462 c = '_' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
464 if c = '\000' then false
466 if c = '_' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' ||
467 c >= '0' && c <= '9' then
480 Invalid_argument _ -> false
482 (* The following functions are actually written in C
483 * because memmem(3) is likely to be much faster than anything
484 * we could write in OCaml.
486 * Also OCaml bigarrays are specifically designed to be accessed
488 * http://caml.inria.fr/pub/docs/manual-ocaml/manual043.html
491 (* Array+offset = string? *)
492 let string_at arr offset str strlen =
493 let j = ref offset in
495 if i >= strlen then true
497 if Array1.get arr !j <> str.[i] then false
505 (* Find in a single file mapping.
506 * [start] is relative to the mapping and we return an offset relative
509 let _find_in start align str arr =
510 let strlen = String.length str in
513 let e = Array1.dim arr - strlen in
516 if string_at arr !j str strlen then Some !j
529 int -> int -> string -> (char,int8_unsigned_elt,c_layout) Array1.t ->
530 int option = "virt_mem_mmap_find_in"
532 (* Generic find function. *)
533 let _find { tree = tree } start align str =
535 let rightend, mapping = get_mapping addr tree in
537 | Some { start = start; size = size; arr = arr } ->
538 (* Offset within this mapping. *)
539 let offset = Int64.to_int (addr -^ start) in
541 (match _find_in offset align str arr with
543 | Some offset -> Some (start +^ Int64.of_int offset)
547 (* Find functions all silently skip holes, so: *)
552 let find t ?(start=0L) str =
555 let find_align t ?(start=0L) str =
556 let align = bytes_of_wordsize (get_wordsize t) in
557 _find t start align str
559 let rec _find_all t start align str =
560 match _find t start align str with
563 offset :: _find_all t (offset +^ Int64.of_int align) align str
565 let find_all t ?(start=0L) str =
566 _find_all t start 1 str
568 let find_all_align t ?(start=0L) str =
569 let align = bytes_of_wordsize (get_wordsize t) in
570 _find_all t start align str
572 (* NB: Phantom types in the interface ensure that these pointer functions
573 * can only be called once endianness and wordsize have both been set.
576 let rec find_pointer t ?start addr =
577 find_align t ?start (string_of_addr t addr)
579 and find_pointer_all t ?start addr =
580 find_all_align t ?start (string_of_addr t addr)
583 and string_of_addr t addr =
584 let bits = bits_of_wordsize (get_wordsize t) in
585 let e = get_endian t in
586 let bs = BITSTRING { addr : bits : endian (e) } in
587 Bitstring.string_of_bitstring bs
589 (* XXX bitstring is missing 'construct_int64_le_unsigned' so we
590 * have to force this to 32 bits for the moment.
592 and string_of_addr t addr =
593 let bits = bits_of_wordsize (get_wordsize t) in
595 let e = get_endian t in
596 let bs = BITSTRING { Int64.to_int32 addr : 32 : endian (e) } in
597 Bitstring.string_of_bitstring bs
599 let follow_pointer t addr =
600 let ws = get_wordsize t in
601 let e = get_endian t in
602 let bits = bits_of_wordsize ws in
603 let str = get_bytes t addr (bytes_of_wordsize ws) in
604 let bs = Bitstring.bitstring_of_string str in
606 | { addr : bits : endian (e) } -> addr
607 | { _ } -> invalid_arg "follow_pointer"
609 let succ_long t addr =
610 let ws = get_wordsize t in
611 addr +^ Int64.of_int (bytes_of_wordsize ws)
613 let pred_long t addr =
614 let ws = get_wordsize t in
615 addr -^ Int64.of_int (bytes_of_wordsize ws)
618 let ws = get_wordsize t in
619 let mask = Int64.of_int (bytes_of_wordsize ws - 1) in
620 (addr +^ mask) &^ (Int64.lognot mask)