2 * (C) Copyright 2008-2011 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 (* Look for ordinary symbol table.
25 * The ordinary symbol table is defined as:
26 * struct kernel_symbol {
27 * unsigned long value;
28 * const char *name; -------> points to string somewhere else
31 * What we do is look for some likely symbols (ie. the strings,
32 * common_ksyms). Then (since we know the address of those strings)
33 * we look for something which is plausibly a symbol table, searching
34 * forwards and backwards to find the ends of it. This gives us, for
35 * each likely symbol found, a corresponding potential symbol table.
36 * Then we take a vote for the most frequently occurring symbol table
40 (* Look for some common entries in the exported symbol table and
41 * from that find the symbol table itself. These are just
42 * supposed to be symbols which are very likely to be present
43 * in any Linux kernel, although we only need one of them to be
44 * present to find the symbol table.
46 * NB. Must not be __initdata, must be in EXPORT_SYMBOL.
49 "init_task"; (* first task_struct *)
50 "root_mountflags"; (* flags for mounting root fs *)
51 "init_uts_ns"; (* uname strings *)
53 "speedstep_get_freqs";
54 "hpet_register_irq_handler";
57 "scsi_register_driver";
59 "input_register_handler";
60 "save_processor_state";
64 let sym_addrs : (string * int64) list =
68 let addrs = Kernel.find_all k (sprintf "\000%s\000" symbol) in
69 (* Need to +1 because the string we matched started with \0
72 let addrs = List.map ((+^) 1L) addrs in
73 List.map (fun addr -> (symbol, addr)) addrs
77 let sym_tables : (int64 * int64) list =
80 fun (source_symbol, addr) ->
81 let addrs = Kernel.find_all_pointers k addr in
83 (* struct kernel_symbol {
84 * unsigned long value;
85 * const char *name; <--- each of addrs (could) point here
89 (* Look at 'value' field and see if it's likely to be a
90 * value. Filter out if not.
92 let addrs = List.filter (
94 let a2 = Kernel.pred_word k a in
95 let a2p = Kernel.follow_pointer k a2 in
96 (* We wouldn't expect the value to point somewhere near
99 Int64.abs (addr -^ a2p) > 32L
102 (* Search back and forward for beginning and end of symbol table. *)
103 let symtab_start_addrs = List.map (
106 (* '*addr' should point to a C identifier. If it
107 * does, step backwards to the previous symbol table
110 let addrp = Kernel.follow_pointer k addr in
111 if Kernel.is_C_identifier k addrp then
112 loop (Kernel.pred_word k (Kernel.pred_word k addr))
114 Kernel.succ_word k addr
121 debug "start_addr %Lx from %s" start_addr source_symbol
122 ) symtab_start_addrs;
127 let addr2 = Kernel.succ_word k addr in (* &name *)
128 let addr2p = Kernel.follow_pointer k addr2 in (* name itself *)
129 if Kernel.is_C_identifier k addr2p then
130 loop (Kernel.succ_word k addr2)
134 let end_addr = loop start_addr in
135 start_addr, end_addr -^ start_addr
140 debug "candidate symbol tables:";
143 debug "\tstart %Lx size %Ld" start size
146 (* Simply ignore any symbol table candidates which are too small. *)
147 let sym_tables = List.filter (fun (_, size) -> size > 64L) sym_tables in
149 (* Vote for the most popular symbol table. *)
150 let freqs = frequency sym_tables in
153 (* No symbol table, so this is likely not a kernel that we
158 | (_, (start_addr, size)) :: _ ->
159 (* Take the most popular symbol table candidate and discard
160 * the others. Parse this into a list of symbols.
162 let rec loop addr acc =
163 if addr < start_addr +^ size then
164 let value = Kernel.follow_pointer k addr in (* value *)
165 let addr2 = Kernel.succ_word k addr in (* &name *)
166 let addr2p = Kernel.follow_pointer k addr2 in (* name itself *)
167 let symbol = Kernel.get_string k addr2p in
168 let acc = (symbol, value) :: acc in
169 loop (Kernel.succ_word k addr2) acc