diff options
Diffstat (limited to 'tools/perf/arch')
| -rw-r--r-- | tools/perf/arch/arm/Makefile | 4 | ||||
| -rw-r--r-- | tools/perf/arch/arm/util/dwarf-regs.c | 64 | ||||
| -rw-r--r-- | tools/perf/arch/common.c | 212 | ||||
| -rw-r--r-- | tools/perf/arch/common.h | 10 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/Makefile | 5 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/util/dwarf-regs.c | 88 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/util/header.c | 36 | ||||
| -rw-r--r-- | tools/perf/arch/s390/Makefile | 4 | ||||
| -rw-r--r-- | tools/perf/arch/s390/util/dwarf-regs.c | 22 | ||||
| -rw-r--r-- | tools/perf/arch/sh/Makefile | 4 | ||||
| -rw-r--r-- | tools/perf/arch/sh/util/dwarf-regs.c | 55 | ||||
| -rw-r--r-- | tools/perf/arch/sparc/Makefile | 4 | ||||
| -rw-r--r-- | tools/perf/arch/sparc/util/dwarf-regs.c | 43 | ||||
| -rw-r--r-- | tools/perf/arch/x86/Makefile | 8 | ||||
| -rw-r--r-- | tools/perf/arch/x86/include/perf_regs.h | 80 | ||||
| -rw-r--r-- | tools/perf/arch/x86/util/dwarf-regs.c | 75 | ||||
| -rw-r--r-- | tools/perf/arch/x86/util/header.c | 59 | ||||
| -rw-r--r-- | tools/perf/arch/x86/util/unwind.c | 111 |
18 files changed, 884 insertions, 0 deletions
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile new file mode 100644 index 00000000..15130b50 --- /dev/null +++ b/tools/perf/arch/arm/Makefile @@ -0,0 +1,4 @@ +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o +endif diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c new file mode 100644 index 00000000..33ec5b33 --- /dev/null +++ b/tools/perf/arch/arm/util/dwarf-regs.c @@ -0,0 +1,64 @@ +/* + * Mapping of DWARF debug register numbers into register names. + * + * Copyright (C) 2010 Will Deacon, ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <stddef.h> +#include <dwarf-regs.h> + +struct pt_regs_dwarfnum { + const char *name; + unsigned int dwarfnum; +}; + +#define STR(s) #s +#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} +#define GPR_DWARFNUM_NAME(num) \ + {.name = STR(%r##num), .dwarfnum = num} +#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} + +/* + * Reference: + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf + */ +static const struct pt_regs_dwarfnum regdwarfnum_table[] = { + GPR_DWARFNUM_NAME(0), + GPR_DWARFNUM_NAME(1), + GPR_DWARFNUM_NAME(2), + GPR_DWARFNUM_NAME(3), + GPR_DWARFNUM_NAME(4), + GPR_DWARFNUM_NAME(5), + GPR_DWARFNUM_NAME(6), + GPR_DWARFNUM_NAME(7), + GPR_DWARFNUM_NAME(8), + GPR_DWARFNUM_NAME(9), + GPR_DWARFNUM_NAME(10), + REG_DWARFNUM_NAME("%fp", 11), + REG_DWARFNUM_NAME("%ip", 12), + REG_DWARFNUM_NAME("%sp", 13), + REG_DWARFNUM_NAME("%lr", 14), + REG_DWARFNUM_NAME("%pc", 15), + REG_DWARFNUM_END, +}; + +/** + * get_arch_regstr() - lookup register name from it's DWARF register number + * @n: the DWARF register number + * + * get_arch_regstr() returns the name of the register in struct + * regdwarfnum_table from it's DWARF register number. If the register is not + * found in the table, this returns NULL; + */ +const char *get_arch_regstr(unsigned int n) +{ + const struct pt_regs_dwarfnum *roff; + for (roff = regdwarfnum_table; roff->name != NULL; roff++) + if (roff->dwarfnum == n) + return roff->name; + return NULL; +} diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c new file mode 100644 index 00000000..aacef07e --- /dev/null +++ b/tools/perf/arch/common.c @@ -0,0 +1,212 @@ +#include <stdio.h> +#include <sys/utsname.h> +#include "common.h" +#include "../util/debug.h" + +const char *const arm_triplets[] = { + "arm-eabi-", + "arm-linux-androideabi-", + "arm-unknown-linux-", + "arm-unknown-linux-gnu-", + "arm-unknown-linux-gnueabi-", + NULL +}; + +const char *const powerpc_triplets[] = { + "powerpc-unknown-linux-gnu-", + "powerpc64-unknown-linux-gnu-", + NULL +}; + +const char *const s390_triplets[] = { + "s390-ibm-linux-", + NULL +}; + +const char *const sh_triplets[] = { + "sh-unknown-linux-gnu-", + "sh64-unknown-linux-gnu-", + NULL +}; + +const char *const sparc_triplets[] = { + "sparc-unknown-linux-gnu-", + "sparc64-unknown-linux-gnu-", + NULL +}; + +const char *const x86_triplets[] = { + "x86_64-pc-linux-gnu-", + "x86_64-unknown-linux-gnu-", + "i686-pc-linux-gnu-", + "i586-pc-linux-gnu-", + "i486-pc-linux-gnu-", + "i386-pc-linux-gnu-", + "i686-linux-android-", + "i686-android-linux-", + NULL +}; + +const char *const mips_triplets[] = { + "mips-unknown-linux-gnu-", + "mipsel-linux-android-", + NULL +}; + +static bool lookup_path(char *name) +{ + bool found = false; + char *path, *tmp; + char buf[PATH_MAX]; + char *env = getenv("PATH"); + + if (!env) + return false; + + env = strdup(env); + if (!env) + return false; + + path = strtok_r(env, ":", &tmp); + while (path) { + scnprintf(buf, sizeof(buf), "%s/%s", path, name); + if (access(buf, F_OK) == 0) { + found = true; + break; + } + path = strtok_r(NULL, ":", &tmp); + } + free(env); + return found; +} + +static int lookup_triplets(const char *const *triplets, const char *name) +{ + int i; + char buf[PATH_MAX]; + + for (i = 0; triplets[i] != NULL; i++) { + scnprintf(buf, sizeof(buf), "%s%s", triplets[i], name); + if (lookup_path(buf)) + return i; + } + return -1; +} + +/* + * Return architecture name in a normalized form. + * The conversion logic comes from the Makefile. + */ +static const char *normalize_arch(char *arch) +{ + if (!strcmp(arch, "x86_64")) + return "x86"; + if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') + return "x86"; + if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) + return "sparc"; + if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) + return "arm"; + if (!strncmp(arch, "s390", 4)) + return "s390"; + if (!strncmp(arch, "parisc", 6)) + return "parisc"; + if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3)) + return "powerpc"; + if (!strncmp(arch, "mips", 4)) + return "mips"; + if (!strncmp(arch, "sh", 2) && isdigit(arch[2])) + return "sh"; + + return arch; +} + +static int perf_session_env__lookup_binutils_path(struct perf_session_env *env, + const char *name, + const char **path) +{ + int idx; + const char *arch, *cross_env; + struct utsname uts; + const char *const *path_list; + char *buf = NULL; + + arch = normalize_arch(env->arch); + + if (uname(&uts) < 0) + goto out; + + /* + * We don't need to try to find objdump path for native system. + * Just use default binutils path (e.g.: "objdump"). + */ + if (!strcmp(normalize_arch(uts.machine), arch)) + goto out; + + cross_env = getenv("CROSS_COMPILE"); + if (cross_env) { + if (asprintf(&buf, "%s%s", cross_env, name) < 0) + goto out_error; + if (buf[0] == '/') { + if (access(buf, F_OK) == 0) + goto out; + goto out_error; + } + if (lookup_path(buf)) + goto out; + free(buf); + buf = NULL; + } + + if (!strcmp(arch, "arm")) + path_list = arm_triplets; + else if (!strcmp(arch, "powerpc")) + path_list = powerpc_triplets; + else if (!strcmp(arch, "sh")) + path_list = sh_triplets; + else if (!strcmp(arch, "s390")) + path_list = s390_triplets; + else if (!strcmp(arch, "sparc")) + path_list = sparc_triplets; + else if (!strcmp(arch, "x86")) + path_list = x86_triplets; + else if (!strcmp(arch, "mips")) + path_list = mips_triplets; + else { + ui__error("binutils for %s not supported.\n", arch); + goto out_error; + } + + idx = lookup_triplets(path_list, name); + if (idx < 0) { + ui__error("Please install %s for %s.\n" + "You can add it to PATH, set CROSS_COMPILE or " + "override the default using --%s.\n", + name, arch, name); + goto out_error; + } + + if (asprintf(&buf, "%s%s", path_list[idx], name) < 0) + goto out_error; + +out: + *path = buf; + return 0; +out_error: + free(buf); + *path = NULL; + return -1; +} + +int perf_session_env__lookup_objdump(struct perf_session_env *env) +{ + /* + * For live mode, env->arch will be NULL and we can use + * the native objdump tool. + */ + if (env->arch == NULL) + return 0; + + return perf_session_env__lookup_binutils_path(env, "objdump", + &objdump_path); +} diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h new file mode 100644 index 00000000..ede246ed --- /dev/null +++ b/tools/perf/arch/common.h @@ -0,0 +1,10 @@ +#ifndef ARCH_PERF_COMMON_H +#define ARCH_PERF_COMMON_H + +#include "../util/session.h" + +extern const char *objdump_path; + +int perf_session_env__lookup_objdump(struct perf_session_env *env); + +#endif /* ARCH_PERF_COMMON_H */ diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile new file mode 100644 index 00000000..744e6297 --- /dev/null +++ b/tools/perf/arch/powerpc/Makefile @@ -0,0 +1,5 @@ +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o +endif +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c new file mode 100644 index 00000000..733151cd --- /dev/null +++ b/tools/perf/arch/powerpc/util/dwarf-regs.c @@ -0,0 +1,88 @@ +/* + * Mapping of DWARF debug register numbers into register names. + * + * Copyright (C) 2010 Ian Munsie, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <stddef.h> +#include <dwarf-regs.h> + + +struct pt_regs_dwarfnum { + const char *name; + unsigned int dwarfnum; +}; + +#define STR(s) #s +#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} +#define GPR_DWARFNUM_NAME(num) \ + {.name = STR(%gpr##num), .dwarfnum = num} +#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} + +/* + * Reference: + * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html + */ +static const struct pt_regs_dwarfnum regdwarfnum_table[] = { + GPR_DWARFNUM_NAME(0), + GPR_DWARFNUM_NAME(1), + GPR_DWARFNUM_NAME(2), + GPR_DWARFNUM_NAME(3), + GPR_DWARFNUM_NAME(4), + GPR_DWARFNUM_NAME(5), + GPR_DWARFNUM_NAME(6), + GPR_DWARFNUM_NAME(7), + GPR_DWARFNUM_NAME(8), + GPR_DWARFNUM_NAME(9), + GPR_DWARFNUM_NAME(10), + GPR_DWARFNUM_NAME(11), + GPR_DWARFNUM_NAME(12), + GPR_DWARFNUM_NAME(13), + GPR_DWARFNUM_NAME(14), + GPR_DWARFNUM_NAME(15), + GPR_DWARFNUM_NAME(16), + GPR_DWARFNUM_NAME(17), + GPR_DWARFNUM_NAME(18), + GPR_DWARFNUM_NAME(19), + GPR_DWARFNUM_NAME(20), + GPR_DWARFNUM_NAME(21), + GPR_DWARFNUM_NAME(22), + GPR_DWARFNUM_NAME(23), + GPR_DWARFNUM_NAME(24), + GPR_DWARFNUM_NAME(25), + GPR_DWARFNUM_NAME(26), + GPR_DWARFNUM_NAME(27), + GPR_DWARFNUM_NAME(28), + GPR_DWARFNUM_NAME(29), + GPR_DWARFNUM_NAME(30), + GPR_DWARFNUM_NAME(31), + REG_DWARFNUM_NAME("%msr", 66), + REG_DWARFNUM_NAME("%ctr", 109), + REG_DWARFNUM_NAME("%link", 108), + REG_DWARFNUM_NAME("%xer", 101), + REG_DWARFNUM_NAME("%dar", 119), + REG_DWARFNUM_NAME("%dsisr", 118), + REG_DWARFNUM_END, +}; + +/** + * get_arch_regstr() - lookup register name from it's DWARF register number + * @n: the DWARF register number + * + * get_arch_regstr() returns the name of the register in struct + * regdwarfnum_table from it's DWARF register number. If the register is not + * found in the table, this returns NULL; + */ +const char *get_arch_regstr(unsigned int n) +{ + const struct pt_regs_dwarfnum *roff; + for (roff = regdwarfnum_table; roff->name != NULL; roff++) + if (roff->dwarfnum == n) + return roff->name; + return NULL; +} diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c new file mode 100644 index 00000000..2f7073d1 --- /dev/null +++ b/tools/perf/arch/powerpc/util/header.c @@ -0,0 +1,36 @@ +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../../util/header.h" + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) + +#define mfspr(rn) ({unsigned long rval; \ + asm volatile("mfspr %0," __stringify(rn) \ + : "=r" (rval)); rval; }) + +#define SPRN_PVR 0x11F /* Processor Version Register */ +#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ +#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ + +int +get_cpuid(char *buffer, size_t sz) +{ + unsigned long pvr; + int nb; + + pvr = mfspr(SPRN_PVR); + + nb = scnprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr)); + + /* look for end marker to ensure the entire data fit */ + if (strchr(buffer, '$')) { + buffer[nb-1] = '\0'; + return 0; + } + return -1; +} diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile new file mode 100644 index 00000000..15130b50 --- /dev/null +++ b/tools/perf/arch/s390/Makefile @@ -0,0 +1,4 @@ +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o +endif diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c new file mode 100644 index 00000000..0469df02 --- /dev/null +++ b/tools/perf/arch/s390/util/dwarf-regs.c @@ -0,0 +1,22 @@ +/* + * Mapping of DWARF debug register numbers into register names. + * + * Copyright IBM Corp. 2010 + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, + * + */ + +#include <stddef.h> +#include <dwarf-regs.h> + +#define NUM_GPRS 16 + +static const char *gpr_names[NUM_GPRS] = { + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", +}; + +const char *get_arch_regstr(unsigned int n) +{ + return (n >= NUM_GPRS) ? NULL : gpr_names[n]; +} diff --git a/tools/perf/arch/sh/Makefile b/tools/perf/arch/sh/Makefile new file mode 100644 index 00000000..15130b50 --- /dev/null +++ b/tools/perf/arch/sh/Makefile @@ -0,0 +1,4 @@ +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o +endif diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c new file mode 100644 index 00000000..0d0897f5 --- /dev/null +++ b/tools/perf/arch/sh/util/dwarf-regs.c @@ -0,0 +1,55 @@ +/* + * Mapping of DWARF debug register numbers into register names. + * + * Copyright (C) 2010 Matt Fleming <matt@console-pimps.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <stddef.h> +#include <dwarf-regs.h> + +/* + * Generic dwarf analysis helpers + */ + +#define SH_MAX_REGS 18 +const char *sh_regs_table[SH_MAX_REGS] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "pc", + "pr", +}; + +/* Return architecture dependent register string (for kprobe-tracer) */ +const char *get_arch_regstr(unsigned int n) +{ + return (n <= SH_MAX_REGS) ? sh_regs_table[n] : NULL; +} diff --git a/tools/perf/arch/sparc/Makefile b/tools/perf/arch/sparc/Makefile new file mode 100644 index 00000000..15130b50 --- /dev/null +++ b/tools/perf/arch/sparc/Makefile @@ -0,0 +1,4 @@ +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o +endif diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c new file mode 100644 index 00000000..92eda412 --- /dev/null +++ b/tools/perf/arch/sparc/util/dwarf-regs.c @@ -0,0 +1,43 @@ +/* + * Mapping of DWARF debug register numbers into register names. + * + * Copyright (C) 2010 David S. Miller <davem@davemloft.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <stddef.h> +#include <dwarf-regs.h> + +#define SPARC_MAX_REGS 96 + +const char *sparc_regs_table[SPARC_MAX_REGS] = { + "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", + "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", + "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", + "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39", + "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47", + "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55", + "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63", +}; + +/** + * get_arch_regstr() - lookup register name from it's DWARF register number + * @n: the DWARF register number + * + * get_arch_regstr() returns the name of the register in struct + * regdwarfnum_table from it's DWARF register number. If the register is not + * found in the table, this returns NULL; + */ +const char *get_arch_regstr(unsigned int n) +{ + return (n <= SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL; +} diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile new file mode 100644 index 00000000..815841c0 --- /dev/null +++ b/tools/perf/arch/x86/Makefile @@ -0,0 +1,8 @@ +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o +endif +ifndef NO_LIBUNWIND +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o +endif +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h new file mode 100644 index 00000000..7fcdcdbe --- /dev/null +++ b/tools/perf/arch/x86/include/perf_regs.h @@ -0,0 +1,80 @@ +#ifndef ARCH_PERF_REGS_H +#define ARCH_PERF_REGS_H + +#include <stdlib.h> +#include "../../util/types.h" +#include <asm/perf_regs.h> + +#ifndef ARCH_X86_64 +#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) +#else +#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \ + (1ULL << PERF_REG_X86_ES) | \ + (1ULL << PERF_REG_X86_FS) | \ + (1ULL << PERF_REG_X86_GS)) +#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT) +#endif +#define PERF_REG_IP PERF_REG_X86_IP +#define PERF_REG_SP PERF_REG_X86_SP + +static inline const char *perf_reg_name(int id) +{ + switch (id) { + case PERF_REG_X86_AX: + return "AX"; + case PERF_REG_X86_BX: + return "BX"; + case PERF_REG_X86_CX: + return "CX"; + case PERF_REG_X86_DX: + return "DX"; + case PERF_REG_X86_SI: + return "SI"; + case PERF_REG_X86_DI: + return "DI"; + case PERF_REG_X86_BP: + return "BP"; + case PERF_REG_X86_SP: + return "SP"; + case PERF_REG_X86_IP: + return "IP"; + case PERF_REG_X86_FLAGS: + return "FLAGS"; + case PERF_REG_X86_CS: + return "CS"; + case PERF_REG_X86_SS: + return "SS"; + case PERF_REG_X86_DS: + return "DS"; + case PERF_REG_X86_ES: + return "ES"; + case PERF_REG_X86_FS: + return "FS"; + case PERF_REG_X86_GS: + return "GS"; +#ifdef ARCH_X86_64 + case PERF_REG_X86_R8: + return "R8"; + case PERF_REG_X86_R9: + return "R9"; + case PERF_REG_X86_R10: + return "R10"; + case PERF_REG_X86_R11: + return "R11"; + case PERF_REG_X86_R12: + return "R12"; + case PERF_REG_X86_R13: + return "R13"; + case PERF_REG_X86_R14: + return "R14"; + case PERF_REG_X86_R15: + return "R15"; +#endif /* ARCH_X86_64 */ + default: + return NULL; + } + + return NULL; +} + +#endif /* ARCH_PERF_REGS_H */ diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c new file mode 100644 index 00000000..be22dd46 --- /dev/null +++ b/tools/perf/arch/x86/util/dwarf-regs.c @@ -0,0 +1,75 @@ +/* + * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. + * Extracted from probe-finder.c + * + * Written by Masami Hiramatsu <mhiramat@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <stddef.h> +#include <dwarf-regs.h> + +/* + * Generic dwarf analysis helpers + */ + +#define X86_32_MAX_REGS 8 +const char *x86_32_regs_table[X86_32_MAX_REGS] = { + "%ax", + "%cx", + "%dx", + "%bx", + "$stack", /* Stack address instead of %sp */ + "%bp", + "%si", + "%di", +}; + +#define X86_64_MAX_REGS 16 +const char *x86_64_regs_table[X86_64_MAX_REGS] = { + "%ax", + "%dx", + "%cx", + "%bx", + "%si", + "%di", + "%bp", + "%sp", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", +}; + +/* TODO: switching by dwarf address size */ +#ifdef __x86_64__ +#define ARCH_MAX_REGS X86_64_MAX_REGS +#define arch_regs_table x86_64_regs_table +#else +#define ARCH_MAX_REGS X86_32_MAX_REGS +#define arch_regs_table x86_32_regs_table +#endif + +/* Return architecture dependent register string (for kprobe-tracer) */ +const char *get_arch_regstr(unsigned int n) +{ + return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL; +} diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c new file mode 100644 index 00000000..146d12a1 --- /dev/null +++ b/tools/perf/arch/x86/util/header.c @@ -0,0 +1,59 @@ +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../../util/header.h" + +static inline void +cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c, + unsigned int *d) +{ + __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t" + "movl %%ebx, %%esi\n\t.byte 0x5b" + : "=a" (*a), + "=S" (*b), + "=c" (*c), + "=d" (*d) + : "a" (op)); +} + +int +get_cpuid(char *buffer, size_t sz) +{ + unsigned int a, b, c, d, lvl; + int family = -1, model = -1, step = -1; + int nb; + char vendor[16]; + + cpuid(0, &lvl, &b, &c, &d); + strncpy(&vendor[0], (char *)(&b), 4); + strncpy(&vendor[4], (char *)(&d), 4); + strncpy(&vendor[8], (char *)(&c), 4); + vendor[12] = '\0'; + + if (lvl >= 1) { + cpuid(1, &a, &b, &c, &d); + + family = (a >> 8) & 0xf; /* bits 11 - 8 */ + model = (a >> 4) & 0xf; /* Bits 7 - 4 */ + step = a & 0xf; + + /* extended family */ + if (family == 0xf) + family += (a >> 20) & 0xff; + + /* extended model */ + if (family >= 0x6) + model += ((a >> 16) & 0xf) << 4; + } + nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); + + /* look for end marker to ensure the entire data fit */ + if (strchr(buffer, '$')) { + buffer[nb-1] = '\0'; + return 0; + } + return -1; +} diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind.c new file mode 100644 index 00000000..78d956ef --- /dev/null +++ b/tools/perf/arch/x86/util/unwind.c @@ -0,0 +1,111 @@ + +#include <errno.h> +#include <libunwind.h> +#include "perf_regs.h" +#include "../../util/unwind.h" + +#ifdef ARCH_X86_64 +int unwind__arch_reg_id(int regnum) +{ + int id; + + switch (regnum) { + case UNW_X86_64_RAX: + id = PERF_REG_X86_AX; + break; + case UNW_X86_64_RDX: + id = PERF_REG_X86_DX; + break; + case UNW_X86_64_RCX: + id = PERF_REG_X86_CX; + break; + case UNW_X86_64_RBX: + id = PERF_REG_X86_BX; + break; + case UNW_X86_64_RSI: + id = PERF_REG_X86_SI; + break; + case UNW_X86_64_RDI: + id = PERF_REG_X86_DI; + break; + case UNW_X86_64_RBP: + id = PERF_REG_X86_BP; + break; + case UNW_X86_64_RSP: + id = PERF_REG_X86_SP; + break; + case UNW_X86_64_R8: + id = PERF_REG_X86_R8; + break; + case UNW_X86_64_R9: + id = PERF_REG_X86_R9; + break; + case UNW_X86_64_R10: + id = PERF_REG_X86_R10; + break; + case UNW_X86_64_R11: + id = PERF_REG_X86_R11; + break; + case UNW_X86_64_R12: + id = PERF_REG_X86_R12; + break; + case UNW_X86_64_R13: + id = PERF_REG_X86_R13; + break; + case UNW_X86_64_R14: + id = PERF_REG_X86_R14; + break; + case UNW_X86_64_R15: + id = PERF_REG_X86_R15; + break; + case UNW_X86_64_RIP: + id = PERF_REG_X86_IP; + break; + default: + pr_err("unwind: invalid reg id %d\n", regnum); + return -EINVAL; + } + + return id; +} +#else +int unwind__arch_reg_id(int regnum) +{ + int id; + + switch (regnum) { + case UNW_X86_EAX: + id = PERF_REG_X86_AX; + break; + case UNW_X86_EDX: + id = PERF_REG_X86_DX; + break; + case UNW_X86_ECX: + id = PERF_REG_X86_CX; + break; + case UNW_X86_EBX: + id = PERF_REG_X86_BX; + break; + case UNW_X86_ESI: + id = PERF_REG_X86_SI; + break; + case UNW_X86_EDI: + id = PERF_REG_X86_DI; + break; + case UNW_X86_EBP: + id = PERF_REG_X86_BP; + break; + case UNW_X86_ESP: + id = PERF_REG_X86_SP; + break; + case UNW_X86_EIP: + id = PERF_REG_X86_IP; + break; + default: + pr_err("unwind: invalid reg id %d\n", regnum); + return -EINVAL; + } + + return id; +} +#endif /* ARCH_X86_64 */ |
