event.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #include <linux/types.h>
  2. #include "event.h"
  3. #include "debug.h"
  4. #include "string.h"
  5. #include "thread.h"
  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. snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
  18. fp = fopen(filename, "r");
  19. if (fp == NULL) {
  20. out_race:
  21. /*
  22. * We raced with a task exiting - just return:
  23. */
  24. pr_debug("couldn't open %s\n", filename);
  25. return 0;
  26. }
  27. memset(&ev.comm, 0, sizeof(ev.comm));
  28. while (!ev.comm.comm[0] || !ev.comm.pid) {
  29. if (fgets(bf, sizeof(bf), fp) == NULL)
  30. goto out_failure;
  31. if (memcmp(bf, "Name:", 5) == 0) {
  32. char *name = bf + 5;
  33. while (*name && isspace(*name))
  34. ++name;
  35. size = strlen(name) - 1;
  36. memcpy(ev.comm.comm, name, size++);
  37. } else if (memcmp(bf, "Tgid:", 5) == 0) {
  38. char *tgids = bf + 5;
  39. while (*tgids && isspace(*tgids))
  40. ++tgids;
  41. tgid = ev.comm.pid = atoi(tgids);
  42. }
  43. }
  44. ev.comm.header.type = PERF_RECORD_COMM;
  45. size = ALIGN(size, sizeof(u64));
  46. ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
  47. if (!full) {
  48. ev.comm.tid = pid;
  49. process(&ev);
  50. goto out_fclose;
  51. }
  52. snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
  53. tasks = opendir(filename);
  54. if (tasks == NULL)
  55. goto out_race;
  56. while (!readdir_r(tasks, &dirent, &next) && next) {
  57. char *end;
  58. pid = strtol(dirent.d_name, &end, 10);
  59. if (*end)
  60. continue;
  61. ev.comm.tid = pid;
  62. process(&ev);
  63. }
  64. closedir(tasks);
  65. out_fclose:
  66. fclose(fp);
  67. return tgid;
  68. out_failure:
  69. pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
  70. return -1;
  71. }
  72. static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
  73. int (*process)(event_t *event))
  74. {
  75. char filename[PATH_MAX];
  76. FILE *fp;
  77. snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
  78. fp = fopen(filename, "r");
  79. if (fp == NULL) {
  80. /*
  81. * We raced with a task exiting - just return:
  82. */
  83. pr_debug("couldn't open %s\n", filename);
  84. return -1;
  85. }
  86. while (1) {
  87. char bf[BUFSIZ], *pbf = bf;
  88. event_t ev = {
  89. .header = { .type = PERF_RECORD_MMAP },
  90. };
  91. int n;
  92. size_t size;
  93. if (fgets(bf, sizeof(bf), fp) == NULL)
  94. break;
  95. /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
  96. n = hex2u64(pbf, &ev.mmap.start);
  97. if (n < 0)
  98. continue;
  99. pbf += n + 1;
  100. n = hex2u64(pbf, &ev.mmap.len);
  101. if (n < 0)
  102. continue;
  103. pbf += n + 3;
  104. if (*pbf == 'x') { /* vm_exec */
  105. char *execname = strchr(bf, '/');
  106. /* Catch VDSO */
  107. if (execname == NULL)
  108. execname = strstr(bf, "[vdso]");
  109. if (execname == NULL)
  110. continue;
  111. size = strlen(execname);
  112. execname[size - 1] = '\0'; /* Remove \n */
  113. memcpy(ev.mmap.filename, execname, size);
  114. size = ALIGN(size, sizeof(u64));
  115. ev.mmap.len -= ev.mmap.start;
  116. ev.mmap.header.size = (sizeof(ev.mmap) -
  117. (sizeof(ev.mmap.filename) - size));
  118. ev.mmap.pid = tgid;
  119. ev.mmap.tid = pid;
  120. process(&ev);
  121. }
  122. }
  123. fclose(fp);
  124. return 0;
  125. }
  126. int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
  127. {
  128. pid_t tgid = event__synthesize_comm(pid, 1, process);
  129. if (tgid == -1)
  130. return -1;
  131. return event__synthesize_mmap_events(pid, tgid, process);
  132. }
  133. void event__synthesize_threads(int (*process)(event_t *event))
  134. {
  135. DIR *proc;
  136. struct dirent dirent, *next;
  137. proc = opendir("/proc");
  138. while (!readdir_r(proc, &dirent, &next) && next) {
  139. char *end;
  140. pid_t pid = strtol(dirent.d_name, &end, 10);
  141. if (*end) /* only interested in proper numerical dirents */
  142. continue;
  143. event__synthesize_thread(pid, process);
  144. }
  145. closedir(proc);
  146. }
  147. char *event__cwd;
  148. int event__cwdlen;
  149. struct events_stats event__stats;
  150. int event__process_comm(event_t *self)
  151. {
  152. struct thread *thread = threads__findnew(self->comm.pid);
  153. dump_printf("PERF_RECORD_COMM: %s:%d\n",
  154. self->comm.comm, self->comm.pid);
  155. if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
  156. dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
  157. return -1;
  158. }
  159. return 0;
  160. }
  161. int event__process_lost(event_t *self)
  162. {
  163. dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
  164. event__stats.lost += self->lost.lost;
  165. return 0;
  166. }
  167. int event__process_mmap(event_t *self)
  168. {
  169. struct thread *thread = threads__findnew(self->mmap.pid);
  170. struct map *map = map__new(&self->mmap, MAP__FUNCTION,
  171. event__cwd, event__cwdlen);
  172. dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
  173. self->mmap.pid, self->mmap.tid,
  174. (void *)(long)self->mmap.start,
  175. (void *)(long)self->mmap.len,
  176. (void *)(long)self->mmap.pgoff,
  177. self->mmap.filename);
  178. if (thread == NULL || map == NULL)
  179. dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
  180. else
  181. thread__insert_map(thread, map);
  182. return 0;
  183. }
  184. int event__process_task(event_t *self)
  185. {
  186. struct thread *thread = threads__findnew(self->fork.pid);
  187. struct thread *parent = threads__findnew(self->fork.ppid);
  188. dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
  189. self->fork.ppid, self->fork.ptid);
  190. /*
  191. * A thread clone will have the same PID for both parent and child.
  192. */
  193. if (thread == parent)
  194. return 0;
  195. if (self->header.type == PERF_RECORD_EXIT)
  196. return 0;
  197. if (thread == NULL || parent == NULL ||
  198. thread__fork(thread, parent) < 0) {
  199. dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
  200. return -1;
  201. }
  202. return 0;
  203. }