Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.35-rc2 281 lines 7.2 kB view raw
1/* 2 * builtin-test.c 3 * 4 * Builtin regression testing command: ever growing number of sanity tests 5 */ 6#include "builtin.h" 7 8#include "util/cache.h" 9#include "util/debug.h" 10#include "util/parse-options.h" 11#include "util/session.h" 12#include "util/symbol.h" 13#include "util/thread.h" 14 15static long page_size; 16 17static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) 18{ 19 bool *visited = symbol__priv(sym); 20 *visited = true; 21 return 0; 22} 23 24static int test__vmlinux_matches_kallsyms(void) 25{ 26 int err = -1; 27 struct rb_node *nd; 28 struct symbol *sym; 29 struct map *kallsyms_map, *vmlinux_map; 30 struct machine kallsyms, vmlinux; 31 enum map_type type = MAP__FUNCTION; 32 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; 33 34 /* 35 * Step 1: 36 * 37 * Init the machines that will hold kernel, modules obtained from 38 * both vmlinux + .ko files and from /proc/kallsyms split by modules. 39 */ 40 machine__init(&kallsyms, "", HOST_KERNEL_ID); 41 machine__init(&vmlinux, "", HOST_KERNEL_ID); 42 43 /* 44 * Step 2: 45 * 46 * Create the kernel maps for kallsyms and the DSO where we will then 47 * load /proc/kallsyms. Also create the modules maps from /proc/modules 48 * and find the .ko files that match them in /lib/modules/`uname -r`/. 49 */ 50 if (machine__create_kernel_maps(&kallsyms) < 0) { 51 pr_debug("machine__create_kernel_maps "); 52 return -1; 53 } 54 55 /* 56 * Step 3: 57 * 58 * Load and split /proc/kallsyms into multiple maps, one per module. 59 */ 60 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) { 61 pr_debug("dso__load_kallsyms "); 62 goto out; 63 } 64 65 /* 66 * Step 4: 67 * 68 * kallsyms will be internally on demand sorted by name so that we can 69 * find the reference relocation * symbol, i.e. the symbol we will use 70 * to see if the running kernel was relocated by checking if it has the 71 * same value in the vmlinux file we load. 72 */ 73 kallsyms_map = machine__kernel_map(&kallsyms, type); 74 75 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL); 76 if (sym == NULL) { 77 pr_debug("dso__find_symbol_by_name "); 78 goto out; 79 } 80 81 ref_reloc_sym.addr = sym->start; 82 83 /* 84 * Step 5: 85 * 86 * Now repeat step 2, this time for the vmlinux file we'll auto-locate. 87 */ 88 if (machine__create_kernel_maps(&vmlinux) < 0) { 89 pr_debug("machine__create_kernel_maps "); 90 goto out; 91 } 92 93 vmlinux_map = machine__kernel_map(&vmlinux, type); 94 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym; 95 96 /* 97 * Step 6: 98 * 99 * Locate a vmlinux file in the vmlinux path that has a buildid that 100 * matches the one of the running kernel. 101 * 102 * While doing that look if we find the ref reloc symbol, if we find it 103 * we'll have its ref_reloc_symbol.unrelocated_addr and then 104 * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines 105 * to fixup the symbols. 106 */ 107 if (machine__load_vmlinux_path(&vmlinux, type, 108 vmlinux_matches_kallsyms_filter) <= 0) { 109 pr_debug("machine__load_vmlinux_path "); 110 goto out; 111 } 112 113 err = 0; 114 /* 115 * Step 7: 116 * 117 * Now look at the symbols in the vmlinux DSO and check if we find all of them 118 * in the kallsyms dso. For the ones that are in both, check its names and 119 * end addresses too. 120 */ 121 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) { 122 struct symbol *pair; 123 124 sym = rb_entry(nd, struct symbol, rb_node); 125 pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL); 126 127 if (pair && pair->start == sym->start) { 128next_pair: 129 if (strcmp(sym->name, pair->name) == 0) { 130 /* 131 * kallsyms don't have the symbol end, so we 132 * set that by using the next symbol start - 1, 133 * in some cases we get this up to a page 134 * wrong, trace_kmalloc when I was developing 135 * this code was one such example, 2106 bytes 136 * off the real size. More than that and we 137 * _really_ have a problem. 138 */ 139 s64 skew = sym->end - pair->end; 140 if (llabs(skew) < page_size) 141 continue; 142 143 pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n", 144 sym->start, sym->name, sym->end, pair->end); 145 } else { 146 struct rb_node *nnd = rb_prev(&pair->rb_node); 147 148 if (nnd) { 149 struct symbol *next = rb_entry(nnd, struct symbol, rb_node); 150 151 if (next->start == sym->start) { 152 pair = next; 153 goto next_pair; 154 } 155 } 156 pr_debug("%#Lx: diff name v: %s k: %s\n", 157 sym->start, sym->name, pair->name); 158 } 159 } else 160 pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name); 161 162 err = -1; 163 } 164 165 if (!verbose) 166 goto out; 167 168 pr_info("Maps only in vmlinux:\n"); 169 170 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) { 171 struct map *pos = rb_entry(nd, struct map, rb_node), *pair; 172 /* 173 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while 174 * the kernel will have the path for the vmlinux file being used, 175 * so use the short name, less descriptive but the same ("[kernel]" in 176 * both cases. 177 */ 178 pair = map_groups__find_by_name(&kallsyms.kmaps, type, 179 (pos->dso->kernel ? 180 pos->dso->short_name : 181 pos->dso->name)); 182 if (pair) 183 pair->priv = 1; 184 else 185 map__fprintf(pos, stderr); 186 } 187 188 pr_info("Maps in vmlinux with a different name in kallsyms:\n"); 189 190 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) { 191 struct map *pos = rb_entry(nd, struct map, rb_node), *pair; 192 193 pair = map_groups__find(&kallsyms.kmaps, type, pos->start); 194 if (pair == NULL || pair->priv) 195 continue; 196 197 if (pair->start == pos->start) { 198 pair->priv = 1; 199 pr_info(" %Lx-%Lx %Lx %s in kallsyms as", 200 pos->start, pos->end, pos->pgoff, pos->dso->name); 201 if (pos->pgoff != pair->pgoff || pos->end != pair->end) 202 pr_info(": \n*%Lx-%Lx %Lx", 203 pair->start, pair->end, pair->pgoff); 204 pr_info(" %s\n", pair->dso->name); 205 pair->priv = 1; 206 } 207 } 208 209 pr_info("Maps only in kallsyms:\n"); 210 211 for (nd = rb_first(&kallsyms.kmaps.maps[type]); 212 nd; nd = rb_next(nd)) { 213 struct map *pos = rb_entry(nd, struct map, rb_node); 214 215 if (!pos->priv) 216 map__fprintf(pos, stderr); 217 } 218out: 219 return err; 220} 221 222static struct test { 223 const char *desc; 224 int (*func)(void); 225} tests[] = { 226 { 227 .desc = "vmlinux symtab matches kallsyms", 228 .func = test__vmlinux_matches_kallsyms, 229 }, 230 { 231 .func = NULL, 232 }, 233}; 234 235static int __cmd_test(void) 236{ 237 int i = 0; 238 239 page_size = sysconf(_SC_PAGE_SIZE); 240 241 while (tests[i].func) { 242 int err; 243 pr_info("%2d: %s:", i + 1, tests[i].desc); 244 pr_debug("\n--- start ---\n"); 245 err = tests[i].func(); 246 pr_debug("---- end ----\n%s:", tests[i].desc); 247 pr_info(" %s\n", err ? "FAILED!\n" : "Ok"); 248 ++i; 249 } 250 251 return 0; 252} 253 254static const char * const test_usage[] = { 255 "perf test [<options>]", 256 NULL, 257}; 258 259static const struct option test_options[] = { 260 OPT_INTEGER('v', "verbose", &verbose, 261 "be more verbose (show symbol address, etc)"), 262 OPT_END() 263}; 264 265int cmd_test(int argc, const char **argv, const char *prefix __used) 266{ 267 argc = parse_options(argc, argv, test_options, test_usage, 0); 268 if (argc) 269 usage_with_options(test_usage, test_options); 270 271 symbol_conf.priv_size = sizeof(int); 272 symbol_conf.sort_by_name = true; 273 symbol_conf.try_vmlinux_path = true; 274 275 if (symbol__init() < 0) 276 return -1; 277 278 setup_pager(); 279 280 return __cmd_test(); 281}