From: Richard W.M. Jones <"Richard W.M. Jones "> Date: Wed, 23 Jul 2008 15:07:24 +0000 (+0100) Subject: Bring kernel version checking (utsname) into the central process. X-Git-Url: http://git.annexia.org/?p=virt-mem.git;a=commitdiff_plain;h=643e58b5e26c18f2cfc1c7b9aa676cb44feee847 Bring kernel version checking (utsname) into the central process. --- diff --git a/Makefile.in b/Makefile.in index 62e2fed..02cb91c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,6 +31,7 @@ OCAMLDOCFILES = lib/virt_mem_utils.ml \ lib/virt_mem_types.ml \ lib/virt_mem_ksyms.mli \ lib/virt_mem_kallsyms.mli \ + lib/virt_mem_utsname.mli \ lib/virt_mem.mli HAVE_PERLDOC = @HAVE_PERLDOC@ diff --git a/dmesg/.depend b/dmesg/.depend index 6c94cb9..89da6ef 100644 --- a/dmesg/.depend +++ b/dmesg/.depend @@ -1,4 +1,4 @@ -virt_dmesg.cmo: ../lib/virt_mem_utils.cmo ../lib/virt_mem_mmap.cmi \ - ../lib/virt_mem_gettext.cmo ../lib/virt_mem.cmi -virt_dmesg.cmx: ../lib/virt_mem_utils.cmx ../lib/virt_mem_mmap.cmx \ - ../lib/virt_mem_gettext.cmx ../lib/virt_mem.cmx +virt_dmesg.cmo: ../lib/virt_mem_utils.cmo ../lib/virt_mem_types.cmo \ + ../lib/virt_mem_mmap.cmi ../lib/virt_mem_gettext.cmo ../lib/virt_mem.cmi +virt_dmesg.cmx: ../lib/virt_mem_utils.cmx ../lib/virt_mem_types.cmx \ + ../lib/virt_mem_mmap.cmx ../lib/virt_mem_gettext.cmx ../lib/virt_mem.cmx diff --git a/dmesg/virt_dmesg.ml b/dmesg/virt_dmesg.ml index dd41d26..1886a92 100644 --- a/dmesg/virt_dmesg.ml +++ b/dmesg/virt_dmesg.ml @@ -21,58 +21,56 @@ open Printf open Virt_mem_gettext.Gettext open Virt_mem_utils +open Virt_mem_types open Virt_mem_mmap -let run debug images = - List.iter ( - fun (_, name, arch, mem, lookup_ksym) -> - try - (* I don't know why but this symbol doesn't exist in 2.6.9 - * even in kallsyms. Hence this won't work with that kernel. - * It's possible we can fall back to memory scanning. XXX - *) - let log_buf = lookup_ksym "log_buf" in - let log_buf = follow_pointer mem log_buf in - let log_buf_len = lookup_ksym "log_buf_len" in - let log_buf_len = Int64.of_int32 (get_C_int mem log_buf_len) in -(* let log_start = lookup_ksym "log_start" in +let run debug (_, name, arch, mem, lookup_ksym, _) = + try + (* I don't know why but this symbol doesn't exist in 2.6.9 + * even in kallsyms. Hence this won't work with that kernel. + * It's possible we can fall back to memory scanning. XXX + *) + let log_buf = lookup_ksym "log_buf" in + let log_buf = follow_pointer mem log_buf in + let log_buf_len = lookup_ksym "log_buf_len" in + let log_buf_len = Int64.of_int32 (get_C_int mem log_buf_len) in + (* let log_start = lookup_ksym "log_start" in let log_start = get_C_long mem log_start in *) - let log_end = lookup_ksym "log_end" in - let log_end = get_C_long mem log_end in -(* let con_start = lookup_ksym "con_start" in + let log_end = lookup_ksym "log_end" in + let log_end = get_C_long mem log_end in + (* let con_start = lookup_ksym "con_start" in let con_start = get_C_long mem con_start in *) - let logged_chars = lookup_ksym "logged_chars" in - let logged_chars = get_C_long mem logged_chars in + let logged_chars = lookup_ksym "logged_chars" in + let logged_chars = get_C_long mem logged_chars in - (* This is basically the same algorithm from printk.c:do_syslog - * type=3, translated into OCaml. Unlike the kernel version - * however we don't copy the buffer backwards. - *) - let get_log_buf idx = - let addr = log_buf +^ (idx &^ (log_buf_len -^ 1L)) in - Char.chr (get_byte mem addr) - in + (* This is basically the same algorithm from printk.c:do_syslog + * type=3, translated into OCaml. Unlike the kernel version + * however we don't copy the buffer backwards. + *) + let get_log_buf idx = + let addr = log_buf +^ (idx &^ (log_buf_len -^ 1L)) in + Char.chr (get_byte mem addr) + in - let count = log_buf_len in - let count = if count > logged_chars then logged_chars else count in - let limit = log_end in + let count = log_buf_len in + let count = if count > logged_chars then logged_chars else count in + let limit = log_end in - let rec loop i = - if i >= 0L then ( - let j = limit-^1L-^i in - if j +^ log_buf_len >= log_end then ( - let c = get_log_buf j in - printf "%c" c; - loop (i-^1L) - ) - ) - in - loop (count-^1L) - with - Not_found -> - eprintf (f_"%s: could not find kernel log buffer in kernel image\n") - name - ) images + let rec loop i = + if i >= 0L then ( + let j = limit-^1L-^i in + if j +^ log_buf_len >= log_end then ( + let c = get_log_buf j in + printf "%c" c; + loop (i-^1L) + ) + ) + in + loop (count-^1L) + with + Not_found -> + eprintf (f_"%s: could not find kernel log buffer in kernel image\n") + name let summary = s_"display kernel messages" let description = s_"\ diff --git a/lib/.depend b/lib/.depend index 6eb3e7f..bb77a91 100644 --- a/lib/.depend +++ b/lib/.depend @@ -2,6 +2,7 @@ virt_mem_kallsyms.cmi: virt_mem_types.cmo virt_mem_ksyms.cmi: virt_mem_types.cmo virt_mem.cmi: virt_mem_types.cmo virt_mem_mmap.cmi: virt_mem_utils.cmo +virt_mem_utsname.cmi: virt_mem_types.cmo test_mmap.cmo: virt_mem_mmap.cmi test_mmap.cmx: virt_mem_mmap.cmx virt_mem_capture.cmo: virt_mem_gettext.cmo virt_mem.cmi @@ -16,13 +17,17 @@ virt_mem_ksyms.cmo: virt_mem_utils.cmo virt_mem_types.cmo 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.cmo: virt_mem_version.cmo virt_mem_utils.cmo virt_mem_types.cmo \ - virt_mem_mmap.cmi virt_mem_ksyms.cmi virt_mem_kallsyms.cmi \ - virt_mem_gettext.cmo virt_mem.cmi -virt_mem.cmx: virt_mem_version.cmx virt_mem_utils.cmx virt_mem_types.cmx \ - virt_mem_mmap.cmx virt_mem_ksyms.cmx virt_mem_kallsyms.cmx \ - virt_mem_gettext.cmx virt_mem.cmi +virt_mem.cmo: virt_mem_version.cmo virt_mem_utsname.cmi virt_mem_utils.cmo \ + virt_mem_types.cmo virt_mem_mmap.cmi virt_mem_ksyms.cmi \ + virt_mem_kallsyms.cmi virt_mem_gettext.cmo virt_mem.cmi +virt_mem.cmx: virt_mem_version.cmx virt_mem_utsname.cmx virt_mem_utils.cmx \ + virt_mem_types.cmx virt_mem_mmap.cmx virt_mem_ksyms.cmx \ + virt_mem_kallsyms.cmx virt_mem_gettext.cmx virt_mem.cmi virt_mem_mmap.cmo: virt_mem_utils.cmo virt_mem_mmap.cmi virt_mem_mmap.cmx: virt_mem_utils.cmx virt_mem_mmap.cmi virt_mem_types.cmo: virt_mem_utils.cmo virt_mem_mmap.cmi virt_mem_types.cmx: virt_mem_utils.cmx virt_mem_mmap.cmx +virt_mem_utsname.cmo: virt_mem_utils.cmo virt_mem_types.cmo virt_mem_mmap.cmi \ + virt_mem_gettext.cmo virt_mem_utsname.cmi +virt_mem_utsname.cmx: virt_mem_utils.cmx virt_mem_types.cmx virt_mem_mmap.cmx \ + virt_mem_gettext.cmx virt_mem_utsname.cmi diff --git a/lib/Makefile.in b/lib/Makefile.in index 2edc175..9b41e68 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -53,6 +53,7 @@ OBJS = virt_mem_gettext.cmo \ virt_mem_types.cmo \ virt_mem_ksyms.cmo \ virt_mem_kallsyms.cmo \ + virt_mem_utsname.cmo \ virt_mem.cmo \ virt_mem_capture.cmo XOBJS = $(OBJS:%.cmo=%.cmx) diff --git a/lib/virt_mem.ml b/lib/virt_mem.ml index 0a956f1..03b0d1e 100644 --- a/lib/virt_mem.ml +++ b/lib/virt_mem.ml @@ -44,11 +44,11 @@ let tools = ref [] (* Registration function used by the tools. *) let register ?(external_cmd = true) ?(extra_args = []) - ?argcheck ?beforeksyms ?run + ?argcheck ?beforeksyms ?beforeutsname ?run name summary description = tools := (name, (name, summary, description, external_cmd, extra_args, - argcheck, beforeksyms, run)) + argcheck, beforeksyms, beforeutsname, run)) :: !tools (* Main program, called from mem/virt_mem_main.ml when all the @@ -106,7 +106,7 @@ let main () = match tool with | None -> (* Generic usage message. *) let tools = List.map ( - fun (name, (_, summary, _, external_cmd, _, _, _, _)) -> + fun (name, (_, summary, _, external_cmd, _, _, _, _, _)) -> if external_cmd then "virt-"^name, summary else "virt-mem "^name, summary ) tools in @@ -133,7 +133,7 @@ To display extra help for a single tool, do: Options:") tools (* Tool-specific usage message. *) - | Some (name, summary, description, external_cmd, _, _, _, _) -> + | Some (name, summary, description, external_cmd, _, _, _, _, _) -> let cmd = if external_cmd then "virt-" ^ name else "virt-mem " ^ name in @@ -219,7 +219,7 @@ Options:") cmd summary description in let argspec = let extra_args = match tool with | None -> [] - | Some (_, _, _, _, extra_args, _, _, _) -> extra_args in + | Some (_, _, _, _, extra_args, _, _, _, _) -> extra_args in let argspec = [ "-A", Arg.String set_architecture, "arch " ^ s_"Set kernel architecture, endianness and word size"; @@ -270,7 +270,7 @@ Options:") cmd summary description in * or the user didn't give us a valid tool (eg. "virt-mem foobar"). * Detect that final case now and give an error. *) - let name, _, _, _, _, argcheck, beforeksyms, run = + let name, _, _, _, _, argcheck, beforeksyms, beforeutsname, run = match tool with | Some t -> t | None -> @@ -469,16 +469,15 @@ Use 'virt-mem --help' for more help or read the manual page virt-mem(1)"); | Some beforeksyms -> beforeksyms debug images ); - (* If there is no run function, then there is no point continuing - * with the rest of the program (kernel symbol analysis) ... + (* If there are no more callback functions, then there is no point + * continuing with the rest of the program (kernel symbol analysis) ... *) - if run = None then exit 0; + if beforeutsname = None && run = None then exit 0; (* Do the kernel symbol analysis. *) let images = List.map ( fun image -> - (* Look for ordinary kernel symbols: *) let image = Virt_mem_ksyms.find_kernel_symbols debug image in (* Look for kallsyms: *) @@ -506,9 +505,22 @@ Use 'virt-mem --help' for more help or read the manual page virt-mem(1)"); image ) images in + (* Before utsname analysis. *) + (match beforeutsname with + | None -> () + | Some beforeutsname -> List.iter (beforeutsname debug) images + ); + + (* If there are no more callback functions, then there is no point + * continuing with the rest of the program (kernel version analysis) ... + *) + if run = None then exit 0; + + (* Get the kernel version (utsname analysis). *) + let images = List.map (Virt_mem_utsname.find_utsname debug) images in + (* Run the tool's main function. *) (match run with | None -> () - | Some run -> - run debug images + | Some run -> List.iter (run debug) images ) diff --git a/lib/virt_mem.mli b/lib/virt_mem.mli index eae488e..c807365 100644 --- a/lib/virt_mem.mli +++ b/lib/virt_mem.mli @@ -23,7 +23,8 @@ val register : ?extra_args:(Arg.key * Arg.spec * Arg.doc) list -> ?argcheck:(bool -> unit) -> ?beforeksyms:(bool -> Virt_mem_types.image0 list -> unit) -> - ?run:(bool -> Virt_mem_types.image1 list -> unit) -> + ?beforeutsname:(bool -> Virt_mem_types.image1 -> unit) -> + ?run:(bool -> Virt_mem_types.image2 -> unit) -> string -> string -> Arg.usage_msg -> unit (** Tools register themselves with this call. @@ -39,7 +40,9 @@ val register : on [extra_args]), - [?beforeksyms] called after images are loaded and before kernel symbols are analyzed, - - [?run] called after kernel symbols have been analyzed + - [?beforeutsname] called after kernel symbols are analyzed + and before the kernel version is detected + - [?run] called after everything (almost all tools supply this callback function). Pass [~external_cmd:false] if this tool doesn't have an diff --git a/lib/virt_mem_types.ml b/lib/virt_mem_types.ml index 2f8b329..34f3fe7 100644 --- a/lib/virt_mem_types.ml +++ b/lib/virt_mem_types.ml @@ -37,3 +37,21 @@ type image1 = * Virt_mem_utils.architecture (* Architecture, eg. i386. *) * ([`Wordsize], [`Endian], [`HasMapping]) Virt_mem_mmap.t (* Memory map. *) * (ksym -> Virt_mem_mmap.addr) (* Kernel symbol lookup function. *) + +(** A kernel image, after finding kernel version (like 'uname'). *) +type image2 = + int option (* Domain ID, if known. *) + * string (* Domain name. *) + * Virt_mem_utils.architecture (* Architecture, eg. i386. *) + * ([`Wordsize], [`Endian], [`HasMapping]) Virt_mem_mmap.t (* Memory map. *) + * (ksym -> Virt_mem_mmap.addr) (* Kernel symbol lookup function. *) + * utsname option (* Kernel version, etc., if known. *) + +and utsname = { + kernel_name : string; + nodename : string; + kernel_release : string; + kernel_version : string; + machine : string; + domainname : string; +} diff --git a/lib/virt_mem_utsname.ml b/lib/virt_mem_utsname.ml new file mode 100644 index 0000000..61a2b37 --- /dev/null +++ b/lib/virt_mem_utsname.ml @@ -0,0 +1,93 @@ +(* 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 Virt_mem_mmap + +(* Truncate an OCaml string at the first ASCII NUL character, ie. as + * if it were a C string. + *) +let truncate str = + try + let i = String.index str '\000' in + String.sub str 0 i + with + Not_found -> str + +let parse_utsname bits = + (* Expect the first (sysname) field to always be "Linux", which is + * also a good way to tell if we're synchronized to the right bit of + * memory. + *) + bitmatch bits with + | { "Linux\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" : 65*8 : string; + nodename : 65*8 : string; + release : 65*8 : string; + version : 65*8 : string; + machine : 65*8 : string; + domainname : 65*8 : string } -> + Some { + kernel_name = "Linux"; + nodename = truncate nodename; + kernel_release = truncate release; + kernel_version = truncate version; + machine = truncate machine; + domainname = truncate domainname + } + | { _ } -> + None + +let find_utsname debug (domid, name, arch, mem, lookup_ksym) = + let utsname = + (* In Linux 2.6.25, the symbol is init_uts_ns. + * http://lxr.linux.no/linux/init/version.c + *) + try + let addr = lookup_ksym "init_uts_ns" in + + let bs = Bitstring.bitstring_of_string (get_bytes mem addr (65*6+4)) in + (bitmatch bs with + | { _ : 32 : int; (* the kref, atomic_t, always 32 bits *) + new_utsname : -1 : bitstring } -> + parse_utsname new_utsname + | { _ } -> + if debug then + eprintf (f_"%s: unexpected init_uts_ns in kernel image\n") name; + None + ) + with + Not_found -> + (* In Linux 2.6.9, the symbol is system_utsname. + * http://lxr.linux.no/linux-bk+v2.6.9/include/linux/utsname.h#L24 + *) + try + let addr = lookup_ksym "system_utsname" in + + let bits = + Bitstring.bitstring_of_string (get_bytes mem addr (65*6)) in + parse_utsname bits + with + Not_found -> + eprintf (f_"%s: could not find utsname in kernel image\n") name + in + (domid, name, arch, mem, lookup_ksym, utsname) diff --git a/lib/virt_mem_utsname.mli b/lib/virt_mem_utsname.mli new file mode 100644 index 0000000..7b62d42 --- /dev/null +++ b/lib/virt_mem_utsname.mli @@ -0,0 +1,22 @@ +(** Get system utsname (like 'uname') from kernel. *) +(* 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. + *) + +val find_utsname : bool -> Virt_mem_types.image1 -> Virt_mem_types.image2 +(** Find the system utsname structure. *) diff --git a/ps/virt_ps.ml b/ps/virt_ps.ml index d18ff48..df876ba 100644 --- a/ps/virt_ps.ml +++ b/ps/virt_ps.ml @@ -222,11 +222,8 @@ let search debug mem lookup_ksym = let ts = loop 0 0 in () -let run debug images = - List.iter ( - fun (domid, domname, arch, mem, lookup_ksym) -> - search debug mem lookup_ksym - ) images +let run debug (_, _, _, mem, lookup_ksym, _) = + search debug mem lookup_ksym let summary = s_"list processes in virtual machine" let description = s_"\ diff --git a/uname/.depend b/uname/.depend index 8738997..dbdac15 100644 --- a/uname/.depend +++ b/uname/.depend @@ -1,4 +1,4 @@ -virt_uname.cmo: ../lib/virt_mem_utils.cmo ../lib/virt_mem_mmap.cmi \ +virt_uname.cmo: ../lib/virt_mem_utils.cmo ../lib/virt_mem_types.cmo \ ../lib/virt_mem_gettext.cmo ../lib/virt_mem.cmi -virt_uname.cmx: ../lib/virt_mem_utils.cmx ../lib/virt_mem_mmap.cmx \ +virt_uname.cmx: ../lib/virt_mem_utils.cmx ../lib/virt_mem_types.cmx \ ../lib/virt_mem_gettext.cmx ../lib/virt_mem.cmx diff --git a/uname/virt_uname.ml b/uname/virt_uname.ml index 6004bb8..981f0ee 100644 --- a/uname/virt_uname.ml +++ b/uname/virt_uname.ml @@ -21,72 +21,17 @@ open Printf open Virt_mem_gettext.Gettext open Virt_mem_utils -open Virt_mem_mmap - -let run debug images = - (* Print new_utsname structure from bitstring. *) - let print_new_utsname name bs = - (* Truncate an OCaml string at the first ASCII NUL character, ie. as - * if it were a C string. - *) - let truncate str = - try - let i = String.index str '\000' in - String.sub str 0 i - with - Not_found -> str - in - (* Expect the first (sysname) field to always be "Linux", which is - * also a good way to tell if we're synchronized to the right bit of - * memory. - *) - bitmatch bs with - | { "Linux\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" : 65*8 : string; - nodename : 65*8 : string; - release : 65*8 : string; - version : 65*8 : string; - machine : 65*8 : string; - domainname : 65*8 : string } -> - printf "%s: Linux %s %s %s %s %s\n" - name - (truncate nodename) (truncate release) - (truncate version) (truncate machine) (truncate domainname) - | { _ } -> - eprintf (f_"%s: unexpected system_utsname in kernel image\n") - name - in - - List.iter ( - fun (_, name, arch, mem, lookup_ksym) -> - (* In Linux 2.6.25, the symbol is init_uts_ns. - * http://lxr.linux.no/linux/init/version.c - *) - try - let addr = lookup_ksym "init_uts_ns" in - - let bs = Bitstring.bitstring_of_string (get_bytes mem addr (65*6+4)) in - (bitmatch bs with - | { _ : 32 : int; (* the kref, atomic_t, always 32 bits *) - new_utsname : -1 : bitstring } -> - print_new_utsname name new_utsname - | { _ } -> - eprintf (f_"%s: unexpected init_uts_ns in kernel image\n") - name) - with - Not_found -> - (* In Linux 2.6.9, the symbol is system_utsname. - * http://lxr.linux.no/linux-bk+v2.6.9/include/linux/utsname.h#L24 - *) - try - let addr = lookup_ksym "system_utsname" in - - let bs = - Bitstring.bitstring_of_string (get_bytes mem addr (65*6)) in - print_new_utsname name bs - with - Not_found -> - eprintf (f_"%s: could not find utsname in kernel image\n") name - ) images +open Virt_mem_types + +let run debug (_, name, _, _, _, utsname) = + match utsname with + | Some u -> + printf "%s: %s %s %s %s %s %s\n" + name + u.kernel_name u.nodename u.kernel_release + u.kernel_version u.machine u.domainname + | None -> + eprintf (f_"%s: no system_utsname in kernel image\n") name let summary = s_"uname command for virtual machines" let description = s_"\