Skip to content

Commit fc1b691

Browse files
ahunter6acmel
authored andcommitted
perf buildid-cache: Add ability to add kcore to the cache
kcore can be used to view the running kernel object code. However, kcore changes as modules are loaded and unloaded, and when the kernel decides to modify its own code. Consequently it is useful to create a copy of kcore at a particular time. Unlike vmlinux, kcore is not unique for a given build-id. And in addition, the kallsyms and modules files are also needed. The tool therefore creates a directory: ~/.debug/[kernel.kcore]/<build-id>/<YYYYmmddHHMMSShh> which contains: kcore, kallsyms and modules. Note that the copied kcore contains only code sections. See the kcore_copy() function for how that is determined. The tool will not make additional copies of kcore if there is already one with the same modules at the same addresses. Currently, perf tools will not look for kcore in the cache. That is addressed in another patch. Signed-off-by: Adrian Hunter <[email protected]> Cc: David Ahern <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Link: http://lkml.kernel.org/r/[email protected] [ renamed 'index' to 'idx' to avoid shadowing string.h symbol in f12, use at least one member initializer when initializing a struct to zeros, also to fix the build on f12 ] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 1179e11 commit fc1b691

File tree

6 files changed

+576
-1
lines changed

6 files changed

+576
-1
lines changed

tools/perf/Documentation/perf-buildid-cache.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ OPTIONS
2121
-a::
2222
--add=::
2323
Add specified file to the cache.
24+
-k::
25+
--kcore::
26+
Add specified kcore file to the cache. For the current host that is
27+
/proc/kcore which requires root permissions to read. Be aware that
28+
running 'perf buildid-cache' as root may update root's build-id cache
29+
not the user's. Use the -v option to see where the file is created.
30+
Note that the copied file contains only code sections not the whole core
31+
image. Note also that files "kallsyms" and "modules" must also be in the
32+
same directory and are also copied. All 3 files are created with read
33+
permissions for root only. kcore will not be added if there is already a
34+
kcore in the cache (with the same build-id) that has the same modules at
35+
the same addresses. Use the -v option to see if a copy of kcore is
36+
actually made.
2437
-r::
2538
--remove=::
2639
Remove specified file from the cache.

tools/perf/builtin-buildid-cache.c

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
* Copyright (C) 2010, Red Hat Inc.
77
* Copyright (C) 2010, Arnaldo Carvalho de Melo <[email protected]>
88
*/
9+
#include <sys/types.h>
10+
#include <sys/time.h>
11+
#include <time.h>
12+
#include <dirent.h>
13+
#include <unistd.h>
914
#include "builtin.h"
1015
#include "perf.h"
1116
#include "util/cache.h"
@@ -17,6 +22,140 @@
1722
#include "util/session.h"
1823
#include "util/symbol.h"
1924

25+
static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
26+
{
27+
char root_dir[PATH_MAX];
28+
char notes[PATH_MAX];
29+
u8 build_id[BUILD_ID_SIZE];
30+
char *p;
31+
32+
strlcpy(root_dir, proc_dir, sizeof(root_dir));
33+
34+
p = strrchr(root_dir, '/');
35+
if (!p)
36+
return -1;
37+
*p = '\0';
38+
39+
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
40+
41+
if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
42+
return -1;
43+
44+
build_id__sprintf(build_id, sizeof(build_id), sbuildid);
45+
46+
return 0;
47+
}
48+
49+
static int build_id_cache__kcore_dir(char *dir, size_t sz)
50+
{
51+
struct timeval tv;
52+
struct tm tm;
53+
char dt[32];
54+
55+
if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
56+
return -1;
57+
58+
if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
59+
return -1;
60+
61+
scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
62+
63+
return 0;
64+
}
65+
66+
static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
67+
size_t to_dir_sz)
68+
{
69+
char from[PATH_MAX];
70+
char to[PATH_MAX];
71+
struct dirent *dent;
72+
int ret = -1;
73+
DIR *d;
74+
75+
d = opendir(to_dir);
76+
if (!d)
77+
return -1;
78+
79+
scnprintf(from, sizeof(from), "%s/modules", from_dir);
80+
81+
while (1) {
82+
dent = readdir(d);
83+
if (!dent)
84+
break;
85+
if (dent->d_type != DT_DIR)
86+
continue;
87+
scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
88+
dent->d_name);
89+
if (!compare_proc_modules(from, to)) {
90+
scnprintf(to, sizeof(to), "%s/%s", to_dir,
91+
dent->d_name);
92+
strlcpy(to_dir, to, to_dir_sz);
93+
ret = 0;
94+
break;
95+
}
96+
}
97+
98+
closedir(d);
99+
100+
return ret;
101+
}
102+
103+
static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
104+
{
105+
char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
106+
char from_dir[PATH_MAX], to_dir[PATH_MAX];
107+
char *p;
108+
109+
strlcpy(from_dir, filename, sizeof(from_dir));
110+
111+
p = strrchr(from_dir, '/');
112+
if (!p || strcmp(p + 1, "kcore"))
113+
return -1;
114+
*p = '\0';
115+
116+
if (build_id_cache__kcore_buildid(from_dir, sbuildid))
117+
return -1;
118+
119+
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
120+
debugdir, sbuildid);
121+
122+
if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
123+
pr_debug("same kcore found in %s\n", to_dir);
124+
return 0;
125+
}
126+
127+
if (build_id_cache__kcore_dir(dir, sizeof(dir)))
128+
return -1;
129+
130+
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
131+
debugdir, sbuildid, dir);
132+
133+
if (mkdir_p(to_dir, 0755))
134+
return -1;
135+
136+
if (kcore_copy(from_dir, to_dir)) {
137+
/* Remove YYYYmmddHHMMSShh directory */
138+
if (!rmdir(to_dir)) {
139+
p = strrchr(to_dir, '/');
140+
if (p)
141+
*p = '\0';
142+
/* Try to remove buildid directory */
143+
if (!rmdir(to_dir)) {
144+
p = strrchr(to_dir, '/');
145+
if (p)
146+
*p = '\0';
147+
/* Try to remove [kernel.kcore] directory */
148+
rmdir(to_dir);
149+
}
150+
}
151+
return -1;
152+
}
153+
154+
pr_debug("kcore added to build-id cache directory %s\n", to_dir);
155+
156+
return 0;
157+
}
158+
20159
static int build_id_cache__add_file(const char *filename, const char *debugdir)
21160
{
22161
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -130,11 +269,14 @@ int cmd_buildid_cache(int argc, const char **argv,
130269
char const *add_name_list_str = NULL,
131270
*remove_name_list_str = NULL,
132271
*missing_filename = NULL,
133-
*update_name_list_str = NULL;
272+
*update_name_list_str = NULL,
273+
*kcore_filename;
134274

135275
const struct option buildid_cache_options[] = {
136276
OPT_STRING('a', "add", &add_name_list_str,
137277
"file list", "file(s) to add"),
278+
OPT_STRING('k', "kcore", &kcore_filename,
279+
"file", "kcore file to add"),
138280
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
139281
"file(s) to remove"),
140282
OPT_STRING('M', "missing", &missing_filename, "file",
@@ -217,5 +359,9 @@ int cmd_buildid_cache(int argc, const char **argv,
217359
}
218360
}
219361

362+
if (kcore_filename &&
363+
build_id_cache__add_kcore(kcore_filename, debugdir))
364+
pr_warning("Couldn't add %s\n", kcore_filename);
365+
220366
return ret;
221367
}

0 commit comments

Comments
 (0)