1 (* Memory info command for virtual domains.
2 (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 Ordinary kernel symbol lookups.
25 open Virt_mem_gettext.Gettext
29 (* Look for some common entries in the exported symbol table and
30 * from that find the symbol table itself. These are just
31 * supposed to be symbols which are very likely to be present
32 * in any Linux kernel, although we only need one of them to be
33 * present to find the symbol table.
35 * NB. Must not be __initdata, must be in EXPORT_SYMBOL.
38 "init_task"; (* first task_struct *)
39 "root_mountflags"; (* flags for mounting root fs *)
40 "init_uts_ns"; (* uname strings *)
41 "sys_open"; (* open(2) entry point *)
42 "sys_chdir"; (* chdir(2) entry point *)
43 "sys_chroot"; (* chroot(2) entry point *)
44 "sys_umask"; (* umask(2) entry point *)
45 "schedule"; (* scheduler entry point *)
48 let find_kernel_symbols debug ({ mem = mem; domname = domname } as kimage) =
49 (* Searching for <NUL>string<NUL> *)
50 let common_ksyms_nul = List.map (sprintf "\000%s\000") common_ksyms in
52 let start_t = gettimeofday () in
54 (* Search for these strings in the memory image. *)
56 List.map (Virt_mem_mmap.find_all mem) common_ksyms_nul in
57 let ksym_strings = List.concat ksym_strings in
58 (* Adjust found addresses to start of the string (skip <NUL>). *)
59 let ksym_strings = List.map Int64.succ ksym_strings in
62 let end_t = gettimeofday () in
63 eprintf "timing: searching for common_ksyms took %f seconds\n%!"
67 let start_t = gettimeofday () in
69 (* For any we found, try to look up the symbol table
72 let ksymtabs = List.map (
74 (* Search for 'addr' appearing in the image. *)
75 let addrs = Virt_mem_mmap.find_pointer_all mem addr in
77 (* Now consider each of these addresses and search back
78 * until we reach the beginning of the (possible) symbol
81 * Kernel symbol table struct is:
82 * struct kernel_symbol {
83 * unsigned long value;
84 * const char *name; <-- initial pointer
88 Virt_mem_mmap.pred_long mem (Virt_mem_mmap.pred_long mem addr)
90 let base_addrs = List.map (
93 (* '*addr' should point to a C identifier. If it does,
94 * step backwards to the previous symbol table entry.
96 let addrp = Virt_mem_mmap.follow_pointer mem addr in
97 if Virt_mem_mmap.is_C_identifier mem addrp then
98 loop (pred_long2 addr)
100 Virt_mem_mmap.succ_long mem addr
105 (* Also look for the end of the symbol table and
106 * calculate its size.
108 let base_addrs_sizes = List.map (
111 let addr2 = Virt_mem_mmap.succ_long mem addr in
112 let addr2p = Virt_mem_mmap.follow_pointer mem addr2 in
113 if Virt_mem_mmap.is_C_identifier mem addr2p then
114 loop (Virt_mem_mmap.succ_long mem addr2)
118 let end_addr = loop base_addr in
119 base_addr, end_addr -^ base_addr
124 let ksymtabs = List.concat ksymtabs in
126 (* Simply ignore any symbol table candidates which are too small. *)
127 let ksymtabs = List.filter (fun (_, size) -> size > 64L) ksymtabs in
130 eprintf "%s: candidate symbol tables at:\n" domname;
133 eprintf "\t%Lx\t%Lx\t%!" addr size;
134 eprintf "first symbol: %S\n%!"
135 (Virt_mem_mmap.get_string mem
136 (Virt_mem_mmap.follow_pointer mem
137 (Virt_mem_mmap.succ_long mem addr)))
141 (* Vote for the most popular symbol table candidate and from this
142 * generate a function to look up ksyms.
144 let ksyms, have_ksyms =
145 let freqs = frequency ksymtabs in
148 eprintf (f_"%s: cannot find start of kernel symbol table\n") domname;
151 | (_, (ksymtab_addr, ksymtab_size)) :: _ ->
154 "%s: Kernel symbol table found at %Lx, size %Lx bytes\n%!"
155 domname ksymtab_addr ksymtab_size;
157 (* Load the whole symbol table as a bitstring. *)
159 Bitstring.bitstring_of_string
160 (Virt_mem_mmap.get_bytes mem ksymtab_addr
161 (Int64.to_int ksymtab_size)) in
163 (* Construct kernel symbol map. *)
165 let bits = bits_of_wordsize (Virt_mem_mmap.get_wordsize mem) in
166 let e = Virt_mem_mmap.get_endian mem in
167 let rec loop ksyms bs =
169 | { value : bits : endian(e);
170 name_ptr : bits : endian(e);
171 bs : -1 : bitstring } ->
172 let name = Virt_mem_mmap.get_string mem name_ptr in
173 let ksyms = Ksymmap.add name value ksyms in
178 loop Ksymmap.empty ksymtab in
184 let end_t = gettimeofday () in
185 eprintf "timing: searching for ordinary ksyms took %f seconds\n%!"
189 { kimage with ksyms = ksyms; have_ksyms = have_ksyms }