X-Git-Url: http://git.annexia.org/?p=virt-mem.git;a=blobdiff_plain;f=lib%2Fvirt_mem_ksyms.ml;fp=lib%2Fvirt_mem_ksyms.ml;h=d70ace180daca9141ca964e190b8ac681d1115c1;hp=0000000000000000000000000000000000000000;hb=89d41f7614612cf991d6005e7c1e20cd502a5404;hpb=8d9837165c14c181d5ce3f59fbd39afcb80ac8cc diff --git a/lib/virt_mem_ksyms.ml b/lib/virt_mem_ksyms.ml new file mode 100644 index 0000000..d70ace1 --- /dev/null +++ b/lib/virt_mem_ksyms.ml @@ -0,0 +1,191 @@ +(* 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. + + Ordinary kernel symbol lookups. + *) + +open Unix +open Printf + +open Virt_mem_gettext.Gettext +open Virt_mem_utils +open Virt_mem_types + +(* Look for some common entries in the exported 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, must be in EXPORT_SYMBOL. + *) +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 *) +] + +let find_kernel_symbols debug (domid, name, arch, mem) = + (* Searching for string *) + let common_ksyms_nul = List.map (sprintf "\000%s\000") common_ksyms in + + let start_t = gettimeofday () in + + (* Search for these strings in the memory image. *) + let ksym_strings = + List.map (Virt_mem_mmap.find_all mem) common_ksyms_nul 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 + + if debug then ( + let end_t = gettimeofday () in + eprintf "timing: searching for common_ksyms took %f seconds\n%!" + (end_t -. start_t) + ); + + let start_t = gettimeofday () 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 = Virt_mem_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 = + Virt_mem_mmap.pred_long mem (Virt_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 = Virt_mem_mmap.follow_pointer mem addr in + if Virt_mem_mmap.is_C_identifier mem addrp then + loop (pred_long2 addr) + else + Virt_mem_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 = Virt_mem_mmap.succ_long mem addr in + let addr2p = Virt_mem_mmap.follow_pointer mem addr2 in + if Virt_mem_mmap.is_C_identifier mem addr2p then + loop (Virt_mem_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 debug then ( + eprintf "%s: candidate symbol tables at:\n" name; + List.iter ( + fun (addr, size) -> + eprintf "\t%Lx\t%Lx\t%!" addr size; + eprintf "first symbol: %s\n%!" + (Virt_mem_mmap.get_string mem + (Virt_mem_mmap.follow_pointer mem + (Virt_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 debug then + eprintf + "%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 = + Bitstring.bitstring_of_string + (Virt_mem_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 (Virt_mem_mmap.get_wordsize mem) in + let e = Virt_mem_mmap.get_endian mem in + let rec loop bs = + bitmatch bs with + | { value : bits : endian(e); + name_ptr : bits : endian(e) } + when Virt_mem_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 + + lookup_ksym + in + + if debug then ( + let end_t = gettimeofday () in + eprintf "timing: searching for ordinary ksyms took %f seconds\n%!" + (end_t -. start_t) + ); + + ((domid, name, arch, mem, lookup_ksym) : image1)