- (* 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)