lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Wed, 01 Apr 2015 09:58:57 +0300
From:	Adrian Hunter <adrian.hunter@...el.com>
To:	Stephane Eranian <eranian@...gle.com>, linux-kernel@...r.kernel.org
CC:	acme@...hat.com, peterz@...radead.org, mingo@...e.hu,
	ak@...ux.intel.com, jolsa@...hat.com, namhyung@...nel.org,
	cel@...ibm.com, sukadev@...ux.vnet.ibm.com, sonnyrao@...omium.org,
	johnmccutchan@...gle.com, dsahern@...il.com, pawel.moll@....com
Subject: Re: [PATCH v6 3/4] perf inject: add jitdump mmap injection support

On 31/03/15 01:19, Stephane Eranian wrote:
> This patch adds a --jit option to perf inject.
> 
> This options injects MMAP records into the perf.data
> file to cover the jitted code mmaps. It also emits
> ELF images for each function in the jidump file.
> Those images are created where the jitdump file is.
> The MMAP records point to that location as well.
> 
> Typical flow:
> $ perf record -k mono -- java -agentpath:libpjvmti.so java_class
> $ perf inject --jit -i perf.data -o perf.data.jitted
> $ perf report -i perf.data.jitted
> 
> Note that jitdump.h support is not limited to Java, it works with
> any jitted environment modified to emit the jitdump file format,
> include those where code can be jitted multiple times and moved
> around.
> 
> The jitdump.h format is adapted from the Oprofile project.
> 
> The genelf.c (ELF binary generation) depends on MD5 hash
> encoding for the buildid. To enable this, libssl-dev must
> be installed. If not, then genelf.c defaults to using
> urandom to generate the buildid, which is not ideal.
> The Makefile auto-detects the presence on libssl-dev.
> 
> This version mmaps the jitdump file to create a marker
> MMAP record in the perf.data file. The marker is used to detect
> jitdump and cause perf inject to inject the jitted mmaps and
> generate ELF images for jitted functions.
> 
> Signed-off-by: Stephane Eranian <eranian@...gle.com>
> ---
>  tools/build/Makefile.feature             |   2 +
>  tools/build/feature/Makefile             |   4 +
>  tools/build/feature/test-libcrypto.c     |   9 +
>  tools/perf/Documentation/perf-inject.txt |   6 +
>  tools/perf/builtin-inject.c              |  60 +++-
>  tools/perf/config/Makefile               |  11 +
>  tools/perf/util/Build                    |   2 +
>  tools/perf/util/genelf.c                 | 479 +++++++++++++++++++++++++
>  tools/perf/util/genelf.h                 |   6 +
>  tools/perf/util/jit.h                    |  15 +
>  tools/perf/util/jitdump.c                | 588 +++++++++++++++++++++++++++++++
>  tools/perf/util/jitdump.h                |  92 +++++
>  12 files changed, 1261 insertions(+), 13 deletions(-)
>  create mode 100644 tools/build/feature/test-libcrypto.c
>  create mode 100644 tools/perf/util/genelf.c
>  create mode 100644 tools/perf/util/genelf.h
>  create mode 100644 tools/perf/util/jit.h
>  create mode 100644 tools/perf/util/jitdump.c
>  create mode 100644 tools/perf/util/jitdump.h
> 
> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> index 3a0b0ca..8b468a3 100644
> --- a/tools/build/Makefile.feature
> +++ b/tools/build/Makefile.feature
> @@ -45,6 +45,7 @@ FEATURE_TESTS =			\
>  	libpython			\
>  	libpython-version		\
>  	libslang			\
> +	libcrypto			\
>  	libunwind			\
>  	pthread-attr-setaffinity-np	\
>  	stackprotector-all		\
> @@ -64,6 +65,7 @@ FEATURE_DISPLAY =			\
>  	libperl				\
>  	libpython			\
>  	libslang			\
> +	libcrypto			\
>  	libunwind			\
>  	libdw-dwarf-unwind		\
>  	zlib				\
> diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
> index 463ed8f..ed86700 100644
> --- a/tools/build/feature/Makefile
> +++ b/tools/build/feature/Makefile
> @@ -23,6 +23,7 @@ FILES=					\
>  	test-libpython.bin		\
>  	test-libpython-version.bin	\
>  	test-libslang.bin		\
> +	test-libcrypto.bin		\
>  	test-libunwind.bin		\
>  	test-libunwind-debug-frame.bin	\
>  	test-pthread-attr-setaffinity-np.bin	\
> @@ -93,6 +94,9 @@ __BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@)
>  test-libslang.bin:
>  	$(BUILD) -I/usr/include/slang -lslang
>  
> +test-libcrypto.bin:
> +	$(BUILD) -lcrypto
> +
>  test-gtk2.bin:
>  	$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
>  
> diff --git a/tools/build/feature/test-libcrypto.c b/tools/build/feature/test-libcrypto.c
> new file mode 100644
> index 0000000..8580c40
> --- /dev/null
> +++ b/tools/build/feature/test-libcrypto.c
> @@ -0,0 +1,9 @@
> +#include <openssl/md5.h>
> +
> +int main(void)
> +{
> +        MD5_CTX context;
> +
> +        MD5_Init(&context);
> +	return 0;
> +}
> diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
> index dc7442c..bb33fe2 100644
> --- a/tools/perf/Documentation/perf-inject.txt
> +++ b/tools/perf/Documentation/perf-inject.txt
> @@ -44,6 +44,12 @@ OPTIONS
>  --kallsyms=<file>::
>  	kallsyms pathname
>  
> +-j::
> +--jit::
> +	Process jitdump files by injecting the mmap records corresponding to jitted
> +	functions. This option also generates the ELF images for each jitted function
> +	found in the jitdumps files captured in the input perf.data file. Use this option
> +	if you are monitoring environment using JIT runtimes, such as Java, DART or V8.
>  SEE ALSO
>  --------
>  linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index ea46df25..af25d1a 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -16,6 +16,7 @@
>  #include "util/debug.h"
>  #include "util/build-id.h"
>  #include "util/data.h"
> +#include "util/jit.h"
>  
>  #include "util/parse-options.h"
>  
> @@ -26,6 +27,7 @@ struct perf_inject {
>  	struct perf_session	*session;
>  	bool			build_ids;
>  	bool			sched_stat;
> +	bool			jit_mode;
>  	const char		*input_name;
>  	struct perf_data_file	output;
>  	u64			bytes_written;
> @@ -121,12 +123,19 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
>  				   struct perf_sample *sample,
>  				   struct machine *machine)
>  {
> -	int err;
> -
> -	err = perf_event__process_mmap(tool, event, sample, machine);
> -	perf_event__repipe(tool, event, sample, machine);
> -
> -	return err;
> +	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
> +	u64 n = 0;
> +
> +	if (inject->jit_mode) {
> +		/*
> +		 * if jit marker, then inject jit mmaps and generate ELF images
> +		 */
> +		if (!jit_process(&inject->tool, &inject->output, machine, event->mmap.filename, sample->pid, &n)) {
> +			inject->bytes_written += n;
> +			return 0;
> +		}
> +	}

You have dropped perf_event__process_mmap() from the !inject->jit_mode case.
But it would be nicer for jit_mode to have its own function.

> +	return perf_event__repipe(tool, event, sample, machine);
>  }
>  
>  static int perf_event__repipe_mmap2(struct perf_tool *tool,
> @@ -134,12 +143,19 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
>  				   struct perf_sample *sample,
>  				   struct machine *machine)
>  {
> -	int err;
> -
> -	err = perf_event__process_mmap2(tool, event, sample, machine);
> -	perf_event__repipe(tool, event, sample, machine);
> -
> -	return err;
> +	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
> +	u64 n = 0;
> +
> +	if (inject->jit_mode) {
> +		/*
> +		 * if jit marker, then inject jit mmaps and generate ELF images
> +		 */
> +		if (!jit_process(&inject->tool, &inject->output, machine, event->mmap2.filename, sample->pid, &n)) {
> +			inject->bytes_written += n;
> +			return 0;
> +		}
> +	}

Ditto

> +	return perf_event__repipe(tool, event, sample, machine);
>  }
>  
>  static int perf_event__repipe_fork(struct perf_tool *tool,
> @@ -341,7 +357,6 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
>  			name, sample_msg);
>  		return -EINVAL;
>  	}
> -
>  	return 0;
>  }
>  
> @@ -439,6 +454,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
>  		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
>  			    "Merge sched-stat and sched-switch for getting events "
>  			    "where and how long tasks slept"),
> +		OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
>  		OPT_INCR('v', "verbose", &verbose,
>  			 "be more verbose (show build ids, etc)"),
>  		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
> @@ -470,6 +486,24 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
>  	if (inject.session == NULL)
>  		return -1;
>  
> +	if (inject.build_ids) {
> +		/*
> +		 * to make sure the mmap records are ordered correctly
> +		 * and so that the correct especially due to jitted code
> +		 * mmaps. We cannot generate the buildid hit list and
> +		 * inject the jit mmaps at the same time for now.
> +		 */
> +		inject.tool.ordered_events = true;
> +		inject.tool.ordering_requires_timestamps = true;
> +	}
> +
> +	if (inject.jit_mode) {
> +		inject.tool.mmap2	   = perf_event__repipe_mmap2;
> +		inject.tool.mmap	   = perf_event__repipe_mmap;

As suggested above, why not make your own tool fns e.g.

		inject.tool.mmap2	   = perf_event__jit_mode_mmap2;
		inject.tool.mmap	   = perf_event__jit_mode_mmap;


> +		inject.tool.ordered_events = true;
> +		inject.tool.ordering_requires_timestamps = true;

You are taking advantage of a bug in perf-inject, that is the
"finished_round" events are not being processed. Really they should be
processed and you should inject in time order.

> +	}
> +
>  	if (symbol__init(&inject.session->header.env) < 0)
>  		return -1;
>  
> diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
> index cd121df..e3cf5e4 100644
> --- a/tools/perf/config/Makefile
> +++ b/tools/perf/config/Makefile
> @@ -366,6 +366,17 @@ ifndef NO_LIBAUDIT
>    endif
>  endif
>  
> +ifndef NO_LIBCRYPTO
> +  ifneq ($(feature-libcrypto), 1)
> +    msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
> +    NO_LIBCRYPTO := 1
> +  else
> +    CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
> +    EXTLIBS += -lcrypto
> +    $(call detected,CONFIG_CRYPTO)
> +  endif
> +endif
> +
>  ifdef NO_NEWT
>    NO_SLANG=1
>  endif
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 9bff65e..8bc62b4 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -75,6 +75,8 @@ libperf-$(CONFIG_X86) += tsc.o
>  libperf-y += cloexec.o
>  libperf-y += thread-stack.o
>  libperf-y += demangle-java.o
> +libperf-y += jitdump.o
> +libperf-y += genelf.o
>  
>  libperf-$(CONFIG_LIBELF) += symbol-elf.o
>  libperf-$(CONFIG_LIBELF) += probe-event.o
> diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
> new file mode 100644
> index 0000000..a5beebe
> --- /dev/null
> +++ b/tools/perf/util/genelf.c
> @@ -0,0 +1,479 @@
> +/*
> + * genelf.c
> + * Copyright (C) 2014, Google, Inc
> + *
> + * Contributed by:
> + * 	Stephane Eranian <eranian@...il.com>
> + *
> + * Released under the GPL v2. (and only v2, not any later version)
> + */
> +
> +#include <sys/types.h>
> +#include <stdio.h>
> +#include <getopt.h>
> +#include <stddef.h>
> +#include <libelf.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <fcntl.h>
> +#include <err.h>
> +
> +#include "perf.h"
> +#include "genelf.h"
> +
> +#define JVMTI
> +
> +#define BUILD_ID_URANDOM /* different uuid for each run */
> +
> +#ifdef HAVE_LIBCRYPTO
> +
> +#define BUILD_ID_MD5
> +#undef BUILD_ID_SHA	/* does not seem to work well when linked with Java */
> +#undef BUILD_ID_URANDOM /* different uuid for each run */
> +
> +#ifdef BUILD_ID_SHA
> +#include <openssl/sha.h>
> +#endif
> +
> +#ifdef BUILD_ID_MD5
> +#include <openssl/md5.h>
> +#endif
> +#endif
> +
> +#if   defined(__arm__)
> +#define GEN_ELF_ARCH	EM_ARM
> +#define GEN_ELF_ENDIAN	ELFDATA2LSB
> +#define GEN_ELF_CLASS	ELFCLASS32
> +#elif defined(__x86_64__)
> +#define GEN_ELF_ARCH	EM_X86_64
> +#define GEN_ELF_ENDIAN	ELFDATA2LSB
> +#define GEN_ELF_CLASS	ELFCLASS64
> +#elif defined(__i386__)
> +#define GEN_ELF_ARCH	EM_386
> +#define GEN_ELF_ENDIAN	ELFDATA2LSB
> +#define GEN_ELF_CLASS	ELFCLASS32
> +#elif defined(__ppcle__)
> +#define GEN_ELF_ARCH	EM_PPC
> +#define GEN_ELF_ENDIAN	ELFDATA2LSB
> +#define GEN_ELF_CLASS	ELFCLASS64
> +#elif defined(__powerpc__)
> +#define GEN_ELF_ARCH	EM_PPC64
> +#define GEN_ELF_ENDIAN	ELFDATA2MSB
> +#define GEN_ELF_CLASS	ELFCLASS64
> +#elif defined(__powerpcle__)
> +#define GEN_ELF_ARCH	EM_PPC64
> +#define GEN_ELF_ENDIAN	ELFDATA2LSB
> +#define GEN_ELF_CLASS	ELFCLASS64
> +#else
> +#error "unsupported architecture"
> +#endif
> +
> +#if GEN_ELF_CLASS == ELFCLASS64
> +#define elf_newehdr	elf64_newehdr
> +#define elf_getshdr	elf64_getshdr
> +#define Elf_Ehdr	Elf64_Ehdr
> +#define Elf_Shdr	Elf64_Shdr
> +#define Elf_Sym		Elf64_Sym
> +#define ELF_ST_TYPE(a)	ELF64_ST_TYPE(a)
> +#define ELF_ST_BIND(a)	ELF64_ST_BIND(a)
> +#define ELF_ST_VIS(a)	ELF64_ST_VISIBILITY(a)
> +#else
> +#define elf_newehdr	elf32_newehdr
> +#define elf_getshdr	elf32_getshdr
> +#define Elf_Ehdr	Elf32_Ehdr
> +#define Elf_Shdr	Elf32_Shdr
> +#define Elf_Sym		Elf32_Sym
> +#define ELF_ST_TYPE(a)	ELF32_ST_TYPE(a)
> +#define ELF_ST_BIND(a)	ELF32_ST_BIND(a)
> +#define ELF_ST_VIS(a)	ELF32_ST_VISIBILITY(a)
> +#endif
> +
> +typedef struct {
> +  unsigned int namesz;  /* Size of entry's owner string */
> +  unsigned int descsz;  /* Size of the note descriptor */
> +  unsigned int type;    /* Interpretation of the descriptor */
> +  char         name[0]; /* Start of the name+desc data */
> +} Elf_Note;
> +
> +struct options {
> +	char *output;
> +	int fd;
> +};
> +
> +static char shd_string_table[] = {
> +	0,
> +	'.', 't', 'e', 'x', 't', 0,			/*  1 */
> +	'.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /*  7 */
> +	'.', 's', 'y', 'm', 't', 'a', 'b', 0,		/* 17 */
> +	'.', 's', 't', 'r', 't', 'a', 'b', 0,		/* 25 */
> +	'.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
> +};
> +
> +
> +static struct buildid_note {
> +	Elf_Note desc;		/* descsz: size of build-id, must be multiple of 4 */
> +	char	 name[4];	/* GNU\0 */
> +	char	 build_id[20];
> +} bnote;
> +
> +static Elf_Sym symtab[]={
> +	/* symbol 0 MUST be the undefined symbol */
> +	{ .st_name  = 0, /* index in sym_string table */
> +	  .st_info  = ELF_ST_TYPE(STT_NOTYPE),
> +	  .st_shndx = 0, /* for now */
> +	  .st_value = 0x0,
> +	  .st_other = ELF_ST_VIS(STV_DEFAULT),
> +	  .st_size  = 0,
> +	},
> +	{ .st_name  = 1, /* index in sym_string table */
> +	  .st_info  = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
> +	  .st_shndx = 1,
> +	  .st_value = 0, /* for now */
> +	  .st_other = ELF_ST_VIS(STV_DEFAULT),
> +	  .st_size  = 0, /* for now */
> +	}
> +};
> +
> +#ifdef BUILD_ID_URANDOM
> +static void
> +gen_build_id(struct buildid_note *note,
> +	     unsigned long load_addr __maybe_unused,
> +	     const void *code __maybe_unused,
> +	     size_t csize __maybe_unused)
> +{
> +	int fd;
> +	size_t sz = sizeof(note->build_id);
> +	ssize_t sret;
> +
> +	fd = open("/dev/urandom", O_RDONLY);
> +	if (fd == -1)
> +		err(1, "cannot access /dev/urandom for builid");
> +
> +	sret = read(fd, note->build_id, sz);
> +
> +	close(fd);
> +
> +	if (sret != (ssize_t)sz)
> +		memset(note->build_id, 0, sz);
> +}
> +#endif
> +
> +#ifdef BUILD_ID_SHA
> +static void
> +gen_build_id(struct buildid_note *note,
> +	     unsigned long load_addr __maybe_unused,
> +	     const void *code,
> +	     size_t csize)
> +{
> +	if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
> +		errx(1, "build_id too small for SHA1");
> +
> +	SHA1(code, csize, (unsigned char *)note->build_id);
> +}
> +#endif
> +
> +#ifdef BUILD_ID_MD5
> +static void
> +gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
> +{
> +	MD5_CTX context;
> +
> +	if (sizeof(note->build_id) < 16)
> +		errx(1, "build_id too small for MD5");
> +
> +	MD5_Init(&context);
> +	MD5_Update(&context, &load_addr, sizeof(load_addr));
> +	MD5_Update(&context, code, csize);
> +	MD5_Final((unsigned char *)note->build_id, &context);
> +}
> +#endif
> +
> +/*
> + * fd: file descriptor open for writing for the output file
> + * load_addr: code load address (could be zero, just used for buildid)
> + * sym: function name (for native code - used as the symbol)
> + * code: the native code
> + * csize: the code size in bytes
> + */
> +int
> +jit_write_elf(int fd, unsigned long load_addr, const char *sym, const void *code, int csize)
> +{
> +	Elf *e;
> +	Elf_Data *d;
> +	Elf_Scn *scn;
> +	Elf_Ehdr *ehdr;
> +	Elf_Shdr *shdr;
> +	char *strsym = NULL;
> +	int symlen;
> +	int retval = -1;
> +
> +	if (elf_version(EV_CURRENT) == EV_NONE) {
> +		warnx("ELF initialization failed");
> +		return -1;
> +	}
> +
> +	e = elf_begin(fd, ELF_C_WRITE, NULL);
> +	if (!e) {
> +		warnx("elf_begin failed");
> +		goto error;
> +	}
> +
> +	/*
> +	 * setup ELF header
> +	 */
> +	ehdr = elf_newehdr(e);
> +	if (!ehdr) {
> +		warnx("cannot get ehdr");
> +		goto error;
> +	}
> +
> +	ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
> +	ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
> +	ehdr->e_machine = GEN_ELF_ARCH;
> +	ehdr->e_type = ET_DYN;
> +	ehdr->e_entry = 0x0;
> +	ehdr->e_version = EV_CURRENT;
> +	ehdr->e_shstrndx= 2; /* shdr index for section name */
> +
> +	/*
> +	 * setup text section
> +	 */
> +	scn = elf_newscn(e);
> +	if (!scn) {
> +		warnx("cannot create section");
> +		goto error;
> +	}
> +
> +	d = elf_newdata(scn);
> +	if (!d) {
> +		warnx("cannot get new data");
> +		goto error;
> +	}
> +
> +	d->d_align = 16;
> +	d->d_off = 0LL;
> +	d->d_buf = (void *)code;
> +	d->d_type = ELF_T_BYTE;
> +	d->d_size = csize;
> +	d->d_version = EV_CURRENT;
> +
> +	shdr = elf_getshdr(scn);
> +	if (!shdr) {
> +		warnx("cannot get section header");
> +		goto error;
> +	}
> +
> +	shdr->sh_name = 1;
> +	shdr->sh_type = SHT_PROGBITS;
> +	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
> +	shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
> +	shdr->sh_entsize = 0;
> +
> +	/*
> +	 * setup section headers string table
> +	 */
> +	scn = elf_newscn(e);
> +	if (!scn) {
> +		warnx("cannot create section");
> +		goto error;
> +	}
> +
> +	d = elf_newdata(scn);
> +	if (!d) {
> +		warnx("cannot get new data");
> +		goto error;
> +	}
> +
> +	d->d_align = 1;
> +	d->d_off = 0LL;
> +	d->d_buf = shd_string_table;
> +	d->d_type = ELF_T_BYTE;
> +	d->d_size = sizeof(shd_string_table);
> +	d->d_version = EV_CURRENT;
> +
> +	shdr = elf_getshdr(scn);
> +	if (!shdr) {
> +		warnx("cannot get section header");
> +		goto error;
> +	}
> +
> +	shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
> +	shdr->sh_type = SHT_STRTAB;
> +	shdr->sh_flags = 0;
> +	shdr->sh_entsize = 0;
> +
> +	/*
> +	 * setup symtab section
> +	 */
> +	symtab[1].st_size  = csize;
> +
> +	scn = elf_newscn(e);
> +	if (!scn) {
> +		warnx("cannot create section");
> +		goto error;
> +	}
> +
> +	d = elf_newdata(scn);
> +	if (!d) {
> +		warnx("cannot get new data");
> +		goto error;
> +	}
> +
> +	d->d_align = 8;
> +	d->d_off = 0LL;
> +	d->d_buf = symtab;
> +	d->d_type = ELF_T_SYM;
> +	d->d_size = sizeof(symtab);
> +	d->d_version = EV_CURRENT;
> +
> +	shdr = elf_getshdr(scn);
> +	if (!shdr) {
> +		warnx("cannot get section header");
> +		goto error;
> +	}
> +
> +	shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
> +	shdr->sh_type = SHT_SYMTAB;
> +	shdr->sh_flags = 0;
> +	shdr->sh_entsize = sizeof(Elf_Sym);
> +	shdr->sh_link = 4; /* index of .strtab section */
> +
> +	/*
> +	 * setup symbols string table
> +	 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
> +	 */
> +	symlen = 2 + strlen(sym);
> +	strsym = calloc(1, symlen);
> +	if (!strsym) {
> +		warnx("cannot allocate strsym");
> +		goto error;
> +	}
> +	strcpy(strsym + 1, sym);
> +
> +	scn = elf_newscn(e);
> +	if (!scn) {
> +		warnx("cannot create section");
> +		goto error;
> +	}
> +
> +	d = elf_newdata(scn);
> +	if (!d) {
> +		warnx("cannot get new data");
> +		goto error;
> +	}
> +
> +	d->d_align = 1;
> +	d->d_off = 0LL;
> +	d->d_buf = strsym;
> +	d->d_type = ELF_T_BYTE;
> +	d->d_size = symlen;
> +	d->d_version = EV_CURRENT;
> +
> +	shdr = elf_getshdr(scn);
> +	if (!shdr) {
> +		warnx("cannot get section header");
> +		goto error;
> +	}
> +
> +	shdr->sh_name = 25; /* offset in shd_string_table */
> +	shdr->sh_type = SHT_STRTAB;
> +	shdr->sh_flags = 0;
> +	shdr->sh_entsize = 0;
> +
> +	/*
> +	 * setup build-id section
> +	 */
> +	scn = elf_newscn(e);
> +	if (!scn) {
> +		warnx("cannot create section");
> +		goto error;
> +	}
> +
> +	d = elf_newdata(scn);
> +	if (!d) {
> +		warnx("cannot get new data");
> +		goto error;
> +	}
> +
> +	/*
> +	 * build-id generation
> +	 */
> +	gen_build_id(&bnote, load_addr, code, csize);
> +	bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
> +	bnote.desc.descsz = sizeof(bnote.build_id);
> +	bnote.desc.type   = NT_GNU_BUILD_ID;
> +	strcpy(bnote.name, "GNU");
> +
> +	d->d_align = 4;
> +	d->d_off = 0LL;
> +	d->d_buf = &bnote;
> +	d->d_type = ELF_T_BYTE;
> +	d->d_size = sizeof(bnote);
> +	d->d_version = EV_CURRENT;
> +
> +	shdr = elf_getshdr(scn);
> +	if (!shdr) {
> +		warnx("cannot get section header");
> +		goto error;
> +	}
> +
> +	shdr->sh_name = 33; /* offset in shd_string_table */
> +	shdr->sh_type = SHT_NOTE;
> +	shdr->sh_addr = 0x0;
> +	shdr->sh_flags = SHF_ALLOC;
> +	shdr->sh_size = sizeof(bnote);
> +	shdr->sh_entsize = 0;
> +
> +	if (elf_update(e, ELF_C_WRITE) < 0) {
> +		warnx("elf_update 4 failed");
> +		goto error;
> +	}
> +	(void)elf_end(e);
> +
> +	retval = 0;
> +error:
> +	free(strsym);
> +
> +	return retval;
> +}
> +
> +#ifndef JVMTI
> +
> +static unsigned char x86_code[] = {
> +    0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
> +    0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
> +    0xCD, 0x80            /* int $0x80 */
> +};
> +
> +static struct options options;
> +
> +int main(int argc, char **argv)
> +{
> +	int c, fd, ret;
> +
> +	while ((c = getopt(argc, argv, "o:h")) != -1) {
> +		switch (c) {
> +		case 'o':
> +			options.output = optarg;
> +			break;
> +		case 'h':
> +			printf("Usage: genelf -o output_file [-h]\n");
> +			return 0;
> +		default:
> +			errx(1, "unknown option");
> +		}
> +	}
> +
> +	fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
> +	if (fd == -1)
> +		err(1, "cannot create file %s", options.output);
> +
> +	ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
> +	close(fd);
> +
> +	if (ret != 0)
> +		unlink(options.output);
> +
> +	return ret;
> +}
> +#endif
> diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
> new file mode 100644
> index 0000000..11307a2
> --- /dev/null
> +++ b/tools/perf/util/genelf.h
> @@ -0,0 +1,6 @@
> +#ifndef __GENELF_H__
> +#define __GENELF_H__
> +
> +extern int jit_write_elf(int fd, unsigned long code_addr, const char *sym, const void *code, int csize);
> +
> +#endif
> diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
> new file mode 100644
> index 0000000..2a812c0
> --- /dev/null
> +++ b/tools/perf/util/jit.h
> @@ -0,0 +1,15 @@
> +#ifndef __JIT_H__
> +#define __JIT_H__
> +
> +#include <data.h>
> +
> +extern int jit_process(struct perf_tool *tool,
> +		       struct perf_data_file *output,
> +		       struct machine *machine,
> +		       char *filename,
> +		       pid_t pid,
> +		       u64 *nbytes);
> +
> +extern int jit_inject_record(const char *filename);
> +
> +#endif /* __JIT_H__ */
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> new file mode 100644
> index 0000000..9c5fafe
> --- /dev/null
> +++ b/tools/perf/util/jitdump.c
> @@ -0,0 +1,588 @@
> +#include <sys/types.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <inttypes.h>
> +#include <byteswap.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +
> +#include "util.h"
> +#include "event.h"
> +#include "debug.h"
> +#include "symbol.h"
> +#include "strlist.h"
> +#include <elf.h>
> +
> +#include "session.h"
> +#include "jit.h"
> +#include "jitdump.h"
> +#include "genelf.h"
> +#include "../builtin.h"
> +
> +struct jit_buf_desc {
> +	struct perf_data_file *output;
> +	struct perf_tool *tool;
> +	struct machine *machine;
> +	union jr_entry   *entry;
> +	void             *buf;
> +	size_t           bufsize;
> +	FILE             *in;
> +	int              needs_bswap; /* handles cross-endianess */
> +	uint32_t         code_load_count;
> +	u64		 bytes_written;
> +	struct rb_root   code_root;
> +	char		 dir[PATH_MAX];
> +};
> +
> +struct debug_line_info {
> +	unsigned long vma;
> +	unsigned int lineno;
> +	/* The filename format is unspecified, absolute path, relative etc. */
> +	char const filename[0];
> +};
> +
> +struct jit_tool {
> +	struct perf_tool tool;
> +	struct perf_data_file	output;
> +	struct perf_data_file	input;
> +	u64 bytes_written;
> +};
> +
> +#define hmax(a, b) ((a) > (b) ? (a) : (b))
> +#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
> +
> +static int
> +jit_emit_elf(char *filename,
> +	     const char *sym,
> +	     unsigned long code,
> +	     int csize)
> +{
> +	int ret, fd;
> +	unsigned long addr = (unsigned long)code;
> +
> +	if (verbose > 0)
> +		fprintf(stderr, "write ELF image %s\n", filename);
> +
> +	fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
> +	if (fd == -1) {
> +		pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
> +		return -1;
> +	}
> +
> +        ret = jit_write_elf(fd, addr, sym, (const void *)code, csize);
> +
> +        close(fd);
> +
> +        if (ret)
> +                unlink(filename);
> +
> +	return ret;
> +}
> +
> +static void
> +jit_close(struct jit_buf_desc *jd)
> +{
> +	if (!(jd && jd->in))
> +		return;
> +	fclose(jd->in);
> +	jd->in = NULL;
> +}
> +
> +static int
> +jit_open(struct jit_buf_desc *jd, const char *name)
> +{
> +	struct jitheader header;
> +	struct jr_prefix *prefix;
> +	ssize_t bs, bsz = 0;
> +	void *n, *buf = NULL;
> +	int ret, retval = -1;
> +
> +	jd->in = fopen(name, "r");
> +	if (!jd->in)
> +		return -1;
> +
> +	bsz = hmax(sizeof(header), sizeof(*prefix));
> +
> +	buf = malloc(bsz);
> +	if (!buf)
> +		goto error;
> +
> +	ret = fread(buf, sizeof(header), 1, jd->in);
> +	if (ret != 1)
> +		goto error;
> +
> +	memcpy(&header, buf, sizeof(header));
> +
> +	if (header.magic != JITHEADER_MAGIC) {
> +		if (header.magic != JITHEADER_MAGIC_SW)
> +			goto error;
> +		jd->needs_bswap = 1;
> +	}
> +
> +	if (jd->needs_bswap) {
> +		header.version    = bswap_32(header.version);
> +		header.total_size = bswap_32(header.total_size);
> +		header.pid	  = bswap_32(header.pid);
> +		header.elf_mach   = bswap_32(header.elf_mach);
> +		header.timestamp  = bswap_64(header.timestamp);
> +	}
> +
> +	if (verbose > 2)
> +		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
> +			header.version,
> +			header.total_size,
> +			(unsigned long long)header.timestamp,
> +			header.pid,
> +			header.elf_mach);
> +
> +	bs = header.total_size - sizeof(header);
> +
> +	if (bs > bsz) {
> +		n = realloc(buf, bs);
> +		if (!n)
> +			goto error;
> +		bsz = bs;
> +		buf = n;
> +		/* read extra we do not know about */
> +		ret = fread(buf, bs - bsz, 1, jd->in);
> +		if (ret != 1)
> +			goto error;
> +	}
> +	/*
> +	 * keep dirname for generating files and mmap records
> +	 */
> +	strcpy(jd->dir, name);
> +	dirname(jd->dir);
> +
> +	return 0;
> +error:
> +	fclose(jd->in);
> +	return retval;
> +}
> +
> +static union jr_entry *
> +jit_get_next_entry(struct jit_buf_desc *jd)
> +{
> +	struct jr_prefix *prefix;
> +	union jr_entry *jr;
> +	void *addr;
> +	size_t bs, size;
> +	int id, ret;
> +
> +	if (!(jd && jd->in))
> +		return NULL;
> +
> +	if (jd->buf == NULL) {
> +		size_t sz = getpagesize();
> +		if (sz < sizeof(*prefix))
> +			sz = sizeof(*prefix);
> +
> +		jd->buf = malloc(sz);
> +		if (jd->buf == NULL)
> +			return NULL;
> +
> +		jd->bufsize = sz;
> +	}
> +
> +	prefix = jd->buf;
> +
> +	ret = fread(prefix, sizeof(*prefix), 1, jd->in);
> +	if (ret  != 1)
> +		return NULL;
> +
> +	if (jd->needs_bswap) {
> +		prefix->id   	   = bswap_32(prefix->id);
> +		prefix->total_size = bswap_32(prefix->total_size);
> +		prefix->timestamp  = bswap_64(prefix->timestamp);
> +	}
> +	id   = prefix->id;
> +	size = prefix->total_size;
> +
> +	bs = (size_t)size;
> +	if (bs < sizeof(*prefix))
> +		return NULL;
> +
> +	if (id >= JIT_CODE_MAX) {
> +		pr_warning("next_entry: unknown prefix %d, skipping\n", id);
> +		return NULL;
> +	}
> +	if (bs > jd->bufsize) {
> +		void *n;
> +		n = realloc(jd->buf, bs);
> +		if (!n)
> +			return NULL;
> +		jd->buf = n;
> +		jd->bufsize = bs;
> +	}
> +
> +	addr = ((void *)jd->buf) + sizeof(*prefix);
> +
> +	ret = fread(addr, bs - sizeof(*prefix), 1, jd->in);
> +	if (ret != 1)
> +		return NULL;
> +
> +	jr = (union jr_entry *)jd->buf;
> +
> +	switch(id) {
> +	case JIT_CODE_DEBUG_INFO:
> +	case JIT_CODE_CLOSE:
> +		break;
> +	case JIT_CODE_LOAD:
> +		if (jd->needs_bswap) {
> +			jr->load.pid       = bswap_32(jr->load.pid);
> +			jr->load.tid       = bswap_32(jr->load.tid);
> +			jr->load.vma       = bswap_64(jr->load.vma);
> +			jr->load.code_addr = bswap_64(jr->load.code_addr);
> +			jr->load.code_size = bswap_64(jr->load.code_size);
> +			jr->load.code_index= bswap_64(jr->load.code_index);
> +		}
> +		jd->code_load_count++;
> +		break;
> +	case JIT_CODE_MOVE:
> +		if (jd->needs_bswap) {
> +			jr->move.pid           = bswap_32(jr->move.pid);
> +			jr->move.tid           = bswap_32(jr->move.tid);
> +			jr->move.vma           = bswap_64(jr->move.vma);
> +			jr->move.old_code_addr = bswap_64(jr->move.old_code_addr);
> +			jr->move.new_code_addr = bswap_64(jr->move.new_code_addr);
> +			jr->move.code_size     = bswap_64(jr->move.code_size);
> +			jr->move.code_index    = bswap_64(jr->move.code_index);
> +		}
> +		break;
> +	case JIT_CODE_MAX:
> +	default:
> +		return NULL;
> +	}
> +	return jr;
> +}
> +
> +static int
> +jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
> +{
> +	ssize_t size;
> +
> +	size = perf_data_file__write(jd->output, event, event->header.size);
> +	if (size < 0)
> +		return -1;
> +
> +	jd->bytes_written += size;
> +	return 0;
> +}
> +
> +static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> +{
> +	struct perf_sample sample;
> +	union perf_event *event;
> +	unsigned long code, addr;
> +	char *filename;
> +	struct stat st;
> +	size_t size;
> +	u16 idr_size;
> +	const char *sym;
> +	uint32_t count;
> +	int ret, csize;
> +	pid_t pid, tid;
> +	struct {
> +		u32 pid, tid;
> +		u64 time;
> +	} *id;
> +
> +	pid   = jr->load.pid;
> +	tid   = jr->load.tid;
> +	csize = jr->load.code_size;
> +	addr  = jr->load.code_addr;
> +	sym   = (void *)((unsigned long)jr + sizeof(jr->load));
> +	code  = (unsigned long)jr + jr->load.p.total_size - csize;
> +	count = jr->load.code_index;
> +	idr_size = jd->machine->id_hdr_size;
> +	/*
> +	 * +16 to account for sample_id_all (hack)
> +	 */
> +	event = calloc(1, sizeof(*event) + 16);
> +	if (!event)
> +		return -1;
> +
> +	filename = event->mmap2.filename;
> +	size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%u",
> +			jd->dir,
> +			pid,
> +			count);
> +
> +	size++; /* for \0 */
> +
> +	size = PERF_ALIGN(size, sizeof(u64));
> +
> +	ret = jit_emit_elf(filename, sym, code, csize);
> +	if (ret) {
> +		free(event);
> +		return -1;
> +	}
> +
> +	if (stat(filename, &st))
> +		memset(&st, 0, sizeof(stat));
> +
> +	event->mmap2.header.type = PERF_RECORD_MMAP2;
> +	event->mmap2.header.misc = PERF_RECORD_MISC_USER;
> +	event->mmap2.header.size = (sizeof(event->mmap2) -
> +			(sizeof(event->mmap2.filename) - size) + idr_size);
> +
> +	event->mmap2.pgoff = 0;
> +	event->mmap2.start = addr;
> +	event->mmap2.len   = csize;
> +	event->mmap2.pid   = pid;
> +	event->mmap2.tid   = tid;
> +	event->mmap2.ino   = st.st_ino;
> +	event->mmap2.maj   = major(st.st_dev);
> +	event->mmap2.min   = minor(st.st_dev);
> +	event->mmap2.prot  = st.st_mode;
> +	event->mmap2.flags = MAP_SHARED;
> +	event->mmap2.ino_generation = 1;
> +
> +	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
> +	id->pid  = pid;
> +	id->tid  = tid;
> +	id->time = jr->load.p.timestamp;

You need to take acount of the sample_type here instead of hard-coding the
format of the id sample.

> +
> +	/*
> +	 * create pseudo sample to induce dso hit increment
> +	 * use first address as sample address
> +	 */
> +	memset(&sample, 0, sizeof(sample));
> +	sample.pid  = pid;
> +	sample.tid  = tid;
> +	sample.time = id->time;
> +	sample.ip   = addr;
> +
> +	ret = perf_event__process_mmap2(jd->tool, event, &sample, jd->machine);
> +	if (ret)
> +		return ret;
> +
> +	ret = jit_inject_event(jd, event);
> +	/*
> +	 * mark dso as use to generate buildid in the header
> +	 */
> +	if (!ret)
> +		build_id__mark_dso_hit(jd->tool, event, &sample, NULL, jd->machine);
> +
> +	return ret;
> +}
> +
> +static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
> +{
> +	struct perf_sample sample;
> +	union perf_event *event;
> +	char *filename;
> +	size_t size;
> +	struct stat st;
> +	u16 idr_size;
> +	int ret;
> +	pid_t pid, tid;
> +	struct {
> +		u32 pid, tid;
> +		u64 time;
> +	} *id;
> +
> +	pid = jr->move.pid;
> +	tid =  jr->move.tid;
> +	idr_size = jd->machine->id_hdr_size;
> +
> +	/*
> +	 * +16 to account for sample_id_all (hack)
> +	 */
> +	event = calloc(1, sizeof(*event) + 16);
> +	if (!event)
> +		return -1;
> +
> +	filename = event->mmap2.filename;
> +	size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64,
> +	         jd->dir,
> +	         pid,
> +		 jr->move.code_index);
> +
> +	size++; /* for \0 */
> +
> +	if (stat(filename, &st))
> +		memset(&st, 0, sizeof(stat));
> +
> +	size = PERF_ALIGN(size, sizeof(u64));
> +
> +	event->mmap2.header.type = PERF_RECORD_MMAP2;
> +	event->mmap2.header.misc = PERF_RECORD_MISC_USER;
> +	event->mmap2.header.size = (sizeof(event->mmap2) -
> +			(sizeof(event->mmap2.filename) - size) + idr_size);
> +	event->mmap2.pgoff = 0;
> +	event->mmap2.start = jr->move.new_code_addr;
> +	event->mmap2.len   = jr->move.code_size;
> +	event->mmap2.pid   = pid;
> +	event->mmap2.tid   = tid;
> +	event->mmap2.ino   = st.st_ino;
> +	event->mmap2.maj   = major(st.st_dev);
> +	event->mmap2.min   = minor(st.st_dev);
> +	event->mmap2.prot  = st.st_mode;
> +	event->mmap2.flags = MAP_SHARED;
> +	event->mmap2.ino_generation = 1;
> +
> +	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
> +	id->pid  = pid;
> +	id->tid  = tid;
> +	id->time = jr->move.p.timestamp;
> +
> +	/*
> +	 * create pseudo sample to induce dso hit increment
> +	 * use first address as sample address
> +	 */
> +	memset(&sample, 0, sizeof(sample));
> +	sample.pid  = pid;
> +	sample.tid  = tid;
> +	sample.time = id->time;
> +	sample.ip   = jr->move.new_code_addr;
> +
> +	ret = perf_event__process_mmap2(jd->tool, event, &sample, jd->machine);
> +	if (ret)
> +		return ret;
> +
> +	ret = jit_inject_event(jd, event);
> +	if (!ret)
> +		build_id__mark_dso_hit(jd->tool, event, &sample, NULL, jd->machine);
> +
> +	return ret;
> +}
> +
> +static int
> +jit_process_dump(struct jit_buf_desc *jd)
> +{
> +	union jr_entry *jr;
> +	int ret;
> +
> +	while ((jr = jit_get_next_entry(jd))) {
> +		switch(jr->prefix.id) {
> +		case JIT_CODE_LOAD:
> +			ret = jit_repipe_code_load(jd, jr);
> +			break;
> +		case JIT_CODE_MOVE:
> +			ret = jit_repipe_code_move(jd, jr);
> +			break;
> +		default:
> +			ret = 0;
> +			continue;
> +		}
> +	}
> +	return ret;
> +}
> +
> +static int
> +jit_inject(struct jit_buf_desc *jd, char *path)
> +{
> +	int ret;
> +
> +	if (verbose > 0)
> +		fprintf(stderr, "injecting: %s\n", path);
> +
> +	ret = jit_open(jd, path);
> +	if (ret)
> +		return -1;
> +
> +	ret = jit_process_dump(jd);
> +
> +	jit_close(jd);
> +
> +	if (verbose > 0)
> +		fprintf(stderr, "injected: %s (%d)\n", path, ret);
> +
> +	return 0;
> +}
> +
> +/*
> + * File must be with pattern .../jit-XXXX.dump
> + * where XXXX is the PID of the process which did the mmap()
> + * as captured in the RECORD_MMAP record
> + */
> +static int
> +jit_detect(char *mmap_name, pid_t pid)
> + {
> +	char *p;
> +	char *end = NULL;
> +	pid_t pid2;
> +
> +	if (verbose > 2)
> +		fprintf(stderr, "jit marker trying : %s\n", mmap_name);
> +	/*
> +	 * get file name
> +	 */
> +	p = strrchr(mmap_name, '/');
> +	if (!p)
> +		return -1;
> +
> +	/*
> +	 * match prefix
> +	 */
> +	if (strncmp(p, "/jit-", 5))
> +		return -1;
> +
> +	/*
> +	 * skip prefix
> +	 */
> +	p += 5;
> +
> +	/*
> +	 * must be followed by a pid
> +	 */
> +	if (!isdigit(*p))
> +		return -1;
> +
> +	pid2 = (int)strtol(p, &end, 10);
> +	if (!end)
> +		return -1;
> +
> +	/*
> +	 * pid does not match mmap pid
> +	 * pid==0 in system-wide mode (synthesized)
> +	 */
> +	if (pid && pid2 != pid)
> +		return -1;
> +	/*
> +	 * validate suffix
> +	 */
> +	if (strcmp(end, ".dump"))
> +		return -1;
> +
> +	if (verbose > 0)
> +		fprintf(stderr, "jit marker found: %s\n", mmap_name);
> +
> +	return 0;
> +}
> +
> +int
> +jit_process(struct perf_tool *tool,
> +	    struct perf_data_file *output,
> +	    struct machine *machine,
> +	    char *filename,
> +	    pid_t pid,
> +	    u64 *nbytes)
> +{
> +	struct jit_buf_desc jd;
> +	int ret;
> +
> +	memset(&jd, 0, sizeof(jd));
> +
> +	jd.tool    = tool;
> +	jd.output  = output;
> +	jd.machine = machine;
> +
> +	*nbytes = 0;
> +
> +	/*
> +	 * detect marker mmap (i.e., the jitdump mmap)
> +	 */
> +	if (jit_detect(filename, pid))
> +		return -1;
> +
> +	ret = jit_inject(&jd, filename);
> +	if (!ret)
> +		*nbytes = jd.bytes_written;
> +
> +	return ret;
> +}
> diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
> new file mode 100644
> index 0000000..120bdcf
> --- /dev/null
> +++ b/tools/perf/util/jitdump.h
> @@ -0,0 +1,92 @@
> +/*
> + * jitdump.h: jitted code info encapsulation file format
> + *
> + * Adapted from OProfile GPLv2 support jidump.h:
> + * Copyright 2007 OProfile authors
> + * Jens Wilke
> + * Daniel Hansel
> + * Copyright IBM Corporation 2007
> + */
> +#ifndef JITDUMP_H
> +#define JITDUMP_H
> +
> +#include <sys/time.h>
> +#include <time.h>
> +#include <stdint.h>
> +
> +/* JiTD */
> +#define JITHEADER_MAGIC		0x4A695444
> +#define JITHEADER_MAGIC_SW	0x4454694A
> +
> +#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
> +
> +#define JITHEADER_VERSION 1
> +
> +struct jitheader {
> +	uint32_t magic;		/* characters "jItD" */
> +	uint32_t version;	/* header version */
> +	uint32_t total_size;	/* total size of header */
> +	uint32_t elf_mach;	/* elf mach target */
> +	uint32_t pad1;		/* reserved */
> +	uint32_t pid;		/* JIT process id */
> +	uint64_t timestamp;	/* timestamp */
> +};
> +
> +enum jit_record_type {
> +	JIT_CODE_LOAD		= 0,
> +        JIT_CODE_MOVE           = 1,
> +	JIT_CODE_DEBUG_INFO	= 2,
> +	JIT_CODE_CLOSE		= 3,
> +
> +	JIT_CODE_MAX,
> +};
> +
> +/* record prefix (mandatory in each record) */
> +struct jr_prefix {
> +	uint32_t id;
> +	uint32_t total_size;
> +	uint64_t timestamp;
> +};
> +
> +struct jr_code_load {
> +	struct jr_prefix p;
> +
> +	uint32_t pid;
> +	uint32_t tid;
> +	uint64_t vma;
> +	uint64_t code_addr;
> +	uint64_t code_size;
> +	uint64_t code_index;
> +};
> +
> +struct jr_code_close {
> +	struct jr_prefix p;
> +};
> +
> +struct jr_code_move {
> +	struct jr_prefix p;
> +
> +	uint32_t pid;
> +	uint32_t tid;
> +	uint64_t vma;
> +	uint64_t old_code_addr;
> +	uint64_t new_code_addr;
> +	uint64_t code_size;
> +	uint64_t code_index;
> +};
> +
> +struct jr_code_debug_info {
> +	struct jr_prefix p;
> +
> +	uint64_t code_addr;
> +	uint64_t nr_entry;
> +};
> +
> +union jr_entry {
> +        struct jr_code_debug_info info;
> +        struct jr_code_close close;
> +        struct jr_code_load load;
> +        struct jr_code_move move;
> +        struct jr_prefix prefix;
> +};
> +#endif /* !JITDUMP_H */
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ