2012-05-14 07:12:09

by Namhyung Kim

[permalink] [raw]
Subject: [RFC 0/5] perf tools: Minimalistic build without libelf dependency

Hi,

NOTE: This is a RFC patchset and it contains a lot of rough edges
and ugly codes.

Current build procedure of perf tools requires a couple of external
libraries. Although most of them are optional, elfutils' libelf is
mandatory for resolving symbols and build-id of the binaries being
profiled. For some reason, it makes embedded guys' life harder who
want to build and run perf tools on their boards.

This patch set tries to fix the problem by letting the perf could
be built without libelf. The initial intent was just providing
perf record command to gather performance events interested on the
system and copies the data to development box to be used by perf
report for analysis.

However it's changed to have most of perf commands as is because
perf can resolve kernel symbols without libelf and many of perf
commands deal (mostly) with kernel events - so no need to restrict
capability of perf tools. Therefore, the end result is not so
minimalistic in fact and only thing it cannot do is "perf probe".

And then I realized that the perf record needs to know about the
build-id's anyway :(. So I implemented a poor man's version of elf
parser only for parsing the build-id info.

To build a minimal perf tools, pass MINIMAL=1 to make. The perf
report will not display symbol names:

# Samples: 988 of event 'cycles'
# Event count (approx.): 3726465542
#
# Overhead Command Shared Object Symbol
# ........ ....... ................. .........................
#
98.40% noploop noploop [.] 0x000000000000066d
1.35% noploop ld-2.15.so [.] 0x000000000000bab1
0.10% noploop [kernel.kallsyms] [k] native_write_msr_safe
0.10% noploop [kernel.kallsyms] [k] scheduler_tick
0.03% noploop [kernel.kallsyms] [k] bad_range
0.01% noploop [kernel.kallsyms] [k] pipe_read

But perf buildid-list can show you the build-id's:

$ ./perf buildid-list
ebfc1bdb98999c64d36ddfe394c58df3de6cbcfb [kernel.kallsyms]
52f0c5f25b95075e6fd7682763f7c3a779a4e889 /usr/lib64/ld-2.15.so
43a7a2b399b6ee2ff29c6bdadbda6bff88712ed4 /home/namhyung/bin/noploop

So it can be packed using perf archive so copied and analized
with full-fledged perf tools on a development machine.

This patchset is based on commit cb04ff9ac424 ("sched, perf: Use
a single callback into the scheduler") and tested on x86_64 and arm.

Any comments are welcome, thanks.
Namhyung


Namhyung Kim (5):
perf symbols: Introduce symbol__elf_init()
perf symbols: Do not use ELF's symbol binding constants
perf tools: Split out util/symbol-elf.c
perf tools: Support minimal build
perf symbols: Implement poor man's ELF parser

tools/perf/Makefile | 29 ++
tools/perf/builtin-buildid-list.c | 4 +-
tools/perf/builtin-top.c | 5 +-
tools/perf/command-list.txt | 2 +-
tools/perf/perf.c | 2 +
tools/perf/ui/browsers/map.c | 5 +-
tools/perf/util/elf-minimal.h | 153 ++++++++
tools/perf/util/generate-cmdlist.sh | 15 +
tools/perf/util/symbol-elf.c | 691 +++++++++++++++++++++++++++++++++
tools/perf/util/symbol-minimal.c | 258 +++++++++++++
tools/perf/util/symbol.c | 712 ++---------------------------------
tools/perf/util/symbol.h | 20 +
12 files changed, 1195 insertions(+), 701 deletions(-)
create mode 100644 tools/perf/util/elf-minimal.h
create mode 100644 tools/perf/util/symbol-elf.c
create mode 100644 tools/perf/util/symbol-minimal.c

--
1.7.10.1


2012-05-14 07:12:11

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 1/5] perf symbols: Introduce symbol__elf_init()

The symbol__elf_init() is for initializing internal libelf
data structure and getting rid of its dependency outside of
ELF/symboling handling code.

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-buildid-list.c | 4 +---
tools/perf/util/symbol.c | 8 +++++++-
tools/perf/util/symbol.h | 1 +
3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 52480467e9ff..dfa01b8160a7 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -16,8 +16,6 @@
#include "util/session.h"
#include "util/symbol.h"

-#include <libelf.h>
-
static const char *input_name;
static bool force;
static bool show_kernel;
@@ -71,7 +69,7 @@ static int perf_session__list_build_ids(void)
{
struct perf_session *session;

- elf_version(EV_CURRENT);
+ symbol__elf_init();

session = perf_session__new(input_name, O_RDONLY, force, false,
&build_id__mark_dso_hit_ops);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0a028c3ebaf..fe37d84e2107 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1395,6 +1395,11 @@ out_close:
return err;
}

+void symbol__elf_init(void)
+{
+ elf_version(EV_CURRENT);
+}
+
static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
{
return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
@@ -2584,7 +2589,8 @@ int symbol__init(void)

symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));

- elf_version(EV_CURRENT);
+ symbol__elf_init();
+
if (symbol_conf.sort_by_name)
symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
sizeof(struct symbol));
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 1f003884f1ab..27e882f5ad8a 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -265,6 +265,7 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);

int symbol__init(void);
void symbol__exit(void);
+void symbol__elf_init(void);
size_t symbol__fprintf_symname_offs(const struct symbol *sym,
const struct addr_location *al, FILE *fp);
size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
--
1.7.10.1

2012-05-14 07:12:14

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 5/5] perf symbols: Implement poor man's ELF parser

Implement minimalistic elf parser for getting build-id.
A couple of structs needed are copied from elf.h and
the parser only looks for PT_NOTE program header to
check build-id.
---
tools/perf/util/elf-minimal.h | 153 ++++++++++++++++++++++++
tools/perf/util/symbol-minimal.c | 244 ++++++++++++++++++++++++++++++++++++--
2 files changed, 388 insertions(+), 9 deletions(-)
create mode 100644 tools/perf/util/elf-minimal.h

diff --git a/tools/perf/util/elf-minimal.h b/tools/perf/util/elf-minimal.h
new file mode 100644
index 000000000000..26540b5718a1
--- /dev/null
+++ b/tools/perf/util/elf-minimal.h
@@ -0,0 +1,153 @@
+/*
+ * Minimal ELF definitions for parsing build-id.
+ */
+/* This file defines standard ELF types, structures, and macros.
+ Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _ELF_MINIMAL_H
+#define _ELF_MINIMAL_H 1
+
+/* Standard ELF types. */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity. */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities. */
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities. */
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+/* Type of addresses. */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets. */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+
+/* The ELF file header. This appears at the start of every ELF file. */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf64_Half e_type; /* Object file type */
+ Elf64_Half e_machine; /* Architecture */
+ Elf64_Word e_version; /* Object file version */
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags; /* Processor-specific flags */
+ Elf64_Half e_ehsize; /* ELF header size in bytes */
+ Elf64_Half e_phentsize; /* Program header table entry size */
+ Elf64_Half e_phnum; /* Program header table entry count */
+ Elf64_Half e_shentsize; /* Section header table entry size */
+ Elf64_Half e_shnum; /* Section header table entry count */
+ Elf64_Half e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Conglomeration of the identification bytes, for easy testing as a word. */
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFCLASSNUM 3
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+#define ELFDATANUM 3
+
+#define EI_VERSION 6 /* File version byte index */
+ /* Value must be EV_CURRENT */
+
+/* Legal values for e_version (version). */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+#define EV_NUM 2
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+/* Program segment header. */
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf64_Word p_type; /* Segment type */
+ Elf64_Word p_flags; /* Segment flags */
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type). */
+
+#define PT_NOTE 4 /* Auxiliary information */
+
+#endif /* _ELF_MINIMAL_H */
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 2917ede1d5ba..dfef571abc9b 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,29 +1,255 @@
#include "symbol.h"
+#include "elf-minimal.h"

+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <byteswap.h>
+#include <sys/stat.h>

-int filename__read_build_id(const char *filename __used, void *bf __used,
- size_t size __used)
+static bool check_need_swap(int file_endian)
{
- return -1;
+ const int data = 1;
+ u8 *check = (u8 *)&data;
+ int host_endian;
+
+ if (check[0] == 1)
+ host_endian = ELFDATA2LSB;
+ else
+ host_endian = ELFDATA2MSB;
+
+ return host_endian != file_endian;
}

-int sysfs__read_build_id(const char *filename __used, void *build_id __used,
- size_t size __used)
+#define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
+
+#define NT_GNU_BUILD_ID 3
+
+static int read_build_id(void *note_data, size_t note_len, void *bf,
+ size_t size, bool need_swap)
{
+ struct {
+ u32 n_namesz;
+ u32 n_descsz;
+ u32 n_type;
+ } *nhdr;
+ void *ptr;
+
+ ptr = note_data;
+ while (ptr < (note_data + note_len)) {
+ const char *name;
+ size_t namesz, descsz;
+
+ nhdr = ptr;
+ if (need_swap) {
+ nhdr->n_namesz = bswap_32(nhdr->n_namesz);
+ nhdr->n_descsz = bswap_32(nhdr->n_descsz);
+ nhdr->n_type = bswap_32(nhdr->n_type);
+ }
+
+ namesz = NOTE_ALIGN(nhdr->n_namesz);
+ descsz = NOTE_ALIGN(nhdr->n_descsz);
+
+ ptr += sizeof(*nhdr);
+ name = ptr;
+ ptr += namesz;
+ if (nhdr->n_type == NT_GNU_BUILD_ID &&
+ nhdr->n_namesz == sizeof("GNU")) {
+ if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
+ size_t sz = min(size, descsz);
+ memcpy(bf, ptr, sz);
+ memset(bf + sz, 0, size - sz);
+ return 0;
+ }
+ }
+ ptr += descsz;
+ }
+
return -1;
}

+/*
+ * Just try PT_NOTE header otherwise fails
+ */
+int filename__read_build_id(const char *filename, void *bf, size_t size)
+{
+ FILE *fp;
+ int ret = -1;
+ bool need_swap = false;
+ u8 e_ident[EI_NIDENT];
+ size_t buf_size;
+ void *buf;
+ int i;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ return -1;
+
+ if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
+ goto out;
+
+ if (memcmp(e_ident, ELFMAG, SELFMAG) ||
+ e_ident[EI_VERSION] != EV_CURRENT)
+ goto out;
+
+ need_swap = check_need_swap(e_ident[EI_DATA]);
+
+ /* for simplicity */
+ fseek(fp, 0, SEEK_SET);
+
+ if (e_ident[EI_CLASS] == ELFCLASS32) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr *phdr;
+
+ if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
+ goto out;
+
+ if (need_swap) {
+ ehdr.e_phoff = bswap_32(ehdr.e_phoff);
+ ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
+ ehdr.e_phnum = bswap_16(ehdr.e_phnum);
+ }
+
+ buf_size = ehdr.e_phentsize * ehdr.e_phnum;
+ buf = malloc(buf_size);
+ if (buf == NULL)
+ goto out;
+
+ fseek(fp, ehdr.e_phoff, SEEK_SET);
+ if (fread(buf, buf_size, 1, fp) != 1)
+ goto out_free;
+
+ for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
+ void *tmp;
+
+ if (need_swap) {
+ phdr->p_type = bswap_32(phdr->p_type);
+ phdr->p_offset = bswap_32(phdr->p_offset);
+ phdr->p_filesz = bswap_32(phdr->p_filesz);
+ }
+
+ if (phdr->p_type != PT_NOTE)
+ continue;
+
+ buf_size = phdr->p_filesz;
+ tmp = realloc(buf, buf_size);
+ if (tmp == NULL)
+ goto out_free;
+
+ buf = tmp;
+ fseek(fp, phdr->p_offset, SEEK_SET);
+ if (fread(buf, buf_size, 1, fp) != 1)
+ goto out_free;
+
+ ret = read_build_id(buf, buf_size, bf, size, need_swap);
+ if (ret == 0)
+ ret = size;
+ break;
+ }
+ } else {
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr *phdr;
+
+ if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
+ goto out;
+
+ if (need_swap) {
+ ehdr.e_phoff = bswap_64(ehdr.e_phoff);
+ ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
+ ehdr.e_phnum = bswap_16(ehdr.e_phnum);
+ }
+
+ buf_size = ehdr.e_phentsize * ehdr.e_phnum;
+ buf = malloc(buf_size);
+ if (buf == NULL)
+ goto out;
+
+ fseek(fp, ehdr.e_phoff, SEEK_SET);
+ if (fread(buf, buf_size, 1, fp) != 1)
+ goto out_free;
+
+ for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
+ void *tmp;
+
+ if (need_swap) {
+ phdr->p_type = bswap_32(phdr->p_type);
+ phdr->p_offset = bswap_64(phdr->p_offset);
+ phdr->p_filesz = bswap_64(phdr->p_filesz);
+ }
+
+ if (phdr->p_type != PT_NOTE)
+ continue;
+
+ buf_size = phdr->p_filesz;
+ tmp = realloc(buf, buf_size);
+ if (tmp == NULL)
+ goto out_free;
+
+ buf = tmp;
+ fseek(fp, phdr->p_offset, SEEK_SET);
+ if (fread(buf, buf_size, 1, fp) != 1)
+ goto out_free;
+
+ ret = read_build_id(buf, buf_size, bf, size, need_swap);
+ if (ret == 0)
+ ret = size;
+ break;
+ }
+ }
+out_free:
+ free(buf);
+out:
+ fclose(fp);
+ return ret;
+}
+
+int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
+{
+ int fd;
+ int ret = -1;
+ struct stat stbuf;
+ size_t buf_size;
+ void *buf;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ if (fstat(fd, &stbuf) < 0)
+ goto out;
+
+ buf_size = stbuf.st_size;
+ buf = malloc(buf_size);
+ if (buf == NULL)
+ goto out;
+
+ if (read(fd, buf, buf_size) != (ssize_t) buf_size)
+ goto out_free;
+
+ ret = read_build_id(buf, buf_size, build_id, size, false);
+out_free:
+ free(buf);
+out:
+ close(fd);
+ return ret;
+}
+
int dso__synthesize_plt_symbols(struct dso *dso __used, struct map *map __used,
symbol_filter_t filter __used)
{
return 0;
}

-int dso__load_sym(struct dso *dso __used, struct map *map __used,
- const char *name __used, int fd __used,
- symbol_filter_t filter __used, int kmodule __used,
- int want_symtab __used)
+int dso__load_sym(struct dso *dso, struct map *map __used, const char *name,
+ int fd __used, symbol_filter_t filter __used,
+ int kmodule __used, int want_symtab __used)
{
+ unsigned char *build_id[BUILD_ID_SIZE];
+
+ if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) {
+ dso__set_build_id(dso, build_id);
+ return 1;
+ }
return 0;
}

--
1.7.10.1

2012-05-14 07:12:37

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 4/5] perf tools: Support minimal build

Now we have isolated all ELF-specific stuff, it's possible
to build without libelf. The output binary can do most of
jobs but lacks (user level) symbol information - kernel
symbols are still accessable thanks to the kallsyms.

For now, only 'perf probe' command is removed since it
depends on libelf/libdw heavily.

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/Makefile | 28 ++++++++++++++++++++++++++++
tools/perf/command-list.txt | 2 +-
tools/perf/perf.c | 2 ++
tools/perf/util/generate-cmdlist.sh | 15 +++++++++++++++
tools/perf/util/symbol-minimal.c | 32 ++++++++++++++++++++++++++++++++
5 files changed, 78 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/util/symbol-minimal.c

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7198c6cbc006..001aec806903 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -424,6 +424,32 @@ PYRF_OBJS += $(OUTPUT)util/xyarray.o
-include config.mak.autogen
-include config.mak

+ifdef MINIMAL
+NO_DWARF := 1
+NO_NEWT := 1
+NO_GTK2 := 1
+NO_LIBPERL := 1
+NO_LIBPYTHON := 1
+NO_DEMANGLE := 1
+NO_STRLCPY := 1
+
+BASIC_CFLAGS += -DMINIMAL_BUILD
+
+EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
+
+# Remove ELF/DWARF dependent codes
+LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
+LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
+LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
+LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
+
+BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
+
+# Use minimal symbol handling
+LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
+
+endif # MINIMAL
+
ifndef NO_DWARF
FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
@@ -438,6 +464,7 @@ ifneq ($(OUTPUT),)
BASIC_CFLAGS += -I$(OUTPUT)
endif

+ifndef MINIMAL
FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
@@ -447,6 +474,7 @@ ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
endif
endif
+endif # MINIMAL

ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
BASIC_CFLAGS += -DLIBELF_NO_MMAP
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index d695fe40fbff..0303ec692274 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -18,7 +18,7 @@ perf-stat mainporcelain common
perf-timechart mainporcelain common
perf-top mainporcelain common
perf-script mainporcelain common
-perf-probe mainporcelain common
+perf-probe mainporcelain full
perf-kmem mainporcelain common
perf-lock mainporcelain common
perf-kvm mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 2b2e225a4d4c..1640d96c1716 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -313,7 +313,9 @@ static void handle_internal_command(int argc, const char **argv)
{ "version", cmd_version, 0 },
{ "script", cmd_script, 0 },
{ "sched", cmd_sched, 0 },
+#ifndef MINIMAL_BUILD
{ "probe", cmd_probe, 0 },
+#endif
{ "kmem", cmd_kmem, 0 },
{ "lock", cmd_lock, 0 },
{ "kvm", cmd_kvm, 0 },
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index f06f6fd148f8..829badc0f56a 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -21,4 +21,19 @@ do
p
}' "Documentation/perf-$cmd.txt"
done
+
+echo "#ifndef MINIMAL_BUILD"
+sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt |
+sort |
+while read cmd
+do
+ sed -n '
+ /^NAME/,/perf-'"$cmd"'/H
+ ${
+ x
+ s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
+ p
+ }' "Documentation/perf-$cmd.txt"
+done
+echo "#endif /* MINIMAL_BUILD */"
echo "};"
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
new file mode 100644
index 000000000000..2917ede1d5ba
--- /dev/null
+++ b/tools/perf/util/symbol-minimal.c
@@ -0,0 +1,32 @@
+#include "symbol.h"
+
+
+int filename__read_build_id(const char *filename __used, void *bf __used,
+ size_t size __used)
+{
+ return -1;
+}
+
+int sysfs__read_build_id(const char *filename __used, void *build_id __used,
+ size_t size __used)
+{
+ return -1;
+}
+
+int dso__synthesize_plt_symbols(struct dso *dso __used, struct map *map __used,
+ symbol_filter_t filter __used)
+{
+ return 0;
+}
+
+int dso__load_sym(struct dso *dso __used, struct map *map __used,
+ const char *name __used, int fd __used,
+ symbol_filter_t filter __used, int kmodule __used,
+ int want_symtab __used)
+{
+ return 0;
+}
+
+void symbol__elf_init(void)
+{
+}
--
1.7.10.1

2012-05-14 07:12:53

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 3/5] perf tools: Split out util/symbol-elf.c

Factor out the dependency of ELF handling into separate
symbol-elf.c file. It is a preparation of building a
minimalistic version perf tools which doesn't depend on
the elfutils.

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/Makefile | 1 +
tools/perf/util/symbol-elf.c | 691 +++++++++++++++++++++++++++++++++++++++++
tools/perf/util/symbol.c | 704 +-----------------------------------------
tools/perf/util/symbol.h | 15 +
4 files changed, 715 insertions(+), 696 deletions(-)
create mode 100644 tools/perf/util/symbol-elf.c

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index e98e14c88532..7198c6cbc006 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -334,6 +334,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
LIB_OBJS += $(OUTPUT)util/wrapper.o
LIB_OBJS += $(OUTPUT)util/sigchain.o
LIB_OBJS += $(OUTPUT)util/symbol.o
+LIB_OBJS += $(OUTPUT)util/symbol-elf.o
LIB_OBJS += $(OUTPUT)util/color.o
LIB_OBJS += $(OUTPUT)util/pager.o
LIB_OBJS += $(OUTPUT)util/header.o
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
new file mode 100644
index 000000000000..d68d16f89549
--- /dev/null
+++ b/tools/perf/util/symbol-elf.c
@@ -0,0 +1,691 @@
+#include <libelf.h>
+#include <gelf.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "symbol.h"
+#include "debug.h"
+
+#ifndef NT_GNU_BUILD_ID
+#define NT_GNU_BUILD_ID 3
+#endif
+
+/**
+ * elf_symtab__for_each_symbol - iterate thru all the symbols
+ *
+ * @syms: struct elf_symtab instance to iterate
+ * @idx: uint32_t idx
+ * @sym: GElf_Sym iterator
+ */
+#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
+ for (idx = 0, gelf_getsym(syms, idx, &sym);\
+ idx < nr_syms; \
+ idx++, gelf_getsym(syms, idx, &sym))
+
+static inline uint8_t elf_sym__type(const GElf_Sym *sym)
+{
+ return GELF_ST_TYPE(sym->st_info);
+}
+
+static inline int elf_sym__is_function(const GElf_Sym *sym)
+{
+ return elf_sym__type(sym) == STT_FUNC &&
+ sym->st_name != 0 &&
+ sym->st_shndx != SHN_UNDEF;
+}
+
+static inline bool elf_sym__is_object(const GElf_Sym *sym)
+{
+ return elf_sym__type(sym) == STT_OBJECT &&
+ sym->st_name != 0 &&
+ sym->st_shndx != SHN_UNDEF;
+}
+
+static inline int elf_sym__is_label(const GElf_Sym *sym)
+{
+ return elf_sym__type(sym) == STT_NOTYPE &&
+ sym->st_name != 0 &&
+ sym->st_shndx != SHN_UNDEF &&
+ sym->st_shndx != SHN_ABS;
+}
+
+static inline const char *elf_sec__name(const GElf_Shdr *shdr,
+ const Elf_Data *secstrs)
+{
+ return secstrs->d_buf + shdr->sh_name;
+}
+
+static inline int elf_sec__is_text(const GElf_Shdr *shdr,
+ const Elf_Data *secstrs)
+{
+ return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
+}
+
+static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
+ const Elf_Data *secstrs)
+{
+ return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
+}
+
+static inline const char *elf_sym__name(const GElf_Sym *sym,
+ const Elf_Data *symstrs)
+{
+ return symstrs->d_buf + sym->st_name;
+}
+
+static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
+{
+ switch (type) {
+ case MAP__FUNCTION:
+ return elf_sym__is_function(sym);
+ case MAP__VARIABLE:
+ return elf_sym__is_object(sym);
+ default:
+ return false;
+ }
+}
+
+static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
+ enum map_type type)
+{
+ switch (type) {
+ case MAP__FUNCTION:
+ return elf_sec__is_text(shdr, secstrs);
+ case MAP__VARIABLE:
+ return elf_sec__is_data(shdr, secstrs);
+ default:
+ return false;
+ }
+}
+
+static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
+{
+ Elf_Scn *sec = NULL;
+ GElf_Shdr shdr;
+ size_t cnt = 1;
+
+ while ((sec = elf_nextscn(elf, sec)) != NULL) {
+ gelf_getshdr(sec, &shdr);
+
+ if ((addr >= shdr.sh_addr) &&
+ (addr < (shdr.sh_addr + shdr.sh_size)))
+ return cnt;
+
+ ++cnt;
+ }
+
+ return -1;
+}
+
+static int elf_sym__binding(const GElf_Sym *sym)
+{
+ switch (GELF_ST_BIND(sym->st_info)) {
+ case STB_GLOBAL:
+ return SYMBIND_GLOBAL;
+ case STB_WEAK:
+ return SYMBIND_WEAK;
+ default:
+ return SYMBIND_LOCAL;
+ }
+}
+
+static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
+ GElf_Shdr *shp, const char *name,
+ size_t *idx)
+{
+ Elf_Scn *sec = NULL;
+ size_t cnt = 1;
+
+ while ((sec = elf_nextscn(elf, sec)) != NULL) {
+ char *str;
+
+ gelf_getshdr(sec, shp);
+ str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+ if (!strcmp(name, str)) {
+ if (idx)
+ *idx = cnt;
+ break;
+ }
+ ++cnt;
+ }
+
+ return sec;
+}
+
+#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
+ for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
+ idx < nr_entries; \
+ ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
+
+#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
+ for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
+ idx < nr_entries; \
+ ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
+
+/*
+ * We need to check if we have a .dynsym, so that we can handle the
+ * .plt, synthesizing its symbols, that aren't on the symtabs (be it
+ * .dynsym or .symtab).
+ * And always look at the original dso, not at debuginfo packages, that
+ * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
+ */
+int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
+ symbol_filter_t filter)
+{
+ uint32_t nr_rel_entries, idx;
+ GElf_Sym sym;
+ u64 plt_offset;
+ GElf_Shdr shdr_plt;
+ struct symbol *f;
+ GElf_Shdr shdr_rel_plt, shdr_dynsym;
+ Elf_Data *reldata, *syms, *symstrs;
+ Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
+ size_t dynsym_idx;
+ GElf_Ehdr ehdr;
+ char sympltname[1024];
+ Elf *elf;
+ int nr = 0, symidx, fd, err = 0;
+ char name[PATH_MAX];
+
+ snprintf(name, sizeof(name), "%s%s",
+ symbol_conf.symfs, dso->long_name);
+ fd = open(name, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+ if (elf == NULL)
+ goto out_close;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL)
+ goto out_elf_end;
+
+ scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
+ ".dynsym", &dynsym_idx);
+ if (scn_dynsym == NULL)
+ goto out_elf_end;
+
+ scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
+ ".rela.plt", NULL);
+ if (scn_plt_rel == NULL) {
+ scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
+ ".rel.plt", NULL);
+ if (scn_plt_rel == NULL)
+ goto out_elf_end;
+ }
+
+ err = -1;
+
+ if (shdr_rel_plt.sh_link != dynsym_idx)
+ goto out_elf_end;
+
+ if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
+ goto out_elf_end;
+
+ /*
+ * Fetch the relocation section to find the idxes to the GOT
+ * and the symbols in the .dynsym they refer to.
+ */
+ reldata = elf_getdata(scn_plt_rel, NULL);
+ if (reldata == NULL)
+ goto out_elf_end;
+
+ syms = elf_getdata(scn_dynsym, NULL);
+ if (syms == NULL)
+ goto out_elf_end;
+
+ scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
+ if (scn_symstrs == NULL)
+ goto out_elf_end;
+
+ symstrs = elf_getdata(scn_symstrs, NULL);
+ if (symstrs == NULL)
+ goto out_elf_end;
+
+ nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
+ plt_offset = shdr_plt.sh_offset;
+
+ if (shdr_rel_plt.sh_type == SHT_RELA) {
+ GElf_Rela pos_mem, *pos;
+
+ elf_section__for_each_rela(reldata, pos, pos_mem, idx,
+ nr_rel_entries) {
+ symidx = GELF_R_SYM(pos->r_info);
+ plt_offset += shdr_plt.sh_entsize;
+ gelf_getsym(syms, symidx, &sym);
+ snprintf(sympltname, sizeof(sympltname),
+ "%s@plt", elf_sym__name(&sym, symstrs));
+
+ f = symbol__new(plt_offset, shdr_plt.sh_entsize,
+ SYMBIND_GLOBAL, sympltname);
+ if (!f)
+ goto out_elf_end;
+
+ if (filter && filter(map, f))
+ symbol__delete(f);
+ else {
+ symbols__insert(&dso->symbols[map->type], f);
+ ++nr;
+ }
+ }
+ } else if (shdr_rel_plt.sh_type == SHT_REL) {
+ GElf_Rel pos_mem, *pos;
+ elf_section__for_each_rel(reldata, pos, pos_mem, idx,
+ nr_rel_entries) {
+ symidx = GELF_R_SYM(pos->r_info);
+ plt_offset += shdr_plt.sh_entsize;
+ gelf_getsym(syms, symidx, &sym);
+ snprintf(sympltname, sizeof(sympltname),
+ "%s@plt", elf_sym__name(&sym, symstrs));
+
+ f = symbol__new(plt_offset, shdr_plt.sh_entsize,
+ SYMBIND_GLOBAL, sympltname);
+ if (!f)
+ goto out_elf_end;
+
+ if (filter && filter(map, f))
+ symbol__delete(f);
+ else {
+ symbols__insert(&dso->symbols[map->type], f);
+ ++nr;
+ }
+ }
+ }
+
+ err = 0;
+out_elf_end:
+ elf_end(elf);
+out_close:
+ close(fd);
+
+ if (err == 0)
+ return nr;
+out:
+ pr_debug("%s: problems reading %s PLT info.\n",
+ __func__, dso->long_name);
+ return 0;
+}
+
+/*
+ * Align offset to 4 bytes as needed for note name and descriptor data.
+ */
+#define NOTE_ALIGN(n) (((n) + 3) & -4U)
+
+static int elf_read_build_id(Elf *elf, void *bf, size_t size)
+{
+ int err = -1;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ Elf_Scn *sec;
+ Elf_Kind ek;
+ void *ptr;
+
+ if (size < BUILD_ID_SIZE)
+ goto out;
+
+ ek = elf_kind(elf);
+ if (ek != ELF_K_ELF)
+ goto out;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ pr_err("%s: cannot get elf header.\n", __func__);
+ goto out;
+ }
+
+ sec = elf_section_by_name(elf, &ehdr, &shdr,
+ ".note.gnu.build-id", NULL);
+ if (sec == NULL) {
+ sec = elf_section_by_name(elf, &ehdr, &shdr,
+ ".notes", NULL);
+ if (sec == NULL)
+ goto out;
+ }
+
+ data = elf_getdata(sec, NULL);
+ if (data == NULL)
+ goto out;
+
+ ptr = data->d_buf;
+ while (ptr < (data->d_buf + data->d_size)) {
+ GElf_Nhdr *nhdr = ptr;
+ size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
+ descsz = NOTE_ALIGN(nhdr->n_descsz);
+ const char *name;
+
+ ptr += sizeof(*nhdr);
+ name = ptr;
+ ptr += namesz;
+ if (nhdr->n_type == NT_GNU_BUILD_ID &&
+ nhdr->n_namesz == sizeof("GNU")) {
+ if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
+ size_t sz = min(size, descsz);
+ memcpy(bf, ptr, sz);
+ memset(bf + sz, 0, size - sz);
+ err = descsz;
+ break;
+ }
+ }
+ ptr += descsz;
+ }
+
+out:
+ return err;
+}
+
+int filename__read_build_id(const char *filename, void *bf, size_t size)
+{
+ int fd, err = -1;
+ Elf *elf;
+
+ if (size < BUILD_ID_SIZE)
+ goto out;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+ if (elf == NULL) {
+ pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
+ goto out_close;
+ }
+
+ err = elf_read_build_id(elf, bf, size);
+
+ elf_end(elf);
+out_close:
+ close(fd);
+out:
+ return err;
+}
+
+int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
+{
+ int fd, err = -1;
+
+ if (size < BUILD_ID_SIZE)
+ goto out;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ while (1) {
+ char bf[BUFSIZ];
+ GElf_Nhdr nhdr;
+ size_t namesz, descsz;
+
+ if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
+ break;
+
+ namesz = NOTE_ALIGN(nhdr.n_namesz);
+ descsz = NOTE_ALIGN(nhdr.n_descsz);
+ if (nhdr.n_type == NT_GNU_BUILD_ID &&
+ nhdr.n_namesz == sizeof("GNU")) {
+ if (read(fd, bf, namesz) != (ssize_t)namesz)
+ break;
+ if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
+ size_t sz = min(descsz, size);
+ if (read(fd, build_id, sz) == (ssize_t)sz) {
+ memset(build_id + sz, 0, size - sz);
+ err = 0;
+ break;
+ }
+ } else if (read(fd, bf, descsz) != (ssize_t)descsz)
+ break;
+ } else {
+ int n = namesz + descsz;
+ if (read(fd, bf, n) != n)
+ break;
+ }
+ }
+ close(fd);
+out:
+ return err;
+}
+
+int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
+ symbol_filter_t filter, int kmodule, int want_symtab)
+{
+ struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
+ struct map *curr_map = map;
+ struct dso *curr_dso = dso;
+ Elf_Data *symstrs, *secstrs;
+ uint32_t nr_syms;
+ int err = -1;
+ uint32_t idx;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr, opdshdr;
+ Elf_Data *syms, *opddata = NULL;
+ GElf_Sym sym;
+ Elf_Scn *sec, *sec_strndx, *opdsec;
+ Elf *elf;
+ int nr = 0;
+ size_t opdidx = 0;
+
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+ if (elf == NULL) {
+ pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
+ goto out_close;
+ }
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ pr_debug("%s: cannot get elf header.\n", __func__);
+ goto out_elf_end;
+ }
+
+ /* Always reject images with a mismatched build-id: */
+ if (dso->has_build_id) {
+ u8 build_id[BUILD_ID_SIZE];
+
+ if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
+ goto out_elf_end;
+
+ if (!dso__build_id_equal(dso, build_id))
+ goto out_elf_end;
+ }
+
+ sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
+ if (sec == NULL) {
+ if (want_symtab)
+ goto out_elf_end;
+
+ sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
+ if (sec == NULL)
+ goto out_elf_end;
+ }
+
+ opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
+ if (opdshdr.sh_type != SHT_PROGBITS)
+ opdsec = NULL;
+ if (opdsec)
+ opddata = elf_rawdata(opdsec, NULL);
+
+ syms = elf_getdata(sec, NULL);
+ if (syms == NULL)
+ goto out_elf_end;
+
+ sec = elf_getscn(elf, shdr.sh_link);
+ if (sec == NULL)
+ goto out_elf_end;
+
+ symstrs = elf_getdata(sec, NULL);
+ if (symstrs == NULL)
+ goto out_elf_end;
+
+ sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+ if (sec_strndx == NULL)
+ goto out_elf_end;
+
+ secstrs = elf_getdata(sec_strndx, NULL);
+ if (secstrs == NULL)
+ goto out_elf_end;
+
+ nr_syms = shdr.sh_size / shdr.sh_entsize;
+
+ memset(&sym, 0, sizeof(sym));
+ if (dso->kernel == DSO_TYPE_USER) {
+ dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
+ elf_section_by_name(elf, &ehdr, &shdr,
+ ".gnu.prelink_undo",
+ NULL) != NULL);
+ } else {
+ dso->adjust_symbols = 0;
+ }
+ elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
+ struct symbol *f;
+ const char *elf_name = elf_sym__name(&sym, symstrs);
+ char *demangled = NULL;
+ int is_label = elf_sym__is_label(&sym);
+ const char *section_name;
+
+ if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
+ strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
+ kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
+
+ if (!is_label && !elf_sym__is_a(&sym, map->type))
+ continue;
+
+ /* Reject ARM ELF "mapping symbols": these aren't unique and
+ * don't identify functions, so will confuse the profile
+ * output: */
+ if (ehdr.e_machine == EM_ARM) {
+ if (!strcmp(elf_name, "$a") ||
+ !strcmp(elf_name, "$d") ||
+ !strcmp(elf_name, "$t"))
+ continue;
+ }
+
+ if (opdsec && sym.st_shndx == opdidx) {
+ u32 offset = sym.st_value - opdshdr.sh_addr;
+ u64 *opd = opddata->d_buf + offset;
+ sym.st_value = *opd;
+ sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
+ }
+
+ sec = elf_getscn(elf, sym.st_shndx);
+ if (!sec)
+ goto out_elf_end;
+
+ gelf_getshdr(sec, &shdr);
+
+ if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
+ continue;
+
+ section_name = elf_sec__name(&shdr, secstrs);
+
+ /* On ARM, symbols for thumb functions have 1 added to
+ * the symbol address as a flag - remove it */
+ if ((ehdr.e_machine == EM_ARM) &&
+ (map->type == MAP__FUNCTION) &&
+ (sym.st_value & 1))
+ --sym.st_value;
+
+ if (dso->kernel != DSO_TYPE_USER || kmodule) {
+ char dso_name[PATH_MAX];
+
+ if (strcmp(section_name,
+ (curr_dso->short_name +
+ dso->short_name_len)) == 0)
+ goto new_symbol;
+
+ if (strcmp(section_name, ".text") == 0) {
+ curr_map = map;
+ curr_dso = dso;
+ goto new_symbol;
+ }
+
+ snprintf(dso_name, sizeof(dso_name),
+ "%s%s", dso->short_name, section_name);
+
+ curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
+ if (curr_map == NULL) {
+ u64 start = sym.st_value;
+
+ if (kmodule)
+ start += map->start + shdr.sh_offset;
+
+ curr_dso = dso__new(dso_name);
+ if (curr_dso == NULL)
+ goto out_elf_end;
+ curr_dso->kernel = dso->kernel;
+ curr_dso->long_name = dso->long_name;
+ curr_dso->long_name_len = dso->long_name_len;
+ curr_map = map__new2(start, curr_dso,
+ map->type);
+ if (curr_map == NULL) {
+ dso__delete(curr_dso);
+ goto out_elf_end;
+ }
+ curr_map->map_ip = identity__map_ip;
+ curr_map->unmap_ip = identity__map_ip;
+ curr_dso->symtab_type = dso->symtab_type;
+ map_groups__insert(kmap->kmaps, curr_map);
+ dsos__add(&dso->node, curr_dso);
+ dso__set_loaded(curr_dso, map->type);
+ } else
+ curr_dso = curr_map->dso;
+
+ goto new_symbol;
+ }
+
+ if (curr_dso->adjust_symbols) {
+ pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
+ "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
+ (u64)sym.st_value, (u64)shdr.sh_addr,
+ (u64)shdr.sh_offset);
+ sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+ }
+ /*
+ * We need to figure out if the object was created from C++ sources
+ * DWARF DW_compile_unit has this, but we don't always have access
+ * to it...
+ */
+ demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
+ if (demangled != NULL)
+ elf_name = demangled;
+new_symbol:
+ f = symbol__new(sym.st_value, sym.st_size,
+ elf_sym__binding(&sym), elf_name);
+ free(demangled);
+ if (!f)
+ goto out_elf_end;
+
+ if (filter && filter(curr_map, f))
+ symbol__delete(f);
+ else {
+ symbols__insert(&curr_dso->symbols[curr_map->type], f);
+ nr++;
+ }
+ }
+
+ /*
+ * For misannotated, zeroed, ASM function sizes.
+ */
+ if (nr > 0) {
+ symbols__fixup_duplicate(&dso->symbols[map->type]);
+ symbols__fixup_end(&dso->symbols[map->type]);
+ if (kmap) {
+ /*
+ * We need to fixup this here too because we create new
+ * maps here, for things like vsyscall sections.
+ */
+ __map_groups__fixup_end(kmap->kmaps, map->type);
+ }
+ }
+ err = nr;
+out_elf_end:
+ elf_end(elf);
+out_close:
+ return err;
+}
+
+void symbol__elf_init(void)
+{
+ elf_version(EV_CURRENT);
+}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d4518a14edd8..462f91f1fe12 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -15,9 +15,6 @@
#include "symbol.h"
#include "strlist.h"

-#include <libelf.h>
-#include <gelf.h>
-#include <elf.h>
#include <limits.h>
#include <sys/utsname.h>

@@ -25,14 +22,7 @@
#define KSYM_NAME_LEN 256
#endif

-#ifndef NT_GNU_BUILD_ID
-#define NT_GNU_BUILD_ID 3
-#endif

-static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
-static int elf_read_build_id(Elf *elf, void *bf, size_t size);
-static void dsos__add(struct list_head *head, struct dso *dso);
-static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static int dso__load_kernel_sym(struct dso *dso, struct map *map,
symbol_filter_t filter);
static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
@@ -144,7 +134,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
return SYMBOL_B;
}

-static void symbols__fixup_duplicate(struct rb_root *symbols)
+void symbols__fixup_duplicate(struct rb_root *symbols)
{
struct rb_node *nd;
struct symbol *curr, *next;
@@ -173,7 +163,7 @@ again:
}
}

-static void symbols__fixup_end(struct rb_root *symbols)
+void symbols__fixup_end(struct rb_root *symbols)
{
struct rb_node *nd, *prevnd = rb_first(symbols);
struct symbol *curr, *prev;
@@ -196,7 +186,7 @@ static void symbols__fixup_end(struct rb_root *symbols)
curr->end = roundup(curr->start, 4096);
}

-static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
+void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
{
struct map *prev, *curr;
struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
@@ -226,8 +216,7 @@ static void map_groups__fixup_end(struct map_groups *mg)
__map_groups__fixup_end(mg, i);
}

-static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
- const char *name)
+struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
{
size_t namelen = strlen(name) + 1;
struct symbol *sym = calloc(1, (symbol_conf.priv_size +
@@ -360,7 +349,7 @@ void dso__set_build_id(struct dso *dso, void *build_id)
dso->has_build_id = 1;
}

-static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
+void symbols__insert(struct rb_root *symbols, struct symbol *sym)
{
struct rb_node **p = &symbols->rb_node;
struct rb_node *parent = NULL;
@@ -874,545 +863,7 @@ out_failure:
return -1;
}

-/**
- * elf_symtab__for_each_symbol - iterate thru all the symbols
- *
- * @syms: struct elf_symtab instance to iterate
- * @idx: uint32_t idx
- * @sym: GElf_Sym iterator
- */
-#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
- for (idx = 0, gelf_getsym(syms, idx, &sym);\
- idx < nr_syms; \
- idx++, gelf_getsym(syms, idx, &sym))
-
-static inline uint8_t elf_sym__type(const GElf_Sym *sym)
-{
- return GELF_ST_TYPE(sym->st_info);
-}
-
-static inline int elf_sym__is_function(const GElf_Sym *sym)
-{
- return elf_sym__type(sym) == STT_FUNC &&
- sym->st_name != 0 &&
- sym->st_shndx != SHN_UNDEF;
-}
-
-static inline bool elf_sym__is_object(const GElf_Sym *sym)
-{
- return elf_sym__type(sym) == STT_OBJECT &&
- sym->st_name != 0 &&
- sym->st_shndx != SHN_UNDEF;
-}
-
-static inline int elf_sym__is_label(const GElf_Sym *sym)
-{
- return elf_sym__type(sym) == STT_NOTYPE &&
- sym->st_name != 0 &&
- sym->st_shndx != SHN_UNDEF &&
- sym->st_shndx != SHN_ABS;
-}
-
-static inline const char *elf_sec__name(const GElf_Shdr *shdr,
- const Elf_Data *secstrs)
-{
- return secstrs->d_buf + shdr->sh_name;
-}
-
-static inline int elf_sec__is_text(const GElf_Shdr *shdr,
- const Elf_Data *secstrs)
-{
- return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
-}
-
-static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
- const Elf_Data *secstrs)
-{
- return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
-}
-
-static inline const char *elf_sym__name(const GElf_Sym *sym,
- const Elf_Data *symstrs)
-{
- return symstrs->d_buf + sym->st_name;
-}
-
-static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
- GElf_Shdr *shp, const char *name,
- size_t *idx)
-{
- Elf_Scn *sec = NULL;
- size_t cnt = 1;
-
- while ((sec = elf_nextscn(elf, sec)) != NULL) {
- char *str;
-
- gelf_getshdr(sec, shp);
- str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
- if (!strcmp(name, str)) {
- if (idx)
- *idx = cnt;
- break;
- }
- ++cnt;
- }
-
- return sec;
-}
-
-#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
- for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
- idx < nr_entries; \
- ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
-
-#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
- for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
- idx < nr_entries; \
- ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
-
-/*
- * We need to check if we have a .dynsym, so that we can handle the
- * .plt, synthesizing its symbols, that aren't on the symtabs (be it
- * .dynsym or .symtab).
- * And always look at the original dso, not at debuginfo packages, that
- * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
- */
-static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
- symbol_filter_t filter)
-{
- uint32_t nr_rel_entries, idx;
- GElf_Sym sym;
- u64 plt_offset;
- GElf_Shdr shdr_plt;
- struct symbol *f;
- GElf_Shdr shdr_rel_plt, shdr_dynsym;
- Elf_Data *reldata, *syms, *symstrs;
- Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
- size_t dynsym_idx;
- GElf_Ehdr ehdr;
- char sympltname[1024];
- Elf *elf;
- int nr = 0, symidx, fd, err = 0;
- char name[PATH_MAX];
-
- snprintf(name, sizeof(name), "%s%s",
- symbol_conf.symfs, dso->long_name);
- fd = open(name, O_RDONLY);
- if (fd < 0)
- goto out;
-
- elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
- if (elf == NULL)
- goto out_close;
-
- if (gelf_getehdr(elf, &ehdr) == NULL)
- goto out_elf_end;
-
- scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
- ".dynsym", &dynsym_idx);
- if (scn_dynsym == NULL)
- goto out_elf_end;
-
- scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
- ".rela.plt", NULL);
- if (scn_plt_rel == NULL) {
- scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
- ".rel.plt", NULL);
- if (scn_plt_rel == NULL)
- goto out_elf_end;
- }
-
- err = -1;
-
- if (shdr_rel_plt.sh_link != dynsym_idx)
- goto out_elf_end;
-
- if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
- goto out_elf_end;
-
- /*
- * Fetch the relocation section to find the idxes to the GOT
- * and the symbols in the .dynsym they refer to.
- */
- reldata = elf_getdata(scn_plt_rel, NULL);
- if (reldata == NULL)
- goto out_elf_end;
-
- syms = elf_getdata(scn_dynsym, NULL);
- if (syms == NULL)
- goto out_elf_end;
-
- scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
- if (scn_symstrs == NULL)
- goto out_elf_end;
-
- symstrs = elf_getdata(scn_symstrs, NULL);
- if (symstrs == NULL)
- goto out_elf_end;
-
- nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
- plt_offset = shdr_plt.sh_offset;
-
- if (shdr_rel_plt.sh_type == SHT_RELA) {
- GElf_Rela pos_mem, *pos;
-
- elf_section__for_each_rela(reldata, pos, pos_mem, idx,
- nr_rel_entries) {
- symidx = GELF_R_SYM(pos->r_info);
- plt_offset += shdr_plt.sh_entsize;
- gelf_getsym(syms, symidx, &sym);
- snprintf(sympltname, sizeof(sympltname),
- "%s@plt", elf_sym__name(&sym, symstrs));
-
- f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- SYMBIND_GLOBAL, sympltname);
- if (!f)
- goto out_elf_end;
-
- if (filter && filter(map, f))
- symbol__delete(f);
- else {
- symbols__insert(&dso->symbols[map->type], f);
- ++nr;
- }
- }
- } else if (shdr_rel_plt.sh_type == SHT_REL) {
- GElf_Rel pos_mem, *pos;
- elf_section__for_each_rel(reldata, pos, pos_mem, idx,
- nr_rel_entries) {
- symidx = GELF_R_SYM(pos->r_info);
- plt_offset += shdr_plt.sh_entsize;
- gelf_getsym(syms, symidx, &sym);
- snprintf(sympltname, sizeof(sympltname),
- "%s@plt", elf_sym__name(&sym, symstrs));
-
- f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- SYMBIND_GLOBAL, sympltname);
- if (!f)
- goto out_elf_end;
-
- if (filter && filter(map, f))
- symbol__delete(f);
- else {
- symbols__insert(&dso->symbols[map->type], f);
- ++nr;
- }
- }
- }
-
- err = 0;
-out_elf_end:
- elf_end(elf);
-out_close:
- close(fd);
-
- if (err == 0)
- return nr;
-out:
- pr_debug("%s: problems reading %s PLT info.\n",
- __func__, dso->long_name);
- return 0;
-}
-
-static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
-{
- switch (type) {
- case MAP__FUNCTION:
- return elf_sym__is_function(sym);
- case MAP__VARIABLE:
- return elf_sym__is_object(sym);
- default:
- return false;
- }
-}
-
-static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
- enum map_type type)
-{
- switch (type) {
- case MAP__FUNCTION:
- return elf_sec__is_text(shdr, secstrs);
- case MAP__VARIABLE:
- return elf_sec__is_data(shdr, secstrs);
- default:
- return false;
- }
-}
-
-static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
-{
- Elf_Scn *sec = NULL;
- GElf_Shdr shdr;
- size_t cnt = 1;
-
- while ((sec = elf_nextscn(elf, sec)) != NULL) {
- gelf_getshdr(sec, &shdr);
-
- if ((addr >= shdr.sh_addr) &&
- (addr < (shdr.sh_addr + shdr.sh_size)))
- return cnt;
-
- ++cnt;
- }
-
- return -1;
-}
-
-static int elf_sym__binding(const GElf_Sym *sym)
-{
- switch (GELF_ST_BIND(sym->st_info)) {
- case STB_GLOBAL:
- return SYMBIND_GLOBAL;
- case STB_WEAK:
- return SYMBIND_WEAK;
- default:
- return SYMBIND_LOCAL;
- }
-}
-
-static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
- int fd, symbol_filter_t filter, int kmodule,
- int want_symtab)
-{
- struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
- struct map *curr_map = map;
- struct dso *curr_dso = dso;
- Elf_Data *symstrs, *secstrs;
- uint32_t nr_syms;
- int err = -1;
- uint32_t idx;
- GElf_Ehdr ehdr;
- GElf_Shdr shdr, opdshdr;
- Elf_Data *syms, *opddata = NULL;
- GElf_Sym sym;
- Elf_Scn *sec, *sec_strndx, *opdsec;
- Elf *elf;
- int nr = 0;
- size_t opdidx = 0;
-
- elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
- if (elf == NULL) {
- pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
- goto out_close;
- }
-
- if (gelf_getehdr(elf, &ehdr) == NULL) {
- pr_debug("%s: cannot get elf header.\n", __func__);
- goto out_elf_end;
- }
-
- /* Always reject images with a mismatched build-id: */
- if (dso->has_build_id) {
- u8 build_id[BUILD_ID_SIZE];
-
- if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
- goto out_elf_end;
-
- if (!dso__build_id_equal(dso, build_id))
- goto out_elf_end;
- }
-
- sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
- if (sec == NULL) {
- if (want_symtab)
- goto out_elf_end;
-
- sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
- if (sec == NULL)
- goto out_elf_end;
- }
-
- opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
- if (opdshdr.sh_type != SHT_PROGBITS)
- opdsec = NULL;
- if (opdsec)
- opddata = elf_rawdata(opdsec, NULL);
-
- syms = elf_getdata(sec, NULL);
- if (syms == NULL)
- goto out_elf_end;
-
- sec = elf_getscn(elf, shdr.sh_link);
- if (sec == NULL)
- goto out_elf_end;
-
- symstrs = elf_getdata(sec, NULL);
- if (symstrs == NULL)
- goto out_elf_end;
-
- sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
- if (sec_strndx == NULL)
- goto out_elf_end;
-
- secstrs = elf_getdata(sec_strndx, NULL);
- if (secstrs == NULL)
- goto out_elf_end;
-
- nr_syms = shdr.sh_size / shdr.sh_entsize;
-
- memset(&sym, 0, sizeof(sym));
- if (dso->kernel == DSO_TYPE_USER) {
- dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
- elf_section_by_name(elf, &ehdr, &shdr,
- ".gnu.prelink_undo",
- NULL) != NULL);
- } else {
- dso->adjust_symbols = 0;
- }
- elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
- struct symbol *f;
- const char *elf_name = elf_sym__name(&sym, symstrs);
- char *demangled = NULL;
- int is_label = elf_sym__is_label(&sym);
- const char *section_name;
-
- if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
- strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
- kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
-
- if (!is_label && !elf_sym__is_a(&sym, map->type))
- continue;
-
- /* Reject ARM ELF "mapping symbols": these aren't unique and
- * don't identify functions, so will confuse the profile
- * output: */
- if (ehdr.e_machine == EM_ARM) {
- if (!strcmp(elf_name, "$a") ||
- !strcmp(elf_name, "$d") ||
- !strcmp(elf_name, "$t"))
- continue;
- }
-
- if (opdsec && sym.st_shndx == opdidx) {
- u32 offset = sym.st_value - opdshdr.sh_addr;
- u64 *opd = opddata->d_buf + offset;
- sym.st_value = *opd;
- sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
- }
-
- sec = elf_getscn(elf, sym.st_shndx);
- if (!sec)
- goto out_elf_end;
-
- gelf_getshdr(sec, &shdr);
-
- if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
- continue;
-
- section_name = elf_sec__name(&shdr, secstrs);
-
- /* On ARM, symbols for thumb functions have 1 added to
- * the symbol address as a flag - remove it */
- if ((ehdr.e_machine == EM_ARM) &&
- (map->type == MAP__FUNCTION) &&
- (sym.st_value & 1))
- --sym.st_value;
-
- if (dso->kernel != DSO_TYPE_USER || kmodule) {
- char dso_name[PATH_MAX];
-
- if (strcmp(section_name,
- (curr_dso->short_name +
- dso->short_name_len)) == 0)
- goto new_symbol;
-
- if (strcmp(section_name, ".text") == 0) {
- curr_map = map;
- curr_dso = dso;
- goto new_symbol;
- }
-
- snprintf(dso_name, sizeof(dso_name),
- "%s%s", dso->short_name, section_name);
-
- curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
- if (curr_map == NULL) {
- u64 start = sym.st_value;
-
- if (kmodule)
- start += map->start + shdr.sh_offset;
-
- curr_dso = dso__new(dso_name);
- if (curr_dso == NULL)
- goto out_elf_end;
- curr_dso->kernel = dso->kernel;
- curr_dso->long_name = dso->long_name;
- curr_dso->long_name_len = dso->long_name_len;
- curr_map = map__new2(start, curr_dso,
- map->type);
- if (curr_map == NULL) {
- dso__delete(curr_dso);
- goto out_elf_end;
- }
- curr_map->map_ip = identity__map_ip;
- curr_map->unmap_ip = identity__map_ip;
- curr_dso->symtab_type = dso->symtab_type;
- map_groups__insert(kmap->kmaps, curr_map);
- dsos__add(&dso->node, curr_dso);
- dso__set_loaded(curr_dso, map->type);
- } else
- curr_dso = curr_map->dso;
-
- goto new_symbol;
- }
-
- if (curr_dso->adjust_symbols) {
- pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
- "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
- (u64)sym.st_value, (u64)shdr.sh_addr,
- (u64)shdr.sh_offset);
- sym.st_value -= shdr.sh_addr - shdr.sh_offset;
- }
- /*
- * We need to figure out if the object was created from C++ sources
- * DWARF DW_compile_unit has this, but we don't always have access
- * to it...
- */
- demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
- if (demangled != NULL)
- elf_name = demangled;
-new_symbol:
- f = symbol__new(sym.st_value, sym.st_size,
- elf_sym__binding(&sym), elf_name);
- free(demangled);
- if (!f)
- goto out_elf_end;
-
- if (filter && filter(curr_map, f))
- symbol__delete(f);
- else {
- symbols__insert(&curr_dso->symbols[curr_map->type], f);
- nr++;
- }
- }
-
- /*
- * For misannotated, zeroed, ASM function sizes.
- */
- if (nr > 0) {
- symbols__fixup_duplicate(&dso->symbols[map->type]);
- symbols__fixup_end(&dso->symbols[map->type]);
- if (kmap) {
- /*
- * We need to fixup this here too because we create new
- * maps here, for things like vsyscall sections.
- */
- __map_groups__fixup_end(kmap->kmaps, map->type);
- }
- }
- err = nr;
-out_elf_end:
- elf_end(elf);
-out_close:
- return err;
-}
-
-void symbol__elf_init(void)
-{
- elf_version(EV_CURRENT);
-}
-
-static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
+bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
{
return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
}
@@ -1439,145 +890,6 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
return have_build_id;
}

-/*
- * Align offset to 4 bytes as needed for note name and descriptor data.
- */
-#define NOTE_ALIGN(n) (((n) + 3) & -4U)
-
-static int elf_read_build_id(Elf *elf, void *bf, size_t size)
-{
- int err = -1;
- GElf_Ehdr ehdr;
- GElf_Shdr shdr;
- Elf_Data *data;
- Elf_Scn *sec;
- Elf_Kind ek;
- void *ptr;
-
- if (size < BUILD_ID_SIZE)
- goto out;
-
- ek = elf_kind(elf);
- if (ek != ELF_K_ELF)
- goto out;
-
- if (gelf_getehdr(elf, &ehdr) == NULL) {
- pr_err("%s: cannot get elf header.\n", __func__);
- goto out;
- }
-
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".note.gnu.build-id", NULL);
- if (sec == NULL) {
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".notes", NULL);
- if (sec == NULL)
- goto out;
- }
-
- data = elf_getdata(sec, NULL);
- if (data == NULL)
- goto out;
-
- ptr = data->d_buf;
- while (ptr < (data->d_buf + data->d_size)) {
- GElf_Nhdr *nhdr = ptr;
- size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
- descsz = NOTE_ALIGN(nhdr->n_descsz);
- const char *name;
-
- ptr += sizeof(*nhdr);
- name = ptr;
- ptr += namesz;
- if (nhdr->n_type == NT_GNU_BUILD_ID &&
- nhdr->n_namesz == sizeof("GNU")) {
- if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
- size_t sz = min(size, descsz);
- memcpy(bf, ptr, sz);
- memset(bf + sz, 0, size - sz);
- err = descsz;
- break;
- }
- }
- ptr += descsz;
- }
-
-out:
- return err;
-}
-
-int filename__read_build_id(const char *filename, void *bf, size_t size)
-{
- int fd, err = -1;
- Elf *elf;
-
- if (size < BUILD_ID_SIZE)
- goto out;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- goto out;
-
- elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
- if (elf == NULL) {
- pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
- goto out_close;
- }
-
- err = elf_read_build_id(elf, bf, size);
-
- elf_end(elf);
-out_close:
- close(fd);
-out:
- return err;
-}
-
-int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
-{
- int fd, err = -1;
-
- if (size < BUILD_ID_SIZE)
- goto out;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- goto out;
-
- while (1) {
- char bf[BUFSIZ];
- GElf_Nhdr nhdr;
- size_t namesz, descsz;
-
- if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
- break;
-
- namesz = NOTE_ALIGN(nhdr.n_namesz);
- descsz = NOTE_ALIGN(nhdr.n_descsz);
- if (nhdr.n_type == NT_GNU_BUILD_ID &&
- nhdr.n_namesz == sizeof("GNU")) {
- if (read(fd, bf, namesz) != (ssize_t)namesz)
- break;
- if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
- size_t sz = min(descsz, size);
- if (read(fd, build_id, sz) == (ssize_t)sz) {
- memset(build_id + sz, 0, size - sz);
- err = 0;
- break;
- }
- } else if (read(fd, bf, descsz) != (ssize_t)descsz)
- break;
- } else {
- int n = namesz + descsz;
- if (read(fd, bf, n) != n)
- break;
- }
- }
- close(fd);
-out:
- return err;
-}
-
char dso__symtab_origin(const struct dso *dso)
{
static const char origin[] = {
@@ -1889,7 +1201,7 @@ static int machine__set_modules_path(struct machine *machine)
* they are loaded) and for vmlinux, where only after we load all the
* symbols we'll know where it starts and ends.
*/
-static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
+struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
{
struct map *map = calloc(1, (sizeof(*map) +
(dso->kernel ? sizeof(struct kmap) : 0)));
@@ -2206,7 +1518,7 @@ out_try_fixup:
return err;
}

-static void dsos__add(struct list_head *head, struct dso *dso)
+void dsos__add(struct list_head *head, struct dso *dso)
{
list_add_tail(&dso->node, head);
}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ea81399fa768..15c6738041fd 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -203,6 +203,7 @@ void dso__sort_by_name(struct dso *dso, enum map_type type);

struct dso *__dsos__findnew(struct list_head *head, const char *name);

+void dsos__add(struct list_head *head, struct dso *dso);
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
int dso__load_vmlinux(struct dso *dso, struct map *map,
const char *vmlinux, symbol_filter_t filter);
@@ -254,11 +255,14 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
int filename__read_build_id(const char *filename, void *bf, size_t size);
int sysfs__read_build_id(const char *filename, void *bf, size_t size);
bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
+bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
int build_id__sprintf(const u8 *build_id, int len, char *bf);
int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start, u64 end));

+struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
+
void machine__destroy_kernel_maps(struct machine *machine);
int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
int machine__create_kernel_maps(struct machine *machine);
@@ -270,6 +274,8 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);
int symbol__init(void);
void symbol__exit(void);
void symbol__elf_init(void);
+struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
+void symbols__insert(struct rb_root *symbols, struct symbol *sym);
size_t symbol__fprintf_symname_offs(const struct symbol *sym,
const struct addr_location *al, FILE *fp);
size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
@@ -277,4 +283,13 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);

size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);

+void symbols__fixup_duplicate(struct rb_root *symbols);
+void symbols__fixup_end(struct rb_root *symbols);
+void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
+
+int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
+ symbol_filter_t filter);
+int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
+ symbol_filter_t filter, int kmodule, int want_symtab);
+
#endif /* __PERF_SYMBOL */
--
1.7.10.1

2012-05-14 07:13:17

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 2/5] perf symbols: Do not use ELF's symbol binding constants

There's no need to use the ELF's internal value directly.
Define and use our own - it's required to eliminated the
dependency of libelf.

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-top.c | 5 ++---
tools/perf/ui/browsers/map.c | 5 ++---
tools/perf/util/symbol.c | 40 ++++++++++++++++++++++++++--------------
tools/perf/util/symbol.h | 4 ++++
4 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8ef59f8262bb..89be1334e7e0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -42,7 +42,6 @@
#include "util/debug.h"

#include <assert.h>
-#include <elf.h>
#include <fcntl.h>

#include <stdio.h>
@@ -181,8 +180,8 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
"Please report to [email protected]\n",
ip, map->dso->long_name, dso__symtab_origin(map->dso),
map->start, map->end, sym->start, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w', sym->name,
+ sym->binding == SYMBIND_GLOBAL ? 'g' :
+ sym->binding == SYMBIND_LOCAL ? 'l' : 'w', sym->name,
err ? "[unknown]" : uts.machine,
err ? "[unknown]" : uts.release, perf_version_string);
if (use_browser <= 0)
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 98851d55a53e..f2059664b23f 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -1,5 +1,4 @@
#include "../libslang.h"
-#include <elf.h>
#include <newt.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
@@ -61,8 +60,8 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
ui_browser__set_percent_color(self, 0, current_entry);
slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
mb->addrlen, sym->start, mb->addrlen, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w');
+ sym->binding == SYMBIND_GLOBAL ? 'g' :
+ sym->binding == SYMBIND_LOCAL ? 'l' : 'w');
width = self->width - ((mb->addrlen * 2) + 4);
if (width > 0)
slsmg_write_nstring(sym->name, width);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index fe37d84e2107..d4518a14edd8 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -114,16 +114,16 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
return SYMBOL_B;

/* Prefer a non weak symbol over a weak one */
- a = syma->binding == STB_WEAK;
- b = symb->binding == STB_WEAK;
+ a = syma->binding == SYMBIND_WEAK;
+ b = symb->binding == SYMBIND_WEAK;
if (b && !a)
return SYMBOL_A;
if (a && !b)
return SYMBOL_B;

/* Prefer a global symbol over a non global one */
- a = syma->binding == STB_GLOBAL;
- b = symb->binding == STB_GLOBAL;
+ a = syma->binding == SYMBIND_GLOBAL;
+ b = symb->binding == SYMBIND_GLOBAL;
if (a && !b)
return SYMBOL_A;
if (b && !a)
@@ -259,8 +259,8 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
{
return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
sym->start, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w',
+ sym->binding == SYMBIND_GLOBAL ? 'g' :
+ sym->binding == SYMBIND_LOCAL ? 'l' : 'w',
sym->name);
}

@@ -608,12 +608,12 @@ struct process_kallsyms_args {
struct dso *dso;
};

-static u8 kallsyms2elf_type(char type)
+static u8 kallsyms_binding(char type)
{
if (type == 'W')
- return STB_WEAK;
+ return SYMBIND_WEAK;

- return isupper(type) ? STB_GLOBAL : STB_LOCAL;
+ return isupper(type) ? SYMBIND_GLOBAL : SYMBIND_LOCAL;
}

static int map__process_kallsym_symbol(void *arg, const char *name,
@@ -627,7 +627,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
return 0;

sym = symbol__new(start, end - start + 1,
- kallsyms2elf_type(type), name);
+ kallsyms_binding(type), name);
if (sym == NULL)
return -ENOMEM;
/*
@@ -850,7 +850,7 @@ static int dso__load_perf_map(struct dso *dso, struct map *map,
if (len + 2 >= line_len)
continue;

- sym = symbol__new(start, size, STB_GLOBAL, line + len);
+ sym = symbol__new(start, size, SYMBIND_GLOBAL, line + len);

if (sym == NULL)
goto out_delete_line;
@@ -1065,7 +1065,7 @@ static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
"%s@plt", elf_sym__name(&sym, symstrs));

f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- STB_GLOBAL, sympltname);
+ SYMBIND_GLOBAL, sympltname);
if (!f)
goto out_elf_end;

@@ -1087,7 +1087,7 @@ static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
"%s@plt", elf_sym__name(&sym, symstrs));

f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- STB_GLOBAL, sympltname);
+ SYMBIND_GLOBAL, sympltname);
if (!f)
goto out_elf_end;

@@ -1158,6 +1158,18 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
return -1;
}

+static int elf_sym__binding(const GElf_Sym *sym)
+{
+ switch (GELF_ST_BIND(sym->st_info)) {
+ case STB_GLOBAL:
+ return SYMBIND_GLOBAL;
+ case STB_WEAK:
+ return SYMBIND_WEAK;
+ default:
+ return SYMBIND_LOCAL;
+ }
+}
+
static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
int fd, symbol_filter_t filter, int kmodule,
int want_symtab)
@@ -1361,7 +1373,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
elf_name = demangled;
new_symbol:
f = symbol__new(sym.st_value, sym.st_size,
- GELF_ST_BIND(sym.st_info), elf_name);
+ elf_sym__binding(&sym), elf_name);
free(demangled);
if (!f)
goto out_elf_end;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 27e882f5ad8a..ea81399fa768 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -49,6 +49,10 @@ char *strxfrchar(char *s, char from, char to);

#define BUILD_ID_SIZE 20

+#define SYMBIND_LOCAL 0
+#define SYMBIND_GLOBAL 1
+#define SYMBIND_WEAK 2
+
/** struct symbol - symtab entry
*
* @ignore - resolvable but tools ignore it (e.g. idle routines)
--
1.7.10.1

2012-05-14 09:22:14

by Ingo Molnar

[permalink] [raw]
Subject: Re: [RFC 0/5] perf tools: Minimalistic build without libelf dependency


* Namhyung Kim <[email protected]> wrote:

> Hi,
>
> NOTE: This is a RFC patchset and it contains a lot of rough edges
> and ugly codes.
>
> Current build procedure of perf tools requires a couple of external
> libraries. Although most of them are optional, elfutils' libelf is
> mandatory for resolving symbols and build-id of the binaries being
> profiled. For some reason, it makes embedded guys' life harder who
> want to build and run perf tools on their boards.

Yeah, and this is a very useful patchset from that perspective.

> This patch set tries to fix the problem by letting the perf could
> be built without libelf. The initial intent was just providing
> perf record command to gather performance events interested on the
> system and copies the data to development box to be used by perf
> report for analysis.
>
> However it's changed to have most of perf commands as is because
> perf can resolve kernel symbols without libelf and many of perf
> commands deal (mostly) with kernel events - so no need to restrict
> capability of perf tools. Therefore, the end result is not so
> minimalistic in fact and only thing it cannot do is "perf probe".
>
> And then I realized that the perf record needs to know about the
> build-id's anyway :(. So I implemented a poor man's version of elf
> parser only for parsing the build-id info.
>
> To build a minimal perf tools, pass MINIMAL=1 to make. The perf
> report will not display symbol names:

Could we make this automatic when the required elf libraries are
not present?

Thanks,

Ingo

2012-05-15 00:42:07

by Namhyung Kim

[permalink] [raw]
Subject: Re: [RFC 0/5] perf tools: Minimalistic build without libelf dependency

Hi,

On Mon, 14 May 2012 11:22:07 +0200, Ingo Molnar wrote:
> * Namhyung Kim <[email protected]> wrote:
>
>> Hi,
>>
>> NOTE: This is a RFC patchset and it contains a lot of rough edges
>> and ugly codes.
>>
>> Current build procedure of perf tools requires a couple of external
>> libraries. Although most of them are optional, elfutils' libelf is
>> mandatory for resolving symbols and build-id of the binaries being
>> profiled. For some reason, it makes embedded guys' life harder who
>> want to build and run perf tools on their boards.
>
> Yeah, and this is a very useful patchset from that perspective.
>

Glad to hear that :).


>> This patch set tries to fix the problem by letting the perf could
>> be built without libelf. The initial intent was just providing
>> perf record command to gather performance events interested on the
>> system and copies the data to development box to be used by perf
>> report for analysis.
>>
>> However it's changed to have most of perf commands as is because
>> perf can resolve kernel symbols without libelf and many of perf
>> commands deal (mostly) with kernel events - so no need to restrict
>> capability of perf tools. Therefore, the end result is not so
>> minimalistic in fact and only thing it cannot do is "perf probe".
>>
>> And then I realized that the perf record needs to know about the
>> build-id's anyway :(. So I implemented a poor man's version of elf
>> parser only for parsing the build-id info.
>>
>> To build a minimal perf tools, pass MINIMAL=1 to make. The perf
>> report will not display symbol names:
>
> Could we make this automatic when the required elf libraries are
> not present?
>

Yes, I think it's doable.

Thanks,
Namhyung

2012-05-21 06:03:09

by Namhyung Kim

[permalink] [raw]
Subject: Re: [RFC 0/5] perf tools: Minimalistic build without libelf dependency

Hi, all

Any other comments for this?


Thanks,
Namhyung


On Mon, 14 May 2012 16:10:19 +0900, Namhyung Kim wrote:
> NOTE: This is a RFC patchset and it contains a lot of rough edges
> and ugly codes.
>
> Current build procedure of perf tools requires a couple of external
> libraries. Although most of them are optional, elfutils' libelf is
> mandatory for resolving symbols and build-id of the binaries being
> profiled. For some reason, it makes embedded guys' life harder who
> want to build and run perf tools on their boards.
>
> This patch set tries to fix the problem by letting the perf could
> be built without libelf. The initial intent was just providing
> perf record command to gather performance events interested on the
> system and copies the data to development box to be used by perf
> report for analysis.
>
> However it's changed to have most of perf commands as is because
> perf can resolve kernel symbols without libelf and many of perf
> commands deal (mostly) with kernel events - so no need to restrict
> capability of perf tools. Therefore, the end result is not so
> minimalistic in fact and only thing it cannot do is "perf probe".
>
> And then I realized that the perf record needs to know about the
> build-id's anyway :(. So I implemented a poor man's version of elf
> parser only for parsing the build-id info.
>
> To build a minimal perf tools, pass MINIMAL=1 to make. The perf
> report will not display symbol names:
>
> # Samples: 988 of event 'cycles'
> # Event count (approx.): 3726465542
> #
> # Overhead Command Shared Object Symbol
> # ........ ....... ................. .........................
> #
> 98.40% noploop noploop [.] 0x000000000000066d
> 1.35% noploop ld-2.15.so [.] 0x000000000000bab1
> 0.10% noploop [kernel.kallsyms] [k] native_write_msr_safe
> 0.10% noploop [kernel.kallsyms] [k] scheduler_tick
> 0.03% noploop [kernel.kallsyms] [k] bad_range
> 0.01% noploop [kernel.kallsyms] [k] pipe_read
>
> But perf buildid-list can show you the build-id's:
>
> $ ./perf buildid-list
> ebfc1bdb98999c64d36ddfe394c58df3de6cbcfb [kernel.kallsyms]
> 52f0c5f25b95075e6fd7682763f7c3a779a4e889 /usr/lib64/ld-2.15.so
> 43a7a2b399b6ee2ff29c6bdadbda6bff88712ed4 /home/namhyung/bin/noploop
>
> So it can be packed using perf archive so copied and analized
> with full-fledged perf tools on a development machine.
>
> This patchset is based on commit cb04ff9ac424 ("sched, perf: Use
> a single callback into the scheduler") and tested on x86_64 and arm.
>
> Any comments are welcome, thanks.
> Namhyung
>
>
> Namhyung Kim (5):
> perf symbols: Introduce symbol__elf_init()
> perf symbols: Do not use ELF's symbol binding constants
> perf tools: Split out util/symbol-elf.c
> perf tools: Support minimal build
> perf symbols: Implement poor man's ELF parser
>
> tools/perf/Makefile | 29 ++
> tools/perf/builtin-buildid-list.c | 4 +-
> tools/perf/builtin-top.c | 5 +-
> tools/perf/command-list.txt | 2 +-
> tools/perf/perf.c | 2 +
> tools/perf/ui/browsers/map.c | 5 +-
> tools/perf/util/elf-minimal.h | 153 ++++++++
> tools/perf/util/generate-cmdlist.sh | 15 +
> tools/perf/util/symbol-elf.c | 691 +++++++++++++++++++++++++++++++++
> tools/perf/util/symbol-minimal.c | 258 +++++++++++++
> tools/perf/util/symbol.c | 712 ++---------------------------------
> tools/perf/util/symbol.h | 20 +
> 12 files changed, 1195 insertions(+), 701 deletions(-)
> create mode 100644 tools/perf/util/elf-minimal.h
> create mode 100644 tools/perf/util/symbol-elf.c
> create mode 100644 tools/perf/util/symbol-minimal.c

2012-05-21 11:46:00

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 3/5] perf tools: Split out util/symbol-elf.c

hi,
this one needs rebase to current code, I got some conflicts

On Mon, May 14, 2012 at 04:10:22PM +0900, Namhyung Kim wrote:
> Factor out the dependency of ELF handling into separate
> symbol-elf.c file. It is a preparation of building a
> minimalistic version perf tools which doesn't depend on
> the elfutils.
>
> Signed-off-by: Namhyung Kim <[email protected]>
> ---
> tools/perf/Makefile | 1 +
> tools/perf/util/symbol-elf.c | 691 +++++++++++++++++++++++++++++++++++++++++
> tools/perf/util/symbol.c | 704 +-----------------------------------------
> tools/perf/util/symbol.h | 15 +
> 4 files changed, 715 insertions(+), 696 deletions(-)
> create mode 100644 tools/perf/util/symbol-elf.c
>
> diff --git a/tools/perf/Makefile b/tools/perf/Makefile
> index e98e14c88532..7198c6cbc006 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -334,6 +334,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
> LIB_OBJS += $(OUTPUT)util/wrapper.o
> LIB_OBJS += $(OUTPUT)util/sigchain.o
> LIB_OBJS += $(OUTPUT)util/symbol.o
> +LIB_OBJS += $(OUTPUT)util/symbol-elf.o

I think I'd like more generic elf interface compiled with either libelf
or our stuff.. also separated from "other perf related" symbol handling

looks like we need to be able to parse out build ID and symbols from
symtab or dyntab:

perf_elf__get_buildid(file, buf, len)

perf_elf__get_symbols(file, ..., callback, )
- calling callback func for each symbol found,
the call would then do the perf symbol related stuff

I understand that means much more changes.. so probably what you have now
is a good start and we can do that later.. just with above goal in mind

thanks,
jirka

2012-05-21 11:47:52

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 5/5] perf symbols: Implement poor man's ELF parser

On Mon, May 14, 2012 at 04:10:24PM +0900, Namhyung Kim wrote:
> Implement minimalistic elf parser for getting build-id.
> A couple of structs needed are copied from elf.h and
> the parser only looks for PT_NOTE program header to
> check build-id.
> ---
> tools/perf/util/elf-minimal.h | 153 ++++++++++++++++++++++++
> tools/perf/util/symbol-minimal.c | 244 ++++++++++++++++++++++++++++++++++++--
> 2 files changed, 388 insertions(+), 9 deletions(-)
> create mode 100644 tools/perf/util/elf-minimal.h
>
> diff --git a/tools/perf/util/elf-minimal.h b/tools/perf/util/elf-minimal.h
> new file mode 100644
> index 000000000000..26540b5718a1
> --- /dev/null
> +++ b/tools/perf/util/elf-minimal.h
> @@ -0,0 +1,153 @@
> +/*
> + * Minimal ELF definitions for parsing build-id.
> + */
> +/* This file defines standard ELF types, structures, and macros.
> + Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011
> + Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, write to the Free
> + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> + 02111-1307 USA. */

I can see all this exported in:

[jolsa@dhcp-26-214 perf]$ rpm -qf /usr/include/elf.h
glibc-headers-2.14.90-24.fc16.6.x86_64

so maybe we dont need to add our own, since glic-headers
seems crutial anyway ;)

jirka

> +
> +#ifndef _ELF_MINIMAL_H
> +#define _ELF_MINIMAL_H 1
> +
> +/* Standard ELF types. */
> +
> +#include <stdint.h>
> +
> +/* Type for a 16-bit quantity. */
> +typedef uint16_t Elf32_Half;
> +typedef uint16_t Elf64_Half;
> +
> +/* Types for signed and unsigned 32-bit quantities. */
> +typedef uint32_t Elf32_Word;
> +typedef int32_t Elf32_Sword;
> +typedef uint32_t Elf64_Word;
> +typedef int32_t Elf64_Sword;
> +
> +/* Types for signed and unsigned 64-bit quantities. */
> +typedef uint64_t Elf32_Xword;
> +typedef int64_t Elf32_Sxword;
> +typedef uint64_t Elf64_Xword;
> +typedef int64_t Elf64_Sxword;
> +
> +/* Type of addresses. */
> +typedef uint32_t Elf32_Addr;
> +typedef uint64_t Elf64_Addr;
> +
> +/* Type of file offsets. */
> +typedef uint32_t Elf32_Off;
> +typedef uint64_t Elf64_Off;
> +
> +
> +/* The ELF file header. This appears at the start of every ELF file. */
> +
> +#define EI_NIDENT (16)
> +
> +typedef struct
> +{
> + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
> + Elf32_Half e_type; /* Object file type */
> + Elf32_Half e_machine; /* Architecture */
> + Elf32_Word e_version; /* Object file version */
> + Elf32_Addr e_entry; /* Entry point virtual address */
> + Elf32_Off e_phoff; /* Program header table file offset */
> + Elf32_Off e_shoff; /* Section header table file offset */
> + Elf32_Word e_flags; /* Processor-specific flags */
> + Elf32_Half e_ehsize; /* ELF header size in bytes */
> + Elf32_Half e_phentsize; /* Program header table entry size */
> + Elf32_Half e_phnum; /* Program header table entry count */
> + Elf32_Half e_shentsize; /* Section header table entry size */
> + Elf32_Half e_shnum; /* Section header table entry count */
> + Elf32_Half e_shstrndx; /* Section header string table index */
> +} Elf32_Ehdr;
> +
> +typedef struct
> +{
> + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
> + Elf64_Half e_type; /* Object file type */
> + Elf64_Half e_machine; /* Architecture */
> + Elf64_Word e_version; /* Object file version */
> + Elf64_Addr e_entry; /* Entry point virtual address */
> + Elf64_Off e_phoff; /* Program header table file offset */
> + Elf64_Off e_shoff; /* Section header table file offset */
> + Elf64_Word e_flags; /* Processor-specific flags */
> + Elf64_Half e_ehsize; /* ELF header size in bytes */
> + Elf64_Half e_phentsize; /* Program header table entry size */
> + Elf64_Half e_phnum; /* Program header table entry count */
> + Elf64_Half e_shentsize; /* Section header table entry size */
> + Elf64_Half e_shnum; /* Section header table entry count */
> + Elf64_Half e_shstrndx; /* Section header string table index */
> +} Elf64_Ehdr;
> +
> +/* Conglomeration of the identification bytes, for easy testing as a word. */
> +#define ELFMAG "\177ELF"
> +#define SELFMAG 4
> +
> +#define EI_CLASS 4 /* File class byte index */
> +#define ELFCLASSNONE 0 /* Invalid class */
> +#define ELFCLASS32 1 /* 32-bit objects */
> +#define ELFCLASS64 2 /* 64-bit objects */
> +#define ELFCLASSNUM 3
> +
> +#define EI_DATA 5 /* Data encoding byte index */
> +#define ELFDATANONE 0 /* Invalid data encoding */
> +#define ELFDATA2LSB 1 /* 2's complement, little endian */
> +#define ELFDATA2MSB 2 /* 2's complement, big endian */
> +#define ELFDATANUM 3
> +
> +#define EI_VERSION 6 /* File version byte index */
> + /* Value must be EV_CURRENT */
> +
> +/* Legal values for e_version (version). */
> +
> +#define EV_NONE 0 /* Invalid ELF version */
> +#define EV_CURRENT 1 /* Current version */
> +#define EV_NUM 2
> +
> +#define EI_PAD 9 /* Byte index of padding bytes */
> +
> +/* Program segment header. */
> +
> +typedef struct
> +{
> + Elf32_Word p_type; /* Segment type */
> + Elf32_Off p_offset; /* Segment file offset */
> + Elf32_Addr p_vaddr; /* Segment virtual address */
> + Elf32_Addr p_paddr; /* Segment physical address */
> + Elf32_Word p_filesz; /* Segment size in file */
> + Elf32_Word p_memsz; /* Segment size in memory */
> + Elf32_Word p_flags; /* Segment flags */
> + Elf32_Word p_align; /* Segment alignment */
> +} Elf32_Phdr;
> +
> +typedef struct
> +{
> + Elf64_Word p_type; /* Segment type */
> + Elf64_Word p_flags; /* Segment flags */
> + Elf64_Off p_offset; /* Segment file offset */
> + Elf64_Addr p_vaddr; /* Segment virtual address */
> + Elf64_Addr p_paddr; /* Segment physical address */
> + Elf64_Xword p_filesz; /* Segment size in file */
> + Elf64_Xword p_memsz; /* Segment size in memory */
> + Elf64_Xword p_align; /* Segment alignment */
> +} Elf64_Phdr;
> +
> +/* Legal values for p_type (segment type). */
> +
> +#define PT_NOTE 4 /* Auxiliary information */
> +
> +#endif /* _ELF_MINIMAL_H */
> diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
> index 2917ede1d5ba..dfef571abc9b 100644
> --- a/tools/perf/util/symbol-minimal.c
> +++ b/tools/perf/util/symbol-minimal.c
> @@ -1,29 +1,255 @@
> #include "symbol.h"
> +#include "elf-minimal.h"
>
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <byteswap.h>
> +#include <sys/stat.h>
>
> -int filename__read_build_id(const char *filename __used, void *bf __used,
> - size_t size __used)
> +static bool check_need_swap(int file_endian)
> {
> - return -1;
> + const int data = 1;
> + u8 *check = (u8 *)&data;
> + int host_endian;
> +
> + if (check[0] == 1)
> + host_endian = ELFDATA2LSB;
> + else
> + host_endian = ELFDATA2MSB;
> +
> + return host_endian != file_endian;
> }
>
> -int sysfs__read_build_id(const char *filename __used, void *build_id __used,
> - size_t size __used)
> +#define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
> +
> +#define NT_GNU_BUILD_ID 3
> +
> +static int read_build_id(void *note_data, size_t note_len, void *bf,
> + size_t size, bool need_swap)
> {
> + struct {
> + u32 n_namesz;
> + u32 n_descsz;
> + u32 n_type;
> + } *nhdr;
> + void *ptr;
> +
> + ptr = note_data;
> + while (ptr < (note_data + note_len)) {
> + const char *name;
> + size_t namesz, descsz;
> +
> + nhdr = ptr;
> + if (need_swap) {
> + nhdr->n_namesz = bswap_32(nhdr->n_namesz);
> + nhdr->n_descsz = bswap_32(nhdr->n_descsz);
> + nhdr->n_type = bswap_32(nhdr->n_type);
> + }
> +
> + namesz = NOTE_ALIGN(nhdr->n_namesz);
> + descsz = NOTE_ALIGN(nhdr->n_descsz);
> +
> + ptr += sizeof(*nhdr);
> + name = ptr;
> + ptr += namesz;
> + if (nhdr->n_type == NT_GNU_BUILD_ID &&
> + nhdr->n_namesz == sizeof("GNU")) {
> + if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
> + size_t sz = min(size, descsz);
> + memcpy(bf, ptr, sz);
> + memset(bf + sz, 0, size - sz);
> + return 0;
> + }
> + }
> + ptr += descsz;
> + }
> +
> return -1;
> }
>
> +/*
> + * Just try PT_NOTE header otherwise fails
> + */
> +int filename__read_build_id(const char *filename, void *bf, size_t size)
> +{
> + FILE *fp;
> + int ret = -1;
> + bool need_swap = false;
> + u8 e_ident[EI_NIDENT];
> + size_t buf_size;
> + void *buf;
> + int i;
> +
> + fp = fopen(filename, "r");
> + if (fp == NULL)
> + return -1;
> +
> + if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
> + goto out;
> +
> + if (memcmp(e_ident, ELFMAG, SELFMAG) ||
> + e_ident[EI_VERSION] != EV_CURRENT)
> + goto out;
> +
> + need_swap = check_need_swap(e_ident[EI_DATA]);
> +
> + /* for simplicity */
> + fseek(fp, 0, SEEK_SET);
> +
> + if (e_ident[EI_CLASS] == ELFCLASS32) {
> + Elf32_Ehdr ehdr;
> + Elf32_Phdr *phdr;
> +
> + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
> + goto out;
> +
> + if (need_swap) {
> + ehdr.e_phoff = bswap_32(ehdr.e_phoff);
> + ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
> + ehdr.e_phnum = bswap_16(ehdr.e_phnum);
> + }
> +
> + buf_size = ehdr.e_phentsize * ehdr.e_phnum;
> + buf = malloc(buf_size);
> + if (buf == NULL)
> + goto out;
> +
> + fseek(fp, ehdr.e_phoff, SEEK_SET);
> + if (fread(buf, buf_size, 1, fp) != 1)
> + goto out_free;
> +
> + for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
> + void *tmp;
> +
> + if (need_swap) {
> + phdr->p_type = bswap_32(phdr->p_type);
> + phdr->p_offset = bswap_32(phdr->p_offset);
> + phdr->p_filesz = bswap_32(phdr->p_filesz);
> + }
> +
> + if (phdr->p_type != PT_NOTE)
> + continue;
> +
> + buf_size = phdr->p_filesz;
> + tmp = realloc(buf, buf_size);
> + if (tmp == NULL)
> + goto out_free;
> +
> + buf = tmp;
> + fseek(fp, phdr->p_offset, SEEK_SET);
> + if (fread(buf, buf_size, 1, fp) != 1)
> + goto out_free;
> +
> + ret = read_build_id(buf, buf_size, bf, size, need_swap);
> + if (ret == 0)
> + ret = size;
> + break;
> + }
> + } else {
> + Elf64_Ehdr ehdr;
> + Elf64_Phdr *phdr;
> +
> + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
> + goto out;
> +
> + if (need_swap) {
> + ehdr.e_phoff = bswap_64(ehdr.e_phoff);
> + ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
> + ehdr.e_phnum = bswap_16(ehdr.e_phnum);
> + }
> +
> + buf_size = ehdr.e_phentsize * ehdr.e_phnum;
> + buf = malloc(buf_size);
> + if (buf == NULL)
> + goto out;
> +
> + fseek(fp, ehdr.e_phoff, SEEK_SET);
> + if (fread(buf, buf_size, 1, fp) != 1)
> + goto out_free;
> +
> + for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
> + void *tmp;
> +
> + if (need_swap) {
> + phdr->p_type = bswap_32(phdr->p_type);
> + phdr->p_offset = bswap_64(phdr->p_offset);
> + phdr->p_filesz = bswap_64(phdr->p_filesz);
> + }
> +
> + if (phdr->p_type != PT_NOTE)
> + continue;
> +
> + buf_size = phdr->p_filesz;
> + tmp = realloc(buf, buf_size);
> + if (tmp == NULL)
> + goto out_free;
> +
> + buf = tmp;
> + fseek(fp, phdr->p_offset, SEEK_SET);
> + if (fread(buf, buf_size, 1, fp) != 1)
> + goto out_free;
> +
> + ret = read_build_id(buf, buf_size, bf, size, need_swap);
> + if (ret == 0)
> + ret = size;
> + break;
> + }
> + }
> +out_free:
> + free(buf);
> +out:
> + fclose(fp);
> + return ret;
> +}
> +
> +int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
> +{
> + int fd;
> + int ret = -1;
> + struct stat stbuf;
> + size_t buf_size;
> + void *buf;
> +
> + fd = open(filename, O_RDONLY);
> + if (fd < 0)
> + return -1;
> +
> + if (fstat(fd, &stbuf) < 0)
> + goto out;
> +
> + buf_size = stbuf.st_size;
> + buf = malloc(buf_size);
> + if (buf == NULL)
> + goto out;
> +
> + if (read(fd, buf, buf_size) != (ssize_t) buf_size)
> + goto out_free;
> +
> + ret = read_build_id(buf, buf_size, build_id, size, false);
> +out_free:
> + free(buf);
> +out:
> + close(fd);
> + return ret;
> +}
> +
> int dso__synthesize_plt_symbols(struct dso *dso __used, struct map *map __used,
> symbol_filter_t filter __used)
> {
> return 0;
> }
>
> -int dso__load_sym(struct dso *dso __used, struct map *map __used,
> - const char *name __used, int fd __used,
> - symbol_filter_t filter __used, int kmodule __used,
> - int want_symtab __used)
> +int dso__load_sym(struct dso *dso, struct map *map __used, const char *name,
> + int fd __used, symbol_filter_t filter __used,
> + int kmodule __used, int want_symtab __used)
> {
> + unsigned char *build_id[BUILD_ID_SIZE];
> +
> + if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) {
> + dso__set_build_id(dso, build_id);
> + return 1;
> + }
> return 0;
> }
>
> --
> 1.7.10.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2012-05-21 15:03:25

by David Ahern

[permalink] [raw]
Subject: Re: [RFC 0/5] perf tools: Minimalistic build without libelf dependency

On 5/21/12 12:00 AM, Namhyung Kim wrote:
> Hi, all
>
> Any other comments for this?

One idea that has been proposed is to make perf configurable - to pick
and choose which pieces you want built-in. For example for target
systems only compile in record command. It seems like that part should
be done first and would potentially handle a lot of these changes.

David

2012-05-22 00:22:51

by Namhyung Kim

[permalink] [raw]
Subject: Re: [RFC 0/5] perf tools: Minimalistic build without libelf dependency

Hi, David

On Mon, 21 May 2012 09:03:19 -0600, David Ahern wrote:
> One idea that has been proposed is to make perf configurable - to pick
> and choose which pieces you want built-in. For example for target
> systems only compile in record command. It seems like that part should
> be done first and would potentially handle a lot of these changes.
>

Yeah, I remember Arnaldo said about the menuconfig-like configuration
interface. But I'd like to finish this minimal build patchset first
since the configuration change can require much work on where I'm not
familiar with and I doubt the users care about it much.

Anyway, thanks for the comment.
Namhyung

2012-05-22 01:02:52

by Namhyung Kim

[permalink] [raw]
Subject: Re: [PATCH 3/5] perf tools: Split out util/symbol-elf.c

Hi, Jiri

On Mon, 21 May 2012 13:45:31 +0200, Jiri Olsa wrote:
> hi,
> this one needs rebase to current code, I got some conflicts
>

Will do.


> On Mon, May 14, 2012 at 04:10:22PM +0900, Namhyung Kim wrote:
>> Factor out the dependency of ELF handling into separate
>> symbol-elf.c file. It is a preparation of building a
>> minimalistic version perf tools which doesn't depend on
>> the elfutils.
>>
>> Signed-off-by: Namhyung Kim <[email protected]>
>> ---
>> tools/perf/Makefile | 1 +
>> tools/perf/util/symbol-elf.c | 691 +++++++++++++++++++++++++++++++++++++++++
>> tools/perf/util/symbol.c | 704 +-----------------------------------------
>> tools/perf/util/symbol.h | 15 +
>> 4 files changed, 715 insertions(+), 696 deletions(-)
>> create mode 100644 tools/perf/util/symbol-elf.c
>>
>> diff --git a/tools/perf/Makefile b/tools/perf/Makefile
>> index e98e14c88532..7198c6cbc006 100644
>> --- a/tools/perf/Makefile
>> +++ b/tools/perf/Makefile
>> @@ -334,6 +334,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
>> LIB_OBJS += $(OUTPUT)util/wrapper.o
>> LIB_OBJS += $(OUTPUT)util/sigchain.o
>> LIB_OBJS += $(OUTPUT)util/symbol.o
>> +LIB_OBJS += $(OUTPUT)util/symbol-elf.o
>
> I think I'd like more generic elf interface compiled with either libelf
> or our stuff.. also separated from "other perf related" symbol handling
>
> looks like we need to be able to parse out build ID and symbols from
> symtab or dyntab:
>
> perf_elf__get_buildid(file, buf, len)
>
> perf_elf__get_symbols(file, ..., callback, )
> - calling callback func for each symbol found,
> the call would then do the perf symbol related stuff
>
> I understand that means much more changes.. so probably what you have now
> is a good start and we can do that later.. just with above goal in mind
>

So you mean we need to have our own libelf or such? I'm not sure it's
the way to go. I just wanted to have a working 'perf record' on my board
:). But I'd like to hear how others think.

Thanks for the comment,
Namhyung

2012-05-22 01:10:48

by Namhyung Kim

[permalink] [raw]
Subject: Re: [PATCH 5/5] perf symbols: Implement poor man's ELF parser

Hi, again

On Mon, 21 May 2012 13:47:39 +0200, Jiri Olsa wrote:
> On Mon, May 14, 2012 at 04:10:24PM +0900, Namhyung Kim wrote:
>> Implement minimalistic elf parser for getting build-id.
>> A couple of structs needed are copied from elf.h and
>> the parser only looks for PT_NOTE program header to
>> check build-id.
>> ---
>> tools/perf/util/elf-minimal.h | 153 ++++++++++++++++++++++++
>> tools/perf/util/symbol-minimal.c | 244 ++++++++++++++++++++++++++++++++++++--
>> 2 files changed, 388 insertions(+), 9 deletions(-)
>> create mode 100644 tools/perf/util/elf-minimal.h
>>
>> diff --git a/tools/perf/util/elf-minimal.h b/tools/perf/util/elf-minimal.h
>> new file mode 100644
>> index 000000000000..26540b5718a1
>> --- /dev/null
>> +++ b/tools/perf/util/elf-minimal.h
>> @@ -0,0 +1,153 @@
>> +/*
>> + * Minimal ELF definitions for parsing build-id.
>> + */
>> +/* This file defines standard ELF types, structures, and macros.
>> + Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011
>> + Free Software Foundation, Inc.
>> + This file is part of the GNU C Library.
>> +
>> + The GNU C Library is free software; you can redistribute it and/or
>> + modify it under the terms of the GNU Lesser General Public
>> + License as published by the Free Software Foundation; either
>> + version 2.1 of the License, or (at your option) any later version.
>> +
>> + The GNU C Library is distributed in the hope that it will be useful,
>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + Lesser General Public License for more details.
>> +
>> + You should have received a copy of the GNU Lesser General Public
>> + License along with the GNU C Library; if not, write to the Free
>> + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
>> + 02111-1307 USA. */
>
> I can see all this exported in:
>
> [jolsa@dhcp-26-214 perf]$ rpm -qf /usr/include/elf.h
> glibc-headers-2.14.90-24.fc16.6.x86_64
>
> so maybe we dont need to add our own, since glic-headers
> seems crutial anyway ;)
>

Thanks for pointing it out. Actually I wanted to be independent to glibc
either, but it seems we tied to it tightly already. Will remove it.

Thanks,
Namhyung

2012-05-22 07:53:16

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 5/5] perf symbols: Implement poor man's ELF parser

On Mon, 2012-05-21 at 13:47 +0200, Jiri Olsa wrote:
> I can see all this exported in:
>
> [jolsa@dhcp-26-214 perf]$ rpm -qf /usr/include/elf.h
> glibc-headers-2.14.90-24.fc16.6.x86_64
>
> so maybe we dont need to add our own, since glic-headers
> seems crutial anyway ;)

There's people building perf against uclibc and such, not sure they
carry it.

2012-05-22 08:35:45

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 3/5] perf tools: Split out util/symbol-elf.c

On Tue, May 22, 2012 at 10:00:43AM +0900, Namhyung Kim wrote:
> Hi, Jiri
>
> On Mon, 21 May 2012 13:45:31 +0200, Jiri Olsa wrote:
> > hi,
> > this one needs rebase to current code, I got some conflicts
> >
>
> Will do.
>
>
> > On Mon, May 14, 2012 at 04:10:22PM +0900, Namhyung Kim wrote:
> >> Factor out the dependency of ELF handling into separate
> >> symbol-elf.c file. It is a preparation of building a
> >> minimalistic version perf tools which doesn't depend on
> >> the elfutils.
> >>
> >> Signed-off-by: Namhyung Kim <[email protected]>
> >> ---
> >> tools/perf/Makefile | 1 +
> >> tools/perf/util/symbol-elf.c | 691 +++++++++++++++++++++++++++++++++++++++++
> >> tools/perf/util/symbol.c | 704 +-----------------------------------------
> >> tools/perf/util/symbol.h | 15 +
> >> 4 files changed, 715 insertions(+), 696 deletions(-)
> >> create mode 100644 tools/perf/util/symbol-elf.c
> >>
> >> diff --git a/tools/perf/Makefile b/tools/perf/Makefile
> >> index e98e14c88532..7198c6cbc006 100644
> >> --- a/tools/perf/Makefile
> >> +++ b/tools/perf/Makefile
> >> @@ -334,6 +334,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
> >> LIB_OBJS += $(OUTPUT)util/wrapper.o
> >> LIB_OBJS += $(OUTPUT)util/sigchain.o
> >> LIB_OBJS += $(OUTPUT)util/symbol.o
> >> +LIB_OBJS += $(OUTPUT)util/symbol-elf.o
> >
> > I think I'd like more generic elf interface compiled with either libelf
> > or our stuff.. also separated from "other perf related" symbol handling
> >
> > looks like we need to be able to parse out build ID and symbols from
> > symtab or dyntab:
> >
> > perf_elf__get_buildid(file, buf, len)
> >
> > perf_elf__get_symbols(file, ..., callback, )
> > - calling callback func for each symbol found,
> > the call would then do the perf symbol related stuff
> >
> > I understand that means much more changes.. so probably what you have now
> > is a good start and we can do that later.. just with above goal in mind
> >
>
> So you mean we need to have our own libelf or such? I'm not sure it's

I meant having above interface implemented either via libelf or your
minimal implementation.. just little more general than the current one

jirka

> the way to go. I just wanted to have a working 'perf record' on my board
> :). But I'd like to hear how others think.
>
> Thanks for the comment,
> Namhyung

2012-05-22 10:28:32

by Namhyung Kim

[permalink] [raw]
Subject: Re: [PATCH 5/5] perf symbols: Implement poor man's ELF parser

Hi,

On Tue, 22 May 2012 09:52:58 +0200, Peter Zijlstra wrote:
> On Mon, 2012-05-21 at 13:47 +0200, Jiri Olsa wrote:
>> I can see all this exported in:
>>
>> [jolsa@dhcp-26-214 perf]$ rpm -qf /usr/include/elf.h
>> glibc-headers-2.14.90-24.fc16.6.x86_64
>>
>> so maybe we dont need to add our own, since glic-headers
>> seems crutial anyway ;)
>
> There's people building perf against uclibc and such, not sure they
> carry it.

I've checked uclibc and it provides elf.h also. It seems bionic does too.
(do we care?)

Thanks,
Namhyung

2012-05-22 10:44:57

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 5/5] perf symbols: Implement poor man's ELF parser

On Tue, 2012-05-22 at 19:26 +0900, Namhyung Kim wrote:
> I've checked uclibc and it provides elf.h also. It seems bionic does too.
> (do we care?)

We should (care), it would be very nice if embedded could also run perf.

IIRC we get the occasional build fix from them as well which means
people are in fact using this.