0001
0002 #include <linux/compiler.h>
0003 #include <linux/rbtree.h>
0004 #include <inttypes.h>
0005 #include <string.h>
0006 #include <ctype.h>
0007 #include <stdlib.h>
0008 #include "dso.h"
0009 #include "map.h"
0010 #include "symbol.h"
0011 #include <internal/lib.h> // page_size
0012 #include "tests.h"
0013 #include "debug.h"
0014 #include "machine.h"
0015
0016 #define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
0017
0018 static bool is_ignored_symbol(const char *name, char type)
0019 {
0020
0021 static const char * const ignored_symbols[] = {
0022
0023
0024
0025
0026
0027
0028
0029 "kallsyms_addresses",
0030 "kallsyms_offsets",
0031 "kallsyms_relative_base",
0032 "kallsyms_num_syms",
0033 "kallsyms_names",
0034 "kallsyms_markers",
0035 "kallsyms_token_table",
0036 "kallsyms_token_index",
0037
0038 "_SDA_BASE_",
0039 "_SDA2_BASE_",
0040 NULL
0041 };
0042
0043
0044 static const char * const ignored_prefixes[] = {
0045 "$",
0046 ".L",
0047 "__crc_",
0048 "__efistub_",
0049 "__kvm_nvhe_$",
0050 "__kvm_nvhe_.L",
0051 "__AArch64ADRPThunk_",
0052 "__ARMV5PILongThunk_",
0053 "__ARMV7PILongThunk_",
0054 "__ThumbV7PILongThunk_",
0055 "__LA25Thunk_",
0056 "__microLA25Thunk_",
0057 NULL
0058 };
0059
0060
0061 static const char * const ignored_suffixes[] = {
0062 "_from_arm",
0063 "_from_thumb",
0064 "_veneer",
0065 NULL
0066 };
0067
0068
0069 static const char * const ignored_matches[] = {
0070 ".long_branch.",
0071 ".plt_branch.",
0072 NULL
0073 };
0074
0075 const char * const *p;
0076
0077 for (p = ignored_symbols; *p; p++)
0078 if (!strcmp(name, *p))
0079 return true;
0080
0081 for (p = ignored_prefixes; *p; p++)
0082 if (!strncmp(name, *p, strlen(*p)))
0083 return true;
0084
0085 for (p = ignored_suffixes; *p; p++) {
0086 int l = strlen(name) - strlen(*p);
0087
0088 if (l >= 0 && !strcmp(name + l, *p))
0089 return true;
0090 }
0091
0092 for (p = ignored_matches; *p; p++) {
0093 if (strstr(name, *p))
0094 return true;
0095 }
0096
0097 if (type == 'U' || type == 'u')
0098 return true;
0099
0100 if (type == 'N' || type == 'n')
0101 return true;
0102
0103 if (toupper(type) == 'A') {
0104
0105 if (strcmp(name, "__kernel_syscall_via_break") &&
0106 strcmp(name, "__kernel_syscall_via_epc") &&
0107 strcmp(name, "__kernel_sigtramp") &&
0108 strcmp(name, "__gp"))
0109 return true;
0110 }
0111
0112 return false;
0113 }
0114
0115 static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused,
0116 int subtest __maybe_unused)
0117 {
0118 int err = TEST_FAIL;
0119 struct rb_node *nd;
0120 struct symbol *sym;
0121 struct map *kallsyms_map, *vmlinux_map, *map;
0122 struct machine kallsyms, vmlinux;
0123 struct maps *maps;
0124 u64 mem_start, mem_end;
0125 bool header_printed;
0126
0127
0128
0129
0130
0131
0132
0133 machine__init(&kallsyms, "", HOST_KERNEL_ID);
0134 machine__init(&vmlinux, "", HOST_KERNEL_ID);
0135
0136 maps = machine__kernel_maps(&vmlinux);
0137
0138
0139
0140
0141
0142
0143
0144
0145 if (machine__create_kernel_maps(&kallsyms) < 0) {
0146 pr_debug("machine__create_kernel_maps failed");
0147 err = TEST_SKIP;
0148 goto out;
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms") <= 0) {
0163 pr_debug("machine__load_kallsyms failed");
0164 err = TEST_SKIP;
0165 goto out;
0166 }
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 kallsyms_map = machine__kernel_map(&kallsyms);
0177
0178
0179
0180
0181
0182
0183 if (machine__create_kernel_maps(&vmlinux) < 0) {
0184 pr_info("machine__create_kernel_maps failed");
0185 goto out;
0186 }
0187
0188 vmlinux_map = machine__kernel_map(&vmlinux);
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 if (machine__load_vmlinux_path(&vmlinux) <= 0) {
0202 pr_info("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
0203 err = TEST_SKIP;
0204 goto out;
0205 }
0206
0207 err = 0;
0208
0209
0210
0211
0212
0213
0214
0215 map__for_each_symbol(vmlinux_map, sym, nd) {
0216 struct symbol *pair, *first_pair;
0217
0218 sym = rb_entry(nd, struct symbol, rb_node);
0219
0220 if (sym->start == sym->end)
0221 continue;
0222
0223 mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start);
0224 mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end);
0225
0226 first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL);
0227 pair = first_pair;
0228
0229 if (pair && UM(pair->start) == mem_start) {
0230 next_pair:
0231 if (arch__compare_symbol_names(sym->name, pair->name) == 0) {
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 s64 skew = mem_end - UM(pair->end);
0242 if (llabs(skew) >= page_size)
0243 pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
0244 mem_start, sym->name, mem_end,
0245 UM(pair->end));
0246
0247
0248
0249
0250
0251
0252
0253 continue;
0254 } else {
0255 pair = machine__find_kernel_symbol_by_name(&kallsyms, sym->name, NULL);
0256 if (pair) {
0257 if (UM(pair->start) == mem_start)
0258 goto next_pair;
0259
0260 pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
0261 mem_start, sym->name, pair->name);
0262 } else {
0263 pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
0264 mem_start, sym->name, first_pair->name);
0265 }
0266
0267 continue;
0268 }
0269 } else if (mem_start == kallsyms.vmlinux_map->end) {
0270
0271
0272
0273
0274 continue;
0275 } else if (is_ignored_symbol(sym->name, sym->type)) {
0276
0277
0278
0279 continue;
0280 } else {
0281 pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
0282 mem_start, sym->name);
0283 }
0284
0285 err = -1;
0286 }
0287
0288 if (verbose <= 0)
0289 goto out;
0290
0291 header_printed = false;
0292
0293 maps__for_each_entry(maps, map) {
0294 struct map *
0295
0296
0297
0298
0299
0300
0301 pair = maps__find_by_name(kallsyms.kmaps, (map->dso->kernel ?
0302 map->dso->short_name :
0303 map->dso->name));
0304 if (pair) {
0305 pair->priv = 1;
0306 } else {
0307 if (!header_printed) {
0308 pr_info("WARN: Maps only in vmlinux:\n");
0309 header_printed = true;
0310 }
0311 map__fprintf(map, stderr);
0312 }
0313 }
0314
0315 header_printed = false;
0316
0317 maps__for_each_entry(maps, map) {
0318 struct map *pair;
0319
0320 mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start);
0321 mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end);
0322
0323 pair = maps__find(kallsyms.kmaps, mem_start);
0324 if (pair == NULL || pair->priv)
0325 continue;
0326
0327 if (pair->start == mem_start) {
0328 if (!header_printed) {
0329 pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n");
0330 header_printed = true;
0331 }
0332
0333 pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
0334 map->start, map->end, map->pgoff, map->dso->name);
0335 if (mem_end != pair->end)
0336 pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64,
0337 pair->start, pair->end, pair->pgoff);
0338 pr_info(" %s\n", pair->dso->name);
0339 pair->priv = 1;
0340 }
0341 }
0342
0343 header_printed = false;
0344
0345 maps = machine__kernel_maps(&kallsyms);
0346
0347 maps__for_each_entry(maps, map) {
0348 if (!map->priv) {
0349 if (!header_printed) {
0350 pr_info("WARN: Maps only in kallsyms:\n");
0351 header_printed = true;
0352 }
0353 map__fprintf(map, stderr);
0354 }
0355 }
0356 out:
0357 machine__exit(&kallsyms);
0358 machine__exit(&vmlinux);
0359 return err;
0360 }
0361
0362 DEFINE_SUITE("vmlinux symtab matches kallsyms", vmlinux_matches_kallsyms);