#include <linux/module.h>
#include <linux/kprobes.h>

static spinlock_t probe_lock = SPIN_LOCK_UNLOCKED;

struct name_addr {
	char name[64];
	unsigned long addr;
};

static char * getname(unsigned long addr);


static struct name_addr na[]={
	/*<nameaddr>*/
};

/* Do nothing jprobe handle */
int inst_sys_call (void)
{
	jprobe_return();
	return 0;
}


int sys_call_rp_handler(struct rprobe_instance *ri, struct pt_regs *regs)
{
	long ret;
	unsigned long probe_lock_flags;
	spin_lock_irqsave (& probe_lock, probe_lock_flags);
	ret = regs->eax;
	if (ret < 0) {
		printk("%s, ret=%li, pid=%d\n", getname((unsigned long) ri->rp->kprobe->addr), ret, current->pid);
	}
	spin_unlock_irqrestore (& probe_lock, probe_lock_flags);
	return 0;
}
	
static struct jprobe jp[] = {
/*	{
  	.kp.addr = (kprobe_opcode_t *) <addr>,
	.entry = (kprobe_opcode_t *) inst_sys_call
	},
*/
	/*<jprobe>*/
};



#define MAX_PROBE (sizeof(jp)/sizeof(struct jprobe))

static struct rprobe *rp[MAX_PROBE];

static char * getname(unsigned long addr)
{
	int i;
	for (i = 0; i < MAX_PROBE; i++) {
		if (na[i].addr == addr) { 
			return na[i].name;
		}
	}
	return NULL;
}

static int init_sys_call_rp(void)
{
	int i, ret;
	for(i = 0; i < MAX_PROBE; i++) {
		rp[i] = kmalloc(sizeof(struct rprobe), GFP_KERNEL);
		rp[i]->handler = sys_call_rp_handler;
		rp[i]->maxactive = 1;
		rp[i]->nmissed = 0;
		if ((ret = register_jrprobe(&jp[i], rp[i])) != 0) {
			if (ret == -EEXIST) {
				printk("Probe point exist for this function  %s address.\n", na[i].name);
			} else {
				printk("Failed to register probe point for %s .\n", na[i].name);
			}
		}
		
	}
	printk("sys_rprobe loaded.\n");
	return 0;
}

static void cleanup_sys_call_rp(void)
{
	int i;
	unsigned long probe_lock_flags;
	
	/* Wait until currently running probe returns.  */
	spin_lock_irqsave (& probe_lock, probe_lock_flags);
	spin_unlock_irqrestore (& probe_lock, probe_lock_flags);
	for (i = 0; i < MAX_PROBE; i++) {
  		unregister_jprobe(&jp[i]);
		kfree(rp[i]);
	}
	printk("sys_rprobe removed\n");
}

module_init(init_sys_call_rp);
module_exit(cleanup_sys_call_rp);
MODULE_LICENSE("GPL");

