From: Vyacheslav Cherkashin Date: Mon, 2 Mar 2015 11:28:19 +0000 (+0300) Subject: [IMPROVE] protorcol 4.0 X-Git-Tag: submit/tizen/20151123.110932~89 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3d696527f4b14d6491d617f821d1c73c8f623a91;p=kernel%2Fswap-modules.git [IMPROVE] protorcol 4.0 Change-Id: I5e7e24cbcc04001f72b73f1e3eddb8949f9e0481 Signed-off-by: Vyacheslav Cherkashin --- diff --git a/driver/driver_to_buffer.c b/driver/driver_to_buffer.c index a24916e..7129c26 100644 --- a/driver/driver_to_buffer.c +++ b/driver/driver_to_buffer.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "driver_defs.h" #include "swap_driver_errors.h" diff --git a/ks_features/Kbuild b/ks_features/Kbuild index a3dcfd7..207627d 100644 --- a/ks_features/Kbuild +++ b/ks_features/Kbuild @@ -5,4 +5,5 @@ KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers \ obj-m := swap_ks_features.o swap_ks_features-y := ks_features.o \ ks_map.o \ - file_ops.o + file_ops.o \ + ksf_msg.o diff --git a/ks_features/features_data.c b/ks_features/features_data.c index d12f7d7..3a96c80 100644 --- a/ks_features/features_data.c +++ b/ks_features/features_data.c @@ -28,8 +28,9 @@ */ +#include "ksf_msg.h" #include "syscall_list.h" -#include + /** * @struct feature @@ -38,7 +39,7 @@ * Syscalls count. * @var feature::feature_list * Pointer to feature's syscall list. - * @var feature::sub_type + * @var feature::type * Featue subtype. * @var feature::enable * Is feature enable. @@ -46,7 +47,7 @@ struct feature { size_t cnt; enum syscall_id *feature_list; - int sub_type; + enum probe_t type; unsigned enable:1; }; @@ -285,22 +286,22 @@ static enum syscall_id id_desc[] = { * @def CREATE_FEATURE * Feature initialization. */ -#define CREATE_FEATURE(x, subtype) \ +#define CREATE_FEATURE(x, _type) \ { \ .cnt = sizeof(x) / sizeof(enum syscall_id), \ .feature_list = x, \ - .sub_type = subtype, \ + .type = _type, \ .enable = 0 \ } static struct feature features[] = { - CREATE_FEATURE(id_none, PST_NONE), - CREATE_FEATURE(id_file, PST_KS_FILE), - CREATE_FEATURE(id_ipc, PST_KS_IPC), - CREATE_FEATURE(id_process, PST_KS_PROCESS), - CREATE_FEATURE(id_signal, PST_KS_SIGNAL), - CREATE_FEATURE(id_net, PST_KS_NETWORK), - CREATE_FEATURE(id_desc, PST_KS_DESC) + CREATE_FEATURE(id_none, PT_KS_NONE), + CREATE_FEATURE(id_file, PT_KS_FILE), + CREATE_FEATURE(id_ipc, PT_KS_IPC), + CREATE_FEATURE(id_process, PT_KS_PROCESS), + CREATE_FEATURE(id_signal, PT_KS_SIGNAL), + CREATE_FEATURE(id_net, PT_KS_NETWORK), + CREATE_FEATURE(id_desc, PT_KS_DESC) }; /** diff --git a/ks_features/file_ops.c b/ks_features/file_ops.c index 1a4b28c..0e00942 100644 --- a/ks_features/file_ops.c +++ b/ks_features/file_ops.c @@ -9,8 +9,8 @@ #include #include #include -#include #include "ks_map.h" +#include "ksf_msg.h" #include "file_ops.h" #define FOPS_PREFIX "[FILE_OPS] " @@ -20,28 +20,6 @@ /* path buffer size */ enum { PATH_LEN = 512 }; -/* event subtypes: the same as for IO probes */ -enum { - FOPS_OPEN = 0, - FOPS_CLOSE = 1, - FOPS_READ_BEGIN = 2, - FOPS_READ_END = 3, - FOPS_READ = FOPS_READ_BEGIN, - FOPS_WRITE_BEGIN = 4, - FOPS_WRITE_END = 5, - FOPS_WRITE = FOPS_WRITE_BEGIN, - FOPS_DIRECTORY = 6, - FOPS_PERMS = 7, - FOPS_OTHER = 8, - FOPS_SEND = 9, - FOPS_RECV = 10, - FOPS_OPTION = 11, - FOPS_MANAGE = 12, - FOPS_LOCK_START = 14, /* 13 */ - FOPS_LOCK_END = 15, - FOPS_LOCK_RELEASE = 16 -}; - struct file_probe { int id; const char *args; @@ -394,10 +372,9 @@ static int generic_entry_handler(struct kretprobe_instance *ri, if (fops_fcheck(current, file) == 0) { char *buf = fops_path_buf(); - custom_entry_event(F_ADDR(rp), regs, PT_FILE, - fprobe->subtype, "Sx", - fops_fpath(file, buf, PATH_LEN), - (u64)fd); + ksf_msg_file_entry(fd, fprobe->subtype, + fops_fpath(file, buf, PATH_LEN)); + priv->dentry = file->f_dentry; } else { priv->dentry = NULL; @@ -416,12 +393,8 @@ static int generic_ret_handler(struct kretprobe_instance *ri, struct kretprobe *rp = ri->rp; struct file_private *priv = (struct file_private *)ri->data; - if (rp && priv->dentry) { - struct file_probe *fprobe = to_file_probe(rp); - - custom_exit_event(F_ADDR(rp), R_ADDR(ri), regs, - PT_FILE, fprobe->subtype, "x"); - } + if (rp && priv->dentry) + ksf_msg_file_exit(regs, 'x'); return 0; } @@ -483,13 +456,11 @@ static int open_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) if (fops_fcheck(current, file) == 0) { char *buf = fops_path_buf(); + const char *path = fops_fpath(file, buf, PATH_LEN); - custom_entry_event(F_ADDR(rp), regs, PT_FILE, - fprobe->subtype, "Sxs", - fops_fpath(file, buf, PATH_LEN), - (u64)fd, priv->name); - custom_exit_event(F_ADDR(rp), R_ADDR(ri), regs, - PT_FILE, fprobe->subtype, "x"); + ksf_msg_file_entry_open(fd, fprobe->subtype, + path, priv->name); + ksf_msg_file_exit(regs, 'x'); } if (file) @@ -566,19 +537,14 @@ static int lock_entry_handler(struct kretprobe_instance *ri, filepath = fops_fpath(file, buf, PATH_LEN); if (lock_arg_init(fprobe->id, regs, &arg) == 0) { - subtype = (arg.type == F_UNLCK ? - FOPS_LOCK_RELEASE : - FOPS_LOCK_START); - - custom_entry_event(F_ADDR(rp), regs, PT_FILE, - subtype, "Sxddxx", - filepath, (u64)fd, - arg.type, arg.whence, - arg.start, arg.len); + subtype = arg.type == F_UNLCK ? + FOPS_LOCK_RELEASE : + FOPS_LOCK_START; + ksf_msg_file_entry_lock(fd, subtype, filepath, + arg.type, arg.whence, + arg.start, arg.len); } else { - custom_entry_event(F_ADDR(rp), regs, PT_FILE, - subtype, "Sx", - filepath, (u64)fd); + ksf_msg_file_entry(fd, subtype, filepath); } priv->dentry = file->f_dentry; @@ -600,16 +566,8 @@ static int lock_ret_handler(struct kretprobe_instance *ri, struct kretprobe *rp = ri->rp; struct flock_private *priv = (struct flock_private *)ri->data; - if (rp && priv->dentry) { - int subtype; - if (priv->subtype == FOPS_LOCK_START) - subtype = FOPS_LOCK_END; - else - subtype = priv->subtype; - - custom_exit_event(F_ADDR(rp), R_ADDR(ri), regs, - PT_FILE, subtype, "x"); - } + if (rp && priv->dentry) + ksf_msg_file_exit(regs, 'x'); return 0; } diff --git a/ks_features/ks_features.c b/ks_features/ks_features.c index 59a22c1..5c4c0a0 100644 --- a/ks_features/ks_features.c +++ b/ks_features/ks_features.c @@ -35,13 +35,14 @@ #include #include #include -#include #include +#include "ksf_msg.h" #include "ks_features.h" #include "syscall_list.h" #include "features_data.c" #include "file_ops.h" + /** * @struct ks_probe * @brief Kernel-space probe. Struct used as a container of syscall probes. @@ -51,14 +52,14 @@ * Installed probes counter. * @var ks_probe::args * Pointer to args format string. - * @var ks_probe::sub_type + * @var ks_probe::type * Probe sub type. */ struct ks_probe { struct kretprobe rp; int counter; char *args; - int sub_type; + int type; }; #define CREATE_RP(name) \ @@ -87,7 +88,7 @@ enum { .rp = CREATE_RP(name), \ .counter = 0, \ .args = #args__, \ - .sub_type = PST_NONE \ + .type = PT_KS_NONE \ } static struct ks_probe ksp[] = { @@ -123,10 +124,10 @@ static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) if (rp && check_event(current)) { struct ks_probe *ksp = container_of(rp, struct ks_probe, rp); const char *fmt = ksp->args; - unsigned long addr = (unsigned long)ksp->rp.kp.addr; - int sub_type = ksp->sub_type; + const unsigned long addr = (unsigned long)ksp->rp.kp.addr; + enum probe_t type = ksp->type; - entry_event(fmt, addr, regs, PT_KS, sub_type); + ksf_msg_entry(regs, addr, type, fmt); } return 0; @@ -138,11 +139,11 @@ static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) if (rp && check_event(current)) { struct ks_probe *ksp = container_of(rp, struct ks_probe, rp); - unsigned long func_addr = (unsigned long)rp->kp.addr; - unsigned long ret_addr = (unsigned long)ri->ret_addr; - int sub_type = ksp->sub_type; + const unsigned long func_addr = (unsigned long)rp->kp.addr; + const unsigned long ret_addr = (unsigned long)ri->ret_addr; + enum probe_t type = ksp->type; - exit_event('x', regs, PT_KS, sub_type, func_addr, ret_addr); + ksf_msg_exit(regs, func_addr, ret_addr, type, 'x'); } return 0; @@ -157,7 +158,7 @@ static int switch_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { if (check_event(current)) - switch_entry(regs); + ksf_switch_entry(regs); return 0; } @@ -166,7 +167,7 @@ static int switch_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { if (check_event(current)) - switch_exit(regs); + ksf_switch_exit(regs); return 0; } @@ -326,12 +327,12 @@ static int unregister_multiple_syscalls(size_t *id_p, size_t cnt) static void set_pst(struct feature *f, size_t id) { - ksp[id].sub_type |= f->sub_type; + ksp[id].type |= f->type; } static void unset_pst(struct feature *f, size_t id) { - ksp[id].sub_type &= !f->sub_type; + ksp[id].type &= !f->type; } static void do_uninstall_features(struct feature *f, size_t i) diff --git a/ks_features/ksf_msg.c b/ks_features/ksf_msg.c new file mode 100644 index 0000000..100fe85 --- /dev/null +++ b/ks_features/ksf_msg.c @@ -0,0 +1,375 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include +#include "ksf_msg.h" + + +#define KSF_PREFIX KERN_INFO "[KSF] " + + + + + +/* ============================================================================ + * = MSG_SYSCALL_* (ENTRY/EXIT) = + * ============================================================================ + */ +struct msg_sys_header { + u32 pid; + u32 tid; + u32 probe_type; + u64 pc_addr; + u64 caller_pc_addr; + u32 cpu_num; +} __packed; + +struct msg_sys_entry { + struct msg_sys_header h; + u32 cnt_args; + char args[0]; +} __packed; + +struct msg_sys_exit { + struct msg_sys_header h; + char ret_val[0]; +} __packed; + + +static void pack_header(struct msg_sys_header *h, unsigned long func_addr, + unsigned long ret_addr, enum probe_t type) +{ + struct task_struct *task = current; + + h->pid = task->tgid; + h->tid = task->pid; + h->probe_type = (u32)type; + h->pc_addr = func_addr; + h->caller_pc_addr = ret_addr; + h->cpu_num = smp_processor_id(); +} + +static void pack_entry_header(struct msg_sys_entry *e, struct pt_regs *regs, + unsigned long func_addr, enum probe_t type, + const char *fmt) +{ + pack_header(&e->h, func_addr, get_regs_ret_func(regs), type); + e->cnt_args = strlen(fmt); +} + +static void pack_exit_header(struct msg_sys_exit *e, unsigned long func_addr, + unsigned long ret_addr, enum probe_t type) +{ + pack_header(&e->h, func_addr, ret_addr, type); +} + +void ksf_msg_entry(struct pt_regs *regs, unsigned long func_addr, + enum probe_t type, const char *fmt) +{ + int ret; + struct swap_msg *m; + struct msg_sys_entry *ent; + size_t size; + + m = swap_msg_get(MSG_SYSCALL_ENTRY); + + ent = swap_msg_payload(m); + pack_entry_header(ent, regs, func_addr, type, fmt); + + size = swap_msg_size(m) - sizeof(*ent); + ret = swap_msg_pack_args(ent->args, size, fmt, regs); + if (ret < 0) { + printk(KSF_PREFIX "ERROR: arguments packing, ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, sizeof(*ent) + ret); + +put_msg: + swap_msg_put(m); +} + +void ksf_msg_exit(struct pt_regs *regs, unsigned long func_addr, + unsigned long ret_addr, enum probe_t type, char ret_type) +{ + int ret; + struct swap_msg *m; + struct msg_sys_exit *ext; + size_t size; + + m = swap_msg_get(MSG_SYSCALL_EXIT); + + ext = swap_msg_payload(m); + pack_exit_header(ext, func_addr, ret_addr, type); + + size = swap_msg_size(m) - sizeof(*ext); + ret = swap_msg_pack_ret_val(ext->ret_val, size, ret_type, regs); + if (ret < 0) { + printk(KSF_PREFIX "ERROR: ret value packing, ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, sizeof(*ext) + ret); + +put_msg: + swap_msg_put(m); +} + + + + + +/* ============================================================================ + * = MSG_FILE_FUNCTION_* (ENTRY/EXIT) = + * ============================================================================ + */ +struct msg_file_entry { + u32 pid; + u32 tid; + u32 fd; + u32 event_type; + char file_path[0]; +} __packed; + +enum file_info { + FI_GENIRAL = 0, + FI_OPEN = 1, + FI_LOCK = 2 +}; + +static int pack_file_entry_head(void *data, size_t size, enum file_info info, + int fd, enum file_api_t api, const char *path) +{ + struct msg_file_entry *ent = (struct msg_file_entry *)data; + struct task_struct *task = current; + size_t len, old_size = size; + + ent->pid = task->tgid; + ent->tid = task->pid; + ent->fd = fd; + ent->event_type = api; + + size -= sizeof(*ent); + len = strlen(path); + if (size < len + 1) + return -ENOMEM; + + memcpy(ent->file_path, path, len); + ent->file_path[len] = '\0'; + + size -= len + 1; + data += old_size - size; + + if (size < 4) + return -ENOMEM; + + *((u32 *)data) = (u32)info; + size -= 4; + + return old_size - size; +} + + + +void ksf_msg_file_entry(int fd, enum file_api_t api, const char *path) +{ + int ret; + void *p; + size_t size; + struct swap_msg *m; + + m = swap_msg_get(MSG_FILE_FUNCTION_ENTRY); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + ret = pack_file_entry_head(p, size, FI_GENIRAL, fd, api, path); + if (ret < 0) { + printk(KSF_PREFIX "buffer is too small\n"); + goto put_msg; + } + + swap_msg_flush(m, ret); + +put_msg: + swap_msg_put(m); +} + +void ksf_msg_file_entry_open(int fd, enum file_api_t api, const char *path, + const char __user *ofile) +{ + long n; + int ret; + void *p; + size_t size; + struct swap_msg *m; + + m = swap_msg_get(MSG_FILE_FUNCTION_ENTRY); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + ret = pack_file_entry_head(p, size, FI_OPEN, fd, api, path); + if (ret < 0) { + printk(KSF_PREFIX "buffer is too small\n"); + goto put_msg; + } + + size -= ret; + p += ret; + + n = strncpy_from_user(p, ofile, size); + if (n < 0) { + printk(KSF_PREFIX "cannot copy ofile\n"); + swap_msg_put(m); + } + + swap_msg_flush(m, ret + n + 1); + +put_msg: + swap_msg_put(m); +} + +struct lock_arg { + u32 type; + u32 whence; + u64 start; + u64 len; +} __packed; + +void ksf_msg_file_entry_lock(int fd, enum file_api_t api, const char *path, + int type, int whence, s64 start, s64 len) +{ + int ret; + void *p; + size_t size; + struct swap_msg *m; + struct lock_arg *arg; + + m = swap_msg_get(MSG_FILE_FUNCTION_ENTRY); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + ret = pack_file_entry_head(p, size, FI_LOCK, fd, api, path); + if (ret < 0) { + printk(KSF_PREFIX "buffer is too small\n"); + goto put_msg; + } + + size -= ret; + p += ret; + + if (size < sizeof(*arg)) { + printk(KSF_PREFIX "buffer is too small\n"); + goto put_msg; + } + + arg = (struct lock_arg *)p; + arg->type = (u32)type; + arg->whence = (u32)whence; + arg->start = (u64)start; + arg->len = (u64)len; + + swap_msg_flush(m, ret + sizeof(*arg)); + +put_msg: + swap_msg_put(m); +} + + +struct msg_file_exit { + u32 pid; + u32 tid; + char ret_val[0]; +} __packed; + +void ksf_msg_file_exit(struct pt_regs *regs, char ret_type) +{ + struct task_struct *task = current; + int ret; + struct swap_msg *m; + struct msg_file_exit *ext; + size_t size; + + m = swap_msg_get(MSG_FILE_FUNCTION_EXIT); + + ext = swap_msg_payload(m); + ext->pid = task->tgid; + ext->tid = task->pid; + + size = swap_msg_size(m) - sizeof(*ext); + ret = swap_msg_pack_ret_val(ext->ret_val, size, ret_type, regs); + if (ret < 0) { + printk(KSF_PREFIX "ERROR: ret value packing, ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, sizeof(*ext) + ret); + +put_msg: + swap_msg_put(m); +} + + + + + +/* ============================================================================ + * = MSG_FILE_FUNCTION_* (ENTRY/EXIT) = + * ============================================================================ + */ +struct msg_context_switch { + u64 pc_addr; + u32 pid; + u32 tid; + u32 cpu_num; +} __packed; + +static void context_switch(struct pt_regs *regs, enum swap_msg_id id) +{ + struct task_struct *task = current; + struct swap_msg *m; + struct msg_context_switch *mcs; + void *p; + + m = swap_msg_get(id); + p = swap_msg_payload(m); + + mcs = p; + mcs->pc_addr = 0; + mcs->pid = task->tgid; + mcs->tid = task->pid; + mcs->cpu_num = smp_processor_id(); + + swap_msg_flush(m, sizeof(*mcs)); + swap_msg_put(m); +} + +void ksf_switch_entry(struct pt_regs *regs) +{ + context_switch(regs, MSG_CONTEXT_SWITCH_ENTRY); +} + +void ksf_switch_exit(struct pt_regs *regs) +{ + context_switch(regs, MSG_CONTEXT_SWITCH_EXIT); +} diff --git a/ks_features/ksf_msg.h b/ks_features/ksf_msg.h new file mode 100644 index 0000000..6be8d5e --- /dev/null +++ b/ks_features/ksf_msg.h @@ -0,0 +1,79 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#ifndef _KSF_MSG_H +#define _KSF_MSG_H + + +enum probe_t { + PT_KS_NONE = 0x00, + PT_KS_FILE = 0x01, + PT_KS_IPC = 0x02, + PT_KS_PROCESS = 0x04, + PT_KS_SIGNAL = 0x08, + PT_KS_NETWORK = 0x10, + PT_KS_DESC = 0x20 +}; + + +enum file_api_t { + FOPS_OPEN = 0, + FOPS_CLOSE = 1, + FOPS_READ_BEGIN = 2, + FOPS_READ_END = 3, + FOPS_READ = FOPS_READ_BEGIN, + FOPS_WRITE_BEGIN = 4, + FOPS_WRITE_END = 5, + FOPS_WRITE = FOPS_WRITE_BEGIN, + FOPS_DIRECTORY = 6, + FOPS_PERMS = 7, + FOPS_OTHER = 8, + FOPS_SEND = 9, + FOPS_RECV = 10, + FOPS_OPTION = 11, + FOPS_MANAGE = 12, + FOPS_LOCK_START = 14, /* 13 */ + FOPS_LOCK_END = 15, + FOPS_LOCK_RELEASE = 16 +}; + + +struct pt_regs; + + +void ksf_msg_entry(struct pt_regs *regs, unsigned long func_addr, + enum probe_t type, const char *fmt); +void ksf_msg_exit(struct pt_regs *regs, unsigned long func_addr, + unsigned long ret_addr, enum probe_t type, char ret_type); + +void ksf_msg_file_entry(int fd, enum file_api_t api, const char *path); +void ksf_msg_file_entry_open(int fd, enum file_api_t api, const char *path, + const char __user *ofile); +void ksf_msg_file_entry_lock(int fd, enum file_api_t api, const char *path, + int type, int whence, s64 start, s64 len); +void ksf_msg_file_exit(struct pt_regs *regs, char ret_type); + +void ksf_switch_entry(struct pt_regs *regs); +void ksf_switch_exit(struct pt_regs *regs); + + +#endif /* _KSF_MSG_H */ diff --git a/parser/features.c b/parser/features.c index 2e7495b..beb7f6b 100644 --- a/parser/features.c +++ b/parser/features.c @@ -29,6 +29,7 @@ #include +#include #include #include #include @@ -36,8 +37,8 @@ #include "features.h" #include "msg_parser.h" +#include #include -#include #include #include @@ -284,6 +285,34 @@ int unset_context_switch(void) } + + + +struct sample { + u32 pid; + u64 pc_addr; + u32 tid; + u32 cpu_num; +} __packed; + +static void sample_msg(struct pt_regs *regs) +{ + struct swap_msg *m; + struct sample *s; + struct task_struct *task = current; + + m = swap_msg_get(MSG_SAMPLE); + + s = swap_msg_payload(m); + s->pid = task->tgid; + s->pc_addr = instruction_pointer(regs); + s->tid = task->pid; + s->cpu_num = smp_processor_id(); + + swap_msg_flush(m, sizeof(*s)); + swap_msg_put(m); +} + static void sampler_cb(struct pt_regs *regs) { if (check_event(current)) diff --git a/parser/msg_cmd.c b/parser/msg_cmd.c index 1da2341..5d6f01c 100644 --- a/parser/msg_cmd.c +++ b/parser/msg_cmd.c @@ -31,14 +31,15 @@ #include #include #include -#include #include "msg_parser.h" #include "msg_buf.h" #include "features.h" #include "parser_defs.h" #include "us_inst.h" +#include #include + static int wrt_launcher_port; static int set_config(struct conf_data *conf) @@ -78,8 +79,8 @@ int msg_start(struct msg_buf *mb) struct us_inst_data *us_inst; struct conf_data conf; - reset_seq_num(); - reset_discarded(); + swap_msg_seq_num_reset(); + swap_msg_discard_reset(); us_inst = create_us_inst_data(mb); if (us_inst == NULL) @@ -121,7 +122,7 @@ int msg_stop(struct msg_buf *mb) { int ret = 0; struct conf_data conf; - unsigned int discarded; + int discarded; if (!is_end_mb(mb)) { print_err("to long message, remained=%u", remained_mb(mb)); @@ -138,9 +139,9 @@ int msg_stop(struct msg_buf *mb) if (ret) printk(KERN_INFO "Cannot set config, ret = %d\n", ret); - discarded = get_discarded_count(); + discarded = swap_msg_discard_get(); printk(KERN_INFO "discarded messages: %d\n", discarded); - reset_discarded(); + swap_msg_discard_reset(); return ret; } diff --git a/preload/preload_probe.c b/preload/preload_probe.c index d773251..efb0d29 100644 --- a/preload/preload_probe.c +++ b/preload/preload_probe.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include "preload_probe.h" diff --git a/retprobe/Kbuild b/retprobe/Kbuild index 0c9fefb..c61030c 100644 --- a/retprobe/Kbuild +++ b/retprobe/Kbuild @@ -1,4 +1,6 @@ EXTRA_CFLAGS := $(extra_cflags) obj-m := swap_retprobe.o -swap_retprobe-y := retprobe.o +swap_retprobe-y := \ + retprobe.o \ + rp_msg.o diff --git a/retprobe/retprobe.c b/retprobe/retprobe.c index 96ba8c4..5a29986 100644 --- a/retprobe/retprobe.c +++ b/retprobe/retprobe.c @@ -26,10 +26,11 @@ #include #include #include -#include #include #include #include +#include "rp_msg.h" + static int retprobe_copy(struct probe_info *dest, const struct probe_info *source) @@ -78,9 +79,9 @@ static int retprobe_entry_handler(struct uretprobe_instance *ri, struct pt_regs if (rp && get_quiet() == QT_OFF) { struct us_ip *ip = container_of(rp, struct us_ip, retprobe); const char *fmt = ip->probe_i.rp_i.args; - unsigned long addr = (unsigned long)ip->orig_addr; + const unsigned long func_addr = (unsigned long)ip->orig_addr; - entry_event(fmt, addr, regs, PT_US, PST_NONE); + rp_msg_entry(regs, func_addr, fmt); } return 0; @@ -92,11 +93,11 @@ static int retprobe_ret_handler(struct uretprobe_instance *ri, struct pt_regs *r if (rp && get_quiet() == QT_OFF) { struct us_ip *ip = container_of(rp, struct us_ip, retprobe); - unsigned long addr = (unsigned long)ip->orig_addr; - unsigned long ret_addr = (unsigned long)ri->ret_addr; + const unsigned long func_addr = (unsigned long)ip->orig_addr; + const unsigned long ret_addr = (unsigned long)ri->ret_addr; + const char ret_type = ip->probe_i.rp_i.ret_type; - exit_event(ip->probe_i.rp_i.ret_type, regs, PT_US, PST_NONE, addr, - ret_addr); + rp_msg_exit(regs, func_addr, ret_type, ret_addr); } return 0; diff --git a/retprobe/rp_msg.c b/retprobe/rp_msg.c new file mode 100644 index 0000000..32b9771 --- /dev/null +++ b/retprobe/rp_msg.c @@ -0,0 +1,119 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include +#include "rp_msg.h" + + +#define RP_PREFIX KERN_INFO "[RP] " + + +struct msg_entry { + u32 pid; + u32 tid; + u64 pc_addr; + u64 caller_pc_addr; + u32 cpu_num; + u32 cnt_args; + char args[0]; +} __packed; + +struct msg_exit { + u32 pid; + u32 tid; + u64 pc_addr; + u64 caller_pc_addr; + u32 cpu_num; + char ret_val[0]; +} __packed; + + +void rp_msg_entry(struct pt_regs *regs, unsigned long func_addr, + const char *fmt) +{ + int ret; + struct task_struct *task = current; + struct swap_msg *m; + struct msg_entry *ent; + void *p; + size_t size; + + m = swap_msg_get(MSG_FUNCTION_ENTRY); + p = swap_msg_payload(m); + + ent = p; + ent->pid = task->tgid; + ent->tid = task->pid; + ent->pc_addr = func_addr; + ent->caller_pc_addr = get_regs_ret_func(regs); + ent->cpu_num = smp_processor_id(); + ent->cnt_args = strlen(fmt); + + size = swap_msg_size(m); + ret = swap_msg_pack_args(p + sizeof(*ent), size - sizeof(*ent), + fmt, regs); + if (ret < 0) { + printk(RP_PREFIX "ERROR: arguments packing, ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, sizeof(*ent) + ret); + +put_msg: + swap_msg_put(m); +} + +void rp_msg_exit(struct pt_regs *regs, unsigned long func_addr, + char ret_type, unsigned long ret_addr) +{ + int ret; + struct task_struct *task = current; + struct swap_msg *m; + struct msg_exit *ext; + void *p; + size_t size; + + m = swap_msg_get(MSG_FUNCTION_EXIT); + p = swap_msg_payload(m); + + ext = p; + ext->pid = task->tgid; + ext->tid = task->pid; + ext->pc_addr = func_addr; + ext->caller_pc_addr = ret_addr; + ext->cpu_num = smp_processor_id(); + + size = swap_msg_size(m); + ret = swap_msg_pack_ret_val(p + sizeof(*ext), size - sizeof(*ext), + ret_type, regs); + if (ret < 0) { + printk(RP_PREFIX "ERROR: return value packing, ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, sizeof(*ext) + ret); + +put_msg: + swap_msg_put(m); +} diff --git a/retprobe/rp_msg.h b/retprobe/rp_msg.h new file mode 100644 index 0000000..a2e3b28 --- /dev/null +++ b/retprobe/rp_msg.h @@ -0,0 +1,36 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#ifndef _RP_MSG_H +#define _RP_MSG_H + + +struct pt_regs; + + +void rp_msg_entry(struct pt_regs *regs, unsigned long func_addr, + const char *fmt); +void rp_msg_exit(struct pt_regs *regs, unsigned long func_addr, + char ret_type, unsigned long ret_addr); + + +#endif /* _RP_MSG_H */ diff --git a/us_manager/Kbuild b/us_manager/Kbuild index c6db3e9..6481da5 100644 --- a/us_manager/Kbuild +++ b/us_manager/Kbuild @@ -9,4 +9,5 @@ swap_us_manager-y := us_manager.o us_slot_manager.o helper.o debugfs_us_manager. sspt/sspt_feature.o sspt/sspt_filter.o \ pf/proc_filters.o pf/pf_group.o \ img/img_proc.o img/img_file.o img/img_ip.o \ - probes/probes.o + probes/probes.o \ + usm_msg.o diff --git a/us_manager/helper.c b/us_manager/helper.c index cca5b09..7a5bc37 100644 --- a/us_manager/helper.c +++ b/us_manager/helper.c @@ -27,9 +27,9 @@ #include #include #include -#include #include "us_slot_manager.h" #include "sspt/sspt.h" +#include "usm_msg.h" #include "helper.h" struct task_struct; @@ -343,7 +343,7 @@ static void __remove_unmap_probes(struct sspt_proc *proc, sspt_proc_insert_files(proc, &head); - proc_unmap_msg(start, end); + usm_msg_unmap(start, end); } } @@ -384,8 +384,7 @@ static int ret_handler_unmap(struct kretprobe_instance *ri, struct task_struct *task; task = current->group_leader; - if (is_kthread(task) || - get_regs_ret_val(regs)) + if (is_kthread(task) || regs_return_value(regs)) goto out; remove_unmap_probes(task, (struct unmap_data *)ri->data); @@ -444,7 +443,7 @@ static int ret_handler_mmap(struct kretprobe_instance *ri, if (is_kthread(task)) return 0; - start_addr = (unsigned long)get_regs_ret_val(regs); + start_addr = regs_return_value(regs); if (IS_ERR_VALUE(start_addr)) return 0; @@ -454,7 +453,7 @@ static int ret_handler_mmap(struct kretprobe_instance *ri, vma = find_vma_intersection(task->mm, start_addr, start_addr + 1); if (vma && check_vma(vma)) - pcoc_map_msg(vma); + usm_msg_map(vma); return 0; } diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c index 8a5b334..c19242c 100644 --- a/us_manager/pf/pf_group.c +++ b/us_manager/pf/pf_group.c @@ -27,12 +27,12 @@ #include #include #include "proc_filters.h" +#include #include #include #include #include #include -#include struct pf_group { struct list_head list; @@ -190,7 +190,7 @@ static void first_install(struct task_struct *task, struct sspt_proc *proc, } down_write(&task->mm->mmap_sem); - proc_info_msg(task, dentry); + usm_msg_info(task, dentry); sspt_proc_install(proc); up_write(&task->mm->mmap_sem); } diff --git a/us_manager/sspt/sspt_proc.c b/us_manager/sspt/sspt_proc.c index 8de9368..cde887e 100644 --- a/us_manager/sspt/sspt_proc.c +++ b/us_manager/sspt/sspt_proc.c @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include static LIST_HEAD(proc_probes_list); @@ -135,7 +135,7 @@ void sspt_proc_free(struct sspt_proc *proc) sspt_destroy_feature(proc->feature); - terminate_msg(proc->task); + usm_msg_term(proc->task); free_sm_us(proc->sm); kfree(proc); } diff --git a/us_manager/us_manager.c b/us_manager/us_manager.c index fb0ee5e..57f3c26 100644 --- a/us_manager/us_manager.c +++ b/us_manager/us_manager.c @@ -29,14 +29,9 @@ #include "helper.h" #include "us_manager.h" #include "debugfs_us_manager.h" - #include #include -/* FIXME: move /un/init_msg() elsewhere and remove this include */ -#include /* for /un/init_msg() */ - - static DEFINE_MUTEX(mutex_inst); static enum status_type status = ST_OFF; @@ -215,12 +210,6 @@ static int init_us_manager(void) int ret; ret = init_us_filter(); - if (ret) - return ret; - - ret = init_msg(32*1024); /* TODO: move to writer */ - if (ret) - exit_us_filter(); return ret; } @@ -230,7 +219,6 @@ static void exit_us_manager(void) if (status == ST_ON) do_usm_stop(); - uninit_msg(); exit_us_filter(); } diff --git a/us_manager/usm_msg.c b/us_manager/usm_msg.c new file mode 100644 index 0000000..a81c0ec --- /dev/null +++ b/us_manager/usm_msg.c @@ -0,0 +1,463 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include + +#include +#include /* ... check_vma() */ + + +#define USM_PREFIX KERN_INFO "[USM] " + + +struct kmem_info { + const char *name; + unsigned long start; + unsigned long end; +}; + +static void kmem_info_fill(struct kmem_info *info, struct mm_struct *mm) +{ +#if defined(CONFIG_ARM) + info->name = "[vectors]" + info->start = CONFIG_VECTORS_BASE; + info->end = CONFIG_VECTORS_BASE + PAGE_SIZE; +#elif defined(CONFIG_X86_32) + unsigned long vdso; + struct vm_area_struct *vma_vdso; + + vdso = (unsigned long)mm->context.vdso; + vma_vdso = find_vma_intersection(mm, vdso, vdso + 1); + if (vma_vdso) { + info->name = "[vdso]"; + info->start = vma_vdso->vm_start; + info->end = vma_vdso->vm_end; + } else { + printk(USM_PREFIX "Cannot get VDSO mapping\n"); + + info->name = NULL; + info->start = 0; + info->end = 0; + } +#endif /* CONFIG_arch */ +} + + +static int pack_path(void *data, size_t size, struct file *file) +{ + enum { TMP_BUF_LEN = 512 }; + char tmp_buf[TMP_BUF_LEN]; + const char NA[] = "N/A"; + const char *filename; + size_t len = sizeof(NA); + + if (file == NULL) { + filename = NA; + goto cp2buf; + } + + filename = d_path(&file->f_path, tmp_buf, TMP_BUF_LEN); + if (IS_ERR_OR_NULL(filename)) { + filename = NA; + goto cp2buf; + } + + len = strlen(filename) + 1; + +cp2buf: + if (size < len) + return -ENOMEM; + + memcpy(data, filename, len); + return len; +} + + + + + +/* ============================================================================ + * = MSG_PROCESS_INFO = + * ============================================================================ + */ +struct proc_info_top { + u32 pid; + char comm[0]; +} __packed; + +struct proc_info_bottom { + u32 ppid; + u64 start_time; + u64 low_addr; + u64 high_addr; + char bin_path[0]; +} __packed; + +struct lib_obj { + u64 low_addr; + u64 high_addr; + char lib_path[0]; +} __packed; + +static int pack_lib_obj(void *data, size_t size, struct vm_area_struct *vma) +{ + int ret; + struct lib_obj *obj = (struct lib_obj *)data; + + if (size < sizeof(*obj)) + return -ENOMEM; + + obj->low_addr = vma->vm_start; + obj->high_addr = vma->vm_end; + size -= sizeof(*obj); + + ret = pack_path(obj->lib_path, size, vma->vm_file); + if (ret < 0) + return ret; + + return ret + sizeof(*obj); +} + +static int pack_shared_kmem(void *data, size_t size, struct mm_struct *mm) +{ + struct lib_obj *obj = (struct lib_obj *)data; + struct kmem_info info; + size_t name_len, obj_size; + + if (size < sizeof(*obj)) + return -ENOMEM; + + kmem_info_fill(&info, mm); + + if (info.name == NULL) + return 0; + + obj->low_addr = (u64)info.start; + obj->high_addr = (u64)info.end; + + name_len = strlen(info.name) + 1; + obj_size = sizeof(*obj) + name_len; + if (size < obj_size) + return -ENOMEM; + + memcpy(obj->lib_path, info.name, name_len); + + return obj_size; +} + +static int pack_libs(void *data, size_t size, struct mm_struct *mm) +{ + int ret; + struct vm_area_struct *vma; + u32 *lib_cnt = (u32 *)data; + const size_t old_size = size; + + if (size < sizeof(*lib_cnt)) + return -ENOMEM; + + /* packing libraries count */ + *lib_cnt = 0; + data += sizeof(*lib_cnt); + size -= sizeof(*lib_cnt); + + /* packing libraries */ + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (check_vma(vma)) { + ret = pack_lib_obj(data, size, vma); + if (ret < 0) + return ret; + + data += ret; + size -= ret; + ++(*lib_cnt); + } + } + + /* packing shared kernel memory */ + ret = pack_shared_kmem(data, size, mm); + if (ret < 0) + return ret; + + *lib_cnt += !!ret; + size -= ret; + + return old_size - size; +} + +static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm, + struct dentry *dentry) +{ + struct vm_area_struct *vma; + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (vma->vm_file && (vma->vm_flags & VM_EXEC) && + (vma->vm_file->f_dentry == dentry)) + goto out; + } + + vma = NULL; +out: + + return vma; +} + +static int pack_proc_info_top(void *data, size_t size, + struct task_struct *task) +{ + struct proc_info_top *pit = (struct proc_info_top *)data; + + if (size < sizeof(*pit) + sizeof(task->comm)) + return -ENOMEM; + + pit->pid = task->tgid; + get_task_comm(pit->comm, task); + + return sizeof(*pit) + strlen(pit->comm) + 1; +} + +static int pack_proc_info_bottom(void *data, size_t size, + struct task_struct *task, + struct dentry *dentry) +{ + struct proc_info_bottom *pib = (struct proc_info_bottom *)data; + struct vm_area_struct *vma = find_vma_exe_by_dentry(task->mm, dentry); + struct timespec boot_time; + struct timespec start_time; + int ret; + + if (size < sizeof(*pib)) + return -ENOMEM; + + getboottime(&boot_time); + start_time = timespec_add(boot_time, task->real_start_time); + + pib->ppid = task->real_parent->tgid; + pib->start_time = swap_msg_spec2time(&start_time); + + if (vma) { + pib->low_addr = vma->vm_start; + pib->high_addr = vma->vm_end; + ret = pack_path(pib->bin_path, size, vma->vm_file); + } else { + pib->low_addr = 0; + pib->high_addr = 0; + ret = pack_path(pib->bin_path, size, NULL); + } + + if (ret < 0) + return ret; + + return sizeof(*pib) + ret; +} + +static int pack_proc_info(void *data, size_t size, struct task_struct *task, + struct dentry *dentry) +{ + int ret; + const size_t old_size = size; + + ret = pack_proc_info_top(data, size, task); + if (ret < 0) + return ret; + + data += ret; + size -= ret; + + ret = pack_proc_info_bottom(data, size, task, dentry); + if (ret < 0) + return ret; + + data += ret; + size -= ret; + + ret = pack_libs(data, size, task->mm); + if (ret < 0) + return ret; + + return old_size - size + ret; +} + +/* Called with down\up\_read(&task->mm->mmap_sem). */ +void usm_msg_info(struct task_struct *task, struct dentry *dentry) +{ + int ret; + struct swap_msg *m; + void *p; + size_t size; + + m = swap_msg_get(MSG_PROC_INFO); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + ret = pack_proc_info(p, size, task, dentry); + if (ret < 0) { + printk(USM_PREFIX "ERROR: message process info packing, " + "ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, ret); + +put_msg: + swap_msg_put(m); +} + + + + + +/* ============================================================================ + * = MSG_TERMINATE = + * ============================================================================ + */ +struct proc_terminate { + u32 pid; +} __packed; + +void usm_msg_term(struct task_struct *task) +{ + struct swap_msg *m; + struct proc_terminate *term; + + m = swap_msg_get(MSG_TERMINATE); + + term = swap_msg_payload(m); + term->pid = task->pid; + + swap_msg_flush(m, sizeof(*term)); + swap_msg_put(m); +} + + + + + +/* ============================================================================ + * = MSG_PROCESS_MAP = + * ============================================================================ + */ +struct proc_map { + u32 pid; + u64 low_addr; + u64 high_addr; + char bin_path[0]; +} __packed; + +static int pack_proc_map(void *data, size_t size, struct vm_area_struct *vma) +{ + struct proc_map *map = (struct proc_map *)data; + int ret; + + map->pid = current->tgid; + map->low_addr = vma->vm_start; + map->high_addr = vma->vm_end; + + ret = pack_path(map->bin_path, size - sizeof(*map), vma->vm_file); + if (ret < 0) + return ret; + + return ret + sizeof(*map); +} + +void usm_msg_map(struct vm_area_struct *vma) +{ + int ret; + struct swap_msg *m; + void *p; + size_t size; + + m = swap_msg_get(MSG_PROC_MAP); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + ret = pack_proc_map(p, size, vma); + if (ret < 0) { + printk(USM_PREFIX "ERROR: message process mapping packing, " + "ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, ret); + +put_msg: + swap_msg_put(m); +} + + + + + +/* ============================================================================ + * = MSG_PROCESS_UNMAP = + * ============================================================================ + */ +struct proc_unmap { + u32 pid; + u64 low_addr; + u64 high_addr; +} __packed; + +void usm_msg_unmap(unsigned long start, unsigned long end) +{ + struct swap_msg *m; + struct proc_unmap *unmap; + + m = swap_msg_get(MSG_PROC_UNMAP); + + unmap = swap_msg_payload(m); + unmap->pid = current->tgid; + unmap->low_addr = (u64)start; + unmap->high_addr = (u64)end; + + swap_msg_flush(m, sizeof(*unmap)); + swap_msg_put(m); +} + + + + + +/* ============================================================================ + * = MSG_PROCESS_COMM = + * ============================================================================ + */ +struct proc_comm { + u32 pid; + char comm[0]; +} __packed; + +void usm_msg_comm(struct task_struct *task) +{ + struct swap_msg *m; + struct proc_comm *c; + + m = swap_msg_get(MSG_PROC_COMM); + + c = swap_msg_payload(m); + c->pid = task->tgid; + get_task_comm(c->comm, task); + + swap_msg_flush(m, sizeof(*c) + strlen(c->comm) + 1); + swap_msg_put(m); +} diff --git a/us_manager/usm_msg.h b/us_manager/usm_msg.h new file mode 100644 index 0000000..c144817 --- /dev/null +++ b/us_manager/usm_msg.h @@ -0,0 +1,39 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#ifndef _USM_MSG_H +#define _USM_MSG_H + + +struct dentry; +struct task_struct; +struct vm_area_struct; + + +void usm_msg_info(struct task_struct *task, struct dentry *dentry); +void usm_msg_term(struct task_struct *task); +void usm_msg_map(struct vm_area_struct *vma); +void usm_msg_unmap(unsigned long start, unsigned long end); +void usm_msg_comm(struct task_struct *task); + + +#endif /* _USM_MSG_H */ diff --git a/webprobe/Kbuild b/webprobe/Kbuild index 8c24f5f..b6eef32 100644 --- a/webprobe/Kbuild +++ b/webprobe/Kbuild @@ -3,4 +3,5 @@ EXTRA_CFLAGS := $(extra_cflags) obj-m := swap_webprobe.o swap_webprobe-y := webprobe.o \ webprobe_debugfs.o \ - webprobe_prof.o + webprobe_prof.o \ + web_msg.o diff --git a/webprobe/web_msg.c b/webprobe/web_msg.c new file mode 100644 index 0000000..07b24fb --- /dev/null +++ b/webprobe/web_msg.c @@ -0,0 +1,204 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include +#include +#include +#include +#include + + +#define WEB_PREFIX KERN_INFO "[WEB_PROF] " + +/* TODO: develop method for obtaining this data during build... */ +/* location: webkit2-efl-123997_0.11.113/Source/WTF/wtf/text/StringImpl.h:70 */ +struct MStringImpl { + unsigned m_refCount; + unsigned m_length; + union { + const unsigned char *m_data8; + const unsigned short *m_data16; + }; + union { + void *m_buffer; + struct MStringImpl *m_substringBuffer; + unsigned short *m_copyData16; + }; + unsigned m_hashAndFlags; +}; + +/* location: webkit2-efl-123997_0.11.113/Source/JavaScriptCore/profiler/ + * CallIdentifier.h:36 + */ +struct MCallIdentifier { + struct MStringImpl *m_name; + struct MStringImpl *m_url; + unsigned m_lineNumber; +}; + +enum { + OFFSET_NAME = offsetof(struct MCallIdentifier, m_name), + OFFSET_URL = offsetof(struct MCallIdentifier, m_url), + OFFSET_LNUM = offsetof(struct MCallIdentifier, m_lineNumber) +}; + + +static int pack_web_string(void *data, size_t size, + struct MStringImpl __user *str_imp) +{ + int ret; + char __user *str; + unsigned len; + char __user **pstr; + unsigned __user *plen; + + pstr = (void __user *)str_imp + offsetof(struct MStringImpl, m_data8); + plen = (void __user *)str_imp + offsetof(struct MStringImpl, m_length); + + if (get_user(str, pstr) || + get_user(len, plen)) { + printk(WEB_PREFIX "%s: cannot read user memory\n", __func__); + return -EPERM; + } + + if (size < len + 1) { + printk(WEB_PREFIX "function name is very long(len=%u)\n", len); + return -ENOMEM; + } + + ret = strncpy_from_user(data, str, len); + if (ret < 0) { + printk(WEB_PREFIX "%s: cannot read user memory\n", __func__); + return ret; + } + + ((char *)data)[ret] = '\0'; + + return ret + 1; +} + + +void web_msg_entry(struct pt_regs *regs) +{ + int ret; + struct swap_msg *m; + void *p; + long t_name, t_url; + unsigned lnum; + size_t pack_size = 0, size; + struct MCallIdentifier *call_id; + struct task_struct *task = current; + + if (!check_event(task)) + return; + + call_id = (void *)swap_get_uarg(regs, 2); + if (get_user(t_name, (long *)((long)call_id + OFFSET_NAME)) || + get_user(t_url, (long *)((long)call_id + OFFSET_URL)) || + get_user(lnum, (unsigned *)((long)call_id + OFFSET_LNUM))) { + printk(WEB_PREFIX "%s: cannot read user memory\n", __func__); + return; + } + + m = swap_msg_get(MSG_WEB_FUNCTION_ENTRY); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + /* Pack message */ + /* PID */ + *(u32 *)p = task->tgid; + p += sizeof(u32); + /* TID */ + *(u32 *)p = task->pid; + p += sizeof(u32); + /* Line number (in source file) */ + *(u32 *)p = lnum; + p += sizeof(u32); + + size -= 3 * sizeof(u32); + pack_size += 3 * sizeof(u32); + + /* Function name */ + ret = pack_web_string(p, size, (struct MStringImpl *)t_name); + if (ret < 0) + goto put_msg; + + size -= ret; + pack_size += ret; + + /* URL (source file) */ + ret = pack_web_string(p, size, (struct MStringImpl *)t_url); + if (ret < 0) + goto put_msg; + + swap_msg_flush(m, pack_size + ret); + +put_msg: + swap_msg_put(m); +} + +void web_msg_exit(struct pt_regs *regs) +{ + int ret; + struct swap_msg *m; + void *p; + long t_name; + size_t pack_size = 0, size; + struct MCallIdentifier *call_id; + struct task_struct *task = current; + + if (!check_event(task)) + return; + + call_id = (void *)swap_get_uarg(regs, 2); + if (get_user(t_name, (long *)((long)call_id + OFFSET_NAME))) { + printk(WEB_PREFIX "%s: cannot read user memory\n", __func__); + return; + } + + m = swap_msg_get(MSG_WEB_FUNCTION_EXIT); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + /* PID */ + *(u32 *)p = task->tgid; + p += sizeof(u32); + + /* TID */ + *(u32 *)p = task->pid; + p += sizeof(u32); + + size -= 2 * sizeof(u32); + pack_size += 2 * sizeof(u32); + + /* Function name */ + ret = pack_web_string(p, size, (struct MStringImpl *)t_name); + if (ret < 0) + goto put_msg; + + swap_msg_flush(m, pack_size + ret); + +put_msg: + swap_msg_put(m); +} diff --git a/webprobe/web_msg.h b/webprobe/web_msg.h new file mode 100644 index 0000000..209562b --- /dev/null +++ b/webprobe/web_msg.h @@ -0,0 +1,34 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#ifndef _WEB_MSG_H +#define _WEB_MSG_H + + +struct pt_regs; + + +void web_msg_entry(struct pt_regs *regs); +void web_msg_exit(struct pt_regs *regs); + + +#endif /* _WEB_MSG_H */ diff --git a/webprobe/webprobe.c b/webprobe/webprobe.c index 96fa006..5de8fea 100644 --- a/webprobe/webprobe.c +++ b/webprobe/webprobe.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -41,6 +40,7 @@ #include "webprobe_debugfs.h" #include "webprobe_prof.h" +#include "web_msg.h" static unsigned long inspserver_addr_local; @@ -104,11 +104,11 @@ static int web_entry_handler(struct uretprobe_instance *ri, if (addr == web_prof_addr(WILL_EXECUTE) && d == web_prof_lib_dentry()) { willexecute_addr_local = ip->orig_addr; - return entry_web_event(addr, regs); + web_msg_entry(regs); } else if (addr == web_prof_addr(DID_EXECUTE) && d == web_prof_lib_dentry()) { didexecute_addr_local = ip->orig_addr; - return exit_web_event(addr, regs); + web_msg_exit(regs); } } diff --git a/writer/Kbuild b/writer/Kbuild index 1df96c8..1c938cf 100644 --- a/writer/Kbuild +++ b/writer/Kbuild @@ -5,7 +5,6 @@ KBUILD_EXTRA_SYMBOLS = $(src)/../buffer/Module.symvers \ obj-m := swap_writer.o swap_writer-y := swap_writer_module.o \ debugfs_writer.o \ - event_filter.o + event_filter.o \ + swap_msg.o -swap_writer-$(CONFIG_ARM) += kernel_operations_arm.o -swap_writer-$(CONFIG_X86) += kernel_operations_x86.o diff --git a/writer/debugfs_writer.c b/writer/debugfs_writer.c index 1fbb706..b577bf7 100644 --- a/writer/debugfs_writer.c +++ b/writer/debugfs_writer.c @@ -35,7 +35,7 @@ #include #include #include -#include "swap_writer_module.h" +#include "swap_msg.h" #include "event_filter.h" @@ -93,7 +93,7 @@ static ssize_t write_raw(struct file *file, const char __user *user_buf, goto put_buf; } - ret = raw_msg(buf, count); + ret = swap_msg_raw(buf, count); put_buf: put_current_buf(); diff --git a/writer/kernel_operations.h b/writer/kernel_operations.h index eb51ed7..a5014e7 100644 --- a/writer/kernel_operations.h +++ b/writer/kernel_operations.h @@ -33,6 +33,7 @@ #define __KERNEL_OPERATIONS_H__ #include +#include #include /* MESSAGES */ @@ -89,10 +90,4 @@ static inline u32 get_regs_ret_func(struct pt_regs *regs) #endif /* CONFIG_arch */ -int get_args(unsigned long args[], int cnt, struct pt_regs *regs); - -/* Returns shared kernel memory area name if it is found, otherwise - NULL */ -const char *get_shared_kmem(struct mm_struct *mm, unsigned long *start, - unsigned long *end); - #endif /* __KERNEL_OPERATIONS_H__ */ diff --git a/writer/kernel_operations_arm.c b/writer/kernel_operations_arm.c deleted file mode 100644 index db9e434..0000000 --- a/writer/kernel_operations_arm.c +++ /dev/null @@ -1,109 +0,0 @@ -/** - * writer/kernel_operations_arm.c - * @author Alexander Aksenov - * - * @section LICENSE - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * @section COPYRIGHT - * - * Copyright (C) Samsung Electronics, 2013 - * - * @section DESCRIPTION - * - * ARM arch-dependent operations. - */ - -#include -#include -#include -#include -#include -#include - -#include "kernel_operations.h" - - -/* ======================= ARGS ========================== */ - -/** - * @brief Returns arg values. - * - * @param[out] args Pointer to array where argument values should be stored/ - * @param cnt Arguments count. - * @param regs Pointer to register data. - * @return 0. - */ -int get_args(unsigned long args[], int cnt, struct pt_regs *regs) -{ - /* All args, except first 4, are passed on the stack */ - enum { stack_args = 4 }; - int i, args_in_regs; - - args_in_regs = cnt < 3 ? cnt : 3; - - /* Get first 4 args from registers */ - switch (args_in_regs) { - case 3: - args[3] = regs->ARM_r3; - case 2: - args[2] = regs->ARM_r2; - case 1: - args[1] = regs->ARM_r1; - case 0: - args[0] = regs->ARM_r0; - } - - /* Get other args from stack */ - for (i = stack_args; i < cnt; ++i) { - unsigned long *args_in_sp = (unsigned long *)regs->ARM_sp + - i - stack_args; - if (get_user(args[i], args_in_sp)) - printk(KERN_INFO "failed to dereference a pointer, addr=%p\n", - args_in_sp); - } - - return 0; -} - - -/* ================== KERNEL SHARED MEM ===================== */ - -/* CONFIG_VECTORS_BASE used to handle both MMU and non-MMU cases. - * According to docs (Documentation/arm/memory.txt) all vector addresses - * are fixed and vectors are always equal to one page, so, - * end = start + PAGE_SIZE - * */ - -/** - * @brief Gets shared kernel memory addresses. - * - * @param mm Pointer to process mm_struct. - * @param[out] start Pointer to the variable where the first shared mem - * address should be put. - * @param[out] end Pointer to the variable where the last shared mem - * address should be put. - * @return Pointer to the string with shared mem area name. - */ -const char *get_shared_kmem(struct mm_struct *mm, - unsigned long *start, - unsigned long *end) -{ - *start = CONFIG_VECTORS_BASE; - *end = CONFIG_VECTORS_BASE + PAGE_SIZE; - - return "[vectors]"; -} diff --git a/writer/kernel_operations_x86.c b/writer/kernel_operations_x86.c deleted file mode 100644 index 1335ccd..0000000 --- a/writer/kernel_operations_x86.c +++ /dev/null @@ -1,121 +0,0 @@ -/** - * writer/kernel_operations_x86.c - * @author Alexander Aksenov - * - * @section LICENSE - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * @section COPYRIGHT - * - * Copyright (C) Samsung Electronics, 2013 - * - * @section DESCRIPTION - * - * X86 arch-dependent operations. - */ - -#include -#include -#include -#include -#include -#include - -#include "kernel_operations.h" - - -/* ======================= ARGS ========================== */ - -/** - * @brief Returns arg values. - * - * @param[out] args Pointer to array where argument values should be stored/ - * @param cnt Arguments count. - * @param regs Pointer to register data. - * @return 0. - */ -int get_args(unsigned long args[], int cnt, struct pt_regs *regs) -{ - int i, stack_args = 0; - - /* If we're in kernel mode on x86, get arguments from bx, cx, dx, si, - * di, bp - */ - if (!user_mode(regs)) { - int args_in_regs; - args_in_regs = cnt < 5 ? cnt : 5; - stack_args = 6; - - switch (args_in_regs) { - case 5: - args[5] = regs->bp; - case 4: - args[4] = regs->di; - case 3: - args[3] = regs->si; - case 2: - args[2] = regs->dx; - case 1: - args[1] = regs->cx; - case 0: - args[0] = regs->bx; - } - } - - /* Get other args from stack */ - for (i = stack_args; i < cnt; ++i) { - unsigned long *args_in_sp = (unsigned long *)regs->sp + - 1 + i - stack_args; - if (get_user(args[i], args_in_sp)) - printk(KERN_INFO "failed to dereference a pointer, addr=%p\n", - args_in_sp); - } - - return 0; -} - - -/* ================== KERNEL SHARED MEM ===================== */ - -/** - * @brief Gets shared kernel memory addresses. - * - * @param mm Pointer to process mm_struct. - * @param[out] start Pointer to the variable where the first shared mem - * address should be put. - * @param[out] end Pointer to the variable where the last shared mem - * address should be put. - * @return Pointer to the string with shared mem area name. - */ -const char *get_shared_kmem(struct mm_struct *mm, unsigned long *start, - unsigned long *end) -{ - unsigned long vdso; - struct vm_area_struct *vma_vdso; - - vdso = (unsigned long)mm->context.vdso; - vma_vdso = find_vma_intersection(mm, vdso, vdso + 1); - - if (vma_vdso == NULL) { - print_err("Cannot get VDSO mapping\n"); - return NULL; - } - - *start = vma_vdso->vm_start; - *end = vma_vdso->vm_end; - - return "[vdso]"; -} diff --git a/writer/swap_msg.c b/writer/swap_msg.c new file mode 100644 index 0000000..90a3d53 --- /dev/null +++ b/writer/swap_msg.c @@ -0,0 +1,388 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "swap_msg.h" + + +#define MSG_PREFIX KERN_INFO "[SWAP_MSG] " + + +struct swap_msg { + u32 msg_id; + u32 seq_num; + u64 time; + u32 len; + char payload[0]; +} __packed; + + +static char *cpu_buf[NR_CPUS]; +static atomic_t seq_num = ATOMIC_INIT(-1); +static atomic_t discarded = ATOMIC_INIT(0); + + +int swap_msg_init(void) +{ + size_t i; + const size_t end = ((size_t) 0) - 1; + + for (i = 0; i < NR_CPUS; ++i) { + cpu_buf[i] = kmalloc(SWAP_MSG_BUF_SIZE, GFP_KERNEL); + if (cpu_buf[i] == NULL) + goto no_mem; + } + + return 0; + +no_mem: + --i; + for (; i != end; --i) + kfree(cpu_buf[i]); + + return -ENOMEM; +} + +void swap_msg_exit(void) +{ + int i; + + for (i = 0; i < NR_CPUS; ++i) + kfree(cpu_buf[i]); +} + +void swap_msg_seq_num_reset(void) +{ + atomic_set(&seq_num, -1); +} +EXPORT_SYMBOL_GPL(swap_msg_seq_num_reset); + +void swap_msg_discard_reset(void) +{ + atomic_set(&discarded, 0); +} +EXPORT_SYMBOL_GPL(swap_msg_discard_reset); + +int swap_msg_discard_get(void) +{ + return atomic_read(&discarded); +} +EXPORT_SYMBOL_GPL(swap_msg_discard_get); + + +u64 swap_msg_timespec2time(struct timespec *ts) +{ + return ((u64)ts->tv_nsec) << 32 | ts->tv_sec; +} + + + + + +struct swap_msg *swap_msg_get(enum swap_msg_id id) +{ + struct timespec ts; + struct swap_msg *m; + + getnstimeofday(&ts); + + m = (struct swap_msg *)cpu_buf[get_cpu()]; + + m->msg_id = (u32)id; + m->seq_num = atomic_inc_return(&seq_num); + m->time = swap_msg_spec2time(&ts); + + return m; +} +EXPORT_SYMBOL_GPL(swap_msg_get); + +int swap_msg_flush(struct swap_msg *m, size_t size) +{ + if (unlikely(size >= SWAP_MSG_PAYLOAD_SIZE)) + return -ENOMEM; + + m->len = size; + + if (swap_buffer_write(m, SWAP_MSG_PRIV_DATA + size)) { + atomic_inc(&discarded); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(swap_msg_flush); + +void swap_msg_put(struct swap_msg *m) +{ + put_cpu(); +} +EXPORT_SYMBOL_GPL(swap_msg_put); + + + + + + +static unsigned long get_arg(struct pt_regs *regs, unsigned long n) +{ + return user_mode(regs) ? + swap_get_uarg(regs, n) : /* US argument */ + swap_get_sarg(regs, n); /* sys_call argument */ +} + +int swap_msg_pack_args(char *buf, int len, + const char *fmt, struct pt_regs *regs) +{ + char *buf_old = buf; + u32 *tmp_u32; + u64 *tmp_u64; + int i, /* the index of the argument */ + fmt_i, /* format index */ + fmt_len; /* the number of parameters, in format */ + + fmt_len = strlen(fmt); + + for (i = 0, fmt_i = 0; fmt_i < fmt_len; ++i, ++fmt_i) { + if (len < 2) + return -ENOMEM; + + *buf = fmt[fmt_i]; + buf += 1; + len -= 1; + + switch (fmt[fmt_i]) { + case 'b': /* 1 byte(bool) */ + if (len < 1) + return -ENOMEM; + *buf = (char)!!get_arg(regs, i); + buf += 1; + len -= 1; + break; + case 'c': /* 1 byte(char) */ + if (len < 1) + return -ENOMEM; + *buf = (char)get_arg(regs, i); + buf += 1; + len -= 1; + break; + case 'f': /* 4 byte(float) */ + case 'd': /* 4 byte(int) */ + if (len < 4) + return -ENOMEM; + tmp_u32 = (u32 *)buf; + *tmp_u32 = (u32)get_arg(regs, i); + buf += 4; + len -= 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_arg(regs, i); + buf += 8; + len -= 8; + break; + case 'w': /* 8 byte(double) */ + if (len < 8) + return -ENOMEM; + tmp_u64 = (u64 *)buf; + *tmp_u64 = get_arg(regs, i); + ++i; + *tmp_u64 |= (u64)get_arg(regs, i) << 32; + buf += 8; + len -= 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_arg(regs, i); + 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; + len -= ret + 1; + } + break; + default: + return -EINVAL; + } + } + + return buf - buf_old; +} +EXPORT_SYMBOL_GPL(swap_msg_pack_args); + +int swap_msg_pack_ret_val(char *buf, int len, + char ret_type, struct pt_regs *regs) +{ + 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)!!regs_return_value(regs); + ++buf; + break; + case 'c': /* 1 byte(char) */ + if (len < 1) + return -ENOMEM; + *buf = (char)regs_return_value(regs); + ++buf; + break; + case 'd': /* 4 byte(int) */ + if (len < 4) + return -ENOMEM; + tmp_u32 = (u32 *)buf; + *tmp_u32 = regs_return_value(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)regs_return_value(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 *)regs_return_value(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; +} +EXPORT_SYMBOL_GPL(swap_msg_pack_ret_val); + + + + + +int swap_msg_raw(void *data, size_t size) +{ + struct swap_msg *m = (struct swap_msg *)data; + + if (sizeof(*m) > size) { + printk(MSG_PREFIX "ERROR: message RAW small size=%u\n", size); + return -EINVAL; + } + + if (m->len + sizeof(*m) != size) { + printk(MSG_PREFIX "ERROR: message RAW wrong format\n"); + return -EINVAL; + } + + m->seq_num = atomic_inc_return(&seq_num); + + /* TODO: What should be returned?! When message was discarded. */ + if (swap_buffer_write(m, size)) + atomic_inc(&discarded); + + return size; +} +EXPORT_SYMBOL_GPL(swap_msg_raw); + +void swap_msg_error(const char *fmt, ...) +{ + int ret; + struct swap_msg *m; + void *p; + size_t size; + va_list args; + + m = swap_msg_get(MSG_ERROR); + p = swap_msg_payload(m); + size = swap_msg_size(m); + + va_start(args, fmt); + ret = vsnprintf(p, size, fmt, args); + va_end(args); + + if (ret <= 0) { + printk(MSG_PREFIX "ERROR: msg error packing, ret=%d\n", ret); + goto put_msg; + } + + swap_msg_flush(m, ret + 1); + +put_msg: + swap_msg_put(m); +} +EXPORT_SYMBOL_GPL(swap_msg_error); diff --git a/writer/swap_msg.h b/writer/swap_msg.h new file mode 100644 index 0000000..c3c3488 --- /dev/null +++ b/writer/swap_msg.h @@ -0,0 +1,98 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin + * + */ + + +#ifndef _SWAP_MSG_H +#define _SWAP_MSG_H + + +#include +#include + + +enum swap_msg_id { + MSG_PROC_INFO = 0x0001, + MSG_TERMINATE = 0x0002, + MSG_ERROR = 0x0003, + MSG_SAMPLE = 0x0004, + MSG_FUNCTION_ENTRY = 0x0008, + MSG_FUNCTION_EXIT = 0x0009, + MSG_SYSCALL_ENTRY = 0x000a, + MSG_SYSCALL_EXIT = 0x000b, + MSG_FILE_FUNCTION_ENTRY = 0x000c, + MSG_FILE_FUNCTION_EXIT = 0x000d, + MSG_CONTEXT_SWITCH_ENTRY = 0x0010, + MSG_CONTEXT_SWITCH_EXIT = 0x0011, + MSG_PROC_MAP = 0x0012, + MSG_PROC_UNMAP = 0x0013, + MSG_PROC_COMM = 0x0014, + MSG_WEB_FUNCTION_ENTRY = 0x0015, + MSG_WEB_FUNCTION_EXIT = 0x0016 +}; + +enum { + SWAP_MSG_PRIV_DATA = 20, + SWAP_MSG_BUF_SIZE = 32 * 1024, + SWAP_MSG_PAYLOAD_SIZE = SWAP_MSG_BUF_SIZE - SWAP_MSG_PRIV_DATA +}; + + +struct swap_msg; + + +static inline u64 swap_msg_spec2time(struct timespec *ts) +{ + return ((u64)ts->tv_nsec) << 32 | ts->tv_sec; +} + +struct swap_msg *swap_msg_get(enum swap_msg_id id); +int swap_msg_flush(struct swap_msg *m, size_t size); +void swap_msg_put(struct swap_msg *m); + +static inline void *swap_msg_payload(struct swap_msg *m) +{ + return (void *)m + SWAP_MSG_PRIV_DATA; +} + +static inline size_t swap_msg_size(struct swap_msg *m) +{ + return (size_t)SWAP_MSG_PAYLOAD_SIZE; +} + + +int swap_msg_pack_args(char *buf, int len, + const char *fmt, struct pt_regs *regs); +int swap_msg_pack_ret_val(char *buf, int len, + char ret_type, struct pt_regs *regs); + + +int swap_msg_raw(void *buf, size_t size); +void swap_msg_error(const char *fmt, ...); + +void swap_msg_seq_num_reset(void); +void swap_msg_discard_reset(void); +int swap_msg_discard_get(void); + +int swap_msg_init(void); +void swap_msg_exit(void); + + +#endif /* _SWAP_MSG_H */ diff --git a/writer/swap_writer_module.c b/writer/swap_writer_module.c index a9d219a..e120b3a 100644 --- a/writer/swap_writer_module.c +++ b/writer/swap_writer_module.c @@ -28,1601 +28,36 @@ * Packing and writing data. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include #include -#include -#include - -#include -#include - -#include "swap_writer_module.h" -#include "swap_writer_errors.h" -#include "kernel_operations.h" -#include "debugfs_writer.h" +#include "swap_msg.h" #include "event_filter.h" +#include "debugfs_writer.h" -/** - * @enum MSG_ID - * @brief Supported message IDs. - */ -enum MSG_ID { - MSG_PROC_INFO = 0x0001, /**< Process info */ - MSG_TERMINATE = 0x0002, /**< Terminate */ - MSG_ERROR = 0x0003, /**< Error */ - MSG_SAMPLE = 0x0004, /**< Sampler event */ - MSG_FUNCTION_ENTRY = 0x0008, /**< Function entry */ - MSG_FUNCTION_EXIT = 0x0009, /**< Function return */ - MSG_CONTEXT_SWITCH_ENTRY = 0x0010, /**< Context switch entry */ - MSG_CONTEXT_SWITCH_EXIT = 0x0011, /**< Context switch exit */ - MSG_PROC_MAP = 0x0012, /**< Process map */ - MSG_PROC_UNMAP = 0x0013, /**< Process unmap */ - MSG_PROC_COMM = 0x0014, /**< Process comm */ - MSG_WEB_FUNCTION_ENTRY = 0x0015, /**< Web function entry */ - MSG_WEB_FUNCTION_EXIT = 0x0016 /**< Web function exit */ -}; - -static char *cpu_buf[NR_CPUS]; -static u32 seq_num; -static unsigned int discarded; - -/** - * @brief Initializes new message. - * - * @param buf_size Message buffer size. - * @return Success. - */ -int init_msg(size_t buf_size) -{ - int i; - - for (i = 0; i < NR_CPUS; ++i) - cpu_buf[i] = kmalloc(buf_size, GFP_KERNEL); - - return E_SW_SUCCESS; -} -EXPORT_SYMBOL_GPL(init_msg); - -/** - * @brief Uninitializes message. - * - * @return Void. - */ -void uninit_msg(void) -{ - int i; - - for (i = 0; i < NR_CPUS; ++i) - kfree(cpu_buf[i]); -} -EXPORT_SYMBOL_GPL(uninit_msg); - -/** - * @brief Sets discarded events count to 0. - * - * @return Void. - */ -void reset_discarded(void) -{ - discarded = 0; -} -EXPORT_SYMBOL_GPL(reset_discarded); - -/** - * @brief Sets events sequence number to 0. - * - * @return Void. - */ -void reset_seq_num(void) -{ - seq_num = 0; -} -EXPORT_SYMBOL_GPL(reset_seq_num); - -/** - * @brief Gets discarded events count. - * - * @return Discarded events count. - */ -unsigned int get_discarded_count(void) -{ - return discarded; -} -EXPORT_SYMBOL_GPL(get_discarded_count); - -static inline char *get_current_buf(void) -{ - return cpu_buf[get_cpu()]; -} - -static inline void put_current_buf(void) -{ - put_cpu(); -} - -static inline u64 timespec2time(struct timespec *ts) -{ - return ((u64)ts->tv_nsec) << 32 | ts->tv_sec; -} - -/* ============================================================================ - * = BASIC MESSAGE FORMAT = - * ============================================================================ - */ - -/** - * @struct basic_msg_fmt - * @brief Basic message. - */ -struct basic_msg_fmt { - u32 msg_id; /**< Message ID */ - u32 seq_number; /**< Sequence number */ - u64 time; /**< Message time */ - u32 len; /**< Message length */ - char payload[0]; /**< Message itself */ -} __packed; - -#if 0 /* debug */ -static void print_hex(char *ptr, int len) -{ - int i; - - printk(KERN_INFO "print_hex:\n"); - for (i = 0; i < len; ++i) - printk(KERN_INFO "[%x] [%3d]=%2x\n", &ptr[i], i, ptr[i]); -} -#endif - -static int write_to_buffer(void *data) -{ - int result; - struct basic_msg_fmt *bmf = (struct basic_msg_fmt *)data; - - result = swap_buffer_write(bmf, bmf->len + sizeof(*bmf)); - if (result < 0) - discarded++; - - return result; -} - -static void set_len_msg(char *buf, char *end) -{ - struct basic_msg_fmt *bmf = (struct basic_msg_fmt *)buf; - bmf->len = end - buf - sizeof(*bmf); -} - -static inline void set_seq_num(struct basic_msg_fmt *bmf) -{ - bmf->seq_number = seq_num; - seq_num++; -} - -static inline void set_time(struct basic_msg_fmt *bmf) -{ - struct timespec ts; - - getnstimeofday(&ts); - bmf->time = timespec2time(&ts); -} - -static char *pack_basic_msg_fmt(char *buf, enum MSG_ID id) -{ - struct basic_msg_fmt *bmf = (struct basic_msg_fmt *)buf; - - set_time(bmf); - set_seq_num(bmf); - bmf->msg_id = id; - - return bmf->payload; -} - - - - - -/* ============================================================================ - * = PROCESS INFO = - * ============================================================================ - */ - -/** - * @struct proc_info_top - * @brief Top proc info part. - */ -struct proc_info_top { - u32 pid; /**< Process PID */ - char comm[0]; /**< Message */ -} __packed; - -/** - * @struct proc_info_bottom - * @brief Bottom proc info part. - */ -struct proc_info_bottom { - u32 ppid; /**< Parent PID */ - u32 start_sec; /**< Start time sec */ - u32 start_nsec; /**< Start time nsec */ - u64 low_addr; /**< Low address */ - u64 high_addr; /**< High address */ - char bin_path[0]; /**< Binary path */ -} __packed; - -/** - * @struct proc_info_part - * @brief Process info part. - */ -struct proc_info_part { - u32 lib_cnt; /**< Library count */ - char libs[0]; /**< Libraries */ -} __packed; - -/** - * @struct lib_obj - * @brief Library object. - */ -struct lib_obj { - u64 low_addr; /**< Low library address */ - u64 high_addr; /**< High library address */ - char lib_path[0]; /**< Library path */ -} __packed; - -static char *pack_path(char *buf, struct file *file) -{ - enum { TMP_BUF_LEN = 512 }; - char tmp_buf[TMP_BUF_LEN]; - char NA[] = "N/A"; - char *filename; - size_t len; - - if (file == NULL) - return strcpy(buf, NA) + sizeof(NA); - - filename = d_path(&file->f_path, tmp_buf, TMP_BUF_LEN); - if (IS_ERR_OR_NULL(filename)) - return strcpy(buf, NA) + sizeof(NA); - - len = strlen(filename) + 1; - memcpy(buf, filename, len); - - return buf + len; -} - -static char *pack_lib_obj(char *lib_obj, struct vm_area_struct *vma) -{ - struct lib_obj *lo = (struct lib_obj *)lib_obj; - - lo->low_addr = vma->vm_start; - lo->high_addr = vma->vm_end; - - return pack_path(lo->lib_path, vma->vm_file); -} - -/* FIXME: check_vma()*/ -static int check_vma(struct vm_area_struct *vma) -{ - return vma->vm_file && - !(vma->vm_pgoff != 0 || - !(vma->vm_flags & VM_EXEC) || - !(vma->vm_flags & (VM_READ | VM_MAYREAD))); -} - -static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm, - struct dentry *dentry) -{ - struct vm_area_struct *vma; - - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (vma->vm_file && (vma->vm_flags & VM_EXEC) && - (vma->vm_file->f_dentry == dentry)) - goto out; - } - - vma = NULL; -out: - - return vma; -} - -static char *pack_shared_kmem(char *lib_obj, - struct mm_struct *mm, - u32 *lib_cnt_p) -{ - struct lib_obj *so = (struct lib_obj *)lib_obj; - char *so_obj; - unsigned long start = 0, end = 0; - - const char *kmem_name = get_shared_kmem(mm, &start, &end); - size_t name_len; - - if (kmem_name == NULL) - return lib_obj; - - name_len = strlen(kmem_name) + 1; - so->low_addr = (u64)start; - so->high_addr = (u64)end; - memcpy(so->lib_path, kmem_name, name_len); - (*lib_cnt_p)++; - so_obj = so->lib_path + name_len; - - return so_obj; -} - -static char *pack_libs(char *lib_obj, struct mm_struct *mm, u32 *lib_cnt_p) -{ - struct vm_area_struct *vma; - - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (check_vma(vma)) { - lib_obj = pack_lib_obj(lib_obj, vma); - ++(*lib_cnt_p); - } - } - - return lib_obj; -} - -static char *pack_proc_info_part(char *end_path, struct mm_struct *mm) -{ - struct proc_info_part *pip; - char *lib_obj; - u32 *lib_cnt_p; - - pip = (struct proc_info_part *)end_path; - pip->lib_cnt = 0; - lib_obj = pip->libs; - lib_cnt_p = &pip->lib_cnt; - - lib_obj = pack_libs(lib_obj, mm, lib_cnt_p); - lib_obj = pack_shared_kmem(lib_obj, mm, lib_cnt_p); - - return lib_obj; -} - -static char *pack_comm(char *buf, struct task_struct *task) -{ - get_task_comm(buf, task); - - return buf + strlen(buf) + 1; -} - -static char *pack_proc_info_top(char *data, struct task_struct *task) -{ - struct proc_info_top *pit = (struct proc_info_top *)data; - - pit->pid = task->tgid; - - return pack_comm(pit->comm, task); -} - -static char *pack_proc_info_bottom(char *data, struct task_struct *task, - struct dentry *dentry) -{ - struct proc_info_bottom *pib = (struct proc_info_bottom *)data; - struct vm_area_struct *vma = find_vma_exe_by_dentry(task->mm, dentry); - struct timespec boot_time; - struct timespec start_time; - char *end_path = NULL; - - getboottime(&boot_time); - start_time = timespec_add(boot_time, task->real_start_time); - - pib->ppid = task->real_parent->tgid; - pib->start_sec = (u32)start_time.tv_sec; - pib->start_nsec = (u32)start_time.tv_nsec; - - if (vma) { - pib->low_addr = vma->vm_start; - pib->high_addr = vma->vm_end; - end_path = pack_path(pib->bin_path, vma->vm_file); - } else { - pib->low_addr = 0; - pib->high_addr = 0; - end_path = pack_path(pib->bin_path, NULL); - } - return pack_proc_info_part(end_path, task->mm); -} - -static char *pack_proc_info(char *payload, struct task_struct *task, - struct dentry *dentry) -{ - payload = pack_proc_info_top(payload, task); - return pack_proc_info_bottom(payload, task, dentry); -} - -/** - * @brief Packs and writes process info message. Called with - * down\up\_read(&task->mm->mmap_sem). - * - * @param task Pointer to the target task_struct. - * @param dentry Pointer to the task dentry. - * @return Written data size on success, negative error code on error. - */ -int proc_info_msg(struct task_struct *task, struct dentry *dentry) +static int core_init(void) { - char *buf, *payload, *buf_end; int ret; - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_PROC_INFO); - buf_end = pack_proc_info(payload, task, dentry); - - set_len_msg(buf, buf_end); + ret = swap_msg_init(); + if (ret) + return ret; - ret = write_to_buffer(buf); - put_current_buf(); + ret = event_filter_init(); + if (ret) + swap_msg_exit(); return ret; } -EXPORT_SYMBOL_GPL(proc_info_msg); - - - - - -/* ============================================================================ - * = PROCESS TERMINATE = - * ============================================================================ - */ - -/** - * @struct proc_terminate - * @brief Terminate message struct. - */ -struct proc_terminate { - u32 pid; /**< Process ID */ -} __packed; - -static char *pack_proc_terminate(char *payload, struct task_struct *task) -{ - struct proc_terminate *pt = (struct proc_terminate *)payload; - - pt->pid = task->pid; - return payload + sizeof(*pt); -} - -/** - * @brief Packs and writes terminate message. - * - * @param task Target task_struct. - * @return Void. - */ -void terminate_msg(struct task_struct *task) -{ - char *buf, *payload, *buf_end; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_TERMINATE); - buf_end = pack_proc_terminate(payload, task); - - set_len_msg(buf, buf_end); - - write_to_buffer(buf); - put_current_buf(); -} -EXPORT_SYMBOL_GPL(terminate_msg); - - - - - -/* ============================================================================ - * = PROCESS MAP = - * ============================================================================ - */ - -/** - * @struct proc_map - * @brief Process mapping info. - */ -struct proc_map { - u32 pid; /**< Process ID */ - u64 low_addr; /**< Low address */ - u64 high_addr; /**< High address */ - char bin_path[0]; /**< Binary path */ -} __packed; - -static char *pack_proc_map(char *payload, struct vm_area_struct *vma) -{ - struct proc_map *pm = (struct proc_map *)payload; - - pm->pid = current->tgid; - pm->low_addr = vma->vm_start; - pm->high_addr = vma->vm_end; - - return pack_path(pm->bin_path, vma->vm_file); -} - -/** - * @brief Packs and writes process map message. - * - * @param vma Target memory area. - * @return Void. - */ -void pcoc_map_msg(struct vm_area_struct *vma) -{ - char *buf, *payload, *buf_end; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_PROC_MAP); - buf_end = pack_proc_map(payload, vma); - - set_len_msg(buf, buf_end); - - write_to_buffer(buf); - put_current_buf(); -} -EXPORT_SYMBOL_GPL(pcoc_map_msg); - - - - - -/* ============================================================================ - * = PROCESS UNMAP = - * ============================================================================ - */ - -/** - * @struct proc_unmap - * @brief Process mapping info. - */ -struct proc_unmap { - u32 pid; /**< Process ID */ - u64 low_addr; /**< Low address */ - u64 high_addr; /**< High address */ -} __packed; - -static char *pack_proc_unmap(char *payload, unsigned long start, - unsigned long end) -{ - struct proc_unmap *pum = (struct proc_unmap *)payload; - - pum->pid = current->tgid; - pum->low_addr = start; - pum->high_addr = end; - - return payload + sizeof(*pum); -} - -/** - * @brief Packs and writes process unmap message. - * - * @param start Unmapping area low address. - * @param end Unmapping area high address. - * @return Void. - */ -void proc_unmap_msg(unsigned long start, unsigned long end) -{ - char *buf, *payload, *buf_end; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_PROC_UNMAP); - buf_end = pack_proc_unmap(payload, start, end); - - set_len_msg(buf, buf_end); - - write_to_buffer(buf); - put_current_buf(); -} -EXPORT_SYMBOL_GPL(proc_unmap_msg); - - - - - -/* ============================================================================ - * = PROCESS COMM = - * ============================================================================ - */ - -/** - * @struct proc_comm - * @brief Comm message info. - */ -struct proc_comm { - u32 pid; /**< Process ID */ - char comm[0]; /**< Comm */ -} __packed; - -static char *pack_proc_comm(char *data, struct task_struct *task) -{ - struct proc_comm *pcomm = (struct proc_comm *)data; - - pcomm->pid = task->tgid; - - return pack_comm(pcomm->comm, task); -} -/** - * @brief Packs and writes process comm message. - * - * @param task Target task_struct. - * @return Void. - */ -void proc_comm_msg(struct task_struct *task) +static void core_exit(void) { - char *buf, *payload, *buf_end; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_PROC_COMM); - buf_end = pack_proc_comm(payload, task); - - set_len_msg(buf, buf_end); - - write_to_buffer(buf); - put_current_buf(); + event_filter_exit(); + swap_msg_exit(); } -EXPORT_SYMBOL_GPL(proc_comm_msg); - - - - - -/* ============================================================================ - * = SAMPLE = - * ============================================================================ - */ - -/** - * @struct sample - * @brief Sampler event info. - */ -struct sample { - u32 pid; /**< Process ID */ - u64 pc_addr; /**< Instruction pointer address */ - u32 tid; /**< Thread ID */ - u32 cpu_num; /**< CPU number */ -} __packed; - -static char *pack_sample(char *payload, struct pt_regs *regs) -{ - struct sample *s = (struct sample *)payload; - struct task_struct *task = current; - - s->pid = task->tgid; - s->pc_addr = get_regs_ip(regs); - s->tid = task->pid; - s->cpu_num = smp_processor_id(); - - return payload + sizeof(*s); -} - -/** - * @brief Packs and writes sample message. - * - * @param regs Pointer to CPU register data. - * @return Written data size on success, negative error code on error. - */ -int sample_msg(struct pt_regs *regs) -{ - char *buf, *payload, *buf_end; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_SAMPLE); - buf_end = pack_sample(payload, regs); - - set_len_msg(buf, buf_end); - - ret = write_to_buffer(buf); - put_current_buf(); - - return ret; -} -EXPORT_SYMBOL_GPL(sample_msg); - - - - -/* ============================================================================ - * = ENTRY = - * ============================================================================ - */ - -/** - * @struct msg_func_entry - * @brief Entry event info. - */ -struct msg_func_entry { - u32 pid; /**< Process ID */ - u32 tid; /**< Thread ID */ - u16 probe_type; /**< Probe type */ - u16 probe_sub_type; /**< Probe subtype */ - u64 pc_addr; /**< Instruction pointer address. */ - u64 caller_pc_addr; /**< Return address */ - u32 cpu_num; /**< CPU number */ - u32 cnt_args; /**< Count of args */ - char args[0]; /**< Args format string */ -} __packed; - -static char *pack_msg_func_entry(char *payload, const char *fmt, - unsigned long func_addr, struct pt_regs *regs, - enum PROBE_TYPE pt, int sub_type) -{ - struct msg_func_entry *mfe = (struct msg_func_entry *)payload; - struct task_struct *task = current; - - mfe->pid = task->tgid; - mfe->tid = task->pid; - mfe->cpu_num = smp_processor_id(); - mfe->pc_addr = func_addr; - mfe->caller_pc_addr = get_regs_ret_func(regs); - mfe->probe_type = pt; - mfe->probe_sub_type = sub_type; - mfe->cnt_args = strlen(fmt); - - return payload + sizeof(*mfe); -} - -static unsigned long get_arg(struct pt_regs *regs, unsigned long n) -{ - return user_mode(regs) ? - swap_get_uarg(regs, n) : /* US argument */ - swap_get_sarg(regs, n); /* sys_call argument */ -} - -static int pack_args(char *buf, int len, const char *fmt, struct pt_regs *regs) -{ - char *buf_old = buf; - u32 *tmp_u32; - u64 *tmp_u64; - int i, /* the index of the argument */ - fmt_i, /* format index */ - fmt_len; /* the number of parameters, in format */ - - fmt_len = strlen(fmt); - - for (i = 0, fmt_i = 0; fmt_i < fmt_len; ++i, ++fmt_i) { - if (len < 2) - return -ENOMEM; - - *buf = fmt[fmt_i]; - buf += 1; - len -= 1; - - switch (fmt[fmt_i]) { - case 'b': /* 1 byte(bool) */ - *buf = (char)!!get_arg(regs, i); - buf += 1; - len -= 1; - break; - case 'c': /* 1 byte(char) */ - *buf = (char)get_arg(regs, i); - buf += 1; - len -= 1; - break; - case 'f': /* 4 byte(float) */ - case 'd': /* 4 byte(int) */ - if (len < 4) - return -ENOMEM; - tmp_u32 = (u32 *)buf; - *tmp_u32 = (u32)get_arg(regs, i); - buf += 4; - len -= 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_arg(regs, i); - buf += 8; - len -= 8; - break; - case 'w': /* 8 byte(double) */ - if (len < 8) - return -ENOMEM; - tmp_u64 = (u64 *)buf; - *tmp_u64 = get_arg(regs, i); - ++i; - *tmp_u64 |= (u64)get_arg(regs, i) << 32; - buf += 8; - len -= 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_arg(regs, i); - 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; - len -= ret + 1; - } - break; - default: - return -EINVAL; - } - } - - return buf - buf_old; -} - -/** - * @brief Packs and writes entry event message. - * - * @param fmt Arguments format string. - * @param func_addr Function address. - * @param regs CPU register data. - * @param pt Probe type. - * @param sub_type Probe sub type. - * @return Written data size on success, negative error code on error. - */ -int entry_event(const char *fmt, unsigned long func_addr, struct pt_regs *regs, - enum PROBE_TYPE pt, int sub_type) -{ - char *buf, *payload, *args, *buf_end; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_ENTRY); - args = pack_msg_func_entry(payload, fmt, func_addr, - regs, pt, sub_type); - - /* FIXME: len = 1024 */ - ret = pack_args(args, 1024, fmt, regs); - if (ret < 0) { - printk(KERN_INFO "ERROR: !!!!!\n"); - goto put_buf; - } - - buf_end = args + ret; - - set_len_msg(buf, buf_end); - - ret = write_to_buffer(buf); - -put_buf: - put_current_buf(); - - return ret; -} -EXPORT_SYMBOL_GPL(entry_event); - - - - - -/* ============================================================================ - * = EXIT = - * ============================================================================ - */ - -/** - * @struct msg_func_exit - * @brief Exit event message info. - */ -struct msg_func_exit { - u32 pid; /**< PID */ - u32 tid; /**< TID */ - u16 probe_type; /**< Probe type */ - u16 probe_sub_type; /**< Probe subtype */ - u64 pc_addr; /**< Instruction pointer */ - u64 caller_pc_addr; /**< Return address */ - u32 cpu_num; /**< CPU number */ - char ret_val[0]; /**< Return value */ -} __packed; - -static int pack_msg_ret_val(char *buf, int len, char ret_type, - struct pt_regs *regs) -{ - 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, int pt, int sub_type, - 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->probe_type = pt; - mfe->probe_sub_type = sub_type; - mfe->cpu_num = smp_processor_id(); - mfe->pc_addr = func_addr; - mfe->caller_pc_addr = ret_addr; - - ret = pack_msg_ret_val(mfe->ret_val, len, ret_type, regs); - if (ret < 0) { - printk(KERN_INFO "ERROR: packing MSG_FUNCTION_EXIT (ret=%d)\n", - ret); - return ret; - } - - return sizeof(*mfe) + ret; -} - -/** - * @brief Packs and writes exit event. - * - * @param ret_type Return value type. - * @param regs CPU register data. - * @param sub_type Event subtype. - * @param func_addr Function address. - * @param ret_addr Return address. - * @return Written data size on success, negative error code on error. - */ -int exit_event(char ret_type, struct pt_regs *regs, int pt, int sub_type, - unsigned long func_addr, unsigned long ret_addr) -{ - char *buf, *payload, *buf_end; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_EXIT); - /* FIXME: len=1024 */ - ret = pack_msg_func_exit(payload, 1024, ret_type, regs, pt, sub_type, - func_addr, ret_addr); - if (ret < 0) - goto put_buf; - - buf_end = payload + ret; - set_len_msg(buf, buf_end); - - ret = write_to_buffer(buf); - -put_buf: - put_current_buf(); - - return ret; -} -EXPORT_SYMBOL_GPL(exit_event); - - - - - -/* ============================================================================ - * = CONTEXT SWITCH = - * ============================================================================ - */ - -/* - * @struct msg_context_switch - * @brief Context switch message info. - */ -struct msg_context_switch { - u64 pc_addr; /**< Instruction pointer */ - u32 pid; /**< PID */ - u32 tid; /**< TID */ - u32 cpu_num; /**< CPU number */ -} __packed; - -static char *pack_msg_context_switch(char *payload, struct pt_regs *regs) -{ - struct msg_context_switch *mcs = (struct msg_context_switch *)payload; - struct task_struct *task = current; - - mcs->pc_addr = 0; - mcs->pid = task->tgid; - mcs->tid = task->pid; - mcs->cpu_num = smp_processor_id(); - - return payload + sizeof(*mcs); -} - -static int context_switch(struct pt_regs *regs, enum MSG_ID id) -{ - char *buf, *payload, *buf_end; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, id); - buf_end = pack_msg_context_switch(payload, regs); - set_len_msg(buf, buf_end); - - ret = write_to_buffer(buf); - put_current_buf(); - - return ret; -} - -/** - * @brief Packs and writes context switch entry message. - * - * @param regs CPU register data. - * @return Written data size on success, negative error code on error. - */ -int switch_entry(struct pt_regs *regs) -{ - return context_switch(regs, MSG_CONTEXT_SWITCH_ENTRY); -} -EXPORT_SYMBOL_GPL(switch_entry); - -/** - * @brief Packs and writes context switch exit message. - * - * @param regs CPU register data. - * @return Written data size on success, negative error code on error. - */ -int switch_exit(struct pt_regs *regs) -{ - return context_switch(regs, MSG_CONTEXT_SWITCH_EXIT); -} -EXPORT_SYMBOL_GPL(switch_exit); - - - - -/* ============================================================================ - * = ERROR = - * ============================================================================ - */ - -/** - * @struct msg_err - * @brief Error message info. - */ -struct msg_err { - char msg[0]; /**< Error message string */ -} __packed; - -static char *pack_msg_err(char *payload, const char *fmt, va_list args) -{ - struct msg_err *me = (struct msg_err *)payload; - int ret; - - ret = vsprintf(me->msg, fmt, args); - if (ret < 0) - return payload; - - return payload + sizeof(*me) + ret + 1; -} - -/** - * @brief Packs and writes error message. - * - * @param fmt Error string format - * @return Written data size on success, negative error code on error. - */ -int error_msg(const char *fmt, ...) -{ - char *buf, *payload, *buf_end; - va_list args; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_ERROR); - - va_start(args, fmt); - buf_end = pack_msg_err(payload, fmt, args); - va_end(args); - - set_len_msg(buf, buf_end); - - ret = write_to_buffer(buf); - put_current_buf(); - - return ret; -} -EXPORT_SYMBOL_GPL(error_msg); - - - - - -/* ============================================================================ - * = MESSAGES FROM USER SPACE = - * ============================================================================ - */ - -/** - * @brief Interface for writing messages from user space directly. - * - * @param buf Pointer to message. - * @param len Message len. - * @return len - */ -int raw_msg(char *buf, size_t len) -{ - struct basic_msg_fmt *bmf = (struct basic_msg_fmt *)buf; - - if (sizeof(*bmf) > len) - return -EINVAL; - - if (bmf->len + sizeof(*bmf) != len) - return -EINVAL; - - set_seq_num(bmf); - write_to_buffer(buf); - - return len; -} - - - -/* ============================================================================ - * = CUSTOM EVENT = - * ============================================================================ - */ - -static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) -{ - enum { max_str_len = 512 }; - const char *p; - char *buf_orig = buf; - - for (p = fmt; *p != '\0'; p++) { - char ch = *p; - - if (len < 1) - return -ENOMEM; - - *buf = tolower(ch); - buf += 1; - len -= 1; - - switch (ch) { - case 'b': /* 1 byte(bool) */ - if (len < 1) - return -ENOMEM; - *buf = !!(char)va_arg(args, int); - buf += 1; - len -= 1; - break; - case 'c': /* 1 byte(char) */ - if (len < 1) - return -ENOMEM; - *buf = (char)va_arg(args, int); - buf += 1; - len -= 1; - break; - case 'f': /* 4 byte(float) */ - case 'd': /* 4 byte(int) */ - if (len < 4) - return -ENOMEM; - *(u32 *)buf = va_arg(args, u32); - buf += 4; - len -= 4; - break; - case 'x': /* 8 byte(long) */ - case 'w': /* 8 byte(double) */ - if (len < 8) - return -ENOMEM; - *(u64 *)buf = va_arg(args, u64); - buf += 8; - len -= 8; - break; - case 'p': /* 8 byte(pointer) */ - if (len < 8) - return -ENOMEM; - *(u64 *)buf = va_arg(args, unsigned long); - buf += 8; - len -= 8; - break; - case 's': /* userspace string with '\0' terminating byte */ - { - const char __user *str; - int len_s, n; - - str = va_arg(args, const char __user *); - /* strnlen_user includes '\0' in its return value */ - len_s = strnlen_user(str, max_str_len); - if (len < len_s) - return -ENOMEM; - /* strncpy_from_user returns the length of the copied - * string (without '\0') */ - n = strncpy_from_user(buf, str, len_s - 1); - if (n < 0) - return n; - buf[n] = '\0'; - - buf += n + 1; - len -= n + 1; - break; - } - case 'S': /* kernelspace string with '\0' terminating byte */ - { - const char *str; - int len_s; - - str = va_arg(args, const char *); - len_s = strnlen(str, max_str_len); - if (len < len_s + 1) /* + '\0' */ - return -ENOMEM; - strncpy(buf, str, len_s); - buf[len_s] = '\0'; - - buf += len_s + 1; - len -= len_s + 1; - break; - } - case 'a': /* userspace byte array (len + ptr) */ - { - const void __user *ptr; - u32 len_p, n; - - len_p = va_arg(args, u32); - if (len < sizeof(len_p) + len_p) - return -ENOMEM; - *(u32 *)buf = len_p; - buf += sizeof(len_p); - len -= sizeof(len_p); - - ptr = va_arg(args, const void __user *); - n = copy_from_user(buf, ptr, len_p); - if (n < len_p) - return -EFAULT; - buf += len_p; - len -= len_p; - break; - } - case 'A': /* kernelspace byte array (len + ptr) */ - { - const void *ptr; - u32 len_p; - - /* array size */ - len_p = va_arg(args, u32); - if (len < sizeof(len_p) + len_p) - return -ENOMEM; - *(u32 *)buf = len_p; - buf += sizeof(len_p); - len -= sizeof(len_p); - - /* byte array */ - ptr = va_arg(args, const void *); - memcpy(buf, ptr, len_p); - buf += len_p; - len -= len_p; - break; - } - default: - return -EINVAL; - } - } - - return buf - buf_orig; -} - -enum { max_custom_event_size = 2048 }; - -/** - * @brief Packs and writes custom entry event. - * - * @param func_addr Function address. - * @param regs CPU register data. - * @param type Probe type. - * @param sub_type Probe sub type. - * @param fmt Format string. - * @return Written data size on success, negative error code on error. - */ -int custom_entry_event(unsigned long func_addr, struct pt_regs *regs, - int pt, int sub_type, const char *fmt, ...) -{ - char *buf, *payload, *args, *buf_end; - va_list vargs; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_ENTRY); - args = pack_msg_func_entry(payload, fmt, func_addr, - regs, pt, sub_type); - - va_start(vargs, fmt); - ret = pack_custom_event(args, max_custom_event_size, fmt, vargs); - va_end(vargs); - - if (ret < 0) - goto put_buf; - - buf_end = args + ret; - set_len_msg(buf, buf_end); - ret = write_to_buffer(buf); - -put_buf: - put_current_buf(); - - return ret; -} -EXPORT_SYMBOL_GPL(custom_entry_event); - -/* TODO currently this function is a simple wrapper. it will be refactored when - * protocol changes are applied */ - -/** - * @brief Packs and writes custom exit event. - * - * @param func_addr Function address. - * @param ret_addr Return address. - * @param regs CPU register data. - * @param fmt Format string. - * @return Written data size on success, negative error code on error. - */ -int custom_exit_event(unsigned long func_addr, unsigned long ret_addr, - struct pt_regs *regs, int pt, int sub_type, - const char *fmt, ...) -{ - char *buf, *payload, *buf_end; - int ret; - - buf = get_current_buf(); - payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_EXIT); - ret = pack_msg_func_exit(payload, max_custom_event_size, - fmt[0], regs, pt, sub_type, - func_addr, ret_addr); - if (ret < 0) - goto put_buf; - - buf_end = payload + ret; - set_len_msg(buf, buf_end); - - ret = write_to_buffer(buf); - -put_buf: - put_current_buf(); - - return ret; -} -EXPORT_SYMBOL_GPL(custom_exit_event); - - - - - -/* ============================================================================ - * = WEB APP EVENT = - * ============================================================================ - */ - -/* TODO: develop method for obtaining this data during build... */ -/* location: webkit2-efl-123997_0.11.113/Source/WTF/wtf/text/StringImpl.h:70 */ -struct MStringImpl { - unsigned m_refCount; - unsigned m_length; - union { - const unsigned char *m_data8; - const unsigned short *m_data16; - }; - union { - void *m_buffer; - struct MStringImpl *m_substringBuffer; - unsigned short *m_copyData16; - }; - unsigned m_hashAndFlags; -}; - -/* location: webkit2-efl-123997_0.11.113/Source/JavaScriptCore/profiler/ - * CallIdentifier.h:36 - */ -struct MCallIdentifier { - struct MStringImpl *m_name; - struct MStringImpl *m_url; - unsigned m_lineNumber; -}; - -int entry_web_event(unsigned long func_addr, struct pt_regs *regs) -{ - char *buf, *pl; - long t; - int ret = 0, n, lnum; - struct MCallIdentifier *callIdentifier; - struct { - const char *str; - int len; - } m_name, m_url; - struct task_struct *task = current; - - if (!check_event(current)) - return 0; - - callIdentifier = (void *)swap_get_uarg(regs, 2); - - if (get_user(t, (int *)&callIdentifier->m_name) || - get_user(m_name.str, &((struct MStringImpl *)t)->m_data8) || - get_user(m_name.len, &((struct MStringImpl *)t)->m_length) || - get_user(t, (int *)&callIdentifier->m_url) || - get_user(m_url.str, &((struct MStringImpl *)t)->m_data8) || - get_user(m_url.len, &((struct MStringImpl *)t)->m_length) || - get_user(lnum, (int *)&callIdentifier->m_lineNumber)) { - print_err("%s: cannot read user memory\n", __func__); - return 0; - } - - buf = get_current_buf(); - pl = pack_basic_msg_fmt(buf, MSG_WEB_FUNCTION_ENTRY); - - /* Pack message */ - /* PID */ - *(u32 *)pl = task->tgid; - pl += sizeof(u32); - /* TID */ - *(u32 *)pl = task->pid; - pl += sizeof(u32); - /* Line number (in source file) */ - *(u32 *)pl = lnum; - pl += sizeof(u32); - /* Function name */ - n = strncpy_from_user(pl, m_name.str, m_name.len); - if (n < 0) { - print_err("%s: cannot read user memory (function name)\n", - __func__); - goto put_current_buf_return; - } else { - pl[n] = '\0'; - pl += n + 1; - } - /* URL (source file) */ - n = strncpy_from_user(pl, m_url.str, m_url.len); - if (n < 0) { - print_err("%s: cannot read user memory (url)\n", __func__); - goto put_current_buf_return; - } else { - pl[n] = '\0'; - pl += n + 1; - } - - set_len_msg(buf, pl); - ret = write_to_buffer(buf); - -put_current_buf_return: - put_current_buf(); - return ret; -} -EXPORT_SYMBOL_GPL(entry_web_event); - -int exit_web_event(unsigned long func_addr, struct pt_regs *regs) -{ - char *buf, *pl; - long t; - int ret = 0, n; - struct MCallIdentifier *callIdentifier; - struct { - const char *str; - int len; - } m_name; - struct task_struct *task = current; - - if (!check_event(current)) - return 0; - - callIdentifier = (void *)swap_get_uarg(regs, 2); - - if (get_user(t, (int *)&callIdentifier->m_name) || - get_user(m_name.str, &((struct MStringImpl *)t)->m_data8) || - get_user(m_name.len, &((struct MStringImpl *)t)->m_length)) { - print_err("%s: cannot read user memory\n", __func__); - return 0; - } - - buf = get_current_buf(); - pl = pack_basic_msg_fmt(buf, MSG_WEB_FUNCTION_EXIT); - - /* Pack message */ - /* PID */ - *(u32 *)pl = task->tgid; - pl += sizeof(u32); - /* TID */ - *(u32 *)pl = task->pid; - pl += sizeof(u32); - /* Function name */ - n = strncpy_from_user(pl, m_name.str, m_name.len); - if (n < 0) { - print_err("%s: cannot read user memory (function name)\n", - __func__); - goto put_current_buf_return; - } else { - pl[n] = '\0'; - pl += n + 1; - } - - set_len_msg(buf, pl); - ret = write_to_buffer(buf); - -put_current_buf_return: - put_current_buf(); - return ret; -} -EXPORT_SYMBOL_GPL(exit_web_event); - - - - -SWAP_LIGHT_INIT_MODULE(NULL, event_filter_init, event_filter_exit, +SWAP_LIGHT_INIT_MODULE(NULL, core_init, core_exit, init_debugfs_writer, exit_debugfs_writer); MODULE_LICENSE("GPL"); diff --git a/writer/swap_writer_module.h b/writer/swap_writer_module.h deleted file mode 100644 index 38f2288..0000000 --- a/writer/swap_writer_module.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file writer/swap_writer_module.h - * @author Alexander Aksenov - * @author Vyacheslav Cherkashin - * - * @section LICENSE - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * @section COPYRIGHT - * - * Copyright (C) Samsung Electronics, 2013 - * - * @section DESCRIPTION - * - * Write module interface defenition. - */ - -#ifndef _SWAP_MSG_H -#define _SWAP_MSG_H - -#include - -/** - * @enum PROBE_TYPE - * @brief Probe types. - */ -enum PROBE_TYPE { - PT_US = 1, /**< User probe */ - PT_KS = 3 /**< Kernel probe */ -}; - -/** - * @enum PROBE_SUB_TYPE - * @brief Probe sub types. - */ -enum PROBE_SUB_TYPE { - PST_NONE = 0x00, /**< Common */ - PST_KS_FILE = 0x01, /**< File feature */ - PST_KS_IPC = 0x02, /**< Ipc feature */ - PST_KS_PROCESS = 0x04, /**< Process feature */ - PST_KS_SIGNAL = 0x08, /**< Signal feature */ - PST_KS_NETWORK = 0x10, /**< Network feature */ - PST_KS_DESC = 0x20 /**< Desc feature */ -}; - -struct pt_regs; -struct dentry; -struct task_struct; -struct vm_area_struct; - -int init_msg(size_t buf_size); -void uninit_msg(void); - -void reset_discarded(void); -unsigned int get_discarded_count(void); -void reset_seq_num(void); - -int proc_info_msg(struct task_struct *task, struct dentry *dentry); -void terminate_msg(struct task_struct *task); -void pcoc_map_msg(struct vm_area_struct *vma); -void proc_unmap_msg(unsigned long start, unsigned long end); -void proc_comm_msg(struct task_struct *task); -int sample_msg(struct pt_regs *regs); - -int entry_event(const char *fmt, unsigned long func_addr, struct pt_regs *regs, - enum PROBE_TYPE pt, int sub_type); -int exit_event(char ret_type, struct pt_regs *regs, int pt, int sub_type, - unsigned long func_addr, unsigned long ret_addr); - -int entry_web_event(unsigned long func_addr, struct pt_regs *regs); -int exit_web_event(unsigned long func_addr, struct pt_regs *regs); - -int switch_entry(struct pt_regs *regs); -int switch_exit(struct pt_regs *regs); - -int error_msg(const char *fmt, ...); - -int raw_msg(char *buf, size_t len); - -int custom_entry_event(unsigned long func_addr, struct pt_regs *regs, - int pt, int sub_type, const char *fmt, ...); -int custom_exit_event(unsigned long func_addr, unsigned long ret_addr, - struct pt_regs *regs, int pt, int sub_type, - const char *fmt, ...); - -#endif /* _SWAP_MSG_H */