aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-02-09 04:38:40 -0500
committerIngo Molnar <mingo@kernel.org>2016-02-09 04:38:40 -0500
commit156d22386503e1efc58b0f3244895b1c0f930018 (patch)
treea0a2764ff4ffe4e86f2858b2f6a09ea57d519cdc
parentd0af1c0525d561fe3ab6d7a767cdd52704da25cd (diff)
parent598b7c6919c7bbcc1243009721a01bc12275ff3e (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible fixes: - Handle spaces in file names obtained from /proc/pid/maps (Marcin Ślusarz) New features: - Improved support for Java, using the JVMTI agent library to do jitdumps that then will be inserted in synthesized PERF_RECORD_MMAP2 events via 'perf inject' pointed to synthesized ELF files stored in ~/.debug and keyed with build-ids, to allow symbol resolution and even annotation with source line info, see the changeset comments to see how to use it (Stephane Eranian) Documentation changes: - Document mmore variables in the 'perf config' man page (Taeung Song) Infrastructure changes: - Improve a bit the 'make -C tools/perf build-test' output (Arnaldo Carvalho de Melo) - Do 'build-test' in parallel, using 'make -j' (Arnaldo Carvalho de Melo) - Fix handling of 'clean' in multi-target make invokations for parallell builds (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/build/Makefile.feature2
-rw-r--r--tools/build/feature/Makefile4
-rw-r--r--tools/build/feature/test-all.c5
-rw-r--r--tools/build/feature/test-libcrypto.c17
-rw-r--r--tools/perf/Documentation/perf-config.txt143
-rw-r--r--tools/perf/Documentation/perf-inject.txt7
-rw-r--r--tools/perf/Makefile16
-rw-r--r--tools/perf/Makefile.perf3
-rw-r--r--tools/perf/builtin-inject.c107
-rw-r--r--tools/perf/config/Makefile11
-rw-r--r--tools/perf/jvmti/Makefile76
-rw-r--r--tools/perf/jvmti/jvmti_agent.c465
-rw-r--r--tools/perf/jvmti/jvmti_agent.h36
-rw-r--r--tools/perf/jvmti/libjvmti.c304
-rw-r--r--tools/perf/tests/make11
-rw-r--r--tools/perf/util/Build6
-rw-r--r--tools/perf/util/demangle-java.c199
-rw-r--r--tools/perf/util/demangle-java.h10
-rw-r--r--tools/perf/util/event.c2
-rw-r--r--tools/perf/util/genelf.c449
-rw-r--r--tools/perf/util/genelf.h67
-rw-r--r--tools/perf/util/genelf_debug.c610
-rw-r--r--tools/perf/util/jit.h15
-rw-r--r--tools/perf/util/jitdump.c672
-rw-r--r--tools/perf/util/jitdump.h124
-rw-r--r--tools/perf/util/symbol-elf.c3
26 files changed, 3357 insertions, 7 deletions
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 7bff2ea831cf..6b7707270aa3 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -46,6 +46,7 @@ FEATURE_TESTS_BASIC := \
46 libpython \ 46 libpython \
47 libpython-version \ 47 libpython-version \
48 libslang \ 48 libslang \
49 libcrypto \
49 libunwind \ 50 libunwind \
50 pthread-attr-setaffinity-np \ 51 pthread-attr-setaffinity-np \
51 stackprotector-all \ 52 stackprotector-all \
@@ -87,6 +88,7 @@ FEATURE_DISPLAY ?= \
87 libperl \ 88 libperl \
88 libpython \ 89 libpython \
89 libslang \ 90 libslang \
91 libcrypto \
90 libunwind \ 92 libunwind \
91 libdw-dwarf-unwind \ 93 libdw-dwarf-unwind \
92 zlib \ 94 zlib \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index bf8f0352264d..c5f4c417428d 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -23,6 +23,7 @@ FILES= \
23 test-libpython.bin \ 23 test-libpython.bin \
24 test-libpython-version.bin \ 24 test-libpython-version.bin \
25 test-libslang.bin \ 25 test-libslang.bin \
26 test-libcrypto.bin \
26 test-libunwind.bin \ 27 test-libunwind.bin \
27 test-libunwind-debug-frame.bin \ 28 test-libunwind-debug-frame.bin \
28 test-pthread-attr-setaffinity-np.bin \ 29 test-pthread-attr-setaffinity-np.bin \
@@ -105,6 +106,9 @@ $(OUTPUT)test-libaudit.bin:
105$(OUTPUT)test-libslang.bin: 106$(OUTPUT)test-libslang.bin:
106 $(BUILD) -I/usr/include/slang -lslang 107 $(BUILD) -I/usr/include/slang -lslang
107 108
109$(OUTPUT)test-libcrypto.bin:
110 $(BUILD) -lcrypto
111
108$(OUTPUT)test-gtk2.bin: 112$(OUTPUT)test-gtk2.bin:
109 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) 113 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
110 114
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 81025cade45f..e499a36c1e4a 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -129,6 +129,10 @@
129# include "test-bpf.c" 129# include "test-bpf.c"
130#undef main 130#undef main
131 131
132#define main main_test_libcrypto
133# include "test-libcrypto.c"
134#undef main
135
132int main(int argc, char *argv[]) 136int main(int argc, char *argv[])
133{ 137{
134 main_test_libpython(); 138 main_test_libpython();
@@ -158,6 +162,7 @@ int main(int argc, char *argv[])
158 main_test_lzma(); 162 main_test_lzma();
159 main_test_get_cpuid(); 163 main_test_get_cpuid();
160 main_test_bpf(); 164 main_test_bpf();
165 main_test_libcrypto();
161 166
162 return 0; 167 return 0;
163} 168}
diff --git a/tools/build/feature/test-libcrypto.c b/tools/build/feature/test-libcrypto.c
new file mode 100644
index 000000000000..bd79dc7f28d3
--- /dev/null
+++ b/tools/build/feature/test-libcrypto.c
@@ -0,0 +1,17 @@
1#include <openssl/sha.h>
2#include <openssl/md5.h>
3
4int main(void)
5{
6 MD5_CTX context;
7 unsigned char md[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
8 unsigned char dat[] = "12345";
9
10 MD5_Init(&context);
11 MD5_Update(&context, &dat[0], sizeof(dat));
12 MD5_Final(&md[0], &context);
13
14 SHA1(&dat[0], sizeof(dat), &md[0]);
15
16 return 0;
17}
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 74589c68558a..c7158bfb1649 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -296,6 +296,149 @@ hist.*::
296 and 'baz' to 50.00% for each, while 'absolute' would show their 296 and 'baz' to 50.00% for each, while 'absolute' would show their
297 current overhead (33.33%). 297 current overhead (33.33%).
298 298
299ui.*::
300 ui.show-headers::
301 This option controls display of column headers (like 'Overhead' and 'Symbol')
302 in 'report' and 'top'. If this option is false, they are hidden.
303 This option is only applied to TUI.
304
305call-graph.*::
306 When sub-commands 'top' and 'report' work with -g/—-children
307 there're options in control of call-graph.
308
309 call-graph.record-mode::
310 The record-mode can be 'fp' (frame pointer), 'dwarf' and 'lbr'.
311 The value of 'dwarf' is effective only if perf detect needed library
312 (libunwind or a recent version of libdw).
313 'lbr' only work for cpus that support it.
314
315 call-graph.dump-size::
316 The size of stack to dump in order to do post-unwinding. Default is 8192 (byte).
317 When using dwarf into record-mode, the default size will be used if omitted.
318
319 call-graph.print-type::
320 The print-types can be graph (graph absolute), fractal (graph relative),
321 flat and folded. This option controls a way to show overhead for each callchain
322 entry. Suppose a following example.
323
324 Overhead Symbols
325 ........ .......
326 40.00% foo
327 |
328 ---foo
329 |
330 |--50.00%--bar
331 | main
332 |
333 --50.00%--baz
334 main
335
336 This output is a 'fractal' format. The 'foo' came from 'bar' and 'baz' exactly
337 half and half so 'fractal' shows 50.00% for each
338 (meaning that it assumes 100% total overhead of 'foo').
339
340 The 'graph' uses absolute overhead value of 'foo' as total so each of
341 'bar' and 'baz' callchain will have 20.00% of overhead.
342 If 'flat' is used, single column and linear exposure of call chains.
343 'folded' mean call chains are displayed in a line, separated by semicolons.
344
345 call-graph.order::
346 This option controls print order of callchains. The default is
347 'callee' which means callee is printed at top and then followed by its
348 caller and so on. The 'caller' prints it in reverse order.
349
350 If this option is not set and report.children or top.children is
351 set to true (or the equivalent command line option is given),
352 the default value of this option is changed to 'caller' for the
353 execution of 'perf report' or 'perf top'. Other commands will
354 still default to 'callee'.
355
356 call-graph.sort-key::
357 The callchains are merged if they contain same information.
358 The sort-key option determines a way to compare the callchains.
359 A value of 'sort-key' can be 'function' or 'address'.
360 The default is 'function'.
361
362 call-graph.threshold::
363 When there're many callchains it'd print tons of lines. So perf omits
364 small callchains under a certain overhead (threshold) and this option
365 control the threshold. Default is 0.5 (%). The overhead is calculated
366 by value depends on call-graph.print-type.
367
368 call-graph.print-limit::
369 This is a maximum number of lines of callchain printed for a single
370 histogram entry. Default is 0 which means no limitation.
371
372report.*::
373 report.percent-limit::
374 This one is mostly the same as call-graph.threshold but works for
375 histogram entries. Entries having an overhead lower than this
376 percentage will not be printed. Default is '0'. If percent-limit
377 is '10', only entries which have more than 10% of overhead will be
378 printed.
379
380 report.queue-size::
381 This option sets up the maximum allocation size of the internal
382 event queue for ordering events. Default is 0, meaning no limit.
383
384 report.children::
385 'Children' means functions called from another function.
386 If this option is true, 'perf report' cumulates callchains of children
387 and show (accumulated) total overhead as well as 'Self' overhead.
388 Please refer to the 'perf report' manual. The default is 'true'.
389
390 report.group::
391 This option is to show event group information together.
392 Example output with this turned on, notice that there is one column
393 per event in the group, ref-cycles and cycles:
394
395 # group: {ref-cycles,cycles}
396 # ========
397 #
398 # Samples: 7K of event 'anon group { ref-cycles, cycles }'
399 # Event count (approx.): 6876107743
400 #
401 # Overhead Command Shared Object Symbol
402 # ................ ....... ................. ...................
403 #
404 99.84% 99.76% noploop noploop [.] main
405 0.07% 0.00% noploop ld-2.15.so [.] strcmp
406 0.03% 0.00% noploop [kernel.kallsyms] [k] timerqueue_del
407
408top.*::
409 top.children::
410 Same as 'report.children'. So if it is enabled, the output of 'top'
411 command will have 'Children' overhead column as well as 'Self' overhead
412 column by default.
413 The default is 'true'.
414
415man.*::
416 man.viewer::
417 This option can assign a tool to view manual pages when 'help'
418 subcommand was invoked. Supported tools are 'man', 'woman'
419 (with emacs client) and 'konqueror'. Default is 'man'.
420
421 New man viewer tool can be also added using 'man.<tool>.cmd'
422 or use different path using 'man.<tool>.path' config option.
423
424pager.*::
425 pager.<subcommand>::
426 When the subcommand is run on stdio, determine whether it uses
427 pager or not based on this value. Default is 'unspecified'.
428
429kmem.*::
430 kmem.default::
431 This option decides which allocator is to be analyzed if neither
432 '--slab' nor '--page' option is used. Default is 'slab'.
433
434record.*::
435 record.build-id::
436 This option can be 'cache', 'no-cache' or 'skip'.
437 'cache' is to post-process data and save/update the binaries into
438 the build-id cache (in ~/.debug). This is the default.
439 But if this option is 'no-cache', it will not update the build-id cache.
440 'skip' skips post-processing and does not update the cache.
441
299SEE ALSO 442SEE ALSO
300-------- 443--------
301linkperf:perf[1] 444linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 0b1cedeef895..87b2588d1cbd 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -53,6 +53,13 @@ include::itrace.txt[]
53--strip:: 53--strip::
54 Use with --itrace to strip out non-synthesized events. 54 Use with --itrace to strip out non-synthesized events.
55 55
56-j::
57--jit::
58 Process jitdump files by injecting the mmap records corresponding to jitted
59 functions. This option also generates the ELF images for each jitted function
60 found in the jitdumps files captured in the input perf.data file. Use this option
61 if you are monitoring environment using JIT runtimes, such as Java, DART or V8.
62
56SEE ALSO 63SEE ALSO
57-------- 64--------
58linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] 65linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4b68f465195c..32a64e619028 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -68,6 +68,20 @@ all tags TAGS:
68 $(print_msg) 68 $(print_msg)
69 $(make) 69 $(make)
70 70
71ifdef MAKECMDGOALS
72has_clean := 0
73ifneq ($(filter clean,$(MAKECMDGOALS)),)
74 has_clean := 1
75endif # clean
76
77ifeq ($(has_clean),1)
78 rest := $(filter-out clean,$(MAKECMDGOALS))
79 ifneq ($(rest),)
80$(rest): clean
81 endif # rest
82endif # has_clean
83endif # MAKECMDGOALS
84
71# 85#
72# The clean target is not really parallel, don't print the jobs info: 86# The clean target is not really parallel, don't print the jobs info:
73# 87#
@@ -85,7 +99,7 @@ clean:
85# make -C tools/perf -f tests/make 99# make -C tools/perf -f tests/make
86# 100#
87build-test: 101build-test:
88 @$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile --no-print-directory tarpkg out 102 @$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory tarpkg out
89 103
90# 104#
91# All other targets get passed through: 105# All other targets get passed through:
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 0ef3d97d7954..d404117810a7 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -58,6 +58,9 @@ include config/utilities.mak
58# 58#
59# Define NO_LIBBIONIC if you do not want bionic support 59# Define NO_LIBBIONIC if you do not want bionic support
60# 60#
61# Define NO_LIBCRYPTO if you do not want libcrypto (openssl) support
62# used for generating build-ids for ELFs generated by jitdump.
63#
61# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support 64# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
62# for dwarf backtrace post unwind. 65# for dwarf backtrace post unwind.
63# 66#
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0022e02ed31a..b38445f08c2f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,6 +17,7 @@
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h" 19#include "util/auxtrace.h"
20#include "util/jit.h"
20 21
21#include <subcmd/parse-options.h> 22#include <subcmd/parse-options.h>
22 23
@@ -29,6 +30,7 @@ struct perf_inject {
29 bool sched_stat; 30 bool sched_stat;
30 bool have_auxtrace; 31 bool have_auxtrace;
31 bool strip; 32 bool strip;
33 bool jit_mode;
32 const char *input_name; 34 const char *input_name;
33 struct perf_data_file output; 35 struct perf_data_file output;
34 u64 bytes_written; 36 u64 bytes_written;
@@ -71,6 +73,15 @@ static int perf_event__repipe_oe_synth(struct perf_tool *tool,
71 return perf_event__repipe_synth(tool, event); 73 return perf_event__repipe_synth(tool, event);
72} 74}
73 75
76#ifdef HAVE_LIBELF_SUPPORT
77static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
78 union perf_event *event __maybe_unused,
79 struct ordered_events *oe __maybe_unused)
80{
81 return 0;
82}
83#endif
84
74static int perf_event__repipe_op2_synth(struct perf_tool *tool, 85static int perf_event__repipe_op2_synth(struct perf_tool *tool,
75 union perf_event *event, 86 union perf_event *event,
76 struct perf_session *session 87 struct perf_session *session
@@ -234,6 +245,27 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
234 return err; 245 return err;
235} 246}
236 247
248#ifdef HAVE_LIBELF_SUPPORT
249static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
250 union perf_event *event,
251 struct perf_sample *sample,
252 struct machine *machine)
253{
254 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
255 u64 n = 0;
256
257 /*
258 * if jit marker, then inject jit mmaps and generate ELF images
259 */
260 if (!jit_process(inject->session, &inject->output, machine,
261 event->mmap.filename, sample->pid, &n)) {
262 inject->bytes_written += n;
263 return 0;
264 }
265 return perf_event__repipe_mmap(tool, event, sample, machine);
266}
267#endif
268
237static int perf_event__repipe_mmap2(struct perf_tool *tool, 269static int perf_event__repipe_mmap2(struct perf_tool *tool,
238 union perf_event *event, 270 union perf_event *event,
239 struct perf_sample *sample, 271 struct perf_sample *sample,
@@ -247,6 +279,27 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
247 return err; 279 return err;
248} 280}
249 281
282#ifdef HAVE_LIBELF_SUPPORT
283static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
284 union perf_event *event,
285 struct perf_sample *sample,
286 struct machine *machine)
287{
288 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
289 u64 n = 0;
290
291 /*
292 * if jit marker, then inject jit mmaps and generate ELF images
293 */
294 if (!jit_process(inject->session, &inject->output, machine,
295 event->mmap2.filename, sample->pid, &n)) {
296 inject->bytes_written += n;
297 return 0;
298 }
299 return perf_event__repipe_mmap2(tool, event, sample, machine);
300}
301#endif
302
250static int perf_event__repipe_fork(struct perf_tool *tool, 303static int perf_event__repipe_fork(struct perf_tool *tool,
251 union perf_event *event, 304 union perf_event *event,
252 struct perf_sample *sample, 305 struct perf_sample *sample,
@@ -664,6 +717,23 @@ static int __cmd_inject(struct perf_inject *inject)
664 return ret; 717 return ret;
665} 718}
666 719
720#ifdef HAVE_LIBELF_SUPPORT
721static int
722jit_validate_events(struct perf_session *session)
723{
724 struct perf_evsel *evsel;
725
726 /*
727 * check that all events use CLOCK_MONOTONIC
728 */
729 evlist__for_each(session->evlist, evsel) {
730 if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
731 return -1;
732 }
733 return 0;
734}
735#endif
736
667int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) 737int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
668{ 738{
669 struct perf_inject inject = { 739 struct perf_inject inject = {
@@ -703,7 +773,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
703 }; 773 };
704 int ret; 774 int ret;
705 775
706 const struct option options[] = { 776 struct option options[] = {
707 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 777 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
708 "Inject build-ids into the output stream"), 778 "Inject build-ids into the output stream"),
709 OPT_STRING('i', "input", &inject.input_name, "file", 779 OPT_STRING('i', "input", &inject.input_name, "file",
@@ -713,6 +783,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
713 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 783 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
714 "Merge sched-stat and sched-switch for getting events " 784 "Merge sched-stat and sched-switch for getting events "
715 "where and how long tasks slept"), 785 "where and how long tasks slept"),
786 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
716 OPT_INCR('v', "verbose", &verbose, 787 OPT_INCR('v', "verbose", &verbose,
717 "be more verbose (show build ids, etc)"), 788 "be more verbose (show build ids, etc)"),
718 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 789 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
@@ -729,7 +800,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
729 "perf inject [<options>]", 800 "perf inject [<options>]",
730 NULL 801 NULL
731 }; 802 };
732 803#ifndef HAVE_LIBELF_SUPPORT
804 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
805#endif
733 argc = parse_options(argc, argv, options, inject_usage, 0); 806 argc = parse_options(argc, argv, options, inject_usage, 0);
734 807
735 /* 808 /*
@@ -755,6 +828,36 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
755 if (inject.session == NULL) 828 if (inject.session == NULL)
756 return -1; 829 return -1;
757 830
831 if (inject.build_ids) {
832 /*
833 * to make sure the mmap records are ordered correctly
834 * and so that the correct especially due to jitted code
835 * mmaps. We cannot generate the buildid hit list and
836 * inject the jit mmaps at the same time for now.
837 */
838 inject.tool.ordered_events = true;
839 inject.tool.ordering_requires_timestamps = true;
840 }
841#ifdef HAVE_LIBELF_SUPPORT
842 if (inject.jit_mode) {
843 /*
844 * validate event is using the correct clockid
845 */
846 if (jit_validate_events(inject.session)) {
847 fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
848 return -1;
849 }
850 inject.tool.mmap2 = perf_event__jit_repipe_mmap2;
851 inject.tool.mmap = perf_event__jit_repipe_mmap;
852 inject.tool.ordered_events = true;
853 inject.tool.ordering_requires_timestamps = true;
854 /*
855 * JIT MMAP injection injects all MMAP events in one go, so it
856 * does not obey finished_round semantics.
857 */
858 inject.tool.finished_round = perf_event__drop_oe;
859 }
860#endif
758 ret = symbol__init(&inject.session->header.env); 861 ret = symbol__init(&inject.session->header.env);
759 if (ret < 0) 862 if (ret < 0)
760 goto out_delete; 863 goto out_delete;
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 0045a5ddd0ca..f7aeaf303f5a 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -404,6 +404,17 @@ ifndef NO_LIBAUDIT
404 endif 404 endif
405endif 405endif
406 406
407ifndef NO_LIBCRYPTO
408 ifneq ($(feature-libcrypto), 1)
409 msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
410 NO_LIBCRYPTO := 1
411 else
412 CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
413 EXTLIBS += -lcrypto
414 $(call detected,CONFIG_CRYPTO)
415 endif
416endif
417
407ifdef NO_NEWT 418ifdef NO_NEWT
408 NO_SLANG=1 419 NO_SLANG=1
409endif 420endif
diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
new file mode 100644
index 000000000000..5968f8332a28
--- /dev/null
+++ b/tools/perf/jvmti/Makefile
@@ -0,0 +1,76 @@
1ARCH=$(shell uname -m)
2
3ifeq ($(ARCH), x86_64)
4JARCH=amd64
5endif
6ifeq ($(ARCH), armv7l)
7JARCH=armhf
8endif
9ifeq ($(ARCH), armv6l)
10JARCH=armhf
11endif
12ifeq ($(ARCH), aarch64)
13JARCH=aarch64
14endif
15ifeq ($(ARCH), ppc64)
16JARCH=powerpc
17endif
18ifeq ($(ARCH), ppc64le)
19JARCH=powerpc
20endif
21
22DESTDIR=/usr/local
23
24VERSION=1
25REVISION=0
26AGE=0
27
28LN=ln -sf
29RM=rm
30
31SLIBJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE)
32VLIBJVMTI=libjvmti.so.$(VERSION)
33SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
34SOLIBEXT=so
35
36# The following works at least on fedora 23, you may need the next
37# line for other distros.
38JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
39#JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
40# -lrt required in 32-bit mode for clock_gettime()
41LIBS=-lelf -lrt
42INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
43
44TARGETS=$(SLIBJVMTI)
45
46SRCS=libjvmti.c jvmti_agent.c
47OBJS=$(SRCS:.c=.o)
48SOBJS=$(OBJS:.o=.lo)
49OPT=-O2 -g -Werror -Wall
50
51CFLAGS=$(INCDIR) $(OPT)
52
53all: $(TARGETS)
54
55.c.o:
56 $(CC) $(CFLAGS) -c $*.c
57.c.lo:
58 $(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo
59
60$(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h
61
62$(SLIBJVMTI): $(SOBJS)
63 $(CC) $(CFLAGS) $(SLDFLAGS) -o $@ $(SOBJS) $(LIBS)
64 $(LN) $@ libjvmti.$(SOLIBEXT)
65
66clean:
67 $(RM) -f *.o *.so.* *.so *.lo
68
69install:
70 -mkdir -p $(DESTDIR)/lib
71 install -m 755 $(SLIBJVMTI) $(DESTDIR)/lib/
72 (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) $(VLIBJVMTI))
73 (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) libjvmti.$(SOLIBEXT))
74 ldconfig
75
76.SUFFIXES: .c .S .o .lo
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
new file mode 100644
index 000000000000..6461e02ab940
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -0,0 +1,465 @@
1/*
2 * jvmti_agent.c: JVMTI agent interface
3 *
4 * Adapted from the Oprofile code in opagent.c:
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Copyright 2007 OProfile authors
20 * Jens Wilke
21 * Daniel Hansel
22 * Copyright IBM Corporation 2007
23 */
24#include <sys/types.h>
25#include <sys/stat.h> /* for mkdir() */
26#include <stdio.h>
27#include <errno.h>
28#include <string.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <limits.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <time.h>
35#include <sys/mman.h>
36#include <syscall.h> /* for gettid() */
37#include <err.h>
38
39#include "jvmti_agent.h"
40#include "../util/jitdump.h"
41
42#define JIT_LANG "java"
43
44static char jit_path[PATH_MAX];
45static void *marker_addr;
46
47/*
48 * padding buffer
49 */
50static const char pad_bytes[7];
51
52static inline pid_t gettid(void)
53{
54 return (pid_t)syscall(__NR_gettid);
55}
56
57static int get_e_machine(struct jitheader *hdr)
58{
59 ssize_t sret;
60 char id[16];
61 int fd, ret = -1;
62 int m = -1;
63 struct {
64 uint16_t e_type;
65 uint16_t e_machine;
66 } info;
67
68 fd = open("/proc/self/exe", O_RDONLY);
69 if (fd == -1)
70 return -1;
71
72 sret = read(fd, id, sizeof(id));
73 if (sret != sizeof(id))
74 goto error;
75
76 /* check ELF signature */
77 if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
78 goto error;
79
80 sret = read(fd, &info, sizeof(info));
81 if (sret != sizeof(info))
82 goto error;
83
84 m = info.e_machine;
85 if (m < 0)
86 m = 0; /* ELF EM_NONE */
87
88 hdr->elf_mach = m;
89 ret = 0;
90error:
91 close(fd);
92 return ret;
93}
94
95#define NSEC_PER_SEC 1000000000
96static int perf_clk_id = CLOCK_MONOTONIC;
97
98static inline uint64_t
99timespec_to_ns(const struct timespec *ts)
100{
101 return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
102}
103
104static inline uint64_t
105perf_get_timestamp(void)
106{
107 struct timespec ts;
108 int ret;
109
110 ret = clock_gettime(perf_clk_id, &ts);
111 if (ret)
112 return 0;
113
114 return timespec_to_ns(&ts);
115}
116
117static int
118debug_cache_init(void)
119{
120 char str[32];
121 char *base, *p;
122 struct tm tm;
123 time_t t;
124 int ret;
125
126 time(&t);
127 localtime_r(&t, &tm);
128
129 base = getenv("JITDUMPDIR");
130 if (!base)
131 base = getenv("HOME");
132 if (!base)
133 base = ".";
134
135 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
136
137 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
138
139 ret = mkdir(jit_path, 0755);
140 if (ret == -1) {
141 if (errno != EEXIST) {
142 warn("jvmti: cannot create jit cache dir %s", jit_path);
143 return -1;
144 }
145 }
146
147 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
148 ret = mkdir(jit_path, 0755);
149 if (ret == -1) {
150 if (errno != EEXIST) {
151 warn("cannot create jit cache dir %s", jit_path);
152 return -1;
153 }
154 }
155
156 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
157
158 p = mkdtemp(jit_path);
159 if (p != jit_path) {
160 warn("cannot create jit cache dir %s", jit_path);
161 return -1;
162 }
163
164 return 0;
165}
166
167static int
168perf_open_marker_file(int fd)
169{
170 long pgsz;
171
172 pgsz = sysconf(_SC_PAGESIZE);
173 if (pgsz == -1)
174 return -1;
175
176 /*
177 * we mmap the jitdump to create an MMAP RECORD in perf.data file.
178 * The mmap is captured either live (perf record running when we mmap)
179 * or in deferred mode, via /proc/PID/maps
180 * the MMAP record is used as a marker of a jitdump file for more meta
181 * data info about the jitted code. Perf report/annotate detect this
182 * special filename and process the jitdump file.
183 *
184 * mapping must be PROT_EXEC to ensure it is captured by perf record
185 * even when not using -d option
186 */
187 marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
188 return (marker_addr == MAP_FAILED) ? -1 : 0;
189}
190
191static void
192perf_close_marker_file(void)
193{
194 long pgsz;
195
196 if (!marker_addr)
197 return;
198
199 pgsz = sysconf(_SC_PAGESIZE);
200 if (pgsz == -1)
201 return;
202
203 munmap(marker_addr, pgsz);
204}
205
206void *jvmti_open(void)
207{
208 int pad_cnt;
209 char dump_path[PATH_MAX];
210 struct jitheader header;
211 int fd;
212 FILE *fp;
213
214 /*
215 * check if clockid is supported
216 */
217 if (!perf_get_timestamp())
218 warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
219
220 memset(&header, 0, sizeof(header));
221
222 debug_cache_init();
223
224 /*
225 * jitdump file name
226 */
227 snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
228
229 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
230 if (fd == -1)
231 return NULL;
232
233 /*
234 * create perf.data maker for the jitdump file
235 */
236 if (perf_open_marker_file(fd)) {
237 warnx("jvmti: failed to create marker file");
238 return NULL;
239 }
240
241 fp = fdopen(fd, "w+");
242 if (!fp) {
243 warn("jvmti: cannot create %s", dump_path);
244 close(fd);
245 goto error;
246 }
247
248 warnx("jvmti: jitdump in %s", dump_path);
249
250 if (get_e_machine(&header)) {
251 warn("get_e_machine failed\n");
252 goto error;
253 }
254
255 header.magic = JITHEADER_MAGIC;
256 header.version = JITHEADER_VERSION;
257 header.total_size = sizeof(header);
258 header.pid = getpid();
259
260 /* calculate amount of padding '\0' */
261 pad_cnt = PADDING_8ALIGNED(header.total_size);
262 header.total_size += pad_cnt;
263
264 header.timestamp = perf_get_timestamp();
265
266 if (!fwrite(&header, sizeof(header), 1, fp)) {
267 warn("jvmti: cannot write dumpfile header");
268 goto error;
269 }
270
271 /* write padding '\0' if necessary */
272 if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
273 warn("jvmti: cannot write dumpfile header padding");
274 goto error;
275 }
276
277 return fp;
278error:
279 fclose(fp);
280 return NULL;
281}
282
283int
284jvmti_close(void *agent)
285{
286 struct jr_code_close rec;
287 FILE *fp = agent;
288
289 if (!fp) {
290 warnx("jvmti: incalid fd in close_agent");
291 return -1;
292 }
293
294 rec.p.id = JIT_CODE_CLOSE;
295 rec.p.total_size = sizeof(rec);
296
297 rec.p.timestamp = perf_get_timestamp();
298
299 if (!fwrite(&rec, sizeof(rec), 1, fp))
300 return -1;
301
302 fclose(fp);
303
304 fp = NULL;
305
306 perf_close_marker_file();
307
308 return 0;
309}
310
311int
312jvmti_write_code(void *agent, char const *sym,
313 uint64_t vma, void const *code, unsigned int const size)
314{
315 static int code_generation = 1;
316 struct jr_code_load rec;
317 size_t sym_len;
318 size_t padding_count;
319 FILE *fp = agent;
320 int ret = -1;
321
322 /* don't care about 0 length function, no samples */
323 if (size == 0)
324 return 0;
325
326 if (!fp) {
327 warnx("jvmti: invalid fd in write_native_code");
328 return -1;
329 }
330
331 sym_len = strlen(sym) + 1;
332
333 rec.p.id = JIT_CODE_LOAD;
334 rec.p.total_size = sizeof(rec) + sym_len;
335 padding_count = PADDING_8ALIGNED(rec.p.total_size);
336 rec.p. total_size += padding_count;
337 rec.p.timestamp = perf_get_timestamp();
338
339 rec.code_size = size;
340 rec.vma = vma;
341 rec.code_addr = vma;
342 rec.pid = getpid();
343 rec.tid = gettid();
344
345 if (code)
346 rec.p.total_size += size;
347
348 /*
349 * If JVM is multi-threaded, nultiple concurrent calls to agent
350 * may be possible, so protect file writes
351 */
352 flockfile(fp);
353
354 /*
355 * get code index inside lock to avoid race condition
356 */
357 rec.code_index = code_generation++;
358
359 ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
360 fwrite_unlocked(sym, sym_len, 1, fp);
361
362 if (padding_count)
363 fwrite_unlocked(pad_bytes, padding_count, 1, fp);
364
365 if (code)
366 fwrite_unlocked(code, size, 1, fp);
367
368 funlockfile(fp);
369
370 ret = 0;
371
372 return ret;
373}
374
375int
376jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
377 jvmti_line_info_t *li, int nr_lines)
378{
379 struct jr_code_debug_info rec;
380 size_t sret, len, size, flen;
381 size_t padding_count;
382 uint64_t addr;
383 const char *fn = file;
384 FILE *fp = agent;
385 int i;
386
387 /*
388 * no entry to write
389 */
390 if (!nr_lines)
391 return 0;
392
393 if (!fp) {
394 warnx("jvmti: invalid fd in write_debug_info");
395 return -1;
396 }
397
398 flen = strlen(file) + 1;
399
400 rec.p.id = JIT_CODE_DEBUG_INFO;
401 size = sizeof(rec);
402 rec.p.timestamp = perf_get_timestamp();
403 rec.code_addr = (uint64_t)(uintptr_t)code;
404 rec.nr_entry = nr_lines;
405
406 /*
407 * on disk source line info layout:
408 * uint64_t : addr
409 * int : line number
410 * int : column discriminator
411 * file[] : source file name
412 * padding : pad to multiple of 8 bytes
413 */
414 size += nr_lines * sizeof(struct debug_entry);
415 size += flen * nr_lines;
416 /*
417 * pad to 8 bytes
418 */
419 padding_count = PADDING_8ALIGNED(size);
420
421 rec.p.total_size = size + padding_count;
422
423 /*
424 * If JVM is multi-threaded, nultiple concurrent calls to agent
425 * may be possible, so protect file writes
426 */
427 flockfile(fp);
428
429 sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
430 if (sret != 1)
431 goto error;
432
433 for (i = 0; i < nr_lines; i++) {
434
435 addr = (uint64_t)li[i].pc;
436 len = sizeof(addr);
437 sret = fwrite_unlocked(&addr, len, 1, fp);
438 if (sret != 1)
439 goto error;
440
441 len = sizeof(li[0].line_number);
442 sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
443 if (sret != 1)
444 goto error;
445
446 len = sizeof(li[0].discrim);
447 sret = fwrite_unlocked(&li[i].discrim, len, 1, fp);
448 if (sret != 1)
449 goto error;
450
451 sret = fwrite_unlocked(fn, flen, 1, fp);
452 if (sret != 1)
453 goto error;
454 }
455 if (padding_count)
456 sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
457 if (sret != 1)
458 goto error;
459
460 funlockfile(fp);
461 return 0;
462error:
463 funlockfile(fp);
464 return -1;
465}
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
new file mode 100644
index 000000000000..bedf5d0ba9ff
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -0,0 +1,36 @@
1#ifndef __JVMTI_AGENT_H__
2#define __JVMTI_AGENT_H__
3
4#include <sys/types.h>
5#include <stdint.h>
6#include <jvmti.h>
7
8#define __unused __attribute__((unused))
9
10#if defined(__cplusplus)
11extern "C" {
12#endif
13
14typedef struct {
15 unsigned long pc;
16 int line_number;
17 int discrim; /* discriminator -- 0 for now */
18} jvmti_line_info_t;
19
20void *jvmti_open(void);
21int jvmti_close(void *agent);
22int jvmti_write_code(void *agent, char const *symbol_name,
23 uint64_t vma, void const *code,
24 const unsigned int code_size);
25
26int jvmti_write_debug_info(void *agent,
27 uint64_t code,
28 const char *file,
29 jvmti_line_info_t *li,
30 int nr_lines);
31
32#if defined(__cplusplus)
33}
34
35#endif
36#endif /* __JVMTI_H__ */
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
new file mode 100644
index 000000000000..ac12e4b91a92
--- /dev/null
+++ b/tools/perf/jvmti/libjvmti.c
@@ -0,0 +1,304 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <err.h>
6#include <jvmti.h>
7#include <jvmticmlr.h>
8#include <limits.h>
9
10#include "jvmti_agent.h"
11
12static int has_line_numbers;
13void *jvmti_agent;
14
15static jvmtiError
16do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
17 jvmti_line_info_t *tab, jint *nr)
18{
19 jint i, lines = 0;
20 jint nr_lines = 0;
21 jvmtiLineNumberEntry *loc_tab = NULL;
22 jvmtiError ret;
23
24 ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
25 if (ret != JVMTI_ERROR_NONE)
26 return ret;
27
28 for (i = 0; i < nr_lines; i++) {
29 if (loc_tab[i].start_location < bci) {
30 tab[lines].pc = (unsigned long)pc;
31 tab[lines].line_number = loc_tab[i].line_number;
32 tab[lines].discrim = 0; /* not yet used */
33 lines++;
34 } else {
35 break;
36 }
37 }
38 (*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
39 *nr = lines;
40 return JVMTI_ERROR_NONE;
41}
42
43static jvmtiError
44get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **tab, int *nr_lines)
45{
46 const jvmtiCompiledMethodLoadRecordHeader *hdr;
47 jvmtiCompiledMethodLoadInlineRecord *rec;
48 jvmtiLineNumberEntry *lne = NULL;
49 PCStackInfo *c;
50 jint nr, ret;
51 int nr_total = 0;
52 int i, lines_total = 0;
53
54 if (!(tab && nr_lines))
55 return JVMTI_ERROR_NULL_POINTER;
56
57 /*
58 * Phase 1 -- get the number of lines necessary
59 */
60 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
61 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
62 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
63 for (i = 0; i < rec->numpcs; i++) {
64 c = rec->pcinfo + i;
65 nr = 0;
66 /*
67 * unfortunately, need a tab to get the number of lines!
68 */
69 ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
70 if (ret == JVMTI_ERROR_NONE) {
71 /* free what was allocated for nothing */
72 (*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
73 nr_total += (int)nr;
74 }
75 }
76 }
77 }
78
79 if (nr_total == 0)
80 return JVMTI_ERROR_NOT_FOUND;
81
82 /*
83 * Phase 2 -- allocate big enough line table
84 */
85 *tab = malloc(nr_total * sizeof(**tab));
86 if (!*tab)
87 return JVMTI_ERROR_OUT_OF_MEMORY;
88
89 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
90 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
91 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
92 for (i = 0; i < rec->numpcs; i++) {
93 c = rec->pcinfo + i;
94 nr = 0;
95 ret = do_get_line_numbers(jvmti, c->pc,
96 c->methods[0],
97 c->bcis[0],
98 *tab + lines_total,
99 &nr);
100 if (ret == JVMTI_ERROR_NONE)
101 lines_total += nr;
102 }
103 }
104 }
105 *nr_lines = lines_total;
106 return JVMTI_ERROR_NONE;
107}
108
109static void JNICALL
110compiled_method_load_cb(jvmtiEnv *jvmti,
111 jmethodID method,
112 jint code_size,
113 void const *code_addr,
114 jint map_length,
115 jvmtiAddrLocationMap const *map,
116 const void *compile_info)
117{
118 jvmti_line_info_t *line_tab = NULL;
119 jclass decl_class;
120 char *class_sign = NULL;
121 char *func_name = NULL;
122 char *func_sign = NULL;
123 char *file_name= NULL;
124 char fn[PATH_MAX];
125 uint64_t addr = (uint64_t)(uintptr_t)code_addr;
126 jvmtiError ret;
127 int nr_lines = 0; /* in line_tab[] */
128 size_t len;
129
130 ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
131 &decl_class);
132 if (ret != JVMTI_ERROR_NONE) {
133 warnx("jvmti: cannot get declaring class");
134 return;
135 }
136
137 if (has_line_numbers && map && map_length) {
138 ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
139 if (ret != JVMTI_ERROR_NONE) {
140 warnx("jvmti: cannot get line table for method");
141 nr_lines = 0;
142 }
143 }
144
145 ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
146 if (ret != JVMTI_ERROR_NONE) {
147 warnx("jvmti: cannot get source filename ret=%d", ret);
148 goto error;
149 }
150
151 ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
152 &class_sign, NULL);
153 if (ret != JVMTI_ERROR_NONE) {
154 warnx("jvmti: getclassignature failed");
155 goto error;
156 }
157
158 ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
159 &func_sign, NULL);
160 if (ret != JVMTI_ERROR_NONE) {
161 warnx("jvmti: failed getmethodname");
162 goto error;
163 }
164
165 /*
166 * Assume path name is class hierarchy, this is a common practice with Java programs
167 */
168 if (*class_sign == 'L') {
169 int j, i = 0;
170 char *p = strrchr(class_sign, '/');
171 if (p) {
172 /* drop the 'L' prefix and copy up to the final '/' */
173 for (i = 0; i < (p - class_sign); i++)
174 fn[i] = class_sign[i+1];
175 }
176 /*
177 * append file name, we use loops and not string ops to avoid modifying
178 * class_sign which is used later for the symbol name
179 */
180 for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
181 fn[i] = file_name[j];
182 fn[i] = '\0';
183 } else {
184 /* fallback case */
185 strcpy(fn, file_name);
186 }
187 /*
188 * write source line info record if we have it
189 */
190 if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines))
191 warnx("jvmti: write_debug_info() failed");
192
193 len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
194 {
195 char str[len];
196 snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
197
198 if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
199 warnx("jvmti: write_code() failed");
200 }
201error:
202 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
203 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
204 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
205 (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
206 free(line_tab);
207}
208
209static void JNICALL
210code_generated_cb(jvmtiEnv *jvmti,
211 char const *name,
212 void const *code_addr,
213 jint code_size)
214{
215 uint64_t addr = (uint64_t)(unsigned long)code_addr;
216 int ret;
217
218 ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
219 if (ret)
220 warnx("jvmti: write_code() failed for code_generated");
221}
222
223JNIEXPORT jint JNICALL
224Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
225{
226 jvmtiEventCallbacks cb;
227 jvmtiCapabilities caps1;
228 jvmtiJlocationFormat format;
229 jvmtiEnv *jvmti = NULL;
230 jint ret;
231
232 jvmti_agent = jvmti_open();
233 if (!jvmti_agent) {
234 warnx("jvmti: open_agent failed");
235 return -1;
236 }
237
238 /*
239 * Request a JVMTI interface version 1 environment
240 */
241 ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
242 if (ret != JNI_OK) {
243 warnx("jvmti: jvmti version 1 not supported");
244 return -1;
245 }
246
247 /*
248 * acquire method_load capability, we require it
249 * request line numbers (optional)
250 */
251 memset(&caps1, 0, sizeof(caps1));
252 caps1.can_generate_compiled_method_load_events = 1;
253
254 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
255 if (ret != JVMTI_ERROR_NONE) {
256 warnx("jvmti: acquire compiled_method capability failed");
257 return -1;
258 }
259 ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
260 if (ret == JVMTI_ERROR_NONE && format == JVMTI_JLOCATION_JVMBCI) {
261 memset(&caps1, 0, sizeof(caps1));
262 caps1.can_get_line_numbers = 1;
263 caps1.can_get_source_file_name = 1;
264 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
265 if (ret == JVMTI_ERROR_NONE)
266 has_line_numbers = 1;
267 }
268
269 memset(&cb, 0, sizeof(cb));
270
271 cb.CompiledMethodLoad = compiled_method_load_cb;
272 cb.DynamicCodeGenerated = code_generated_cb;
273
274 ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
275 if (ret != JVMTI_ERROR_NONE) {
276 warnx("jvmti: cannot set event callbacks");
277 return -1;
278 }
279
280 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
281 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
282 if (ret != JVMTI_ERROR_NONE) {
283 warnx("jvmti: setnotification failed for method_load");
284 return -1;
285 }
286
287 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
288 JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
289 if (ret != JVMTI_ERROR_NONE) {
290 warnx("jvmti: setnotification failed on code_generated");
291 return -1;
292 }
293 return 0;
294}
295
296JNIEXPORT void JNICALL
297Agent_OnUnload(JavaVM *jvm __unused)
298{
299 int ret;
300
301 ret = jvmti_close(jvmti_agent);
302 if (ret)
303 errx(1, "Error: op_close_agent()");
304}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index cc72b67bde5e..cac15d93aea6 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -80,6 +80,7 @@ make_no_libaudit := NO_LIBAUDIT=1
80make_no_libbionic := NO_LIBBIONIC=1 80make_no_libbionic := NO_LIBBIONIC=1
81make_no_auxtrace := NO_AUXTRACE=1 81make_no_auxtrace := NO_AUXTRACE=1
82make_no_libbpf := NO_LIBBPF=1 82make_no_libbpf := NO_LIBBPF=1
83make_no_libcrypto := NO_LIBCRYPTO=1
83make_tags := tags 84make_tags := tags
84make_cscope := cscope 85make_cscope := cscope
85make_help := help 86make_help := help
@@ -103,6 +104,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
103make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 104make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
104make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 105make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
105make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 106make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
107make_minimal += NO_LIBCRYPTO=1
106 108
107# $(run) contains all available tests 109# $(run) contains all available tests
108run := make_pure 110run := make_pure
@@ -111,6 +113,9 @@ run := make_pure
111# disable features detection 113# disable features detection
112ifeq ($(MK),Makefile) 114ifeq ($(MK),Makefile)
113run += make_clean_all 115run += make_clean_all
116MAKE_F := $(MAKE)
117else
118MAKE_F := $(MAKE) -f $(MK)
114endif 119endif
115run += make_python_perf_so 120run += make_python_perf_so
116run += make_debug 121run += make_debug
@@ -270,12 +275,12 @@ endif
270 275
271MAKEFLAGS := --no-print-directory 276MAKEFLAGS := --no-print-directory
272 277
273clean := @(cd $(PERF); make -s -f $(MK) $(O_OPT) clean >/dev/null) 278clean := @(cd $(PERF); $(MAKE_F) -s $(O_OPT) clean >/dev/null)
274 279
275$(run): 280$(run):
276 $(call clean) 281 $(call clean)
277 @TMP_DEST=$$(mktemp -d); \ 282 @TMP_DEST=$$(mktemp -d); \
278 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST $($@)"; \ 283 cmd="cd $(PERF) && $(MAKE_F) $($@) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST"; \
279 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \ 284 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
280 ( eval $$cmd ) >> $@ 2>&1; \ 285 ( eval $$cmd ) >> $@ 2>&1; \
281 echo " test: $(call test,$@)" >> $@ 2>&1; \ 286 echo " test: $(call test,$@)" >> $@ 2>&1; \
@@ -286,7 +291,7 @@ $(run_O):
286 $(call clean) 291 $(call clean)
287 @TMP_O=$$(mktemp -d); \ 292 @TMP_O=$$(mktemp -d); \
288 TMP_DEST=$$(mktemp -d); \ 293 TMP_DEST=$$(mktemp -d); \
289 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 294 cmd="cd $(PERF) && $(MAKE_F) $($(patsubst %_O,%,$@)) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST"; \
290 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \ 295 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
291 ( eval $$cmd ) >> $@ 2>&1 && \ 296 ( eval $$cmd ) >> $@ 2>&1 && \
292 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 297 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5eec53a3f4ac..a34752d28488 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -105,8 +105,14 @@ libperf-y += scripting-engines/
105 105
106libperf-$(CONFIG_ZLIB) += zlib.o 106libperf-$(CONFIG_ZLIB) += zlib.o
107libperf-$(CONFIG_LZMA) += lzma.o 107libperf-$(CONFIG_LZMA) += lzma.o
108libperf-y += demangle-java.o
109libperf-$(CONFIG_LIBELF) += jitdump.o
110libperf-$(CONFIG_LIBELF) += genelf.o
111libperf-$(CONFIG_LIBELF) += genelf_debug.o
108 112
109CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 113CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
114# avoid compiler warnings in 32-bit mode
115CFLAGS_genelf_debug.o += -Wno-packed
110 116
111$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 117$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
112 $(call rule_mkdir) 118 $(call rule_mkdir)
diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
new file mode 100644
index 000000000000..3e6062ab2cdd
--- /dev/null
+++ b/tools/perf/util/demangle-java.c
@@ -0,0 +1,199 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <string.h>
4#include "util.h"
5#include "debug.h"
6#include "symbol.h"
7
8#include "demangle-java.h"
9
10enum {
11 MODE_PREFIX = 0,
12 MODE_CLASS = 1,
13 MODE_FUNC = 2,
14 MODE_TYPE = 3,
15 MODE_CTYPE = 3, /* class arg */
16};
17
18#define BASE_ENT(c, n) [c - 'A']=n
19static const char *base_types['Z' - 'A' + 1] = {
20 BASE_ENT('B', "byte" ),
21 BASE_ENT('C', "char" ),
22 BASE_ENT('D', "double" ),
23 BASE_ENT('F', "float" ),
24 BASE_ENT('I', "int" ),
25 BASE_ENT('J', "long" ),
26 BASE_ENT('S', "short" ),
27 BASE_ENT('Z', "bool" ),
28};
29
30/*
31 * demangle Java symbol between str and end positions and stores
32 * up to maxlen characters into buf. The parser starts in mode.
33 *
34 * Use MODE_PREFIX to process entire prototype till end position
35 * Use MODE_TYPE to process return type if str starts on return type char
36 *
37 * Return:
38 * success: buf
39 * error : NULL
40 */
41static char *
42__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
43{
44 int rlen = 0;
45 int array = 0;
46 int narg = 0;
47 const char *q;
48
49 if (!end)
50 end = str + strlen(str);
51
52 for (q = str; q != end; q++) {
53
54 if (rlen == (maxlen - 1))
55 break;
56
57 switch (*q) {
58 case 'L':
59 if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
60 if (mode == MODE_CTYPE) {
61 if (narg)
62 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
63 narg++;
64 }
65 rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
66 if (mode == MODE_PREFIX)
67 mode = MODE_CLASS;
68 } else
69 buf[rlen++] = *q;
70 break;
71 case 'B':
72 case 'C':
73 case 'D':
74 case 'F':
75 case 'I':
76 case 'J':
77 case 'S':
78 case 'Z':
79 if (mode == MODE_TYPE) {
80 if (narg)
81 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
82 rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
83 while (array--)
84 rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
85 array = 0;
86 narg++;
87 } else
88 buf[rlen++] = *q;
89 break;
90 case 'V':
91 if (mode == MODE_TYPE) {
92 rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
93 while (array--)
94 rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
95 array = 0;
96 } else
97 buf[rlen++] = *q;
98 break;
99 case '[':
100 if (mode != MODE_TYPE)
101 goto error;
102 array++;
103 break;
104 case '(':
105 if (mode != MODE_FUNC)
106 goto error;
107 buf[rlen++] = *q;
108 mode = MODE_TYPE;
109 break;
110 case ')':
111 if (mode != MODE_TYPE)
112 goto error;
113 buf[rlen++] = *q;
114 narg = 0;
115 break;
116 case ';':
117 if (mode != MODE_CLASS && mode != MODE_CTYPE)
118 goto error;
119 /* safe because at least one other char to process */
120 if (isalpha(*(q + 1)))
121 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
122 if (mode == MODE_CLASS)
123 mode = MODE_FUNC;
124 else if (mode == MODE_CTYPE)
125 mode = MODE_TYPE;
126 break;
127 case '/':
128 if (mode != MODE_CLASS && mode != MODE_CTYPE)
129 goto error;
130 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
131 break;
132 default :
133 buf[rlen++] = *q;
134 }
135 }
136 buf[rlen] = '\0';
137 return buf;
138error:
139 return NULL;
140}
141
142/*
143 * Demangle Java function signature (openJDK, not GCJ)
144 * input:
145 * str: string to parse. String is not modified
146 * flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
147 * return:
148 * if input can be demangled, then a newly allocated string is returned.
149 * if input cannot be demangled, then NULL is returned
150 *
151 * Note: caller is responsible for freeing demangled string
152 */
153char *
154java_demangle_sym(const char *str, int flags)
155{
156 char *buf, *ptr;
157 char *p;
158 size_t len, l1 = 0;
159
160 if (!str)
161 return NULL;
162
163 /* find start of retunr type */
164 p = strrchr(str, ')');
165 if (!p)
166 return NULL;
167
168 /*
169 * expansion factor estimated to 3x
170 */
171 len = strlen(str) * 3 + 1;
172 buf = malloc(len);
173 if (!buf)
174 return NULL;
175
176 buf[0] = '\0';
177 if (!(flags & JAVA_DEMANGLE_NORET)) {
178 /*
179 * get return type first
180 */
181 ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
182 if (!ptr)
183 goto error;
184
185 /* add space between return type and function prototype */
186 l1 = strlen(buf);
187 buf[l1++] = ' ';
188 }
189
190 /* process function up to return type */
191 ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
192 if (!ptr)
193 goto error;
194
195 return buf;
196error:
197 free(buf);
198 return NULL;
199}
diff --git a/tools/perf/util/demangle-java.h b/tools/perf/util/demangle-java.h
new file mode 100644
index 000000000000..a981c1f968fe
--- /dev/null
+++ b/tools/perf/util/demangle-java.h
@@ -0,0 +1,10 @@
1#ifndef __PERF_DEMANGLE_JAVA
2#define __PERF_DEMANGLE_JAVA 1
3/*
4 * demangle function flags
5 */
6#define JAVA_DEMANGLE_NORET 0x1 /* do not process return type */
7
8char * java_demangle_sym(const char *str, int flags);
9
10#endif /* __PERF_DEMANGLE_JAVA */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 85155e91b61b..7bad5c3fa7b7 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -282,7 +282,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
282 strcpy(execname, ""); 282 strcpy(execname, "");
283 283
284 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 284 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
285 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 285 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n",
286 &event->mmap2.start, &event->mmap2.len, prot, 286 &event->mmap2.start, &event->mmap2.len, prot,
287 &event->mmap2.pgoff, &event->mmap2.maj, 287 &event->mmap2.pgoff, &event->mmap2.maj,
288 &event->mmap2.min, 288 &event->mmap2.min,
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
new file mode 100644
index 000000000000..c1ef805c6a8f
--- /dev/null
+++ b/tools/perf/util/genelf.c
@@ -0,0 +1,449 @@
1/*
2 * genelf.c
3 * Copyright (C) 2014, Google, Inc
4 *
5 * Contributed by:
6 * Stephane Eranian <eranian@gmail.com>
7 *
8 * Released under the GPL v2. (and only v2, not any later version)
9 */
10
11#include <sys/types.h>
12#include <stdio.h>
13#include <getopt.h>
14#include <stddef.h>
15#include <libelf.h>
16#include <string.h>
17#include <stdlib.h>
18#include <inttypes.h>
19#include <limits.h>
20#include <fcntl.h>
21#include <err.h>
22#include <dwarf.h>
23
24#include "perf.h"
25#include "genelf.h"
26#include "../util/jitdump.h"
27
28#define JVMTI
29
30#define BUILD_ID_URANDOM /* different uuid for each run */
31
32#ifdef HAVE_LIBCRYPTO
33
34#define BUILD_ID_MD5
35#undef BUILD_ID_SHA /* does not seem to work well when linked with Java */
36#undef BUILD_ID_URANDOM /* different uuid for each run */
37
38#ifdef BUILD_ID_SHA
39#include <openssl/sha.h>
40#endif
41
42#ifdef BUILD_ID_MD5
43#include <openssl/md5.h>
44#endif
45#endif
46
47
48typedef struct {
49 unsigned int namesz; /* Size of entry's owner string */
50 unsigned int descsz; /* Size of the note descriptor */
51 unsigned int type; /* Interpretation of the descriptor */
52 char name[0]; /* Start of the name+desc data */
53} Elf_Note;
54
55struct options {
56 char *output;
57 int fd;
58};
59
60static char shd_string_table[] = {
61 0,
62 '.', 't', 'e', 'x', 't', 0, /* 1 */
63 '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /* 7 */
64 '.', 's', 'y', 'm', 't', 'a', 'b', 0, /* 17 */
65 '.', 's', 't', 'r', 't', 'a', 'b', 0, /* 25 */
66 '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
67 '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
68 '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
69 '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
70};
71
72static struct buildid_note {
73 Elf_Note desc; /* descsz: size of build-id, must be multiple of 4 */
74 char name[4]; /* GNU\0 */
75 char build_id[20];
76} bnote;
77
78static Elf_Sym symtab[]={
79 /* symbol 0 MUST be the undefined symbol */
80 { .st_name = 0, /* index in sym_string table */
81 .st_info = ELF_ST_TYPE(STT_NOTYPE),
82 .st_shndx = 0, /* for now */
83 .st_value = 0x0,
84 .st_other = ELF_ST_VIS(STV_DEFAULT),
85 .st_size = 0,
86 },
87 { .st_name = 1, /* index in sym_string table */
88 .st_info = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
89 .st_shndx = 1,
90 .st_value = 0, /* for now */
91 .st_other = ELF_ST_VIS(STV_DEFAULT),
92 .st_size = 0, /* for now */
93 }
94};
95
96#ifdef BUILD_ID_URANDOM
97static void
98gen_build_id(struct buildid_note *note,
99 unsigned long load_addr __maybe_unused,
100 const void *code __maybe_unused,
101 size_t csize __maybe_unused)
102{
103 int fd;
104 size_t sz = sizeof(note->build_id);
105 ssize_t sret;
106
107 fd = open("/dev/urandom", O_RDONLY);
108 if (fd == -1)
109 err(1, "cannot access /dev/urandom for builid");
110
111 sret = read(fd, note->build_id, sz);
112
113 close(fd);
114
115 if (sret != (ssize_t)sz)
116 memset(note->build_id, 0, sz);
117}
118#endif
119
120#ifdef BUILD_ID_SHA
121static void
122gen_build_id(struct buildid_note *note,
123 unsigned long load_addr __maybe_unused,
124 const void *code,
125 size_t csize)
126{
127 if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
128 errx(1, "build_id too small for SHA1");
129
130 SHA1(code, csize, (unsigned char *)note->build_id);
131}
132#endif
133
134#ifdef BUILD_ID_MD5
135static void
136gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
137{
138 MD5_CTX context;
139
140 if (sizeof(note->build_id) < 16)
141 errx(1, "build_id too small for MD5");
142
143 MD5_Init(&context);
144 MD5_Update(&context, &load_addr, sizeof(load_addr));
145 MD5_Update(&context, code, csize);
146 MD5_Final((unsigned char *)note->build_id, &context);
147}
148#endif
149
150/*
151 * fd: file descriptor open for writing for the output file
152 * load_addr: code load address (could be zero, just used for buildid)
153 * sym: function name (for native code - used as the symbol)
154 * code: the native code
155 * csize: the code size in bytes
156 */
157int
158jit_write_elf(int fd, uint64_t load_addr, const char *sym,
159 const void *code, int csize,
160 void *debug, int nr_debug_entries)
161{
162 Elf *e;
163 Elf_Data *d;
164 Elf_Scn *scn;
165 Elf_Ehdr *ehdr;
166 Elf_Shdr *shdr;
167 char *strsym = NULL;
168 int symlen;
169 int retval = -1;
170
171 if (elf_version(EV_CURRENT) == EV_NONE) {
172 warnx("ELF initialization failed");
173 return -1;
174 }
175
176 e = elf_begin(fd, ELF_C_WRITE, NULL);
177 if (!e) {
178 warnx("elf_begin failed");
179 goto error;
180 }
181
182 /*
183 * setup ELF header
184 */
185 ehdr = elf_newehdr(e);
186 if (!ehdr) {
187 warnx("cannot get ehdr");
188 goto error;
189 }
190
191 ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
192 ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
193 ehdr->e_machine = GEN_ELF_ARCH;
194 ehdr->e_type = ET_DYN;
195 ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
196 ehdr->e_version = EV_CURRENT;
197 ehdr->e_shstrndx= 2; /* shdr index for section name */
198
199 /*
200 * setup text section
201 */
202 scn = elf_newscn(e);
203 if (!scn) {
204 warnx("cannot create section");
205 goto error;
206 }
207
208 d = elf_newdata(scn);
209 if (!d) {
210 warnx("cannot get new data");
211 goto error;
212 }
213
214 d->d_align = 16;
215 d->d_off = 0LL;
216 d->d_buf = (void *)code;
217 d->d_type = ELF_T_BYTE;
218 d->d_size = csize;
219 d->d_version = EV_CURRENT;
220
221 shdr = elf_getshdr(scn);
222 if (!shdr) {
223 warnx("cannot get section header");
224 goto error;
225 }
226
227 shdr->sh_name = 1;
228 shdr->sh_type = SHT_PROGBITS;
229 shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
230 shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
231 shdr->sh_entsize = 0;
232
233 /*
234 * setup section headers string table
235 */
236 scn = elf_newscn(e);
237 if (!scn) {
238 warnx("cannot create section");
239 goto error;
240 }
241
242 d = elf_newdata(scn);
243 if (!d) {
244 warnx("cannot get new data");
245 goto error;
246 }
247
248 d->d_align = 1;
249 d->d_off = 0LL;
250 d->d_buf = shd_string_table;
251 d->d_type = ELF_T_BYTE;
252 d->d_size = sizeof(shd_string_table);
253 d->d_version = EV_CURRENT;
254
255 shdr = elf_getshdr(scn);
256 if (!shdr) {
257 warnx("cannot get section header");
258 goto error;
259 }
260
261 shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
262 shdr->sh_type = SHT_STRTAB;
263 shdr->sh_flags = 0;
264 shdr->sh_entsize = 0;
265
266 /*
267 * setup symtab section
268 */
269 symtab[1].st_size = csize;
270 symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
271
272 scn = elf_newscn(e);
273 if (!scn) {
274 warnx("cannot create section");
275 goto error;
276 }
277
278 d = elf_newdata(scn);
279 if (!d) {
280 warnx("cannot get new data");
281 goto error;
282 }
283
284 d->d_align = 8;
285 d->d_off = 0LL;
286 d->d_buf = symtab;
287 d->d_type = ELF_T_SYM;
288 d->d_size = sizeof(symtab);
289 d->d_version = EV_CURRENT;
290
291 shdr = elf_getshdr(scn);
292 if (!shdr) {
293 warnx("cannot get section header");
294 goto error;
295 }
296
297 shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
298 shdr->sh_type = SHT_SYMTAB;
299 shdr->sh_flags = 0;
300 shdr->sh_entsize = sizeof(Elf_Sym);
301 shdr->sh_link = 4; /* index of .strtab section */
302
303 /*
304 * setup symbols string table
305 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
306 */
307 symlen = 2 + strlen(sym);
308 strsym = calloc(1, symlen);
309 if (!strsym) {
310 warnx("cannot allocate strsym");
311 goto error;
312 }
313 strcpy(strsym + 1, sym);
314
315 scn = elf_newscn(e);
316 if (!scn) {
317 warnx("cannot create section");
318 goto error;
319 }
320
321 d = elf_newdata(scn);
322 if (!d) {
323 warnx("cannot get new data");
324 goto error;
325 }
326
327 d->d_align = 1;
328 d->d_off = 0LL;
329 d->d_buf = strsym;
330 d->d_type = ELF_T_BYTE;
331 d->d_size = symlen;
332 d->d_version = EV_CURRENT;
333
334 shdr = elf_getshdr(scn);
335 if (!shdr) {
336 warnx("cannot get section header");
337 goto error;
338 }
339
340 shdr->sh_name = 25; /* offset in shd_string_table */
341 shdr->sh_type = SHT_STRTAB;
342 shdr->sh_flags = 0;
343 shdr->sh_entsize = 0;
344
345 /*
346 * setup build-id section
347 */
348 scn = elf_newscn(e);
349 if (!scn) {
350 warnx("cannot create section");
351 goto error;
352 }
353
354 d = elf_newdata(scn);
355 if (!d) {
356 warnx("cannot get new data");
357 goto error;
358 }
359
360 /*
361 * build-id generation
362 */
363 gen_build_id(&bnote, load_addr, code, csize);
364 bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
365 bnote.desc.descsz = sizeof(bnote.build_id);
366 bnote.desc.type = NT_GNU_BUILD_ID;
367 strcpy(bnote.name, "GNU");
368
369 d->d_align = 4;
370 d->d_off = 0LL;
371 d->d_buf = &bnote;
372 d->d_type = ELF_T_BYTE;
373 d->d_size = sizeof(bnote);
374 d->d_version = EV_CURRENT;
375
376 shdr = elf_getshdr(scn);
377 if (!shdr) {
378 warnx("cannot get section header");
379 goto error;
380 }
381
382 shdr->sh_name = 33; /* offset in shd_string_table */
383 shdr->sh_type = SHT_NOTE;
384 shdr->sh_addr = 0x0;
385 shdr->sh_flags = SHF_ALLOC;
386 shdr->sh_size = sizeof(bnote);
387 shdr->sh_entsize = 0;
388
389 if (debug && nr_debug_entries) {
390 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
391 if (retval)
392 goto error;
393 } else {
394 if (elf_update(e, ELF_C_WRITE) < 0) {
395 warnx("elf_update 4 failed");
396 goto error;
397 }
398 }
399
400 retval = 0;
401error:
402 (void)elf_end(e);
403
404 free(strsym);
405
406
407 return retval;
408}
409
410#ifndef JVMTI
411
412static unsigned char x86_code[] = {
413 0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
414 0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
415 0xCD, 0x80 /* int $0x80 */
416};
417
418static struct options options;
419
420int main(int argc, char **argv)
421{
422 int c, fd, ret;
423
424 while ((c = getopt(argc, argv, "o:h")) != -1) {
425 switch (c) {
426 case 'o':
427 options.output = optarg;
428 break;
429 case 'h':
430 printf("Usage: genelf -o output_file [-h]\n");
431 return 0;
432 default:
433 errx(1, "unknown option");
434 }
435 }
436
437 fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
438 if (fd == -1)
439 err(1, "cannot create file %s", options.output);
440
441 ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
442 close(fd);
443
444 if (ret != 0)
445 unlink(options.output);
446
447 return ret;
448}
449#endif
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
new file mode 100644
index 000000000000..45bf9c6d3257
--- /dev/null
+++ b/tools/perf/util/genelf.h
@@ -0,0 +1,67 @@
1#ifndef __GENELF_H__
2#define __GENELF_H__
3
4/* genelf.c */
5extern int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
6 const void *code, int csize,
7 void *debug, int nr_debug_entries);
8/* genelf_debug.c */
9extern int jit_add_debug_info(Elf *e, uint64_t code_addr,
10 void *debug, int nr_debug_entries);
11
12#if defined(__arm__)
13#define GEN_ELF_ARCH EM_ARM
14#define GEN_ELF_ENDIAN ELFDATA2LSB
15#define GEN_ELF_CLASS ELFCLASS32
16#elif defined(__aarch64__)
17#define GEN_ELF_ARCH EM_AARCH64
18#define GEN_ELF_ENDIAN ELFDATA2LSB
19#define GEN_ELF_CLASS ELFCLASS64
20#elif defined(__x86_64__)
21#define GEN_ELF_ARCH EM_X86_64
22#define GEN_ELF_ENDIAN ELFDATA2LSB
23#define GEN_ELF_CLASS ELFCLASS64
24#elif defined(__i386__)
25#define GEN_ELF_ARCH EM_386
26#define GEN_ELF_ENDIAN ELFDATA2LSB
27#define GEN_ELF_CLASS ELFCLASS32
28#elif defined(__ppcle__)
29#define GEN_ELF_ARCH EM_PPC
30#define GEN_ELF_ENDIAN ELFDATA2LSB
31#define GEN_ELF_CLASS ELFCLASS64
32#elif defined(__powerpc__)
33#define GEN_ELF_ARCH EM_PPC64
34#define GEN_ELF_ENDIAN ELFDATA2MSB
35#define GEN_ELF_CLASS ELFCLASS64
36#elif defined(__powerpcle__)
37#define GEN_ELF_ARCH EM_PPC64
38#define GEN_ELF_ENDIAN ELFDATA2LSB
39#define GEN_ELF_CLASS ELFCLASS64
40#else
41#error "unsupported architecture"
42#endif
43
44#if GEN_ELF_CLASS == ELFCLASS64
45#define elf_newehdr elf64_newehdr
46#define elf_getshdr elf64_getshdr
47#define Elf_Ehdr Elf64_Ehdr
48#define Elf_Shdr Elf64_Shdr
49#define Elf_Sym Elf64_Sym
50#define ELF_ST_TYPE(a) ELF64_ST_TYPE(a)
51#define ELF_ST_BIND(a) ELF64_ST_BIND(a)
52#define ELF_ST_VIS(a) ELF64_ST_VISIBILITY(a)
53#else
54#define elf_newehdr elf32_newehdr
55#define elf_getshdr elf32_getshdr
56#define Elf_Ehdr Elf32_Ehdr
57#define Elf_Shdr Elf32_Shdr
58#define Elf_Sym Elf32_Sym
59#define ELF_ST_TYPE(a) ELF32_ST_TYPE(a)
60#define ELF_ST_BIND(a) ELF32_ST_BIND(a)
61#define ELF_ST_VIS(a) ELF32_ST_VISIBILITY(a)
62#endif
63
64/* The .text section is directly after the ELF header */
65#define GEN_ELF_TEXT_OFFSET sizeof(Elf_Ehdr)
66
67#endif
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c
new file mode 100644
index 000000000000..5980f7d256b1
--- /dev/null
+++ b/tools/perf/util/genelf_debug.c
@@ -0,0 +1,610 @@
1/*
2 * genelf_debug.c
3 * Copyright (C) 2015, Google, Inc
4 *
5 * Contributed by:
6 * Stephane Eranian <eranian@google.com>
7 *
8 * Released under the GPL v2.
9 *
10 * based on GPLv2 source code from Oprofile
11 * @remark Copyright 2007 OProfile authors
12 * @author Philippe Elie
13 */
14#include <sys/types.h>
15#include <stdio.h>
16#include <getopt.h>
17#include <stddef.h>
18#include <libelf.h>
19#include <string.h>
20#include <stdlib.h>
21#include <inttypes.h>
22#include <limits.h>
23#include <fcntl.h>
24#include <err.h>
25#include <dwarf.h>
26
27#include "perf.h"
28#include "genelf.h"
29#include "../util/jitdump.h"
30
31#define BUFFER_EXT_DFL_SIZE (4 * 1024)
32
33typedef uint32_t uword;
34typedef uint16_t uhalf;
35typedef int32_t sword;
36typedef int16_t shalf;
37typedef uint8_t ubyte;
38typedef int8_t sbyte;
39
40struct buffer_ext {
41 size_t cur_pos;
42 size_t max_sz;
43 void *data;
44};
45
46static void
47buffer_ext_dump(struct buffer_ext *be, const char *msg)
48{
49 size_t i;
50 warnx("DUMP for %s", msg);
51 for (i = 0 ; i < be->cur_pos; i++)
52 warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
53}
54
55static inline int
56buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
57{
58 void *tmp;
59 size_t be_sz = be->max_sz;
60
61retry:
62 if ((be->cur_pos + sz) < be_sz) {
63 memcpy(be->data + be->cur_pos, addr, sz);
64 be->cur_pos += sz;
65 return 0;
66 }
67
68 if (!be_sz)
69 be_sz = BUFFER_EXT_DFL_SIZE;
70 else
71 be_sz <<= 1;
72
73 tmp = realloc(be->data, be_sz);
74 if (!tmp)
75 return -1;
76
77 be->data = tmp;
78 be->max_sz = be_sz;
79
80 goto retry;
81}
82
83static void
84buffer_ext_init(struct buffer_ext *be)
85{
86 be->data = NULL;
87 be->cur_pos = 0;
88 be->max_sz = 0;
89}
90
91static inline size_t
92buffer_ext_size(struct buffer_ext *be)
93{
94 return be->cur_pos;
95}
96
97static inline void *
98buffer_ext_addr(struct buffer_ext *be)
99{
100 return be->data;
101}
102
103struct debug_line_header {
104 // Not counting this field
105 uword total_length;
106 // version number (2 currently)
107 uhalf version;
108 // relative offset from next field to
109 // program statement
110 uword prolog_length;
111 ubyte minimum_instruction_length;
112 ubyte default_is_stmt;
113 // line_base - see DWARF 2 specs
114 sbyte line_base;
115 // line_range - see DWARF 2 specs
116 ubyte line_range;
117 // number of opcode + 1
118 ubyte opcode_base;
119 /* follow the array of opcode args nr: ubytes [nr_opcode_base] */
120 /* follow the search directories index, zero terminated string
121 * terminated by an empty string.
122 */
123 /* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
124 * the directory index entry, 0 means current directory, then mtime
125 * and filesize, last entry is followed by en empty string.
126 */
127 /* follow the first program statement */
128} __attribute__((packed));
129
130/* DWARF 2 spec talk only about one possible compilation unit header while
131 * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
132 * related to the used arch, an ELF 32 can hold more than 4 Go of debug
133 * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
134 * become a problem if we generate more than 4GB of debug information.
135 */
136struct compilation_unit_header {
137 uword total_length;
138 uhalf version;
139 uword debug_abbrev_offset;
140 ubyte pointer_size;
141} __attribute__((packed));
142
143#define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
144
145/* field filled at run time are marked with -1 */
146static struct debug_line_header const default_debug_line_header = {
147 .total_length = -1,
148 .version = 2,
149 .prolog_length = -1,
150 .minimum_instruction_length = 1, /* could be better when min instruction size != 1 */
151 .default_is_stmt = 1, /* we don't take care about basic block */
152 .line_base = -5, /* sensible value for line base ... */
153 .line_range = -14, /* ... and line range are guessed statically */
154 .opcode_base = DW_LNS_num_opcode
155};
156
157static ubyte standard_opcode_length[] =
158{
159 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
160};
161#if 0
162{
163 [DW_LNS_advance_pc] = 1,
164 [DW_LNS_advance_line] = 1,
165 [DW_LNS_set_file] = 1,
166 [DW_LNS_set_column] = 1,
167 [DW_LNS_fixed_advance_pc] = 1,
168 [DW_LNS_set_isa] = 1,
169};
170#endif
171
172/* field filled at run time are marked with -1 */
173static struct compilation_unit_header default_comp_unit_header = {
174 .total_length = -1,
175 .version = 2,
176 .debug_abbrev_offset = 0, /* we reuse the same abbrev entries for all comp unit */
177 .pointer_size = sizeof(void *)
178};
179
180static void emit_uword(struct buffer_ext *be, uword data)
181{
182 buffer_ext_add(be, &data, sizeof(uword));
183}
184
185static void emit_string(struct buffer_ext *be, const char *s)
186{
187 buffer_ext_add(be, (void *)s, strlen(s) + 1);
188}
189
190static void emit_unsigned_LEB128(struct buffer_ext *be,
191 unsigned long data)
192{
193 do {
194 ubyte cur = data & 0x7F;
195 data >>= 7;
196 if (data)
197 cur |= 0x80;
198 buffer_ext_add(be, &cur, 1);
199 } while (data);
200}
201
202static void emit_signed_LEB128(struct buffer_ext *be, long data)
203{
204 int more = 1;
205 int negative = data < 0;
206 int size = sizeof(long) * CHAR_BIT;
207 while (more) {
208 ubyte cur = data & 0x7F;
209 data >>= 7;
210 if (negative)
211 data |= - (1 << (size - 7));
212 if ((data == 0 && !(cur & 0x40)) ||
213 (data == -1l && (cur & 0x40)))
214 more = 0;
215 else
216 cur |= 0x80;
217 buffer_ext_add(be, &cur, 1);
218 }
219}
220
221static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
222 void *data, size_t data_len)
223{
224 buffer_ext_add(be, (char *)"", 1);
225
226 emit_unsigned_LEB128(be, data_len + 1);
227
228 buffer_ext_add(be, &opcode, 1);
229 buffer_ext_add(be, data, data_len);
230}
231
232static void emit_opcode(struct buffer_ext *be, ubyte opcode)
233{
234 buffer_ext_add(be, &opcode, 1);
235}
236
237static void emit_opcode_signed(struct buffer_ext *be,
238 ubyte opcode, long data)
239{
240 buffer_ext_add(be, &opcode, 1);
241 emit_signed_LEB128(be, data);
242}
243
244static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
245 unsigned long data)
246{
247 buffer_ext_add(be, &opcode, 1);
248 emit_unsigned_LEB128(be, data);
249}
250
251static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
252{
253 emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
254}
255
256static void emit_advance_lineno(struct buffer_ext *be, long delta_lineno)
257{
258 emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
259}
260
261static void emit_lne_end_of_sequence(struct buffer_ext *be)
262{
263 emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
264}
265
266static void emit_set_file(struct buffer_ext *be, unsigned long idx)
267{
268 emit_opcode_unsigned(be, DW_LNS_set_file, idx);
269}
270
271static void emit_lne_define_filename(struct buffer_ext *be,
272 const char *filename)
273{
274 buffer_ext_add(be, (void *)"", 1);
275
276 /* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
277 emit_unsigned_LEB128(be, strlen(filename) + 5);
278 emit_opcode(be, DW_LNE_define_file);
279 emit_string(be, filename);
280 /* directory index 0=do not know */
281 emit_unsigned_LEB128(be, 0);
282 /* last modification date on file 0=do not know */
283 emit_unsigned_LEB128(be, 0);
284 /* filesize 0=do not know */
285 emit_unsigned_LEB128(be, 0);
286}
287
288static void emit_lne_set_address(struct buffer_ext *be,
289 void *address)
290{
291 emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
292}
293
294static ubyte get_special_opcode(struct debug_entry *ent,
295 unsigned int last_line,
296 unsigned long last_vma)
297{
298 unsigned int temp;
299 unsigned long delta_addr;
300
301 /*
302 * delta from line_base
303 */
304 temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
305
306 if (temp >= default_debug_line_header.line_range)
307 return 0;
308
309 /*
310 * delta of addresses
311 */
312 delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
313
314 /* This is not sufficient to ensure opcode will be in [0-256] but
315 * sufficient to ensure when summing with the delta lineno we will
316 * not overflow the unsigned long opcode */
317
318 if (delta_addr <= 256 / default_debug_line_header.line_range) {
319 unsigned long opcode = temp +
320 (delta_addr * default_debug_line_header.line_range) +
321 default_debug_line_header.opcode_base;
322
323 return opcode <= 255 ? opcode : 0;
324 }
325 return 0;
326}
327
328static void emit_lineno_info(struct buffer_ext *be,
329 struct debug_entry *ent, size_t nr_entry,
330 unsigned long code_addr)
331{
332 size_t i;
333
334 /*
335 * Machine state at start of a statement program
336 * address = 0
337 * file = 1
338 * line = 1
339 * column = 0
340 * is_stmt = default_is_stmt as given in the debug_line_header
341 * basic block = 0
342 * end sequence = 0
343 */
344
345 /* start state of the state machine we take care of */
346 unsigned long last_vma = code_addr;
347 char const *cur_filename = NULL;
348 unsigned long cur_file_idx = 0;
349 int last_line = 1;
350
351 emit_lne_set_address(be, (void *)code_addr);
352
353 for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
354 int need_copy = 0;
355 ubyte special_opcode;
356
357 /*
358 * check if filename changed, if so add it
359 */
360 if (!cur_filename || strcmp(cur_filename, ent->name)) {
361 emit_lne_define_filename(be, ent->name);
362 cur_filename = ent->name;
363 emit_set_file(be, ++cur_file_idx);
364 need_copy = 1;
365 }
366
367 special_opcode = get_special_opcode(ent, last_line, last_vma);
368 if (special_opcode != 0) {
369 last_line = ent->lineno;
370 last_vma = ent->addr;
371 emit_opcode(be, special_opcode);
372 } else {
373 /*
374 * lines differ, emit line delta
375 */
376 if (last_line != ent->lineno) {
377 emit_advance_lineno(be, ent->lineno - last_line);
378 last_line = ent->lineno;
379 need_copy = 1;
380 }
381 /*
382 * addresses differ, emit address delta
383 */
384 if (last_vma != ent->addr) {
385 emit_advance_pc(be, ent->addr - last_vma);
386 last_vma = ent->addr;
387 need_copy = 1;
388 }
389 /*
390 * add new row to matrix
391 */
392 if (need_copy)
393 emit_opcode(be, DW_LNS_copy);
394 }
395 }
396}
397
398static void add_debug_line(struct buffer_ext *be,
399 struct debug_entry *ent, size_t nr_entry,
400 unsigned long code_addr)
401{
402 struct debug_line_header * dbg_header;
403 size_t old_size;
404
405 old_size = buffer_ext_size(be);
406
407 buffer_ext_add(be, (void *)&default_debug_line_header,
408 sizeof(default_debug_line_header));
409
410 buffer_ext_add(be, &standard_opcode_length, sizeof(standard_opcode_length));
411
412 // empty directory entry
413 buffer_ext_add(be, (void *)"", 1);
414
415 // empty filename directory
416 buffer_ext_add(be, (void *)"", 1);
417
418 dbg_header = buffer_ext_addr(be) + old_size;
419 dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
420 offsetof(struct debug_line_header, minimum_instruction_length);
421
422 emit_lineno_info(be, ent, nr_entry, code_addr);
423
424 emit_lne_end_of_sequence(be);
425
426 dbg_header = buffer_ext_addr(be) + old_size;
427 dbg_header->total_length = (buffer_ext_size(be) - old_size) -
428 offsetof(struct debug_line_header, version);
429}
430
431static void
432add_debug_abbrev(struct buffer_ext *be)
433{
434 emit_unsigned_LEB128(be, 1);
435 emit_unsigned_LEB128(be, DW_TAG_compile_unit);
436 emit_unsigned_LEB128(be, DW_CHILDREN_yes);
437 emit_unsigned_LEB128(be, DW_AT_stmt_list);
438 emit_unsigned_LEB128(be, DW_FORM_data4);
439 emit_unsigned_LEB128(be, 0);
440 emit_unsigned_LEB128(be, 0);
441 emit_unsigned_LEB128(be, 0);
442}
443
444static void
445add_compilation_unit(struct buffer_ext *be,
446 size_t offset_debug_line)
447{
448 struct compilation_unit_header *comp_unit_header;
449 size_t old_size = buffer_ext_size(be);
450
451 buffer_ext_add(be, &default_comp_unit_header,
452 sizeof(default_comp_unit_header));
453
454 emit_unsigned_LEB128(be, 1);
455 emit_uword(be, offset_debug_line);
456
457 comp_unit_header = buffer_ext_addr(be) + old_size;
458 comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
459 offsetof(struct compilation_unit_header, version);
460}
461
462static int
463jit_process_debug_info(uint64_t code_addr,
464 void *debug, int nr_debug_entries,
465 struct buffer_ext *dl,
466 struct buffer_ext *da,
467 struct buffer_ext *di)
468{
469 struct debug_entry *ent = debug;
470 int i;
471
472 for (i = 0; i < nr_debug_entries; i++) {
473 ent->addr = ent->addr - code_addr;
474 ent = debug_entry_next(ent);
475 }
476 add_compilation_unit(di, buffer_ext_size(dl));
477 add_debug_line(dl, debug, nr_debug_entries, 0);
478 add_debug_abbrev(da);
479 if (0) buffer_ext_dump(da, "abbrev");
480
481 return 0;
482}
483
484int
485jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
486{
487 Elf_Data *d;
488 Elf_Scn *scn;
489 Elf_Shdr *shdr;
490 struct buffer_ext dl, di, da;
491 int ret;
492
493 buffer_ext_init(&dl);
494 buffer_ext_init(&di);
495 buffer_ext_init(&da);
496
497 ret = jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di);
498 if (ret)
499 return -1;
500 /*
501 * setup .debug_line section
502 */
503 scn = elf_newscn(e);
504 if (!scn) {
505 warnx("cannot create section");
506 return -1;
507 }
508
509 d = elf_newdata(scn);
510 if (!d) {
511 warnx("cannot get new data");
512 return -1;
513 }
514
515 d->d_align = 1;
516 d->d_off = 0LL;
517 d->d_buf = buffer_ext_addr(&dl);
518 d->d_type = ELF_T_BYTE;
519 d->d_size = buffer_ext_size(&dl);
520 d->d_version = EV_CURRENT;
521
522 shdr = elf_getshdr(scn);
523 if (!shdr) {
524 warnx("cannot get section header");
525 return -1;
526 }
527
528 shdr->sh_name = 52; /* .debug_line */
529 shdr->sh_type = SHT_PROGBITS;
530 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
531 shdr->sh_flags = 0;
532 shdr->sh_entsize = 0;
533
534 /*
535 * setup .debug_info section
536 */
537 scn = elf_newscn(e);
538 if (!scn) {
539 warnx("cannot create section");
540 return -1;
541 }
542
543 d = elf_newdata(scn);
544 if (!d) {
545 warnx("cannot get new data");
546 return -1;
547 }
548
549 d->d_align = 1;
550 d->d_off = 0LL;
551 d->d_buf = buffer_ext_addr(&di);
552 d->d_type = ELF_T_BYTE;
553 d->d_size = buffer_ext_size(&di);
554 d->d_version = EV_CURRENT;
555
556 shdr = elf_getshdr(scn);
557 if (!shdr) {
558 warnx("cannot get section header");
559 return -1;
560 }
561
562 shdr->sh_name = 64; /* .debug_info */
563 shdr->sh_type = SHT_PROGBITS;
564 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
565 shdr->sh_flags = 0;
566 shdr->sh_entsize = 0;
567
568 /*
569 * setup .debug_abbrev section
570 */
571 scn = elf_newscn(e);
572 if (!scn) {
573 warnx("cannot create section");
574 return -1;
575 }
576
577 d = elf_newdata(scn);
578 if (!d) {
579 warnx("cannot get new data");
580 return -1;
581 }
582
583 d->d_align = 1;
584 d->d_off = 0LL;
585 d->d_buf = buffer_ext_addr(&da);
586 d->d_type = ELF_T_BYTE;
587 d->d_size = buffer_ext_size(&da);
588 d->d_version = EV_CURRENT;
589
590 shdr = elf_getshdr(scn);
591 if (!shdr) {
592 warnx("cannot get section header");
593 return -1;
594 }
595
596 shdr->sh_name = 76; /* .debug_info */
597 shdr->sh_type = SHT_PROGBITS;
598 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
599 shdr->sh_flags = 0;
600 shdr->sh_entsize = 0;
601
602 /*
603 * now we update the ELF image with all the sections
604 */
605 if (elf_update(e, ELF_C_WRITE) < 0) {
606 warnx("elf_update debug failed");
607 return -1;
608 }
609 return 0;
610}
diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
new file mode 100644
index 000000000000..a1e99da0715a
--- /dev/null
+++ b/tools/perf/util/jit.h
@@ -0,0 +1,15 @@
1#ifndef __JIT_H__
2#define __JIT_H__
3
4#include <data.h>
5
6extern int jit_process(struct perf_session *session,
7 struct perf_data_file *output,
8 struct machine *machine,
9 char *filename,
10 pid_t pid,
11 u64 *nbytes);
12
13extern int jit_inject_record(const char *filename);
14
15#endif /* __JIT_H__ */
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
new file mode 100644
index 000000000000..99fa5eee9fe0
--- /dev/null
+++ b/tools/perf/util/jitdump.c
@@ -0,0 +1,672 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <inttypes.h>
8#include <byteswap.h>
9#include <sys/stat.h>
10#include <sys/mman.h>
11
12#include "util.h"
13#include "event.h"
14#include "debug.h"
15#include "evlist.h"
16#include "symbol.h"
17#include "strlist.h"
18#include <elf.h>
19
20#include "session.h"
21#include "jit.h"
22#include "jitdump.h"
23#include "genelf.h"
24#include "../builtin.h"
25
26struct jit_buf_desc {
27 struct perf_data_file *output;
28 struct perf_session *session;
29 struct machine *machine;
30 union jr_entry *entry;
31 void *buf;
32 uint64_t sample_type;
33 size_t bufsize;
34 FILE *in;
35 bool needs_bswap; /* handles cross-endianess */
36 void *debug_data;
37 size_t nr_debug_entries;
38 uint32_t code_load_count;
39 u64 bytes_written;
40 struct rb_root code_root;
41 char dir[PATH_MAX];
42};
43
44struct debug_line_info {
45 unsigned long vma;
46 unsigned int lineno;
47 /* The filename format is unspecified, absolute path, relative etc. */
48 char const filename[0];
49};
50
51struct jit_tool {
52 struct perf_tool tool;
53 struct perf_data_file output;
54 struct perf_data_file input;
55 u64 bytes_written;
56};
57
58#define hmax(a, b) ((a) > (b) ? (a) : (b))
59#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
60
61static int
62jit_emit_elf(char *filename,
63 const char *sym,
64 uint64_t code_addr,
65 const void *code,
66 int csize,
67 void *debug,
68 int nr_debug_entries)
69{
70 int ret, fd;
71
72 if (verbose > 0)
73 fprintf(stderr, "write ELF image %s\n", filename);
74
75 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
76 if (fd == -1) {
77 pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
78 return -1;
79 }
80
81 ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries);
82
83 close(fd);
84
85 if (ret)
86 unlink(filename);
87
88 return ret;
89}
90
91static void
92jit_close(struct jit_buf_desc *jd)
93{
94 if (!(jd && jd->in))
95 return;
96 funlockfile(jd->in);
97 fclose(jd->in);
98 jd->in = NULL;
99}
100
101static int
102jit_open(struct jit_buf_desc *jd, const char *name)
103{
104 struct jitheader header;
105 struct jr_prefix *prefix;
106 ssize_t bs, bsz = 0;
107 void *n, *buf = NULL;
108 int ret, retval = -1;
109
110 jd->in = fopen(name, "r");
111 if (!jd->in)
112 return -1;
113
114 bsz = hmax(sizeof(header), sizeof(*prefix));
115
116 buf = malloc(bsz);
117 if (!buf)
118 goto error;
119
120 /*
121 * protect from writer modifying the file while we are reading it
122 */
123 flockfile(jd->in);
124
125 ret = fread(buf, sizeof(header), 1, jd->in);
126 if (ret != 1)
127 goto error;
128
129 memcpy(&header, buf, sizeof(header));
130
131 if (header.magic != JITHEADER_MAGIC) {
132 if (header.magic != JITHEADER_MAGIC_SW)
133 goto error;
134 jd->needs_bswap = true;
135 }
136
137 if (jd->needs_bswap) {
138 header.version = bswap_32(header.version);
139 header.total_size = bswap_32(header.total_size);
140 header.pid = bswap_32(header.pid);
141 header.elf_mach = bswap_32(header.elf_mach);
142 header.timestamp = bswap_64(header.timestamp);
143 header.flags = bswap_64(header.flags);
144 }
145
146 if (verbose > 2)
147 pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
148 header.version,
149 header.total_size,
150 (unsigned long long)header.timestamp,
151 header.pid,
152 header.elf_mach);
153
154 if (header.flags & JITDUMP_FLAGS_RESERVED) {
155 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
156 (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
157 goto error;
158 }
159
160 bs = header.total_size - sizeof(header);
161
162 if (bs > bsz) {
163 n = realloc(buf, bs);
164 if (!n)
165 goto error;
166 bsz = bs;
167 buf = n;
168 /* read extra we do not know about */
169 ret = fread(buf, bs - bsz, 1, jd->in);
170 if (ret != 1)
171 goto error;
172 }
173 /*
174 * keep dirname for generating files and mmap records
175 */
176 strcpy(jd->dir, name);
177 dirname(jd->dir);
178
179 return 0;
180error:
181 funlockfile(jd->in);
182 fclose(jd->in);
183 return retval;
184}
185
186static union jr_entry *
187jit_get_next_entry(struct jit_buf_desc *jd)
188{
189 struct jr_prefix *prefix;
190 union jr_entry *jr;
191 void *addr;
192 size_t bs, size;
193 int id, ret;
194
195 if (!(jd && jd->in))
196 return NULL;
197
198 if (jd->buf == NULL) {
199 size_t sz = getpagesize();
200 if (sz < sizeof(*prefix))
201 sz = sizeof(*prefix);
202
203 jd->buf = malloc(sz);
204 if (jd->buf == NULL)
205 return NULL;
206
207 jd->bufsize = sz;
208 }
209
210 prefix = jd->buf;
211
212 /*
213 * file is still locked at this point
214 */
215 ret = fread(prefix, sizeof(*prefix), 1, jd->in);
216 if (ret != 1)
217 return NULL;
218
219 if (jd->needs_bswap) {
220 prefix->id = bswap_32(prefix->id);
221 prefix->total_size = bswap_32(prefix->total_size);
222 prefix->timestamp = bswap_64(prefix->timestamp);
223 }
224 id = prefix->id;
225 size = prefix->total_size;
226
227 bs = (size_t)size;
228 if (bs < sizeof(*prefix))
229 return NULL;
230
231 if (id >= JIT_CODE_MAX) {
232 pr_warning("next_entry: unknown prefix %d, skipping\n", id);
233 return NULL;
234 }
235 if (bs > jd->bufsize) {
236 void *n;
237 n = realloc(jd->buf, bs);
238 if (!n)
239 return NULL;
240 jd->buf = n;
241 jd->bufsize = bs;
242 }
243
244 addr = ((void *)jd->buf) + sizeof(*prefix);
245
246 ret = fread(addr, bs - sizeof(*prefix), 1, jd->in);
247 if (ret != 1)
248 return NULL;
249
250 jr = (union jr_entry *)jd->buf;
251
252 switch(id) {
253 case JIT_CODE_DEBUG_INFO:
254 if (jd->needs_bswap) {
255 uint64_t n;
256 jr->info.code_addr = bswap_64(jr->info.code_addr);
257 jr->info.nr_entry = bswap_64(jr->info.nr_entry);
258 for (n = 0 ; n < jr->info.nr_entry; n++) {
259 jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
260 jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno);
261 jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
262 }
263 }
264 break;
265 case JIT_CODE_CLOSE:
266 break;
267 case JIT_CODE_LOAD:
268 if (jd->needs_bswap) {
269 jr->load.pid = bswap_32(jr->load.pid);
270 jr->load.tid = bswap_32(jr->load.tid);
271 jr->load.vma = bswap_64(jr->load.vma);
272 jr->load.code_addr = bswap_64(jr->load.code_addr);
273 jr->load.code_size = bswap_64(jr->load.code_size);
274 jr->load.code_index= bswap_64(jr->load.code_index);
275 }
276 jd->code_load_count++;
277 break;
278 case JIT_CODE_MOVE:
279 if (jd->needs_bswap) {
280 jr->move.pid = bswap_32(jr->move.pid);
281 jr->move.tid = bswap_32(jr->move.tid);
282 jr->move.vma = bswap_64(jr->move.vma);
283 jr->move.old_code_addr = bswap_64(jr->move.old_code_addr);
284 jr->move.new_code_addr = bswap_64(jr->move.new_code_addr);
285 jr->move.code_size = bswap_64(jr->move.code_size);
286 jr->move.code_index = bswap_64(jr->move.code_index);
287 }
288 break;
289 case JIT_CODE_MAX:
290 default:
291 return NULL;
292 }
293 return jr;
294}
295
296static int
297jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
298{
299 ssize_t size;
300
301 size = perf_data_file__write(jd->output, event, event->header.size);
302 if (size < 0)
303 return -1;
304
305 jd->bytes_written += size;
306 return 0;
307}
308
309static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
310{
311 struct perf_sample sample;
312 union perf_event *event;
313 struct perf_tool *tool = jd->session->tool;
314 uint64_t code, addr;
315 uintptr_t uaddr;
316 char *filename;
317 struct stat st;
318 size_t size;
319 u16 idr_size;
320 const char *sym;
321 uint32_t count;
322 int ret, csize;
323 pid_t pid, tid;
324 struct {
325 u32 pid, tid;
326 u64 time;
327 } *id;
328
329 pid = jr->load.pid;
330 tid = jr->load.tid;
331 csize = jr->load.code_size;
332 addr = jr->load.code_addr;
333 sym = (void *)((unsigned long)jr + sizeof(jr->load));
334 code = (unsigned long)jr + jr->load.p.total_size - csize;
335 count = jr->load.code_index;
336 idr_size = jd->machine->id_hdr_size;
337
338 event = calloc(1, sizeof(*event) + idr_size);
339 if (!event)
340 return -1;
341
342 filename = event->mmap2.filename;
343 size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%u.so",
344 jd->dir,
345 pid,
346 count);
347
348 size++; /* for \0 */
349
350 size = PERF_ALIGN(size, sizeof(u64));
351 uaddr = (uintptr_t)code;
352 ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries);
353
354 if (jd->debug_data && jd->nr_debug_entries) {
355 free(jd->debug_data);
356 jd->debug_data = NULL;
357 jd->nr_debug_entries = 0;
358 }
359
360 if (ret) {
361 free(event);
362 return -1;
363 }
364 if (stat(filename, &st))
365 memset(&st, 0, sizeof(stat));
366
367 event->mmap2.header.type = PERF_RECORD_MMAP2;
368 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
369 event->mmap2.header.size = (sizeof(event->mmap2) -
370 (sizeof(event->mmap2.filename) - size) + idr_size);
371
372 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
373 event->mmap2.start = addr;
374 event->mmap2.len = csize;
375 event->mmap2.pid = pid;
376 event->mmap2.tid = tid;
377 event->mmap2.ino = st.st_ino;
378 event->mmap2.maj = major(st.st_dev);
379 event->mmap2.min = minor(st.st_dev);
380 event->mmap2.prot = st.st_mode;
381 event->mmap2.flags = MAP_SHARED;
382 event->mmap2.ino_generation = 1;
383
384 id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
385 if (jd->sample_type & PERF_SAMPLE_TID) {
386 id->pid = pid;
387 id->tid = tid;
388 }
389 if (jd->sample_type & PERF_SAMPLE_TIME)
390 id->time = jr->load.p.timestamp;
391
392 /*
393 * create pseudo sample to induce dso hit increment
394 * use first address as sample address
395 */
396 memset(&sample, 0, sizeof(sample));
397 sample.pid = pid;
398 sample.tid = tid;
399 sample.time = id->time;
400 sample.ip = addr;
401
402 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
403 if (ret)
404 return ret;
405
406 ret = jit_inject_event(jd, event);
407 /*
408 * mark dso as use to generate buildid in the header
409 */
410 if (!ret)
411 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
412
413 return ret;
414}
415
416static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
417{
418 struct perf_sample sample;
419 union perf_event *event;
420 struct perf_tool *tool = jd->session->tool;
421 char *filename;
422 size_t size;
423 struct stat st;
424 u16 idr_size;
425 int ret;
426 pid_t pid, tid;
427 struct {
428 u32 pid, tid;
429 u64 time;
430 } *id;
431
432 pid = jr->move.pid;
433 tid = jr->move.tid;
434 idr_size = jd->machine->id_hdr_size;
435
436 /*
437 * +16 to account for sample_id_all (hack)
438 */
439 event = calloc(1, sizeof(*event) + 16);
440 if (!event)
441 return -1;
442
443 filename = event->mmap2.filename;
444 size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64,
445 jd->dir,
446 pid,
447 jr->move.code_index);
448
449 size++; /* for \0 */
450
451 if (stat(filename, &st))
452 memset(&st, 0, sizeof(stat));
453
454 size = PERF_ALIGN(size, sizeof(u64));
455
456 event->mmap2.header.type = PERF_RECORD_MMAP2;
457 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
458 event->mmap2.header.size = (sizeof(event->mmap2) -
459 (sizeof(event->mmap2.filename) - size) + idr_size);
460 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
461 event->mmap2.start = jr->move.new_code_addr;
462 event->mmap2.len = jr->move.code_size;
463 event->mmap2.pid = pid;
464 event->mmap2.tid = tid;
465 event->mmap2.ino = st.st_ino;
466 event->mmap2.maj = major(st.st_dev);
467 event->mmap2.min = minor(st.st_dev);
468 event->mmap2.prot = st.st_mode;
469 event->mmap2.flags = MAP_SHARED;
470 event->mmap2.ino_generation = 1;
471
472 id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
473 if (jd->sample_type & PERF_SAMPLE_TID) {
474 id->pid = pid;
475 id->tid = tid;
476 }
477 if (jd->sample_type & PERF_SAMPLE_TIME)
478 id->time = jr->load.p.timestamp;
479
480 /*
481 * create pseudo sample to induce dso hit increment
482 * use first address as sample address
483 */
484 memset(&sample, 0, sizeof(sample));
485 sample.pid = pid;
486 sample.tid = tid;
487 sample.time = id->time;
488 sample.ip = jr->move.new_code_addr;
489
490 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
491 if (ret)
492 return ret;
493
494 ret = jit_inject_event(jd, event);
495 if (!ret)
496 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
497
498 return ret;
499}
500
501static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
502{
503 void *data;
504 size_t sz;
505
506 if (!(jd && jr))
507 return -1;
508
509 sz = jr->prefix.total_size - sizeof(jr->info);
510 data = malloc(sz);
511 if (!data)
512 return -1;
513
514 memcpy(data, &jr->info.entries, sz);
515
516 jd->debug_data = data;
517
518 /*
519 * we must use nr_entry instead of size here because
520 * we cannot distinguish actual entry from padding otherwise
521 */
522 jd->nr_debug_entries = jr->info.nr_entry;
523
524 return 0;
525}
526
527static int
528jit_process_dump(struct jit_buf_desc *jd)
529{
530 union jr_entry *jr;
531 int ret;
532
533 while ((jr = jit_get_next_entry(jd))) {
534 switch(jr->prefix.id) {
535 case JIT_CODE_LOAD:
536 ret = jit_repipe_code_load(jd, jr);
537 break;
538 case JIT_CODE_MOVE:
539 ret = jit_repipe_code_move(jd, jr);
540 break;
541 case JIT_CODE_DEBUG_INFO:
542 ret = jit_repipe_debug_info(jd, jr);
543 break;
544 default:
545 ret = 0;
546 continue;
547 }
548 }
549 return ret;
550}
551
552static int
553jit_inject(struct jit_buf_desc *jd, char *path)
554{
555 int ret;
556
557 if (verbose > 0)
558 fprintf(stderr, "injecting: %s\n", path);
559
560 ret = jit_open(jd, path);
561 if (ret)
562 return -1;
563
564 ret = jit_process_dump(jd);
565
566 jit_close(jd);
567
568 if (verbose > 0)
569 fprintf(stderr, "injected: %s (%d)\n", path, ret);
570
571 return 0;
572}
573
574/*
575 * File must be with pattern .../jit-XXXX.dump
576 * where XXXX is the PID of the process which did the mmap()
577 * as captured in the RECORD_MMAP record
578 */
579static int
580jit_detect(char *mmap_name, pid_t pid)
581 {
582 char *p;
583 char *end = NULL;
584 pid_t pid2;
585
586 if (verbose > 2)
587 fprintf(stderr, "jit marker trying : %s\n", mmap_name);
588 /*
589 * get file name
590 */
591 p = strrchr(mmap_name, '/');
592 if (!p)
593 return -1;
594
595 /*
596 * match prefix
597 */
598 if (strncmp(p, "/jit-", 5))
599 return -1;
600
601 /*
602 * skip prefix
603 */
604 p += 5;
605
606 /*
607 * must be followed by a pid
608 */
609 if (!isdigit(*p))
610 return -1;
611
612 pid2 = (int)strtol(p, &end, 10);
613 if (!end)
614 return -1;
615
616 /*
617 * pid does not match mmap pid
618 * pid==0 in system-wide mode (synthesized)
619 */
620 if (pid && pid2 != pid)
621 return -1;
622 /*
623 * validate suffix
624 */
625 if (strcmp(end, ".dump"))
626 return -1;
627
628 if (verbose > 0)
629 fprintf(stderr, "jit marker found: %s\n", mmap_name);
630
631 return 0;
632}
633
634int
635jit_process(struct perf_session *session,
636 struct perf_data_file *output,
637 struct machine *machine,
638 char *filename,
639 pid_t pid,
640 u64 *nbytes)
641{
642 struct perf_evsel *first;
643 struct jit_buf_desc jd;
644 int ret;
645
646 /*
647 * first, detect marker mmap (i.e., the jitdump mmap)
648 */
649 if (jit_detect(filename, pid))
650 return -1;
651
652 memset(&jd, 0, sizeof(jd));
653
654 jd.session = session;
655 jd.output = output;
656 jd.machine = machine;
657
658 /*
659 * track sample_type to compute id_all layout
660 * perf sets the same sample type to all events as of now
661 */
662 first = perf_evlist__first(session->evlist);
663 jd.sample_type = first->attr.sample_type;
664
665 *nbytes = 0;
666
667 ret = jit_inject(&jd, filename);
668 if (!ret)
669 *nbytes = jd.bytes_written;
670
671 return ret;
672}
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
new file mode 100644
index 000000000000..b66c1f503d9e
--- /dev/null
+++ b/tools/perf/util/jitdump.h
@@ -0,0 +1,124 @@
1/*
2 * jitdump.h: jitted code info encapsulation file format
3 *
4 * Adapted from OProfile GPLv2 support jidump.h:
5 * Copyright 2007 OProfile authors
6 * Jens Wilke
7 * Daniel Hansel
8 * Copyright IBM Corporation 2007
9 */
10#ifndef JITDUMP_H
11#define JITDUMP_H
12
13#include <sys/time.h>
14#include <time.h>
15#include <stdint.h>
16
17/* JiTD */
18#define JITHEADER_MAGIC 0x4A695444
19#define JITHEADER_MAGIC_SW 0x4454694A
20
21#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
22
23#define JITHEADER_VERSION 1
24
25enum jitdump_flags_bits {
26 JITDUMP_FLAGS_MAX_BIT,
27};
28
29#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
30 (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
31
32struct jitheader {
33 uint32_t magic; /* characters "jItD" */
34 uint32_t version; /* header version */
35 uint32_t total_size; /* total size of header */
36 uint32_t elf_mach; /* elf mach target */
37 uint32_t pad1; /* reserved */
38 uint32_t pid; /* JIT process id */
39 uint64_t timestamp; /* timestamp */
40 uint64_t flags; /* flags */
41};
42
43enum jit_record_type {
44 JIT_CODE_LOAD = 0,
45 JIT_CODE_MOVE = 1,
46 JIT_CODE_DEBUG_INFO = 2,
47 JIT_CODE_CLOSE = 3,
48
49 JIT_CODE_MAX,
50};
51
52/* record prefix (mandatory in each record) */
53struct jr_prefix {
54 uint32_t id;
55 uint32_t total_size;
56 uint64_t timestamp;
57};
58
59struct jr_code_load {
60 struct jr_prefix p;
61
62 uint32_t pid;
63 uint32_t tid;
64 uint64_t vma;
65 uint64_t code_addr;
66 uint64_t code_size;
67 uint64_t code_index;
68};
69
70struct jr_code_close {
71 struct jr_prefix p;
72};
73
74struct jr_code_move {
75 struct jr_prefix p;
76
77 uint32_t pid;
78 uint32_t tid;
79 uint64_t vma;
80 uint64_t old_code_addr;
81 uint64_t new_code_addr;
82 uint64_t code_size;
83 uint64_t code_index;
84};
85
86struct debug_entry {
87 uint64_t addr;
88 int lineno; /* source line number starting at 1 */
89 int discrim; /* column discriminator, 0 is default */
90 const char name[0]; /* null terminated filename, \xff\0 if same as previous entry */
91};
92
93struct jr_code_debug_info {
94 struct jr_prefix p;
95
96 uint64_t code_addr;
97 uint64_t nr_entry;
98 struct debug_entry entries[0];
99};
100
101union jr_entry {
102 struct jr_code_debug_info info;
103 struct jr_code_close close;
104 struct jr_code_load load;
105 struct jr_code_move move;
106 struct jr_prefix prefix;
107};
108
109static inline struct debug_entry *
110debug_entry_next(struct debug_entry *ent)
111{
112 void *a = ent + 1;
113 size_t l = strlen(ent->name) + 1;
114 return a + l;
115}
116
117static inline char *
118debug_entry_file(struct debug_entry *ent)
119{
120 void *a = ent + 1;
121 return a;
122}
123
124#endif /* !JITDUMP_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 562b8ebeae5b..b1dd68f358fc 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
6#include <inttypes.h> 6#include <inttypes.h>
7 7
8#include "symbol.h" 8#include "symbol.h"
9#include "demangle-java.h"
9#include "machine.h" 10#include "machine.h"
10#include "vdso.h" 11#include "vdso.h"
11#include <symbol/kallsyms.h> 12#include <symbol/kallsyms.h>
@@ -1077,6 +1078,8 @@ new_symbol:
1077 demangle_flags = DMGL_PARAMS | DMGL_ANSI; 1078 demangle_flags = DMGL_PARAMS | DMGL_ANSI;
1078 1079
1079 demangled = bfd_demangle(NULL, elf_name, demangle_flags); 1080 demangled = bfd_demangle(NULL, elf_name, demangle_flags);
1081 if (demangled == NULL)
1082 demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
1080 if (demangled != NULL) 1083 if (demangled != NULL)
1081 elf_name = demangled; 1084 elf_name = demangled;
1082 } 1085 }