lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri,  7 Nov 2014 14:20:05 +0900
From:	Namhyung Kim <namhyung@...nel.org>
To:	Arnaldo Carvalho de Melo <acme@...nel.org>
Cc:	Peter Zijlstra <a.p.zijlstra@...llo.nl>,
	Ingo Molnar <mingo@...nel.org>,
	Paul Mackerras <paulus@...ba.org>,
	Namhyung Kim <namhyung.kim@....com>,
	Namhyung Kim <namhyung@...nel.org>,
	LKML <linux-kernel@...r.kernel.org>,
	Jiri Olsa <jolsa@...hat.com>,
	Adrian Hunter <adrian.hunter@...el.com>,
	David Ahern <dsahern@...il.com>
Subject: [PATCH 2/3] perf symbol: Implement a very simple ELF symbol parser

It'll be used to show (userspace) symbol names when libelf isn't (or
cannot be) linked.

  # Overhead  Command     Shared Object      Symbol
  # ........  ..........  .................  .........................
  #
      37.01%  mem-memcpy  libc-2.17.so       [.] __memcpy_ssse3_back
      24.25%  perf        ld-2.17.so         [.] _dl_relocate_object
      22.16%  perf        [kernel.kallsyms]  [k] kmem_cache_alloc
      14.29%  mem-memset  libc-2.17.so       [.] __memset_sse2
       2.21%  perf        [kernel.kallsyms]  [k] flush_signal_handlers
       0.07%  perf        [kernel.kallsyms]  [k] intel_pmu_enable_all

Cc: Adrian Hunter <adrian.hunter@...el.com>
Signed-off-by: Namhyung Kim <namhyung@...nel.org>
---
 tools/perf/util/symbol-minimal.c | 143 ++++++++++++++++++++++++++++++++++++---
 tools/perf/util/symbol-minimal.h |  64 ++++++++++++++++++
 tools/perf/util/symbol.h         |  10 ++-
 3 files changed, 208 insertions(+), 9 deletions(-)
 create mode 100644 tools/perf/util/symbol-minimal.h

diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 226cf41ed7e6..9da571d83a25 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,11 +1,13 @@
 #include "symbol.h"
 #include "util.h"
+#include "debug.h"
 
 #include <stdio.h>
 #include <fcntl.h>
 #include <string.h>
 #include <byteswap.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 
 
 static bool check_need_swap(int file_endian)
@@ -242,22 +244,81 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
 	return ret;
 }
 
+static const char *symsrc__symname(struct symsrc *ss, Elf_Shdr *strsec, int idx)
+{
+	return ss->ptr + strsec->sh_offset + idx;
+}
+
 int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
 		 const char *name,
 	         enum dso_binary_type type)
 {
-	int fd = open(name, O_RDONLY);
+	int fd;
+	unsigned i;
+	Elf_Ehdr ehdr;
+	struct stat stbuf;
+	void *ptr;
+
+	fd = open(name, O_RDONLY);
 	if (fd < 0)
 		return -1;
 
 	ss->name = strdup(name);
-	if (!ss->name)
-		goto out_close;
+	if (!ss->name) {
+		close(fd);
+		return -1;
+	}
 
 	ss->fd = fd;
 	ss->type = type;
 
+	/* only consider native case (no swap) */
+	if (read(fd, &ehdr, sizeof(ehdr)) < 0)
+		goto out_close;
+
+	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
+	    ehdr.e_ident[EI_VERSION] != EV_CURRENT)
+		goto out_close;
+
+	if (ehdr.e_ident[EI_CLASS] != ELFCLASS)
+		goto out_close;
+
+	if (check_need_swap(ehdr.e_ident[EI_DATA]))
+		goto out_close;
+
+	if (ehdr.e_shentsize != sizeof(Elf_Shdr))
+		goto out_close;
+
+	if (fstat(fd, &stbuf) < 0)
+		goto out_close;
+
+	ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (ptr == MAP_FAILED)
+		goto out_close;
+
+	ss->ptr = ptr;
+	ss->len = stbuf.st_size;
+	ss->sec = ptr + ehdr.e_shoff;
+
+	ss->symtab = NULL;
+	for (i = 0; i < ehdr.e_shnum; i++) {
+		Elf_Shdr *shdrp = &ss->sec[i];
+		const char *shname;
+
+		shname = symsrc__symname(ss, &ss->sec[ehdr.e_shstrndx],
+					 shdrp->sh_name);
+
+		if (!strcmp(shname, ".text"))
+			ss->adjust_offset = shdrp->sh_addr - shdrp->sh_offset;
+
+		if (shdrp->sh_type == SHT_SYMTAB) {
+			ss->symtab = shdrp;
+			ss->strtab = &ss->sec[shdrp->sh_link];
+		}
+	}
+
 	return 0;
+
 out_close:
 	close(fd);
 	return -1;
@@ -276,6 +337,7 @@ bool symsrc__has_symtab(struct symsrc *ss __maybe_unused)
 
 void symsrc__destroy(struct symsrc *ss)
 {
+	munmap(ss->ptr, ss->len);
 	zfree(&ss->name);
 	close(ss->fd);
 }
@@ -332,7 +394,9 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  symbol_filter_t filter __maybe_unused,
 		  int kmodule __maybe_unused)
 {
-	unsigned char *build_id[BUILD_ID_SIZE];
+	Elf_Ehdr *ehdr = ss->ptr;
+	Elf_Sym *symtab;
+	size_t i, nr_sym;
 	int ret;
 
 	if (dso->kernel)
@@ -342,11 +406,74 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 	if (ret >= 0)
 		dso->is_64_bit = ret;
 
-	if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
-		dso__set_build_id(dso, build_id);
-		return 1;
+	if (dso->has_build_id) {
+		u8 build_id[BUILD_ID_SIZE];
+
+		if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) < 0)
+			return -1;
+
+		if (!dso__build_id_equal(dso, build_id))
+			return -1;
 	}
-	return 0;
+
+	if (map->type != MAP__FUNCTION)
+		return 0;
+
+	if (!ss->symtab)
+		return 0;
+
+	symtab = ss->ptr + ss->symtab->sh_offset;
+	nr_sym = ss->symtab->sh_size / ss->symtab->sh_entsize;
+
+	pr_debug4("loading symbols from %s\n", ss->name);
+	ret = 0;
+	for (i = 0; i < nr_sym; i++) {
+		struct symbol *s;
+		Elf_Sym *sym = &symtab[i];
+		const char *symname = symsrc__symname(ss, ss->strtab, sym->st_name);
+		unsigned long sym_addr = sym->st_value;
+
+		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
+			continue;
+
+		if (sym->st_shndx == SHN_UNDEF)
+			continue;
+
+		if (ehdr->e_machine == EM_ARM) {
+			/* Reject ARM ELF "mapping symbols": these aren't unique
+			 * and don't identify functions, so will confuse the
+			 * profile output: */
+			if (!strcmp(symname, "$a") ||
+			    !strcmp(symname, "$d") ||
+			    !strcmp(symname, "$t"))
+				continue;
+
+			/* On ARM, symbols for thumb functions have 1 added to
+			 * the symbol address as a flag - remove it */
+			if (sym->st_value & 1)
+				sym_addr--;
+		}
+		sym_addr -= ss->adjust_offset;
+
+		pr_debug4("sym: %s (%lx+%lu)\n", symname, sym_addr, sym->st_size);
+		s = symbol__new(sym_addr, sym->st_size,
+				ELF_ST_BIND(sym->st_info), symname);
+		if (!s)
+			break;
+
+		if (filter && filter(map, s))
+			symbol__delete(s);
+		else {
+			symbols__insert(&dso->symbols[map->type], s);
+			ret++;
+		}
+	}
+
+	if (ret > 0) {
+		symbols__fixup_duplicate(&dso->symbols[map->type]);
+		symbols__fixup_end(&dso->symbols[map->type]);
+	}
+	return ret;
 }
 
 int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
diff --git a/tools/perf/util/symbol-minimal.h b/tools/perf/util/symbol-minimal.h
new file mode 100644
index 000000000000..7b8b38426359
--- /dev/null
+++ b/tools/perf/util/symbol-minimal.h
@@ -0,0 +1,64 @@
+#ifndef __PERF_SYMBOL_MINIMAL_H
+#define __PERF_SYMBOL_MINIMAL_H
+
+#include <elf.h>
+#include <linux/bitops.h>
+
+#if BITS_PER_LONG == 32
+
+# define ELFCLASS	ELFCLASS32
+
+# define Elf_Half	Elf32_Half
+# define Elf_Word	Elf32_Word
+# define Elf_Sword	Elf32_Sword
+# define Elf_Xword	Elf32_Xword
+# define Elf_Sxword	Elf32_Sxword
+# define Elf_Addr	Elf32_Addr
+# define Elf_Off	Elf32_Off
+# define Elf_Section	Elf32_Section
+# define Elf_Versym	Elf32_Versym
+
+# define Elf_Ehdr	Elf32_Ehdr
+# define Elf_Phdr	Elf32_Phdr
+# define Elf_Shdr	Elf32_Shdr
+# define Elf_Nhdr	Elf32_Nhdr
+# define Elf_Sym	Elf32_Sym
+# define Elf_Syminfo	Elf32_Syminfo
+# define Elf_Rel	Elf32_Rel
+# define Elf_Rela	Elf32_Rela
+# define Elf_Dyn	Elf32_Dyn
+
+# define ELF_ST_BIND(val)		ELF32_ST_BIND(val)
+# define ELF_ST_TYPE(val)		ELF32_ST_TYPE(val)
+# define ELF_ST_INFO(bind, type)	ELF32_ST_INFO(bind, type)
+
+#else /* BITS_PER_LONG == 64 */
+
+# define ELFCLASS	ELFCLASS64
+
+# define Elf_Half	Elf64_Half
+# define Elf_Word	Elf64_Word
+# define Elf_Sword	Elf64_Sword
+# define Elf_Xword	Elf64_Xword
+# define Elf_Sxword	Elf64_Sxword
+# define Elf_Addr	Elf64_Addr
+# define Elf_Off	Elf64_Off
+# define Elf_Section	Elf64_Section
+# define Elf_Versym	Elf64_Versym
+
+# define Elf_Ehdr	Elf64_Ehdr
+# define Elf_Phdr	Elf64_Phdr
+# define Elf_Shdr	Elf64_Shdr
+# define Elf_Nhdr	Elf64_Nhdr
+# define Elf_Sym	Elf64_Sym
+# define Elf_Syminfo	Elf64_Syminfo
+# define Elf_Rel	Elf64_Rel
+# define Elf_Rela	Elf64_Rela
+# define Elf_Dyn	Elf64_Dyn
+
+# define ELF_ST_BIND(val)		ELF64_ST_BIND(val)
+# define ELF_ST_TYPE(val)		ELF64_ST_TYPE(val)
+# define ELF_ST_INFO(bind, type)	ELF64_ST_INFO(bind, type)
+
+#endif /* BITS_PER_LONG == 64 */
+#endif /* __PERF_SYMBOL_MINIMAL_H */
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ded3ca7266de..1c1dc5b9b3f8 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -18,8 +18,9 @@
 #ifdef HAVE_LIBELF_SUPPORT
 #include <libelf.h>
 #include <gelf.h>
+#else
+#include "symbol-minimal.h"
 #endif
-#include <elf.h>
 
 #include "dso.h"
 
@@ -229,6 +230,13 @@ struct symsrc {
 
 	bool adjust_symbols;
 	bool is_64_bit;
+#else
+	void *ptr;
+	size_t len;
+	Elf_Shdr *sec;
+	Elf_Shdr *symtab;
+	Elf_Shdr *strtab;
+	long adjust_offset;
 #endif
 };
 
-- 
2.1.2

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ