From: Richard W.M. Jones <"Richard W.M. Jones "> Date: Tue, 3 Jun 2008 13:09:43 +0000 (+0100) Subject: Librarify the arg-parsing code. Added virt-uname command. X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=cb0cb33ae593436fd984c105cf5682155704e39f;p=virt-mem.git Librarify the arg-parsing code. Added virt-uname command. --- diff --git a/.hgignore b/.hgignore index 5512c6b..e54fcbe 100644 --- a/.hgignore +++ b/.hgignore @@ -19,3 +19,5 @@ config.status configure gmon.out lib/virt_mem_gettext.ml +uname/virt-uname +dmesg/virt-dmesg \ No newline at end of file diff --git a/lib/.depend b/lib/.depend index 8b11723..180057e 100644 --- a/lib/.depend +++ b/lib/.depend @@ -1,8 +1,9 @@ +virt_mem.cmi: virt_mem_utils.cmo virt_mem_mmap.cmi virt_mem_mmap.cmi: virt_mem_utils.cmo /usr/lib64/ocaml/bitmatch/bitmatch.cmi -virt_mem.cmo: virt_mem_utils.cmo virt_mem_mmap.cmi \ - /usr/lib64/ocaml/bitmatch/bitmatch.cmi -virt_mem.cmx: virt_mem_utils.cmx virt_mem_mmap.cmx \ - /usr/lib64/ocaml/bitmatch/bitmatch.cmi +virt_mem.cmo: virt_mem_utils.cmo virt_mem_mmap.cmi virt_mem_gettext.cmo \ + /usr/lib64/ocaml/bitmatch/bitmatch.cmi virt_mem.cmi +virt_mem.cmx: virt_mem_utils.cmx virt_mem_mmap.cmx virt_mem_gettext.cmx \ + /usr/lib64/ocaml/bitmatch/bitmatch.cmi virt_mem.cmi virt_mem_mmap.cmo: virt_mem_utils.cmo /usr/lib64/ocaml/bitmatch/bitmatch.cmi \ virt_mem_mmap.cmi virt_mem_mmap.cmx: virt_mem_utils.cmx /usr/lib64/ocaml/bitmatch/bitmatch.cmi \ 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 diff --git a/lib/virt_mem.mli b/lib/virt_mem.mli new file mode 100644 index 0000000..a0f1963 --- /dev/null +++ b/lib/virt_mem.mli @@ -0,0 +1,47 @@ +(* Memory info 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 ksym = string + (** A kernel symbol name. *) + +type image = + string + * Virt_mem_utils.architecture + * ([`Wordsize], [`Endian]) Virt_mem_mmap.t + * (ksym -> Virt_mem_mmap.addr) + (** An image after it has been processed by the code common to + all commands. + + The tuple fields are: + - name + - architecture (eg. I386) + - kernel memory map (wordsize & endianness already determined) + - a function to look up kernel symbols. It raises [Not_found] + if a kernel symbol could not be found or if the kernel symbol + table could not be found at all. + *) + +val start : Arg.usage_msg -> bool * image list + (** Programs call this to parse the standard command-line arguments + and do all the standard processing of domains into images. + + The returned tuple is: + - verbose mode + - list of images + *) diff --git a/uname/.depend b/uname/.depend index e69de29..eafb6d7 100644 --- a/uname/.depend +++ b/uname/.depend @@ -0,0 +1,2 @@ +virt_uname.cmo: ../lib/virt_mem_gettext.cmo ../lib/virt_mem.cmi +virt_uname.cmx: ../lib/virt_mem_gettext.cmx ../lib/virt_mem.cmx diff --git a/uname/Makefile.in b/uname/Makefile.in index 1740e00..6a57ad2 100644 --- a/uname/Makefile.in +++ b/uname/Makefile.in @@ -24,33 +24,36 @@ INSTALL = @INSTALL@ SYNTAX = -pp "camlp4o -I`ocamlc -where`/bitmatch bitmatch.cma pa_bitmatch.cmo" #OCAMLCPACKAGES = -package unix,bigarray,extlib,bitmatch -OCAMLCPACKAGES = -package unix,bigarray,extlib -I +bitmatch +OCAMLCPACKAGES = -package unix,bigarray,extlib -I +bitmatch -I ../lib ifneq ($(pkg_gettext),no) OCAMLCPACKAGES += -package gettext-stub endif OCAMLCFLAGS = @OCAMLCFLAGS@ $(SYNTAX) -OCAMLCLIBS = -linkpkg bitmatch.cma +OCAMLCLIBS = -linkpkg bitmatch.cma ../lib/virt_mem.cma OCAMLOPTFLAGS = @OCAMLOPTFLAGS@ $(SYNTAX) OCAMLOPTPACKAGES = $(OCAMLCPACKAGES) -OCAMLOPTLIBS = -linkpkg bitmatch.cmxa +OCAMLOPTLIBS = -linkpkg bitmatch.cmxa ../lib/virt_mem.cmxa OCAMLDOCFLAGS = -html -sort $(OCAMLCPACKAGES) $(SYNTAX) OCAMLDEPFLAGS = $(SYNTAX) -TARGETS = +TARGETS = virt-uname virt-uname.opt + +OBJS = virt_uname.cmo +XOBJS = virt_uname.cmx all: $(TARGETS) -#virt-mem: $(OBJS) -# ocamlfind ocamlc \ -# $(OCAMLCFLAGS) $(OCAMLCPACKAGES) $(OCAMLCLIBS) $^ -o $@ -# -#virt-mem.opt: $(XOBJS) -# ocamlfind ocamlopt \ -# $(OCAMLOPTFLAGS) $(OCAMLOPTPACKAGES) $(OCAMLOPTLIBS) $^ -o $@ +virt-uname: $(OBJS) ../lib/virt_mem.cma + ocamlfind ocamlc \ + $(OCAMLCFLAGS) $(OCAMLCPACKAGES) $(OCAMLCLIBS) $(OBJS) -o $@ + +virt-uname.opt: $(XOBJS) ../lib/virt_mem.cmxa + ocamlfind ocamlopt \ + $(OCAMLOPTFLAGS) $(OCAMLOPTPACKAGES) $(OCAMLOPTLIBS) $(XOBJS) -o $@ include ../Make.rules \ No newline at end of file diff --git a/uname/virt_uname.ml b/uname/virt_uname.ml new file mode 100644 index 0000000..54c0148 --- /dev/null +++ b/uname/virt_uname.ml @@ -0,0 +1,33 @@ +(* Memory info 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 Virt_mem_gettext.Gettext + +let usage = s_"NAME + virt-uname - uname command for virtual machines + +SUMMARY + virt-uname [-options] [domains] + +DESCRIPTION + virt-uname prints the uname information such as OS version, + architecture and node name for virtual machines running under + libvirt." + +let verbose, images = Virt_mem.start usage