2022-08-19 08:33:24

by Qing Zhang

[permalink] [raw]
Subject: [PATCH 6/9] LoongArch: modules/ftrace: Initialize PLT at load time

To Implement ftrace trampiones through plt entry.

Tested by forcing ftrace_make_call() to use the module PLT, and then
loading up a module after setting up ftrace with:

| echo ":mod:<module-name>" > set_ftrace_filter;
| echo function > current_tracer;
| modprobe <module-name>

Since FTRACE_ADDR/FTRACE_REGS_ADDR is only defined when CONFIG_DYNAMIC_FTRACE
is selected, we wrap its use along with most of module_init_ftrace_plt() with
ifdeffery rather than using IS_ENABLED().

Signed-off-by: Qing Zhang <[email protected]>
---
arch/loongarch/include/asm/ftrace.h | 4 ++
arch/loongarch/include/asm/inst.h | 2 +
arch/loongarch/include/asm/module.h | 14 +++--
arch/loongarch/include/asm/module.lds.h | 1 +
arch/loongarch/kernel/ftrace_dyn.c | 79 +++++++++++++++++++++++++
arch/loongarch/kernel/inst.c | 12 ++++
arch/loongarch/kernel/module-sections.c | 11 ++++
arch/loongarch/kernel/module.c | 48 +++++++++++++++
8 files changed, 166 insertions(+), 5 deletions(-)

diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
index a3f974a7a5ce..0ed3d649c1ba 100644
--- a/arch/loongarch/include/asm/ftrace.h
+++ b/arch/loongarch/include/asm/ftrace.h
@@ -6,6 +6,10 @@
#ifndef _ASM_LOONGARCH_FTRACE_H
#define _ASM_LOONGARCH_FTRACE_H

+#define FTRACE_PLT_IDX 0
+#define FTRACE_REGS_PLT_IDX 1
+#define NR_FTRACE_PLTS 2
+
#ifdef CONFIG_FUNCTION_TRACER
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 713b4996bfac..41cb15c4c475 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -52,6 +52,7 @@ enum reg2i12_op {
};

enum reg2i16_op {
+ addu16id_op = 0x04,
jirl_op = 0x13,
beq_op = 0x16,
bne_op = 0x17,
@@ -191,6 +192,7 @@ u32 larch_insn_gen_nop(void);
u32 larch_insn_gen_b(unsigned long pc, unsigned long dest);
u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest);

+u32 larch_insn_gen_addu16id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj,
enum loongarch_gpr rk);
u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj);
diff --git a/arch/loongarch/include/asm/module.h b/arch/loongarch/include/asm/module.h
index 9f6718df1854..1aac156cd187 100644
--- a/arch/loongarch/include/asm/module.h
+++ b/arch/loongarch/include/asm/module.h
@@ -19,10 +19,13 @@ struct mod_section {
struct mod_arch_specific {
struct mod_section plt;
struct mod_section plt_idx;
+
+ /* for CONFIG_DYNAMIC_FTRACE */
+ struct plt_entry *ftrace_trampolines;
};

struct plt_entry {
- u32 inst_lu12iw;
+ u32 inst_addu16id;
u32 inst_lu32id;
u32 inst_lu52id;
u32 inst_jirl;
@@ -36,14 +39,15 @@ Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val);

static inline struct plt_entry emit_plt_entry(unsigned long val)
{
- u32 lu12iw, lu32id, lu52id, jirl;
+ u32 addu16id, lu32id, lu52id, jirl;

- lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) | LOONGARCH_GPR_T1);
+ addu16id = larch_insn_gen_addu16id(LOONGARCH_GPR_T1, LOONGARCH_GPR_ZERO,
+ ADDR_IMM(val, ADDU16ID));
lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
- jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));
+ jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xffff));

- return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
+ return (struct plt_entry) { addu16id, lu32id, lu52id, jirl };
}

static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
diff --git a/arch/loongarch/include/asm/module.lds.h b/arch/loongarch/include/asm/module.lds.h
index 31c1c0db11a3..ecff54b81754 100644
--- a/arch/loongarch/include/asm/module.lds.h
+++ b/arch/loongarch/include/asm/module.lds.h
@@ -4,4 +4,5 @@ SECTIONS {
. = ALIGN(4);
.plt : { BYTE(0) }
.plt.idx : { BYTE(0) }
+ .ftrace_trampoline : { BYTE(0) }
}
diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c
index ec3d951be50c..a7c36b92e558 100644
--- a/arch/loongarch/kernel/ftrace_dyn.c
+++ b/arch/loongarch/kernel/ftrace_dyn.c
@@ -9,6 +9,7 @@
#include <linux/uaccess.h>

#include <asm/inst.h>
+#include <asm/module.h>

static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
bool validate)
@@ -72,12 +73,63 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
return ftrace_modify_code(pc, old, new, true);
}

+static inline int __get_mod(struct module **mod, unsigned long addr)
+{
+ preempt_disable();
+ *mod = __module_text_address(addr);
+ preempt_enable();
+
+ if (WARN_ON(!(*mod)))
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
+{
+ struct plt_entry *plt = mod->arch.ftrace_trampolines;
+
+ if (addr == FTRACE_ADDR)
+ return &plt[FTRACE_PLT_IDX];
+ if (addr == FTRACE_REGS_ADDR &&
+ IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
+ return &plt[FTRACE_REGS_PLT_IDX];
+
+ return NULL;
+}
+
+static unsigned long get_plt_addr(struct module *mod, unsigned long addr)
+{
+ struct plt_entry *plt;
+
+ plt = get_ftrace_plt(mod, addr);
+ if (!plt) {
+ pr_err("ftrace: no module PLT for %ps\n", (void *)addr);
+ return -EINVAL;
+ }
+
+ return (unsigned long)plt;
+}
+
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
unsigned long pc;
+ long offset;
u32 old, new;

pc = rec->ip + LOONGARCH_INSN_SIZE;
+ offset = (long)pc - (long)addr;
+
+ if (offset < -SZ_128M || offset >= SZ_128M) {
+ int ret;
+ struct module *mod;
+
+ ret = __get_mod(&mod, pc);
+ if (ret)
+ return ret;
+
+ addr = get_plt_addr(mod, addr);
+ }

old = larch_insn_gen_nop();
new = larch_insn_gen_bl(pc, addr);
@@ -89,9 +141,22 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
unsigned long addr)
{
unsigned long pc;
+ long offset;
u32 old, new;

pc = rec->ip + LOONGARCH_INSN_SIZE;
+ offset = (long)pc - (long)addr;
+
+ if (offset < -SZ_128M || offset >= SZ_128M) {
+ int ret;
+ struct module *mod;
+
+ ret = __get_mod(&mod, pc);
+ if (ret)
+ return ret;
+
+ addr = get_plt_addr(mod, addr);
+ }

new = larch_insn_gen_nop();
old = larch_insn_gen_bl(pc, addr);
@@ -108,6 +173,20 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
u32 old, new;

pc = rec->ip + LOONGARCH_INSN_SIZE;
+ offset = (long)pc - (long)addr;
+
+ if (offset < -SZ_128M || offset >= SZ_128M) {
+ int ret;
+ struct module *mod;
+
+ ret = __get_mod(&mod, pc);
+ if (ret)
+ return ret;
+
+ addr = get_plt_addr(mod, addr);
+
+ old_addr = get_plt_addr(mod, old_addr);
+ }

old = larch_insn_gen_bl(pc, old_addr);
new = larch_insn_gen_bl(pc, addr);
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index 4f7a62ddf210..9a1769620b25 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -103,6 +103,18 @@ u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
return insn.word;
}

+u32 larch_insn_gen_addu16id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
+{
+ union loongarch_instruction insn;
+
+ insn.reg2i16_format.opcode = addu16id_op;
+ insn.reg2i16_format.rd = rd;
+ insn.reg2i16_format.rj = rj;
+ insn.reg2i16_format.immediate = imm;
+
+ return insn.word;
+}
+
u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
{
union loongarch_instruction insn;
diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
index 6d498288977d..b75fc711f144 100644
--- a/arch/loongarch/kernel/module-sections.c
+++ b/arch/loongarch/kernel/module-sections.c
@@ -4,6 +4,7 @@
*/

#include <linux/elf.h>
+#include <linux/ftrace.h>
#include <linux/kernel.h>
#include <linux/module.h>

@@ -67,6 +68,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
char *secstrings, struct module *mod)
{
unsigned int i, num_plts = 0;
+ Elf_Shdr *tramp = NULL;

/*
* Find the empty .plt sections.
@@ -76,6 +78,8 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
mod->arch.plt.shdr = sechdrs + i;
else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx"))
mod->arch.plt_idx.shdr = sechdrs + i;
+ else if (!strcmp(secstrings + sechdrs[i].sh_name, ".ftrace_trampoline"))
+ tramp = sechdrs + i;
}

if (!mod->arch.plt.shdr) {
@@ -117,5 +121,12 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
mod->arch.plt_idx.num_entries = 0;
mod->arch.plt_idx.max_entries = num_plts;

+ if (tramp) {
+ tramp->sh_type = SHT_NOBITS;
+ tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ tramp->sh_addralign = __alignof__(struct plt_entry);
+ tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
+ }
+
return 0;
}
diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
index 638427ff0d51..acb75bccb6c5 100644
--- a/arch/loongarch/kernel/module.c
+++ b/arch/loongarch/kernel/module.c
@@ -10,6 +10,7 @@

#include <linux/moduleloader.h>
#include <linux/elf.h>
+#include <linux/ftrace.h>
#include <linux/mm.h>
#include <linux/numa.h>
#include <linux/vmalloc.h>
@@ -17,6 +18,7 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <asm/inst.h>

static inline bool signed_imm_check(long val, unsigned int bit)
{
@@ -373,3 +375,49 @@ void *module_alloc(unsigned long size)
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0));
}
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ const char *name)
+{
+ const Elf_Shdr *s, *se;
+ const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
+ if (strcmp(name, secstrs + s->sh_name) == 0)
+ return s;
+ }
+
+ return NULL;
+}
+#endif
+
+static int module_init_ftrace_plt(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *mod)
+{
+#ifdef CONFIG_DYNAMIC_FTRACE
+ const Elf_Shdr *s;
+ struct plt_entry *ftrace_plts;
+
+ s = find_section(hdr, sechdrs, ".ftrace_trampoline");
+ if (!s)
+ return -ENOEXEC;
+
+ ftrace_plts = (void *)s->sh_addr;
+
+ ftrace_plts[FTRACE_PLT_IDX] = emit_plt_entry(FTRACE_ADDR);
+
+ if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
+ ftrace_plts[FTRACE_REGS_PLT_IDX] = emit_plt_entry(FTRACE_REGS_ADDR);
+
+ mod->arch.ftrace_trampolines = ftrace_plts;
+#endif
+ return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
+{
+ module_init_ftrace_plt(hdr, sechdrs, mod);
+
+ return 0;
+}
--
2.36.1


2022-08-19 08:33:56

by Qing Zhang

[permalink] [raw]
Subject: [PATCH 9/9] LoongArch: Enable CONFIG_KALLSYMS_ALL and CONFIG_DEBUG_FS

Defaults enable CONFIG_KALLSYMS_ALL and CONFIG_DEBUG_FS to convenient
ftrace tests.

Signed-off-by: Qing Zhang <[email protected]>
---
arch/loongarch/configs/loongson3_defconfig | 60 +++++-----------------
1 file changed, 13 insertions(+), 47 deletions(-)

diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig
index 3712552e18d3..c48c31a7286a 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson3_defconfig
@@ -33,29 +33,15 @@ CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
-CONFIG_USERFAULTFD=y
+CONFIG_KALLSYMS_ALL=y
CONFIG_PERF_EVENTS=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_LOONGARCH=y
-CONFIG_64BIT=y
-CONFIG_MACH_LOONGSON64=y
-CONFIG_DMI=y
-CONFIG_EFI=y
-CONFIG_SMP=y
CONFIG_HOTPLUG_CPU=y
-CONFIG_NR_CPUS=64
CONFIG_NUMA=y
-CONFIG_PAGE_SIZE_16KB=y
-CONFIG_HZ_250=y
-CONFIG_ACPI=y
CONFIG_ACPI_SPCR_TABLE=y
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_TAD=y
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_IPMI=m
CONFIG_ACPI_PCI_SLOT=y
CONFIG_ACPI_HOTPLUG_MEMORY=y
-CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
CONFIG_EFI_CAPSULE_LOADER=m
CONFIG_EFI_TEST=m
CONFIG_MODULES=y
@@ -68,17 +54,16 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_IOSCHED_BFQ=y
CONFIG_BFQ_GROUP_IOSCHED=y
CONFIG_BINFMT_MISC=m
+CONFIG_ZSWAP=y
+CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y
+CONFIG_Z3FOLD=y
+# CONFIG_COMPAT_BRK is not set
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_KSM=y
CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_ZSWAP=y
-CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y
-CONFIG_ZPOOL=y
-CONFIG_ZBUD=y
-CONFIG_Z3FOLD=y
-CONFIG_ZSMALLOC=m
+CONFIG_USERFAULTFD=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -108,14 +93,12 @@ CONFIG_NETFILTER=y
CONFIG_BRIDGE_NETFILTER=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_NETBIOS_NS=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_TABLES=m
-CONFIG_NFT_COUNTER=m
CONFIG_NFT_CONNLIMIT=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
@@ -292,7 +275,6 @@ CONFIG_RFKILL=m
CONFIG_RFKILL_INPUT=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
-CONFIG_CEPH_LIB=m
CONFIG_PCIEPORTBUS=y
CONFIG_HOTPLUG_PCI_PCIE=y
CONFIG_PCIEAER=y
@@ -329,7 +311,6 @@ CONFIG_PARPORT_PC_FIFO=y
CONFIG_ZRAM=m
CONFIG_ZRAM_DEF_COMP_ZSTD=y
CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=y
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
@@ -374,7 +355,6 @@ CONFIG_SCSI_QLOGIC_1280=m
CONFIG_SCSI_QLA_FC=m
CONFIG_TCM_QLA2XXX=m
CONFIG_SCSI_QLA_ISCSI=m
-CONFIG_SCSI_LPFC=m
CONFIG_SCSI_VIRTIO=m
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
@@ -382,12 +362,7 @@ CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_PATA_ATIIXP=y
CONFIG_PATA_PCMCIA=m
CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-CONFIG_MD_RAID10=m
-CONFIG_MD_RAID456=m
CONFIG_MD_MULTIPATH=m
CONFIG_BCACHE=m
CONFIG_BLK_DEV_DM=y
@@ -432,13 +407,11 @@ CONFIG_VIRTIO_NET=m
# CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_ATHEROS is not set
CONFIG_BNX2=y
-# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CAVIUM is not set
CONFIG_CHELSIO_T1=m
CONFIG_CHELSIO_T1_1G=y
CONFIG_CHELSIO_T3=m
CONFIG_CHELSIO_T4=m
-# CONFIG_NET_VENDOR_CIRRUS is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
@@ -459,6 +432,7 @@ CONFIG_IXGBE=y
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_QUALCOMM is not set
# CONFIG_NET_VENDOR_RDC is not set
CONFIG_8139CP=m
@@ -468,9 +442,9 @@ CONFIG_R8169=y
# CONFIG_NET_VENDOR_ROCKER is not set
# CONFIG_NET_VENDOR_SAMSUNG is not set
# CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_SOLARFLARE is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
# CONFIG_NET_VENDOR_SMSC is not set
CONFIG_STMMAC_ETH=y
# CONFIG_NET_VENDOR_SUN is not set
@@ -505,7 +479,6 @@ CONFIG_ATH9K_HTC=m
CONFIG_IWLWIFI=m
CONFIG_IWLDVM=m
CONFIG_IWLMVM=m
-CONFIG_IWLWIFI_BCAST_FILTERING=y
CONFIG_HOSTAP=m
CONFIG_MT7601U=m
CONFIG_RT2X00=m
@@ -556,7 +529,6 @@ CONFIG_I2C_PIIX4=y
CONFIG_I2C_GPIO=y
CONFIG_SPI=y
CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_LOONGSON=y
CONFIG_SENSORS_LM75=m
CONFIG_SENSORS_LM93=m
CONFIG_SENSORS_W83795=m
@@ -564,16 +536,16 @@ CONFIG_SENSORS_W83627HF=m
CONFIG_RC_CORE=m
CONFIG_LIRC=y
CONFIG_RC_DECODERS=y
+CONFIG_IR_IMON_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
CONFIG_IR_NEC_DECODER=m
CONFIG_IR_RC5_DECODER=m
CONFIG_IR_RC6_DECODER=m
-CONFIG_IR_JVC_DECODER=m
-CONFIG_IR_SONY_DECODER=m
CONFIG_IR_SANYO_DECODER=m
CONFIG_IR_SHARP_DECODER=m
-CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_SONY_DECODER=m
CONFIG_IR_XMP_DECODER=m
-CONFIG_IR_IMON_DECODER=m
CONFIG_MEDIA_SUPPORT=m
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
@@ -593,7 +565,6 @@ CONFIG_DRM_VIRTIO_GPU=m
CONFIG_FB=y
CONFIG_FB_EFI=y
CONFIG_FB_RADEON=y
-CONFIG_LCD_PLATFORM=m
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
@@ -602,7 +573,6 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SEQUENCER=m
CONFIG_SND_SEQ_DUMMY=m
-# CONFIG_SND_ISA is not set
CONFIG_SND_BT87X=m
CONFIG_SND_BT87X_OVERCLOCK=y
CONFIG_SND_HDA_INTEL=y
@@ -628,7 +598,6 @@ CONFIG_HID_MULTITOUCH=m
CONFIG_HID_SUNPLUS=m
CONFIG_USB_HIDDEV=y
CONFIG_USB=y
-CONFIG_USB_OTG=y
CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
@@ -688,7 +657,6 @@ CONFIG_COMEDI_NI_PCIDIO=m
CONFIG_COMEDI_NI_PCIMIO=m
CONFIG_STAGING=y
CONFIG_R8188EU=m
-# CONFIG_88EU_AP_MODE is not set
CONFIG_PM_DEVFREQ=y
CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
CONFIG_DEVFREQ_GOV_PERFORMANCE=y
@@ -770,16 +738,13 @@ CONFIG_CRYPTO_USER=m
CONFIG_CRYPTO_PCRYPT=m
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_CHACHA20POLY1305=m
-CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SALSA20=m
CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
@@ -797,6 +762,7 @@ CONFIG_CRYPTO_DEV_VIRTIO=m
CONFIG_PRINTK_TIME=y
CONFIG_STRIP_ASM_SYMS=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_PREEMPT is not set
--
2.36.1

2022-08-19 08:38:11

by Qing Zhang

[permalink] [raw]
Subject: [PATCH 7/9] Loongarch/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support

Ftrace_graph_ret_addr can be called by stack unwinding code to convert
a found stack return address ('ret') to its original value, in case the
function graph tracer has modified it to be 'return_to_handler',If the
hasn't been modified, the unchanged value of 'ret' is returned.

Signed-off-by: Qing Zhang <[email protected]>
---
arch/loongarch/include/asm/ftrace.h | 3 +++
arch/loongarch/include/asm/unwind.h | 1 +
arch/loongarch/kernel/ftrace_dyn.c | 2 +-
arch/loongarch/kernel/unwind_guess.c | 4 +++-
arch/loongarch/kernel/unwind_prologue.c | 10 +++++++++-
5 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
index 0ed3d649c1ba..f96adef0e4a5 100644
--- a/arch/loongarch/include/asm/ftrace.h
+++ b/arch/loongarch/include/asm/ftrace.h
@@ -10,6 +10,8 @@
#define FTRACE_REGS_PLT_IDX 1
#define NR_FTRACE_PLTS 2

+#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
+
#ifdef CONFIG_FUNCTION_TRACER
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */

@@ -20,6 +22,7 @@ extern void _mcount(void);
#endif

#ifdef CONFIG_DYNAMIC_FTRACE
+#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
return addr;
diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/asm/unwind.h
index 6af4718bdf01..f66b07c3e6a1 100644
--- a/arch/loongarch/include/asm/unwind.h
+++ b/arch/loongarch/include/asm/unwind.h
@@ -21,6 +21,7 @@ struct unwind_state {
struct stack_info stack_info;
struct task_struct *task;
bool first, error;
+ int graph_idx;
unsigned long sp, pc, ra;
};

diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c
index a7c36b92e558..53961e5890fd 100644
--- a/arch/loongarch/kernel/ftrace_dyn.c
+++ b/arch/loongarch/kernel/ftrace_dyn.c
@@ -219,7 +219,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent)

old = *parent;

- if (!function_graph_enter(old, self_addr, 0, NULL))
+ if (!function_graph_enter(old, self_addr, 0, parent))
*parent = return_hooker;
}

diff --git a/arch/loongarch/kernel/unwind_guess.c b/arch/loongarch/kernel/unwind_guess.c
index 5afa6064d73e..229ba014cea0 100644
--- a/arch/loongarch/kernel/unwind_guess.c
+++ b/arch/loongarch/kernel/unwind_guess.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2022 Loongson Technology Corporation Limited
*/
+#include <linux/ftrace.h>
#include <linux/kernel.h>

#include <asm/unwind.h>
@@ -53,7 +54,8 @@ bool unwind_next_frame(struct unwind_state *state)
state->sp < info->end;
state->sp += sizeof(unsigned long)) {
addr = *(unsigned long *)(state->sp);
-
+ state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
+ addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
if (__kernel_text_address(addr))
return true;
}
diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c
index b206d9159205..03f8b31a90cc 100644
--- a/arch/loongarch/kernel/unwind_prologue.c
+++ b/arch/loongarch/kernel/unwind_prologue.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2022 Loongson Technology Corporation Limited
*/
+#include <linux/ftrace.h>
#include <linux/kallsyms.h>

#include <asm/inst.h>
@@ -32,6 +33,8 @@ static bool unwind_by_guess(struct unwind_state *state)
state->sp < info->end;
state->sp += sizeof(unsigned long)) {
addr = *(unsigned long *)(state->sp);
+ state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
+ addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
if (__kernel_text_address(addr))
return true;
}
@@ -146,8 +149,11 @@ bool unwind_next_frame(struct unwind_state *state)
break;

case UNWINDER_PROLOGUE:
- if (unwind_by_prologue(state))
+ if (unwind_by_prologue(state)) {
+ state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
+ state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
return true;
+ }

if (info->type == STACK_TYPE_IRQ &&
info->end == state->sp) {
@@ -159,6 +165,8 @@ bool unwind_next_frame(struct unwind_state *state)

state->pc = pc;
state->sp = regs->regs[3];
+ state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
+ pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
state->ra = regs->regs[1];
state->first = true;
get_stack_info(state->sp, state->task, info);
--
2.36.1

2022-08-19 10:54:43

by Jinyang He

[permalink] [raw]
Subject: Re: [PATCH 6/9] LoongArch: modules/ftrace: Initialize PLT at load time

On 2022/8/19 16:16, Qing Zhang wrote:

> To Implement ftrace trampiones through plt entry.
>
> Tested by forcing ftrace_make_call() to use the module PLT, and then
> loading up a module after setting up ftrace with:
>
> | echo ":mod:<module-name>" > set_ftrace_filter;
> | echo function > current_tracer;
> | modprobe <module-name>
>
> Since FTRACE_ADDR/FTRACE_REGS_ADDR is only defined when CONFIG_DYNAMIC_FTRACE
> is selected, we wrap its use along with most of module_init_ftrace_plt() with
> ifdeffery rather than using IS_ENABLED().
>
> Signed-off-by: Qing Zhang <[email protected]>
> ---
> arch/loongarch/include/asm/ftrace.h | 4 ++
> arch/loongarch/include/asm/inst.h | 2 +
> arch/loongarch/include/asm/module.h | 14 +++--
> arch/loongarch/include/asm/module.lds.h | 1 +
> arch/loongarch/kernel/ftrace_dyn.c | 79 +++++++++++++++++++++++++
> arch/loongarch/kernel/inst.c | 12 ++++
> arch/loongarch/kernel/module-sections.c | 11 ++++
> arch/loongarch/kernel/module.c | 48 +++++++++++++++
> 8 files changed, 166 insertions(+), 5 deletions(-)
[...]
> @@ -36,14 +39,15 @@ Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val);
>
> static inline struct plt_entry emit_plt_entry(unsigned long val)
> {
> - u32 lu12iw, lu32id, lu52id, jirl;
> + u32 addu16id, lu32id, lu52id, jirl;
>
> - lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) | LOONGARCH_GPR_T1);
> + addu16id = larch_insn_gen_addu16id(LOONGARCH_GPR_T1, LOONGARCH_GPR_ZERO,
> + ADDR_IMM(val, ADDU16ID));

Hi, Qing,

Why change lu12iw to addu16id? They have same effect here.


> lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
> lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
> - jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));
> + jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xffff));
>
> - return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
> + return (struct plt_entry) { addu16id, lu32id, lu52id, jirl };
> }
[...]
> +static int module_init_ftrace_plt(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
> + struct module *mod)
> +{
> +#ifdef CONFIG_DYNAMIC_FTRACE
> + const Elf_Shdr *s;
> + struct plt_entry *ftrace_plts;
> +
> + s = find_section(hdr, sechdrs, ".ftrace_trampoline");
> + if (!s)
> + return -ENOEXEC;

Return value is not used later, may we do something or drop returning value.

Thanks,

Jinyang

> +
> + ftrace_plts = (void *)s->sh_addr;
> +
> + ftrace_plts[FTRACE_PLT_IDX] = emit_plt_entry(FTRACE_ADDR);
> +
> + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
> + ftrace_plts[FTRACE_REGS_PLT_IDX] = emit_plt_entry(FTRACE_REGS_ADDR);
> +
> + mod->arch.ftrace_trampolines = ftrace_plts;
> +#endif
> + return 0;
> +}
> +
> +int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
> +{
> + module_init_ftrace_plt(hdr, sechdrs, mod);
> +
> + return 0;
> +}

2022-08-20 01:49:33

by Qing Zhang

[permalink] [raw]
Subject: Re: [PATCH 6/9] LoongArch: modules/ftrace: Initialize PLT at load time



On 2022/8/19 下午6:43, Jinyang He wrote:
> On 2022/8/19 16:16, Qing Zhang wrote:
>
>> To Implement ftrace trampiones through plt entry.
>>
>> Tested by forcing ftrace_make_call() to use the module PLT, and then
>> loading up a module after setting up ftrace with:
>>
>> | echo ":mod:<module-name>" > set_ftrace_filter;
>> | echo function > current_tracer;
>> | modprobe <module-name>
>>
>> Since FTRACE_ADDR/FTRACE_REGS_ADDR is only defined when
>> CONFIG_DYNAMIC_FTRACE
>> is selected, we wrap its use along with most of
>> module_init_ftrace_plt() with
>> ifdeffery rather than using IS_ENABLED().
>>
>> Signed-off-by: Qing Zhang <[email protected]>
>> ---
>>   arch/loongarch/include/asm/ftrace.h     |  4 ++
>>   arch/loongarch/include/asm/inst.h       |  2 +
>>   arch/loongarch/include/asm/module.h     | 14 +++--
>>   arch/loongarch/include/asm/module.lds.h |  1 +
>>   arch/loongarch/kernel/ftrace_dyn.c      | 79 +++++++++++++++++++++++++
>>   arch/loongarch/kernel/inst.c            | 12 ++++
>>   arch/loongarch/kernel/module-sections.c | 11 ++++
>>   arch/loongarch/kernel/module.c          | 48 +++++++++++++++
>>   8 files changed, 166 insertions(+), 5 deletions(-)
> [...]
>> @@ -36,14 +39,15 @@ Elf_Addr module_emit_plt_entry(struct module *mod,
>> unsigned long val);
>>   static inline struct plt_entry emit_plt_entry(unsigned long val)
>>   {
>> -    u32 lu12iw, lu32id, lu52id, jirl;
>> +    u32 addu16id, lu32id, lu52id, jirl;
>> -    lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) |
>> LOONGARCH_GPR_T1);
>> +    addu16id = larch_insn_gen_addu16id(LOONGARCH_GPR_T1,
>> LOONGARCH_GPR_ZERO,
>> +        ADDR_IMM(val, ADDU16ID));
>
> Hi, Qing,
>
> Why change lu12iw to addu16id? They have same effect here.
>
Hi. Jinyang

Yes, the effect is the same.
I will modify it to lu12iw in V2, which can be consistent with the
user's plt style.

Thanks,
- Qing

>
>>       lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val,
>> LU32ID));
>>       lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1,
>> LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
>> -    jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));
>> +    jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xffff));
>> -    return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
>> +    return (struct plt_entry) { addu16id, lu32id, lu52id, jirl };
>>   }
> [...]
>> +static int module_init_ftrace_plt(const Elf_Ehdr *hdr, const Elf_Shdr
>> *sechdrs,
>> +                  struct module *mod)
>> +{
>> +#ifdef CONFIG_DYNAMIC_FTRACE
>> +    const Elf_Shdr *s;
>> +    struct plt_entry *ftrace_plts;
>> +
>> +    s = find_section(hdr, sechdrs, ".ftrace_trampoline");
>> +    if (!s)
>> +        return -ENOEXEC;
>
> Return value is not used later, may we do something or drop returning
> value.
>
Yes, Should return module_init_ftrace_plt(hdr, sechdrs, mod) here.

Thanks,
-Qing
> Thanks,
>
> Jinyang
>
>> +
>> +    ftrace_plts = (void *)s->sh_addr;
>> +
>> +    ftrace_plts[FTRACE_PLT_IDX] = emit_plt_entry(FTRACE_ADDR);
>> +
>> +    if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
>> +        ftrace_plts[FTRACE_REGS_PLT_IDX] =
>> emit_plt_entry(FTRACE_REGS_ADDR);
>> +
>> +    mod->arch.ftrace_trampolines = ftrace_plts;
>> +#endif
>> +    return 0;
>> +}
>> +
>> +int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
>> struct module *mod)
>> +{
>> +    module_init_ftrace_plt(hdr, sechdrs, mod);
>> +
>> +    return 0;
>> +}
>