(* Registration function used by the tools. *)
let register
?(needs_ksyms = false) ?(needs_utsname = false)
- ?(needs_tasks = false) ?(needs_everything = false)
+ ?(needs_tasks = false) ?(needs_net_devices = false)
+ ?(needs_everything = false)
~run
?(external_cmd = true)
?(extra_args = [])
name summary description =
tools :=
(name, (name, summary, description,
- needs_ksyms, needs_utsname, needs_tasks, needs_everything,
+ needs_ksyms, needs_utsname, needs_tasks, needs_net_devices,
+ needs_everything,
run, external_cmd, extra_args, argcheck))
:: !tools
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
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
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
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";
"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,
* Detect that final case now and give an error.
*)
let name, _, _,
- needs_ksyms, needs_utsname, needs_tasks, needs_everything,
+ needs_ksyms, needs_utsname, needs_tasks, needs_net_devices,
+ needs_everything,
run, external_cmd, extra_args, argcheck =
match tool with
| Some t -> t
);
(* Get the kernel images. *)
- let images =
+ let kimages =
if testimages = [] then (
let conn =
let name = uri in
(* 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
(end_t -. start_t)
);
- image
+ kimage
) xmls
) else (
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
- (* Now build the kdata, depending on what the tool asked for. *)
- let images =
- List.map (
- fun image ->
- let kdata = { ksyms = None; utsname = None; tasks = None } in
- image, kdata
- ) images in
(* Certain needs are dependent on others ... *)
let needs_ksyms =
if needs_utsname then true
let needs_ksyms, needs_utsname =
if needs_tasks then true, true
else needs_ksyms, needs_utsname in
- let needs_ksyms, needs_utsname, needs_tasks =
- if needs_everything then true, true, true
- else needs_ksyms, needs_utsname, needs_tasks in
-
- (* Do the kernel symbol analysis. *)
- let images =
- if not needs_ksyms then images
- else
- List.map (
- fun (image, kdata) ->
- (* Look for ordinary kernel symbols: *)
- let image, ksyms =
- Virt_mem_ksyms.find_kernel_symbols debug image in
-
- match ksyms with
- | None -> image, kdata
- | Some ksyms ->
- (* Look for kallsyms: *)
- let image, kallsyms =
- Virt_mem_kallsyms.find_kallsyms debug image ksyms in
-
- let ksyms =
- match kallsyms with
- | None -> ksyms (* no kallsyms, just use module symbols *)
- | Some kallsyms -> kallsyms (* ksyms + kallsyms *) in
-
- image, { kdata with ksyms = Some ksyms }
- ) images 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
- (* Get the kernel version (utsname analysis). *)
- let images =
- if not needs_utsname then images
- else
- List.map (
- fun (image, ({ ksyms = ksyms } as kdata)) ->
- match ksyms with
- | None -> image, kdata
- | Some ksyms ->
- let image, utsname =
- Virt_mem_utsname.find_utsname debug image ksyms in
- let kdata = { kdata with utsname = utsname } in
- image, kdata
- ) images in
-
- (* Get the tasks. *)
- let images =
- if not needs_tasks then images
- else
- List.map (
- fun (image, ({ ksyms = ksyms; utsname = utsname } as kdata)) ->
- match ksyms, utsname with
- | Some ksyms, Some { kernel_release = kversion } ->
- let image, tasks =
- Virt_mem_tasks.find_tasks debug image ksyms kversion in
- let kdata = { kdata with tasks = tasks } in
- image, kdata
- | _, _ -> image, kdata
- ) images in
-
- (* Run the tool's main function. *)
let errors = ref 0 in
+
List.iter (
- fun (image, kdata) ->
+ 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 && kdata.ksyms = None then
+ if needs_ksyms && kimage.have_ksyms = false then
failwith (s_"could not read kernel symbols")
- else if needs_utsname && kdata.utsname = None then
+ else if needs_utsname && kimage.utsname = None then
failwith (s_"could not read kernel version")
- else if needs_tasks && kdata.tasks = None then
+ 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 image kdata
+ run debug kimage
with exn ->
- eprintf "%s: %s\n" image.domname (Printexc.to_string exn);
+ eprintf "%s: %s\n" kimage.domname (Printexc.to_string exn);
incr errors
- ) images;
+ ) kimages;
+
exit (if !errors > 0 then 1 else 0)