(* 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. *) open Printf open Virt_mem_gettext.Gettext open Virt_mem_utils open Virt_mem_types open Kernel_net_device type linkage = Next | DevList of int let rec find_net_devices debug image ksymmap kernel_version = if not (net_device_known kernel_version) then ( eprintf (f_"%s: %s: unknown kernel version Try a newer version of virt-mem, or if the guest is not from a supported Linux distribution, see this page about adding support: http://et.redhat.com/~rjones/virt-mem/faq.html\n") image.domname kernel_version; image, None ) else ( let size = net_device_size kernel_version in (* In kernels < around 2.6.22, this is a simple linked list: * dev_base -> next -> next * In kernels >= 2.6.23, this is a list_head: * dev_base_head -> list_head dev_list -> ... *) let linkage = let { field_available = available } = field_signature_of_net_device_next kernel_version in if available then Some Next else ( let { field_available = available; field_offset = offset } = field_signature_of_net_device_dev_list'next kernel_version in if available then Some (DevList offset) else ( eprintf (f_"%s: kernel net_device table is not linked through either next pointer or dev_list list_head. Cannot read net devices.\n") image.domname; None ) ) in match linkage with | None -> image, None | Some Next -> printf "linkage = Next\n%!"; (* Linkage through old-style chain of next pointers. *) let dev_base = try Some (Ksymmap.find "dev_base" ksymmap) with Not_found -> eprintf (f_"%s: could not find dev_base symbol in kernel image\n") image.domname; None in (match dev_base with | None -> image, None | Some dev_base -> do_next image kernel_version dev_base size ); | Some (DevList offset) -> printf "linkage = DevList %d\n%!" offset; (* Linkage through new-style list_head dev_list. *) let dev_base_head = try Some (Ksymmap.find "dev_base_head" ksymmap) with Not_found -> eprintf (f_"%s: could not find dev_base_head symbol in kernel image\n") image.domname; None in (match dev_base_head with | None -> image, None | Some dev_base_head -> let dev_base_head = Virt_mem_mmap.follow_pointer image.mem dev_base_head in do_dev_list image kernel_version dev_base_head offset size ); ) (* Iterate dev_base_head -> list_head dev_list -> ... *) and do_dev_list image kernel_version dev_base_head offset size = (* The list_head points into the middle of the structure. * Adjust this address to point to the start of the * structure. *) let addr = Int64.sub dev_base_head (Int64.of_int offset) in printf "do_dev_list, size = %d\n" size; let image = let rec loop 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 let dev = get_net_device kernel_version image.mem addr in printf "net_device_name = %S\n" dev.net_device_name; let addr = Option.get dev.net_device_dev_list'next in if addr <> dev_base_head then loop image addr else image in loop image addr in image, Some dev_base_head (* Iterate dev_base -> next -> next ... *) and do_next image kernel_version addr size = printf "do_next, size = %d\n" size; let image = let rec loop image addr = if addr <> 0L then ( 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 let dev = get_net_device kernel_version image.mem addr in printf "net_device_name = %S\n" dev.net_device_name; let addr = match dev.net_device_next with | None -> assert false | Some addr -> addr in loop image addr ) else image in loop image addr in image, Some addr