aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrister Johansen <kjlx@templeofstupid.com>2017-07-05 21:48:09 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-07-18 22:14:09 -0400
commitbf2e710b3cb8445c052f2ff50b4875a2523bb279 (patch)
tree404a86734bb7b7275638b1d5c7a49a136d6e4766
parent843ff37bb59edbe51d64e77ba1b3245a15a4dd9f (diff)
perf maps: Lookup maps in both intitial mountns and inner mountns.
If a process is in a mountns and has symbols in /tmp/perf-<pid>.map, look first in the namespace using the tgid for the pidns that the process might be in. If the map isn't found there, try looking in the mountns where perf is running, and use the tgid that's appropriate for perf's pid namespace. If all else fails, use the original pid. This allows us to locate a symbol map file in the mount namespace, if it was generated there. However, we also try the tool's /tmp in case it's there instead. Signed-off-by: Krister Johansen <kjlx@templeofstupid.com> Tested-by: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com> Link: http://lkml.kernel.org/r/1499305693-1599-3-git-send-email-kjlx@templeofstupid.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/machine.c4
-rw-r--r--tools/perf/util/map.c23
-rw-r--r--tools/perf/util/map.h2
-rw-r--r--tools/perf/util/namespaces.c83
-rw-r--r--tools/perf/util/namespaces.h5
-rw-r--r--tools/perf/util/symbol.c70
6 files changed, 160 insertions, 27 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 2e9eb6aa3ce2..246b441110a1 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1392,7 +1392,7 @@ int machine__process_mmap2_event(struct machine *machine,
1392 1392
1393 map = map__new(machine, event->mmap2.start, 1393 map = map__new(machine, event->mmap2.start,
1394 event->mmap2.len, event->mmap2.pgoff, 1394 event->mmap2.len, event->mmap2.pgoff,
1395 event->mmap2.pid, event->mmap2.maj, 1395 event->mmap2.maj,
1396 event->mmap2.min, event->mmap2.ino, 1396 event->mmap2.min, event->mmap2.ino,
1397 event->mmap2.ino_generation, 1397 event->mmap2.ino_generation,
1398 event->mmap2.prot, 1398 event->mmap2.prot,
@@ -1450,7 +1450,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1450 1450
1451 map = map__new(machine, event->mmap.start, 1451 map = map__new(machine, event->mmap.start,
1452 event->mmap.len, event->mmap.pgoff, 1452 event->mmap.len, event->mmap.pgoff,
1453 event->mmap.pid, 0, 0, 0, 0, 0, 0, 1453 0, 0, 0, 0, 0, 0,
1454 event->mmap.filename, 1454 event->mmap.filename,
1455 type, thread); 1455 type, thread);
1456 1456
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 5dc60ca5a294..bdaa0a4edc17 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -146,11 +146,13 @@ void map__init(struct map *map, enum map_type type,
146} 146}
147 147
148struct map *map__new(struct machine *machine, u64 start, u64 len, 148struct map *map__new(struct machine *machine, u64 start, u64 len,
149 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 149 u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
150 u64 ino_gen, u32 prot, u32 flags, char *filename, 150 u64 ino_gen, u32 prot, u32 flags, char *filename,
151 enum map_type type, struct thread *thread) 151 enum map_type type, struct thread *thread)
152{ 152{
153 struct map *map = malloc(sizeof(*map)); 153 struct map *map = malloc(sizeof(*map));
154 struct nsinfo *nsi = NULL;
155 struct nsinfo *nnsi;
154 156
155 if (map != NULL) { 157 if (map != NULL) {
156 char newfilename[PATH_MAX]; 158 char newfilename[PATH_MAX];
@@ -168,9 +170,11 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
168 map->ino_generation = ino_gen; 170 map->ino_generation = ino_gen;
169 map->prot = prot; 171 map->prot = prot;
170 map->flags = flags; 172 map->flags = flags;
173 nsi = nsinfo__get(thread->nsinfo);
171 174
172 if ((anon || no_dso) && type == MAP__FUNCTION) { 175 if ((anon || no_dso) && nsi && type == MAP__FUNCTION) {
173 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 176 snprintf(newfilename, sizeof(newfilename),
177 "/tmp/perf-%d.map", nsi->pid);
174 filename = newfilename; 178 filename = newfilename;
175 } 179 }
176 180
@@ -180,6 +184,16 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
180 } 184 }
181 185
182 if (vdso) { 186 if (vdso) {
187 /* The vdso maps are always on the host and not the
188 * container. Ensure that we don't use setns to look
189 * them up.
190 */
191 nnsi = nsinfo__copy(nsi);
192 if (nnsi) {
193 nsinfo__put(nsi);
194 nnsi->need_setns = false;
195 nsi = nnsi;
196 }
183 pgoff = 0; 197 pgoff = 0;
184 dso = machine__findnew_vdso(machine, thread); 198 dso = machine__findnew_vdso(machine, thread);
185 } else 199 } else
@@ -201,11 +215,12 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
201 if (type != MAP__FUNCTION) 215 if (type != MAP__FUNCTION)
202 dso__set_loaded(dso, map->type); 216 dso__set_loaded(dso, map->type);
203 } 217 }
204 dso->nsinfo = nsinfo__get(thread->nsinfo); 218 dso->nsinfo = nsi;
205 dso__put(dso); 219 dso__put(dso);
206 } 220 }
207 return map; 221 return map;
208out_delete: 222out_delete:
223 nsinfo__put(nsi);
209 free(map); 224 free(map);
210 return NULL; 225 return NULL;
211} 226}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f9e8ac8a52cd..73aacf7a7dc4 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -141,7 +141,7 @@ struct thread;
141void map__init(struct map *map, enum map_type type, 141void map__init(struct map *map, enum map_type type,
142 u64 start, u64 end, u64 pgoff, struct dso *dso); 142 u64 start, u64 end, u64 pgoff, struct dso *dso);
143struct map *map__new(struct machine *machine, u64 start, u64 len, 143struct map *map__new(struct machine *machine, u64 start, u64 len,
144 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 144 u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
145 u64 ino_gen, u32 prot, u32 flags, 145 u64 ino_gen, u32 prot, u32 flags,
146 char *filename, enum map_type type, struct thread *thread); 146 char *filename, enum map_type type, struct thread *thread);
147struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 147struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
index bcc6bb19cf10..fc5f398779a4 100644
--- a/tools/perf/util/namespaces.c
+++ b/tools/perf/util/namespaces.c
@@ -40,18 +40,23 @@ void namespaces__free(struct namespaces *namespaces)
40 free(namespaces); 40 free(namespaces);
41} 41}
42 42
43void nsinfo__init(struct nsinfo *nsi) 43int nsinfo__init(struct nsinfo *nsi)
44{ 44{
45 char oldns[PATH_MAX]; 45 char oldns[PATH_MAX];
46 char spath[PATH_MAX];
46 char *newns = NULL; 47 char *newns = NULL;
48 char *statln = NULL;
47 struct stat old_stat; 49 struct stat old_stat;
48 struct stat new_stat; 50 struct stat new_stat;
51 FILE *f = NULL;
52 size_t linesz = 0;
53 int rv = -1;
49 54
50 if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX) 55 if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
51 return; 56 return rv;
52 57
53 if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1) 58 if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
54 return; 59 return rv;
55 60
56 if (stat(oldns, &old_stat) < 0) 61 if (stat(oldns, &old_stat) < 0)
57 goto out; 62 goto out;
@@ -68,24 +73,89 @@ void nsinfo__init(struct nsinfo *nsi)
68 newns = NULL; 73 newns = NULL;
69 } 74 }
70 75
76 /* If we're dealing with a process that is in a different PID namespace,
77 * attempt to work out the innermost tgid for the process.
78 */
79 if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsi->pid) >= PATH_MAX)
80 goto out;
81
82 f = fopen(spath, "r");
83 if (f == NULL)
84 goto out;
85
86 while (getline(&statln, &linesz, f) != -1) {
87 /* Use tgid if CONFIG_PID_NS is not defined. */
88 if (strstr(statln, "Tgid:") != NULL) {
89 nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
90 NULL, 10);
91 nsi->nstgid = nsi->tgid;
92 }
93
94 if (strstr(statln, "NStgid:") != NULL) {
95 nsi->nstgid = (pid_t)strtol(strrchr(statln, '\t'),
96 NULL, 10);
97 break;
98 }
99 }
100 rv = 0;
101
71out: 102out:
103 if (f != NULL)
104 (void) fclose(f);
105 free(statln);
72 free(newns); 106 free(newns);
107 return rv;
73} 108}
74 109
75struct nsinfo *nsinfo__new(pid_t pid) 110struct nsinfo *nsinfo__new(pid_t pid)
76{ 111{
77 struct nsinfo *nsi = calloc(1, sizeof(*nsi)); 112 struct nsinfo *nsi;
78 113
114 if (pid == 0)
115 return NULL;
116
117 nsi = calloc(1, sizeof(*nsi));
79 if (nsi != NULL) { 118 if (nsi != NULL) {
80 nsi->pid = pid; 119 nsi->pid = pid;
120 nsi->tgid = pid;
121 nsi->nstgid = pid;
81 nsi->need_setns = false; 122 nsi->need_setns = false;
82 nsinfo__init(nsi); 123 /* Init may fail if the process exits while we're trying to look
124 * at its proc information. In that case, save the pid but
125 * don't try to enter the namespace.
126 */
127 if (nsinfo__init(nsi) == -1)
128 nsi->need_setns = false;
129
83 refcount_set(&nsi->refcnt, 1); 130 refcount_set(&nsi->refcnt, 1);
84 } 131 }
85 132
86 return nsi; 133 return nsi;
87} 134}
88 135
136struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
137{
138 struct nsinfo *nnsi;
139
140 nnsi = calloc(1, sizeof(*nnsi));
141 if (nnsi != NULL) {
142 nnsi->pid = nsi->pid;
143 nnsi->tgid = nsi->tgid;
144 nnsi->nstgid = nsi->nstgid;
145 nnsi->need_setns = nsi->need_setns;
146 if (nsi->mntns_path) {
147 nnsi->mntns_path = strdup(nsi->mntns_path);
148 if (!nnsi->mntns_path) {
149 free(nnsi);
150 return NULL;
151 }
152 }
153 refcount_set(&nnsi->refcnt, 1);
154 }
155
156 return nnsi;
157}
158
89void nsinfo__delete(struct nsinfo *nsi) 159void nsinfo__delete(struct nsinfo *nsi)
90{ 160{
91 zfree(&nsi->mntns_path); 161 zfree(&nsi->mntns_path);
@@ -105,7 +175,8 @@ void nsinfo__put(struct nsinfo *nsi)
105 nsinfo__delete(nsi); 175 nsinfo__delete(nsi);
106} 176}
107 177
108void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc) 178void nsinfo__mountns_enter(struct nsinfo *nsi,
179 struct nscookie *nc)
109{ 180{
110 char curpath[PATH_MAX]; 181 char curpath[PATH_MAX];
111 int oldns = -1; 182 int oldns = -1;
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
index b20f6ead7b2d..f19aa41119ae 100644
--- a/tools/perf/util/namespaces.h
+++ b/tools/perf/util/namespaces.h
@@ -26,6 +26,8 @@ void namespaces__free(struct namespaces *namespaces);
26 26
27struct nsinfo { 27struct nsinfo {
28 pid_t pid; 28 pid_t pid;
29 pid_t tgid;
30 pid_t nstgid;
29 bool need_setns; 31 bool need_setns;
30 char *mntns_path; 32 char *mntns_path;
31 refcount_t refcnt; 33 refcount_t refcnt;
@@ -36,8 +38,9 @@ struct nscookie {
36 int newns; 38 int newns;
37}; 39};
38 40
39void nsinfo__init(struct nsinfo *nsi); 41int nsinfo__init(struct nsinfo *nsi);
40struct nsinfo *nsinfo__new(pid_t pid); 42struct nsinfo *nsinfo__new(pid_t pid);
43struct nsinfo *nsinfo__copy(struct nsinfo *nsi);
41void nsinfo__delete(struct nsinfo *nsi); 44void nsinfo__delete(struct nsinfo *nsi);
42 45
43struct nsinfo *nsinfo__get(struct nsinfo *nsi); 46struct nsinfo *nsinfo__get(struct nsinfo *nsi);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 60a9eaa372ef..21c97cc41cfc 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -19,7 +19,6 @@
19#include "strlist.h" 19#include "strlist.h"
20#include "intlist.h" 20#include "intlist.h"
21#include "namespaces.h" 21#include "namespaces.h"
22#include "vdso.h"
23#include "header.h" 22#include "header.h"
24#include "path.h" 23#include "path.h"
25#include "sane_ctype.h" 24#include "sane_ctype.h"
@@ -1327,14 +1326,15 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
1327 return __dso__load_kallsyms(dso, filename, map, false); 1326 return __dso__load_kallsyms(dso, filename, map, false);
1328} 1327}
1329 1328
1330static int dso__load_perf_map(struct dso *dso, struct map *map) 1329static int dso__load_perf_map(const char *map_path, struct dso *dso,
1330 struct map *map)
1331{ 1331{
1332 char *line = NULL; 1332 char *line = NULL;
1333 size_t n; 1333 size_t n;
1334 FILE *file; 1334 FILE *file;
1335 int nr_syms = 0; 1335 int nr_syms = 0;
1336 1336
1337 file = fopen(dso->long_name, "r"); 1337 file = fopen(map_path, "r");
1338 if (file == NULL) 1338 if (file == NULL)
1339 goto out_failure; 1339 goto out_failure;
1340 1340
@@ -1426,6 +1426,45 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
1426 } 1426 }
1427} 1427}
1428 1428
1429/* Checks for the existence of the perf-<pid>.map file in two different
1430 * locations. First, if the process is a separate mount namespace, check in
1431 * that namespace using the pid of the innermost pid namespace. If's not in a
1432 * namespace, or the file can't be found there, try in the mount namespace of
1433 * the tracing process using our view of its pid.
1434 */
1435static int dso__find_perf_map(char *filebuf, size_t bufsz,
1436 struct nsinfo **nsip)
1437{
1438 struct nscookie nsc;
1439 struct nsinfo *nsi;
1440 struct nsinfo *nnsi;
1441 int rc = -1;
1442
1443 nsi = *nsip;
1444
1445 if (nsi->need_setns) {
1446 snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid);
1447 nsinfo__mountns_enter(nsi, &nsc);
1448 rc = access(filebuf, R_OK);
1449 nsinfo__mountns_exit(&nsc);
1450 if (rc == 0)
1451 return rc;
1452 }
1453
1454 nnsi = nsinfo__copy(nsi);
1455 if (nnsi) {
1456 nsinfo__put(nsi);
1457
1458 nnsi->need_setns = false;
1459 snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid);
1460 *nsip = nnsi;
1461 rc = 0;
1462 }
1463
1464 return rc;
1465}
1466
1467
1429int dso__load(struct dso *dso, struct map *map) 1468int dso__load(struct dso *dso, struct map *map)
1430{ 1469{
1431 char *name; 1470 char *name;
@@ -1437,18 +1476,23 @@ int dso__load(struct dso *dso, struct map *map)
1437 struct symsrc ss_[2]; 1476 struct symsrc ss_[2];
1438 struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 1477 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
1439 bool kmod; 1478 bool kmod;
1479 bool perfmap;
1440 unsigned char build_id[BUILD_ID_SIZE]; 1480 unsigned char build_id[BUILD_ID_SIZE];
1441 struct nscookie nsc; 1481 struct nscookie nsc;
1482 char newmapname[PATH_MAX];
1483 const char *map_path = dso->long_name;
1484
1485 perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0;
1486 if (perfmap) {
1487 if (dso->nsinfo && (dso__find_perf_map(newmapname,
1488 sizeof(newmapname), &dso->nsinfo) == 0)) {
1489 map_path = newmapname;
1490 }
1491 }
1442 1492
1443 nsinfo__mountns_enter(dso->nsinfo, &nsc); 1493 nsinfo__mountns_enter(dso->nsinfo, &nsc);
1444 pthread_mutex_lock(&dso->lock); 1494 pthread_mutex_lock(&dso->lock);
1445 1495
1446 /* The vdso files always live in the host container, so don't go looking
1447 * for them in the container's mount namespace.
1448 */
1449 if (dso__is_vdso(dso))
1450 nsinfo__mountns_exit(&nsc);
1451
1452 /* check again under the dso->lock */ 1496 /* check again under the dso->lock */
1453 if (dso__loaded(dso, map->type)) { 1497 if (dso__loaded(dso, map->type)) {
1454 ret = 1; 1498 ret = 1;
@@ -1471,19 +1515,19 @@ int dso__load(struct dso *dso, struct map *map)
1471 1515
1472 dso->adjust_symbols = 0; 1516 dso->adjust_symbols = 0;
1473 1517
1474 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1518 if (perfmap) {
1475 struct stat st; 1519 struct stat st;
1476 1520
1477 if (lstat(dso->name, &st) < 0) 1521 if (lstat(map_path, &st) < 0)
1478 goto out; 1522 goto out;
1479 1523
1480 if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) { 1524 if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
1481 pr_warning("File %s not owned by current user or root, " 1525 pr_warning("File %s not owned by current user or root, "
1482 "ignoring it (use -f to override).\n", dso->name); 1526 "ignoring it (use -f to override).\n", map_path);
1483 goto out; 1527 goto out;
1484 } 1528 }
1485 1529
1486 ret = dso__load_perf_map(dso, map); 1530 ret = dso__load_perf_map(map_path, dso, map);
1487 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 1531 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
1488 DSO_BINARY_TYPE__NOT_FOUND; 1532 DSO_BINARY_TYPE__NOT_FOUND;
1489 goto out; 1533 goto out;