unsigned long func_addr = (unsigned long)rp->kp.addr;
unsigned long ret_addr = (unsigned long)ri->ret_addr;
- exit_event(regs, func_addr, ret_addr);
+ exit_event('d', regs, func_addr, ret_addr);
}
return 0;
return mb->ptr == mb->end;
}
+int get_u8(struct msg_buf *mb, u8 *val)
+{
+ if (cmp_mb(mb, sizeof(*val)) < 0)
+ return -EINVAL;
+
+ *val = *((u8 *)mb->ptr);
+ mb->ptr += sizeof(*val);
+
+ print_parse_debug("u8 ->%d;%08X\n", *val, *val);
+
+ return 0;
+}
+
int get_u32(struct msg_buf *mb, u32 *val)
{
if (cmp_mb(mb, sizeof(*val)) < 0)
size_t remained_mb(struct msg_buf *mb);
int is_end_mb(struct msg_buf *mb);
+int get_u8(struct msg_buf *mb, u8 *val);
int get_u32(struct msg_buf *mb, u32 *val);
int get_u64(struct msg_buf *mb, u64 *val);
struct func_inst_data *fi;
u64 addr;
char *args;
+ char ret_type;
print_parse_debug("func addr:");
if (get_u64(mb, &addr)) {
return NULL;
}
+ print_parse_debug("funct ret type:");
+ if (get_u8(mb, (u8 *)&ret_type)) {
+ print_err("failed to read data function arguments\n");
+ return NULL;
+ }
+
fi = kmalloc(sizeof(*fi), GFP_KERNEL);
if (fi == NULL) {
print_err("out of memory\n");
fi->addr = addr;
fi->args = args;
+ fi->ret_type = ret_type;
return fi;
}
struct func_inst_data {
u64 addr;
char *args;
+ char ret_type;
};
/* Library struct */
switch (mt) {
case MT_ADD:
- ret = pf_register_probe(pfg, dentry, func->addr, func->args);
+ ret = pf_register_probe(pfg, dentry, func->addr, func->args,
+ func->ret_type);
break;
case MT_DEL:
ret = pf_unregister_probe(pfg, dentry, func->addr);
struct kprobe;
-struct pt_regs;
struct task_struct;
struct uprobe;
struct uretprobe;
struct uretprobe_instance;
+static inline u32 swap_get_urp_float(struct pt_regs *regs)
+{
+ return regs->ARM_r0;
+}
+
+static inline u64 swap_get_urp_double(struct pt_regs *regs)
+{
+
+ return regs->ARM_r0 | (u64)regs->ARM_r1 << 32;
+}
static inline void arch_ujprobe_return(void)
{
#ifndef _ARM_SWAP_UPROBES_H
#define _ARM_SWAP_UPROBES_H
+
#include <kprobe/arch/asm/dbi_kprobes.h>
struct uretprobe_instance;
+
+static inline u32 swap_get_urp_float(struct pt_regs *regs)
+{
+ u32 st0;
+
+ asm volatile ("fstps %0" : "=m" (st0));
+
+ return st0;
+}
+
+static inline u64 swap_get_urp_double(struct pt_regs *regs)
+{
+ u64 st1;
+
+ asm volatile ("fstpl %0" : "=m" (st1));
+
+ return st1;
+}
+
static inline void arch_ujprobe_return(void)
{
}
}
int img_file_add_ip(struct img_file *file, unsigned long addr,
- const char *args)
+ const char *args, char ret_type)
{
struct img_ip *ip;
return 0;
}
- ip = create_img_ip(addr, args);
+ ip = create_img_ip(addr, args, ret_type);
img_add_ip_by_list(file, ip);
return 0;
void free_img_file(struct img_file *ip);
int img_file_add_ip(struct img_file *file, unsigned long addr,
- const char *args);
+ const char *args, char ret_type);
int img_file_del_ip(struct img_file *file, unsigned long addr);
int img_file_empty(struct img_file *file);
#include "img_ip.h"
#include <linux/slab.h>
-struct img_ip *create_img_ip(unsigned long addr, const char *args)
+struct img_ip *create_img_ip(unsigned long addr, const char *args,
+ char ret_type)
{
struct img_ip *ip;
size_t len;
ip->args = kmalloc(len, GFP_KERNEL);
memcpy(ip->args, args, len);
+ ip->ret_type = ret_type;
+
return ip;
}
struct list_head list; /* for img_file */
unsigned long addr;
char *args;
+ char ret_type;
};
-struct img_ip *create_img_ip(unsigned long addr, const char *args);
+struct img_ip *create_img_ip(unsigned long addr, const char *args,
+ char ret_type);
void free_img_ip(struct img_ip *ip);
/* debug */
}
int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
- unsigned long addr, const char *args)
+ unsigned long addr, const char *args, char ret_type)
{
int ret;
struct img_file *file;
file = find_img_file(proc, dentry);
if (file)
- return img_file_add_ip(file, addr, args);
+ return img_file_add_ip(file, addr, args, ret_type);
file = create_img_file(dentry);
- ret = img_file_add_ip(file, addr, args);
+ ret = img_file_add_ip(file, addr, args, ret_type);
if (ret) {
printk("Cannot add ip to img file\n");
free_img_file(file);
void free_img_proc(struct img_proc *proc);
int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
- unsigned long addr, const char *args);
+ unsigned long addr, const char *args, char ret_type);
int img_proc_del_ip(struct img_proc *proc, struct dentry *dentry, unsigned long addr);
/* debug */
file = sspt_proc_find_file_or_new(proc, i_file->dentry);
list_for_each_entry(i_ip, &i_file->ip_list, list)
- sspt_file_add_ip(file, i_ip->addr, i_ip->args);
+ sspt_file_add_ip(file, i_ip->addr, i_ip->args,
+ i_ip->ret_type);
}
}
}
int pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
- unsigned long offset, const char *args)
+ unsigned long offset, const char *args, char ret_type)
{
- return img_proc_add_ip(pfg->i_proc, dentry, offset, args);
+ return img_proc_add_ip(pfg->i_proc, dentry, offset, args, ret_type);
}
EXPORT_SYMBOL_GPL(pf_register_probe);
void put_pf_group(struct pf_group *pfg);
int pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
- unsigned long offset, const char *args);
+ unsigned long offset, const char *args, char ret_type);
int pf_unregister_probe(struct pf_group *pfg, struct dentry *dentry,
unsigned long offset);
addr = ip->offset & 0x01 ? addr | 0x01 : addr;
#endif
- exit_event(regs, addr, ret_addr);
+ exit_event(ip->ret_type, regs, addr, ret_addr);
}
return 0;
}
-struct us_ip *create_ip(unsigned long offset, const char *args)
+struct us_ip *create_ip(unsigned long offset, const char *args, char ret_type)
{
size_t len = strlen(args) + 1;
struct us_ip *ip = kmalloc(sizeof(*ip) + len, GFP_ATOMIC);
INIT_LIST_HEAD(&ip->list);
ip->offset = offset;
ip->args = (char *)ip + sizeof(*ip);
+ ip->ret_type = ret_type;
/* copy args */
memcpy(ip->args, args, len);
struct uretprobe retprobe;
char *args;
+ char ret_type;
unsigned long offset;
};
-struct us_ip *create_ip(unsigned long offset, const char *args);
+struct us_ip *create_ip(unsigned long offset, const char *args, char ret_type);
void free_ip(struct us_ip *ip);
#endif /* __IP__ */
}
void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
- const char *args)
+ const char *args, char ret_type)
{
struct sspt_page *page = sspt_find_page_or_new(file, offset & PAGE_MASK);
// FIXME: delete ip
- struct us_ip *ip = create_ip(offset, args);
+ struct us_ip *ip = create_ip(offset, args, ret_type);
sspt_add_ip(page, ip);
}
struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
unsigned long page);
void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
- const char *args);
+ const char *args, char ret_type);
struct sspt_page *sspt_get_page(struct sspt_file *file, unsigned long offset_addr);
void sspt_put_page(struct sspt_page *page);
u64 pc_addr;
u64 caller_pc_addr;
u32 cpu_num;
- u64 ret_val;
+ char ret_val[0];
} __attribute__((packed));
-static char *pack_msg_func_exit(char *payload, struct pt_regs *regs,
- unsigned long func_addr,
- unsigned long ret_addr)
+static int pack_msg_ret_val(char *buf, int len, char ret_type,
+ struct pt_regs *regs)
{
- struct msg_func_exit *mfe = (struct msg_func_exit *)payload;
+ const char *buf_old = buf;
+ u32 *tmp_u32;
+ u64 *tmp_u64;
+
+ *buf = ret_type;
+ ++buf;
+
+ switch (ret_type) {
+ case 'b': /* 1 byte(bool) */
+ if (len < 1)
+ return -ENOMEM;
+ *buf = (char)!!get_regs_ret_val(regs);
+ ++buf;
+ break;
+ case 'c': /* 1 byte(char) */
+ if (len < 1)
+ return -ENOMEM;
+ *buf = (char)get_regs_ret_val(regs);
+ ++buf;
+ break;
+ case 'd': /* 4 byte(int) */
+ if (len < 4)
+ return -ENOMEM;
+ tmp_u32 = (u32 *)buf;
+ *tmp_u32 = get_regs_ret_val(regs);
+ buf += 4;
+ break;
+ case 'x': /* 8 byte(long) */
+ case 'p': /* 8 byte(pointer) */
+ if (len < 8)
+ return -ENOMEM;
+ tmp_u64 = (u64 *)buf;
+ *tmp_u64 = (u64)get_regs_ret_val(regs);
+ buf += 8;
+ break;
+ case 's': /* string end with '\0' */
+ {
+ enum { max_str_len = 512 };
+ const char __user *user_s;
+ int len_s, ret;
+
+ user_s = (const char __user *)get_regs_ret_val(regs);
+ len_s = strnlen_user(user_s, max_str_len);
+ if (len < len_s)
+ return -ENOMEM;
+
+ ret = strncpy_from_user(buf, user_s, len_s);
+ if (ret < 0)
+ return -EFAULT;
+
+ buf[ret] = '\0';
+ buf += ret + 1;
+ }
+ break;
+ case 'n':
+ case 'v':
+ break;
+ case 'f': /* 4 byte(float) */
+ if (len < 4)
+ return -ENOMEM;
+ tmp_u32 = (u32 *)buf;
+ *tmp_u32 = swap_get_urp_float(regs);
+ buf += 4;
+ break;
+ case 'w': /* 8 byte(double) */
+ if (len < 8)
+ return -ENOMEM;
+ tmp_u64 = (u64 *)buf;
+ *tmp_u64 = swap_get_urp_double(regs);
+ buf += 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return buf - buf_old;
+}
+
+
+static int pack_msg_func_exit(char *buf, int len, char ret_type,
+ struct pt_regs *regs, unsigned long func_addr,
+ unsigned long ret_addr)
+{
+ struct msg_func_exit *mfe = (struct msg_func_exit *)buf;
struct task_struct *task = current;
+ int ret;
mfe->pid = task->tgid;
mfe->tid = task->pid;
mfe->cpu_num = smp_processor_id();
mfe->pc_addr = func_addr;
mfe->caller_pc_addr = ret_addr;
- mfe->ret_val = get_regs_ret_val(regs);
- return payload + sizeof(*mfe);
+ ret = pack_msg_ret_val(mfe->ret_val, len, ret_type, regs);
+ if (ret < 0) {
+ printk("ERROR: packing MSG_FUNCTION_EXIT (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return sizeof(*mfe) + ret;
}
-int exit_event(struct pt_regs *regs, unsigned long func_addr,
+int exit_event(char ret_type, struct pt_regs *regs, unsigned long func_addr,
unsigned long ret_addr)
{
char *buf, *payload, *buf_end;
+ int ret;
if (!check_event(current))
return 0;
buf = get_current_buf();
payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_EXIT);
- buf_end = pack_msg_func_exit(payload, regs, func_addr, ret_addr);
+ /* FIXME: len=1024 */
+ ret = pack_msg_func_exit(payload, 1024, ret_type, regs,
+ func_addr, ret_addr);
+ if (ret < 0)
+ return ret;
+
+ buf_end = payload + ret;
set_len_msg(buf, buf_end);
return write_to_buffer(buf);
int entry_event(const char *fmt, struct pt_regs *regs,
enum PROBE_TYPE pt, int sub_type);
-int exit_event(struct pt_regs *regs, unsigned long func_addr,
+int exit_event(char ret_type, struct pt_regs *regs, unsigned long func_addr,
unsigned long ret_addr);
int switch_entry(struct pt_regs *regs);