X-Git-Url: http://git.annexia.org/?p=virt-mem.git;a=blobdiff_plain;f=lib%2Fvirt_mem.ml;h=8a835ec2427a525f446664f8716e6a81109bd509;hp=82e0b37e820e7f1a7f389685d0fb92cf46201cf8;hb=cb0cb33ae593436fd984c105cf5682155704e39f;hpb=5ce06c3326a2672e82dc656b35eb7a3e6616539a diff --git a/lib/virt_mem.ml b/lib/virt_mem.ml index 82e0b37..8a835ec 100644 --- a/lib/virt_mem.ml +++ b/lib/virt_mem.ml @@ -1,4 +1,4 @@ -(* Memory info command for virtual domains. +(* Memory info for virtual domains. (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc. http://libvirt.org/ @@ -21,11 +21,19 @@ open Unix open Printf open ExtList +open Virt_mem_gettext.Gettext open Virt_mem_utils module MMap = Virt_mem_mmap -(* Main program. *) -let () = +type ksym = string + +type image = + string + * Virt_mem_utils.architecture + * ([`Wordsize], [`Endian]) Virt_mem_mmap.t + * (ksym -> Virt_mem_mmap.addr) + +let start usage_msg = (* Verbose messages. *) let verbose = ref false in @@ -35,7 +43,7 @@ let () = | "32" -> def_wordsize := Some W32 | "64" -> def_wordsize := Some W64 | "auto" -> def_wordsize := None - | str -> failwith (sprintf "set_wordsize: %s: unknown wordsize" str) + | str -> failwith (sprintf (f_"set_wordsize: %s: unknown wordsize") str) in (* Default endianness. *) @@ -46,7 +54,7 @@ let () = def_endian := Some Bitmatch.LittleEndian | "be" | "big" | "bigendian" | "motorola" -> def_endian := Some Bitmatch.BigEndian - | str -> failwith (sprintf "set_endian: %s: unknown endianness" str) + | str -> failwith (sprintf (f_"set_endian: %s: unknown endianness") str) in (* Default architecture. *) @@ -80,28 +88,22 @@ let () = let argspec = Arg.align [ "-A", Arg.String set_architecture, - "arch " ^ "Set kernel architecture, endianness and word size"; + "arch " ^ s_"Set kernel architecture, endianness and word size"; "-E", Arg.String set_endian, - "endian " ^ "Set kernel endianness"; + "endian " ^ s_"Set kernel endianness"; "-T", Arg.String set_text_addr, - "addr " ^ "Set kernel text address"; + "addr " ^ s_"Set kernel text address"; "-W", Arg.String set_wordsize, - "addr " ^ "Set kernel word size"; + "addr " ^ s_"Set kernel word size"; "-t", Arg.String memory_image, - "image " ^ "Use saved kernel memory image"; + "image " ^ s_"Use saved kernel memory image"; "-verbose", Arg.Set verbose, - " " ^ "Verbose messages"; + " " ^ s_"Verbose messages"; ] in let anon_fun str = - raise (Arg.Bad (sprintf "%s: unknown parameter" str)) in - let usage_msg = "virt-mem: shows memory information for guests - -SUMMARY - virt-mem [-options] - -OPTIONS" in - + raise (Arg.Bad (sprintf (f_"%s: unknown parameter") str)) in + let usage_msg = usage_msg ^ s_"\n\nOPTIONS" in Arg.parse argspec anon_fun usage_msg; let images = !images in @@ -123,14 +125,14 @@ OPTIONS" in match wordsize with | None -> failwith - (sprintf "%s: use -W to define word size for this image" + (sprintf (f_"%s: use -W to define word size for this image") filename); | Some ws -> ws in let endian = match endian with | None -> failwith - (sprintf "%s: use -E to define endianness for this image" + (sprintf (f_"%s: use -E to define endianness for this image") filename); | Some e -> e in @@ -139,11 +141,11 @@ OPTIONS" in | Some I386 -> I386 | Some X86_64 -> X86_64 | _ -> failwith - (sprintf "%s: use -A to define architecture (i386/x86-64 only) for this image" filename) in + (sprintf (f_"%s: use -A to define architecture (i386/x86-64 only) for this image") filename) in if text_addr = 0L then failwith - (sprintf "%s: use -T to define kernel load address for this image" + (sprintf (f_"%s: use -T to define kernel load address for this image") filename); (* Map the virtual memory. *) @@ -154,159 +156,155 @@ OPTIONS" in let mem = MMap.set_wordsize mem wordsize in let mem = MMap.set_endian mem endian in - (filename, (arch, mem)) + (filename, arch, mem) ) images in - List.iter ( - fun (name, (arch, mem)) -> - (* Look for some common entries in the symbol table and from - * that find the symbol table itself. These are just supposed to - * be symbols which are very likely to be present in any Linux - * kernel, although we only need one of them to be present to - * find the symbol table. - * - * NB. Must not be __initdata. - *) - let common_ksyms = [ - "init_task"; (* first task_struct *) - "root_mountflags"; (* flags for mounting root fs *) - "init_uts_ns"; (* uname strings *) - "sys_open"; (* open(2) entry point *) - "sys_chdir"; (* chdir(2) entry point *) - "sys_chroot"; (* chroot(2) entry point *) - "sys_umask"; (* umask(2) entry point *) - "schedule"; (* scheduler entry point *) - ] in - (* Searching for string *) - let common_ksyms = List.map (sprintf "\000%s\000") common_ksyms in - - (* Search for these strings in the memory image. *) - let ksym_strings = List.map (MMap.find_all mem) common_ksyms in - let ksym_strings = List.concat ksym_strings in - (* Adjust found addresses to start of the string (skip ). *) - let ksym_strings = List.map Int64.succ ksym_strings in - - (* For any we found, try to look up the symbol table - * base addr and size. - *) - let ksymtabs = List.map ( - fun addr -> - (* Search for 'addr' appearing in the image. *) - let addrs = MMap.find_pointer_all mem addr in - - (* Now consider each of these addresses and search back - * until we reach the beginning of the (possible) symbol - * table. - * - * Kernel symbol table struct is: - * struct kernel_symbol { - * unsigned long value; - * const char *name; <-- initial pointer - * } symbols[]; - *) - let pred_long2 addr = MMap.pred_long mem (MMap.pred_long mem addr) in - let base_addrs = List.map ( - fun addr -> - let rec loop addr = - (* '*addr' should point to a C identifier. If it does, - * step backwards to the previous symbol table entry. - *) - let addrp = MMap.follow_pointer mem addr in - if MMap.is_C_identifier mem addrp then - loop (pred_long2 addr) - else - MMap.succ_long mem addr + let images = + List.map ( + fun (name, arch, mem) -> + (* Look for some common entries in the symbol table and from + * that find the symbol table itself. These are just supposed to + * be symbols which are very likely to be present in any Linux + * kernel, although we only need one of them to be present to + * find the symbol table. + * + * NB. Must not be __initdata. + *) + let common_ksyms = [ + "init_task"; (* first task_struct *) + "root_mountflags"; (* flags for mounting root fs *) + "init_uts_ns"; (* uname strings *) + "sys_open"; (* open(2) entry point *) + "sys_chdir"; (* chdir(2) entry point *) + "sys_chroot"; (* chroot(2) entry point *) + "sys_umask"; (* umask(2) entry point *) + "schedule"; (* scheduler entry point *) + ] in + (* Searching for string *) + let common_ksyms = List.map (sprintf "\000%s\000") common_ksyms in + + (* Search for these strings in the memory image. *) + let ksym_strings = List.map (MMap.find_all mem) common_ksyms in + let ksym_strings = List.concat ksym_strings in + (* Adjust found addresses to start of the string (skip ). *) + let ksym_strings = List.map Int64.succ ksym_strings in + + (* For any we found, try to look up the symbol table + * base addr and size. + *) + let ksymtabs = List.map ( + fun addr -> + (* Search for 'addr' appearing in the image. *) + let addrs = MMap.find_pointer_all mem addr in + + (* Now consider each of these addresses and search back + * until we reach the beginning of the (possible) symbol + * table. + * + * Kernel symbol table struct is: + * struct kernel_symbol { + * unsigned long value; + * const char *name; <-- initial pointer + * } symbols[]; + *) + let pred_long2 addr = + MMap.pred_long mem (MMap.pred_long mem addr) + in + let base_addrs = List.map ( + fun addr -> + let rec loop addr = + (* '*addr' should point to a C identifier. If it does, + * step backwards to the previous symbol table entry. + *) + let addrp = MMap.follow_pointer mem addr in + if MMap.is_C_identifier mem addrp then + loop (pred_long2 addr) + else + MMap.succ_long mem addr + in + loop addr + ) addrs in + + (* Also look for the end of the symbol table and + * calculate its size. + *) + let base_addrs_sizes = List.map ( + fun base_addr -> + let rec loop addr = + let addr2 = MMap.succ_long mem addr in + let addr2p = MMap.follow_pointer mem addr2 in + if MMap.is_C_identifier mem addr2p then + loop (MMap.succ_long mem addr2) + else + addr + in + let end_addr = loop base_addr in + base_addr, end_addr -^ base_addr + ) base_addrs in + + base_addrs_sizes + ) ksym_strings in + let ksymtabs = List.concat ksymtabs in + + (* Simply ignore any symbol table candidates which are too small. *) + let ksymtabs = List.filter (fun (_, size) -> size > 64L) ksymtabs in + + if verbose then ( + printf "name %s:\n" name; + List.iter ( + fun (addr, size) -> + printf "\t%Lx\t%Lx\t%!" addr size; + printf "first symbol: %s\n%!" + (MMap.get_string mem + (MMap.follow_pointer mem + (MMap.succ_long mem addr))) + ) ksymtabs + ); + + (* Vote for the most popular symbol table candidate and from this + * generate a function to look up ksyms. + *) + let lookup_ksym = + let freqs = frequency ksymtabs in + match freqs with + | [] -> + eprintf (f_"%s: cannot find start of kernel symbol table\n") name; + (fun _ -> raise Not_found) + + | (_, (ksymtab_addr, ksymtab_size)) :: _ -> + if verbose then + printf + "%s: Kernel symbol table found at %Lx, size %Lx bytes\n%!" + name ksymtab_addr ksymtab_size; + + (* Load the whole symbol table as a bitstring. *) + let ksymtab = + Bitmatch.bitstring_of_string + (MMap.get_bytes mem ksymtab_addr + (Int64.to_int ksymtab_size)) in + + (* Function to look up an address in the symbol table. *) + let lookup_ksym sym = + let bits = bits_of_wordsize (MMap.get_wordsize mem) in + let e = MMap.get_endian mem in + let rec loop bs = + bitmatch bs with + | { value : bits : endian(e); + name_ptr : bits : endian(e) } + when MMap.get_string mem name_ptr = sym -> + value + | { _ : bits : endian(e); + _ : bits : endian(e); + bs : -1 : bitstring } -> + loop bs + | { _ } -> raise Not_found + in + loop ksymtab in - loop addr - ) addrs in - (* Also look for the end of the symbol table and - * calculate its size. - *) - let base_addrs_sizes = List.map ( - fun base_addr -> - let rec loop addr = - let addr2 = MMap.succ_long mem addr in - let addr2p = MMap.follow_pointer mem addr2 in - if MMap.is_C_identifier mem addr2p then - loop (MMap.succ_long mem addr2) - else - addr - in - let end_addr = loop base_addr in - base_addr, end_addr -^ base_addr - ) base_addrs in - - base_addrs_sizes - ) ksym_strings in - let ksymtabs = List.concat ksymtabs in - - (* Simply ignore any symbol table candidates which are too small. *) - let ksymtabs = List.filter (fun (_, size) -> size > 64L) ksymtabs in - - if verbose then ( - printf "name %s:\n" name; - List.iter ( - fun (addr, size) -> - printf "\t%Lx\t%Lx\t%!" addr size; - printf "first symbol: %s\n%!" - (MMap.get_string mem - (MMap.follow_pointer mem - (MMap.succ_long mem addr))) - ) ksymtabs - ); - - (* Vote for the most popular symbol table candidate. *) - let freqs = frequency ksymtabs in - match freqs with - | [] -> - eprintf "%s: cannot find start of kernel symbol table\n" name - | (_, (ksymtab_addr, ksymtab_size)) :: _ -> - if verbose then - printf "%s: Kernel symbol table found at %Lx, size %Lx bytes\n%!" - name ksymtab_addr ksymtab_size; - - (* Load the whole symbol table as a bitstring. *) - let ksymtab = - Bitmatch.bitstring_of_string - (MMap.get_bytes mem ksymtab_addr (Int64.to_int ksymtab_size)) in - - (* Function to look up an address in the symbol table. *) - let lookup_ksym sym = - let bits = bits_of_wordsize (MMap.get_wordsize mem) in - let e = MMap.get_endian mem in - let rec loop bs = - bitmatch bs with - | { value : bits : endian(e); - name_ptr : bits : endian(e) } - when MMap.get_string mem name_ptr = sym -> - value - | { _ : bits : endian(e); - _ : bits : endian(e); - bs : -1 : bitstring } -> - loop bs - | { _ } -> raise Not_found - in - loop ksymtab - in - - if verbose then ( - (* This just tests looking up kernel symbols. *) - printf "init_task = %Lx\n" (lookup_ksym "init_task"); - printf "schedule = %Lx\n" (lookup_ksym "schedule"); - printf "system_utsname = %s\n" - (try - let addr = lookup_ksym "system_utsname" in - sprintf "%Lx" addr - with Not_found -> "not found"); - printf "init_uts_ns = %s\n" - (try - let addr = lookup_ksym "init_uts_ns" in - sprintf "%Lx" addr - with Not_found -> "not found"); - ); - - - - - ) images + lookup_ksym + in + ((name, arch, mem, lookup_ksym) : image) + ) images in + + verbose, images