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.
28 (* Simple implementation at the moment: Store a list of mappings,
29 * sorted by start address. We assume that mappings do not overlap.
30 * We can change the implementation later if we need to. In most cases
31 * there will only be a small number of mappings (probably 1).
34 mappings : mapping list;
35 wordsize : wordsize option;
36 endian : Bitmatch.endian option;
41 (* Bigarray mmap(2)'d region with byte addressing: *)
42 arr : (char,int8_unsigned_elt,c_layout) Array1.t;
53 let set_wordsize t ws = { t with wordsize = Some ws }
55 let set_endian t e = { t with endian = Some e }
57 let get_wordsize t = Option.get t.wordsize
59 let get_endian t = Option.get t.endian
61 let sort_mappings mappings =
62 let cmp { start = s1 } { start = s2 } = compare s1 s2 in
63 List.sort cmp mappings
65 let add_file ({ mappings = mappings } as t) fd addr =
66 if addr &^ 7L <> 0L then
67 invalid_arg "add_file: mapping address must be aligned to 8 bytes";
68 let size = (fstat fd).st_size in
69 (* mmap(2) the file using Bigarray module. *)
70 let arr = Array1.map_file fd char c_layout false size in
71 (* Create the mapping entry and keep the mappings sorted by start addr. *)
73 { start = addr; size = Int64.of_int size; arr = arr } :: mappings in
74 let mappings = sort_mappings mappings in
75 { t with mappings = mappings }
81 let add_string ({ mappings = mappings } as t) str addr =
82 if addr &^ 7L <> 0L then
83 invalid_arg "add_file: mapping address must be aligned to 8 bytes";
84 let size = String.length str in
85 (* Use Bigarray.Array1. XXX We should just use the string. *)
86 let arr = Array1.create char c_layout size in
87 for i = 0 to size-1 do
88 Array1.set arr i (String.unsafe_get str i)
90 (* Create the mapping entry and keep the mappings sorted by start addr. *)
92 { start = addr; size = Int64.of_int size; arr = arr } :: mappings in
93 let mappings = sort_mappings mappings in
94 { t with mappings = mappings }
96 let of_string str addr =
100 (* Find in mappings and return first predicate match. *)
101 let _find_map { mappings = mappings } pred =
102 let rec loop = function
111 (* Array+offset = string? *)
112 let string_at arr offset str strlen =
113 let j = ref offset in
115 if i >= strlen then true
117 if Array1.get arr !j <> str.[i] then false
125 (* Find in a single file mapping.
126 * [start] is relative to the mapping and we return an offset relative
129 let _find_in start align str arr =
130 let strlen = String.length str in
133 let e = Array1.dim arr - strlen in
136 if string_at arr !j str strlen then Some !j
148 (* Generic find function. *)
149 let _find t start align str =
151 fun { start = mstart; size = msize; arr = arr } ->
152 if mstart >= start then (
153 (* Check this mapping from the beginning. *)
154 match _find_in 0 align str arr with
155 | Some offset -> Some (mstart +^ Int64.of_int offset)
158 else if mstart < start && start <= mstart+^msize then (
159 (* Check this mapping from somewhere in the middle. *)
160 let offset = Int64.to_int (start -^ mstart) in
161 match _find_in offset align str arr with
162 | Some offset -> Some (mstart +^ Int64.of_int offset)
168 let find t ?(start=0L) str =
171 let find_align t ?(start=0L) str =
172 let align = bytes_of_wordsize (get_wordsize t) in
173 _find t start align str
175 let rec _find_all t start align str =
176 match _find t start align str with
179 offset :: _find_all t (offset +^ Int64.of_int align) align str
181 let find_all t ?(start=0L) str =
182 _find_all t start 1 str
184 let find_all_align t ?(start=0L) str =
185 let align = bytes_of_wordsize (get_wordsize t) in
186 _find_all t start align str
188 (* NB: Phantom types in the interface ensure that these pointer functions
189 * can only be called once endianness and wordsize have both been set.
192 let rec find_pointer t ?start addr =
193 find_align t ?start (string_of_addr t addr)
195 and find_pointer_all t ?start addr =
196 find_all_align t ?start (string_of_addr t addr)
199 and string_of_addr t addr =
200 let bits = bits_of_wordsize (get_wordsize t) in
201 let e = get_endian t in
202 let bs = BITSTRING { addr : bits : endian (e) } in
203 Bitmatch.string_of_bitstring bs
205 (* XXX bitmatch is missing 'construct_int64_le_unsigned' so we
206 * have to force this to 32 bits for the moment.
208 and string_of_addr t addr =
209 let bits = bits_of_wordsize (get_wordsize t) in
211 let e = get_endian t in
212 let bs = BITSTRING { Int64.to_int32 addr : 32 : endian (e) } in
213 Bitmatch.string_of_bitstring bs
215 and addr_of_string t str =
216 let bits = bits_of_wordsize (get_wordsize t) in
217 let e = get_endian t in
218 let bs = Bitmatch.bitstring_of_string str in
220 | { addr : bits : endian (e) } -> addr
221 | { _ } -> invalid_arg "addr_of_string"
223 let get_byte { mappings = mappings } addr =
224 let rec loop = function
225 | [] -> invalid_arg "get_byte"
226 | { start = start; size = size; arr = arr } :: _
227 when start <= addr && addr < start +^ size ->
228 let offset = Int64.to_int (addr -^ start) in
229 Char.code (Array1.get arr offset)
234 (* Take bytes until a condition is not met. This is efficient in that
235 * we stay within the same mapping as long as we can.
237 let dowhile { mappings = mappings } addr cond =
238 let rec get_next_mapping addr = function
239 | [] -> invalid_arg "dowhile"
240 | { start = start; size = size; arr = arr } :: _
241 when start <= addr && addr < start +^ size ->
242 let offset = Int64.to_int (addr -^ start) in
243 let len = Int64.to_int size - offset in
245 | _ :: ms -> get_next_mapping addr ms
248 let arr, offset, len = get_next_mapping addr mappings in
251 let c = Array1.get arr (offset+i) in
252 if cond c then loop2 (i+1)
254 loop (addr +^ Int64.of_int len)
260 let get_bytes t addr len =
261 let str = String.create len in
272 Invalid_argument _ -> invalid_arg "get_bytes"
274 let get_int32 t addr =
275 let e = get_endian t in
276 let str = get_bytes t addr 4 in
277 let bs = Bitmatch.bitstring_of_string str in
279 | { addr : 32 : endian (e) } -> addr
280 | { _ } -> invalid_arg "follow_pointer"
282 let get_int64 t addr =
283 let e = get_endian t in
284 let str = get_bytes t addr 8 in
285 let bs = Bitmatch.bitstring_of_string str in
287 | { addr : 64 : endian (e) } -> addr
288 | { _ } -> invalid_arg "follow_pointer"
290 let get_C_int = get_int32
292 let get_C_long t addr =
293 let ws = get_wordsize t in
295 | W32 -> Int64.of_int32 (get_int32 t addr)
296 | W64 -> get_int64 t addr
298 let get_string t addr =
299 let chars = ref [] in
303 if c <> '\000' then (
304 chars := c :: !chars;
308 let chars = List.rev !chars in
309 let len = List.length chars in
310 let str = String.create len in
312 List.iter (fun c -> str.[!i] <- c; incr i) chars;
315 Invalid_argument _ -> invalid_arg "get_string"
317 let is_string t addr =
318 try dowhile t addr (fun c -> c <> '\000'); true
319 with Invalid_argument _ -> false
321 let is_C_identifier t addr =
329 c = '_' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
331 if c = '\000' then false
333 if c = '_' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' ||
334 c >= '0' && c <= '9' then
347 Invalid_argument _ -> false
349 let is_mapped { mappings = mappings } addr =
350 let rec loop = function
352 | { start = start; size = size; arr = arr } :: _
353 when start <= addr && addr < start +^ size -> true
358 let follow_pointer t addr =
359 let ws = get_wordsize t in
360 let e = get_endian t in
361 let bits = bits_of_wordsize ws in
362 let str = get_bytes t addr (bytes_of_wordsize ws) in
363 let bs = Bitmatch.bitstring_of_string str in
365 | { addr : bits : endian (e) } -> addr
366 | { _ } -> invalid_arg "follow_pointer"
368 let succ_long t addr =
369 let ws = get_wordsize t in
370 addr +^ Int64.of_int (bytes_of_wordsize ws)
372 let pred_long t addr =
373 let ws = get_wordsize t in
374 addr -^ Int64.of_int (bytes_of_wordsize ws)
377 let ws = get_wordsize t in
378 let mask = Int64.of_int (bytes_of_wordsize ws - 1) in
379 (addr +^ mask) &^ (Int64.lognot mask)