X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=lib%2Fvirt_mem.ml;h=fd99b86fac2fc8d11611ffb3d617dc32b7abeac3;hb=30f9bc6cfcd5915fd64b00ec11e1329423d5a801;hp=69a08215daaff6e01d4618733819b619cfad656c;hpb=b8aef502747b039b20877f99f3d8986b6a9329d2;p=virt-mem.git diff --git a/lib/virt_mem.ml b/lib/virt_mem.ml index 69a0821..fd99b86 100644 --- a/lib/virt_mem.ml +++ b/lib/virt_mem.ml @@ -42,12 +42,20 @@ let kernel_size = let tools = ref [] (* Registration function used by the tools. *) -let register ?(external_cmd = true) ?(extra_args = []) - ?argcheck ?beforeksyms ?beforeutsname ?run +let register + ?(needs_ksyms = false) ?(needs_utsname = false) + ?(needs_tasks = false) ?(needs_net_devices = false) + ?(needs_everything = false) + ~run + ?(external_cmd = true) + ?(extra_args = []) + ?argcheck name summary description = tools := - (name, (name, summary, description, external_cmd, extra_args, - argcheck, beforeksyms, beforeutsname, run)) + (name, (name, summary, description, + needs_ksyms, needs_utsname, needs_tasks, needs_net_devices, + needs_everything, + run, external_cmd, extra_args, argcheck)) :: !tools (* Main program, called from mem/virt_mem_main.ml when all the @@ -105,7 +113,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 @@ -127,12 +135,12 @@ General usage is: [-options] [domains...] To display extra help for a single tool, do: - virt-mem help + virt-mem --help 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 @@ -233,6 +241,12 @@ Options:") cmd summary description in exit 0 in + (* Handle --list-kernels option. *) + let list_kernels () = + List.iter print_endline Virt_mem_kernels.kernels; + exit 0 + in + (* Function to collect up any anonymous args (domain names/IDs). *) let anon_arg str = anon_args := str :: !anon_args in @@ -242,7 +256,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"; @@ -258,6 +272,8 @@ Options:") cmd summary description in "uri " ^ s_ "Connect to URI"; "--debug", Arg.Set debug, " " ^ s_"Debug mode (default: false)"; + "--list-kernels", Arg.Unit list_kernels, + " " ^ s_"List known kernels"; "-t", Arg.String memory_image, "image " ^ s_"Use saved kernel memory image"; "--version", Arg.Unit version, @@ -293,7 +309,10 @@ 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, beforeutsname, run = + let name, _, _, + needs_ksyms, needs_utsname, needs_tasks, needs_net_devices, + needs_everything, + run, external_cmd, extra_args, argcheck = match tool with | Some t -> t | None -> @@ -311,7 +330,7 @@ Use 'virt-mem --help' for more help or read the manual page virt-mem(1)"); ); (* Get the kernel images. *) - let images = + let kimages = if testimages = [] then ( let conn = let name = uri in @@ -406,7 +425,7 @@ Use 'virt-mem --help' for more help or read the manual page virt-mem(1)"); (* Download the static part of the kernel. *) let start_t = gettimeofday () in - let image = + let kimage = try load_static_memory ~dom ~domname ~arch ~wordsize ~endian @@ -425,7 +444,7 @@ Possibly the '-T' command line parameter was used inconsistently."); (end_t -. start_t) ); - image + kimage ) xmls ) else ( @@ -475,73 +494,153 @@ Possibly the '-T' command line parameter was used inconsistently."); let mem = Virt_mem_mmap.set_wordsize mem wordsize in let mem = Virt_mem_mmap.set_endian mem endian in - { dom = None; domname = filename; mem = mem; arch = arch; - kernel_min = kernel_min; kernel_max = kernel_max } + { dom = None; domname = filename; arch = arch; + kernel_min = kernel_min; kernel_max = kernel_max; + mem = mem; addrmap = Kernel.AddrMap.empty; + ksyms = Ksymmap.empty; have_ksyms = false; have_kallsyms = false; + utsname = None; + have_tasks = false; have_net_devices = false } ) testimages ) in - (* Optional callback into the tool before we start looking for - * kernel symbols. - *) - (match beforeksyms with - | None -> () - | Some beforeksyms -> beforeksyms debug images - ); - - (* If there are no more callback functions, then there is no point - * continuing with the rest of the program (kernel symbol analysis) ... - *) - 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: *) - let image = Virt_mem_kallsyms.find_kallsyms debug image in - -(* - (* Finally, just wrap the lookup_ksym call in something - * which prints the query when debug is set. - *) - let image = - if debug then - let (domid, name, arch, mem, lookup_ksym) = image in - let lookup_ksym sym = - try - let value = lookup_ksym sym in - eprintf "lookup_ksym %S = %Lx\n%!" sym value; - value - with Not_found -> - eprintf "lookup_ksym %S failed\n%!" sym; - raise Not_found - in - (domid, name, arch, mem, lookup_ksym) - else - image in -*) - - 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 -> List.iter (run debug) images - ) + (* Certain needs are dependent on others ... *) + let needs_ksyms = + if needs_utsname then true + else needs_ksyms in + let needs_ksyms, needs_utsname = + if needs_tasks then true, true + else needs_ksyms, needs_utsname in + let needs_ksyms, needs_utsname = + if needs_net_devices then true, true + else needs_ksyms, needs_utsname in + let needs_ksyms, needs_utsname, needs_tasks, needs_net_devices = + if needs_everything then true, true, true, true + else needs_ksyms, needs_utsname, needs_tasks, needs_net_devices in + + let errors = ref 0 in + + List.iter ( + fun kimage -> + try + (* Do the kernel symbol analysis. *) + let kimage = + if not needs_ksyms then kimage + else ( + (* Look for ordinary kernel symbols: *) + let kimage = Virt_mem_ksyms.find_kernel_symbols debug kimage in + + if kimage.have_ksyms then + (* Look for kallsyms: *) + Virt_mem_kallsyms.find_kallsyms debug kimage + else kimage + ) in + + (* Get the kernel version (utsname analysis). *) + let kimage = + if not needs_utsname then kimage + else ( + if kimage.have_ksyms then + Virt_mem_utsname.find_utsname debug kimage + else + kimage + ) in + + (* Get the tasks. *) + let kimage = + if not needs_tasks then kimage + else ( + let { ksyms = ksyms; have_ksyms = have_ksyms; utsname = utsname; + addrmap = addrmap } = kimage in + match have_ksyms, utsname with + | true, Some { uts_kernel_release = kernel_version } -> + let kimage = ref kimage in + let load struct_name addr size = + if debug then + eprintf "load for task, %s: %Lx %d ...\n" + struct_name addr size; + let mapped = + Virt_mem_mmap.is_mapped_range !kimage.mem addr size in + if not mapped then kimage := load_memory !kimage addr size; + let bits = Virt_mem_mmap.get_bytes !kimage.mem addr size in + Bitstring.bitstring_of_string bits + in + let addrmap = + try + let init_task = Ksymmap.find "init_task" ksyms in + Some (Kernel.task_struct_follower debug kernel_version + load addrmap init_task) + with + Not_found -> + eprintf (f_"%s: cannot find init_task symbol in kernel image.\n") !kimage.domname; + None in + (match addrmap with + | None -> !kimage + | Some addrmap -> + { !kimage with addrmap = addrmap; have_tasks = true } + ) + | _, _ -> kimage + ) in + + (* Get the net devices. *) + let kimage = + if not needs_net_devices then kimage + else ( + let { ksyms = ksyms; have_ksyms = have_ksyms; utsname = utsname; + addrmap = addrmap } = kimage in + match have_ksyms, utsname with + | true, Some { uts_kernel_release = kernel_version } -> + let kimage = ref kimage in + let load struct_name addr size = + if debug then + eprintf "load for net dev, %s: %Lx %d ...\n" + struct_name addr size; + let mapped = + Virt_mem_mmap.is_mapped_range !kimage.mem addr size in + if not mapped then kimage := load_memory !kimage addr size; + let bits = Virt_mem_mmap.get_bytes !kimage.mem addr size in + Bitstring.bitstring_of_string bits + in + let addrmap = + try + let dev_base = Ksymmap.find "dev_base" ksyms in + Some (Kernel.net_device_follower debug kernel_version + load addrmap dev_base) + with Not_found -> + try + let dev_base_head = Ksymmap.find "dev_base_head" ksyms in + (* XXX adjust to get offset of start of net_device *) + assert false + with Not_found -> + try + let init_net = Ksymmap.find "init_net" ksyms in + Some (Kernel.net_follower debug kernel_version + load addrmap init_net) + with Not_found -> + eprintf (f_"%s: cannot find dev_base, dev_base_head or init_net symbols in kernel image.\n") !kimage.domname; + None in + (match addrmap with + | None -> !kimage + | Some addrmap -> + { !kimage with addrmap = addrmap; have_net_devices = true } + ) + | _, _ -> kimage + ) in + + (* Run the tool's main function. *) + if not needs_everything then ( + if needs_ksyms && kimage.have_ksyms = false then + failwith (s_"could not read kernel symbols") + else if needs_utsname && kimage.utsname = None then + failwith (s_"could not read kernel version") + else if needs_tasks && kimage.have_tasks = false then + failwith (s_"could not read process table") + else if needs_net_devices && kimage.have_net_devices = false then + failwith (s_"could not read net device table") + ); + run debug kimage + with exn -> + eprintf "%s: %s\n" kimage.domname (Printexc.to_string exn); + incr errors + ) kimages; + + exit (if !errors > 0 then 1 else 0)