builtin-inject.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * builtin-inject.c
  3. *
  4. * Builtin inject command: Examine the live mode (stdin) event stream
  5. * and repipe it to stdout while optionally injecting additional
  6. * events into it.
  7. */
  8. #include "builtin.h"
  9. #include "perf.h"
  10. #include "util/session.h"
  11. #include "util/tool.h"
  12. #include "util/debug.h"
  13. #include "util/parse-options.h"
  14. static char const *input_name = "-";
  15. static bool inject_build_ids;
  16. static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused,
  17. union perf_event *event,
  18. struct machine *machine __maybe_unused)
  19. {
  20. uint32_t size;
  21. void *buf = event;
  22. size = event->header.size;
  23. while (size) {
  24. int ret = write(STDOUT_FILENO, buf, size);
  25. if (ret < 0)
  26. return -errno;
  27. size -= ret;
  28. buf += ret;
  29. }
  30. return 0;
  31. }
  32. static int perf_event__repipe_op2_synth(struct perf_tool *tool,
  33. union perf_event *event,
  34. struct perf_session *session
  35. __maybe_unused)
  36. {
  37. return perf_event__repipe_synth(tool, event, NULL);
  38. }
  39. static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
  40. union perf_event *event)
  41. {
  42. return perf_event__repipe_synth(tool, event, NULL);
  43. }
  44. static int perf_event__repipe_tracing_data_synth(union perf_event *event,
  45. struct perf_session *session
  46. __maybe_unused)
  47. {
  48. return perf_event__repipe_synth(NULL, event, NULL);
  49. }
  50. static int perf_event__repipe_attr(union perf_event *event,
  51. struct perf_evlist **pevlist __maybe_unused)
  52. {
  53. int ret;
  54. ret = perf_event__process_attr(event, pevlist);
  55. if (ret)
  56. return ret;
  57. return perf_event__repipe_synth(NULL, event, NULL);
  58. }
  59. static int perf_event__repipe(struct perf_tool *tool,
  60. union perf_event *event,
  61. struct perf_sample *sample __maybe_unused,
  62. struct machine *machine)
  63. {
  64. return perf_event__repipe_synth(tool, event, machine);
  65. }
  66. static int perf_event__repipe_sample(struct perf_tool *tool,
  67. union perf_event *event,
  68. struct perf_sample *sample __maybe_unused,
  69. struct perf_evsel *evsel __maybe_unused,
  70. struct machine *machine)
  71. {
  72. return perf_event__repipe_synth(tool, event, machine);
  73. }
  74. static int perf_event__repipe_mmap(struct perf_tool *tool,
  75. union perf_event *event,
  76. struct perf_sample *sample,
  77. struct machine *machine)
  78. {
  79. int err;
  80. err = perf_event__process_mmap(tool, event, sample, machine);
  81. perf_event__repipe(tool, event, sample, machine);
  82. return err;
  83. }
  84. static int perf_event__repipe_task(struct perf_tool *tool,
  85. union perf_event *event,
  86. struct perf_sample *sample,
  87. struct machine *machine)
  88. {
  89. int err;
  90. err = perf_event__process_task(tool, event, sample, machine);
  91. perf_event__repipe(tool, event, sample, machine);
  92. return err;
  93. }
  94. static int perf_event__repipe_tracing_data(union perf_event *event,
  95. struct perf_session *session)
  96. {
  97. int err;
  98. perf_event__repipe_synth(NULL, event, NULL);
  99. err = perf_event__process_tracing_data(event, session);
  100. return err;
  101. }
  102. static int dso__read_build_id(struct dso *self)
  103. {
  104. if (self->has_build_id)
  105. return 0;
  106. if (filename__read_build_id(self->long_name, self->build_id,
  107. sizeof(self->build_id)) > 0) {
  108. self->has_build_id = true;
  109. return 0;
  110. }
  111. return -1;
  112. }
  113. static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
  114. struct machine *machine)
  115. {
  116. u16 misc = PERF_RECORD_MISC_USER;
  117. int err;
  118. if (dso__read_build_id(self) < 0) {
  119. pr_debug("no build_id found for %s\n", self->long_name);
  120. return -1;
  121. }
  122. if (self->kernel)
  123. misc = PERF_RECORD_MISC_KERNEL;
  124. err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
  125. machine);
  126. if (err) {
  127. pr_err("Can't synthesize build_id event for %s\n", self->long_name);
  128. return -1;
  129. }
  130. return 0;
  131. }
  132. static int perf_event__inject_buildid(struct perf_tool *tool,
  133. union perf_event *event,
  134. struct perf_sample *sample,
  135. struct perf_evsel *evsel __maybe_unused,
  136. struct machine *machine)
  137. {
  138. struct addr_location al;
  139. struct thread *thread;
  140. u8 cpumode;
  141. cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
  142. thread = machine__findnew_thread(machine, event->ip.pid);
  143. if (thread == NULL) {
  144. pr_err("problem processing %d event, skipping it.\n",
  145. event->header.type);
  146. goto repipe;
  147. }
  148. thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
  149. event->ip.ip, &al);
  150. if (al.map != NULL) {
  151. if (!al.map->dso->hit) {
  152. al.map->dso->hit = 1;
  153. if (map__load(al.map, NULL) >= 0) {
  154. dso__inject_build_id(al.map->dso, tool, machine);
  155. /*
  156. * If this fails, too bad, let the other side
  157. * account this as unresolved.
  158. */
  159. } else {
  160. #ifndef NO_LIBELF_SUPPORT
  161. pr_warning("no symbols found in %s, maybe "
  162. "install a debug package?\n",
  163. al.map->dso->long_name);
  164. #endif
  165. }
  166. }
  167. }
  168. repipe:
  169. perf_event__repipe(tool, event, sample, machine);
  170. return 0;
  171. }
  172. struct perf_tool perf_inject = {
  173. .sample = perf_event__repipe_sample,
  174. .mmap = perf_event__repipe,
  175. .comm = perf_event__repipe,
  176. .fork = perf_event__repipe,
  177. .exit = perf_event__repipe,
  178. .lost = perf_event__repipe,
  179. .read = perf_event__repipe_sample,
  180. .throttle = perf_event__repipe,
  181. .unthrottle = perf_event__repipe,
  182. .attr = perf_event__repipe_attr,
  183. .event_type = perf_event__repipe_event_type_synth,
  184. .tracing_data = perf_event__repipe_tracing_data_synth,
  185. .build_id = perf_event__repipe_op2_synth,
  186. };
  187. extern volatile int session_done;
  188. static void sig_handler(int sig __maybe_unused)
  189. {
  190. session_done = 1;
  191. }
  192. static int __cmd_inject(void)
  193. {
  194. struct perf_session *session;
  195. int ret = -EINVAL;
  196. signal(SIGINT, sig_handler);
  197. if (inject_build_ids) {
  198. perf_inject.sample = perf_event__inject_buildid;
  199. perf_inject.mmap = perf_event__repipe_mmap;
  200. perf_inject.fork = perf_event__repipe_task;
  201. perf_inject.tracing_data = perf_event__repipe_tracing_data;
  202. }
  203. session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject);
  204. if (session == NULL)
  205. return -ENOMEM;
  206. ret = perf_session__process_events(session, &perf_inject);
  207. perf_session__delete(session);
  208. return ret;
  209. }
  210. static const char * const report_usage[] = {
  211. "perf inject [<options>]",
  212. NULL
  213. };
  214. static const struct option options[] = {
  215. OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
  216. "Inject build-ids into the output stream"),
  217. OPT_INCR('v', "verbose", &verbose,
  218. "be more verbose (show build ids, etc)"),
  219. OPT_END()
  220. };
  221. int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
  222. {
  223. argc = parse_options(argc, argv, options, report_usage, 0);
  224. /*
  225. * Any (unrecognized) arguments left?
  226. */
  227. if (argc)
  228. usage_with_options(report_usage, options);
  229. if (symbol__init() < 0)
  230. return -1;
  231. return __cmd_inject();
  232. }