提交 bf00d67d 编写于 作者: H Huacai Chen 提交者: openeuler-sync-bot

tools/perf: Add basic support for LoongArch

LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I6BWFP

--------------------------------
Signed-off-by: NHuacai Chen <chenhuacai@loongson.cn>
Signed-off-by: NMing Wang <wangming01@loongson.cn>
Change-Id: Id8769bae9287344689add6b523c4c49f7391354f
(cherry picked from commit 4efd0de6)
上级 8608bbcf
......@@ -24,10 +24,17 @@ HOSTCFLAGS_extract-cert.o = $(CRYPTO_CFLAGS)
HOSTLDLIBS_extract-cert = $(CRYPTO_LIBS)
ifdef CONFIG_UNWINDER_ORC
# Additional ARCH settings for x86
ifeq ($(ARCH),x86_64)
ARCH := x86
endif
HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
# Additional ARCH settings for loongarch
ifeq ($(ARCH),loongarch64)
ARCH := loongarch
endif
HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/$(ARCH)/include
HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
HOSTLDLIBS_sorttable = -lpthread
endif
......
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_LOONGARCH_PERF_REGS_H
#define _ASM_LOONGARCH_PERF_REGS_H
enum perf_event_loongarch_regs {
PERF_REG_LOONGARCH_PC,
PERF_REG_LOONGARCH_R1,
PERF_REG_LOONGARCH_R2,
PERF_REG_LOONGARCH_R3,
PERF_REG_LOONGARCH_R4,
PERF_REG_LOONGARCH_R5,
PERF_REG_LOONGARCH_R6,
PERF_REG_LOONGARCH_R7,
PERF_REG_LOONGARCH_R8,
PERF_REG_LOONGARCH_R9,
PERF_REG_LOONGARCH_R10,
PERF_REG_LOONGARCH_R11,
PERF_REG_LOONGARCH_R12,
PERF_REG_LOONGARCH_R13,
PERF_REG_LOONGARCH_R14,
PERF_REG_LOONGARCH_R15,
PERF_REG_LOONGARCH_R16,
PERF_REG_LOONGARCH_R17,
PERF_REG_LOONGARCH_R18,
PERF_REG_LOONGARCH_R19,
PERF_REG_LOONGARCH_R20,
PERF_REG_LOONGARCH_R21,
PERF_REG_LOONGARCH_R22,
PERF_REG_LOONGARCH_R23,
PERF_REG_LOONGARCH_R24,
PERF_REG_LOONGARCH_R25,
PERF_REG_LOONGARCH_R26,
PERF_REG_LOONGARCH_R27,
PERF_REG_LOONGARCH_R28,
PERF_REG_LOONGARCH_R29,
PERF_REG_LOONGARCH_R30,
PERF_REG_LOONGARCH_R31,
PERF_REG_LOONGARCH_MAX = PERF_REG_LOONGARCH_R31 + 1,
};
#endif /* _ASM_LOONGARCH_PERF_REGS_H */
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (C) 2020-2021 Loongson Technology Corporation Limited
*
* 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.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#define __ARCH_WANT_NEW_STAT
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_CLONE3
#include <asm-generic/unistd.h>
......@@ -74,6 +74,13 @@ ifeq ($(SRCARCH),arm64)
LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
endif
ifeq ($(SRCARCH),loongarch)
NO_PERF_REGS := 0
CFLAGS += -I$(OUTPUT)arch/loongarch/include/generated
CFLAGS += -I$(OUTPUT)../arch/loongarch/include/uapi
LIBUNWIND_LIBS = -lunwind -lunwind-loongarch
endif
ifeq ($(SRCARCH),riscv)
NO_PERF_REGS := 0
endif
......
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
PERF_HAVE_JITDUMP := 1
#
# Syscall table generation for perf
#
out := $(OUTPUT)arch/loongarch/include/generated/asm
header := $(out)/syscalls_64.c
incpath := $(srctree)/tools
sysdef := $(srctree)/tools/arch/loongarch/include/uapi/asm/unistd.h
sysprf := $(srctree)/tools/perf/arch/loongarch/entry/syscalls/
systbl := $(sysprf)/mksyscalltbl
# Create output directory if not already present
_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
$(header): $(sysdef) $(systbl)
$(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(incpath) $(sysdef) > $@
clean::
$(call QUIET_CLEAN, loongarch) $(RM) $(header)
archheaders: $(header)
// SPDX-License-Identifier: GPL-2.0
/*
* Perf annotate functions.
*
* Copyright (C) 2020 Loongson Technology Corporation Limited
*/
static
struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name)
{
struct ins_ops *ops = NULL;
if (!strncmp(name, "beqz", 4) ||
!strncmp(name, "bnez", 4) ||
!strncmp(name, "beq", 3) ||
!strncmp(name, "bne", 3) ||
!strncmp(name, "blt", 3) ||
!strncmp(name, "bge", 3) ||
!strncmp(name, "bltu", 4) ||
!strncmp(name, "bgeu", 4) ||
!strncmp(name, "bl", 2))
ops = &call_ops;
else if (!strncmp(name, "jirl", 4))
ops = &ret_ops;
else if (name[0] == 'b')
ops = &jump_ops;
else
return NULL;
arch__associate_ins_ops(arch, name, ops);
return ops;
}
static
int loongarch__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
if (!arch->initialized) {
arch->associate_instruction_ops = loongarch__associate_ins_ops;
arch->initialized = true;
arch->objdump.comment_char = '#';
}
return 0;
}
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Generate system call table for perf. Derived from
# powerpc script.
#
# Copyright (C) 2020 Loongson Technology Co., Ltd.
# Author(s): Ming Wang <wangming01@loongson.cn>
gcc=$1
hostcc=$2
incpath=$3
input=$4
if ! test -r $input; then
echo "Could not read input file" >&2
exit 1
fi
create_table_from_c()
{
local sc nr last_sc
create_table_exe=`mktemp ${TMPDIR:-/tmp}/create-table-XXXXXX`
{
cat <<-_EoHEADER
#include <stdio.h>
#include "$input"
int main(int argc, char *argv[])
{
_EoHEADER
while read sc nr; do
printf "%s\n" " printf(\"\\t[%d] = \\\"$sc\\\",\\n\", $nr);"
last_sc=$nr
done
printf "%s\n" " printf(\"#define SYSCALLTBL_LOONGARCH_MAX_ID %d\\n\", $last_sc);"
printf "}\n"
} | $hostcc -I $incpath/include/uapi -o $create_table_exe -x c -
$create_table_exe
rm -f $create_table_exe
}
create_table()
{
echo "static const char *syscalltbl_loongarch[] = {"
create_table_from_c
echo "};"
}
$gcc -E -dM -x c -I $incpath/include/uapi $input \
|sed -ne 's/^#define __NR_//p' \
|sort -t' ' -k2 -n \
|create_table
/* SPDX-License-Identifier: GPL-2.0 */
/*
* dwarf-regs-table.h : Mapping of DWARF debug register numbers into
* register names.
*
* Copyright (C) 2020 Loongson Technology Corporation Limited
*
* 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.
*
*/
#ifdef DEFINE_DWARF_REGSTR_TABLE
static const char * const loongarch_regstr_tbl[] = {
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
"$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19",
"$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "%29",
"$30", "$31",
};
#endif
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ARCH_PERF_REGS_H
#define ARCH_PERF_REGS_H
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#define PERF_REGS_MAX PERF_REG_LOONGARCH_MAX
#define PERF_REG_IP PERF_REG_LOONGARCH_PC
#define PERF_REG_SP PERF_REG_LOONGARCH_R3
#define PERF_REGS_MASK ((1ULL << PERF_REG_LOONGARCH_MAX) - 1)
static inline const char *__perf_reg_name(int id)
{
switch (id) {
case PERF_REG_LOONGARCH_PC:
return "PC";
case PERF_REG_LOONGARCH_R1:
return "$1";
case PERF_REG_LOONGARCH_R2:
return "$2";
case PERF_REG_LOONGARCH_R3:
return "$3";
case PERF_REG_LOONGARCH_R4:
return "$4";
case PERF_REG_LOONGARCH_R5:
return "$5";
case PERF_REG_LOONGARCH_R6:
return "$6";
case PERF_REG_LOONGARCH_R7:
return "$7";
case PERF_REG_LOONGARCH_R8:
return "$8";
case PERF_REG_LOONGARCH_R9:
return "$9";
case PERF_REG_LOONGARCH_R10:
return "$10";
case PERF_REG_LOONGARCH_R11:
return "$11";
case PERF_REG_LOONGARCH_R12:
return "$12";
case PERF_REG_LOONGARCH_R13:
return "$13";
case PERF_REG_LOONGARCH_R14:
return "$14";
case PERF_REG_LOONGARCH_R15:
return "$15";
case PERF_REG_LOONGARCH_R16:
return "$16";
case PERF_REG_LOONGARCH_R17:
return "$17";
case PERF_REG_LOONGARCH_R18:
return "$18";
case PERF_REG_LOONGARCH_R19:
return "$19";
case PERF_REG_LOONGARCH_R20:
return "$20";
case PERF_REG_LOONGARCH_R21:
return "$21";
case PERF_REG_LOONGARCH_R22:
return "$22";
case PERF_REG_LOONGARCH_R23:
return "$23";
case PERF_REG_LOONGARCH_R24:
return "$24";
case PERF_REG_LOONGARCH_R25:
return "$25";
case PERF_REG_LOONGARCH_R26:
return "$26";
case PERF_REG_LOONGARCH_R27:
return "$27";
case PERF_REG_LOONGARCH_R28:
return "$28";
case PERF_REG_LOONGARCH_R29:
return "$29";
case PERF_REG_LOONGARCH_R30:
return "$30";
case PERF_REG_LOONGARCH_R31:
return "$31";
default:
break;
}
return NULL;
}
#endif /* ARCH_PERF_REGS_H */
perf-y += perf_regs.o
perf-$(CONFIG_DWARF) += dwarf-regs.o
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
// SPDX-License-Identifier: GPL-2.0
/*
* dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2013 Cavium, Inc.
*
* 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.
*
*/
#include <stdio.h>
#include <dwarf-regs.h>
static const char *loongarch_gpr_names[32] = {
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
"$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19",
"$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29",
"$30", "$31"
};
const char *get_arch_regstr(unsigned int n)
{
n %= 32;
return loongarch_gpr_names[n];
}
// SPDX-License-Identifier: GPL-2.0
#include "../../../util/perf_regs.h"
const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <libunwind.h>
#include "perf_regs.h"
#include "../../util/unwind.h"
#include "util/debug.h"
int libunwind__arch_reg_id(int regnum)
{
switch (regnum) {
case UNW_LOONGARCH_R1:
return PERF_REG_LOONGARCH_R1;
case UNW_LOONGARCH_R2:
return PERF_REG_LOONGARCH_R2;
case UNW_LOONGARCH_R3:
return PERF_REG_LOONGARCH_R3;
case UNW_LOONGARCH_R4:
return PERF_REG_LOONGARCH_R4;
case UNW_LOONGARCH_R5:
return PERF_REG_LOONGARCH_R5;
case UNW_LOONGARCH_R6:
return PERF_REG_LOONGARCH_R6;
case UNW_LOONGARCH_R7:
return PERF_REG_LOONGARCH_R7;
case UNW_LOONGARCH_R8:
return PERF_REG_LOONGARCH_R8;
case UNW_LOONGARCH_R9:
return PERF_REG_LOONGARCH_R9;
case UNW_LOONGARCH_R10:
return PERF_REG_LOONGARCH_R10;
case UNW_LOONGARCH_R11:
return PERF_REG_LOONGARCH_R11;
case UNW_LOONGARCH_R12:
return PERF_REG_LOONGARCH_R12;
case UNW_LOONGARCH_R13:
return PERF_REG_LOONGARCH_R13;
case UNW_LOONGARCH_R14:
return PERF_REG_LOONGARCH_R14;
case UNW_LOONGARCH_R15:
return PERF_REG_LOONGARCH_R15;
case UNW_LOONGARCH_R16:
return PERF_REG_LOONGARCH_R16;
case UNW_LOONGARCH_R17:
return PERF_REG_LOONGARCH_R17;
case UNW_LOONGARCH_R18:
return PERF_REG_LOONGARCH_R18;
case UNW_LOONGARCH_R19:
return PERF_REG_LOONGARCH_R19;
case UNW_LOONGARCH_R20:
return PERF_REG_LOONGARCH_R20;
case UNW_LOONGARCH_R21:
return PERF_REG_LOONGARCH_R21;
case UNW_LOONGARCH_R22:
return PERF_REG_LOONGARCH_R22;
case UNW_LOONGARCH_R23:
return PERF_REG_LOONGARCH_R23;
case UNW_LOONGARCH_R24:
return PERF_REG_LOONGARCH_R24;
case UNW_LOONGARCH_R25:
return PERF_REG_LOONGARCH_R25;
case UNW_LOONGARCH_R26:
return PERF_REG_LOONGARCH_R26;
case UNW_LOONGARCH_R27:
return PERF_REG_LOONGARCH_R27;
case UNW_LOONGARCH_R28:
return PERF_REG_LOONGARCH_R28;
case UNW_LOONGARCH_R29:
return PERF_REG_LOONGARCH_R29;
case UNW_LOONGARCH_R30:
return PERF_REG_LOONGARCH_R30;
case UNW_LOONGARCH_R31:
return PERF_REG_LOONGARCH_R31;
case UNW_LOONGARCH_PC:
return PERF_REG_LOONGARCH_PC;
default:
pr_err("unwind: invalid reg id %d\n", regnum);
return -EINVAL;
}
return -EINVAL;
}
......@@ -156,6 +156,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i
#include "arch/powerpc/annotate/instructions.c"
#include "arch/s390/annotate/instructions.c"
#include "arch/sparc/annotate/instructions.c"
#include "arch/loongarch/annotate/instructions.c"
static struct arch architectures[] = {
{
......@@ -205,6 +206,13 @@ static struct arch architectures[] = {
.comment_char = '#',
},
},
{
.name = "loongarch",
.init = loongarch__annotate_init,
.objdump = {
.comment_char = '#',
},
},
};
static void ins__delete(struct ins_operands *ops)
......
......@@ -14,6 +14,10 @@
#define EM_AARCH64 183 /* ARM 64 bit */
#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258 /* LoongArch */
#endif
/* Define const char * {arch}_register_tbl[] */
#define DEFINE_DWARF_REGSTR_TABLE
#include "../arch/x86/include/dwarf-regs-table.h"
......@@ -24,6 +28,7 @@
#include "../arch/s390/include/dwarf-regs-table.h"
#include "../arch/sparc/include/dwarf-regs-table.h"
#include "../arch/xtensa/include/dwarf-regs-table.h"
#include "../arch/loongarch/include/dwarf-regs-table.h"
#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL)
......@@ -53,6 +58,8 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine)
return __get_dwarf_regstr(sparc_regstr_tbl, n);
case EM_XTENSA:
return __get_dwarf_regstr(xtensa_regstr_tbl, n);
case EM_LOONGARCH:
return __get_dwarf_regstr(loongarch_regstr_tbl, n);
default:
pr_err("ELF MACHINE %x is not supported.\n", machine);
}
......
......@@ -347,6 +347,8 @@ static const char *normalize_arch(char *arch)
return "mips";
if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
return "sh";
if (!strncmp(arch, "loongarch", 9))
return "loongarch";
return arch;
}
......
......@@ -38,6 +38,9 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent
#elif defined(__s390x__)
#define GEN_ELF_ARCH EM_S390
#define GEN_ELF_CLASS ELFCLASS64
#elif defined(__loongarch__)
#define GEN_ELF_ARCH EM_LOONGARCH
#define GEN_ELF_CLASS ELFCLASS64
#else
#error "unsupported architecture"
#endif
......
......@@ -34,6 +34,10 @@ static const char **syscalltbl_native = syscalltbl_powerpc_32;
#include <asm/syscalls.c>
const int syscalltbl_native_max_id = SYSCALLTBL_ARM64_MAX_ID;
static const char **syscalltbl_native = syscalltbl_arm64;
#elif defined(__loongarch__)
#include <asm/syscalls.c>
const int syscalltbl_native_max_id = SYSCALLTBL_LOONGARCH_MAX_ID;
static const char **syscalltbl_native = syscalltbl_loongarch;
#endif
struct syscall {
......
......@@ -4,7 +4,8 @@ HOSTARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-e /arm64/!s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
-e s/loongarch.*/loongarch/)
ifndef ARCH
ARCH := $(HOSTARCH)
......@@ -33,6 +34,15 @@ ifeq ($(ARCH),sh64)
SRCARCH := sh
endif
# Additional ARCH settings for loongarch
ifeq ($(ARCH),loongarch32)
SRCARCH := loongarch
endif
ifeq ($(ARCH),loongarch64)
SRCARCH := loongarch
endif
LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
ifeq ($(LP64), 1)
IS_64_BIT := 1
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册