summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Aksenov <a.aksenov@samsung.com>2014-04-24 16:05:48 +0400
committerAlexander Aksenov <a.aksenov@samsung.com>2014-04-29 18:45:08 +0400
commit7aa5d1c3653e83743b71493420e18b07f5fe6175 (patch)
tree19136bc920666914e10707bbd098a3d324d3236b
parentcffc6e626ea2375c840523d9de053feb12e6b1d5 (diff)
downloadswap-modules-7aa5d1c3653e83743b71493420e18b07f5fe6175.tar.gz
swap-modules-7aa5d1c3653e83743b71493420e18b07f5fe6175.tar.bz2
swap-modules-7aa5d1c3653e83743b71493420e18b07f5fe6175.zip
[FEATURE] Dlog: dlog suspend module implement
Change-Id: Idd16fa1b40b128179d606b5eb0b3a16867520659 Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
-rw-r--r--Kbuild7
-rw-r--r--dlog_suspend/dentry.c45
-rw-r--r--dlog_suspend/dentry.h7
-rw-r--r--dlog_suspend/elf_parser.c269
-rw-r--r--dlog_suspend/elf_parser.h7
-rw-r--r--dlog_suspend/file_ops.c57
-rw-r--r--dlog_suspend/file_ops.h15
-rw-r--r--dlog_suspend/get_task.c198
-rw-r--r--dlog_suspend/get_task.h14
-rw-r--r--dlog_suspend/lib_handler.c102
-rw-r--r--dlog_suspend/lib_handler.h10
-rw-r--r--dlog_suspend/swap_dlog_suspend.c246
-rw-r--r--dlog_suspend/swap_dlog_suspend.h9
-rw-r--r--dlog_suspend/tasks_list.c78
-rw-r--r--dlog_suspend/tasks_list.h14
-rw-r--r--swap_module.c13
16 files changed, 1090 insertions, 1 deletions
diff --git a/Kbuild b/Kbuild
index c8ffd8ab..3a5e6b26 100644
--- a/Kbuild
+++ b/Kbuild
@@ -46,6 +46,13 @@ swap-y := buffer/swap_buffer_module.o \
parser/msg_cmd.o \
parser/features.o \
parser/us_inst.o \
+ dlog_suspend/swap_dlog_suspend.o \
+ dlog_suspend/elf_parser.o \
+ dlog_suspend/file_ops.o \
+ dlog_suspend/get_task.o \
+ dlog_suspend/tasks_list.o \
+ dlog_suspend/dentry.o \
+ dlog_suspend/lib_handler.o \
swap_module.o
ifeq ($(CONFIG_KALLSYMS),y)
diff --git a/dlog_suspend/dentry.c b/dlog_suspend/dentry.c
new file mode 100644
index 00000000..73d1b282
--- /dev/null
+++ b/dlog_suspend/dentry.c
@@ -0,0 +1,45 @@
+#include <linux/namei.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <us_manager/sspt/sspt.h>
+
+#include "dentry.h"
+
+int check_dentry(struct task_struct * const task, struct dentry * const dentry)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = task->mm;
+
+ if (mm == NULL) {
+ return 0;
+ }
+
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (check_vma(vma) && vma->vm_file->f_dentry == dentry) {
+ up_read(&mm->mmap_sem);
+ return 1;
+ }
+ }
+ up_read(&mm->mmap_sem);
+
+ return 0;
+}
+
+int get_dentry(char * const path, struct dentry **dentry)
+{
+ struct path st_path;
+
+ *dentry = NULL;
+ if (kern_path(path, LOOKUP_FOLLOW, &st_path) != 0) {
+ printk("failed to lookup dentry for path %s!\n", path);
+ return -EINVAL;
+ }
+
+ *dentry = st_path.dentry;
+ path_put(&st_path);
+
+ return 0;
+}
+
diff --git a/dlog_suspend/dentry.h b/dlog_suspend/dentry.h
new file mode 100644
index 00000000..dff9172f
--- /dev/null
+++ b/dlog_suspend/dentry.h
@@ -0,0 +1,7 @@
+#ifndef __DENTRY_H__
+#define __DENTRY_H__
+
+int check_dentry(struct task_struct * const task, struct dentry * const dentry);
+int get_dentry(char * const path, struct dentry **dentry);
+
+#endif /* __DENTRY_H__ */
diff --git a/dlog_suspend/elf_parser.c b/dlog_suspend/elf_parser.c
new file mode 100644
index 00000000..3612c8cd
--- /dev/null
+++ b/dlog_suspend/elf_parser.c
@@ -0,0 +1,269 @@
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "elf_parser.h"
+#include "file_ops.h"
+
+#define EI_NIDENT 16
+
+typedef unsigned int Elf32_Addr;
+typedef unsigned int Elf32_Off;
+typedef unsigned int Elf32_Sword;
+typedef unsigned int Elf32_Word;
+typedef unsigned short Elf32_Half;
+
+
+struct Elf32_Ehdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+};
+
+struct Elf32_Shdr {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+};
+
+struct Elf32_Sym {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+};
+
+
+static Elf32_Off get_sections_header_offset(struct file *bin_p)
+{
+ Elf32_Off ret = 0;
+ loff_t off;
+
+ off = file_seek(bin_p, offsetof(struct Elf32_Ehdr, e_shoff), SEEK_SET);
+ file_read(bin_p, (char *)&ret, sizeof(ret), off);
+
+ return ret;
+}
+
+static Elf32_Half get_sections_count(struct file *bin_p)
+{
+ Elf32_Half ret = 0;
+ loff_t off;
+
+ off = file_seek(bin_p, offsetof(struct Elf32_Ehdr, e_shnum), SEEK_SET);
+ file_read(bin_p, (char *)&ret, sizeof(ret), off);
+
+ return ret;
+}
+
+static Elf32_Half get_sections_header_size(struct file *bin_p)
+{
+ Elf32_Half ret = 0;
+ loff_t off;
+
+ off = file_seek(bin_p, offsetof(struct Elf32_Ehdr, e_shentsize), SEEK_SET);
+ file_read(bin_p, (char *)&ret, sizeof(ret), off);
+
+ return ret;
+}
+
+static Elf32_Half get_sections(struct Elf32_Shdr **sections, struct file *bin_p)
+{
+ Elf32_Off sec_off;
+ Elf32_Half sec_count;
+ Elf32_Half sec_size;
+ loff_t off;
+
+ sec_off = get_sections_header_offset(bin_p);
+ sec_count = get_sections_count(bin_p);
+ sec_size = get_sections_header_size(bin_p);
+
+ *sections = kmalloc(sec_size * sec_count, GFP_KERNEL);
+ if (*sections == NULL) {
+ printk("ERROR: Not enough memory!\n");
+ return 0;
+ }
+
+ off = file_seek(bin_p, sec_off, SEEK_SET);
+ file_read(bin_p, (char *)*sections, sec_size * sec_count, off);
+
+ return sec_count;
+}
+
+static Elf32_Word find_section_offset(struct Elf32_Shdr *sections,
+ Elf32_Half count, Elf32_Word type,
+ Elf32_Off *offset)
+{
+ unsigned short i;
+
+
+ for (i = 0; i < count; i++)
+ if (sections[i].sh_type == type) {
+ *offset = sections[i].sh_offset;
+ return sections[i].sh_size;
+ }
+ return 0;
+}
+
+static Elf32_Half get_symbols(struct Elf32_Sym **syms, Elf32_Word size,
+ Elf32_Word offset, struct file *bin_p)
+{
+ Elf32_Word i_size = 0;
+ Elf32_Half syms_count;
+ loff_t off;
+
+ *syms = kmalloc(size, GFP_KERNEL);
+ if (*syms == NULL) {
+ printk("ERROR: Not enough memory!\n");
+ return 0;
+ }
+ off = file_seek(bin_p, offset, SEEK_SET);
+ file_read(bin_p, (char *)*syms, size, off);
+
+ for (syms_count = 0; ; syms_count++) {
+ if (i_size >= size)
+ return syms_count;
+ i_size += sizeof(struct Elf32_Sym);
+ }
+
+ /* Never get there */
+ return 0;
+}
+
+static Elf32_Addr find_addr_by_name_offset(struct Elf32_Sym *syms,
+ Elf32_Half syms_count,
+ Elf32_Word name_offset)
+{
+ Elf32_Half i;
+
+ for (i = 0; i < syms_count; i++)
+ if (syms[i].st_name == name_offset)
+ return syms[i].st_value;
+
+ /* No symbol with such name offset */
+
+ return 0;
+
+}
+
+static int compare_names(char *name, char **names, int names_cnt)
+{
+ int i;
+ size_t name_size = strlen(name);
+
+ for (i = 0; i < names_cnt; i++)
+ if (strncmp(name, names[i], name_size) == 0)
+ return i;
+
+ return -1;
+}
+
+static unsigned int find_symbols_by_names(struct Elf32_Sym *syms,
+ Elf32_Half syms_count,
+ Elf32_Off str_offset,
+ Elf32_Word str_size, struct file *bin_p,
+ char **name, int name_cnt,
+ Elf32_Addr **addrs)
+{
+ Elf32_Word i = 0;
+ Elf32_Addr addr = 0;
+ Elf32_Addr *addrs_arr = NULL;
+ loff_t off;
+ unsigned int ret = 0;
+ char *names = NULL;
+
+ names = kmalloc(str_size, GFP_KERNEL);
+ if (names == NULL) {
+ printk("ERROR: Not enough memory!\n");
+ return 0;
+ }
+
+ addrs_arr = kmalloc(sizeof(Elf32_Addr) * name_cnt, GFP_KERNEL);
+ if (addrs_arr == NULL) {
+ printk("ERROR: Not enough memory!\n");
+ goto exit_find_syms;
+ }
+
+ off = file_seek(bin_p, str_offset, SEEK_SET);
+ file_read(bin_p, names, str_size, off);
+
+ for (i = 1; i <= str_size; ) {
+ if (compare_names(names + i, name, name_cnt) >= 0) {
+ addr = find_addr_by_name_offset(syms, syms_count, i);
+ /* If we've found addr - add it to addrs list. Filter for thumb */
+ if (addr) {
+ addrs_arr[ret] = addr & 0xfffffffe ;
+ ret++;
+ }
+ }
+ i += strlen(names + i) + 1;
+ }
+
+ *addrs = addrs_arr;
+
+exit_find_syms:
+ kfree(names);
+
+ return ret;
+}
+
+/**
+ * get_offset_from_bin - get specified symbols offset in binary
+ * @bin_path: path to binary
+ * @names: symbols names
+ * @syms_cnt: symbols count
+ * @addrs: pointer to array where result is stored
+ *
+ */
+int get_offset_from_bin(char *bin_path, char **names,
+ unsigned int syms_cnt, unsigned long **addrs)
+{
+ struct file *filp = NULL;
+ Elf32_Half sec_count, sym_count;
+ Elf32_Off syms_offset = 0;
+ Elf32_Word syms_size;
+ Elf32_Off str_offset = 0;
+ Elf32_Word str_size;
+ unsigned int found_addrs = 0;
+ struct Elf32_Sym *syms = NULL;
+ struct Elf32_Shdr *sections = NULL;
+
+ filp = file_open(bin_path, O_RDONLY, 0);
+ if (filp == NULL)
+ return -1;
+
+ sec_count = get_sections(&sections, filp);
+
+ syms_size = find_section_offset(sections, sec_count, 0xb, &syms_offset);
+ sym_count = get_symbols(&syms, syms_size, syms_offset, filp);
+
+ str_size = find_section_offset(sections, sec_count, 0x3, &str_offset);
+
+ found_addrs = find_symbols_by_names(syms, sym_count, str_offset, str_size, filp, names, syms_cnt, (Elf32_Addr **)addrs);
+
+ kfree(syms);
+ kfree(sections);
+
+ file_close(filp);
+
+ return found_addrs;
+}
diff --git a/dlog_suspend/elf_parser.h b/dlog_suspend/elf_parser.h
new file mode 100644
index 00000000..aec47f24
--- /dev/null
+++ b/dlog_suspend/elf_parser.h
@@ -0,0 +1,7 @@
+#ifndef __ELF_PARSER_H__
+#define __ELF_PARSER_H__
+
+int get_offset_from_bin(char *bin_path, char **names,
+ unsigned int syms_cnt, unsigned long **addrs);
+
+#endif /* __ELF_PARSER_H__ */
diff --git a/dlog_suspend/file_ops.c b/dlog_suspend/file_ops.c
new file mode 100644
index 00000000..ab51763c
--- /dev/null
+++ b/dlog_suspend/file_ops.c
@@ -0,0 +1,57 @@
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include "file_ops.h"
+
+struct file *file_open(const char *bin, int flags, int rights)
+{
+ struct file *filp = NULL;
+ mm_segment_t oldfs;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ filp = filp_open(bin, flags, rights);
+ set_fs(oldfs);
+ if (IS_ERR(filp)) {
+ printk("ERROR: Cannot open file %s\n", bin);
+ return NULL;
+ }
+
+ return filp;
+}
+
+void file_close(struct file *filp)
+{
+ filp_close(filp, NULL);
+}
+
+int file_read(struct file *filp, unsigned char *data, unsigned int size,
+ loff_t offset)
+{
+ mm_segment_t oldfs;
+ int ret;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+
+ ret = vfs_read(filp, data, size, &offset);
+
+ set_fs(oldfs);
+
+ return ret;
+}
+
+loff_t file_seek(struct file *filp, loff_t offset, int whence)
+{
+ mm_segment_t oldfs;
+ loff_t ret;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+
+ ret = vfs_llseek(filp, offset, whence);
+
+ set_fs(oldfs);
+
+ return ret;
+}
diff --git a/dlog_suspend/file_ops.h b/dlog_suspend/file_ops.h
new file mode 100644
index 00000000..0e829bab
--- /dev/null
+++ b/dlog_suspend/file_ops.h
@@ -0,0 +1,15 @@
+#ifndef __FILE_OPS_H__
+#define __FILE_OPS_H__
+
+#include <linux/fs.h>
+
+#define SEEK_SET 0
+
+
+struct file *file_open(const char *bin, int flags, int rights);
+void file_close(struct file *filp);
+int file_read(struct file *filp, unsigned char *data, unsigned int size,
+ loff_t offset);
+loff_t file_seek(struct file *filp, loff_t offset, int whence);
+
+#endif /* __FILE_OPS_H__ */
diff --git a/dlog_suspend/get_task.c b/dlog_suspend/get_task.c
new file mode 100644
index 00000000..29507d95
--- /dev/null
+++ b/dlog_suspend/get_task.c
@@ -0,0 +1,198 @@
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/rwlock.h>
+#include <linux/stop_machine.h>
+
+#include <us_manager/sspt/sspt.h>
+
+#include "get_task.h"
+#include "lib_handler.h"
+#include "tasks_list.h"
+#include "dentry.h"
+
+/* libdlog.so dentry */
+struct dentry *lib_dentry = NULL;
+
+/* Offsets in libdlog.so */
+static unsigned long *addrs = NULL;
+
+/* Default log level for apps.
+ * -1 - logs disabled
+ */
+static int main_log_level = 4; /* According to libdlog sources */
+
+struct for_each_task_info_t {
+ int (*filter_func)(struct task_struct *, void *);
+ void *filter_data;
+ int (*for_each_task_func)(struct task_struct *, void *);
+ void *for_each_task_data;
+};
+
+/* 1 - equal
+ * 0 - not equal
+ */
+static int pid_filter(struct task_struct *task, void *desired_pid)
+{
+ if (task->pid == *(unsigned long *)desired_pid)
+ return 1;
+
+ return 0;
+}
+
+/* 1 - equal
+ * 0 - not equal
+ */
+static int dentry_filter(struct task_struct *task, void *desired_dentry)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = task->mm;
+
+ if (mm == NULL)
+ return 0;
+
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (check_vma(vma) && vma->vm_file->f_dentry ==
+ *(struct dentry **)desired_dentry) {
+ up_read(&mm->mmap_sem);
+ return 1;
+ }
+ }
+ up_read(&mm->mmap_sem);
+
+ return 0;
+}
+
+/* Always equal */
+static int dumb_filter(struct task_struct *task, void *data)
+{
+ return 1;
+}
+
+static int patch_process(struct task_struct * const task, void * const data)
+{
+ int log_level = *(int *)data;
+ struct vm_area_struct *vma = NULL;
+
+ if (addrs == NULL)
+ if (get_offsets(&addrs) == 0)
+ return -1;
+
+ if (lib_dentry == NULL)
+ lib_dentry = get_lib_dentry();
+
+ if (task->mm == NULL)
+ return 0;
+
+ down_read(&task->mm->mmap_sem);
+ for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
+ if (check_vma(vma) && vma->vm_file->f_dentry == lib_dentry) {
+ patch_dlog(task, vma->vm_start + addrs[0], log_level);
+ patch_dlog(task, vma->vm_start + addrs[1], log_level);
+ up_read(&task->mm->mmap_sem);
+ return 1;
+ }
+ }
+ up_read(&task->mm->mmap_sem);
+
+ return 0;
+
+}
+
+static int find_library(struct task_struct *task, void *data)
+{
+ int ret;
+
+ ret = patch_process(task, data);
+ if (ret == 0)
+ return -1;
+ else
+ return ret;
+}
+
+static int __look_through_all_tasks(void *data)
+{
+ int res, ret = 0;
+ struct task_struct *task;
+ struct for_each_task_info_t *feti_p = (struct for_each_task_info_t *)data;
+
+ if (feti_p == NULL)
+ return -1;
+
+ for_each_process(task) {
+ if (feti_p->filter_func && feti_p->filter_func(task, feti_p->filter_data)) {
+ if (feti_p->for_each_task_func) {
+ res = feti_p->for_each_task_func(task, feti_p->for_each_task_data);
+ if (res < 0) {
+ ret = res;
+ goto look_exit;
+ }
+ else if (res > 0) {
+ ret = res;
+ }
+ }
+ }
+ }
+
+look_exit:
+ return ret;
+}
+
+
+static int patch_lli(struct task_struct * const task,
+ struct dentry * const dentry, int log_level)
+{
+ if (check_dentry(current, dentry) == 0)
+ return 0;
+
+ return patch_process(task, &log_level);
+}
+
+int page_fault_callback(void)
+{
+ return for_each_log_level_item(current, patch_lli);
+}
+
+int patch_process_by_pid(pid_t pid, int *log_level_p)
+{
+ struct for_each_task_info_t feti = {
+ .filter_func = pid_filter,
+ .filter_data = (void *)&pid,
+ .for_each_task_func = find_library,
+ .for_each_task_data = log_level_p
+ };
+
+ return stop_machine(__look_through_all_tasks, &feti, NULL);
+}
+
+int patch_process_by_dentry(struct dentry *dentry, int *log_level_p)
+{
+ struct for_each_task_info_t feti = {
+ .filter_func = dentry_filter,
+ .filter_data = (void *)&dentry,
+ .for_each_task_func = find_library,
+ .for_each_task_data = log_level_p
+ };
+
+ return stop_machine(__look_through_all_tasks, &feti, NULL);
+}
+
+int patch_all_processes(void)
+{
+ struct for_each_task_info_t feti = {
+ .filter_func = dumb_filter,
+ .filter_data = NULL,
+ .for_each_task_func = patch_process,
+ .for_each_task_data = &main_log_level
+ };
+
+ return stop_machine(__look_through_all_tasks, &feti, NULL);
+}
+
+void set_main_log_level(const int log_level)
+{
+ if ((log_level >= -1) && (log_level <= 9))
+ main_log_level = log_level;
+ else
+ printk("ERROR: Wrong log_level!\n");
+}
diff --git a/dlog_suspend/get_task.h b/dlog_suspend/get_task.h
new file mode 100644
index 00000000..f9b01b76
--- /dev/null
+++ b/dlog_suspend/get_task.h
@@ -0,0 +1,14 @@
+#ifndef __GET_TASK_H__
+#define __GET_TASK_H__
+
+#include <linux/types.h>
+
+struct dentry;
+
+int patch_process_by_pid(pid_t pid, int *log_level);
+int patch_process_by_dentry(struct dentry *dentry, int *log_level);
+int patch_all_processes(void);
+int page_fault_callback(void);
+void set_main_log_level(const int log_level);
+
+#endif /* __GET_TASK_H__ */
diff --git a/dlog_suspend/lib_handler.c b/dlog_suspend/lib_handler.c
new file mode 100644
index 00000000..4d32ea80
--- /dev/null
+++ b/dlog_suspend/lib_handler.c
@@ -0,0 +1,102 @@
+#include <linux/sched.h>
+
+#include <kprobe/dbi_kprobes_deps.h>
+
+#include "elf_parser.h"
+#include "lib_handler.h"
+#include "dentry.h"
+
+#define LIBDLOG_PATH "/usr/lib/libdlog.so.0.0.0"
+#define LIBDLOG_NAME "libdlog.so.0.0.0"
+
+struct patch_insns {
+ unsigned short insn_1;
+ unsigned short insn_2;
+ unsigned short insn_3;
+} __attribute__((packed));
+
+
+static int patch_dlog_enable(struct task_struct *task, unsigned long addr,
+ unsigned int log_level)
+{
+ int ret = 0;
+ struct patch_insns enable_insns = {
+ .insn_1 = 0xbf00, /* nop */
+ .insn_2 = 0xbf00, /* nop */
+ .insn_3 = 0x2900 /* cmp r1, #0 */
+ };
+
+ enable_insns.insn_3 += log_level; /* cmp r1, #(0+log_level) */
+
+ ret = write_proc_vm_atomic(task, addr, &enable_insns, sizeof(enable_insns));
+ if (ret == 0) {
+ printk("ERROR: Cannot write memory! PID: %d\n", task->pid);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int patch_dlog_disable(struct task_struct *task, unsigned long addr)
+{
+ int ret = 0;
+
+ struct patch_insns disable_insns = {
+ .insn_1 = 0xf04f,
+ .insn_2 = 0x0000, /* mov r0, #0 */
+ .insn_3 = 0x4770 /* bx lr */
+ };
+
+
+ ret = write_proc_vm_atomic(task, addr, &disable_insns, sizeof(disable_insns));
+ if (ret == 0) {
+ printk("ERROR: Cannot write memory! PID: %d\n", task->pid);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int patch_dlog(struct task_struct *task, unsigned long addr, int log_level)
+{
+ if (log_level == -1) {
+ return patch_dlog_disable(task, addr);
+ } else if (log_level >= 0) {
+ return patch_dlog_enable(task, addr, log_level);
+ } else {
+ printk("ERROR: Wrong log level!\n");
+ return -1;
+ }
+}
+
+int get_offsets(unsigned long **addrs)
+{
+ char **names;
+ char *name_1 = "__dlog_print";
+ char *name_2 = "__dlog_vprint";
+ int found_addrs;
+
+ names = kmalloc(sizeof(name_1) * 2, GFP_KERNEL);
+
+ names[0] = name_1;
+ names[1] = name_2;
+
+ found_addrs = get_offset_from_bin(LIBDLOG_PATH, names, 2, addrs);
+
+ kfree(names);
+
+ return found_addrs;
+}
+
+struct dentry *get_lib_dentry(void)
+{
+ struct dentry *dentry;
+
+ if (get_dentry(LIBDLOG_PATH, &dentry) == 0)
+ return dentry;
+ else
+ return NULL;
+}
+
+#undef LIBDLOG_NAME
+#undef LIBDLOG_PATH
diff --git a/dlog_suspend/lib_handler.h b/dlog_suspend/lib_handler.h
new file mode 100644
index 00000000..b9e0632c
--- /dev/null
+++ b/dlog_suspend/lib_handler.h
@@ -0,0 +1,10 @@
+#ifndef __LIB_HANDLER_H__
+#define __LIB_HANDLER_H__
+
+struct task_struct;
+
+int get_offsets(unsigned long **addrs);
+int patch_dlog(struct task_struct *task, unsigned long addr, int log_level);
+struct dentry *get_lib_dentry(void);
+
+#endif /* __LIB_HANDLER_H__ */
diff --git a/dlog_suspend/swap_dlog_suspend.c b/dlog_suspend/swap_dlog_suspend.c
new file mode 100644
index 00000000..717f1efb
--- /dev/null
+++ b/dlog_suspend/swap_dlog_suspend.c
@@ -0,0 +1,246 @@
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/namei.h>
+#include <asm/uaccess.h>
+
+#include <driver/swap_debugfs.h>
+#include <us_manager/sspt/sspt.h>
+#include <us_manager/callbacks.h>
+#include <us_manager/helper.h>
+
+#include "swap_dlog_suspend.h"
+#include "dentry.h"
+#include "lib_handler.h"
+#include "tasks_list.h"
+#include "get_task.h"
+
+
+
+static char *common_buf = NULL;
+enum message_type_t {
+ PID = 0,
+ PATH,
+ ALL
+};
+
+
+/* ============================================================================
+ * = BUFFER =
+ * ============================================================================
+ */
+
+enum { subbuf_size = 8*1024 };
+enum { common_buf_size = subbuf_size * NR_CPUS };
+
+static int init_buffer(void)
+{
+ common_buf = vmalloc(common_buf_size);
+
+ return common_buf ? 0 : -ENOMEM;
+}
+
+static void exit_buffer(void)
+{
+ vfree(common_buf);
+ common_buf = NULL;
+}
+
+static void *get_current_buf(void)
+{
+ return common_buf + subbuf_size * get_cpu();
+}
+
+static void put_current_buf(void)
+{
+ put_cpu();
+}
+
+
+/* ============================================================================
+ * = PARSER =
+ * ============================================================================
+ */
+
+static int check_action(char * const action)
+{
+ ssize_t action_size = strnlen(action, subbuf_size);
+
+ if ((action_size != 2) ||
+ (strncmp(action, "d", 1) &&
+ strncmp(action, "0", 1) &&
+ strncmp(action, "1", 1) &&
+ strncmp(action, "2", 1) &&
+ strncmp(action, "3", 1) &&
+ strncmp(action, "4", 1) &&
+ strncmp(action, "5", 1) &&
+ strncmp(action, "6", 1) &&
+ strncmp(action, "7", 1) &&
+ strncmp(action, "8", 1) &&
+ strncmp(action, "9", 1)))
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t parse_string(char *buf)
+{
+ size_t str_size = strnlen(buf, subbuf_size);
+ char *app_s = NULL;
+ pid_t pid = 0;
+ struct dentry *app_dentry = NULL;
+ char *action_s = NULL;
+ int ret = 0;
+ int log_level;
+ enum message_type_t msg_type;
+
+
+ /* Parse app */
+ app_s = strsep(&buf, " ");
+ if (app_s == NULL)
+ return -EINVAL;
+
+ /* Check action */
+ ret = check_action(buf);
+ if (ret)
+ return -EINVAL;
+
+ /* Here we absolutely sure that action_s is 'd' or in between '0' - '8' */
+
+ /* Parse log level */
+ if (buf[0] == 'd') {
+ log_level = -1;
+ } else {
+ ret = kstrtouint(buf, 10, &log_level);
+ if (ret) {
+ printk("ERROR: Wrong log level: %s\n", action_s);
+ return -EINVAL;
+ }
+ }
+
+ /* If log level for all apps */
+ if (strnlen(app_s, 3) == 1 && app_s[0] == '*') {
+ msg_type = ALL;
+ set_main_log_level(log_level);
+ patch_all_processes();
+ } else if (get_dentry(app_s, &app_dentry) == 0) {
+ msg_type = PATH;
+
+ ret = patch_process_by_dentry(app_dentry, &log_level);
+ if (ret <= 0) {
+ /* If task not found - add to list */
+ ret = add_to_logs_list(app_dentry, log_level);
+ if (ret) {
+ printk("ERROR: Task not found!\n");
+ return -EINVAL;
+ }
+ return str_size;
+ }
+ } else if (kstrtouint(app_s, 10, &pid) == 0) {
+ msg_type = PID;
+ ret = patch_process_by_pid(pid, &log_level);
+ if (ret <= 0) {
+ printk("ERROR: Task not found! Specified PID: %d\n", pid);
+ return -EINVAL;
+ }
+ } else {
+ printk("ERROR: Cannot identify application!\n");
+ return -EINVAL;
+ }
+
+ return str_size;
+}
+
+
+/* ============================================================================
+ * = FILE OPERATIONS =
+ * ============================================================================
+ */
+
+static ssize_t write_dlog(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ void *buf;
+
+ if (count > subbuf_size)
+ return -EINVAL;
+
+ buf = get_current_buf();
+
+ memset(buf, 0, subbuf_size);
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto put_buf;
+ }
+
+ ret = parse_string(buf);
+
+put_buf:
+ put_current_buf();
+ return ret;
+}
+
+
+static const struct file_operations fops_dlog = {
+ .owner = THIS_MODULE,
+ .write = write_dlog
+};
+
+
+/* ============================================================================
+ * = INIT/EXIT =
+ * ============================================================================
+ */
+
+static struct dentry *swap_dlog_dentry = NULL;
+
+void swap_dlog_exit_debugfs(void)
+{
+ unregister_helper_top();
+ unregister_helper_bottom();
+
+ free_logs_list();
+
+ if (swap_dlog_dentry)
+ debugfs_remove(swap_dlog_dentry);
+
+ swap_dlog_dentry = NULL;
+
+ exit_buffer();
+}
+
+int swap_dlog_init_debugfs(void)
+{
+ struct dentry *swap_dir;
+ int ret;
+
+ ret = init_buffer();
+ if (ret)
+ return ret;
+
+ swap_dir = get_swap_debugfs_dir();
+ if (swap_dir == NULL)
+ return -ENOENT;
+
+ swap_dlog_dentry = debugfs_create_file(SWAP_DLOG, 0600, swap_dir, NULL,
+ &fops_dlog);
+ if (swap_dlog_dentry == NULL)
+ goto fail;
+
+ register_pf_cb(page_fault_callback);
+
+ if (register_helper()) {
+ printk("ERROR: Cannot install probes\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ swap_dlog_exit_debugfs();
+ return -ENOMEM;
+}
diff --git a/dlog_suspend/swap_dlog_suspend.h b/dlog_suspend/swap_dlog_suspend.h
new file mode 100644
index 00000000..69342d74
--- /dev/null
+++ b/dlog_suspend/swap_dlog_suspend.h
@@ -0,0 +1,9 @@
+#ifndef __SWAP_DLOG_SUSPEND_H__
+#define __SWAP_DLOG_SUSPEND_H__
+
+#define SWAP_DLOG "dlog"
+
+int swap_dlog_init_debugfs(void);
+void swap_dlog_exit_debugfs(void);
+
+#endif /* __SWAP_DLOG_SUSPEND_H__ */
diff --git a/dlog_suspend/tasks_list.c b/dlog_suspend/tasks_list.c
new file mode 100644
index 00000000..394c7b93
--- /dev/null
+++ b/dlog_suspend/tasks_list.c
@@ -0,0 +1,78 @@
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "tasks_list.h"
+
+struct log_level_item {
+ struct list_head list;
+
+ struct dentry *bin;
+ int log_level;
+};
+
+static LIST_HEAD(logs_list);
+
+static struct log_level_item *create_log_level_item(struct dentry * const dentry,
+ const int log_level)
+{
+ struct log_level_item *lli = NULL;
+
+ lli = kmalloc(sizeof(*lli), GFP_KERNEL);
+ if (lli == NULL)
+ return NULL;
+
+ lli->bin = dentry;
+ lli->log_level = log_level;
+ INIT_LIST_HEAD(&lli->list);
+
+ return lli;
+}
+
+static void free_log_level_item(struct log_level_item *lli)
+{
+ kfree(lli);
+}
+
+int add_to_logs_list(struct dentry * const dentry, const int log_level)
+{
+ struct log_level_item *lli = NULL;
+
+ lli = create_log_level_item(dentry, log_level);
+ if (lli == NULL) {
+ printk("ERROR: Not enough memory!\n");
+ return -ENOMEM;
+ }
+
+ list_add_tail(&lli->list, &logs_list);
+
+ return 0;
+}
+
+int for_each_log_level_item(struct task_struct *task,
+ int (*lli_cb)(struct task_struct *,
+ struct dentry *,
+ int))
+{
+ struct log_level_item *lli, *n;
+ int ret;
+
+ list_for_each_entry_safe(lli, n, &logs_list, list) {
+ ret = lli_cb(task, lli->bin, lli->log_level);
+ if (ret == 1) {
+ list_del(&lli->list);
+ free_log_level_item(lli);
+ }
+ }
+
+ return ret;
+}
+
+void free_logs_list(void)
+{
+ struct log_level_item *lli, *n;
+
+ list_for_each_entry_safe(lli, n, &logs_list, list) {
+ list_del(&lli->list);
+ free_log_level_item(lli);
+ }
+}
diff --git a/dlog_suspend/tasks_list.h b/dlog_suspend/tasks_list.h
new file mode 100644
index 00000000..7d04eafd
--- /dev/null
+++ b/dlog_suspend/tasks_list.h
@@ -0,0 +1,14 @@
+#ifndef __TASKS_LIST_H__
+#define __TASKS_LIST_H__
+
+struct dentry;
+struct task_struct;
+
+int add_to_logs_list(struct dentry * const dentry, const int log_level);
+void free_logs_list(void);
+int for_each_log_level_item(struct task_struct *task,
+ int (*lli_cb)(struct task_struct *,
+ struct dentry *,
+ int));
+
+#endif /* __TASKS_LIST_H__ */
diff --git a/swap_module.c b/swap_module.c
index 788776c5..26522900 100644
--- a/swap_module.c
+++ b/swap_module.c
@@ -12,6 +12,8 @@
#include <us_manager/us_manager.h>
#include <writer/swap_writer_module.h>
+#include <dlog_suspend/swap_dlog_suspend.h>
+
typedef enum {
FULL_REMOVE,
BUFFER_FAIL,
@@ -24,13 +26,16 @@ typedef enum {
KS_FEATURE_FAIL,
SAMPLER_FAIL,
ENERGY_FAIL,
- PARSER_FAIL
+ PARSER_FAIL,
+ DLOG_FAIL
} exit_modules_t;
static void uninit_modules(exit_modules_t exit_m)
{
switch (exit_m) {
case FULL_REMOVE:
+ swap_dlog_exit_debugfs();
+ case DLOG_FAIL:
swap_parser_exit();
case PARSER_FAIL:
swap_energy_exit();
@@ -127,6 +132,12 @@ static int __init swap_init(void)
return ret;
}
+ ret = swap_dlog_init_debugfs();
+ if (ret) {
+ uninit_modules(DLOG_FAIL);
+ return ret;
+ }
+
return ret;
}