text: // SPDX-License-Identifier: MIT
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/perf_event.h>
  #include <linux/bug.h>
  #include <linux/stddef.h>
  #include <asm/perf_regs.h>
  #include <asm/ptrace.h>
  #include "kdks_i.h"
  #include "dks_perf_regs.h"
  
  //#define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
  
  /*kernel pt_regs offset*/
  static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
  	PT_REGS_OFFSET(PERF_REG_X86_AX, ax),
  	PT_REGS_OFFSET(PERF_REG_X86_BX, bx),
  	PT_REGS_OFFSET(PERF_REG_X86_CX, cx),
  	PT_REGS_OFFSET(PERF_REG_X86_DX, dx),
  	PT_REGS_OFFSET(PERF_REG_X86_SI, si),
  	PT_REGS_OFFSET(PERF_REG_X86_DI, di),
  	PT_REGS_OFFSET(PERF_REG_X86_BP, bp),
  	PT_REGS_OFFSET(PERF_REG_X86_SP, sp),
  	PT_REGS_OFFSET(PERF_REG_X86_IP, ip),
  	PT_REGS_OFFSET(PERF_REG_X86_FLAGS, flags),
  	PT_REGS_OFFSET(PERF_REG_X86_CS, cs),
  	PT_REGS_OFFSET(PERF_REG_X86_SS, ss),
  #ifdef CONFIG_X86_32
  	PT_REGS_OFFSET(PERF_REG_X86_DS, ds),
  	PT_REGS_OFFSET(PERF_REG_X86_ES, es),
  	PT_REGS_OFFSET(PERF_REG_X86_FS, fs),
  	PT_REGS_OFFSET(PERF_REG_X86_GS, gs),
  #else
  	/*
  	 * The pt_regs struct does not store
  	 * ds, es, fs, gs in 64 bit mode.
  	 */
  	(unsigned int) -1,
  	(unsigned int) -1,
  	(unsigned int) -1,
  	(unsigned int) -1,
  #endif
  #ifdef CONFIG_X86_64
  	PT_REGS_OFFSET(PERF_REG_X86_R8, r8),
  	PT_REGS_OFFSET(PERF_REG_X86_R9, r9),
  	PT_REGS_OFFSET(PERF_REG_X86_R10, r10),
  	PT_REGS_OFFSET(PERF_REG_X86_R11, r11),
  	PT_REGS_OFFSET(PERF_REG_X86_R12, r12),
  	PT_REGS_OFFSET(PERF_REG_X86_R13, r13),
  	PT_REGS_OFFSET(PERF_REG_X86_R14, r14),
  	PT_REGS_OFFSET(PERF_REG_X86_R15, r15),
  #endif
  };
  
  const struct regname_offset regname_to_perf_reg[] = {
  	REGNAME_MAPPING(rax, PERF_REG_X86_AX, X86_REG_QWORD),
  	REGNAME_MAPPING(eax, PERF_REG_X86_AX, X86_REG_DWORD),
  	REGNAME_MAPPING(ax,  PERF_REG_X86_AX, X86_REG_WORD),
  	REGNAME_MAPPING(ah,  PERF_REG_X86_AX, X86_REG_HIGH),
  	REGNAME_MAPPING(al,  PERF_REG_X86_AX, X86_REG_LOW),
  
  	REGNAME_MAPPING(rbx, PERF_REG_X86_BX, X86_REG_QWORD),
  	REGNAME_MAPPING(ebx, PERF_REG_X86_BX, X86_REG_DWORD),
  	REGNAME_MAPPING(bx,  PERF_REG_X86_BX, X86_REG_WORD),
  	REGNAME_MAPPING(bh,  PERF_REG_X86_BX, X86_REG_HIGH),
  	REGNAME_MAPPING(bl,  PERF_REG_X86_BX, X86_REG_LOW),
  
  	REGNAME_MAPPING(rcx, PERF_REG_X86_CX, X86_REG_QWORD),
  	REGNAME_MAPPING(ecx, PERF_REG_X86_CX, X86_REG_DWORD),
  	REGNAME_MAPPING(cx,  PERF_REG_X86_CX, X86_REG_WORD),
  	REGNAME_MAPPING(ch,  PERF_REG_X86_CX, X86_REG_HIGH),
  	REGNAME_MAPPING(cl,  PERF_REG_X86_CX, X86_REG_LOW),
  
  	REGNAME_MAPPING(rdx, PERF_REG_X86_DX, X86_REG_QWORD),
  	REGNAME_MAPPING(edx, PERF_REG_X86_DX, X86_REG_DWORD),
  	REGNAME_MAPPING(dx,  PERF_REG_X86_DX, X86_REG_WORD),
  	REGNAME_MAPPING(dh,  PERF_REG_X86_DX, X86_REG_HIGH),
  	REGNAME_MAPPING(dl,  PERF_REG_X86_DX, X86_REG_LOW),
  
  	REGNAME_MAPPING(rsi, PERF_REG_X86_SI, X86_REG_QWORD),
  	REGNAME_MAPPING(esi, PERF_REG_X86_SI, X86_REG_DWORD),
  	REGNAME_MAPPING(si,  PERF_REG_X86_SI, X86_REG_WORD),
  	REGNAME_MAPPING(sil, PERF_REG_X86_SI, X86_REG_LOW),
  
  	REGNAME_MAPPING(rdi, PERF_REG_X86_DI, X86_REG_QWORD),
  	REGNAME_MAPPING(edi, PERF_REG_X86_DI, X86_REG_DWORD),
  	REGNAME_MAPPING(di,  PERF_REG_X86_DI, X86_REG_WORD),
  	REGNAME_MAPPING(dil, PERF_REG_X86_DI, X86_REG_LOW),
  
  	REGNAME_MAPPING(rbp, PERF_REG_X86_BP, X86_REG_QWORD),
  	REGNAME_MAPPING(ebp, PERF_REG_X86_BP, X86_REG_DWORD),
  	REGNAME_MAPPING(bp,  PERF_REG_X86_BP, X86_REG_WORD),
  	REGNAME_MAPPING(bpl, PERF_REG_X86_BP, X86_REG_LOW),
  
  	REGNAME_MAPPING(rsp, PERF_REG_X86_SP, X86_REG_QWORD),
  	REGNAME_MAPPING(esp, PERF_REG_X86_SP, X86_REG_DWORD),
  	REGNAME_MAPPING(sp,  PERF_REG_X86_SP, X86_REG_WORD),
  	REGNAME_MAPPING(spl, PERF_REG_X86_SP, X86_REG_LOW),
  
  	REGNAME_MAPPING(rip, PERF_REG_X86_IP, X86_REG_QWORD),
  	REGNAME_MAPPING(eip, PERF_REG_X86_IP, X86_REG_DWORD),
  
  	REGNAME_MAPPING(rflags, PERF_REG_X86_FLAGS, X86_REG_QWORD),
  	REGNAME_MAPPING(eflags, PERF_REG_X86_FLAGS, X86_REG_DWORD),
  	REGNAME_MAPPING(flags,  PERF_REG_X86_FLAGS, X86_REG_WORD),
  
  	REGNAME_MAPPING(cs, PERF_REG_X86_CS, X86_REG_WORD),
  	REGNAME_MAPPING(ss, PERF_REG_X86_SS, X86_REG_WORD),
  #ifdef CONFIG_X86_32
  	REGNAME_MAPPING(ds, PERF_REGS_X86_DS, X86_REG_WORD),
  	REGNAME_MAPPING(es, PERF_REGS_X86_ES, X86_REG_WORD),
  	REGNAME_MAPPING(fs, PERF_REGS_X86_FS, X86_REG_WORD),
  	REGNAME_MAPPING(gs, PERF_REGS_X86_GS, X86_REG_WORD),
  #else
  	REGNAME_MAPPING(r8,  PERF_REG_X86_R8, X86_REG_QWORD),
  	REGNAME_MAPPING(r8d, PERF_REG_X86_R8, X86_REG_DWORD),
  	REGNAME_MAPPING(r8w, PERF_REG_X86_R8, X86_REG_WORD),
  	REGNAME_MAPPING(r8b, PERF_REG_X86_R8, X86_REG_LOW),
  
  	REGNAME_MAPPING(r9,  PERF_REG_X86_R9, X86_REG_QWORD),
  	REGNAME_MAPPING(r9d, PERF_REG_X86_R9, X86_REG_DWORD),
  	REGNAME_MAPPING(r9w, PERF_REG_X86_R9, X86_REG_WORD),
  	REGNAME_MAPPING(r9b, PERF_REG_X86_R9, X86_REG_LOW),
  
  	REGNAME_MAPPING(r10,  PERF_REG_X86_R10, X86_REG_QWORD),
  	REGNAME_MAPPING(r10d, PERF_REG_X86_R10, X86_REG_DWORD),
  	REGNAME_MAPPING(r10w, PERF_REG_X86_R10, X86_REG_WORD),
  	REGNAME_MAPPING(r10b, PERF_REG_X86_R10, X86_REG_LOW),
  
  	REGNAME_MAPPING(r11,  PERF_REG_X86_R11, X86_REG_QWORD),
  	REGNAME_MAPPING(r11d, PERF_REG_X86_R11, X86_REG_DWORD),
  	REGNAME_MAPPING(r11w, PERF_REG_X86_R11, X86_REG_WORD),
  	REGNAME_MAPPING(r11b, PERF_REG_X86_R11, X86_REG_LOW),
  
  	REGNAME_MAPPING(r12,  PERF_REG_X86_R12, X86_REG_QWORD),
  	REGNAME_MAPPING(r12d, PERF_REG_X86_R12, X86_REG_DWORD),
  	REGNAME_MAPPING(r12w, PERF_REG_X86_R12, X86_REG_WORD),
  	REGNAME_MAPPING(r12b, PERF_REG_X86_R12, X86_REG_LOW),
  
  	REGNAME_MAPPING(r13,  PERF_REG_X86_R13, X86_REG_QWORD),
  	REGNAME_MAPPING(r13d, PERF_REG_X86_R13, X86_REG_DWORD),
  	REGNAME_MAPPING(r13w, PERF_REG_X86_R13, X86_REG_WORD),
  	REGNAME_MAPPING(r13b, PERF_REG_X86_R13, X86_REG_LOW),
  
  	REGNAME_MAPPING(r14,  PERF_REG_X86_R14, X86_REG_QWORD),
  	REGNAME_MAPPING(r14d, PERF_REG_X86_R14, X86_REG_DWORD),
  	REGNAME_MAPPING(r14w, PERF_REG_X86_R14, X86_REG_WORD),
  	REGNAME_MAPPING(r14b, PERF_REG_X86_R14, X86_REG_LOW),
  
  	REGNAME_MAPPING(r15,  PERF_REG_X86_R15, X86_REG_QWORD),
  	REGNAME_MAPPING(r15d, PERF_REG_X86_R15, X86_REG_DWORD),
  	REGNAME_MAPPING(r15w, PERF_REG_X86_R15, X86_REG_WORD),
  	REGNAME_MAPPING(r15b, PERF_REG_X86_R15, X86_REG_LOW),
  #endif
  	REGNAME_MAPPING_END,
  };
  
  /*This is not export_symbol,
    so copied it from kernel source*/
  u64 perf_regs__get_reg_value(struct pt_regs *regs, int idx)
  {
  	const struct regname_offset *roff;
  	unsigned long val = 0;
  	union x86_64_reg ret;
  
  	if (WARN_ON_ONCE(idx >= ARRAY_SIZE(regname_to_perf_reg)))
  		return KDKS_INVALID_ADDR;
  
  	roff = &regname_to_perf_reg[idx];
  	val = regs_get_register(regs, pt_regs_offset[roff->perf_offset]);
  	if(!val)
  		return KDKS_INVALID_ADDR; 
  
  	ret.q = (u64) val;
  	/*get width*/
  	switch(roff->reg_width){
  		case X86_REG_QWORD:
  			return ret.q;
  		case X86_REG_DWORD:
  			return (u64)ret.d;
  		case X86_REG_WORD:
  			return (u64)ret.w;
  		case X86_REG_LOW:
  			return (u64)ret.b[0];
  		case X86_REG_HIGH:
  			return (u64)ret.b[1];
  		default:
  			break;
  	}
  
  	return KDKS_INVALID_ADDR;
  }
  
  /*get register id from a name - user_regname translated to perf_regname*/
  u16 perf_regs__regname_to_offset(const char* perf_reg) {
  	u16 idx = 0; /*index of regname mapping table*/
  	const struct regname_offset *roff;
  
  	for(roff = regname_to_perf_reg; roff->name != NULL; roff++, idx++){
  		if(strcmp(roff->name, perf_reg) == 0){
  			return idx;
  		}
  	}
  
  	return USHRT_MAX;
  }
  
  const char *perf_regs__get_reg_name(u16 idx){
  	if (WARN_ON_ONCE(idx >= ARRAY_SIZE(regname_to_perf_reg)))
  		return "NULL";
  	return regname_to_perf_reg[idx].name;
  }
  