- Reimplement virt_mem_tasks using this library.
lib/virt_mem_kernels.ml
lib/virt_mem_ksyms.ml
lib/virt_mem_ksyms.mli
+lib/virt_mem_list_head.ml
+lib/virt_mem_list_head.mli
lib/virt_mem.ml
lib/virt_mem.mli
lib/virt_mem_mmap.ml
kernel_task_struct.cmi: virt_mem_types.cmi virt_mem_mmap.cmi
virt_mem_kallsyms.cmi: virt_mem_types.cmi
virt_mem_ksyms.cmi: virt_mem_types.cmi
+virt_mem_list_head.cmi: virt_mem_types.cmi virt_mem_mmap.cmi
virt_mem.cmi: virt_mem_types.cmi
virt_mem_mmap.cmi: virt_mem_utils.cmo
virt_mem_net_devices.cmi: virt_mem_types.cmi
virt_mem_gettext.cmo virt_mem_ksyms.cmi
virt_mem_ksyms.cmx: virt_mem_utils.cmx virt_mem_types.cmx virt_mem_mmap.cmx \
virt_mem_gettext.cmx virt_mem_ksyms.cmi
+virt_mem_list_head.cmo: virt_mem_utils.cmo virt_mem_types.cmi \
+ virt_mem_mmap.cmi virt_mem_list_head.cmi
+virt_mem_list_head.cmx: virt_mem_utils.cmx virt_mem_types.cmx \
+ virt_mem_mmap.cmx virt_mem_list_head.cmi
virt_mem.cmo: virt_mem_version.cmo virt_mem_utsname.cmi virt_mem_utils.cmo \
virt_mem_types.cmi virt_mem_tasks.cmi virt_mem_net_devices.cmi \
virt_mem_mmap.cmi virt_mem_ksyms.cmi virt_mem_kernels.cmo \
virt_mem_net_devices.cmx: virt_mem_utils.cmx virt_mem_types.cmx \
virt_mem_mmap.cmx virt_mem_gettext.cmx kernel_net_device.cmx \
kernel_net.cmx virt_mem_net_devices.cmi
-virt_mem_tasks.cmo: virt_mem_utils.cmo virt_mem_types.cmi virt_mem_mmap.cmi \
- virt_mem_gettext.cmo kernel_task_struct.cmi virt_mem_tasks.cmi
-virt_mem_tasks.cmx: virt_mem_utils.cmx virt_mem_types.cmx virt_mem_mmap.cmx \
- virt_mem_gettext.cmx kernel_task_struct.cmx virt_mem_tasks.cmi
+virt_mem_tasks.cmo: virt_mem_utils.cmo virt_mem_types.cmi \
+ virt_mem_list_head.cmi virt_mem_gettext.cmo kernel_task_struct.cmi \
+ virt_mem_tasks.cmi
+virt_mem_tasks.cmx: virt_mem_utils.cmx virt_mem_types.cmx \
+ virt_mem_list_head.cmx virt_mem_gettext.cmx kernel_task_struct.cmx \
+ virt_mem_tasks.cmi
virt_mem_types.cmo: virt_mem_utils.cmo virt_mem_mmap.cmi virt_mem_types.cmi
virt_mem_types.cmx: virt_mem_utils.cmx virt_mem_mmap.cmx virt_mem_types.cmi
virt_mem_utsname.cmo: virt_mem_utils.cmo virt_mem_types.cmi virt_mem_mmap.cmi \
virt_mem_mmap_c.o \
virt_mem_mmap.cmo \
virt_mem_types.cmo \
+ virt_mem_list_head.cmo \
kernel_task_struct.cmo \
kernel_net_device.cmo \
kernel_net.cmo \
--- /dev/null
+(* Memory info command for virtual domains.
+ (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
+ http://libvirt.org/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *)
+
+(* This code will work provided list_head always contains just a
+ * 'next' and 'prev' pointer. If it changes, then we'll have to
+ * import the struct list_head from the kernel version, just like
+ * every other structure. (XXX)
+ *)
+
+open Printf
+
+open Virt_mem_utils
+open Virt_mem_types
+
+type t =
+ image (* Kernel image. *)
+ * int64 (* Pointer to start of head struct. *)
+ * int64 (* Offset. *)
+
+let create_base image head offset =
+ let offset = Int64.of_int offset in
+ (image, head, offset)
+
+let create image head offset =
+ let offset = Int64.of_int offset in
+ let head = head -^ offset in
+ (image, head, offset)
+
+let get_next_ptr image addr offset =
+ let addr = addr +^ offset in
+ let addr = Virt_mem_mmap.follow_pointer image.mem addr in
+ let addr = addr -^ offset in
+ addr
+
+let load (image, head, offset) f =
+ let rec loop image addr =
+ if addr <> head then (
+ let image = f image addr in
+ let addr = get_next_ptr image addr offset in
+ loop image addr
+ )
+ else image
+ in
+ let image = loop image (get_next_ptr image head offset) in
+ image, (image, head, offset)
+
+let load_all t size =
+ let f image addr =
+ let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
+ let image =
+ if not mapped then Virt_mem_types.load_memory image addr size
+ else image in
+ image
+ in
+ load t f
+
+let fold (image, head, offset) b f =
+ let rec loop b addr =
+ if addr <> head then (
+ let b = f b addr in
+ let addr = get_next_ptr image addr offset in
+ loop b addr
+ )
+ else b
+ in
+ loop b (get_next_ptr image head offset)
+
+(* Iter and map can be implemented in terms of fold. *)
+let iter t f =
+ fold t () (fun () addr -> let () = f addr in ())
+
+let map t f =
+ List.rev (fold t [] (fun xs addr -> let x = f addr in x :: xs))
--- /dev/null
+(** Handle struct list_head linked lists. *)
+(* Memory info command for virtual domains.
+ (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
+ http://libvirt.org/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *)
+
+type t
+
+val create : Virt_mem_types.image -> Virt_mem_mmap.addr -> int -> t
+ (** [create image head offset] creates a list_head handle.
+
+ [head] is the address of the base [list_head] in kernel memory.
+
+ [offset] is the offset of the [list_head] within the whole
+ structure.
+
+ Note that [head] may be an isolated [struct list_head] or
+ it may be a member of a structure. In the case where the
+ head is in a structure, the head structure is ignored (as is
+ generally the case in kernel code too).
+
+ If the memory might not have been loaded yet, you should
+ call {!load} or {!load_all} immediately after this.
+ *)
+
+val create_base : Virt_mem_types.image -> Virt_mem_mmap.addr -> int -> t
+ (** Same as {!create} but the address passed in is the base address
+ of the head structure {i not} the address of the list_head
+ within that structure.
+ *)
+
+val load : t ->
+ (Virt_mem_types.image -> Virt_mem_mmap.addr -> Virt_mem_types.image) ->
+ Virt_mem_types.image * t
+ (** This call allows you to load the kernel memory for each
+ structure in the list.
+
+ You supply a function to do the loading, given the
+ address of each structure in turn. This returns an
+ updated memory map and {!t}.
+ *)
+
+val load_all : t -> int -> Virt_mem_types.image * t
+ (** More convenient version of {!load} where you specify the
+ structure size, and this function does all the rest.
+ *)
+
+val iter : t -> (Virt_mem_mmap.addr -> unit) -> unit
+ (** [iter t f] applies function [f] to every element of the list [t]. *)
+
+val map : t -> (Virt_mem_mmap.addr -> 'a) -> 'a list
+ (** [map t f] applies function [f] to every element of the list [t] and
+ returns a list of the results.
+ *)
+
+val fold : t -> 'a -> ('a -> Virt_mem_mmap.addr -> 'a) -> 'a
+ (** [fold t b f] folds function [f] over every element of the list [t]
+ with [b] as the base case.
+ *)
image.domname kernel_version;
image, None
) else (
- let task_struct_size = task_struct_size kernel_version in
+ let size = task_struct_size kernel_version in
let init_task_addr =
try Some (Ksymmap.find "init_task" ksymmap)
match init_task_addr with
| None -> image, None
| Some init_task_addr ->
- let init_task =
- get_task_struct kernel_version image.mem init_task_addr in
+ let { field_offset = offset } =
+ field_signature_of_task_struct_tasks'next kernel_version in
- (* Starting at init_task, navigate through the linked list of
- * tasks (through tasks.next). Map them into memory and load
- * them into a list.
- *)
- let image, tasks =
- let rec loop i image acc task =
- if i <= max_tasks then (
- let next = task.task_struct_tasks'next in
- if next <> init_task_addr then (
- let mapped =
- Virt_mem_mmap.is_mapped_range image.mem next task_struct_size in
- let image =
- if not mapped then
- Virt_mem_types.load_memory image next task_struct_size
- else
- image in
- let task = get_task_struct kernel_version image.mem next in
- loop (i+1) image (task :: acc) task
- ) else
- image, acc
- ) else
- failwith (sprintf (f_"%s: too many tasks") image.domname)
- in
- loop 0 image [] init_task in
+ let lh = Virt_mem_list_head.create_base image init_task_addr offset in
+ let image, lh = Virt_mem_list_head.load_all lh size in
+
+ let tasks, _ =
+ Virt_mem_list_head.fold lh ([], 0) (
+ fun (tasks, i) addr ->
+ if i > max_tasks then
+ failwith (sprintf (f_"%s: too many tasks") image.domname);
+
+ let task = get_task_struct kernel_version image.mem addr in
+ let tasks = task :: tasks in
+ (tasks, i+1)
+ ) in
(* Convert to the internal format. *)
let tasks = List.rev_map (