aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-06-03 04:52:21 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-06-03 09:02:38 -0400
commit1f121b03d058dd07199d8924373d3c52a207f63b (patch)
treef8fe8788f068105ea71719e0c942b2ac6d1d599d
parent4fc62a89dc607cee4f75f6dbb102cd6215fd0d64 (diff)
perf tools: Deal with kernel module names in '[]' correctly
Before patch ba92732e9808 ('perf kmaps: Check kmaps to make code more robust'), 'perf report' and 'perf annotate' will segfault if trace data contains kernel module information like this: # perf report -D -i ./perf.data ... 0 0 0x188 [0x50]: PERF_RECORD_MMAP -1/0: [0xffffffbff1018000(0xf068000) @ 0]: x [test_module] ... # perf report -i ./perf.data --objdump=/path/to/objdump --kallsyms=/path/to/kallsyms perf: Segmentation fault -------- backtrace -------- /path/to/perf[0x503478] /lib64/libc.so.6(+0x3545f)[0x7fb201f3745f] /path/to/perf[0x499b56] /path/to/perf(dso__load_kallsyms+0x13c)[0x49b56c] /path/to/perf(dso__load+0x72e)[0x49c21e] /path/to/perf(map__load+0x6e)[0x4ae9ee] /path/to/perf(thread__find_addr_map+0x24c)[0x47deec] /path/to/perf(perf_event__preprocess_sample+0x88)[0x47e238] /path/to/perf[0x43ad02] /path/to/perf[0x4b55bc] /path/to/perf(ordered_events__flush+0xca)[0x4b57ea] /path/to/perf[0x4b1a01] /path/to/perf(perf_session__process_events+0x3be)[0x4b428e] /path/to/perf(cmd_report+0xf11)[0x43bfc1] /path/to/perf[0x474702] /path/to/perf(main+0x5f5)[0x42de95] /lib64/libc.so.6(__libc_start_main+0xf4)[0x7fb201f23bd4] /path/to/perf[0x42dfc4] This is because __kmod_path__parse treats '[' leading names as kernel name instead of names of kernel module. If perf.data contains build information and the buildid of such modules can be found, the dso->kernel of it will be set to DSO_TYPE_KERNEL by __event_process_build_id(), not kernel module. It will then be passed to dso__load() -> dso__load_kernel_sym() -> dso__load_kcore() if --kallsyms is provided. The refered patch adds NULL pointer checker to avoid segfault. However, such kernel modules are still processed incorrectly. This patch fixes __kmod_path__parse, makes it treat names like '[test_module]' as kernel modules. kmod-path.c is also update to reflect the above changes. Signed-off-by: Wang Nan <wangnan0@huawei.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Zefan Li <lizefan@huawei.com> Link: http://lkml.kernel.org/r/1433321541-170245-1-git-send-email-wangnan0@huawei.com [ Fixed the merged with 0443f36b0de0 ("perf machine: Fix the search for the kernel DSO on the unified list" ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/tests/kmod-path.c72
-rw-r--r--tools/perf/util/dso.c47
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/header.c8
-rw-r--r--tools/perf/util/machine.c22
5 files changed, 140 insertions, 11 deletions
diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c
index e8d7cbb9320c..08c433b4bf4f 100644
--- a/tools/perf/tests/kmod-path.c
+++ b/tools/perf/tests/kmod-path.c
@@ -34,9 +34,21 @@ static int test(const char *path, bool alloc_name, bool alloc_ext,
34 return 0; 34 return 0;
35} 35}
36 36
37static int test_is_kernel_module(const char *path, int cpumode, bool expect)
38{
39 TEST_ASSERT_VAL("is_kernel_module",
40 (!!is_kernel_module(path, cpumode)) == (!!expect));
41 pr_debug("%s (cpumode: %d) - is_kernel_module: %s\n",
42 path, cpumode, expect ? "true" : "false");
43 return 0;
44}
45
37#define T(path, an, ae, k, c, n, e) \ 46#define T(path, an, ae, k, c, n, e) \
38 TEST_ASSERT_VAL("failed", !test(path, an, ae, k, c, n, e)) 47 TEST_ASSERT_VAL("failed", !test(path, an, ae, k, c, n, e))
39 48
49#define M(path, c, e) \
50 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e))
51
40int test__kmod_path__parse(void) 52int test__kmod_path__parse(void)
41{ 53{
42 /* path alloc_name alloc_ext kmod comp name ext */ 54 /* path alloc_name alloc_ext kmod comp name ext */
@@ -44,30 +56,90 @@ int test__kmod_path__parse(void)
44 T("/xxxx/xxxx/x-x.ko", false , true , true, false, NULL , NULL); 56 T("/xxxx/xxxx/x-x.ko", false , true , true, false, NULL , NULL);
45 T("/xxxx/xxxx/x-x.ko", true , false , true, false, "[x_x]", NULL); 57 T("/xxxx/xxxx/x-x.ko", true , false , true, false, "[x_x]", NULL);
46 T("/xxxx/xxxx/x-x.ko", false , false , true, false, NULL , NULL); 58 T("/xxxx/xxxx/x-x.ko", false , false , true, false, NULL , NULL);
59 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
60 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true);
61 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false);
47 62
48 /* path alloc_name alloc_ext kmod comp name ext */ 63 /* path alloc_name alloc_ext kmod comp name ext */
49 T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz"); 64 T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz");
50 T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz"); 65 T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz");
51 T("/xxxx/xxxx/x.ko.gz", true , false , true, true, "[x]", NULL); 66 T("/xxxx/xxxx/x.ko.gz", true , false , true, true, "[x]", NULL);
52 T("/xxxx/xxxx/x.ko.gz", false , false , true, true, NULL , NULL); 67 T("/xxxx/xxxx/x.ko.gz", false , false , true, true, NULL , NULL);
68 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
69 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_KERNEL, true);
70 M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_USER, false);
53 71
54 /* path alloc_name alloc_ext kmod comp name ext */ 72 /* path alloc_name alloc_ext kmod comp name ext */
55 T("/xxxx/xxxx/x.gz", true , true , false, true, "x.gz" ,"gz"); 73 T("/xxxx/xxxx/x.gz", true , true , false, true, "x.gz" ,"gz");
56 T("/xxxx/xxxx/x.gz", false , true , false, true, NULL ,"gz"); 74 T("/xxxx/xxxx/x.gz", false , true , false, true, NULL ,"gz");
57 T("/xxxx/xxxx/x.gz", true , false , false, true, "x.gz" , NULL); 75 T("/xxxx/xxxx/x.gz", true , false , false, true, "x.gz" , NULL);
58 T("/xxxx/xxxx/x.gz", false , false , false, true, NULL , NULL); 76 T("/xxxx/xxxx/x.gz", false , false , false, true, NULL , NULL);
77 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
78 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_KERNEL, false);
79 M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_USER, false);
59 80
60 /* path alloc_name alloc_ext kmod comp name ext */ 81 /* path alloc_name alloc_ext kmod comp name ext */
61 T("x.gz", true , true , false, true, "x.gz", "gz"); 82 T("x.gz", true , true , false, true, "x.gz", "gz");
62 T("x.gz", false , true , false, true, NULL , "gz"); 83 T("x.gz", false , true , false, true, NULL , "gz");
63 T("x.gz", true , false , false, true, "x.gz", NULL); 84 T("x.gz", true , false , false, true, "x.gz", NULL);
64 T("x.gz", false , false , false, true, NULL , NULL); 85 T("x.gz", false , false , false, true, NULL , NULL);
86 M("x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
87 M("x.gz", PERF_RECORD_MISC_KERNEL, false);
88 M("x.gz", PERF_RECORD_MISC_USER, false);
65 89
66 /* path alloc_name alloc_ext kmod comp name ext */ 90 /* path alloc_name alloc_ext kmod comp name ext */
67 T("x.ko.gz", true , true , true, true, "[x]", "gz"); 91 T("x.ko.gz", true , true , true, true, "[x]", "gz");
68 T("x.ko.gz", false , true , true, true, NULL , "gz"); 92 T("x.ko.gz", false , true , true, true, NULL , "gz");
69 T("x.ko.gz", true , false , true, true, "[x]", NULL); 93 T("x.ko.gz", true , false , true, true, "[x]", NULL);
70 T("x.ko.gz", false , false , true, true, NULL , NULL); 94 T("x.ko.gz", false , false , true, true, NULL , NULL);
95 M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
96 M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true);
97 M("x.ko.gz", PERF_RECORD_MISC_USER, false);
98
99 /* path alloc_name alloc_ext kmod comp name ext */
100 T("[test_module]", true , true , true, false, "[test_module]", NULL);
101 T("[test_module]", false , true , true, false, NULL , NULL);
102 T("[test_module]", true , false , true, false, "[test_module]", NULL);
103 T("[test_module]", false , false , true, false, NULL , NULL);
104 M("[test_module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
105 M("[test_module]", PERF_RECORD_MISC_KERNEL, true);
106 M("[test_module]", PERF_RECORD_MISC_USER, false);
107
108 /* path alloc_name alloc_ext kmod comp name ext */
109 T("[test.module]", true , true , true, false, "[test.module]", NULL);
110 T("[test.module]", false , true , true, false, NULL , NULL);
111 T("[test.module]", true , false , true, false, "[test.module]", NULL);
112 T("[test.module]", false , false , true, false, NULL , NULL);
113 M("[test.module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
114 M("[test.module]", PERF_RECORD_MISC_KERNEL, true);
115 M("[test.module]", PERF_RECORD_MISC_USER, false);
116
117 /* path alloc_name alloc_ext kmod comp name ext */
118 T("[vdso]", true , true , false, false, "[vdso]", NULL);
119 T("[vdso]", false , true , false, false, NULL , NULL);
120 T("[vdso]", true , false , false, false, "[vdso]", NULL);
121 T("[vdso]", false , false , false, false, NULL , NULL);
122 M("[vdso]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
123 M("[vdso]", PERF_RECORD_MISC_KERNEL, false);
124 M("[vdso]", PERF_RECORD_MISC_USER, false);
125
126 /* path alloc_name alloc_ext kmod comp name ext */
127 T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL);
128 T("[vsyscall]", false , true , false, false, NULL , NULL);
129 T("[vsyscall]", true , false , false, false, "[vsyscall]", NULL);
130 T("[vsyscall]", false , false , false, false, NULL , NULL);
131 M("[vsyscall]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
132 M("[vsyscall]", PERF_RECORD_MISC_KERNEL, false);
133 M("[vsyscall]", PERF_RECORD_MISC_USER, false);
134
135 /* path alloc_name alloc_ext kmod comp name ext */
136 T("[kernel.kallsyms]", true , true , false, false, "[kernel.kallsyms]", NULL);
137 T("[kernel.kallsyms]", false , true , false, false, NULL , NULL);
138 T("[kernel.kallsyms]", true , false , false, false, "[kernel.kallsyms]", NULL);
139 T("[kernel.kallsyms]", false , false , false, false, NULL , NULL);
140 M("[kernel.kallsyms]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
141 M("[kernel.kallsyms]", PERF_RECORD_MISC_KERNEL, false);
142 M("[kernel.kallsyms]", PERF_RECORD_MISC_USER, false);
71 143
72 return 0; 144 return 0;
73} 145}
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index b335db3532a2..5ec9e892c89b 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -166,12 +166,28 @@ bool is_supported_compression(const char *ext)
166 return false; 166 return false;
167} 167}
168 168
169bool is_kernel_module(const char *pathname) 169bool is_kernel_module(const char *pathname, int cpumode)
170{ 170{
171 struct kmod_path m; 171 struct kmod_path m;
172 172 int mode = cpumode & PERF_RECORD_MISC_CPUMODE_MASK;
173 if (kmod_path__parse(&m, pathname)) 173
174 return NULL; 174 WARN_ONCE(mode != cpumode,
175 "Internal error: passing unmasked cpumode (%x) to is_kernel_module",
176 cpumode);
177
178 switch (mode) {
179 case PERF_RECORD_MISC_USER:
180 case PERF_RECORD_MISC_HYPERVISOR:
181 case PERF_RECORD_MISC_GUEST_USER:
182 return false;
183 /* Treat PERF_RECORD_MISC_CPUMODE_UNKNOWN as kernel */
184 default:
185 if (kmod_path__parse(&m, pathname)) {
186 pr_err("Failed to check whether %s is a kernel module or not. Assume it is.",
187 pathname);
188 return true;
189 }
190 }
175 191
176 return m.kmod; 192 return m.kmod;
177} 193}
@@ -215,12 +231,33 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
215{ 231{
216 const char *name = strrchr(path, '/'); 232 const char *name = strrchr(path, '/');
217 const char *ext = strrchr(path, '.'); 233 const char *ext = strrchr(path, '.');
234 bool is_simple_name = false;
218 235
219 memset(m, 0x0, sizeof(*m)); 236 memset(m, 0x0, sizeof(*m));
220 name = name ? name + 1 : path; 237 name = name ? name + 1 : path;
221 238
239 /*
240 * '.' is also a valid character for module name. For example:
241 * [aaa.bbb] is a valid module name. '[' should have higher
242 * priority than '.ko' suffix.
243 *
244 * The kernel names are from machine__mmap_name. Such
245 * name should belong to kernel itself, not kernel module.
246 */
247 if (name[0] == '[') {
248 is_simple_name = true;
249 if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) ||
250 (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) ||
251 (strncmp(name, "[vdso]", 6) == 0) ||
252 (strncmp(name, "[vsyscall]", 10) == 0)) {
253 m->kmod = false;
254
255 } else
256 m->kmod = true;
257 }
258
222 /* No extension, just return name. */ 259 /* No extension, just return name. */
223 if (ext == NULL) { 260 if ((ext == NULL) || is_simple_name) {
224 if (alloc_name) { 261 if (alloc_name) {
225 m->name = strdup(name); 262 m->name = strdup(name);
226 return m->name ? 0 : -ENOMEM; 263 return m->name ? 0 : -ENOMEM;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 24a507a54147..ba2d90ed881f 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -220,7 +220,7 @@ char dso__symtab_origin(const struct dso *dso);
220int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 220int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
221 char *root_dir, char *filename, size_t size); 221 char *root_dir, char *filename, size_t size);
222bool is_supported_compression(const char *ext); 222bool is_supported_compression(const char *ext);
223bool is_kernel_module(const char *pathname); 223bool is_kernel_module(const char *pathname, int cpumode);
224bool decompress_to_file(const char *ext, const char *filename, int output_fd); 224bool decompress_to_file(const char *ext, const char *filename, int output_fd);
225bool dso__needs_decompress(struct dso *dso); 225bool dso__needs_decompress(struct dso *dso);
226 226
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 851143a7988d..ac5aaaeed7ff 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1239,7 +1239,7 @@ static int __event_process_build_id(struct build_id_event *bev,
1239{ 1239{
1240 int err = -1; 1240 int err = -1;
1241 struct machine *machine; 1241 struct machine *machine;
1242 u16 misc; 1242 u16 cpumode;
1243 struct dso *dso; 1243 struct dso *dso;
1244 enum dso_kernel_type dso_type; 1244 enum dso_kernel_type dso_type;
1245 1245
@@ -1247,9 +1247,9 @@ static int __event_process_build_id(struct build_id_event *bev,
1247 if (!machine) 1247 if (!machine)
1248 goto out; 1248 goto out;
1249 1249
1250 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1250 cpumode = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1251 1251
1252 switch (misc) { 1252 switch (cpumode) {
1253 case PERF_RECORD_MISC_KERNEL: 1253 case PERF_RECORD_MISC_KERNEL:
1254 dso_type = DSO_TYPE_KERNEL; 1254 dso_type = DSO_TYPE_KERNEL;
1255 break; 1255 break;
@@ -1270,7 +1270,7 @@ static int __event_process_build_id(struct build_id_event *bev,
1270 1270
1271 dso__set_build_id(dso, &bev->build_id); 1271 dso__set_build_id(dso, &bev->build_id);
1272 1272
1273 if (!is_kernel_module(filename)) 1273 if (!is_kernel_module(filename, cpumode))
1274 dso->kernel = dso_type; 1274 dso->kernel = dso_type;
1275 1275
1276 build_id__sprintf(dso->build_id, sizeof(dso->build_id), 1276 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 4e29e80932e5..9e02c86f39f5 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1149,9 +1149,29 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
1149 struct dso *dso; 1149 struct dso *dso;
1150 1150
1151 list_for_each_entry(dso, &machine->dsos.head, node) { 1151 list_for_each_entry(dso, &machine->dsos.head, node) {
1152 if (!dso->kernel || is_kernel_module(dso->long_name)) 1152
1153 /*
1154 * The cpumode passed to is_kernel_module is not the
1155 * cpumode of *this* event. If we insist on passing
1156 * correct cpumode to is_kernel_module, we should
1157 * record the cpumode when we adding this dso to the
1158 * linked list.
1159 *
1160 * However we don't really need passing correct
1161 * cpumode. We know the correct cpumode must be kernel
1162 * mode (if not, we should not link it onto kernel_dsos
1163 * list).
1164 *
1165 * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
1166 * is_kernel_module() treats it as a kernel cpumode.
1167 */
1168
1169 if (!dso->kernel ||
1170 is_kernel_module(dso->long_name,
1171 PERF_RECORD_MISC_CPUMODE_UNKNOWN))
1153 continue; 1172 continue;
1154 1173
1174
1155 kernel = dso; 1175 kernel = dso;
1156 break; 1176 break;
1157 } 1177 }