From 25e5c025746a9ea2fcde20aae1684aab04ae55e1 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 1 Jan 1970 00:00:00 +0000 Subject: [PATCH] Add list_head helper library. - Reimplement virt_mem_tasks using this library. --- MANIFEST | 2 ++ lib/.depend | 15 +++++--- lib/Makefile.in | 1 + lib/virt_mem_list_head.ml | 89 ++++++++++++++++++++++++++++++++++++++++++++++ lib/virt_mem_list_head.mli | 73 +++++++++++++++++++++++++++++++++++++ lib/virt_mem_tasks.ml | 43 +++++++++------------- 6 files changed, 192 insertions(+), 31 deletions(-) create mode 100644 lib/virt_mem_list_head.ml create mode 100644 lib/virt_mem_list_head.mli diff --git a/MANIFEST b/MANIFEST index 5c95026..8ec273c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -33,6 +33,8 @@ lib/virt_mem_kallsyms.mli 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 diff --git a/lib/.depend b/lib/.depend index 6262905..a740b52 100644 --- a/lib/.depend +++ b/lib/.depend @@ -3,6 +3,7 @@ kernel_net.cmi: virt_mem_types.cmi virt_mem_mmap.cmi 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 @@ -37,6 +38,10 @@ virt_mem_ksyms.cmo: virt_mem_utils.cmo virt_mem_types.cmi virt_mem_mmap.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 \ @@ -53,10 +58,12 @@ virt_mem_net_devices.cmo: virt_mem_utils.cmo virt_mem_types.cmi \ 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 \ diff --git a/lib/Makefile.in b/lib/Makefile.in index b1f09d2..ee50a4c 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -54,6 +54,7 @@ OBJS = virt_mem_gettext.cmo \ 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 \ diff --git a/lib/virt_mem_list_head.ml b/lib/virt_mem_list_head.ml new file mode 100644 index 0000000..de16a16 --- /dev/null +++ b/lib/virt_mem_list_head.ml @@ -0,0 +1,89 @@ +(* 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)) diff --git a/lib/virt_mem_list_head.mli b/lib/virt_mem_list_head.mli new file mode 100644 index 0000000..3bf4246 --- /dev/null +++ b/lib/virt_mem_list_head.mli @@ -0,0 +1,73 @@ +(** 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. + *) diff --git a/lib/virt_mem_tasks.ml b/lib/virt_mem_tasks.ml index c2ae54e..b75a711 100644 --- a/lib/virt_mem_tasks.ml +++ b/lib/virt_mem_tasks.ml @@ -36,7 +36,7 @@ supported Linux distribution, see this page about adding support: 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) @@ -47,33 +47,22 @@ supported Linux distribution, see this page about adding support: 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 ( -- 1.8.3.1