event.c 3.6 KB

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