code-reading.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #include <sys/types.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <inttypes.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include "parse-events.h"
  9. #include "evlist.h"
  10. #include "evsel.h"
  11. #include "thread_map.h"
  12. #include "cpumap.h"
  13. #include "machine.h"
  14. #include "event.h"
  15. #include "thread.h"
  16. #include "tests.h"
  17. #define BUFSZ 1024
  18. #define READLEN 128
  19. static unsigned int hex(char c)
  20. {
  21. if (c >= '0' && c <= '9')
  22. return c - '0';
  23. if (c >= 'a' && c <= 'f')
  24. return c - 'a' + 10;
  25. return c - 'A' + 10;
  26. }
  27. static void read_objdump_line(const char *line, size_t line_len, void **buf,
  28. size_t *len)
  29. {
  30. const char *p;
  31. size_t i;
  32. /* Skip to a colon */
  33. p = strchr(line, ':');
  34. if (!p)
  35. return;
  36. i = p + 1 - line;
  37. /* Read bytes */
  38. while (*len) {
  39. char c1, c2;
  40. /* Skip spaces */
  41. for (; i < line_len; i++) {
  42. if (!isspace(line[i]))
  43. break;
  44. }
  45. /* Get 2 hex digits */
  46. if (i >= line_len || !isxdigit(line[i]))
  47. break;
  48. c1 = line[i++];
  49. if (i >= line_len || !isxdigit(line[i]))
  50. break;
  51. c2 = line[i++];
  52. /* Followed by a space */
  53. if (i < line_len && line[i] && !isspace(line[i]))
  54. break;
  55. /* Store byte */
  56. *(unsigned char *)*buf = (hex(c1) << 4) | hex(c2);
  57. *buf += 1;
  58. *len -= 1;
  59. }
  60. }
  61. static int read_objdump_output(FILE *f, void **buf, size_t *len)
  62. {
  63. char *line = NULL;
  64. size_t line_len;
  65. ssize_t ret;
  66. int err = 0;
  67. while (1) {
  68. ret = getline(&line, &line_len, f);
  69. if (feof(f))
  70. break;
  71. if (ret < 0) {
  72. pr_debug("getline failed\n");
  73. err = -1;
  74. break;
  75. }
  76. read_objdump_line(line, ret, buf, len);
  77. }
  78. free(line);
  79. return err;
  80. }
  81. static int read_via_objdump(const char *filename, u64 addr, void *buf,
  82. size_t len)
  83. {
  84. char cmd[PATH_MAX * 2];
  85. const char *fmt;
  86. FILE *f;
  87. int ret;
  88. fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
  89. ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
  90. filename);
  91. if (ret <= 0 || (size_t)ret >= sizeof(cmd))
  92. return -1;
  93. pr_debug("Objdump command is: %s\n", cmd);
  94. f = popen(cmd, "r");
  95. if (!f) {
  96. pr_debug("popen failed\n");
  97. return -1;
  98. }
  99. ret = read_objdump_output(f, &buf, &len);
  100. if (len) {
  101. pr_debug("objdump read too few bytes\n");
  102. if (!ret)
  103. ret = len;
  104. }
  105. pclose(f);
  106. return ret;
  107. }
  108. static int read_object_code(u64 addr, size_t len, u8 cpumode,
  109. struct thread *thread, struct machine *machine)
  110. {
  111. struct addr_location al;
  112. unsigned char buf1[BUFSZ];
  113. unsigned char buf2[BUFSZ];
  114. size_t ret_len;
  115. u64 objdump_addr;
  116. int ret;
  117. pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
  118. thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr,
  119. &al);
  120. if (!al.map || !al.map->dso) {
  121. pr_debug("thread__find_addr_map failed\n");
  122. return -1;
  123. }
  124. pr_debug("File is: %s\n", al.map->dso->long_name);
  125. if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
  126. pr_debug("Unexpected kernel address - skipping\n");
  127. return 0;
  128. }
  129. pr_debug("On file address is: %#"PRIx64"\n", al.addr);
  130. if (len > BUFSZ)
  131. len = BUFSZ;
  132. /* Do not go off the map */
  133. if (addr + len > al.map->end)
  134. len = al.map->end - addr;
  135. /* Read the object code using perf */
  136. ret_len = dso__data_read_offset(al.map->dso, machine, al.addr, buf1,
  137. len);
  138. if (ret_len != len) {
  139. pr_debug("dso__data_read_offset failed\n");
  140. return -1;
  141. }
  142. /*
  143. * Converting addresses for use by objdump requires more information.
  144. * map__load() does that. See map__rip_2objdump() for details.
  145. */
  146. if (map__load(al.map, NULL))
  147. return -1;
  148. /* Read the object code using objdump */
  149. objdump_addr = map__rip_2objdump(al.map, al.addr);
  150. ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len);
  151. if (ret > 0) {
  152. /*
  153. * The kernel maps are inaccurate - assume objdump is right in
  154. * that case.
  155. */
  156. if (cpumode == PERF_RECORD_MISC_KERNEL ||
  157. cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
  158. len -= ret;
  159. if (len)
  160. pr_debug("Reducing len to %zu\n", len);
  161. else
  162. return -1;
  163. }
  164. }
  165. if (ret < 0) {
  166. pr_debug("read_via_objdump failed\n");
  167. return -1;
  168. }
  169. /* The results should be identical */
  170. if (memcmp(buf1, buf2, len)) {
  171. pr_debug("Bytes read differ from those read by objdump\n");
  172. return -1;
  173. }
  174. pr_debug("Bytes read match those read by objdump\n");
  175. return 0;
  176. }
  177. static int process_sample_event(struct machine *machine,
  178. struct perf_evlist *evlist,
  179. union perf_event *event)
  180. {
  181. struct perf_sample sample;
  182. struct thread *thread;
  183. u8 cpumode;
  184. if (perf_evlist__parse_sample(evlist, event, &sample)) {
  185. pr_debug("perf_evlist__parse_sample failed\n");
  186. return -1;
  187. }
  188. thread = machine__findnew_thread(machine, sample.pid);
  189. if (!thread) {
  190. pr_debug("machine__findnew_thread failed\n");
  191. return -1;
  192. }
  193. cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
  194. return read_object_code(sample.ip, READLEN, cpumode, thread, machine);
  195. }
  196. static int process_event(struct machine *machine, struct perf_evlist *evlist,
  197. union perf_event *event)
  198. {
  199. if (event->header.type == PERF_RECORD_SAMPLE)
  200. return process_sample_event(machine, evlist, event);
  201. if (event->header.type < PERF_RECORD_MAX)
  202. return machine__process_event(machine, event);
  203. return 0;
  204. }
  205. static int process_events(struct machine *machine, struct perf_evlist *evlist)
  206. {
  207. union perf_event *event;
  208. int i, ret;
  209. for (i = 0; i < evlist->nr_mmaps; i++) {
  210. while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
  211. ret = process_event(machine, evlist, event);
  212. if (ret < 0)
  213. return ret;
  214. }
  215. }
  216. return 0;
  217. }
  218. static int comp(const void *a, const void *b)
  219. {
  220. return *(int *)a - *(int *)b;
  221. }
  222. static void do_sort_something(void)
  223. {
  224. size_t sz = 40960;
  225. int buf[sz], i;
  226. for (i = 0; i < (int)sz; i++)
  227. buf[i] = sz - i - 1;
  228. qsort(buf, sz, sizeof(int), comp);
  229. for (i = 0; i < (int)sz; i++) {
  230. if (buf[i] != i) {
  231. pr_debug("qsort failed\n");
  232. break;
  233. }
  234. }
  235. }
  236. static void sort_something(void)
  237. {
  238. int i;
  239. for (i = 0; i < 10; i++)
  240. do_sort_something();
  241. }
  242. static void syscall_something(void)
  243. {
  244. int pipefd[2];
  245. int i;
  246. for (i = 0; i < 1000; i++) {
  247. if (pipe(pipefd) < 0) {
  248. pr_debug("pipe failed\n");
  249. break;
  250. }
  251. close(pipefd[1]);
  252. close(pipefd[0]);
  253. }
  254. }
  255. static void fs_something(void)
  256. {
  257. const char *test_file_name = "temp-perf-code-reading-test-file--";
  258. FILE *f;
  259. int i;
  260. for (i = 0; i < 1000; i++) {
  261. f = fopen(test_file_name, "w+");
  262. if (f) {
  263. fclose(f);
  264. unlink(test_file_name);
  265. }
  266. }
  267. }
  268. static void do_something(void)
  269. {
  270. fs_something();
  271. sort_something();
  272. syscall_something();
  273. }
  274. enum {
  275. TEST_CODE_READING_OK,
  276. TEST_CODE_READING_NO_VMLINUX,
  277. TEST_CODE_READING_NO_ACCESS,
  278. };
  279. static int do_test_code_reading(void)
  280. {
  281. struct machines machines;
  282. struct machine *machine;
  283. struct thread *thread;
  284. struct perf_record_opts opts = {
  285. .mmap_pages = UINT_MAX,
  286. .user_freq = UINT_MAX,
  287. .user_interval = ULLONG_MAX,
  288. .freq = 4000,
  289. .target = {
  290. .uses_mmap = true,
  291. },
  292. };
  293. struct thread_map *threads = NULL;
  294. struct cpu_map *cpus = NULL;
  295. struct perf_evlist *evlist = NULL;
  296. struct perf_evsel *evsel = NULL;
  297. int err = -1, ret;
  298. pid_t pid;
  299. struct map *map;
  300. bool have_vmlinux, excl_kernel = false;
  301. pid = getpid();
  302. machines__init(&machines);
  303. machine = &machines.host;
  304. ret = machine__create_kernel_maps(machine);
  305. if (ret < 0) {
  306. pr_debug("machine__create_kernel_maps failed\n");
  307. goto out_err;
  308. }
  309. /* Load kernel map */
  310. map = machine->vmlinux_maps[MAP__FUNCTION];
  311. ret = map__load(map, NULL);
  312. if (ret < 0) {
  313. pr_debug("map__load failed\n");
  314. goto out_err;
  315. }
  316. have_vmlinux = map->dso->symtab_type == DSO_BINARY_TYPE__VMLINUX;
  317. /* No point getting kernel events if there is no vmlinux */
  318. if (!have_vmlinux)
  319. excl_kernel = true;
  320. threads = thread_map__new_by_tid(pid);
  321. if (!threads) {
  322. pr_debug("thread_map__new_by_tid failed\n");
  323. goto out_err;
  324. }
  325. ret = perf_event__synthesize_thread_map(NULL, threads,
  326. perf_event__process, machine);
  327. if (ret < 0) {
  328. pr_debug("perf_event__synthesize_thread_map failed\n");
  329. goto out_err;
  330. }
  331. thread = machine__findnew_thread(machine, pid);
  332. if (!thread) {
  333. pr_debug("machine__findnew_thread failed\n");
  334. goto out_err;
  335. }
  336. cpus = cpu_map__new(NULL);
  337. if (!cpus) {
  338. pr_debug("cpu_map__new failed\n");
  339. goto out_err;
  340. }
  341. while (1) {
  342. const char *str;
  343. evlist = perf_evlist__new();
  344. if (!evlist) {
  345. pr_debug("perf_evlist__new failed\n");
  346. goto out_err;
  347. }
  348. perf_evlist__set_maps(evlist, cpus, threads);
  349. if (excl_kernel)
  350. str = "cycles:u";
  351. else
  352. str = "cycles";
  353. pr_debug("Parsing event '%s'\n", str);
  354. ret = parse_events(evlist, str);
  355. if (ret < 0) {
  356. pr_debug("parse_events failed\n");
  357. goto out_err;
  358. }
  359. perf_evlist__config(evlist, &opts);
  360. evsel = perf_evlist__first(evlist);
  361. evsel->attr.comm = 1;
  362. evsel->attr.disabled = 1;
  363. evsel->attr.enable_on_exec = 0;
  364. ret = perf_evlist__open(evlist);
  365. if (ret < 0) {
  366. if (!excl_kernel) {
  367. excl_kernel = true;
  368. perf_evlist__delete(evlist);
  369. evlist = NULL;
  370. continue;
  371. }
  372. pr_debug("perf_evlist__open failed\n");
  373. goto out_err;
  374. }
  375. break;
  376. }
  377. ret = perf_evlist__mmap(evlist, UINT_MAX, false);
  378. if (ret < 0) {
  379. pr_debug("perf_evlist__mmap failed\n");
  380. goto out_err;
  381. }
  382. perf_evlist__enable(evlist);
  383. do_something();
  384. perf_evlist__disable(evlist);
  385. ret = process_events(machine, evlist);
  386. if (ret < 0)
  387. goto out_err;
  388. if (!have_vmlinux)
  389. err = TEST_CODE_READING_NO_VMLINUX;
  390. else if (excl_kernel)
  391. err = TEST_CODE_READING_NO_ACCESS;
  392. else
  393. err = TEST_CODE_READING_OK;
  394. out_err:
  395. if (evlist) {
  396. perf_evlist__munmap(evlist);
  397. perf_evlist__close(evlist);
  398. perf_evlist__delete(evlist);
  399. }
  400. if (cpus)
  401. cpu_map__delete(cpus);
  402. if (threads)
  403. thread_map__delete(threads);
  404. machines__destroy_kernel_maps(&machines);
  405. machine__delete_threads(machine);
  406. machines__exit(&machines);
  407. return err;
  408. }
  409. int test__code_reading(void)
  410. {
  411. int ret;
  412. ret = do_test_code_reading();
  413. switch (ret) {
  414. case TEST_CODE_READING_OK:
  415. return 0;
  416. case TEST_CODE_READING_NO_VMLINUX:
  417. fprintf(stderr, " (no vmlinux)");
  418. return 0;
  419. case TEST_CODE_READING_NO_ACCESS:
  420. fprintf(stderr, " (no access)");
  421. return 0;
  422. default:
  423. return -1;
  424. };
  425. }