Merge commit 'v2.6.32-rc6' into perf/core
[safe/jmp/linux-2.6] / tools / perf / util / event.c
1 #include <linux/types.h>
2 #include "event.h"
3 #include "debug.h"
4 #include "string.h"
5
6 static pid_t event__synthesize_comm(pid_t pid, int full,
7                                     int (*process)(event_t *event))
8 {
9         event_t ev;
10         char filename[PATH_MAX];
11         char bf[BUFSIZ];
12         FILE *fp;
13         size_t size = 0;
14         DIR *tasks;
15         struct dirent dirent, *next;
16         pid_t tgid = 0;
17
18         snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
19
20         fp = fopen(filename, "r");
21         if (fp == NULL) {
22 out_race:
23                 /*
24                  * We raced with a task exiting - just return:
25                  */
26                 pr_debug("couldn't open %s\n", filename);
27                 return 0;
28         }
29
30         memset(&ev.comm, 0, sizeof(ev.comm));
31         while (!ev.comm.comm[0] || !ev.comm.pid) {
32                 if (fgets(bf, sizeof(bf), fp) == NULL)
33                         goto out_failure;
34
35                 if (memcmp(bf, "Name:", 5) == 0) {
36                         char *name = bf + 5;
37                         while (*name && isspace(*name))
38                                 ++name;
39                         size = strlen(name) - 1;
40                         memcpy(ev.comm.comm, name, size++);
41                 } else if (memcmp(bf, "Tgid:", 5) == 0) {
42                         char *tgids = bf + 5;
43                         while (*tgids && isspace(*tgids))
44                                 ++tgids;
45                         tgid = ev.comm.pid = atoi(tgids);
46                 }
47         }
48
49         ev.comm.header.type = PERF_RECORD_COMM;
50         size = ALIGN(size, sizeof(u64));
51         ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
52
53         if (!full) {
54                 ev.comm.tid = pid;
55
56                 process(&ev);
57                 goto out_fclose;
58         }
59
60         snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
61
62         tasks = opendir(filename);
63         if (tasks == NULL)
64                 goto out_race;
65
66         while (!readdir_r(tasks, &dirent, &next) && next) {
67                 char *end;
68                 pid = strtol(dirent.d_name, &end, 10);
69                 if (*end)
70                         continue;
71
72                 ev.comm.tid = pid;
73
74                 process(&ev);
75         }
76         closedir(tasks);
77
78 out_fclose:
79         fclose(fp);
80         return tgid;
81
82 out_failure:
83         pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
84         return -1;
85 }
86
87 static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
88                                          int (*process)(event_t *event))
89 {
90         char filename[PATH_MAX];
91         FILE *fp;
92
93         snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
94
95         fp = fopen(filename, "r");
96         if (fp == NULL) {
97                 /*
98                  * We raced with a task exiting - just return:
99                  */
100                 pr_debug("couldn't open %s\n", filename);
101                 return -1;
102         }
103
104         while (1) {
105                 char bf[BUFSIZ], *pbf = bf;
106                 event_t ev = {
107                         .header = { .type = PERF_RECORD_MMAP },
108                 };
109                 int n;
110                 size_t size;
111                 if (fgets(bf, sizeof(bf), fp) == NULL)
112                         break;
113
114                 /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
115                 n = hex2u64(pbf, &ev.mmap.start);
116                 if (n < 0)
117                         continue;
118                 pbf += n + 1;
119                 n = hex2u64(pbf, &ev.mmap.len);
120                 if (n < 0)
121                         continue;
122                 pbf += n + 3;
123                 if (*pbf == 'x') { /* vm_exec */
124                         char *execname = strchr(bf, '/');
125
126                         /* Catch VDSO */
127                         if (execname == NULL)
128                                 execname = strstr(bf, "[vdso]");
129
130                         if (execname == NULL)
131                                 continue;
132
133                         size = strlen(execname);
134                         execname[size - 1] = '\0'; /* Remove \n */
135                         memcpy(ev.mmap.filename, execname, size);
136                         size = ALIGN(size, sizeof(u64));
137                         ev.mmap.len -= ev.mmap.start;
138                         ev.mmap.header.size = (sizeof(ev.mmap) -
139                                                (sizeof(ev.mmap.filename) - size));
140                         ev.mmap.pid = tgid;
141                         ev.mmap.tid = pid;
142
143                         process(&ev);
144                 }
145         }
146
147         fclose(fp);
148         return 0;
149 }
150
151 int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
152 {
153         pid_t tgid = event__synthesize_comm(pid, 1, process);
154         if (tgid == -1)
155                 return -1;
156         return event__synthesize_mmap_events(pid, tgid, process);
157 }
158
159 void event__synthesize_threads(int (*process)(event_t *event))
160 {
161         DIR *proc;
162         struct dirent dirent, *next;
163
164         proc = opendir("/proc");
165
166         while (!readdir_r(proc, &dirent, &next) && next) {
167                 char *end;
168                 pid_t pid = strtol(dirent.d_name, &end, 10);
169
170                 if (*end) /* only interested in proper numerical dirents */
171                         continue;
172
173                 event__synthesize_thread(pid, process);
174         }
175
176         closedir(proc);
177 }