24 #include "../builtin.h"
27 struct perf_data_file
*output
;
28 struct perf_session
*session
;
29 struct machine
*machine
;
30 union jr_entry
*entry
;
35 bool needs_bswap
; /* handles cross-endianess */
37 size_t nr_debug_entries
;
38 uint32_t code_load_count
;
40 struct rb_root code_root
;
44 struct debug_line_info
{
47 /* The filename format is unspecified, absolute path, relative etc. */
48 char const filename
[0];
52 struct perf_tool tool
;
53 struct perf_data_file output
;
54 struct perf_data_file input
;
58 #define hmax(a, b) ((a) > (b) ? (a) : (b))
59 #define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
62 jit_emit_elf(char *filename
,
73 fprintf(stderr
, "write ELF image %s\n", filename
);
75 fd
= open(filename
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0644);
77 pr_warning("cannot create jit ELF %s: %s\n", filename
, strerror(errno
));
81 ret
= jit_write_elf(fd
, code_addr
, sym
, (const void *)code
, csize
, debug
, nr_debug_entries
);
92 jit_close(struct jit_buf_desc
*jd
)
102 jit_validate_events(struct perf_session
*session
)
104 struct perf_evsel
*evsel
;
107 * check that all events use CLOCK_MONOTONIC
109 evlist__for_each(session
->evlist
, evsel
) {
110 if (evsel
->attr
.use_clockid
== 0 || evsel
->attr
.clockid
!= CLOCK_MONOTONIC
)
117 jit_open(struct jit_buf_desc
*jd
, const char *name
)
119 struct jitheader header
;
120 struct jr_prefix
*prefix
;
122 void *n
, *buf
= NULL
;
123 int ret
, retval
= -1;
125 jd
->in
= fopen(name
, "r");
129 bsz
= hmax(sizeof(header
), sizeof(*prefix
));
136 * protect from writer modifying the file while we are reading it
140 ret
= fread(buf
, sizeof(header
), 1, jd
->in
);
144 memcpy(&header
, buf
, sizeof(header
));
146 if (header
.magic
!= JITHEADER_MAGIC
) {
147 if (header
.magic
!= JITHEADER_MAGIC_SW
)
149 jd
->needs_bswap
= true;
152 if (jd
->needs_bswap
) {
153 header
.version
= bswap_32(header
.version
);
154 header
.total_size
= bswap_32(header
.total_size
);
155 header
.pid
= bswap_32(header
.pid
);
156 header
.elf_mach
= bswap_32(header
.elf_mach
);
157 header
.timestamp
= bswap_64(header
.timestamp
);
158 header
.flags
= bswap_64(header
.flags
);
162 pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
165 (unsigned long long)header
.timestamp
,
169 if (header
.flags
& JITDUMP_FLAGS_RESERVED
) {
170 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
171 (unsigned long long)header
.flags
& JITDUMP_FLAGS_RESERVED
);
176 * validate event is using the correct clockid
178 if (jit_validate_events(jd
->session
)) {
179 pr_err("error, jitted code must be sampled with perf record -k 1\n");
183 bs
= header
.total_size
- sizeof(header
);
186 n
= realloc(buf
, bs
);
191 /* read extra we do not know about */
192 ret
= fread(buf
, bs
- bsz
, 1, jd
->in
);
197 * keep dirname for generating files and mmap records
199 strcpy(jd
->dir
, name
);
209 static union jr_entry
*
210 jit_get_next_entry(struct jit_buf_desc
*jd
)
212 struct jr_prefix
*prefix
;
221 if (jd
->buf
== NULL
) {
222 size_t sz
= getpagesize();
223 if (sz
< sizeof(*prefix
))
224 sz
= sizeof(*prefix
);
226 jd
->buf
= malloc(sz
);
236 * file is still locked at this point
238 ret
= fread(prefix
, sizeof(*prefix
), 1, jd
->in
);
242 if (jd
->needs_bswap
) {
243 prefix
->id
= bswap_32(prefix
->id
);
244 prefix
->total_size
= bswap_32(prefix
->total_size
);
245 prefix
->timestamp
= bswap_64(prefix
->timestamp
);
248 size
= prefix
->total_size
;
251 if (bs
< sizeof(*prefix
))
254 if (id
>= JIT_CODE_MAX
) {
255 pr_warning("next_entry: unknown prefix %d, skipping\n", id
);
258 if (bs
> jd
->bufsize
) {
260 n
= realloc(jd
->buf
, bs
);
267 addr
= ((void *)jd
->buf
) + sizeof(*prefix
);
269 ret
= fread(addr
, bs
- sizeof(*prefix
), 1, jd
->in
);
273 jr
= (union jr_entry
*)jd
->buf
;
276 case JIT_CODE_DEBUG_INFO
:
277 if (jd
->needs_bswap
) {
279 jr
->info
.code_addr
= bswap_64(jr
->info
.code_addr
);
280 jr
->info
.nr_entry
= bswap_64(jr
->info
.nr_entry
);
281 for (n
= 0 ; n
< jr
->info
.nr_entry
; n
++) {
282 jr
->info
.entries
[n
].addr
= bswap_64(jr
->info
.entries
[n
].addr
);
283 jr
->info
.entries
[n
].lineno
= bswap_32(jr
->info
.entries
[n
].lineno
);
284 jr
->info
.entries
[n
].discrim
= bswap_32(jr
->info
.entries
[n
].discrim
);
291 if (jd
->needs_bswap
) {
292 jr
->load
.pid
= bswap_32(jr
->load
.pid
);
293 jr
->load
.tid
= bswap_32(jr
->load
.tid
);
294 jr
->load
.vma
= bswap_64(jr
->load
.vma
);
295 jr
->load
.code_addr
= bswap_64(jr
->load
.code_addr
);
296 jr
->load
.code_size
= bswap_64(jr
->load
.code_size
);
297 jr
->load
.code_index
= bswap_64(jr
->load
.code_index
);
299 jd
->code_load_count
++;
302 if (jd
->needs_bswap
) {
303 jr
->move
.pid
= bswap_32(jr
->move
.pid
);
304 jr
->move
.tid
= bswap_32(jr
->move
.tid
);
305 jr
->move
.vma
= bswap_64(jr
->move
.vma
);
306 jr
->move
.old_code_addr
= bswap_64(jr
->move
.old_code_addr
);
307 jr
->move
.new_code_addr
= bswap_64(jr
->move
.new_code_addr
);
308 jr
->move
.code_size
= bswap_64(jr
->move
.code_size
);
309 jr
->move
.code_index
= bswap_64(jr
->move
.code_index
);
320 jit_inject_event(struct jit_buf_desc
*jd
, union perf_event
*event
)
324 size
= perf_data_file__write(jd
->output
, event
, event
->header
.size
);
328 jd
->bytes_written
+= size
;
332 static int jit_repipe_code_load(struct jit_buf_desc
*jd
, union jr_entry
*jr
)
334 struct perf_sample sample
;
335 union perf_event
*event
;
336 struct perf_tool
*tool
= jd
->session
->tool
;
354 csize
= jr
->load
.code_size
;
355 addr
= jr
->load
.code_addr
;
356 sym
= (void *)((unsigned long)jr
+ sizeof(jr
->load
));
357 code
= (unsigned long)jr
+ jr
->load
.p
.total_size
- csize
;
358 count
= jr
->load
.code_index
;
359 idr_size
= jd
->machine
->id_hdr_size
;
361 event
= calloc(1, sizeof(*event
) + idr_size
);
365 filename
= event
->mmap2
.filename
;
366 size
= snprintf(filename
, PATH_MAX
, "%s/jitted-%d-%u.so",
373 size
= PERF_ALIGN(size
, sizeof(u64
));
374 uaddr
= (uintptr_t)code
;
375 ret
= jit_emit_elf(filename
, sym
, addr
, (const void *)uaddr
, csize
, jd
->debug_data
, jd
->nr_debug_entries
);
377 if (jd
->debug_data
&& jd
->nr_debug_entries
) {
378 free(jd
->debug_data
);
379 jd
->debug_data
= NULL
;
380 jd
->nr_debug_entries
= 0;
387 if (stat(filename
, &st
))
388 memset(&st
, 0, sizeof(stat
));
390 event
->mmap2
.header
.type
= PERF_RECORD_MMAP2
;
391 event
->mmap2
.header
.misc
= PERF_RECORD_MISC_USER
;
392 event
->mmap2
.header
.size
= (sizeof(event
->mmap2
) -
393 (sizeof(event
->mmap2
.filename
) - size
) + idr_size
);
395 event
->mmap2
.pgoff
= GEN_ELF_TEXT_OFFSET
;
396 event
->mmap2
.start
= addr
;
397 event
->mmap2
.len
= csize
;
398 event
->mmap2
.pid
= pid
;
399 event
->mmap2
.tid
= tid
;
400 event
->mmap2
.ino
= st
.st_ino
;
401 event
->mmap2
.maj
= major(st
.st_dev
);
402 event
->mmap2
.min
= minor(st
.st_dev
);
403 event
->mmap2
.prot
= st
.st_mode
;
404 event
->mmap2
.flags
= MAP_SHARED
;
405 event
->mmap2
.ino_generation
= 1;
407 id
= (void *)((unsigned long)event
+ event
->mmap
.header
.size
- idr_size
);
408 if (jd
->sample_type
& PERF_SAMPLE_TID
) {
412 if (jd
->sample_type
& PERF_SAMPLE_TIME
)
413 id
->time
= jr
->load
.p
.timestamp
;
416 * create pseudo sample to induce dso hit increment
417 * use first address as sample address
419 memset(&sample
, 0, sizeof(sample
));
420 sample
.cpumode
= PERF_RECORD_MISC_USER
;
423 sample
.time
= id
->time
;
426 ret
= perf_event__process_mmap2(tool
, event
, &sample
, jd
->machine
);
430 ret
= jit_inject_event(jd
, event
);
432 * mark dso as use to generate buildid in the header
435 build_id__mark_dso_hit(tool
, event
, &sample
, NULL
, jd
->machine
);
440 static int jit_repipe_code_move(struct jit_buf_desc
*jd
, union jr_entry
*jr
)
442 struct perf_sample sample
;
443 union perf_event
*event
;
444 struct perf_tool
*tool
= jd
->session
->tool
;
458 idr_size
= jd
->machine
->id_hdr_size
;
461 * +16 to account for sample_id_all (hack)
463 event
= calloc(1, sizeof(*event
) + 16);
467 filename
= event
->mmap2
.filename
;
468 size
= snprintf(filename
, PATH_MAX
, "%s/jitted-%d-%"PRIu64
,
471 jr
->move
.code_index
);
475 if (stat(filename
, &st
))
476 memset(&st
, 0, sizeof(stat
));
478 size
= PERF_ALIGN(size
, sizeof(u64
));
480 event
->mmap2
.header
.type
= PERF_RECORD_MMAP2
;
481 event
->mmap2
.header
.misc
= PERF_RECORD_MISC_USER
;
482 event
->mmap2
.header
.size
= (sizeof(event
->mmap2
) -
483 (sizeof(event
->mmap2
.filename
) - size
) + idr_size
);
484 event
->mmap2
.pgoff
= GEN_ELF_TEXT_OFFSET
;
485 event
->mmap2
.start
= jr
->move
.new_code_addr
;
486 event
->mmap2
.len
= jr
->move
.code_size
;
487 event
->mmap2
.pid
= pid
;
488 event
->mmap2
.tid
= tid
;
489 event
->mmap2
.ino
= st
.st_ino
;
490 event
->mmap2
.maj
= major(st
.st_dev
);
491 event
->mmap2
.min
= minor(st
.st_dev
);
492 event
->mmap2
.prot
= st
.st_mode
;
493 event
->mmap2
.flags
= MAP_SHARED
;
494 event
->mmap2
.ino_generation
= 1;
496 id
= (void *)((unsigned long)event
+ event
->mmap
.header
.size
- idr_size
);
497 if (jd
->sample_type
& PERF_SAMPLE_TID
) {
501 if (jd
->sample_type
& PERF_SAMPLE_TIME
)
502 id
->time
= jr
->load
.p
.timestamp
;
505 * create pseudo sample to induce dso hit increment
506 * use first address as sample address
508 memset(&sample
, 0, sizeof(sample
));
509 sample
.cpumode
= PERF_RECORD_MISC_USER
;
512 sample
.time
= id
->time
;
513 sample
.ip
= jr
->move
.new_code_addr
;
515 ret
= perf_event__process_mmap2(tool
, event
, &sample
, jd
->machine
);
519 ret
= jit_inject_event(jd
, event
);
521 build_id__mark_dso_hit(tool
, event
, &sample
, NULL
, jd
->machine
);
526 static int jit_repipe_debug_info(struct jit_buf_desc
*jd
, union jr_entry
*jr
)
534 sz
= jr
->prefix
.total_size
- sizeof(jr
->info
);
539 memcpy(data
, &jr
->info
.entries
, sz
);
541 jd
->debug_data
= data
;
544 * we must use nr_entry instead of size here because
545 * we cannot distinguish actual entry from padding otherwise
547 jd
->nr_debug_entries
= jr
->info
.nr_entry
;
553 jit_process_dump(struct jit_buf_desc
*jd
)
558 while ((jr
= jit_get_next_entry(jd
))) {
559 switch(jr
->prefix
.id
) {
561 ret
= jit_repipe_code_load(jd
, jr
);
564 ret
= jit_repipe_code_move(jd
, jr
);
566 case JIT_CODE_DEBUG_INFO
:
567 ret
= jit_repipe_debug_info(jd
, jr
);
578 jit_inject(struct jit_buf_desc
*jd
, char *path
)
583 fprintf(stderr
, "injecting: %s\n", path
);
585 ret
= jit_open(jd
, path
);
589 ret
= jit_process_dump(jd
);
594 fprintf(stderr
, "injected: %s (%d)\n", path
, ret
);
600 * File must be with pattern .../jit-XXXX.dump
601 * where XXXX is the PID of the process which did the mmap()
602 * as captured in the RECORD_MMAP record
605 jit_detect(char *mmap_name
, pid_t pid
)
612 fprintf(stderr
, "jit marker trying : %s\n", mmap_name
);
616 p
= strrchr(mmap_name
, '/');
623 if (strncmp(p
, "/jit-", 5))
632 * must be followed by a pid
637 pid2
= (int)strtol(p
, &end
, 10);
642 * pid does not match mmap pid
643 * pid==0 in system-wide mode (synthesized)
645 if (pid
&& pid2
!= pid
)
650 if (strcmp(end
, ".dump"))
654 fprintf(stderr
, "jit marker found: %s\n", mmap_name
);
660 jit_process(struct perf_session
*session
,
661 struct perf_data_file
*output
,
662 struct machine
*machine
,
667 struct perf_evsel
*first
;
668 struct jit_buf_desc jd
;
672 * first, detect marker mmap (i.e., the jitdump mmap)
674 if (jit_detect(filename
, pid
))
677 memset(&jd
, 0, sizeof(jd
));
679 jd
.session
= session
;
681 jd
.machine
= machine
;
684 * track sample_type to compute id_all layout
685 * perf sets the same sample type to all events as of now
687 first
= perf_evlist__first(session
->evlist
);
688 jd
.sample_type
= first
->attr
.sample_type
;
692 ret
= jit_inject(&jd
, filename
);
694 *nbytes
= jd
.bytes_written
;