Move modules to modules dir 84/156484/2
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 3 Oct 2017 15:48:25 +0000 (18:48 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Wed, 18 Oct 2017 12:29:46 +0000 (15:29 +0300)
Change-Id: I2b4cbfe8c39fef4049083d523eb2d4acbea03041
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
619 files changed:
Doxyfile [deleted file]
Kbuild [deleted file]
arch/arm/probes/compat_arm64.h [deleted file]
arch/arm/probes/decode_arm_old.h [deleted file]
arch/arm/probes/decode_thumb.c [deleted file]
arch/arm/probes/decode_thumb.h [deleted file]
arch/arm/probes/decode_thumb_old.h [deleted file]
arch/arm/probes/probes.c [deleted file]
arch/arm/probes/probes.h [deleted file]
arch/arm/probes/probes_arm.c [deleted file]
arch/arm/probes/probes_arm.h [deleted file]
arch/arm/probes/probes_thumb.c [deleted file]
arch/arm/probes/probes_thumb.h [deleted file]
arch/arm/probes/tramps_arm.c [deleted file]
arch/arm/probes/tramps_arm.h [deleted file]
arch/arm/probes/tramps_thumb.c [deleted file]
arch/arm/probes/tramps_thumb.h [deleted file]
arch/arm/uprobe/swap_uprobe.c [deleted file]
arch/arm/uprobe/swap_uprobe.h [deleted file]
buffer/Kbuild [deleted file]
buffer/buffer_description.h [deleted file]
buffer/buffer_queue.c [deleted file]
buffer/buffer_queue.h [deleted file]
buffer/data_types.h [deleted file]
buffer/kernel_operations.h [deleted file]
buffer/swap_buffer_errors.h [deleted file]
buffer/swap_buffer_module.c [deleted file]
buffer/swap_buffer_module.h [deleted file]
buffer/swap_buffer_to_buffer_queue.h [deleted file]
build.config.example [deleted file]
build.sh [deleted file]
deploy.sh [deleted file]
driver/Kbuild [deleted file]
driver/app_manage.h [deleted file]
driver/device_driver.c [deleted file]
driver/device_driver.h [deleted file]
driver/device_driver_to_driver_to_buffer.h [deleted file]
driver/driver_debugfs.c [deleted file]
driver/driver_debugfs.h [deleted file]
driver/driver_defs.h [deleted file]
driver/driver_to_buffer.c [deleted file]
driver/driver_to_buffer.h [deleted file]
driver/driver_to_msg.h [deleted file]
driver/swap_driver_errors.h [deleted file]
driver/swap_driver_module.c [deleted file]
driver/swap_ioctl.h [deleted file]
driver/us_interaction.c [deleted file]
driver/us_interaction.h [deleted file]
driver/us_interaction_msg.h [deleted file]
energy/Kbuild [deleted file]
energy/debugfs_energy.c [deleted file]
energy/debugfs_energy.h [deleted file]
energy/energy.c [deleted file]
energy/energy.h [deleted file]
energy/energy_module.c [deleted file]
energy/lcd/lcd_base.c [deleted file]
energy/lcd/lcd_base.h [deleted file]
energy/lcd/lcd_debugfs.c [deleted file]
energy/lcd/lcd_debugfs.h [deleted file]
energy/lcd/maru.c [deleted file]
energy/lcd/s6e8aa0.c [deleted file]
energy/lcd/s6e8aa0_panel.c [deleted file]
energy/rational_debugfs.c [deleted file]
energy/rational_debugfs.h [deleted file]
energy/tm_stat.h [deleted file]
fbiprobe/Kbuild [deleted file]
fbiprobe/fbi_msg.c [deleted file]
fbiprobe/fbi_msg.h [deleted file]
fbiprobe/fbi_probe_module.h [deleted file]
fbiprobe/fbiprobe.c [deleted file]
fbiprobe/fbiprobe.h [deleted file]
fbiprobe/regs.h [deleted file]
got_patcher/Kbuild [deleted file]
got_patcher/gt.h [deleted file]
got_patcher/gt_debugfs.c [deleted file]
got_patcher/gt_debugfs.h [deleted file]
got_patcher/gt_module.c [deleted file]
got_patcher/gt_module.h [deleted file]
kprobe/Kbuild [deleted file]
kprobe/arch/arm/swap-asm/memory_rwx.c [deleted file]
kprobe/arch/arm/swap-asm/memory_rwx.h [deleted file]
kprobe/arch/arm/swap-asm/swap_kprobes.c [deleted file]
kprobe/arch/arm/swap-asm/swap_kprobes.h [deleted file]
kprobe/arch/arm/swap-asm/swap_probes.h [deleted file]
kprobe/arch/arm64/swap-asm/condn-helpers.c [deleted file]
kprobe/arch/arm64/swap-asm/condn-helpers.h [deleted file]
kprobe/arch/arm64/swap-asm/dbg_interface.c [deleted file]
kprobe/arch/arm64/swap-asm/dbg_interface.h [deleted file]
kprobe/arch/arm64/swap-asm/kprobes-arm64.c [deleted file]
kprobe/arch/arm64/swap-asm/kprobes-arm64.h [deleted file]
kprobe/arch/arm64/swap-asm/probes-decode.h [deleted file]
kprobe/arch/arm64/swap-asm/simulate-insn.c [deleted file]
kprobe/arch/arm64/swap-asm/simulate-insn.h [deleted file]
kprobe/arch/arm64/swap-asm/swap_kprobes.c [deleted file]
kprobe/arch/arm64/swap-asm/swap_kprobes.h [deleted file]
kprobe/arch/arm64/swap-asm/swap_probes.h [deleted file]
kprobe/arch/asm-mips/dbi_kprobes.c [deleted file]
kprobe/arch/asm-mips/dbi_kprobes.h [deleted file]
kprobe/arch/x86/swap-asm/swap_kprobes.c [deleted file]
kprobe/arch/x86/swap-asm/swap_kprobes.h [deleted file]
kprobe/swap_kdebug.h [deleted file]
kprobe/swap_kprobes.c [deleted file]
kprobe/swap_kprobes.h [deleted file]
kprobe/swap_kprobes_deps.c [deleted file]
kprobe/swap_kprobes_deps.h [deleted file]
kprobe/swap_ktd.c [deleted file]
kprobe/swap_ktd.h [deleted file]
kprobe/swap_no_kprobes.c [deleted file]
kprobe/swap_slots.c [deleted file]
kprobe/swap_slots.h [deleted file]
kprobe/swap_td_raw.c [deleted file]
kprobe/swap_td_raw.h [deleted file]
ks_features/Kbuild [deleted file]
ks_features/features_data.c [deleted file]
ks_features/file_ops.c [deleted file]
ks_features/file_ops.h [deleted file]
ks_features/ks_feature_hook.c [deleted file]
ks_features/ks_feature_kprobe.c [deleted file]
ks_features/ks_features.c [deleted file]
ks_features/ks_features.h [deleted file]
ks_features/ks_features_data.c [deleted file]
ks_features/ks_features_data.h [deleted file]
ks_features/ks_map.c [deleted file]
ks_features/ks_map.h [deleted file]
ks_features/ksf_msg.c [deleted file]
ks_features/ksf_msg.h [deleted file]
ks_features/syscall_list.h [deleted file]
ks_manager/Kbuild [deleted file]
ks_manager/ks_manager.c [deleted file]
ks_manager/ks_manager.h [deleted file]
ksyms/Kbuild [deleted file]
ksyms/ksyms.c [deleted file]
ksyms/ksyms.h [deleted file]
ksyms/ksyms_init.h [deleted file]
ksyms/ksyms_module.c [deleted file]
ksyms/no_ksyms.c [deleted file]
loader/Kbuild [deleted file]
loader/loader.h [deleted file]
loader/loader_debugfs.c [deleted file]
loader/loader_debugfs.h [deleted file]
loader/loader_defs.h [deleted file]
loader/loader_module.c [deleted file]
loader/loader_module.h [deleted file]
loader/loader_pd.c [deleted file]
loader/loader_pd.h [deleted file]
loader/loader_storage.c [deleted file]
loader/loader_storage.h [deleted file]
master/Kbuild [deleted file]
master/master_module.c [deleted file]
master/swap_debugfs.c [deleted file]
master/swap_debugfs.h [deleted file]
master/swap_deps.c [deleted file]
master/swap_deps.h [deleted file]
master/swap_initializer.c [deleted file]
master/swap_initializer.h [deleted file]
master/wait.c [deleted file]
master/wait.h [deleted file]
modules/Doxyfile [new file with mode: 0644]
modules/Kbuild [new file with mode: 0644]
modules/arch/arm/probes/compat_arm64.h [new file with mode: 0644]
modules/arch/arm/probes/decode_arm_old.h [new file with mode: 0644]
modules/arch/arm/probes/decode_thumb.c [new file with mode: 0644]
modules/arch/arm/probes/decode_thumb.h [new file with mode: 0644]
modules/arch/arm/probes/decode_thumb_old.h [new file with mode: 0644]
modules/arch/arm/probes/probes.c [new file with mode: 0644]
modules/arch/arm/probes/probes.h [new file with mode: 0644]
modules/arch/arm/probes/probes_arm.c [new file with mode: 0644]
modules/arch/arm/probes/probes_arm.h [new file with mode: 0644]
modules/arch/arm/probes/probes_thumb.c [new file with mode: 0644]
modules/arch/arm/probes/probes_thumb.h [new file with mode: 0644]
modules/arch/arm/probes/tramps_arm.c [new file with mode: 0644]
modules/arch/arm/probes/tramps_arm.h [new file with mode: 0644]
modules/arch/arm/probes/tramps_thumb.c [new file with mode: 0644]
modules/arch/arm/probes/tramps_thumb.h [new file with mode: 0644]
modules/arch/arm/uprobe/swap_uprobe.c [new file with mode: 0644]
modules/arch/arm/uprobe/swap_uprobe.h [new file with mode: 0644]
modules/buffer/Kbuild [new file with mode: 0644]
modules/buffer/buffer_description.h [new file with mode: 0644]
modules/buffer/buffer_queue.c [new file with mode: 0644]
modules/buffer/buffer_queue.h [new file with mode: 0644]
modules/buffer/data_types.h [new file with mode: 0644]
modules/buffer/kernel_operations.h [new file with mode: 0644]
modules/buffer/swap_buffer_errors.h [new file with mode: 0644]
modules/buffer/swap_buffer_module.c [new file with mode: 0644]
modules/buffer/swap_buffer_module.h [new file with mode: 0644]
modules/buffer/swap_buffer_to_buffer_queue.h [new file with mode: 0644]
modules/build.config.example [new file with mode: 0644]
modules/build.sh [new file with mode: 0755]
modules/deploy.sh [new file with mode: 0755]
modules/driver/Kbuild [new file with mode: 0644]
modules/driver/app_manage.h [new file with mode: 0644]
modules/driver/device_driver.c [new file with mode: 0644]
modules/driver/device_driver.h [new file with mode: 0644]
modules/driver/device_driver_to_driver_to_buffer.h [new file with mode: 0644]
modules/driver/driver_debugfs.c [new file with mode: 0644]
modules/driver/driver_debugfs.h [new file with mode: 0644]
modules/driver/driver_defs.h [new file with mode: 0644]
modules/driver/driver_to_buffer.c [new file with mode: 0644]
modules/driver/driver_to_buffer.h [new file with mode: 0644]
modules/driver/driver_to_msg.h [new file with mode: 0644]
modules/driver/swap_driver_errors.h [new file with mode: 0644]
modules/driver/swap_driver_module.c [new file with mode: 0644]
modules/driver/swap_ioctl.h [new file with mode: 0644]
modules/driver/us_interaction.c [new file with mode: 0644]
modules/driver/us_interaction.h [new file with mode: 0644]
modules/driver/us_interaction_msg.h [new file with mode: 0644]
modules/energy/Kbuild [new file with mode: 0644]
modules/energy/debugfs_energy.c [new file with mode: 0644]
modules/energy/debugfs_energy.h [new file with mode: 0644]
modules/energy/energy.c [new file with mode: 0644]
modules/energy/energy.h [new file with mode: 0644]
modules/energy/energy_module.c [new file with mode: 0644]
modules/energy/lcd/lcd_base.c [new file with mode: 0644]
modules/energy/lcd/lcd_base.h [new file with mode: 0644]
modules/energy/lcd/lcd_debugfs.c [new file with mode: 0644]
modules/energy/lcd/lcd_debugfs.h [new file with mode: 0644]
modules/energy/lcd/maru.c [new file with mode: 0644]
modules/energy/lcd/s6e8aa0.c [new file with mode: 0644]
modules/energy/lcd/s6e8aa0_panel.c [new file with mode: 0644]
modules/energy/rational_debugfs.c [new file with mode: 0644]
modules/energy/rational_debugfs.h [new file with mode: 0644]
modules/energy/tm_stat.h [new file with mode: 0644]
modules/fbiprobe/Kbuild [new file with mode: 0644]
modules/fbiprobe/fbi_msg.c [new file with mode: 0644]
modules/fbiprobe/fbi_msg.h [new file with mode: 0644]
modules/fbiprobe/fbi_probe_module.h [new file with mode: 0644]
modules/fbiprobe/fbiprobe.c [new file with mode: 0644]
modules/fbiprobe/fbiprobe.h [new file with mode: 0644]
modules/fbiprobe/regs.h [new file with mode: 0644]
modules/got_patcher/Kbuild [new file with mode: 0644]
modules/got_patcher/gt.h [new file with mode: 0644]
modules/got_patcher/gt_debugfs.c [new file with mode: 0644]
modules/got_patcher/gt_debugfs.h [new file with mode: 0644]
modules/got_patcher/gt_module.c [new file with mode: 0644]
modules/got_patcher/gt_module.h [new file with mode: 0644]
modules/kprobe/Kbuild [new file with mode: 0644]
modules/kprobe/arch/arm/swap-asm/memory_rwx.c [new file with mode: 0644]
modules/kprobe/arch/arm/swap-asm/memory_rwx.h [new file with mode: 0644]
modules/kprobe/arch/arm/swap-asm/swap_kprobes.c [new file with mode: 0644]
modules/kprobe/arch/arm/swap-asm/swap_kprobes.h [new file with mode: 0644]
modules/kprobe/arch/arm/swap-asm/swap_probes.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/condn-helpers.c [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/condn-helpers.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/dbg_interface.c [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/dbg_interface.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/kprobes-arm64.c [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/kprobes-arm64.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/probes-decode.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/simulate-insn.c [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/simulate-insn.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/swap_kprobes.c [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/swap_kprobes.h [new file with mode: 0644]
modules/kprobe/arch/arm64/swap-asm/swap_probes.h [new file with mode: 0644]
modules/kprobe/arch/asm-mips/dbi_kprobes.c [new file with mode: 0644]
modules/kprobe/arch/asm-mips/dbi_kprobes.h [new file with mode: 0644]
modules/kprobe/arch/x86/swap-asm/swap_kprobes.c [new file with mode: 0644]
modules/kprobe/arch/x86/swap-asm/swap_kprobes.h [new file with mode: 0644]
modules/kprobe/swap_kdebug.h [new file with mode: 0644]
modules/kprobe/swap_kprobes.c [new file with mode: 0644]
modules/kprobe/swap_kprobes.h [new file with mode: 0644]
modules/kprobe/swap_kprobes_deps.c [new file with mode: 0644]
modules/kprobe/swap_kprobes_deps.h [new file with mode: 0644]
modules/kprobe/swap_ktd.c [new file with mode: 0644]
modules/kprobe/swap_ktd.h [new file with mode: 0644]
modules/kprobe/swap_no_kprobes.c [new file with mode: 0644]
modules/kprobe/swap_slots.c [new file with mode: 0644]
modules/kprobe/swap_slots.h [new file with mode: 0644]
modules/kprobe/swap_td_raw.c [new file with mode: 0644]
modules/kprobe/swap_td_raw.h [new file with mode: 0644]
modules/ks_features/Kbuild [new file with mode: 0644]
modules/ks_features/features_data.c [new file with mode: 0644]
modules/ks_features/file_ops.c [new file with mode: 0644]
modules/ks_features/file_ops.h [new file with mode: 0644]
modules/ks_features/ks_feature_hook.c [new file with mode: 0644]
modules/ks_features/ks_feature_kprobe.c [new file with mode: 0644]
modules/ks_features/ks_features.c [new file with mode: 0644]
modules/ks_features/ks_features.h [new file with mode: 0644]
modules/ks_features/ks_features_data.c [new file with mode: 0644]
modules/ks_features/ks_features_data.h [new file with mode: 0644]
modules/ks_features/ks_map.c [new file with mode: 0644]
modules/ks_features/ks_map.h [new file with mode: 0644]
modules/ks_features/ksf_msg.c [new file with mode: 0644]
modules/ks_features/ksf_msg.h [new file with mode: 0644]
modules/ks_features/syscall_list.h [new file with mode: 0644]
modules/ks_manager/Kbuild [new file with mode: 0644]
modules/ks_manager/ks_manager.c [new file with mode: 0644]
modules/ks_manager/ks_manager.h [new file with mode: 0644]
modules/ksyms/Kbuild [new file with mode: 0644]
modules/ksyms/ksyms.c [new file with mode: 0644]
modules/ksyms/ksyms.h [new file with mode: 0644]
modules/ksyms/ksyms_init.h [new file with mode: 0644]
modules/ksyms/ksyms_module.c [new file with mode: 0644]
modules/ksyms/no_ksyms.c [new file with mode: 0644]
modules/loader/Kbuild [new file with mode: 0644]
modules/loader/loader.h [new file with mode: 0644]
modules/loader/loader_debugfs.c [new file with mode: 0644]
modules/loader/loader_debugfs.h [new file with mode: 0644]
modules/loader/loader_defs.h [new file with mode: 0644]
modules/loader/loader_module.c [new file with mode: 0644]
modules/loader/loader_module.h [new file with mode: 0644]
modules/loader/loader_pd.c [new file with mode: 0644]
modules/loader/loader_pd.h [new file with mode: 0644]
modules/loader/loader_storage.c [new file with mode: 0644]
modules/loader/loader_storage.h [new file with mode: 0644]
modules/master/Kbuild [new file with mode: 0644]
modules/master/master_module.c [new file with mode: 0644]
modules/master/swap_debugfs.c [new file with mode: 0644]
modules/master/swap_debugfs.h [new file with mode: 0644]
modules/master/swap_deps.c [new file with mode: 0644]
modules/master/swap_deps.h [new file with mode: 0644]
modules/master/swap_initializer.c [new file with mode: 0644]
modules/master/swap_initializer.h [new file with mode: 0644]
modules/master/wait.c [new file with mode: 0644]
modules/master/wait.h [new file with mode: 0644]
modules/nsp/Kbuild [new file with mode: 0644]
modules/nsp/nsp.c [new file with mode: 0644]
modules/nsp/nsp.h [new file with mode: 0644]
modules/nsp/nsp_debugfs.c [new file with mode: 0644]
modules/nsp/nsp_debugfs.h [new file with mode: 0644]
modules/nsp/nsp_module.c [new file with mode: 0644]
modules/nsp/nsp_msg.c [new file with mode: 0644]
modules/nsp/nsp_msg.h [new file with mode: 0644]
modules/nsp/nsp_print.h [new file with mode: 0644]
modules/pack.sh [new file with mode: 0755]
modules/parser/Kbuild [new file with mode: 0644]
modules/parser/cpu_ctrl.c [new file with mode: 0644]
modules/parser/cpu_ctrl.h [new file with mode: 0644]
modules/parser/features.c [new file with mode: 0644]
modules/parser/features.h [new file with mode: 0644]
modules/parser/msg_buf.c [new file with mode: 0644]
modules/parser/msg_buf.h [new file with mode: 0644]
modules/parser/msg_cmd.c [new file with mode: 0644]
modules/parser/msg_cmd.h [new file with mode: 0644]
modules/parser/msg_parser.c [new file with mode: 0644]
modules/parser/msg_parser.h [new file with mode: 0644]
modules/parser/parser_defs.h [new file with mode: 0644]
modules/parser/swap_msg_parser.c [new file with mode: 0644]
modules/parser/us_inst.c [new file with mode: 0644]
modules/parser/us_inst.h [new file with mode: 0644]
modules/parser/usm_msg.c [new file with mode: 0644]
modules/parser/usm_msg.h [new file with mode: 0644]
modules/preload/Kbuild [new file with mode: 0644]
modules/preload/preload.h [new file with mode: 0644]
modules/preload/preload_control.c [new file with mode: 0644]
modules/preload/preload_control.h [new file with mode: 0644]
modules/preload/preload_debugfs.c [new file with mode: 0644]
modules/preload/preload_debugfs.h [new file with mode: 0644]
modules/preload/preload_module.c [new file with mode: 0644]
modules/preload/preload_module.h [new file with mode: 0644]
modules/preload/preload_probe.c [new file with mode: 0644]
modules/preload/preload_probe.h [new file with mode: 0644]
modules/preload/preload_process.c [new file with mode: 0644]
modules/preload/preload_process.h [new file with mode: 0644]
modules/preload/preload_threads.c [new file with mode: 0644]
modules/preload/preload_threads.h [new file with mode: 0644]
modules/retprobe/Kbuild [new file with mode: 0644]
modules/retprobe/retprobe.c [new file with mode: 0644]
modules/retprobe/retprobe.h [new file with mode: 0644]
modules/retprobe/rp_msg.c [new file with mode: 0644]
modules/retprobe/rp_msg.h [new file with mode: 0644]
modules/sampler/Kbuild [new file with mode: 0644]
modules/sampler/kernel_operations.h [new file with mode: 0644]
modules/sampler/sampler_hrtimer.c [new file with mode: 0644]
modules/sampler/sampler_timer.c [new file with mode: 0644]
modules/sampler/sampler_timers.h [new file with mode: 0644]
modules/sampler/swap_sampler_errors.h [new file with mode: 0644]
modules/sampler/swap_sampler_module.c [new file with mode: 0644]
modules/sampler/swap_sampler_module.h [new file with mode: 0644]
modules/task_ctx/Kbuild [new file with mode: 0644]
modules/task_ctx/task_ctx.c [new file with mode: 0644]
modules/task_ctx/task_ctx.h [new file with mode: 0644]
modules/tests/Kbuild [new file with mode: 0644]
modules/tests/kprobe_tests/Kbuild [new file with mode: 0644]
modules/tests/kprobe_tests/kp_module.c [new file with mode: 0644]
modules/tests/kprobe_tests/kp_module.h [new file with mode: 0644]
modules/tests/kprobe_tests/kp_tests.c [new file with mode: 0644]
modules/tests/kprobe_tests/krp_tests.c [new file with mode: 0644]
modules/tests/kprobe_tests/run_kp_tests.sh [new file with mode: 0644]
modules/uihv/Kbuild [new file with mode: 0644]
modules/uihv/uihv.h [new file with mode: 0644]
modules/uihv/uihv_debugfs.c [new file with mode: 0644]
modules/uihv/uihv_debugfs.h [new file with mode: 0644]
modules/uihv/uihv_module.c [new file with mode: 0644]
modules/uihv/uihv_module.h [new file with mode: 0644]
modules/uprobe/Kbuild [new file with mode: 0644]
modules/uprobe/arch/arm/swap-asm/swap_uprobes.c [new file with mode: 0644]
modules/uprobe/arch/arm/swap-asm/swap_uprobes.h [new file with mode: 0644]
modules/uprobe/arch/arm64/swap-asm/swap_uprobes.c [new file with mode: 0644]
modules/uprobe/arch/arm64/swap-asm/swap_uprobes.h [new file with mode: 0644]
modules/uprobe/arch/arm64/swap-asm/uprobes-arm64.c [new file with mode: 0644]
modules/uprobe/arch/arm64/swap-asm/uprobes-arm64.h [new file with mode: 0644]
modules/uprobe/arch/arm64/swap-asm/uprobes-decode.h [new file with mode: 0644]
modules/uprobe/arch/x86/swap-asm/swap_sc_patch.c [new file with mode: 0644]
modules/uprobe/arch/x86/swap-asm/swap_sc_patch.h [new file with mode: 0644]
modules/uprobe/arch/x86/swap-asm/swap_uprobes.c [new file with mode: 0644]
modules/uprobe/arch/x86/swap-asm/swap_uprobes.h [new file with mode: 0644]
modules/uprobe/swap_uaccess.h [new file with mode: 0644]
modules/uprobe/swap_uprobes.c [new file with mode: 0644]
modules/uprobe/swap_uprobes.h [new file with mode: 0644]
modules/us_manager/Kbuild [new file with mode: 0644]
modules/us_manager/callbacks.c [new file with mode: 0644]
modules/us_manager/callbacks.h [new file with mode: 0644]
modules/us_manager/debugfs_us_manager.c [new file with mode: 0644]
modules/us_manager/debugfs_us_manager.h [new file with mode: 0644]
modules/us_manager/helper.c [new file with mode: 0644]
modules/us_manager/helper.h [new file with mode: 0644]
modules/us_manager/helper_hook.c [new file with mode: 0644]
modules/us_manager/helper_kprobe.c [new file with mode: 0644]
modules/us_manager/img/img_file.c [new file with mode: 0644]
modules/us_manager/img/img_file.h [new file with mode: 0644]
modules/us_manager/img/img_ip.c [new file with mode: 0644]
modules/us_manager/img/img_ip.h [new file with mode: 0644]
modules/us_manager/img/img_proc.c [new file with mode: 0644]
modules/us_manager/img/img_proc.h [new file with mode: 0644]
modules/us_manager/pf/pf_group.c [new file with mode: 0644]
modules/us_manager/pf/pf_group.h [new file with mode: 0644]
modules/us_manager/pf/proc_filters.c [new file with mode: 0644]
modules/us_manager/pf/proc_filters.h [new file with mode: 0644]
modules/us_manager/probes/probe_info_new.c [new file with mode: 0644]
modules/us_manager/probes/probe_info_new.h [new file with mode: 0644]
modules/us_manager/probes/probes.c [new file with mode: 0644]
modules/us_manager/probes/probes.h [new file with mode: 0644]
modules/us_manager/probes/register_probes.h [new file with mode: 0644]
modules/us_manager/probes/use_probes.h [new file with mode: 0644]
modules/us_manager/sspt/sspt.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_debug.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_feature.c [new file with mode: 0644]
modules/us_manager/sspt/sspt_feature.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_file.c [new file with mode: 0644]
modules/us_manager/sspt/sspt_file.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_filter.c [new file with mode: 0644]
modules/us_manager/sspt/sspt_filter.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_ip.c [new file with mode: 0644]
modules/us_manager/sspt/sspt_ip.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_page.c [new file with mode: 0644]
modules/us_manager/sspt/sspt_page.h [new file with mode: 0644]
modules/us_manager/sspt/sspt_proc.c [new file with mode: 0644]
modules/us_manager/sspt/sspt_proc.h [new file with mode: 0644]
modules/us_manager/us_common_file.h [new file with mode: 0644]
modules/us_manager/us_manager.c [new file with mode: 0644]
modules/us_manager/us_manager.h [new file with mode: 0644]
modules/us_manager/us_manager_common.h [new file with mode: 0644]
modules/us_manager/us_slot_manager.c [new file with mode: 0644]
modules/us_manager/us_slot_manager.h [new file with mode: 0644]
modules/us_manager/usm_hook.c [new file with mode: 0644]
modules/us_manager/usm_hook.h [new file with mode: 0644]
modules/writer/Kbuild [new file with mode: 0644]
modules/writer/debugfs_writer.c [new file with mode: 0644]
modules/writer/debugfs_writer.h [new file with mode: 0644]
modules/writer/event_filter.c [new file with mode: 0644]
modules/writer/event_filter.h [new file with mode: 0644]
modules/writer/kernel_operations.h [new file with mode: 0644]
modules/writer/swap_msg.c [new file with mode: 0644]
modules/writer/swap_msg.h [new file with mode: 0644]
modules/writer/swap_writer_errors.h [new file with mode: 0644]
modules/writer/swap_writer_module.c [new file with mode: 0644]
modules/wsp/Kbuild [new file with mode: 0644]
modules/wsp/wsp.c [new file with mode: 0644]
modules/wsp/wsp.h [new file with mode: 0644]
modules/wsp/wsp_debugfs.c [new file with mode: 0644]
modules/wsp/wsp_debugfs.h [new file with mode: 0644]
modules/wsp/wsp_module.c [new file with mode: 0644]
modules/wsp/wsp_msg.c [new file with mode: 0644]
modules/wsp/wsp_msg.h [new file with mode: 0644]
modules/wsp/wsp_res.c [new file with mode: 0644]
modules/wsp/wsp_res.h [new file with mode: 0644]
nsp/Kbuild [deleted file]
nsp/nsp.c [deleted file]
nsp/nsp.h [deleted file]
nsp/nsp_debugfs.c [deleted file]
nsp/nsp_debugfs.h [deleted file]
nsp/nsp_module.c [deleted file]
nsp/nsp_msg.c [deleted file]
nsp/nsp_msg.h [deleted file]
nsp/nsp_print.h [deleted file]
pack.sh [deleted file]
packaging/swap-modules.spec
parser/Kbuild [deleted file]
parser/cpu_ctrl.c [deleted file]
parser/cpu_ctrl.h [deleted file]
parser/features.c [deleted file]
parser/features.h [deleted file]
parser/msg_buf.c [deleted file]
parser/msg_buf.h [deleted file]
parser/msg_cmd.c [deleted file]
parser/msg_cmd.h [deleted file]
parser/msg_parser.c [deleted file]
parser/msg_parser.h [deleted file]
parser/parser_defs.h [deleted file]
parser/swap_msg_parser.c [deleted file]
parser/us_inst.c [deleted file]
parser/us_inst.h [deleted file]
parser/usm_msg.c [deleted file]
parser/usm_msg.h [deleted file]
preload/Kbuild [deleted file]
preload/preload.h [deleted file]
preload/preload_control.c [deleted file]
preload/preload_control.h [deleted file]
preload/preload_debugfs.c [deleted file]
preload/preload_debugfs.h [deleted file]
preload/preload_module.c [deleted file]
preload/preload_module.h [deleted file]
preload/preload_probe.c [deleted file]
preload/preload_probe.h [deleted file]
preload/preload_process.c [deleted file]
preload/preload_process.h [deleted file]
preload/preload_threads.c [deleted file]
preload/preload_threads.h [deleted file]
retprobe/Kbuild [deleted file]
retprobe/retprobe.c [deleted file]
retprobe/retprobe.h [deleted file]
retprobe/rp_msg.c [deleted file]
retprobe/rp_msg.h [deleted file]
sampler/Kbuild [deleted file]
sampler/kernel_operations.h [deleted file]
sampler/sampler_hrtimer.c [deleted file]
sampler/sampler_timer.c [deleted file]
sampler/sampler_timers.h [deleted file]
sampler/swap_sampler_errors.h [deleted file]
sampler/swap_sampler_module.c [deleted file]
sampler/swap_sampler_module.h [deleted file]
task_ctx/Kbuild [deleted file]
task_ctx/task_ctx.c [deleted file]
task_ctx/task_ctx.h [deleted file]
tests/Kbuild [deleted file]
tests/kprobe_tests/Kbuild [deleted file]
tests/kprobe_tests/kp_module.c [deleted file]
tests/kprobe_tests/kp_module.h [deleted file]
tests/kprobe_tests/kp_tests.c [deleted file]
tests/kprobe_tests/krp_tests.c [deleted file]
tests/kprobe_tests/run_kp_tests.sh [deleted file]
uihv/Kbuild [deleted file]
uihv/uihv.h [deleted file]
uihv/uihv_debugfs.c [deleted file]
uihv/uihv_debugfs.h [deleted file]
uihv/uihv_module.c [deleted file]
uihv/uihv_module.h [deleted file]
uprobe/Kbuild [deleted file]
uprobe/arch/arm/swap-asm/swap_uprobes.c [deleted file]
uprobe/arch/arm/swap-asm/swap_uprobes.h [deleted file]
uprobe/arch/arm64/swap-asm/swap_uprobes.c [deleted file]
uprobe/arch/arm64/swap-asm/swap_uprobes.h [deleted file]
uprobe/arch/arm64/swap-asm/uprobes-arm64.c [deleted file]
uprobe/arch/arm64/swap-asm/uprobes-arm64.h [deleted file]
uprobe/arch/arm64/swap-asm/uprobes-decode.h [deleted file]
uprobe/arch/x86/swap-asm/swap_sc_patch.c [deleted file]
uprobe/arch/x86/swap-asm/swap_sc_patch.h [deleted file]
uprobe/arch/x86/swap-asm/swap_uprobes.c [deleted file]
uprobe/arch/x86/swap-asm/swap_uprobes.h [deleted file]
uprobe/swap_uaccess.h [deleted file]
uprobe/swap_uprobes.c [deleted file]
uprobe/swap_uprobes.h [deleted file]
us_manager/Kbuild [deleted file]
us_manager/callbacks.c [deleted file]
us_manager/callbacks.h [deleted file]
us_manager/debugfs_us_manager.c [deleted file]
us_manager/debugfs_us_manager.h [deleted file]
us_manager/helper.c [deleted file]
us_manager/helper.h [deleted file]
us_manager/helper_hook.c [deleted file]
us_manager/helper_kprobe.c [deleted file]
us_manager/img/img_file.c [deleted file]
us_manager/img/img_file.h [deleted file]
us_manager/img/img_ip.c [deleted file]
us_manager/img/img_ip.h [deleted file]
us_manager/img/img_proc.c [deleted file]
us_manager/img/img_proc.h [deleted file]
us_manager/pf/pf_group.c [deleted file]
us_manager/pf/pf_group.h [deleted file]
us_manager/pf/proc_filters.c [deleted file]
us_manager/pf/proc_filters.h [deleted file]
us_manager/probes/probe_info_new.c [deleted file]
us_manager/probes/probe_info_new.h [deleted file]
us_manager/probes/probes.c [deleted file]
us_manager/probes/probes.h [deleted file]
us_manager/probes/register_probes.h [deleted file]
us_manager/probes/use_probes.h [deleted file]
us_manager/sspt/sspt.h [deleted file]
us_manager/sspt/sspt_debug.h [deleted file]
us_manager/sspt/sspt_feature.c [deleted file]
us_manager/sspt/sspt_feature.h [deleted file]
us_manager/sspt/sspt_file.c [deleted file]
us_manager/sspt/sspt_file.h [deleted file]
us_manager/sspt/sspt_filter.c [deleted file]
us_manager/sspt/sspt_filter.h [deleted file]
us_manager/sspt/sspt_ip.c [deleted file]
us_manager/sspt/sspt_ip.h [deleted file]
us_manager/sspt/sspt_page.c [deleted file]
us_manager/sspt/sspt_page.h [deleted file]
us_manager/sspt/sspt_proc.c [deleted file]
us_manager/sspt/sspt_proc.h [deleted file]
us_manager/us_common_file.h [deleted file]
us_manager/us_manager.c [deleted file]
us_manager/us_manager.h [deleted file]
us_manager/us_manager_common.h [deleted file]
us_manager/us_slot_manager.c [deleted file]
us_manager/us_slot_manager.h [deleted file]
us_manager/usm_hook.c [deleted file]
us_manager/usm_hook.h [deleted file]
writer/Kbuild [deleted file]
writer/debugfs_writer.c [deleted file]
writer/debugfs_writer.h [deleted file]
writer/event_filter.c [deleted file]
writer/event_filter.h [deleted file]
writer/kernel_operations.h [deleted file]
writer/swap_msg.c [deleted file]
writer/swap_msg.h [deleted file]
writer/swap_writer_errors.h [deleted file]
writer/swap_writer_module.c [deleted file]
wsp/Kbuild [deleted file]
wsp/wsp.c [deleted file]
wsp/wsp.h [deleted file]
wsp/wsp_debugfs.c [deleted file]
wsp/wsp_debugfs.h [deleted file]
wsp/wsp_module.c [deleted file]
wsp/wsp_msg.c [deleted file]
wsp/wsp_msg.h [deleted file]
wsp/wsp_res.c [deleted file]
wsp/wsp_res.h [deleted file]

diff --git a/Doxyfile b/Doxyfile
deleted file mode 100644 (file)
index 3fa14b4..0000000
--- a/Doxyfile
+++ /dev/null
@@ -1,2310 +0,0 @@
-# Doxyfile 1.8.7
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME           = "SWAP Modules"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER         =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          =
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
-
-PROJECT_LOGO           =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       =
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS         = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES    = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF       =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES        = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH        =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH    =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF      = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES                =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST              =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING      =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT       = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT       = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT   = NO
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL            = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. When set to YES local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC  = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS       =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES        = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER    =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE            =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. Do not use file names with spaces, bibtex cannot handle them. See
-# also \cite for info how to create references.
-
-CITE_BIB_FILES         =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS               = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE           =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
-# Note: If this tag is empty the current directory is searched.
-
-INPUT                  =
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
-
-FILE_PATTERNS          =
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE                =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS        =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH           =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS       =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH             =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-
-INPUT_FILTER           =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS        =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES    = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS        = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX     = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX          =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER            =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER            =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET        =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
-# defined cascading style sheet that is included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
-# Doxygen will copy the style sheet file to the output directory. For an example
-# see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET  =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES       =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET        = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP      = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE               =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION           =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI           = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING     =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND             = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE               =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE          = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME   =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS  =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS  =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION           =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX          = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW      = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH         = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX            = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT         = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS     =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE       =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE           = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH    = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH        = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL       =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE        = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID     =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS  =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX         = YES
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE             = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES         =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
-# replace them by respectively the title of the page, the current date and time,
-# only the current date, the version number of doxygen, the project name (see
-# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER           =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER           =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES      =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS         = YES
-
-# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE        = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES     = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE        = plain
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE    =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE    =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION          = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR             =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT             = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK       = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT         = docbook
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION        = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH           =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS  =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED             =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED      =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES               =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE       =
-
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
-# The default value is: NO.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS        = YES
-
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES         = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               =
-
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS        = 0
-
-# When you want a differently looking font n the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME           = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH           =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK               = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH          = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH             = YES
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH           = YES
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif and svg.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG        = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH               =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS           =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS           =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS           =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP            = YES
diff --git a/Kbuild b/Kbuild
deleted file mode 100644 (file)
index 007e021..0000000
--- a/Kbuild
+++ /dev/null
@@ -1,30 +0,0 @@
-extra_cflags := -I$(M) -I$(M)/kprobe/arch/$(LINKNAME)/ -I$(M)/uprobe/arch/$(LINKNAME)/
-extra_cflags += $(MCFLAGS)
-EXTRA_CFLAGS := $(extra_cflags)
-export extra_cflags
-
-obj-m := master/ \
-         buffer/ \
-         ksyms/ \
-         driver/ \
-         writer/ \
-         kprobe/ \
-         uprobe/ \
-         us_manager/ \
-         ks_features/ \
-         loader/ \
-         sampler/ \
-         energy/ \
-         parser/ \
-         retprobe/ \
-         preload/ \
-         fbiprobe/ \
-         wsp/ \
-         nsp/ \
-         task_ctx/ \
-         uihv/ \
-         got_patcher/
-
-ifneq ($(CONFIG_SWAP_KERNEL_IMMUTABLE), y)
-obj-m += ks_manager/
-endif # CONFIG_SWAP_KERNEL_IMMUTABLE
diff --git a/arch/arm/probes/compat_arm64.h b/arch/arm/probes/compat_arm64.h
deleted file mode 100644 (file)
index e85766e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_COMPAT_ARM64_H
-#define _SWAP_ASM_COMPAT_ARM64_H
-
-
-#ifdef CONFIG_ARM64
-
-# define PSR_T_BIT             COMPAT_PSR_T_BIT
-
-# define ARM_r0                        compat_usr(0)
-# define ARM_r1                        compat_usr(1)
-# define ARM_r2                        compat_usr(2)
-# define ARM_r3                        compat_usr(3)
-# define ARM_r4                        compat_usr(4)
-# define ARM_r5                        compat_usr(5)
-# define ARM_r6                        compat_usr(6)
-# define ARM_r7                        compat_usr(7)
-# define ARM_r8                        compat_usr(8)
-# define ARM_r9                        compat_usr(9)
-# define ARM_r10               compat_usr(10)
-# define ARM_fp                        compat_fp
-# define ARM_ip                        compat_usr(12)
-# define ARM_sp                        compat_sp
-# define ARM_lr                        compat_lr
-# define ARM_pc                        pc
-# define ARM_cpsr              pstate
-
-# define thumb_mode(regs)      compat_thumb_mode(regs)
-
-#endif /* CONFIG_ARM64 */
-
-
-#endif /* _SWAP_ASM_COMPAT_ARM64_H */
-
-
-
-
-
-
diff --git a/arch/arm/probes/decode_arm_old.h b/arch/arm/probes/decode_arm_old.h
deleted file mode 100644 (file)
index ae6b6c8..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_DECODE_ARM_OLD_H
-#define _SWAP_ASM_DECODE_ARM_OLD_H
-
-
-#define ARM_INSN_MATCH(name, insn) \
-       ((insn & MASK_ARM_INSN_##name) == PTRN_ARM_INSN_##name)
-#define ARM_INSN_REG_RN(insn)                  ((insn & 0x000F0000) >> 16)
-#define ARM_INSN_REG_SET_RN(insn, nreg)                { insn &= ~0x000F0000; insn |= nreg << 16; }
-#define ARM_INSN_REG_RD(insn)                  ((insn & 0x0000F000) >> 12)
-#define ARM_INSN_REG_SET_RD(insn, nreg)                { insn &= ~0x0000F000; insn |= nreg << 12; }
-#define ARM_INSN_REG_RS(insn)                  ((insn & 0x00000F00) >> 8)
-#define ARM_INSN_REG_SET_RS(insn, nreg)                { insn &= ~0x00000F00; insn |= nreg << 8; }
-#define ARM_INSN_REG_RM(insn)                  (insn & 0x0000000F)
-#define ARM_INSN_REG_SET_RM(insn, nreg)                { insn &= ~0x0000000F; insn |= nreg; }
-#define ARM_INSN_REG_MR(insn, nreg)            (insn & (1 << nreg))
-#define ARM_INSN_REG_SET_MR(insn, nreg)                { insn |= (1 << nreg); }
-#define ARM_INSN_REG_CLEAR_MR(insn, nreg)      { insn &= ~(1 << nreg); }
-
-
-/* Undefined */
-#define MASK_ARM_INSN_UNDEF            0x0FF00000
-#define PTRN_ARM_INSN_UNDEF            0x03000000
-
-/* Architecturally undefined */
-#define MASK_ARM_INSN_AUNDEF           0x0FF000F0
-#define PTRN_ARM_INSN_AUNDEF           0x07F000F0
-
-/* Branches */
-#define MASK_ARM_INSN_B                        0x0F000000
-#define PTRN_ARM_INSN_B                        0x0A000000
-
-#define MASK_ARM_INSN_BL               0x0F000000
-#define PTRN_ARM_INSN_BL               0x0B000000
-
-#define MASK_ARM_INSN_BLX1             0xFE000000
-#define PTRN_ARM_INSN_BLX1             0xFA000000
-
-#define MASK_ARM_INSN_BLX2             0x0FF000F0
-#define PTRN_ARM_INSN_BLX2             0x01200030
-
-#define MASK_ARM_INSN_BX               0x0FF000F0
-#define PTRN_ARM_INSN_BX               0x01200010
-
-#define MASK_ARM_INSN_BXJ              0x0FF000F0
-#define PTRN_ARM_INSN_BXJ              0x01200020
-
-/* Software interrupts */
-#define MASK_ARM_INSN_SWI              0x0F000000
-#define PTRN_ARM_INSN_SWI              0x0F000000
-
-/* Break */
-#define MASK_ARM_INSN_BREAK            0xFFF000F0
-#define PTRN_ARM_INSN_BREAK            0xE1200070
-/* A8-56 ARM DDI 046B if cond != â€˜1110’ then UNPREDICTABLE; */
-
-/* CLZ */
-#define MASK_ARM_INSN_CLZ              0x0FFF0FF0
-#define PTRN_ARM_INSN_CLZ              0x016F0F10
-
-/* Data processing immediate shift */
-#define MASK_ARM_INSN_DPIS             0x0E000010
-#define PTRN_ARM_INSN_DPIS             0x00000000
-
-/* Data processing register shift */
-#define MASK_ARM_INSN_DPRS             0x0E000090
-#define PTRN_ARM_INSN_DPRS             0x00000010
-
-/* Data processing immediate */
-#define MASK_ARM_INSN_DPI              0x0E000000
-#define PTRN_ARM_INSN_DPI              0x02000000
-
-/* Load immediate offset */
-#define MASK_ARM_INSN_LIO              0x0E100000
-#define PTRN_ARM_INSN_LIO              0x04100000
-
-/* Store immediate offset */
-#define MASK_ARM_INSN_SIO              MASK_ARM_INSN_LIO
-#define PTRN_ARM_INSN_SIO              0x04000000
-
-/* Load register offset */
-#define MASK_ARM_INSN_LRO              0x0E100010
-#define PTRN_ARM_INSN_LRO              0x06100000
-
-/* Store register offset */
-#define MASK_ARM_INSN_SRO              MASK_ARM_INSN_LRO
-#define PTRN_ARM_INSN_SRO              0x06000000
-
-/* Load multiple */
-#define MASK_ARM_INSN_LM               0x0E100000
-#define PTRN_ARM_INSN_LM               0x08100000
-
-/* Store multiple */
-#define MASK_ARM_INSN_SM               MASK_ARM_INSN_LM
-#define PTRN_ARM_INSN_SM               0x08000000
-
-
-/* Coprocessor load/store and double register transfers */
-#define MASK_ARM_INSN_CLS              0x0E000000
-#define PTRN_ARM_INSN_CLS              0x0C000000
-
-/*  Coprocessor register transfers */
-#define MASK_ARM_INSN_CRT              0x0F000010
-#define PTRN_ARM_INSN_CRT              0x0E000010
-
-
-#endif /* _SWAP_ASM_DECODE_ARM_OLD_H */
diff --git a/arch/arm/probes/decode_thumb.c b/arch/arm/probes/decode_thumb.c
deleted file mode 100644 (file)
index a35f262..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include "decode_thumb.h"
-#include "tramps_thumb.h"
-#include "compat_arm64.h"
-
-
-#define GET_BIT(x, n)          ((x >> n) & 0x1)
-#define GET_FIELD(x, s, l)      ((x >> s) & ((1 << l) - 1))
-#define SET_FIELD(x, s, l, v)  ({              \
-       typeof(x) mask = (((1 << l) - 1) << s); \
-       (x & ~mask) | ((v << s) & mask);        \
-})
-
-
-typedef union thumb_insn {
-       u32 val;
-       struct {
-               u16 hw1;
-               u16 hw2;
-       } __packed;
-} thumb_insn_t;
-
-typedef int (*decode_handler_t)(thumb_insn_t insn, struct decode_info *info);
-
-
-static void make_def(void *tramp, u32 insn, u32 vaddr, bool t2)
-{
-       u32 ret_addr;
-       u16 *tr = tramp;
-
-       /*
-        * thumb  - +2
-        * thumb2 - +4
-        */
-       ret_addr = vaddr + (2 << t2);
-       tr[4] = insn & 0x0000ffff;
-       if (t2)
-               tr[5] = insn >> 16;
-
-       tr[13] = RET_BREAK_THUMB;
-       tr[16] = (ret_addr & 0x0000ffff) | 0x1;
-       tr[17] = ret_addr >> 16;
-}
-
-static void tt_make_common(void *tramp, u32 insn, u32 vaddr, bool t2)
-{
-       memcpy(tramp, gen_insn_execbuf_thumb, sizeof(gen_insn_execbuf_thumb));
-       make_def(tramp, insn, vaddr, t2);
-}
-
-static void tt_make_pc_deps(void *tramp, u32 mod_insn, u32 vaddr, bool t2)
-{
-       u32 pc_val = vaddr + 4;
-       u16 *tr = tramp;
-
-       memcpy(tramp, pc_dep_insn_execbuf_thumb,
-              sizeof(pc_dep_insn_execbuf_thumb));
-       make_def(tramp, mod_insn, vaddr, t2);
-
-       /* save PC value */
-       tr[14] = pc_val & 0x0000ffff;
-       tr[15] = pc_val >> 16;
-}
-
-
-static bool bad_reg(int n)
-{
-       return n == 13 || n == 15;
-}
-
-static int thumb_not_implement(thumb_insn_t insn, struct decode_info *info)
-{
-       return -EFAULT;
-}
-
-static int thumb_unpredictable(thumb_insn_t insn, struct decode_info *info)
-{
-       return -EINVAL;
-}
-
-/* hw1[1110 100x x1xx ????] */
-static int t32_ldrd_strd(thumb_insn_t insn, struct decode_info *info)
-{
-       int w = GET_BIT(insn.hw1, 5);
-       int n = GET_FIELD(insn.hw1, 0, 4);
-       int t = GET_FIELD(insn.hw2, 12, 4);
-       int t2 = GET_FIELD(insn.hw2, 8, 4);
-
-       if (bad_reg(t) || bad_reg(t2))
-               return thumb_unpredictable(insn, info);
-
-       /* check load flag */
-       if (GET_BIT(insn.hw1, 4)) {
-               /* LDRD */
-               if ((w && (n == 15)) || t == t2)
-                       return thumb_unpredictable(insn, info);
-
-               if (n == 15) {
-                       /* change PC -> SP */
-                       insn.hw1 = SET_FIELD(insn.hw1, 0, 4, 13);
-                       tt_make_pc_deps(info->tramp, insn.val,
-                                       info->vaddr, true);
-
-                       return 0;
-               }
-       } else {
-               /* STRD */
-               if ((w && t == n) || (w && t2 == n) || (n == 15))
-                       return thumb_unpredictable(insn, info);
-       }
-
-       tt_make_common(info->tramp, insn.val, info->vaddr, true);
-
-       return 0;
-}
-
-static int t32_b1110_100x_x1(thumb_insn_t insn, struct decode_info *info)
-{
-       /* check PW bits */
-       if (insn.hw1 & 0x120)
-               return t32_ldrd_strd(insn, info);
-
-       return thumb_not_implement(insn, info);
-}
-
-static int t32_b1110_100(thumb_insn_t insn, struct decode_info *info)
-{
-       if (GET_BIT(insn.hw1, 6))
-               return t32_b1110_100x_x1(insn, info);
-
-       return thumb_not_implement(insn, info);
-}
-
-static void t32_simulate_branch(u32 insn, struct arch_insn_arm *ainsn,
-                               struct pt_regs *regs)
-{
-       u32 pc = regs->ARM_pc;
-       thumb_insn_t i = { .val = insn };
-
-       s32 offset = GET_FIELD(i.hw2, 0, 11);           /* imm11 */
-       offset += GET_FIELD(i.hw1, 0, 10) << 11;        /* imm10 */
-       offset += GET_BIT(i.hw2, 13) << 21;             /* J1 */
-       offset += GET_BIT(i.hw2, 11) << 22;             /* J2 */
-
-       /* check S bit */
-       if (GET_BIT(i.hw1, 10))
-               offset -= 0x00800000;   /* Apply sign bit */
-       else
-               offset ^= 0x00600000;   /* Invert J1 and J2 */
-
-       /* check link */
-       if (GET_BIT(i.hw2, 14)) {
-               /* BL or BLX */
-               regs->ARM_lr = regs->ARM_pc | 1;
-               if (!GET_BIT(i.hw2, 12)) {
-                       /* BLX so switch to ARM mode */
-                       regs->ARM_cpsr &= ~PSR_T_BIT;
-                       pc &= ~3;
-               }
-       }
-
-       regs->ARM_pc = pc + (offset * 2);
-}
-
-static int t32_branch(thumb_insn_t insn, struct decode_info *info)
-{
-       info->handeler = t32_simulate_branch;
-
-       return 0;
-}
-
-static decode_handler_t table_branches[8] = {
-       /* hw2[14 12 0] */
-       /* Bc   0  0 0  */      thumb_not_implement,
-       /* Bc   0  0 1  */      thumb_not_implement,
-       /* B    0  1 0  */      t32_branch,
-       /* B    0  1 1  */      t32_branch,
-       /* BLX  1  0 0  */      t32_branch,
-       /* res  1  0 1  */      thumb_unpredictable,
-       /* BL   1  1 0  */      t32_branch,
-       /* BL   1  1 1  */      t32_branch,
-};
-
-
-
-static int t32_b1111_0xxx_xxxx_xxxx_1(thumb_insn_t insn,
-                                     struct decode_info *info)
-{
-       u32 s = GET_BIT(insn.hw2, 14) << 2 |
-               GET_BIT(insn.hw2, 12) << 1 |
-               GET_BIT(insn.hw2, 0);
-
-       return table_branches[s](insn, info);
-}
-
-static int b111(thumb_insn_t insn, struct decode_info *info)
-{
-       /* hw1[111x xxx? ???? ????] */
-       switch (GET_FIELD(insn.hw1, 9, 4)) {
-       case 0b0100:
-               return t32_b1110_100(insn, info);
-       }
-
-       /* [1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx] */
-       if (GET_FIELD(insn.hw1, 11, 2) == 0b10 && GET_BIT(insn.hw2, 15) == 1)
-               return t32_b1111_0xxx_xxxx_xxxx_1(insn, info);
-
-       return thumb_not_implement(insn, info);
-}
-
-
-decode_handler_t table_xxx[8] = {
-       /* 000 */       thumb_not_implement,
-       /* 001 */       thumb_not_implement,
-       /* 010 */       thumb_not_implement,
-       /* 011 */       thumb_not_implement,
-       /* 100 */       thumb_not_implement,
-       /* 101 */       thumb_not_implement,
-       /* 110 */       thumb_not_implement,
-       /* 111 */       b111,
-};
-
-
-int decode_thumb(u32 insn, struct decode_info *info)
-{
-       thumb_insn_t tinsn = { .val = insn };
-
-       /* check first 3 bits hw1[xxx? ???? ???? ????] */
-       return table_xxx[GET_FIELD(tinsn.hw1, 13, 3)](tinsn, info);
-}
diff --git a/arch/arm/probes/decode_thumb.h b/arch/arm/probes/decode_thumb.h
deleted file mode 100644 (file)
index 63d47db..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _ARM_DECODE_THUMB_H
-#define _ARM_DECODE_THUMB_H
-
-
-#include "probes.h"
-
-
-struct decode_info {
-       u32 vaddr;
-       void *tramp;
-       probe_handler_arm_t handeler;
-};
-
-
-int decode_thumb(u32 insn, struct decode_info *info);
-
-
-#endif /* _ARM_DECODE_THUMB_H */
diff --git a/arch/arm/probes/decode_thumb_old.h b/arch/arm/probes/decode_thumb_old.h
deleted file mode 100644 (file)
index df1faba..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_DECODE_THUMB_OLD_H
-#define _SWAP_ASM_DECODE_THUMB_OLD_H
-
-
-/* == THUMB == */
-#define THUMB_INSN_MATCH(name, insn) \
-       (((insn & 0x0000FFFF) & MASK_THUMB_INSN_##name) == \
-        PTRN_THUMB_INSN_##name)
-
-
-/* Undefined */
-#define MASK_THUMB_INSN_UNDEF  0xFE00
-#define PTRN_THUMB_INSN_UNDEF  0xDE00
-
-/* Branches */
-#define MASK_THUMB_INSN_B1     0xF000
-#define PTRN_THUMB_INSN_B1     0xD000          /* b<cond> label */
-
-#define MASK_THUMB_INSN_B2     0xF800
-#define PTRN_THUMB_INSN_B2     0xE000          /* b label */
-
-#define MASK_THUMB_INSN_CBZ    0xF500
-#define PTRN_THUMB_INSN_CBZ    0xB100          /* CBZ/CBNZ */
-
-#define MASK_THUMB_INSN_BLX2   0xFF80          /* blx reg */
-#define PTRN_THUMB_INSN_BLX2   0x4780
-
-#define MASK_THUMB_INSN_BX     0xFF80
-#define PTRN_THUMB_INSN_BX     0x4700
-
-/* Software interrupts */
-#define MASK_THUMB_INSN_SWI    0xFF00
-#define PTRN_THUMB_INSN_SWI    0xDF00
-
-/* Break */
-#define MASK_THUMB_INSN_BREAK  0xFF00
-#define PTRN_THUMB_INSN_BREAK  0xBE00
-
-/* Data processing immediate */
-#define MASK_THUMB_INSN_DP     0xFC00
-#define PTRN_THUMB_INSN_DP     0x4000
-
-#define MASK_THUMB_INSN_APC    0xF800
-#define PTRN_THUMB_INSN_APC    0xA000          /* ADD Rd, [PC, #<imm8> * 4] */
-
-#define MASK_THUMB_INSN_MOV3   0xFF00
-#define PTRN_THUMB_INSN_MOV3   0x4600          /* MOV Rd, PC */
-
-/* Load immediate offset */
-#define MASK_THUMB_INSN_LIO1   0xF800
-#define PTRN_THUMB_INSN_LIO1   0x6800          /* LDR */
-
-#define MASK_THUMB_INSN_LIO2   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_LIO2   0x7800          /* LDRB */
-
-#define MASK_THUMB_INSN_LIO3   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_LIO3   0x8800          /* LDRH */
-
-#define MASK_THUMB_INSN_LIO4   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_LIO4   0x9800          /* LDR SP relative */
-
-/* Store immediate offset */
-#define MASK_THUMB_INSN_SIO1   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO1   0x6000          /* STR */
-
-#define MASK_THUMB_INSN_SIO2   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO2   0x7000          /* STRB */
-
-#define MASK_THUMB_INSN_SIO3   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO3   0x8000          /* STRH */
-
-#define MASK_THUMB_INSN_SIO4   MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO4   0x9000          /* STR SP relative */
-
-/* Load register offset */
-#define MASK_THUMB_INSN_LRO1   0xFE00
-#define PTRN_THUMB_INSN_LRO1   0x5600          /* LDRSB */
-
-#define MASK_THUMB_INSN_LRO2   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO2   0x5800          /* LDR */
-
-#define MASK_THUMB_INSN_LRO3   0xf800
-#define PTRN_THUMB_INSN_LRO3   0x4800          /* LDR Rd, [PC, #<imm8> * 4] */
-
-#define MASK_THUMB_INSN_LRO4   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO4   0x5A00          /* LDRH */
-
-#define MASK_THUMB_INSN_LRO5   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO5   0x5C00          /* LDRB */
-
-#define MASK_THUMB_INSN_LRO6   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO6   0x5E00          /* LDRSH */
-
-/* Store register offset */
-#define MASK_THUMB_INSN_SRO1   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_SRO1   0x5000          /* STR */
-
-#define MASK_THUMB_INSN_SRO2   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_SRO2   0x5200          /* STRH */
-
-#define MASK_THUMB_INSN_SRO3   MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_SRO3   0x5400          /* STRB */
-
-
-/* == THUMB2 == */
-#define THUMB2_INSN_MATCH(name, insn) \
-       ((insn & MASK_THUMB2_INSN_##name) == PTRN_THUMB2_INSN_##name)
-
-#define THUMB2_INSN_REG_RT(insn)       ((insn & 0xf0000000) >> 28)
-#define THUMB2_INSN_REG_RT2(insn)      ((insn & 0x0f000000) >> 24)
-#define THUMB2_INSN_REG_RN(insn)       (insn & 0x0000000f)
-#define THUMB2_INSN_REG_RD(insn)       ((insn & 0x0f000000) >> 24)
-#define THUMB2_INSN_REG_RM(insn)       ((insn & 0x000f0000) >> 16)
-
-
-/* Branches */
-#define MASK_THUMB2_INSN_B1    0xD000F800
-#define PTRN_THUMB2_INSN_B1    0x8000F000
-
-#define MASK_THUMB2_INSN_B2    0xD000F800
-#define PTRN_THUMB2_INSN_B2    0x9000F000
-
-#define MASK_THUMB2_INSN_BL    0xD000F800
-#define PTRN_THUMB2_INSN_BL    0xD000F000      /* bl imm  swapped */
-
-#define MASK_THUMB2_INSN_BLX1  0xD001F800
-#define PTRN_THUMB2_INSN_BLX1  0xC000F000
-
-#define MASK_THUMB2_INSN_BXJ   0xD000FFF0
-#define PTRN_THUMB2_INSN_BXJ   0x8000F3C0
-
-/* Data processing register shift */
-#define MASK_THUMB2_INSN_DPRS  0xFFE00000
-#define PTRN_THUMB2_INSN_DPRS  0xEA000000
-
-/* Data processing immediate */
-#define MASK_THUMB2_INSN_DPI   0xFBE08000
-#define PTRN_THUMB2_INSN_DPI   0xF2000000
-
-#define MASK_THUMB2_INSN_RSBW  0x8000fbe0
-#define PTRN_THUMB2_INSN_RSBW  0x0000f1c0      /* RSB{S}.W Rd,Rn,#<const> */
-
-#define MASK_THUMB2_INSN_RORW  0xf0f0ffe0
-#define PTRN_THUMB2_INSN_RORW  0xf000fa60      /* ROR{S}.W Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_ROR   0x0030ffef
-#define PTRN_THUMB2_INSN_ROR   0x0030ea4f      /* ROR{S} Rd, Rm, #<imm> */
-
-#define MASK_THUMB2_INSN_LSLW1 0xf0f0ffe0
-#define PTRN_THUMB2_INSN_LSLW1 0xf000fa00      /* LSL{S}.W Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_LSLW2 0x0030ffef
-#define PTRN_THUMB2_INSN_LSLW2 0x0000ea4f      /* LSL{S}.W Rd, Rm, #<imm5>*/
-
-#define MASK_THUMB2_INSN_LSRW1 0xf0f0ffe0
-#define PTRN_THUMB2_INSN_LSRW1 0xf000fa20      /* LSR{S}.W Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_LSRW2 0x0030ffef
-#define PTRN_THUMB2_INSN_LSRW2 0x0010ea4f      /* LSR{S}.W Rd, Rm, #<imm5> */
-
-#define MASK_THUMB2_INSN_TEQ1  0x8f00fbf0
-#define PTRN_THUMB2_INSN_TEQ1  0x0f00f090      /* TEQ Rn, #<const> */
-
-#define MASK_THUMB2_INSN_TEQ2  0x0f00fff0
-#define PTRN_THUMB2_INSN_TEQ2  0x0f00ea90      /* TEQ Rn, Rm{,<shift>} */
-
-#define MASK_THUMB2_INSN_TST1  0x8f00fbf0
-#define PTRN_THUMB2_INSN_TST1  0x0f00f010      /* TST Rn, #<const> */
-
-#define MASK_THUMB2_INSN_TST2  0x0f00fff0
-#define PTRN_THUMB2_INSN_TST2  0x0f00ea10      /* TST Rn, Rm{,<shift>} */
-
-/* Load immediate offset */
-#define MASK_THUMB2_INSN_LDRW  0x0000fff0
-#define PTRN_THUMB2_INSN_LDRW  0x0000f850      /* LDR.W Rt, [Rn, #-<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRW1 MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRW1 0x0000f8d0      /* LDR.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRBW MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRBW 0x0000f810      /* LDRB.W Rt, [Rn, #-<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRBW1        MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRBW1        0x0000f890      /* LDRB.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRHW MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRHW 0x0000f830      /* LDRH.W Rt, [Rn, #-<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRHW1        MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRHW1        0x0000f8b0      /* LDRH.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRD  0x0000fed0
-#define PTRN_THUMB2_INSN_LDRD  0x0000e850      /* LDRD Rt, Rt2, [Rn, #-<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRD1 MASK_THUMB2_INSN_LDRD
-#define PTRN_THUMB2_INSN_LDRD1 0x0000e8d0      /* LDRD Rt, Rt2, [Rn, #<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRWL 0x0fc0fff0
-#define PTRN_THUMB2_INSN_LDRWL 0x0000f850      /* LDR.W Rt, [Rn,Rm,LSL #<imm2>] */
-
-#define MASK_THUMB2_INSN_LDREX 0x0f00ffff
-#define PTRN_THUMB2_INSN_LDREX 0x0f00e85f      /* LDREX Rt, [PC, #<imm8>] */
-
-#define MASK_THUMB2_INSN_MUL   0xf0f0fff0
-#define PTRN_THUMB2_INSN_MUL   0xf000fb00      /* MUL Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_DP    0x0000ff00
-#define PTRN_THUMB2_INSN_DP    0x0000eb00      /* ADD/SUB/SBC/...Rd,Rn,Rm{,<shift>} */
-
-/* Store immediate offset */
-#define MASK_THUMB2_INSN_STRW  0x0fc0fff0
-#define PTRN_THUMB2_INSN_STRW  0x0000f840      /* STR.W Rt,[Rn,Rm,{LSL #<imm2>}] */
-
-#define MASK_THUMB2_INSN_STRW1 0x0000fff0
-#define PTRN_THUMB2_INSN_STRW1 0x0000f8c0      /* STR.W Rt, [Rn, #imm12]
-                                                * STR.W Rt, [PC, #imm12] shall be
-                                                * skipped, because it hangs
-                                                * on Tegra. WTF */
-
-#define MASK_THUMB2_INSN_STRHW MASK_THUMB2_INSN_STRW
-#define PTRN_THUMB2_INSN_STRHW 0x0000f820      /* STRH.W Rt,[Rn,Rm,{LSL #<imm2>}] */
-
-#define MASK_THUMB2_INSN_STRHW1        0x0000fff0
-#define PTRN_THUMB2_INSN_STRHW1        0x0000f8a0      /* STRH.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_STRHT 0x0f00fff0      /* strht r1, [pc, #imm] illegal
-                                                * instruction on Tegra. WTF */
-#define PTRN_THUMB2_INSN_STRHT 0x0e00f820      /* STRHT Rt, [Rn, #<imm8>] */
-
-#define MASK_THUMB2_INSN_STRT  0x0f00fff0
-#define PTRN_THUMB2_INSN_STRT  0x0e00f840      /* STRT Rt, [Rn, #<imm8>] */
-
-#define MASK_THUMB2_INSN_STRBW MASK_THUMB2_INSN_STRW
-#define PTRN_THUMB2_INSN_STRBW 0x0000f800      /* STRB.W Rt,[Rn,Rm,{LSL #<imm2>}] */
-
-#define MASK_THUMB2_INSN_STRBW1        0x0000fff0
-#define PTRN_THUMB2_INSN_STRBW1        0x0000f880      /* STRB.W Rt, [Rn, #<imm12>]
-                                                * STRB.W Rt, [PC, #imm12] shall be
-                                                * skipped, because it hangs
-                                                * on Tegra. WTF */
-
-#define MASK_THUMB2_INSN_STRBT 0x0f00fff0
-#define PTRN_THUMB2_INSN_STRBT 0x0e00f800      /* STRBT Rt, [Rn, #<imm8>}] */
-
-#define MASK_THUMB2_INSN_STRD  0x0000fe50
-#define PTRN_THUMB2_INSN_STRD  0x0000e840      /* STR{D,EX,EXB,EXH,EXD} Rt, Rt2, [Rn, #<imm8>] */
-
-/* Load register offset */
-#define MASK_THUMB2_INSN_ADR   0x8000fa1f
-#define PTRN_THUMB2_INSN_ADR   0x0000f20f
-
-/* Load multiple */
-#define MASK_THUMB2_INSN_LDMIA 0x8000ffd0
-#define PTRN_THUMB2_INSN_LDMIA 0x8000e890      /* LDMIA(.W) Rn(!),{Rx-PC} */
-
-#define MASK_THUMB2_INSN_LDMDB 0x8000ffd0
-#define PTRN_THUMB2_INSN_LDMDB 0x8000e910      /* LDMDB(.W) Rn(!), {Rx-PC} */
-
-
-#endif /* _SWAP_ASM_DECODE_THUMB_OLD_H */
diff --git a/arch/arm/probes/probes.c b/arch/arm/probes/probes.c
deleted file mode 100644 (file)
index 0f2818b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include "probes.h"
-#include "probes_arm.h"
-#include "probes_thumb.h"
-
-
-int make_tramp(struct arch_insn_arm *ainsn, u32 vaddr, u32 insn,
-              u32 *tramp, u32 tramp_len)
-{
-       int ret;
-       int thumb_mode = vaddr & 1;
-
-       vaddr &= ~1;
-       if (thumb_mode)
-               ret = make_trampoline_thumb(ainsn, vaddr, insn,
-                                           tramp, tramp_len);
-       else
-               ret = make_trampoline_arm(vaddr, insn, tramp);
-
-       return ret;
-}
diff --git a/arch/arm/probes/probes.h b/arch/arm/probes/probes.h
deleted file mode 100644 (file)
index 4dcda9d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_PROBES_H
-#define _SWAP_ASM_PROBES_H
-
-
-#include <linux/types.h>
-#include <swap-asm/swap_probes.h>
-
-
-struct pt_regs;
-struct arch_insn_arm;
-
-
-typedef void (*probe_handler_arm_t)(u32 insn, struct arch_insn_arm *ainsn,
-                                   struct pt_regs *regs);
-
-
-struct arch_insn_arm {
-       probe_handler_arm_t handler;
-};
-
-
-int make_tramp(struct arch_insn_arm *ainsn, u32 vaddr, u32 insn,
-              u32 *tramp, u32 tramp_len);
-
-
-#endif /* _SWAP_ASM_PROBES_H */
-
diff --git a/arch/arm/probes/probes_arm.c b/arch/arm/probes/probes_arm.c
deleted file mode 100644 (file)
index 114eeb4..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>      /* nedded for printk.h */
-#include <linux/linkage.h>     /* needed for printk.h */
-#include <linux/printk.h>
-#include "probes.h"
-#include "tramps_arm.h"
-#include "decode_arm_old.h"
-
-
-#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
-#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
-
-
-static u32 get_addr_b(u32 insn, u32 addr)
-{
-       /* real position less then PC by 8 */
-       return ((s32)addr + 8 + branch_displacement(insn));
-}
-
-static int prep_pc_dep_insn_execbuf(u32 *insns, u32 insn, int uregs)
-{
-       int i;
-
-       if (uregs & 0x10) {
-               int reg_mask = 0x1;
-               /* search in reg list */
-               for (i = 0; i < 13; i++, reg_mask <<= 1) {
-                       if (!(insn & reg_mask))
-                               break;
-               }
-       } else {
-               for (i = 0; i < 13; i++) {
-                       if ((uregs & 0x1) && (ARM_INSN_REG_RN(insn) == i))
-                               continue;
-                       if ((uregs & 0x2) && (ARM_INSN_REG_RD(insn) == i))
-                               continue;
-                       if ((uregs & 0x4) && (ARM_INSN_REG_RS(insn) == i))
-                               continue;
-                       if ((uregs & 0x8) && (ARM_INSN_REG_RM(insn) == i))
-                               continue;
-                       break;
-               }
-       }
-
-       if (i == 13) {
-               pr_err("there are no free register %x in insn %x!",
-                      uregs, insn);
-               return -EINVAL;
-       }
-
-       /* set register to save */
-       ARM_INSN_REG_SET_RD(insns[0], i);
-       /* set register to load address to */
-       ARM_INSN_REG_SET_RD(insns[1], i);
-       /* set instruction to execute and patch it */
-       if (uregs & 0x10) {
-               ARM_INSN_REG_CLEAR_MR(insn, 15);
-               ARM_INSN_REG_SET_MR(insn, i);
-       } else {
-               if ((uregs & 0x1) && (ARM_INSN_REG_RN(insn) == 15))
-                       ARM_INSN_REG_SET_RN(insn, i);
-               if ((uregs & 0x2) && (ARM_INSN_REG_RD(insn) == 15))
-                       ARM_INSN_REG_SET_RD(insn, i);
-               if ((uregs & 0x4) && (ARM_INSN_REG_RS(insn) == 15))
-                       ARM_INSN_REG_SET_RS(insn, i);
-               if ((uregs & 0x8) && (ARM_INSN_REG_RM(insn) == 15))
-                       ARM_INSN_REG_SET_RM(insn, i);
-       }
-
-       insns[PROBES_TRAMP_INSN_IDX] = insn;
-       /* set register to restore */
-       ARM_INSN_REG_SET_RD(insns[3], i);
-
-       return 0;
-}
-
-static int arch_check_insn_arm(u32 insn)
-{
-       /* check instructions that can change PC by nature */
-       if (
-        /* ARM_INSN_MATCH(UNDEF, insn) || */
-           ARM_INSN_MATCH(AUNDEF, insn) ||
-           ARM_INSN_MATCH(SWI, insn) ||
-           ARM_INSN_MATCH(BREAK, insn) ||
-           ARM_INSN_MATCH(BXJ, insn)) {
-               goto bad_insn;
-#ifndef CONFIG_CPU_V7
-       /* check instructions that can write result to PC */
-       } else if ((ARM_INSN_MATCH(DPIS, insn) ||
-                   ARM_INSN_MATCH(DPRS, insn) ||
-                   ARM_INSN_MATCH(DPI, insn) ||
-                   ARM_INSN_MATCH(LIO, insn) ||
-                   ARM_INSN_MATCH(LRO, insn)) &&
-                  (ARM_INSN_REG_RD(insn) == 15)) {
-               goto bad_insn;
-#endif /* CONFIG_CPU_V7 */
-       /* check special instruction loads store multiple registers */
-       } else if ((ARM_INSN_MATCH(LM, insn) || ARM_INSN_MATCH(SM, insn)) &&
-                       /* store PC or load to PC */
-                  (ARM_INSN_REG_MR(insn, 15) ||
-                        /* store/load with PC update */
-                   ((ARM_INSN_REG_RN(insn) == 15) && (insn & 0x200000)))) {
-               goto bad_insn;
-       }
-
-       return 0;
-
-bad_insn:
-       return -EFAULT;
-}
-
-static int make_branch_tarmpoline(u32 addr, u32 insn, u32 *tramp)
-{
-       int ok = 0;
-
-       /* B */
-       if (ARM_INSN_MATCH(B, insn) &&
-           !ARM_INSN_MATCH(BLX1, insn)) {
-               /* B check can be false positive on BLX1 instruction */
-               memcpy(tramp, b_cond_insn_execbuf, sizeof(b_cond_insn_execbuf));
-               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
-               tramp[0] |= insn & 0xf0000000;
-               tramp[6] = get_addr_b(insn, addr);
-               tramp[7] = addr + 4;
-               ok = 1;
-       /* BX, BLX (Rm) */
-       } else if (ARM_INSN_MATCH(BX, insn) ||
-                  ARM_INSN_MATCH(BLX2, insn)) {
-               memcpy(tramp, b_r_insn_execbuf, sizeof(b_r_insn_execbuf));
-               tramp[0] = insn;
-               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
-               tramp[7] = addr + 4;
-               ok = 1;
-       /* BL, BLX (Off) */
-       } else if (ARM_INSN_MATCH(BLX1, insn)) {
-               memcpy(tramp, blx_off_insn_execbuf, sizeof(blx_off_insn_execbuf));
-               tramp[0] |= 0xe0000000;
-               tramp[1] |= 0xe0000000;
-               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
-               tramp[6] = get_addr_b(insn, addr) +
-                          2 * (insn & 01000000) + 1; /* jump to thumb */
-               tramp[7] = addr + 4;
-               ok = 1;
-       /* BL */
-       } else if (ARM_INSN_MATCH(BL, insn)) {
-               memcpy(tramp, blx_off_insn_execbuf, sizeof(blx_off_insn_execbuf));
-               tramp[0] |= insn & 0xf0000000;
-               tramp[1] |= insn & 0xf0000000;
-               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
-               tramp[6] = get_addr_b(insn, addr);
-               tramp[7] = addr + 4;
-               ok = 1;
-       }
-
-       return ok;
-}
-
-/**
- * @brief Creates ARM trampoline.
- *
- * @param addr Probe address.
- * @param insn Instuction at this address.
- * @param tramp Pointer to memory for trampoline.
- * @return 0 on success, error code on error.
- */
-int make_trampoline_arm(u32 addr, u32 insn, u32 *tramp)
-{
-       int ret, uregs, pc_dep;
-
-       if (addr & 0x03) {
-               pr_err("Error in %s at %d: attempt to register probe "
-                      "at an unaligned address\n", __FILE__, __LINE__);
-               return -EINVAL;
-       }
-
-       ret = arch_check_insn_arm(insn);
-       if (ret)
-               return ret;
-
-       if (make_branch_tarmpoline(addr, insn, tramp))
-               return 0;
-
-       uregs = pc_dep = 0;
-       /* Rm */
-       if (ARM_INSN_MATCH(CLZ, insn)) {
-               uregs = 0xa;
-               if (ARM_INSN_REG_RM(insn) == 15)
-                       pc_dep = 1;
-       /* Rn, Rm ,Rd */
-       } else if (ARM_INSN_MATCH(DPIS, insn) || ARM_INSN_MATCH(LRO, insn) ||
-           ARM_INSN_MATCH(SRO, insn)) {
-               uregs = 0xb;
-               if ((ARM_INSN_REG_RN(insn) == 15) ||
-                   (ARM_INSN_REG_RM(insn) == 15) ||
-                   (ARM_INSN_MATCH(SRO, insn) &&
-                    (ARM_INSN_REG_RD(insn) == 15))) {
-                       pc_dep = 1;
-               }
-       /* Rn ,Rd */
-       } else if (ARM_INSN_MATCH(DPI, insn) || ARM_INSN_MATCH(LIO, insn) ||
-                  ARM_INSN_MATCH(SIO, insn)) {
-               uregs = 0x3;
-               if ((ARM_INSN_REG_RN(insn) == 15) ||
-                   (ARM_INSN_MATCH(SIO, insn) &&
-                   (ARM_INSN_REG_RD(insn) == 15))) {
-                       pc_dep = 1;
-               }
-       /* Rn, Rm, Rs */
-       } else if (ARM_INSN_MATCH(DPRS, insn)) {
-               uregs = 0xd;
-               if ((ARM_INSN_REG_RN(insn) == 15) ||
-                   (ARM_INSN_REG_RM(insn) == 15) ||
-                   (ARM_INSN_REG_RS(insn) == 15)) {
-                       pc_dep = 1;
-               }
-       /* register list */
-       } else if (ARM_INSN_MATCH(SM, insn)) {
-               uregs = 0x10;
-               if (ARM_INSN_REG_MR(insn, 15))
-                       pc_dep = 1;
-       }
-
-       /* check instructions that can write result to SP and uses PC */
-       if (pc_dep && (ARM_INSN_REG_RD(insn) == 13)) {
-               pr_err("Error in %s at %d: instruction check failed (arm)\n",
-                      __FILE__, __LINE__);
-               return -EFAULT;
-       }
-
-       if (unlikely(uregs && pc_dep)) {
-               memcpy(tramp, pc_dep_insn_execbuf, sizeof(pc_dep_insn_execbuf));
-               if (prep_pc_dep_insn_execbuf(tramp, insn, uregs) != 0) {
-                       pr_err("Error in %s at %d: failed "
-                              "to prepare exec buffer for insn %x!",
-                              __FILE__, __LINE__, insn);
-                       return -EINVAL;
-               }
-
-               tramp[6] = addr + 8;
-       } else {
-               memcpy(tramp, gen_insn_execbuf, sizeof(gen_insn_execbuf));
-               tramp[PROBES_TRAMP_INSN_IDX] = insn;
-       }
-
-       /* TODO: remove for probe */
-       tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
-       tramp[7] = addr + 4;
-
-       return 0;
-}
-
-int noret_arm(u32 opcode)
-{
-       return !!(ARM_INSN_MATCH(BL, opcode) ||
-                 ARM_INSN_MATCH(BLX1, opcode) ||
-                 ARM_INSN_MATCH(BLX2, opcode));
-}
diff --git a/arch/arm/probes/probes_arm.h b/arch/arm/probes/probes_arm.h
deleted file mode 100644 (file)
index c324985..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_PROBES_ARM_H
-#define _SWAP_ASM_PROBES_ARM_H
-
-
-int make_trampoline_arm(u32 addr, u32 insn, u32 *tramp);
-int noret_arm(u32 opcode);
-
-
-#endif /* _SWAP_ASM_PROBES_ARM_H */
diff --git a/arch/arm/probes/probes_thumb.c b/arch/arm/probes/probes_thumb.c
deleted file mode 100644 (file)
index e94e3e2..0000000
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/errno.h>
-#include <linux/string.h>
-#include "tramps_thumb.h"
-#include "decode_thumb.h"
-#include "decode_thumb_old.h"
-
-
-static inline s32 branch_t16_dest(u32 insn, unsigned int insn_addr)
-{
-       s32 offset = insn & 0x3ff;
-       offset -= insn & 0x400;
-       return insn_addr + 4 + offset * 2;
-}
-
-static inline s32 branch_cond_t16_dest(u32 insn, unsigned int insn_addr)
-{
-       s32 offset = insn & 0x7f;
-       offset -= insn & 0x80;
-       return insn_addr + 4 + offset * 2;
-}
-
-static inline s32 branch_t32_dest(u32 insn, unsigned int insn_addr)
-{
-       unsigned int poff = insn & 0x3ff;
-       unsigned int offset = (insn & 0x07fe0000) >> 17;
-
-       poff -= (insn & 0x400);
-
-       if (insn & (1 << 12))
-               return insn_addr + 4 + (poff << 12) + offset * 4;
-
-       return (insn_addr + 4 + (poff << 12) + offset * 4) & ~3;
-}
-
-static inline s32 cbz_t16_dest(u32 insn, unsigned int insn_addr)
-{
-       unsigned int i = (insn & 0x200) >> 3;
-       unsigned int offset = (insn & 0xf8) >> 2;
-       return insn_addr + 4 + i + offset;
-}
-
-/* is instruction Thumb2 and NOT a branch, etc... */
-static int is_thumb2(u32 insn)
-{
-       return ((insn & 0xf800) == 0xe800 ||
-               (insn & 0xf800) == 0xf000 ||
-               (insn & 0xf800) == 0xf800);
-}
-
-static int prep_pc_dep_insn_execbuf_thumb(u32 *insns, u32 insn, int uregs)
-{
-       unsigned char mreg = 0;
-       unsigned char reg = 0;
-
-       if (THUMB_INSN_MATCH(APC, insn) ||
-           THUMB_INSN_MATCH(LRO3, insn)) {
-               reg = ((insn & 0xffff) & uregs) >> 8;
-       } else if (THUMB_INSN_MATCH(MOV3, insn)) {
-               if (((((unsigned char)insn) & 0xff) >> 3) == 15)
-                       reg = (insn & 0xffff) & uregs;
-               else
-                       return 0;
-       } else if (THUMB2_INSN_MATCH(ADR, insn)) {
-               reg = ((insn >> 16) & uregs) >> 8;
-               if (reg == 15)
-                       return 0;
-       } else if (THUMB2_INSN_MATCH(LDRW, insn) ||
-                  THUMB2_INSN_MATCH(LDRW1, insn) ||
-                  THUMB2_INSN_MATCH(LDRHW, insn) ||
-                  THUMB2_INSN_MATCH(LDRHW1, insn) ||
-                  THUMB2_INSN_MATCH(LDRWL, insn)) {
-               reg = ((insn >> 16) & uregs) >> 12;
-               if (reg == 15)
-                       return 0;
-       /*
-        * LDRB.W PC, [PC, #immed] => PLD [PC, #immed], so Rt == PC is skipped
-        */
-       } else if (THUMB2_INSN_MATCH(LDRBW, insn) ||
-                  THUMB2_INSN_MATCH(LDRBW1, insn) ||
-                  THUMB2_INSN_MATCH(LDREX, insn)) {
-               reg = ((insn >> 16) & uregs) >> 12;
-       } else if (THUMB2_INSN_MATCH(DP, insn)) {
-               reg = ((insn >> 16) & uregs) >> 12;
-               if (reg == 15)
-                       return 0;
-       } else if (THUMB2_INSN_MATCH(RSBW, insn)) {
-               reg = ((insn >> 12) & uregs) >> 8;
-               if (reg == 15)
-                       return 0;
-       } else if (THUMB2_INSN_MATCH(RORW, insn)) {
-               reg = ((insn >> 12) & uregs) >> 8;
-               if (reg == 15)
-                       return 0;
-       } else if (THUMB2_INSN_MATCH(ROR, insn) ||
-                  THUMB2_INSN_MATCH(LSLW1, insn) ||
-                  THUMB2_INSN_MATCH(LSLW2, insn) ||
-                  THUMB2_INSN_MATCH(LSRW1, insn) ||
-                  THUMB2_INSN_MATCH(LSRW2, insn)) {
-               reg = ((insn >> 12) & uregs) >> 8;
-               if (reg == 15)
-                       return 0;
-       } else if (THUMB2_INSN_MATCH(TEQ1, insn) ||
-                  THUMB2_INSN_MATCH(TST1, insn)) {
-               reg = 15;
-       } else if (THUMB2_INSN_MATCH(TEQ2, insn) ||
-                  THUMB2_INSN_MATCH(TST2, insn)) {
-               reg = THUMB2_INSN_REG_RM(insn);
-       }
-
-       if ((THUMB2_INSN_MATCH(STRW, insn) ||
-            THUMB2_INSN_MATCH(STRBW, insn) ||
-            THUMB2_INSN_MATCH(STRD, insn) ||
-            THUMB2_INSN_MATCH(STRHT, insn) ||
-            THUMB2_INSN_MATCH(STRT, insn) ||
-            THUMB2_INSN_MATCH(STRHW1, insn) ||
-            THUMB2_INSN_MATCH(STRHW, insn)) &&
-           THUMB2_INSN_REG_RT(insn) == 15) {
-               reg = THUMB2_INSN_REG_RT(insn);
-       }
-
-       if (reg == 6 || reg == 7) {
-               *((u16 *)insns + 0) =
-                       (*((u16 *)insns + 0) & 0x00ff) |
-                       ((1 << mreg) | (1 << (mreg + 1)));
-               *((u16 *)insns + 1) =
-                       (*((u16 *)insns + 1) & 0xf8ff) | (mreg << 8);
-               *((u16 *)insns + 2) =
-                       (*((u16 *)insns + 2) & 0xfff8) | (mreg + 1);
-               *((u16 *)insns + 3) =
-                       (*((u16 *)insns + 3) & 0xffc7) | (mreg << 3);
-               *((u16 *)insns + 7) =
-                       (*((u16 *)insns + 7) & 0xf8ff) | (mreg << 8);
-               *((u16 *)insns + 8) =
-                       (*((u16 *)insns + 8) & 0xffc7) | (mreg << 3);
-               *((u16 *)insns + 9) =
-                       (*((u16 *)insns + 9) & 0xffc7) | ((mreg + 1) << 3);
-               *((u16 *)insns + 10) =
-                       (*((u16 *)insns + 10) & 0x00ff) |
-                       ((1 << mreg) | (1 << (mreg + 1)));
-       }
-
-       if (THUMB_INSN_MATCH(APC, insn)) {
-               /* ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4 */
-               *((u16 *)insns + 4) = ((insn & 0xffff) | 0x800);
-       } else if (THUMB_INSN_MATCH(LRO3, insn)) {
-               /* LDR Rd, [PC, #immed_8*4] ->
-                * LDR Rd, [SP, #immed_8*4] */
-               *((u16 *)insns + 4) = ((insn & 0xffff) + 0x5000);
-       } else if (THUMB_INSN_MATCH(MOV3, insn)) {
-               /* MOV Rd, PC -> MOV Rd, SP */
-               *((u16 *)insns + 4) = ((insn & 0xffff) ^ 0x10);
-       } else if (THUMB2_INSN_MATCH(ADR, insn)) {
-               /* ADDW Rd,PC,#imm -> ADDW Rd,SP,#imm */
-               insns[2] = (insn & 0xfffffff0) | 0x0d;
-       } else if (THUMB2_INSN_MATCH(LDRW, insn) ||
-                  THUMB2_INSN_MATCH(LDRBW, insn) ||
-                  THUMB2_INSN_MATCH(LDRHW, insn)) {
-               /* LDR.W Rt, [PC, #-<imm_12>] ->
-                * LDR.W Rt, [SP, #-<imm_8>]
-                * !!!!!!!!!!!!!!!!!!!!!!!!
-                * !!! imm_12 vs. imm_8 !!!
-                * !!!!!!!!!!!!!!!!!!!!!!!! */
-               insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;
-       } else if (THUMB2_INSN_MATCH(LDRW1, insn) ||
-                  THUMB2_INSN_MATCH(LDRBW1, insn) ||
-                  THUMB2_INSN_MATCH(LDRHW1, insn) ||
-                  THUMB2_INSN_MATCH(LDRD, insn) ||
-                  THUMB2_INSN_MATCH(LDRD1, insn) ||
-                  THUMB2_INSN_MATCH(LDREX, insn)) {
-               /* LDRx.W Rt, [PC, #+<imm_12>] ->
-                * LDRx.W Rt, [SP, #+<imm_12>]
-                (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>] */
-               insns[2] = (insn & 0xfffffff0) | 0xd;
-       } else if (THUMB2_INSN_MATCH(MUL, insn)) {
-               /* MUL Rd, Rn, SP */
-               insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
-       } else if (THUMB2_INSN_MATCH(DP, insn)) {
-               if (THUMB2_INSN_REG_RM(insn) == 15)
-                       /* DP Rd, Rn, PC */
-                       insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
-               else if (THUMB2_INSN_REG_RN(insn) == 15)
-                       /* DP Rd, PC, Rm */
-                       insns[2] = (insn & 0xfffffff0) | 0xd;
-       } else if (THUMB2_INSN_MATCH(LDRWL, insn)) {
-               /* LDRx.W Rt, [PC, #<imm_12>] ->
-                * LDRx.W Rt, [SP, #+<imm_12>]
-                * (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>] */
-               insns[2] = (insn & 0xfffffff0) | 0xd;
-       } else if (THUMB2_INSN_MATCH(RSBW, insn)) {
-               /*  RSB{S}.W Rd, PC, #<const> -> RSB{S}.W Rd, SP, #<const> */
-               insns[2] = (insn & 0xfffffff0) | 0xd;
-       } else if (THUMB2_INSN_MATCH(RORW, insn) ||
-                  THUMB2_INSN_MATCH(LSLW1, insn) ||
-                  THUMB2_INSN_MATCH(LSRW1, insn)) {
-               if ((THUMB2_INSN_REG_RM(insn) == 15) &&
-                   (THUMB2_INSN_REG_RN(insn) == 15))
-                       /*  ROR.W Rd, PC, PC */
-                       insns[2] = (insn & 0xfffdfffd);
-               else if (THUMB2_INSN_REG_RM(insn) == 15)
-                       /*  ROR.W Rd, Rn, PC */
-                       insns[2] = (insn & 0xfff0ffff) | 0xd0000;
-               else if (THUMB2_INSN_REG_RN(insn) == 15)
-                       /*  ROR.W Rd, PC, Rm */
-                       insns[2] = (insn & 0xfffffff0) | 0xd;
-       } else if (THUMB2_INSN_MATCH(ROR, insn) ||
-                  THUMB2_INSN_MATCH(LSLW2, insn) ||
-                  THUMB2_INSN_MATCH(LSRW2, insn)) {
-               /*  ROR{S} Rd, PC, #<const> -> ROR{S} Rd, SP, #<const> */
-               insns[2] = (insn & 0xfff0ffff) | 0xd0000;
-       }
-
-       if (THUMB2_INSN_MATCH(STRW, insn) ||
-           THUMB2_INSN_MATCH(STRBW, insn)) {
-               /*  STRx.W Rt, [Rn, SP] */
-               insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
-       } else if (THUMB2_INSN_MATCH(STRD, insn) ||
-                  THUMB2_INSN_MATCH(STRHT, insn) ||
-                  THUMB2_INSN_MATCH(STRT, insn) ||
-                  THUMB2_INSN_MATCH(STRHW1, insn)) {
-               if (THUMB2_INSN_REG_RN(insn) == 15)
-                       /*  STRD/T/HT{.W} Rt, [SP, ...] */
-                       insns[2] = (insn & 0xfffffff0) | 0xd;
-               else
-                       insns[2] = insn;
-       } else if (THUMB2_INSN_MATCH(STRHW, insn) &&
-                  (THUMB2_INSN_REG_RN(insn) == 15)) {
-               if (THUMB2_INSN_REG_RN(insn) == 15)
-                       /*  STRH.W Rt, [SP, #-<imm_8>] */
-                       insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;
-               else
-                       insns[2] = insn;
-       }
-
-       /*  STRx PC, xxx */
-       if ((reg == 15) && (THUMB2_INSN_MATCH(STRW, insn)   ||
-                           THUMB2_INSN_MATCH(STRBW, insn)  ||
-                           THUMB2_INSN_MATCH(STRD, insn)   ||
-                           THUMB2_INSN_MATCH(STRHT, insn)  ||
-                           THUMB2_INSN_MATCH(STRT, insn)   ||
-                           THUMB2_INSN_MATCH(STRHW1, insn) ||
-                           THUMB2_INSN_MATCH(STRHW, insn))) {
-               insns[2] = (insns[2] & 0x0fffffff) | 0xd0000000;
-       }
-
-       if (THUMB2_INSN_MATCH(TEQ1, insn) ||
-           THUMB2_INSN_MATCH(TST1, insn)) {
-               /*  TEQ SP, #<const> */
-               insns[2] = (insn & 0xfffffff0) | 0xd;
-       } else if (THUMB2_INSN_MATCH(TEQ2, insn) ||
-                  THUMB2_INSN_MATCH(TST2, insn)) {
-               if ((THUMB2_INSN_REG_RN(insn) == 15) &&
-                   (THUMB2_INSN_REG_RM(insn) == 15))
-                       /*  TEQ/TST PC, PC */
-                       insns[2] = (insn & 0xfffdfffd);
-               else if (THUMB2_INSN_REG_RM(insn) == 15)
-                       /*  TEQ/TST Rn, PC */
-                       insns[2] = (insn & 0xfff0ffff) | 0xd0000;
-               else if (THUMB2_INSN_REG_RN(insn) == 15)
-                       /*  TEQ/TST PC, Rm */
-                       insns[2] = (insn & 0xfffffff0) | 0xd;
-       }
-
-       return 0;
-}
-
-static int arch_check_insn_thumb(u32 insn)
-{
-       int ret = 0;
-
-       /* check instructions that can change PC */
-       if (THUMB_INSN_MATCH(UNDEF, insn) ||
-           THUMB2_INSN_MATCH(BLX1, insn) ||
-           THUMB2_INSN_MATCH(BL, insn) ||
-           THUMB_INSN_MATCH(SWI, insn) ||
-           THUMB_INSN_MATCH(BREAK, insn) ||
-           THUMB2_INSN_MATCH(B1, insn) ||
-           THUMB2_INSN_MATCH(B2, insn) ||
-           THUMB2_INSN_MATCH(BXJ, insn) ||
-           (THUMB2_INSN_MATCH(ADR, insn) &&
-            THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRW, insn) && THUMB2_INSN_REG_RT(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRW1, insn) &&
-            THUMB2_INSN_REG_RT(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRHW, insn) &&
-            THUMB2_INSN_REG_RT(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRHW1, insn) &&
-            THUMB2_INSN_REG_RT(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRWL, insn) &&
-            THUMB2_INSN_REG_RT(insn) == 15) ||
-           THUMB2_INSN_MATCH(LDMIA, insn) ||
-           THUMB2_INSN_MATCH(LDMDB, insn) ||
-           (THUMB2_INSN_MATCH(DP, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(RSBW, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(RORW, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(ROR, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LSLW1, insn) &&
-            THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LSLW2, insn) &&
-            THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LSRW1, insn) &&
-            THUMB2_INSN_REG_RD(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LSRW2, insn) &&
-            THUMB2_INSN_REG_RD(insn) == 15) ||
-           /* skip PC, #-imm12 -> SP, #-imm8 and Tegra-hanging instructions */
-           (THUMB2_INSN_MATCH(STRW1, insn) &&
-            THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(STRBW1, insn) &&
-            THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(STRHW1, insn) &&
-            THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(STRW, insn) && THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(STRHW, insn) &&
-            THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRW, insn) && THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRBW, insn) &&
-            THUMB2_INSN_REG_RN(insn) == 15) ||
-           (THUMB2_INSN_MATCH(LDRHW, insn) &&
-            THUMB2_INSN_REG_RN(insn) == 15) ||
-           /* skip STRDx/LDRDx Rt, Rt2, [Rd, ...] */
-           (THUMB2_INSN_MATCH(LDRD, insn) || THUMB2_INSN_MATCH(LDRD1, insn) ||
-            THUMB2_INSN_MATCH(STRD, insn))) {
-               ret = -EFAULT;
-       }
-
-       return ret;
-}
-
-static int do_make_trampoline_thumb(u32 vaddr, u32 insn,
-                                   u32 *tramp, size_t tramp_len)
-{
-       int ret;
-       int uregs = 0;
-       int pc_dep = 0;
-       unsigned int addr;
-
-       ret = arch_check_insn_thumb(insn);
-       if (ret)
-               return ret;
-
-       if (THUMB_INSN_MATCH(APC, insn) || THUMB_INSN_MATCH(LRO3, insn)) {
-               uregs = 0x0700;         /* 8-10 */
-               pc_dep = 1;
-       } else if (THUMB_INSN_MATCH(MOV3, insn) &&
-                  (((((unsigned char)insn) & 0xff) >> 3) == 15)) {
-               /* MOV Rd, PC */
-               uregs = 0x07;
-               pc_dep = 1;
-       } else if THUMB2_INSN_MATCH(ADR, insn) {
-               uregs = 0x0f00;         /* Rd 8-11 */
-               pc_dep = 1;
-       } else if (((THUMB2_INSN_MATCH(LDRW, insn) ||
-                    THUMB2_INSN_MATCH(LDRW1, insn) ||
-                    THUMB2_INSN_MATCH(LDRBW, insn) ||
-                    THUMB2_INSN_MATCH(LDRBW1, insn) ||
-                    THUMB2_INSN_MATCH(LDRHW, insn) ||
-                    THUMB2_INSN_MATCH(LDRHW1, insn) ||
-                    THUMB2_INSN_MATCH(LDRWL, insn)) &&
-                   THUMB2_INSN_REG_RN(insn) == 15) ||
-                    THUMB2_INSN_MATCH(LDREX, insn) ||
-                    ((THUMB2_INSN_MATCH(STRW, insn) ||
-                      THUMB2_INSN_MATCH(STRBW, insn) ||
-                      THUMB2_INSN_MATCH(STRHW, insn) ||
-                      THUMB2_INSN_MATCH(STRHW1, insn)) &&
-                     (THUMB2_INSN_REG_RN(insn) == 15 ||
-                      THUMB2_INSN_REG_RT(insn) == 15)) ||
-                    ((THUMB2_INSN_MATCH(STRT, insn) ||
-                      THUMB2_INSN_MATCH(STRHT, insn)) &&
-                      (THUMB2_INSN_REG_RN(insn) == 15 ||
-                       THUMB2_INSN_REG_RT(insn) == 15))) {
-               uregs = 0xf000;         /* Rt 12-15 */
-               pc_dep = 1;
-       } else if ((THUMB2_INSN_MATCH(LDRD, insn) ||
-                   THUMB2_INSN_MATCH(LDRD1, insn)) &&
-                  (THUMB2_INSN_REG_RN(insn) == 15)) {
-               uregs = 0xff00;         /* Rt 12-15, Rt2 8-11 */
-               pc_dep = 1;
-       } else if (THUMB2_INSN_MATCH(MUL, insn) &&
-                  THUMB2_INSN_REG_RM(insn) == 15) {
-               uregs = 0xf;
-               pc_dep = 1;
-       } else if (THUMB2_INSN_MATCH(DP, insn) &&
-                  (THUMB2_INSN_REG_RN(insn) == 15 ||
-                   THUMB2_INSN_REG_RM(insn) == 15)) {
-               uregs = 0xf000;         /* Rd 12-15 */
-               pc_dep = 1;
-       } else if (THUMB2_INSN_MATCH(STRD, insn) &&
-                  ((THUMB2_INSN_REG_RN(insn) == 15) ||
-                   (THUMB2_INSN_REG_RT(insn) == 15) ||
-                   THUMB2_INSN_REG_RT2(insn) == 15)) {
-               uregs = 0xff00;         /* Rt 12-15, Rt2 8-11 */
-               pc_dep = 1;
-       } else if (THUMB2_INSN_MATCH(RSBW, insn) &&
-                  THUMB2_INSN_REG_RN(insn) == 15) {
-               uregs = 0x0f00;         /* Rd 8-11 */
-               pc_dep = 1;
-       } else if (THUMB2_INSN_MATCH(RORW, insn) &&
-                  (THUMB2_INSN_REG_RN(insn) == 15 ||
-                   THUMB2_INSN_REG_RM(insn) == 15)) {
-               uregs = 0x0f00;
-               pc_dep = 1;
-       } else if ((THUMB2_INSN_MATCH(ROR, insn) ||
-                   THUMB2_INSN_MATCH(LSLW2, insn) ||
-                   THUMB2_INSN_MATCH(LSRW2, insn)) &&
-                  THUMB2_INSN_REG_RM(insn) == 15) {
-               uregs = 0x0f00;         /* Rd 8-11 */
-               pc_dep = 1;
-       } else if ((THUMB2_INSN_MATCH(LSLW1, insn) ||
-                   THUMB2_INSN_MATCH(LSRW1, insn)) &&
-                  (THUMB2_INSN_REG_RN(insn) == 15 ||
-                   THUMB2_INSN_REG_RM(insn) == 15)) {
-               uregs = 0x0f00;         /* Rd 8-11 */
-               pc_dep = 1;
-       } else if ((THUMB2_INSN_MATCH(TEQ1, insn) ||
-                   THUMB2_INSN_MATCH(TST1, insn)) &&
-                  THUMB2_INSN_REG_RN(insn) == 15) {
-               uregs = 0xf0000;        /* Rn 0-3 (16-19) */
-               pc_dep = 1;
-       } else if ((THUMB2_INSN_MATCH(TEQ2, insn) ||
-                   THUMB2_INSN_MATCH(TST2, insn)) &&
-                  (THUMB2_INSN_REG_RN(insn) == 15 ||
-                   THUMB2_INSN_REG_RM(insn) == 15)) {
-               uregs = 0xf0000;        /* Rn 0-3 (16-19) */
-               pc_dep = 1;
-       }
-
-       if (unlikely(uregs && pc_dep)) {
-               memcpy(tramp, pc_dep_insn_execbuf_thumb, tramp_len);
-               prep_pc_dep_insn_execbuf_thumb(tramp, insn, uregs);
-
-               addr = vaddr + 4;
-               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
-               *((u16 *)tramp + 14) = addr & 0x0000ffff;
-               *((u16 *)tramp + 15) = addr >> 16;
-               if (!is_thumb2(insn)) {
-                       addr = vaddr + 2;
-                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((u16 *)tramp + 17) = addr >> 16;
-               } else {
-                       addr = vaddr + 4;
-                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((u16 *)tramp + 17) = addr >> 16;
-               }
-       } else {
-               memcpy(tramp, gen_insn_execbuf_thumb, tramp_len);
-               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
-               if (!is_thumb2(insn)) {
-                       addr = vaddr + 2;
-                       *((u16 *)tramp + 2) = insn;
-                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((u16 *)tramp + 17) = addr >> 16;
-               } else {
-                       addr = vaddr + 4;
-                       tramp[1] = insn;
-                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((u16 *)tramp + 17) = addr >> 16;
-               }
-       }
-
-       if (THUMB_INSN_MATCH(B2, insn)) {
-               memcpy(tramp, b_off_insn_execbuf_thumb, tramp_len);
-               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
-               addr = branch_t16_dest(insn, vaddr);
-               *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
-               *((u16 *)tramp + 15) = addr >> 16;
-               *((u16 *)tramp + 16) = 0;
-               *((u16 *)tramp + 17) = 0;
-
-       } else if (THUMB_INSN_MATCH(B1, insn)) {
-               memcpy(tramp, b_cond_insn_execbuf_thumb, tramp_len);
-               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
-               *((u16 *)tramp + 0) |= (insn & 0xf00);
-               addr = branch_cond_t16_dest(insn, vaddr);
-               *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
-               *((u16 *)tramp + 15) = addr >> 16;
-               addr = vaddr + 2;
-               *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-               *((u16 *)tramp + 17) = addr >> 16;
-
-       } else if (THUMB_INSN_MATCH(BLX2, insn) ||
-                  THUMB_INSN_MATCH(BX, insn)) {
-               memcpy(tramp, b_r_insn_execbuf_thumb, tramp_len);
-               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
-               *((u16 *)tramp + 4) = insn;
-               addr = vaddr + 2;
-               *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-               *((u16 *)tramp + 17) = addr >> 16;
-
-       } else if (THUMB_INSN_MATCH(CBZ, insn)) {
-               memcpy(tramp, cbz_insn_execbuf_thumb, tramp_len);
-               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
-               /* zero out original branch displacement (imm5 = 0; i = 0) */
-               *((u16 *)tramp + 0) = insn & (~0x2f8);
-               /* replace it with 8 bytes offset in execbuf (imm5 = 0b00010) */
-               *((u16 *)tramp + 0) |= 0x20;
-               addr = cbz_t16_dest(insn, vaddr);
-               *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
-               *((u16 *)tramp + 15) = addr >> 16;
-               addr = vaddr + 2;
-               *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
-               *((u16 *)tramp + 17) = addr >> 16;
-       }
-
-       return 0;
-}
-
-int make_trampoline_thumb(struct arch_insn_arm *ainsn,
-                         u32 vaddr, u32 insn, u32 *tramp, size_t tramp_len)
-{
-       int ret;
-
-       ret = do_make_trampoline_thumb(vaddr, insn, tramp, tramp_len);
-       if (ret) {
-               struct decode_info info = {
-                       .vaddr = vaddr,
-                       .tramp = tramp,
-                       .handeler = NULL,
-               };
-
-               ret = decode_thumb(insn, &info);
-               if (info.handeler) {
-                       u16 *tr = (u16 *)tramp;
-                       tr[13] = RET_BREAK_THUMB; /* bp for uretprobe */
-                       ainsn->handler = info.handeler;
-               }
-       }
-
-       return ret;
-}
-
-int noret_thumb(u32 opcode)
-{
-       return !!(THUMB2_INSN_MATCH(BL, opcode) ||
-                 THUMB2_INSN_MATCH(BLX1, opcode) ||
-                 THUMB_INSN_MATCH(BLX2, opcode));
-}
diff --git a/arch/arm/probes/probes_thumb.h b/arch/arm/probes/probes_thumb.h
deleted file mode 100644 (file)
index 1b20094..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_PROBES_THUMB_H
-#define _SWAP_ASM_PROBES_THUMB_H
-
-
-int make_trampoline_thumb(struct arch_insn_arm *ainsn, u32 vaddr, u32 insn,
-                         u32 *tramp, size_t tramp_len);
-int noret_thumb(u32 opcode);
-
-
-#endif /* _SWAP_ASM_PROBES_THUMB_H */
diff --git a/arch/arm/probes/tramps_arm.c b/arch/arm/probes/tramps_arm.c
deleted file mode 100644 (file)
index 84d978d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-__asm(
-".text\n"
-".arm\n"
-".global gen_insn_execbuf\n"
-"gen_insn_execbuf:\n"
-"      nop\n"
-"      nop\n"
-"      nop\n"                  /* original instruction */
-"      nop\n"
-"      ldr     pc, [pc, #4]\n" /* ssbreak */
-"      nop\n"                  /* retbreak */
-"      nop\n"
-"      nop\n"                  /* stored PC-4(next insn addr) */
-
-".global pc_dep_insn_execbuf\n"
-"pc_dep_insn_execbuf:\n"
-"      str     r0, [sp, #-4]\n"
-"      ldr     r0, [pc, #12]\n"
-"      nop\n"                  /* instruction with replaced PC */
-"      ldr     r0, [sp, #-4]\n"
-"      ldr     pc, [pc, #4]\n" /* ssbreak */
-"      nop\n"                  /* retbreak */
-"      nop\n"                  /* stored PC */
-"      nop\n"                  /* stored PC-4 (next insn addr) */
-
-".global b_r_insn_execbuf\n"
-"b_r_insn_execbuf:\n"
-"      nop\n"                  /* bx, blx (Rm) */
-"      ldr     pc, np1\n"
-"      nop\n"
-"      nop\n"
-"      nop\n"
-"      nop\n"                  /* retbreak */
-"      nop\n"
-"np1:\n"
-"      nop\n"                  /* stored PC-4 (next insn addr) */
-
-".global b_cond_insn_execbuf\n"
-"b_cond_insn_execbuf:\n"
-"      beq     condway\n"
-"      ldr     pc, np2\n"
-"condway:\n"
-"      ldr     pc, bd2\n"
-"      nop\n"
-"      nop\n"
-"      nop\n"                  /* retbreak */
-"bd2:\n"
-"      nop\n"                  /* branch displacement */
-"np2:\n"
-"      nop\n"                  /* stored PC-4 (next insn addr) */
-
-".global blx_off_insn_execbuf\n"
-"blx_off_insn_execbuf:\n"
-"      ldreq   lr, bd3\n"
-"      blxeq   lr\n"
-"      ldr     pc, np3\n"
-"      nop\n"
-"      nop\n"
-"      nop\n"                  /* retbreak */
-"bd3:\n"
-"      nop\n"                  /* branch displacement */
-"np3:\n"
-"      nop\n"                  /* stored PC-4 (next insn addr) */
-);
diff --git a/arch/arm/probes/tramps_arm.h b/arch/arm/probes/tramps_arm.h
deleted file mode 100644 (file)
index 0fc5d72..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
- * Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- * redesign module for separating core and arch parts
- * @author Alexander Shirshikov <a.shirshikov@samsung.com>:
- * initial implementation for Thumb
- *
- * @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, 2006-2010
- *
- */
-
-#ifndef _SWAP_ASM_TRAMPS_ARM_H
-#define _SWAP_ASM_TRAMPS_ARM_H
-
-
-#include <linux/types.h>
-
-
-/*
- * These arrays generated from tramps_arm.c
- * using 32 bit compiler:
- *   $ gcc tramps_arm.c -c -o tramps_arm.o
- *   $ objdump -d tramps_arm.o
- */
-
-static u32 __attribute__((unused)) gen_insn_execbuf[] = {
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe59ff004,     //   ldr        pc, [pc, #4]
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-};
-
-static u32 __attribute__((unused)) pc_dep_insn_execbuf[] = {
-       0xe50d0004,     //   str        r0, [sp, #-4]
-       0xe59f000c,     //   ldr        r0, [pc, #12]
-       0xe320f000,     //   nop
-       0xe51d0004,     //   ldr        r0, [sp, #-4]
-       0xe59ff004,     //   ldr        pc, [pc, #4]
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-};
-
-static u32 __attribute__((unused)) b_r_insn_execbuf[] = {
-       0xe320f000,     //   nop
-       0xe59ff010,     //   ldr        pc, [pc, #16]
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-};
-
-static u32 __attribute__((unused)) b_cond_insn_execbuf[] = {
-       0x0a000000,     //   beq        68 <condway>
-       0xe59ff010,     //   ldr        pc, [pc, #16]
-       0xe59ff008,     //   ldr        pc, [pc, #8]
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-};
-
-static u32 __attribute__((unused)) blx_off_insn_execbuf[] = {
-       0x059fe010,     //   ldreq      lr, [pc, #16]
-       0x012fff3e,     //   blxeq      lr
-       0xe59ff00c,     //   ldr        pc, [pc, #12]
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-       0xe320f000,     //   nop
-};
-
-
-#endif /* _SWAP_ASM_TRAMPS_ARM_H */
diff --git a/arch/arm/probes/tramps_thumb.c b/arch/arm/probes/tramps_thumb.c
deleted file mode 100644 (file)
index c9ce11d..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-__asm(
-".text\n"
-".thumb\n"
-
-".global gen_insn_execbuf_thumb\n"
-"gen_insn_execbuf_thumb:\n"
-       "nop\n"
-       "nop\n"
-       "nop\n"                 /* original instruction */
-       "nop\n"                 /* original instruction */
-       "nop\n"
-       "nop\n"
-       "nop\n"
-       "sub    sp, sp, #8\n"
-       "str    r0, [sp, #0]\n"
-       "ldr    r0, [pc, #12]\n"
-       "str    r0, [sp, #4]\n"
-       "nop\n"
-       "pop    {r0, pc}\n"     /* ssbreak */
-       "nop\n"                 /* retbreak */
-       "nop\n"
-       "nop\n"
-       "nop\n"                 /* stored PC-4(next insn addr) hi */
-       "nop\n"                 /* stored PC-4(next insn addr) lo */
-
-       "nop\n"
-
-".global pc_dep_insn_execbuf_thumb\n"
-".align 4\n"
-"pc_dep_insn_execbuf_thumb:\n"
-       "push   {r6, r7}\n"
-       "ldr    r6, i1\n"
-       "mov    r7, sp\n"
-       "mov    sp, r6\n"
-       "nop\n"                 /* PC -> SP */
-       "nop\n"                 /* PC -> SP */
-       "mov    sp, r7\n"
-       "pop    {r6, r7}\n"
-       "push   {r0, r1}\n"
-       "ldr    r0, i2\n"
-       "nop\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0, pc}\n"     /* ssbreak */
-       "nop\n"                 /* retbreak */
-"i1:\n"
-       "nop\n"                 /* stored PC hi */
-       "nop\n"                 /* stored PC lo */
-"i2:\n"
-       "nop\n"                 /* stored PC-4(next insn addr) hi */
-       "nop\n"                 /* stored PC-4(next insn addr) lo */
-
-".global b_r_insn_execbuf_thumb\n"
-".align 4\n"
-"b_r_insn_execbuf_thumb:\n"
-       "nop\n"
-       "nop\n"
-       "nop\n"
-       "nop\n"
-       "nop\n"                 /* bx,blx (Rm) */
-       "nop\n"
-       "push   {r0,r1}\n"
-       "ldr    r0, np\n"
-       "nop\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0,pc}\n"
-       "nop\n"
-       "nop\n"                 /* ssbreak */
-       "nop\n"                 /* retbreak */
-       "nop\n"
-       "nop\n"
-"np:\n"
-       "nop\n"                 /* stored PC-4(next insn addr) hi */
-       "nop\n"                 /* stored PC-4(next insn addr) lo */
-
-".global b_off_insn_execbuf_thumb\n"
-".align 4\n"
-"b_off_insn_execbuf_thumb:\n"
-       "push   {r0,r1}\n"
-       "ldr    r0, bd\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0, pc}\n"
-       "nop\n"
-       "nop\n"
-       "push   {r0,r1}\n"
-       "ldr    r0, np2\n"
-       "nop\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0,pc}\n"
-       "nop\n"
-       "nop\n"                 /* ssbreak */
-       "nop\n"                 /* retbreak */
-"bd:\n"
-       "nop\n"                 /* branch displacement hi */
-       "nop\n"                 /* branch displacement lo */
-"np2:\n"
-       "nop\n"                 /* stored PC-4(next insn addr) hi */
-       "nop\n"                 /* stored PC-4(next insn addr) lo */
-
-".global b_cond_insn_execbuf_thumb\n"
-".align 4\n"
-"b_cond_insn_execbuf_thumb:\n"
-       "beq    condway\n"
-       "push   {r0,r1}\n"
-       "ldr    r0, np4\n"
-       "nop\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0,pc}\n"
-"condway:\n"
-       "push   {r0,r1}\n"
-       "ldr    r0, bd4\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0,pc}\n"
-       "nop\n"
-       "nop\n"
-       "nop\n"                 /* ssbreak */
-       "nop\n"                 /* retbreak */
-"bd4:\n"
-       "nop\n"                 /* branch displacement hi */
-       "nop\n"                 /* branch displacement lo */
-"np4:\n"
-       "nop\n"                 /* stored PC-4(next insn addr) hi */
-       "nop\n"                 /* stored PC-4(next insn addr) lo */
-
-".global cbz_insn_execbuf_thumb\n"
-".align 4\n"
-"cbz_insn_execbuf_thumb:\n"
-       "nop\n"                 /* cbz */
-       "push   {r0,r1}\n"
-       "ldr    r0, np5\n"
-       "nop\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0,pc}\n"
-       "push   {r0,r1}\n"
-       "ldr    r0, bd5\n"
-       "str    r0, [sp, #4]\n"
-       "pop    {r0,pc}\n"
-       "nop\n"
-       "nop\n"
-       "nop\n"                 /* ssbreak */
-       "nop\n"                 /* retbreak */
-"bd5:\n"
-       "nop\n"                 /* branch displacement hi */
-       "nop\n"                 /* branch displacement lo */
-"np5:\n"
-       "nop\n"                 /* stored PC-4(next insn addr) hi */
-       "nop\n"                 /* stored PC-4(next insn addr) lo */
-);
diff --git a/arch/arm/probes/tramps_thumb.h b/arch/arm/probes/tramps_thumb.h
deleted file mode 100644 (file)
index eb34275..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- */
-
-
-#ifndef _SWAP_ASM_TRAMPS_THUMB_H
-#define _SWAP_ASM_TRAMPS_THUMB_H
-
-
-#include <linux/types.h>
-
-
-/*
- * These arrays generated from tramps_thumb.c
- * using 32 bit compiler:
- *   $ gcc tramps_thumb.c -c -o tramps_thumb.o
- *   $ objdump -d tramps_thumb.o
- */
-
-static u16 __attribute__((unused)) gen_insn_execbuf_thumb[] = {
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xb082,         //   sub        sp, #8
-       0x9000,         //   str        r0, [sp, #0]
-       0x4803,         //   ldr        r0, [pc, #12]
-       0x9001,         //   str        r0, [sp, #4]
-       0xbf00,         //   nop
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-};
-
-static u16 __attribute__((unused)) pc_dep_insn_execbuf_thumb[] = {
-       0xb4c0,         //   push       {r6, r7}
-       0x4e06,         //   ldr        r6, [pc, #24]
-       0x466f,         //   mov        r7, sp
-       0x46b5,         //   mov        sp, r6
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0x46bd,         //   mov        sp, r7
-       0xbcc0,         //   pop        {r6, r7}
-       0xb403,         //   push       {r0, r1}
-       0x4803,         //   ldr        r0, [pc, #12]
-       0xbf00,         //   nop
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-};
-
-static u16 __attribute__((unused)) b_r_insn_execbuf_thumb[] = {
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xb403,         //   push       {r0, r1}
-       0x4804,         //   ldr        r0, [pc, #16]
-       0xbf00,         //   nop
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-};
-
-static u16 __attribute__((unused)) b_off_insn_execbuf_thumb[] = {
-       0xb403,         //   push       {r0, r1}
-       0x4806,         //   ldr        r0, [pc, #24]
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xb403,         //   push       {r0, r1}
-       0x4804,         //   ldr        r0, [pc, #16]
-       0xbf00,         //   nop
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-};
-
-static u16 __attribute__((unused)) b_cond_insn_execbuf_thumb[] = {
-       0xf000, 0x8005, //   beq.w      ce <condway>
-       0xb403,         //   push       {r0, r1}
-       0x4807,         //   ldr        r0, [pc, #28]
-       0xbf00,         //   nop
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xb403,         //   push       {r0, r1}
-       0xf8df, 0x000c, //   ldr.w      r0, [pc, #12]
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-};
-
-static u16 __attribute__((unused)) cbz_insn_execbuf_thumb[] = {
-       0xbf00,         //   nop
-       0xb403,         //   push       {r0, r1}
-       0x4806,         //   ldr        r0, [pc, #24]
-       0xbf00,         //   nop
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xb403,         //   push       {r0, r1}
-       0x4803,         //   ldr        r0, [pc, #12]
-       0x9001,         //   str        r0, [sp, #4]
-       0xbd01,         //   pop        {r0, pc}
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-       0xbf00,         //   nop
-};
-
-
-#endif /* _SWAP_ASM_TRAMPS_THUMB_H */
diff --git a/arch/arm/uprobe/swap_uprobe.c b/arch/arm/uprobe/swap_uprobe.c
deleted file mode 100644 (file)
index c7b2d0f..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-
-#include <arch/arm/probes/probes.h>
-#include <arch/arm/probes/probes_arm.h>
-#include <arch/arm/probes/probes_thumb.h>
-#include <uprobe/swap_uprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <kprobe/swap_slots.h>
-#include "../probes/compat_arm64.h"
-
-
-#define PTR_TO_U32(x)  ((u32)(unsigned long)(x))
-#define U32_TO_PTR(x)  ((void *)(unsigned long)(x))
-
-#define flush_insns(addr, size) \
-               flush_icache_range((unsigned long)(addr), \
-                                  (unsigned long)(addr) + (size))
-
-
-/**
- * @brief Prepares uprobe for ARM.
- *
- * @param up Pointer to the uprobe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_prepare_uprobe_arm(struct uprobe *p)
-{
-       int ret;
-       struct task_struct *task = p->task;
-       unsigned long vaddr = (unsigned long)p->addr;
-       u32 insn;
-       u32 tramp[UPROBES_TRAMP_LEN];
-       u32 __user *utramp;
-       enum { tramp_len = sizeof(tramp) };
-
-       if (!read_proc_vm_atomic(task, vaddr & ~1, &insn, sizeof(insn))) {
-               printk(KERN_ERR "failed to read memory %lx!\n", vaddr);
-               return -EINVAL;
-       }
-
-       ret = make_tramp(&p->ainsn.insn, vaddr, insn, tramp, tramp_len);
-       if (ret) {
-               pr_err("failed to make tramp, addr=%p\n", p->addr);
-               return ret;
-       }
-
-       utramp = swap_slot_alloc(p->sm);
-       if (utramp == NULL) {
-               printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
-                      vaddr);
-               return -ENOMEM;
-       }
-
-       if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
-                                 tramp_len)) {
-               pr_err("failed to write memory tramp=%p!\n", utramp);
-               swap_slot_free(p->sm, utramp);
-               return -EINVAL;
-       }
-
-       flush_insns(utramp, tramp_len);
-       p->insn = utramp;
-       p->opcode = insn;
-
-       return 0;
-}
-
-int arch_arm_uprobe_arm(struct uprobe *p)
-{
-       int ret;
-       unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
-       int thumb_mode = (unsigned long)p->addr & 1;
-       int len = 4 >> thumb_mode;      /* if thumb_mode then len = 2 */
-       unsigned long insn = thumb_mode ? BREAK_THUMB : BREAK_ARM;
-
-       ret = write_proc_vm_atomic(p->task, vaddr, &insn, len);
-       if (!ret) {
-               pr_err("failed to write memory tgid=%u addr=%08lx len=%d\n",
-                      p->task->tgid, vaddr, len);
-
-               return -EACCES;
-       } else {
-               flush_insns(vaddr, len);
-       }
-
-       return 0;
-}
-
-void arch_disarm_uprobe_arm(struct uprobe *p, struct task_struct *task)
-{
-       int ret;
-
-       unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
-       int thumb_mode = (unsigned long)p->addr & 1;
-       int len = 4 >> thumb_mode;      /* if thumb_mode then len = 2 */
-
-       ret = write_proc_vm_atomic(task, vaddr, &p->opcode, len);
-       if (!ret) {
-               pr_err("Failed to write memory tgid=%u addr=%08lx len=%d\n",
-                      task->tgid, vaddr, len);
-       } else {
-               flush_insns(vaddr, len);
-       }
-}
-
-/**
- * @brief Prepates uretprobe for ARM.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param regs Pointer to CPU register data.
- * @return Error code.
- */
-int prepare_uretprobe_arm(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       unsigned long thumb, bp_offset;
-
-       thumb = ri->preload.use ? ri->preload.thumb : thumb_mode(regs);
-       bp_offset = thumb ? 0x1b : 4 * PROBES_TRAMP_RET_BREAK_IDX;
-
-       /* save original return address */
-       ri->ret_addr = (uprobe_opcode_t *)regs->ARM_lr;
-
-       /* replace return address with break point adddress */
-       regs->ARM_lr = (unsigned long)(ri->rp->up.insn) + bp_offset;
-
-       /* save stack pointer address */
-       ri->sp = (uprobe_opcode_t *)regs->ARM_sp;
-
-       /* Set flag of current mode */
-       ri->sp = (uprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
-
-       return 0;
-}
-
-/**
- * @brief Restores return address.
- *
- * @param orig_ret_addr Original return address.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-void set_orig_ret_addr_arm(unsigned long orig_ret_addr, struct pt_regs *regs)
-{
-       regs->ARM_lr = orig_ret_addr;
-       regs->ARM_pc = orig_ret_addr & ~0x1;
-
-       if (regs->ARM_lr & 0x1)
-               regs->ARM_cpsr |= PSR_T_BIT;
-       else
-               regs->ARM_cpsr &= ~PSR_T_BIT;
-}
-
-void arch_opcode_analysis_uretprobe_arm(struct uretprobe *rp)
-{
-       /* Remove retprobe if first insn overwrites lr */
-       rp->thumb_noret = noret_thumb(rp->up.opcode);
-       rp->arm_noret = noret_arm(rp->up.opcode);
-}
-
-unsigned long arch_get_trampoline_addr_arm(struct uprobe *p,
-                                          struct pt_regs *regs)
-{
-       return thumb_mode(regs) ?
-                       PTR_TO_U32(p->insn) + 0x1b :
-                       PTR_TO_U32(p->insn +
-                                  PROBES_TRAMP_RET_BREAK_IDX);
-}
-
-unsigned long arch_tramp_by_ri_arm(struct uretprobe_instance *ri)
-{
-       /* Understand function mode */
-       return (PTR_TO_U32(ri->sp) & 1) ?
-                       PTR_TO_U32(ri->rp->up.insn) + 0x1b :
-                       PTR_TO_U32(ri->rp->up.insn +
-                                  PROBES_TRAMP_RET_BREAK_IDX);
-}
-
-int arch_disarm_urp_inst_arm(struct uretprobe_instance *ri,
-                            struct task_struct *task)
-{
-       struct pt_regs *uregs = task_pt_regs(ri->task);
-       u32 ra = uregs->ARM_lr;
-       u32 vaddr, tramp, found = 0;
-       u32 sp = PTR_TO_U32(ri->sp) & ~1;
-       u32 ret_addr = PTR_TO_U32(ri->ret_addr);
-       u32 stack = sp - 4 * (URETPROBE_STACK_DEPTH + 1);
-       u32 buf[URETPROBE_STACK_DEPTH];
-       int i, ret;
-
-       vaddr = PTR_TO_U32(ri->rp->up.addr);
-       tramp = arch_tramp_by_ri_arm(ri);
-
-       /* check stack */
-       ret = read_proc_vm_atomic(task, stack, buf, sizeof(buf));
-       if (ret != sizeof(buf)) {
-               pr_info("---> %s (%d/%d): failed to read stack from %08x\n",
-                       task->comm, task->tgid, task->pid, stack);
-               ret = -EFAULT;
-               goto check_lr;
-       }
-
-       /* search the stack from the bottom */
-       for (i = URETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
-               if (buf[i] == tramp) {
-                       found = stack + 4 * i;
-                       break;
-               }
-       }
-
-       if (!found) {
-               ret = -ESRCH;
-               goto check_lr;
-       }
-
-       pr_info("---> %s (%d/%d): trampoline found at "
-               "%08x (%08x /%+d) - %x, set ret_addr=%08x\n",
-               task->comm, task->tgid, task->pid,
-               found, sp,
-               found - sp, vaddr, ret_addr);
-       ret = write_proc_vm_atomic(task, found, &ret_addr, 4);
-       if (ret != 4) {
-               pr_info("---> %s (%d/%d): failed to write value to %08x",
-                       task->comm, task->tgid, task->pid, found);
-               ret = -EFAULT;
-       } else {
-               ret = 0;
-       }
-
-check_lr: /* check lr anyway */
-       if (ra == tramp) {
-               pr_info("---> %s (%d/%d): trampoline found at "
-                       "lr = %08x - %x, set ret_addr=%08x\n",
-                       task->comm, task->tgid, task->pid, ra, vaddr,
-                       ret_addr);
-
-               /* set ret_addr */
-               uregs->ARM_lr = ret_addr;
-               ret = 0;
-       } else if (ret) {
-               pr_info("---> %s (%d/%d): trampoline NOT found at "
-                       "sp=%08x, lr=%08x - %x, ret_addr=%08x\n",
-                       task->comm, task->tgid, task->pid,
-                       sp, ra, vaddr, ret_addr);
-       }
-
-       return ret;
-}
diff --git a/arch/arm/uprobe/swap_uprobe.h b/arch/arm/uprobe/swap_uprobe.h
deleted file mode 100644 (file)
index 19c84f1..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_ARM_UPROBE_H
-#define _SWAP_ASM_ARM_UPROBE_H
-
-
-#include <linux/printk.h>
-#include <linux/uaccess.h>
-#include "../probes/compat_arm64.h"
-
-
-struct pt_regs;
-struct uprobe;
-struct uretprobe;
-struct uretprobe_instance;
-
-
-static inline unsigned long swap_get_upc_arm(struct pt_regs *regs)
-{
-       return regs->ARM_pc | !!thumb_mode(regs);
-}
-
-static inline void swap_set_upc_arm(struct pt_regs *regs, unsigned long val)
-{
-       if (val & 1) {
-               regs->ARM_pc = val & ~1UL;
-               regs->ARM_cpsr |= PSR_T_BIT;
-       } else {
-               regs->ARM_pc = val;
-               regs->ARM_cpsr &= ~PSR_T_BIT;
-       }
-}
-
-static inline unsigned long swap_get_uarg_arm(struct pt_regs *regs,
-                                             unsigned long n)
-{
-       u32 *ptr, val = 0;
-
-       switch (n) {
-       case 0:
-               return regs->ARM_r0;
-       case 1:
-               return regs->ARM_r1;
-       case 2:
-               return regs->ARM_r2;
-       case 3:
-               return regs->ARM_r3;
-       default:
-               ptr = (u32 *)regs->ARM_sp + n - 4;
-               if (get_user(val, ptr))
-                       pr_err("Failed to dereference a pointer[%p]\n", ptr);
-               break;
-       }
-
-       return val;
-}
-
-static inline void swap_put_uarg_arm(struct pt_regs *regs, unsigned long n,
-                                    unsigned long val)
-{
-       u32 *ptr;
-
-       switch (n) {
-       case 0:
-               regs->ARM_r0 = val;
-               break;
-       case 1:
-               regs->ARM_r1 = val;
-               break;
-       case 2:
-               regs->ARM_r2 = val;
-               break;
-       case 3:
-               regs->ARM_r3 = val;
-               break;
-       default:
-               ptr = (u32 *)regs->ARM_sp + n - 4;
-               if (put_user(val, ptr))
-                       pr_err("Failed to dereference a pointer[%p]\n", ptr);
-       }
-}
-
-static inline unsigned long swap_get_uret_addr_arm(struct pt_regs *regs)
-{
-       return regs->ARM_lr;
-}
-
-static inline void swap_set_uret_addr_arm(struct pt_regs *regs, unsigned long v)
-{
-       regs->ARM_lr = v;
-}
-
-int arch_prepare_uprobe_arm(struct uprobe *p);
-int arch_arm_uprobe_arm(struct uprobe *p);
-void arch_disarm_uprobe_arm(struct uprobe *p, struct task_struct *task);
-
-int prepare_uretprobe_arm(struct uretprobe_instance *ri, struct pt_regs *regs);
-void set_orig_ret_addr_arm(unsigned long orig_ret_addr, struct pt_regs *regs);
-void arch_opcode_analysis_uretprobe_arm(struct uretprobe *rp);
-unsigned long arch_get_trampoline_addr_arm(struct uprobe *p,
-                                          struct pt_regs *regs);
-unsigned long arch_tramp_by_ri_arm(struct uretprobe_instance *ri);
-int arch_disarm_urp_inst_arm(struct uretprobe_instance *ri,
-                            struct task_struct *task);
-
-
-#endif /* _SWAP_ASM_ARM_UPROBE_H */
-
diff --git a/buffer/Kbuild b/buffer/Kbuild
deleted file mode 100644 (file)
index 98872bf..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_buffer.o
-swap_buffer-y := swap_buffer_module.o \
-                 buffer_queue.o
-
diff --git a/buffer/buffer_description.h b/buffer/buffer_description.h
deleted file mode 100644 (file)
index 353e33a..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * @file buffer/buffer_description.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * swap_subbuffer structure represents one buffers subbufer
- */
-
-#ifndef __BUFFER_DESCRIPTION_H__
-#define __BUFFER_DESCRIPTION_H__
-
-#include "data_types.h"
-
-/**
- * @struct swap_subbuffer
- * @brief This structures are combined in array which represents the SWAP buffer.
- * @var swap_subbuffer::next_in_queue
- * Pointer to the next swap_subbufer in queue
- * @var swap_subbuffer::full_buffer_part
- * Currently occupied subbuffers size
- * @var swap_subbuffer::data_buffer
- * Pointer to subbuffers data itself of type swap_subbuffer_ptr
- * @var swap_subbuffer::buffer_sync
- * Subbuffers sync primitive
- */
-struct swap_subbuffer {
-       /* Pointer to the next subbuffer in queue */
-       struct swap_subbuffer *next_in_queue;
-       /* Size of the filled part of a subbuffer */
-       size_t full_buffer_part;
-       /* Pointer to data buffer */
-       swap_subbuffer_ptr data_buffer;
-       /* Buffer rw sync */
-       struct sync_t buffer_sync;
-};
-
-#endif /* __BUFFER_DESCRIPTION_H__ */
diff --git a/buffer/buffer_queue.c b/buffer/buffer_queue.c
deleted file mode 100644 (file)
index 803e930..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-/**
- * buffer/buffer_queue.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
- *
- * @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
- *
- * Implements buffers queues interface
- */
-
-/* For all memory allocation/deallocation operations, except buffer memory
- * allocation/deallocation should be used
- *  memory_allocation(size_t memory_size)
- *  memory_free(void *ptr)
- * defines.
- * For subbuffer allocation/deallocation operations should be used
- *  buffer_allocation(size_t subbuffer_size)
- *  buffer_free(void *ptr, size_t subbuffer_size)
- * To get buffer pointer for any usage, EXCEPT ALLOCATION AND DEALLOCATION
- * use the following define:
- *  buffer_pointer(void *ptr_to_buffer_element_of_swap_buffer_structure)
- * DO NOT USE SUBBUFFER PTR IN STRUCT SWAP_BUFFER WITHOUT THIS DEFINE!
- * It will be ok for user space, but fail in kernel space.
- *
- * See space_dep_types_and_def.h for details */
-
-
-
-#include "buffer_queue.h"
-#include "swap_buffer_to_buffer_queue.h"
-#include "swap_buffer_errors.h"
-#include "kernel_operations.h"
-
-/**
- * @struct queue_t
- * @brief Queue structure. Consist of pointers to the first and the last
- * elements of queue.
- * @var queue_t::start_ptr
- * Pointer to the first subbuffer in queue
- * @var queue_t::end_ptr
- * Pointer to the last subbuffer in queue
- * @var queue_t::subbuffers_count
- * Subbuffers count in queue
- * @var queue_t::queue_sync
- * Queue access sync primitive
- */
-struct queue_t {
-       struct swap_subbuffer *start_ptr;
-       struct swap_subbuffer *end_ptr;
-       unsigned int subbuffers_count;
-       struct sync_t queue_sync;
-};
-
-/**
- * @var write_queue
- * @brief Represents write queue.
- */
-struct queue_t write_queue = {
-       .start_ptr = NULL,
-       .end_ptr = NULL,
-       .subbuffers_count = 0,
-       .queue_sync = {
-               .flags = 0x0
-       }
-};
-
-/**
- * @var read_queue
- * @brief Represents read queue.
- */
-struct queue_t read_queue = {
-       .start_ptr = NULL,
-       .end_ptr = NULL,
-       .subbuffers_count = 0,
-       .queue_sync = {
-               .flags = 0x0
-       }
-};
-
-/* Pointers array. Points to busy buffers */
-static struct swap_subbuffer **queue_busy;
-
-/* Store last busy element */
-static unsigned int queue_busy_last_element;
-
-/* Subbuffers count */
-static unsigned int queue_subbuffer_count;
-
-/* One subbuffer size */
-static size_t queue_subbuffer_size;
-
-/* Busy list sync */
-static struct sync_t buffer_busy_sync = {
-       .flags = 0x0
-};
-
-/* Memory pages count in one subbuffer */
-static int pages_order_in_subbuffer;
-
-/**
- * @brief Allocates memory for swap_subbuffer structures and subbuffers.
- * Total allocated memory = subbuffer_size * subbuffers_count.
- *
- * @param subbuffer_size Size of each subbuffer.
- * @param subbuffers_count Count of subbuffers.
- * @return 0 on success, negative error code otherwise.
- */
-int buffer_queue_allocation(size_t subbuffer_size,
-                           unsigned int subbuffers_count)
-{
-       unsigned int i = 0;
-       unsigned int j = 0;
-       unsigned int allocated_buffers = 0;
-       unsigned int allocated_structs = 0;
-       struct swap_subbuffer *clean_tmp_struct;
-       int result;
-
-       /* Static varibles initialization */
-       queue_subbuffer_size = subbuffer_size;
-       queue_subbuffer_count = subbuffers_count;
-       queue_busy_last_element = 0;
-
-       /* Set variable pages_in_subbuffer. It is used for allocation and
-        * deallocation memory pages and its value is returned from
-        * swap_buffer_get() and contains page count in one subbuffer.
-        * All this useful only in kernel space. In userspace it is dummy.*/
-       set_pages_order_in_subbuffer(queue_subbuffer_size);
-       /* Sync primitives initialization */
-       sync_init(&read_queue.queue_sync);
-       sync_init(&write_queue.queue_sync);
-       sync_init(&buffer_busy_sync);
-
-       /* Memory allocation for queue_busy */
-       queue_busy =
-               memory_allocation(sizeof(*queue_busy) * queue_subbuffer_count);
-
-       if (!queue_busy) {
-               result = -E_SB_NO_MEM_QUEUE_BUSY;
-               goto buffer_allocation_error_ret;
-       }
-
-       /* Memory allocation for swap_subbuffer structures */
-
-       /* Allocation for first structure. */
-       write_queue.start_ptr =
-               memory_allocation(sizeof(*write_queue.start_ptr));
-
-       if (!write_queue.start_ptr) {
-               result = -E_SB_NO_MEM_BUFFER_STRUCT;
-               goto buffer_allocation_queue_busy_free;
-       }
-       allocated_structs++;
-
-
-       write_queue.end_ptr = write_queue.start_ptr;
-
-       write_queue.end_ptr->next_in_queue = NULL;
-       write_queue.end_ptr->full_buffer_part = 0;
-       write_queue.end_ptr->data_buffer =
-               buffer_allocation(queue_subbuffer_size);
-       if (!write_queue.end_ptr->data_buffer) {
-               print_err("Cannot allocate memory for buffer 1\n");
-               result = -E_SB_NO_MEM_DATA_BUFFER;
-               goto buffer_allocation_error_free;
-       }
-       allocated_buffers++;
-
-       sync_init(&write_queue.end_ptr->buffer_sync);
-
-       /* Buffer initialization */
-       memset(buffer_address(write_queue.end_ptr->data_buffer), 0,
-              queue_subbuffer_size);
-
-       /* Allocation for other structures. */
-       for (i = 1; i < queue_subbuffer_count; i++) {
-               write_queue.end_ptr->next_in_queue =
-                   memory_allocation(
-                           sizeof(*write_queue.end_ptr->next_in_queue));
-               if (!write_queue.end_ptr->next_in_queue) {
-                       result = -E_SB_NO_MEM_BUFFER_STRUCT;
-                       goto buffer_allocation_error_free;
-               }
-               allocated_structs++;
-
-               /* Now next write_queue.end_ptr is next */
-               write_queue.end_ptr = write_queue.end_ptr->next_in_queue;
-
-               write_queue.end_ptr->next_in_queue = NULL;
-               write_queue.end_ptr->full_buffer_part = 0;
-               write_queue.end_ptr->data_buffer =
-                       buffer_allocation(queue_subbuffer_size);
-               if (!write_queue.end_ptr->data_buffer) {
-                       result = -E_SB_NO_MEM_DATA_BUFFER;
-                       goto buffer_allocation_error_free;
-               }
-               allocated_buffers++;
-
-               sync_init(&write_queue.end_ptr->buffer_sync);
-
-               /* Buffer initialization */
-               memset(buffer_address(write_queue.end_ptr->data_buffer), 0,
-                      queue_subbuffer_size);
-       }
-
-       /* All subbuffers are in write list */
-       write_queue.subbuffers_count = subbuffers_count;
-
-       return E_SB_SUCCESS;
-
-       /* In case of errors, this code is called */
-       /* Free all previously allocated memory */
-buffer_allocation_error_free:
-       clean_tmp_struct = write_queue.start_ptr;
-
-       for (j = 0; j < allocated_structs; j++) {
-               clean_tmp_struct = write_queue.start_ptr;
-               if (allocated_buffers) {
-                       buffer_free(clean_tmp_struct->data_buffer,
-                                   queue_subbuffer_size);
-                       allocated_buffers--;
-               }
-               if (write_queue.start_ptr != write_queue.end_ptr)
-                       write_queue.start_ptr =
-                               write_queue.start_ptr->next_in_queue;
-               memory_free(clean_tmp_struct);
-       }
-       write_queue.end_ptr = NULL;
-       write_queue.start_ptr = NULL;
-
-buffer_allocation_queue_busy_free:
-       memory_free(queue_busy);
-       queue_busy = NULL;
-
-buffer_allocation_error_ret:
-       return result;
-}
-
-/**
- * @brief Resets all subbuffers for writing.
- *
- * @return 0 on success, negative error code otherwise.
- */
-int buffer_queue_reset(void)
-{
-       struct swap_subbuffer *buffer = read_queue.start_ptr;
-
-       /* Check if there are some subbuffers in busy list.
-        * If so - return error */
-       if (get_busy_buffers_count())
-               return -E_SB_UNRELEASED_BUFFERS;
-
-       /* Lock read sync primitive */
-       sync_lock(&read_queue.queue_sync);
-
-       /* Set all subbuffers in read list to write list
-        * and reinitialize them */
-       while (read_queue.start_ptr) {
-
-               /* Lock buffer sync primitive to prevent writing to buffer if it
-                * had been selected for writing, but still wasn't wrote. */
-               sync_lock(&buffer->buffer_sync);
-
-               buffer = read_queue.start_ptr;
-
-               /* If we reached end of the list */
-               if (read_queue.start_ptr == read_queue.end_ptr)
-                       read_queue.end_ptr = NULL;
-
-               read_queue.start_ptr = read_queue.start_ptr->next_in_queue;
-
-               /* Reinit full buffer part */
-               buffer->full_buffer_part = 0;
-
-               add_to_write_list(buffer);
-
-               /* Unlock buffer sync primitive */
-               sync_unlock(&buffer->buffer_sync);
-       }
-
-       /* Unlock read primitive */
-       sync_unlock(&read_queue.queue_sync);
-
-       return E_SB_SUCCESS;
-}
-
-/**
- * @brief Free all allocated subbuffers.
- *
- * @return Void.
- */
-void buffer_queue_free(void)
-{
-       struct swap_subbuffer *tmp = NULL;
-
-       /* Lock all sync primitives to prevet accessing free memory */
-       sync_lock(&write_queue.queue_sync);
-       sync_lock(&read_queue.queue_sync);
-       sync_lock(&buffer_busy_sync);
-
-       /* Free buffers and structures memory that are in read list */
-       while (read_queue.start_ptr) {
-               tmp = read_queue.start_ptr;
-               read_queue.start_ptr = read_queue.start_ptr->next_in_queue;
-               buffer_free(tmp->data_buffer, queue_subbuffer_size);
-               memory_free(tmp);
-       }
-
-       /* Free buffers and structures memory that are in read list */
-       while (write_queue.start_ptr) {
-               tmp = write_queue.start_ptr;
-               write_queue.start_ptr = write_queue.start_ptr->next_in_queue;
-               buffer_free(tmp->data_buffer, queue_subbuffer_size);
-               memory_free(tmp);
-       }
-
-       /* Free busy_list */
-       memory_free(queue_busy);
-       queue_busy = NULL;
-
-       queue_subbuffer_size = 0;
-       queue_subbuffer_count = 0;
-       read_queue.start_ptr = NULL;
-       read_queue.end_ptr = NULL;
-       write_queue.start_ptr = NULL;
-       write_queue.end_ptr = NULL;
-
-       /* Unlock all sync primitives */
-       sync_unlock(&buffer_busy_sync);
-       sync_unlock(&read_queue.queue_sync);
-       sync_unlock(&write_queue.queue_sync);
-}
-
-static unsigned int is_buffer_enough(struct swap_subbuffer *subbuffer,
-                                    size_t size)
-{
-       /* XXX Think about checking full_buffer_part for correctness
-        * (<queue_subbuffer_size). It should be true, but if isn't (due to
-        * sources chaning, etc.) this function should be true! */
-       return ((queue_subbuffer_size-subbuffer->full_buffer_part) >= size) ?
-               1 : 0;
-}
-
-static void next_queue_element(struct queue_t *queue)
-{
-       /* If we reached the last elemenet, end pointer should point to NULL */
-       if (queue->start_ptr == queue->end_ptr)
-               queue->end_ptr = NULL;
-
-       queue->start_ptr = queue->start_ptr->next_in_queue;
-       --queue->subbuffers_count;
-}
-
-/**
- * @brief Get first subbuffer from read list.
- *
- * @return Pointer to swap_subbuffer
- */
-struct swap_subbuffer *get_from_read_list(void)
-{
-       struct swap_subbuffer *result = NULL;
-
-       /* Lock read sync primitive */
-       sync_lock(&read_queue.queue_sync);
-
-       if (read_queue.start_ptr == NULL) {
-               result = NULL;
-               goto get_from_read_list_unlock;
-       }
-
-       result = read_queue.start_ptr;
-
-       next_queue_element(&read_queue);
-
-get_from_read_list_unlock:
-       /* Unlock read sync primitive */
-       sync_unlock(&read_queue.queue_sync);
-
-       return result;
-}
-
-/**
- * @brief Add subbuffer to read list.
- *
- * @param subbuffer Pointer to the subbuffer to add.
- * @return Void.
- */
-void add_to_read_list(struct swap_subbuffer *subbuffer)
-{
-       /* Lock read sync primitive */
-       sync_lock(&read_queue.queue_sync);
-
-       if (!read_queue.start_ptr)
-               read_queue.start_ptr = subbuffer;
-
-       if (read_queue.end_ptr) {
-               read_queue.end_ptr->next_in_queue = subbuffer;
-
-               read_queue.end_ptr = read_queue.end_ptr->next_in_queue;
-       } else {
-               read_queue.end_ptr = subbuffer;
-       }
-       read_queue.end_ptr->next_in_queue = NULL;
-       ++read_queue.subbuffers_count;
-
-       /* Unlock read sync primitive */
-       sync_unlock(&read_queue.queue_sync);
-}
-
-static int add_to_read_list_with_callback(struct swap_subbuffer *subbuffer,
-                                  bool wakeup)
-{
-       int result = 0;
-
-       add_to_read_list(subbuffer);
-       /* TODO Handle ret value */
-       result = swap_buffer_callback(subbuffer, wakeup);
-
-       return result;
-}
-
-/**
- * @brief Returns subbuffers to read count.
- *
- * @return Count of subbuffers in read_queue.
- */
-unsigned int get_readable_buf_cnt(void)
-{
-       return read_queue.subbuffers_count;
-}
-
-
-/**
- * @brief Get first writable subbuffer from write list.
- *
- * @param size Minimum amount of free space in subbuffer.
- * @param[out] ptr_to_write Pointer to the variable where pointer to the
- * beginning of memory for writing should be stored.
- * @return Found swap_subbuffer.
- */
-struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write,
-                                          bool wakeup)
-{
-       struct swap_subbuffer *result = NULL;
-
-       /* Callbacks are called at the end of the function
-        * to prevent deadlocks */
-       struct queue_t callback_queue = {
-               .start_ptr = NULL,
-               .end_ptr = NULL,
-               .queue_sync = {
-                       .flags = 0x0
-               }
-       };
-       struct swap_subbuffer *tmp_buffer = NULL;
-
-       /* Init pointer */
-       *ptr_to_write = NULL;
-
-       /* Lock write list sync primitive */
-       sync_lock(&write_queue.queue_sync);
-
-       while (write_queue.start_ptr) {
-
-               /* We're found subbuffer */
-               if (is_buffer_enough(write_queue.start_ptr, size)) {
-
-                       result = write_queue.start_ptr;
-                       *ptr_to_write =
-                               (void *)((unsigned long)
-                                        (buffer_address(result->data_buffer)) +
-                                        result->full_buffer_part);
-
-                       /* Add data size to full_buffer_part.
-                        * Very important to do it in
-                        * write_queue.queue_sync spinlock */
-                       write_queue.start_ptr->full_buffer_part += size;
-
-                       /* Lock rw sync.
-                        * Should be unlocked in swap_buffer_write() */
-                       sync_lock_no_flags(&result->buffer_sync);
-                       break;
-               /* This subbuffer is not enough => it goes to read list */
-               } else {
-                       result = write_queue.start_ptr;
-
-                       next_queue_element(&write_queue);
-
-                       /* Add to callback list */
-                       if (!callback_queue.start_ptr)
-                               callback_queue.start_ptr = result;
-
-                       if (callback_queue.end_ptr)
-                               callback_queue.end_ptr->next_in_queue = result;
-                       callback_queue.end_ptr = result;
-                       callback_queue.end_ptr->next_in_queue = NULL;
-                       result = NULL;
-               }
-       }
-
-       /* Unlock write list sync primitive */
-       sync_unlock(&write_queue.queue_sync);
-
-       /* Adding buffers to read list and calling callbacks */
-       for (tmp_buffer = NULL; callback_queue.start_ptr; ) {
-               if (callback_queue.start_ptr == callback_queue.end_ptr)
-                       callback_queue.end_ptr = NULL;
-
-               tmp_buffer = callback_queue.start_ptr;
-               callback_queue.start_ptr =
-                       callback_queue.start_ptr->next_in_queue;
-
-               add_to_read_list_with_callback(tmp_buffer, wakeup);
-       }
-
-       return result;
-}
-
-/**
- * @brief Add subbuffer to write list.
- *
- * @param subbuffer Pointer to the swap_subbuffer that should be stored.
- * @return Void.
- */
-void add_to_write_list(struct swap_subbuffer *subbuffer)
-{
-       sync_lock(&write_queue.queue_sync);
-
-       /* Reinitialize */
-       subbuffer->full_buffer_part = 0;
-
-       if (!write_queue.start_ptr)
-               write_queue.start_ptr = subbuffer;
-
-       if (write_queue.end_ptr) {
-               write_queue.end_ptr->next_in_queue = subbuffer;
-               write_queue.end_ptr = write_queue.end_ptr->next_in_queue;
-       } else {
-               write_queue.end_ptr = subbuffer;
-       }
-       write_queue.end_ptr->next_in_queue = NULL;
-       ++write_queue.subbuffers_count;
-
-       sync_unlock(&write_queue.queue_sync);
-}
-
-/**
- * @brief Returns subbuffers to write count.
- *
- * @return Count of subbuffers in write queue.
- */
-unsigned int get_writable_buf_cnt(void)
-{
-       return write_queue.subbuffers_count;
-}
-
-
-/**
- * @brief Add subbuffer to busy list when it is read from out of the buffer.
- *
- * @param subbuffer Pointer to the swap_subbuffer that should be added.
- * @return Void.
- */
-void add_to_busy_list(struct swap_subbuffer *subbuffer)
-{
-       /* Lock busy sync primitive */
-       sync_lock(&buffer_busy_sync);
-
-       subbuffer->next_in_queue = NULL;
-       queue_busy[queue_busy_last_element] = subbuffer;
-       queue_busy_last_element += 1;
-
-       /* Unlock busy sync primitive */
-       sync_unlock(&buffer_busy_sync);
-}
-
-/**
- * @brief Remove subbuffer from busy list when it is released.
- *
- * @param subbuffer Pointer to the swap_subbuffer that should be removed.
- * @return 0 on success, negative error code otherwise.
- */
-int remove_from_busy_list(struct swap_subbuffer *subbuffer)
-{
-       int result = -E_SB_NO_SUBBUFFER_IN_BUSY;  /* For sanitization */
-       int i;
-
-       /* Lock busy list sync primitive */
-       sync_lock(&buffer_busy_sync);
-
-       /* Sanitization and removing */
-       for (i = 0; i < queue_busy_last_element; i++) {
-               if (queue_busy[i] == subbuffer) {
-                       /* Last element goes here and length is down 1 */
-                       queue_busy[i] = queue_busy[queue_busy_last_element - 1];
-                       queue_busy_last_element -= 1;
-                       result = E_SB_SUCCESS;
-                       break;
-               }
-       }
-
-       /* Unlock busy list sync primitive */
-       sync_unlock(&buffer_busy_sync);
-
-       return result;
-}
-
-/**
- * @brief Set all subbuffers in write list to read list.
- *
- * @return Void.
- */
-void buffer_queue_flush(void)
-{
-       struct swap_subbuffer *buffer = write_queue.start_ptr;
-
-       /* Locking write sync primitive */
-       sync_lock(&write_queue.queue_sync);
-
-       while (write_queue.start_ptr &&
-              write_queue.start_ptr->full_buffer_part) {
-
-               /* Lock buffer sync primitive to prevent writing to buffer if it
-                * had been selected for writing, but still wasn't wrote. */
-               sync_lock(&buffer->buffer_sync);
-
-               buffer = write_queue.start_ptr;
-               next_queue_element(&write_queue);
-               add_to_read_list(buffer);
-
-               /* Unlock buffer sync primitive */
-               sync_unlock(&buffer->buffer_sync);
-       }
-
-       /* Unlock write primitive */
-       sync_unlock(&write_queue.queue_sync);
-}
-
-/**
- * @brief Get subbuffers count in busy list.
- *
- * @return Count of swap_subbuffers in busy  list.
- */
-int get_busy_buffers_count(void)
-{
-       int result;
-
-       sync_lock(&buffer_busy_sync);
-       result = queue_busy_last_element;
-       sync_unlock(&buffer_busy_sync);
-
-       return result;
-}
-
-/**
- * @brief Get memory pages count in subbuffer.
- *
- * @return Pages count in subbuffer.
- */
-int get_pages_count_in_subbuffer(void)
-{
-/* Return 1 if pages order 0,
- * or 2 of power pages_order_in_subbuffer otherwise */
-       return (pages_order_in_subbuffer) ?
-               2 << (pages_order_in_subbuffer - 1) : 1;
-}
diff --git a/buffer/buffer_queue.h b/buffer/buffer_queue.h
deleted file mode 100644 (file)
index 9b3291e..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * @file buffer/buffer_queue.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Represents buffers queues interface
- */
-
-/* SWAP Buffer queues interface */
-
-#ifndef __BUFFER_QUEUE_H__
-#define __BUFFER_QUEUE_H__
-
-#include <linux/types.h>
-#include "buffer_description.h"
-
-int buffer_queue_allocation(size_t subbuffer_size,
-                           unsigned int subbuffers_count);
-void buffer_queue_free(void);
-int buffer_queue_reset(void);
-void buffer_queue_flush(void);
-struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write,
-                                          bool wakeup);
-struct swap_subbuffer *get_from_read_list(void);
-void add_to_write_list(struct swap_subbuffer *subbuffer);
-void add_to_read_list(struct swap_subbuffer *subbuffer);
-void add_to_busy_list(struct swap_subbuffer *subbuffer);
-int remove_from_busy_list(struct swap_subbuffer *subbuffer);
-
-unsigned int get_readable_buf_cnt(void);
-unsigned int get_writable_buf_cnt(void);
-int get_busy_buffers_count(void);
-int get_pages_count_in_subbuffer(void);
-
-#endif /* __BUFFER_QUEUE_H__ */
diff --git a/buffer/data_types.h b/buffer/data_types.h
deleted file mode 100644 (file)
index 47ef1d8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file buffer/data_types.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Declares data types for SWAP buffer.
- */
-
-#ifndef __DATA_TYPES_H__
-#define __DATA_TYPES_H__
-
-
-#include <linux/spinlock.h>
-
-
-struct page;
-
-/**
- * @struct sync_t
- * @brief Using spinlocks as sync primitives.
- * @var sync_t::spinlock
- * Spinlock.
- * @var sync_t::flags
- * Flags for spinlock.
- */
-struct sync_t {
-       spinlock_t spinlock;
-       unsigned long flags;
-};
-
-/**
- * @brief swap_subbuffer_ptr points to the first memory page of the subbuffer.
- */
-typedef struct page *swap_subbuffer_ptr;
-
-#endif /* __DATA_TYPES_H__ */
diff --git a/buffer/kernel_operations.h b/buffer/kernel_operations.h
deleted file mode 100644 (file)
index 62aefb2..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * @file buffer/kernel_operations.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Kernel functions wrap.
- */
-
-#ifndef __KERNEL_OPERATIONS_H__
-#define __KERNEL_OPERATIONS_H__
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/semaphore.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/mm.h>
-
-#include "data_types.h"
-
-
-/* MESSAGES */
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
-       printk(KERN_DEBUG "SWAP_BUFFER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...)   \
-       printk(KERN_INFO "SWAP_BUFFER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...)  \
-       printk(KERN_WARNING "SWAP_BUFFER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...)   \
-       printk(KERN_ERR "SWAP_BUFFER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...)  \
-       printk(KERN_CRIT "SWAP_BUFFER CRITICAL : " msg, ##args)
-
-
-/**
- * @brief struct sync_t initialization.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_init(struct sync_t *buffer_sync)
-{
-       spin_lock_init(&buffer_sync->spinlock);
-}
-
-/**
- * @brief Lock sync_t with saving flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_lock(struct sync_t *buffer_sync)
-{
-       spin_lock_irqsave(&buffer_sync->spinlock, buffer_sync->flags);
-}
-
-/**
- * @brief Unlock sync_t with restoring flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_unlock(struct sync_t *buffer_sync)
-{
-       spin_unlock_irqrestore(&buffer_sync->spinlock, buffer_sync->flags);
-}
-
-/**
- * @brief Lock sync_t without saving flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_lock_no_flags(struct sync_t *buffer_sync)
-{
-       spin_lock(&buffer_sync->spinlock);
-}
-
-/**
- * @brief Unlock sync_t without restoring flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_unlock_no_flags(struct sync_t *buffer_sync)
-{
-       spin_unlock(&buffer_sync->spinlock);
-}
-
-/**
- * @brief Disable preemption and irqs.
- *
- * @param flags Variable to save flags to.
- * @return Void.
- */
-static inline void swap_irq_disable(unsigned long *flags)
-{
-       preempt_disable();
-       local_irq_save(*flags);
-}
-
-/**
- * @brief Enable preemption and irqs.
- *
- * @param flags Variable to restore flags from.
- * @return Void.
- */
-static inline void swap_irq_enable(unsigned long *flags)
-{
-       local_irq_restore(*flags);
-       preempt_enable();
-}
-
-/* SWAP SUBBUFER */
-
-
-/* We alloc memory for swap_subbuffer structures with common kmalloc */
-/** Allocates memory for subbuffer structures.*/
-#define memory_allocation(memory_size)  kmalloc(memory_size, GFP_KERNEL)
-/** Free subbuffer structures memory.*/
-#define memory_free(ptr)                kfree(ptr)
-
-/** For subbuffers themselves, we allocate memory with alloc_pages, so, we have
- * to evaluate required pages order */
-#define buffer_allocation(memory_size)                        \
-       alloc_pages(GFP_KERNEL, (pages_order_in_subbuffer >= 0) ? \
-               pages_order_in_subbuffer :                            \
-               get_order_for_alloc_pages(memory_size))
-
-/** Free buffer's memory.*/
-#define buffer_free(ptr, subbuf_size)                         \
-       __free_pages(ptr, (pages_order_in_subbuffer >= 0) ?       \
-                pages_order_in_subbuffer :                           \
-                get_order_for_alloc_pages(subbuf_size))
-
-/** Returns buffer address.*/
-#define buffer_address(buffer_ptr)  page_address(buffer_ptr)
-/** Sets page order in subbuffer.*/
-#define set_pages_order_in_subbuffer(memory_size) \
-       pages_order_in_subbuffer = get_order_for_alloc_pages(memory_size)
-
-/**
- * @brief Functions for pages allocation.
- *
- * @param number Target number.
- * @return Power of two.
- */
-static inline unsigned int nearest_power_of_two(unsigned int number)
-{
-       unsigned int result = 0;
-       unsigned int two_to_the_power = 1;
-
-       /* If aligned_size == PAGE_SIZE we need only one page, so return 0 */
-       if (number == 1)
-               return result;
-
-       while (two_to_the_power < number) {
-               two_to_the_power <<= 1;
-               result++;
-       }
-
-       return result;
-}
-
-/**
- * @brief Order for alloc pages.
- *
- * @param memory_size Wishful memory size.
- * @return Pages order.
- */
-static inline unsigned int get_order_for_alloc_pages(size_t memory_size)
-{
-       /* First evaluate remainder of the division memory_size by PAGE_SIZE.
-        * If memory_size is divisible by PAGE_SIZE, then remainder equals 0. */
-       size_t remainder = (memory_size % PAGE_SIZE) ?
-                      (memory_size % PAGE_SIZE) : PAGE_SIZE;
-
-       /* Align memory_size to the PAGE_SIZE. aligned_size >= memory_size */
-       size_t aligned_size = memory_size + (PAGE_SIZE - remainder);
-
-       return nearest_power_of_two(aligned_size / PAGE_SIZE);
-}
-
-#endif /* __KERNEL_OPERATIONS_H__ */
diff --git a/buffer/swap_buffer_errors.h b/buffer/swap_buffer_errors.h
deleted file mode 100644 (file)
index f153214..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file buffer/swap_buffer_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * SWAP Buffer error codes enumeration.
- */
-
-#ifndef __SWAP_BUFFER_ERRORS_H__
-#define __SWAP_BUFFER_ERRORS_H__
-
-/**
- * @enum _swap_buffer_errors
- * @brief SWAP buffer errors enumeration.
- */
-enum _swap_buffer_errors {
-       /**
-        * @brief Success.
-        */
-       E_SB_SUCCESS = 0,
-       /**
-        * @brief There are some unreleased buffers.
-        * Mainly returned by swap_buffer_uninit.
-        */
-       E_SB_UNRELEASED_BUFFERS = 1,
-       /**
-        * @brief No buffers for writing.
-        */
-       E_SB_NO_WRITABLE_BUFFERS = 2,
-       /**
-        * @brief Wrong data size: size == 0 or size > subbuffer size.
-        */
-       E_SB_WRONG_DATA_SIZE = 3,
-       /**
-        * @brief Trying to write data after SWAP buffer has been stopped.
-        */
-       E_SB_IS_STOPPED = 4,
-       /**
-        * @brief Memory areas of data to be written and subbuffer itself
-        * are overlap.
-        */
-       E_SB_OVERLAP = 5,
-       /**
-        * @brief No buffers for reading.
-        */
-       E_SB_NO_READABLE_BUFFERS = 6,
-       /**
-        * @brief Callback function ptr == NULL.
-        */
-       E_SB_NO_CALLBACK = 7,
-       /**
-        * @brief Memory for queue_busy wasn't allocated.
-        */
-       E_SB_NO_MEM_QUEUE_BUSY = 8,
-       /**
-        * @brief Memory for one of struct swap_buffer wasn't allocated.
-        */
-       E_SB_NO_MEM_BUFFER_STRUCT = 9,
-       /**
-        * @brief Memort for data buffer itself wasn't allocated.
-        */
-       E_SB_NO_MEM_DATA_BUFFER = 10,
-       /**
-        * @brief No such subbuffer in busy_list.
-        */
-       E_SB_NO_SUBBUFFER_IN_BUSY = 11,
-       /**
-        * @brief Subbuffers aren't allocated.
-        */
-       E_SB_NOT_ALLOC = 12,
-       /**
-        * @brief Thresholds > 100, top < lower.
-        */
-       E_SB_WRONG_THRESHOLD = 13
-};
-
-#endif /* __SWAP_BUFFER_ERRORS_H__ */
diff --git a/buffer/swap_buffer_module.c b/buffer/swap_buffer_module.c
deleted file mode 100644 (file)
index 551f940..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/**
- * buffer/swap_buffer_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * SWAP Buffer interface implementation.
- */
-
-#include "swap_buffer_module.h"
-#include "buffer_queue.h"
-#include "buffer_description.h"
-#include "swap_buffer_errors.h"
-#include "kernel_operations.h"
-
-/**
- * @enum _swap_buffer_status_mask
- * @brief Bitwise mask for buffer status.
- */
-enum _swap_buffer_status_mask {
-       BUFFER_FREE = 0,                /**< 000 - memory free. */
-       BUFFER_ALLOC = 1,               /**< 001 - memory allocated. */
-       BUFFER_PAUSE = 2,               /**< 010 - buffer overflow. */
-       BUFFER_WORK = 4                 /**< @brief 100 - buffer work. */
-};
-
-static unsigned char swap_buffer_status = BUFFER_FREE;
-
-/**
- * @brief Subbuffer callback type.
- */
-typedef int(*subbuffer_callback_type)(bool wakeup);
-
-/* Callback that is called when full subbuffer appears */
-static subbuffer_callback_type subbuffer_callback;
-
-/* One subbuffer size */
-static size_t subbuffers_size;
-
-/* Subbuffers count */
-static unsigned int subbuffers_num;
-
-static unsigned int enough_writable_bufs;
-static unsigned int min_writable_bufs;
-static int (*low_mem_cb)(void);
-static int (*enough_mem_cb)(void);
-
-
-static inline int areas_overlap(const void *area1,
-                               const void *area2,
-                               size_t size)
-{
-       int i;
-
-       for (i = 0; i < size; i++)
-               if ((area1 + i == area2) || (area2 + i == area1))
-                       return 1;
-
-       return 0;
-}
-
-static inline unsigned int percent_to_count(unsigned char percent,
-                                            unsigned int cnt)
-{
-       return (percent * cnt) / 100;
-}
-
-/**
- * @brief Initializes SWAP buffer and allocates memory.
- *
- * @param buf_init Pointer to the buffer_init_t structure which contains
- * information about subbuffers count, subbuffers size and subbuffer-full-
- * callback.
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_init(struct buffer_init_t *buf_init)
-{
-       int result = -1;
-
-       swap_buffer_status &= ~BUFFER_WORK;
-       print_debug("status buffer stop = %d\n", swap_buffer_status);
-
-       if ((buf_init->top_threshold > 100) ||
-           (buf_init->lower_threshold > 100) ||
-           (buf_init->top_threshold < buf_init->lower_threshold))
-               return -E_SB_WRONG_THRESHOLD;
-
-       min_writable_bufs = percent_to_count(buf_init->lower_threshold,
-                                            buf_init->nr_subbuffers);
-
-       enough_writable_bufs = percent_to_count(buf_init->top_threshold,
-                                               buf_init->nr_subbuffers);
-
-       low_mem_cb = buf_init->low_mem_cb;
-       enough_mem_cb = buf_init->enough_mem_cb;
-
-       if ((swap_buffer_status & BUFFER_ALLOC) &&
-               (subbuffers_size == buf_init->subbuffer_size) &&
-               (subbuffers_num == buf_init->nr_subbuffers) &&
-               ((subbuffer_callback_type)subbuffer_callback ==
-                                 buf_init->subbuffer_full_cb)) {
-               result = buffer_queue_reset();
-               goto swap_buffer_init_work;
-       }
-
-       subbuffer_callback = buf_init->subbuffer_full_cb;
-       subbuffers_size = buf_init->subbuffer_size;
-       subbuffers_num = buf_init->nr_subbuffers;
-
-       result = buffer_queue_allocation(subbuffers_size, subbuffers_num);
-       if (result < 0)
-               return result;
-
-       result = get_pages_count_in_subbuffer();
-
-       swap_buffer_status |= BUFFER_ALLOC;
-       print_debug("status buffer alloc = %d\n", swap_buffer_status);
-
-swap_buffer_init_work:
-       swap_buffer_status |= BUFFER_WORK;
-       print_debug("status buffer work = %d\n", swap_buffer_status);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_init);
-
-/**
- * @brief Uninitializes SWAP buffer, releases allocated memory.
- *
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_uninit(void)
-{
-       /* Check whether buffer is allocated */
-       if (!(swap_buffer_status & BUFFER_ALLOC))
-               return -E_SB_NOT_ALLOC;
-
-       /* Stop buffer */
-       swap_buffer_status &= ~BUFFER_WORK;
-       print_debug("status buffer stop = %d\n", swap_buffer_status);
-
-       /* Check whether all buffers are released */
-       if (get_busy_buffers_count())
-               return -E_SB_UNRELEASED_BUFFERS;
-
-       /* Free */
-       buffer_queue_free();
-
-       subbuffer_callback = NULL;
-       subbuffers_size = 0;
-       subbuffers_num = 0;
-       min_writable_bufs = 0;
-       enough_writable_bufs = 0;
-       low_mem_cb = NULL;
-       enough_mem_cb = NULL;
-
-       swap_buffer_status &= ~BUFFER_ALLOC;
-       print_debug("status buffer dealloc = %d\n", swap_buffer_status);
-
-       return E_SB_SUCCESS;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_uninit);
-
-/**
- * @brief Writes data to SWAP buffer.
- *
- * @param data Pointer to a data for writing.
- * @param size Size of a data for writing.
- * @return Size of written data on success, negative error code otherwise.
- */
-ssize_t swap_buffer_write(void *data, size_t size, bool wakeup)
-{
-       int result = E_SB_SUCCESS;
-       struct swap_subbuffer *buffer_to_write = NULL;
-       void *ptr_to_write = NULL;
-       unsigned long flags = 0;
-
-       /* Size sanitization */
-       if ((size > subbuffers_size) || (size == 0))
-               return -E_SB_WRONG_DATA_SIZE;
-
-       /* Check buffer status */
-       if (!(swap_buffer_status & BUFFER_WORK))
-               return -E_SB_IS_STOPPED;
-
-       /* We're going to look for writable buffer, so disable irqs */
-       swap_irq_disable(&flags);
-
-       /* Get next write buffer and occupying semaphore */
-       buffer_to_write = get_from_write_list(size, &ptr_to_write, wakeup);
-       if (!buffer_to_write) {
-               swap_irq_enable(&flags);
-               return -E_SB_NO_WRITABLE_BUFFERS;
-       }
-
-       /* Check for overlapping */
-       if (areas_overlap(ptr_to_write, data, size)) {
-               result = -E_SB_OVERLAP;
-               goto buf_write_sem_post;
-       }
-
-       /* Copy data to buffer */
-       /* XXX Think of using memmove instead - useless, anyway overlapping
-        * means that something went wrong. */
-       memcpy(ptr_to_write, data, size);
-
-       result = size;
-
-       if ((get_writable_buf_cnt() < min_writable_bufs) &&
-           !(swap_buffer_status & BUFFER_PAUSE)) {
-               swap_buffer_status |= BUFFER_PAUSE;
-               if (low_mem_cb != NULL)
-                       low_mem_cb();
-       }
-
-       /* Unlock sync (Locked in get_from_write_list()) and enable irqs */
-buf_write_sem_post:
-       sync_unlock_no_flags(&buffer_to_write->buffer_sync);
-       swap_irq_enable(&flags);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_write);
-
-/**
- * @brief Gets pointer to subbuffer for reading.
- *
- * @param[out] subbuffer Pointer to a variable which points on target subbuffer.
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_get(struct swap_subbuffer **subbuffer)
-{
-       int result = 0;
-       struct swap_subbuffer *buffer_to_read = NULL;
-
-       /* Check buffer status */
-       if (!(swap_buffer_status & BUFFER_WORK))
-               return -E_SB_IS_STOPPED;
-
-       /* Get next read buffer */
-       buffer_to_read = get_from_read_list();
-       if (!buffer_to_read)
-               return -E_SB_NO_READABLE_BUFFERS;
-
-       /* Add to busy list */
-       buffer_to_read->next_in_queue = NULL;
-       add_to_busy_list(buffer_to_read);
-
-       *subbuffer = buffer_to_read;
-
-       result = get_pages_count_in_subbuffer();
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_get);
-
-/**
- * @brief Releases subbuffer after reading.
- *
- * @param subbuffer Subbuffer that should be released.
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_release(struct swap_subbuffer **subbuffer)
-{
-       int result;
-
-       /* Remove from busy list (includes sanitization) */
-       result = remove_from_busy_list(*subbuffer);
-       if (result < 0)
-               return result;
-
-       /* Add to write list */
-       add_to_write_list(*subbuffer);
-
-       if ((swap_buffer_status & BUFFER_PAUSE) &&
-           (get_writable_buf_cnt() >= enough_writable_bufs)) {
-               swap_buffer_status &= ~BUFFER_PAUSE;
-               if (enough_mem_cb != NULL)
-                       enough_mem_cb();
-       }
-
-       return E_SB_SUCCESS;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_release);
-
-/**
- * @brief Sets all subbuffers for reading.
- *
- * @return Count of subbeffers for reading.
- */
-unsigned int swap_buffer_flush(void)
-{
-       unsigned int result;
-
-       /* Set all non-empty write buffers to read list */
-       buffer_queue_flush();
-
-       /* Get count of all full buffers */
-       result = get_readable_buf_cnt();
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_flush);
-
-/**
- * @brief Executes subbuffer-full-callback.
- *
- * @param buffer Pointer to the full subbuffer.
- * @return -E_SB_NO_CALLBACK if no callback is registered or callbacks ret
- * value otherwise.
- */
-int swap_buffer_callback(void *buffer, bool wakeup)
-{
-       int result;
-
-       if (!subbuffer_callback)
-               return -E_SB_NO_CALLBACK;
-
-       result = subbuffer_callback(wakeup);
-       if (result < 0)
-               print_err("Callback error! Error code: %d\n", result);
-
-       return result;
-}
-
-static int __init swap_buffer_module_init(void)
-{
-       printk(KERN_NOTICE "SWAP_BUFFER : Buffer module initialized\n");
-       return E_SB_SUCCESS;
-}
-
-static void __exit swap_buffer_module_exit(void)
-{
-       if (swap_buffer_status & BUFFER_ALLOC)
-               swap_buffer_uninit();
-       printk(KERN_NOTICE "SWAP_BUFFER : Buffer module unintialized\n");
-}
-
-module_init(swap_buffer_module_init);
-module_exit(swap_buffer_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP buffer module");
-MODULE_AUTHOR("Aksenov A.S.");
diff --git a/buffer/swap_buffer_module.h b/buffer/swap_buffer_module.h
deleted file mode 100644 (file)
index 95b31fa..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file buffer/swap_buffer_module.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * SWAP Buffer interface declaration.
- */
-
-#ifndef __SWAP_BUFFER_MODULE_H__
-#define __SWAP_BUFFER_MODULE_H__
-
-#include <linux/types.h>
-
-struct swap_subbuffer;
-
-/**
- * @struct buffer_init_t
- * @brief Buffer init structure. Contains information necessary for SWAP buffer
- * initialization.
- * @var buffer_init_t::subbuffer_size
- * Subbuffer size.
- * @var buffer_init_t::nr_subbuffers
- * Subbuffers count.
- * @var buffer_init_t::subbuffer_full_cb
- * Callback. Called when one of subbuffers is full.
- * @var buffer_init_t::lower_threshold
- * Lower threshold in percent. When buffers fall below this limit
- * low_mem_cb is called and swap_buffer is suspended.
- * @var buffer_init_t::low_mem_cb
- * Callback that is called when count of free subbuffers falls below
- * lower_threshold.
- * @var buffer_init_t::top_threshold
- * Top threshold in percent. When buffers exceed this limit
- * enough_mem_cb is called.
- * @var buffer_init_t::enough_mem_cb
- * Callback that is called when count of free subbuffers exceeds top_threshold.
- */
-
-struct buffer_init_t {
-       size_t subbuffer_size;
-       unsigned int nr_subbuffers;
-       int (*subbuffer_full_cb)(bool wakeup);
-
-       unsigned char lower_threshold;
-       int (*low_mem_cb)(void);
-
-       unsigned char top_threshold;
-       int (*enough_mem_cb)(void);
-};
-
-/* SWAP Buffer initialization function. Call it before using buffer.
- * Returns memory pages count (>0) in one subbuffer on success, or error code
- * (<0) otherwise. */
-int swap_buffer_init(struct buffer_init_t *buf_init);
-
-/* SWAP Buffer uninitialization function. Call it every time before removing
- * this module.
- * Returns E_SB_SUCCESS (0) on success, otherwise error code. */
-int swap_buffer_uninit(void);
-
-/* SWAP Buffer write function. Pass it size of the data and pointer to the data.
- * On success returns number of bytes written (>=0) or error code (<0)
- * otherwise */
-ssize_t swap_buffer_write(void *data, size_t size, bool wakeup);
-
-/* SWAP Buffer get. Put subbuffer pointer to the variable *subbuffer.
- * Return pages count in subbuffer. */
-int swap_buffer_get(struct swap_subbuffer **subbuffer);
-
-/* SWAP Buffer release. All 'get' buffers must be released with this function.
- * Just pass &subbuffer_ptr to it */
-int swap_buffer_release(struct swap_subbuffer **subbuffer);
-
-/* SWAP Buffer flush. Puts all buffers to read queue and returns their count. */
-unsigned int swap_buffer_flush(void);
-
-#endif /* __SWAP_BUFFER_MODULE_H__ */
diff --git a/buffer/swap_buffer_to_buffer_queue.h b/buffer/swap_buffer_to_buffer_queue.h
deleted file mode 100644 (file)
index 076549d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @file buffer/swap_buffer_to_buffer_queue.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- * SWAP Buffer interface for buffer queue.
- */
-
-#ifndef __SWAP_BUFFER_TO_BUFFER_QUEUE_H__
-#define __SWAP_BUFFER_TO_BUFFER_QUEUE_H__
-
-#include <linux/types.h>
-
-int swap_buffer_callback(void *buffer, bool wakeup);
-
-#endif /* __SWAP_BUFFER_TO_BUFFER_QUEUE_H__ */
diff --git a/build.config.example b/build.config.example
deleted file mode 100644 (file)
index 557b452..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config for build.sh
-
-kernel=<path-to-kernel-sourse>
-toolchain=<path-to-toolchain>
-arch=<architecture>
diff --git a/build.sh b/build.sh
deleted file mode 100755 (executable)
index 5b1e3a5..0000000
--- a/build.sh
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env bash
-# NOTE: This requires GNU getopt.  On Mac OS X and FreeBSD, you have to install
-# this separately; see below.
-
-IDENT=${0}
-
-show_usage_and_exit () {
-       echo -e "Usage: ${IDENT} <options> <compile|check|clean>"
-       echo -e "\tOptions:"
-       echo -e "\t--verbose"
-       echo -e "\t--file <config file>"
-#      echo -e "\t--debug"
-       echo -e "\t--kernel <kernel path>"
-       echo -e "\t--arch <arm|arm64|i386>"
-       echo -e "\t[--toolchain <cross compile path>]"
-       exit 1
-}
-
-TEMP=`getopt -o vk:t:a:f: --long verbose,kernel:,toolchain:,arch:,file: \
-       -n '${IDENT}' -- "$@"`
-
-if [ $? != 0 ] ; then
-       show_usage_and_exit
-fi
-
-# Note the quotes around `$TEMP': they are essential!
-eval set -- "$TEMP"
-
-MDIR=`pwd`
-VERBOSE=false
-CONFIG_FILE="build.config"
-KERNELDIR=""
-TOOLCHAIN=""
-ARCH=""
-
-while true; do
-       case "$1" in
-               -v | --verbose ) VERBOSE=true; shift ;;
-               -k | --kernel ) KERNELDIR="$2"; shift 2 ;;
-               -t | --toolchain ) TOOLCHAIN="$2"; shift 2;;
-               -a | --arch ) ARCH="$2"; shift 2;;
-               -f | --file ) CONFIG_FILE="$2"; shift 2;;
-               -- ) shift; break ;;
-               * ) break ;;
-       esac
-done
-
-if  [ "${1}" != "compile" -a "${1}" != "clean" -a "${1}" != "check"  ] ; then
-       ACTION="compile"
-        ARCH=${2}
-       KERNELDIR=${1}
-       if [ "${3}" != "" ] ; then
-               TOOLCHAIN=${3}
-       fi
-else
-       if [ -r ${CONFIG_FILE} ]; then
-               . ${CONFIG_FILE}
-               KERNELDIR=${kernel}
-               TOOLCHAIN=${toolchain}
-               ARCH=$arch
-       fi
-       ACTION="${1}"
-fi
-
-if [ "${KERNELDIR}" = "" ] ; then
-       show_usage_and_exit
-fi
-
-if [ "${ARCH}" = "arm" ] ; then
-       LINKNAME="arm"
-elif [ "${ARCH}" = "arm64" ] ; then
-       LINKNAME="arm64"
-elif [ "${ARCH}" = "i386" ] ; then
-       LINKNAME="x86"
-else
-       show_usage_and_exit
-fi
-
-MCFLAGS="-Werror"
-
-CMDLINE_ARGS=""
-CMDLINE_ARGS="CROSS_COMPILE=${TOOLCHAIN} ARCH=${ARCH} -C ${KERNELDIR}"
-CMDLINE_ARGS="${CMDLINE_ARGS} M=${MDIR} MCFLAGS=${MCFLAGS} LINKNAME=${LINKNAME}"
-
-if [ "${ACTION}" = "check" ] ; then
-       CMDLINE="make C=2 CF=\"-Wsparse-all\" ${CMDLINE_ARGS} modules"
-elif [ "${ACTION}" = "clean" ] ; then
-       CMDLINE="make ${CMDLINE_ARGS} clean"
-else
-       CMDLINE="make ${CMDLINE_ARGS} modules"
-fi
-
-if [ ${VERBOSE} = "true" ] ; then
-       CMDLINE="${CMDLINE} V=1"
-fi
-
-#echo -n "CMDLINE ${CMDLINE}\n"
-
-${CMDLINE} || exit 1
-
-# On arm64 gbs compiler fails on stripping arm64. This workaround is made to 
-# make it buildable until the bug is fixed.
-if [ "${ARCH}" = "arm64" ] ; then
-       for i in */*.ko; do
-               echo "Stripping $i..."
-               strip -x -g $i
-       done
-fi
-
-exit 0
-
diff --git a/deploy.sh b/deploy.sh
deleted file mode 100755 (executable)
index 5309f27..0000000
--- a/deploy.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/bash
-
-model=$(sed -n  "s|.*tizen.org/system/model_name[^>]*>\([^<]*\)<.*|\1|p" /etc/config/model-config.xml)
-modpath=/opt/swap/sdk
-
-case $model in
-# armv7l
-       "TM1")
-               mv $modpath/tm1_swap_modules/* $modpath
-               rm -r $modpath/tm1_swap_modules
-               rm -rf $modpath/odroid_swap_modules
-               rm -rf $modpath/tw1_swap_modules
-               ;;
-       "xu3")
-               mv $modpath/odroid_swap_modules/* $modpath
-               rm -r $modpath/odroid_swap_modules
-               rm -rf $modpath/tm1_swap_modules
-               rm -rf $modpath/tw1_swap_modules
-               ;;
-       "TW1")
-               mv $modpath/tw1_swap_modules/* $modpath
-               rm -r $modpath/tw1_swap_modules
-               rm -rf $modpath/odroid_swap_modules
-               rm -rf $modpath/tm1_swap_modules
-               ;;
-# x86
-       "Emulator")
-               mv $modpath/emul_swap_modules/* $modpath
-               rm -r $modpath/emul_swap_modules
-               ;;
-# aarch64
-       "TM2")
-               mv $modpath/tm2_swap_modules/* $modpath
-               rm -r $modpath/tm2_swap_modules
-               rm -rf $modpath/rpi3_swap_modules
-               rm -rf $modpath/tw2_swap_modules
-               ;;
-       "TW2")
-               mv $modpath/tw2_swap_modules/* $modpath
-               rm -r $modpath/tw2_swap_modules
-               rm -rf $modpath/rpi3_swap_modules
-               rm -rf $modpath/tm2_swap_modules
-               ;;
-       "rpi3")
-               mv $modpath/rpi3_swap_modules/* $modpath
-               rm -r $modpath/rpi3_swap_modules
-               rm -rf $modpath/tw2_swap_modules
-               rm -rf $modpath/tm2_swap_modules
-               ;;
-       *)
-               echo "Device isn't supported" > /tmp/swap-modules_install.log
-               ;;
-esac
diff --git a/driver/Kbuild b/driver/Kbuild
deleted file mode 100644 (file)
index 51f30cc..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../buffer/Module.symvers
-
-obj-m := swap_driver.o
-swap_driver-y := swap_driver_module.o \
-                     device_driver.o \
-                     driver_to_buffer.o \
-                     driver_debugfs.o
-
-ifeq ($(CONFIG_CONNECTOR),y)
-       swap_driver-y += us_interaction.o
-endif
diff --git a/driver/app_manage.h b/driver/app_manage.h
deleted file mode 100644 (file)
index 6c31de6..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @file driver/app_manage.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * Driver user <-> kernel connect implement.
- */
-
-#ifndef __APP_MANAGE_H__
-#define __APP_MANAGE_H__
-
-#include "us_interaction.h"
-#include "us_interaction_msg.h"
-
-/**
- * @brief Sends pause message to kernel.
- *
- * @return us_interaction_send_msg result.
- */
-static inline int app_manage_pause_apps(void)
-{
-       enum us_interaction_k2u_msg_t us_int_msg = US_INT_PAUSE_APPS;
-
-       return us_interaction_send_msg(&us_int_msg, sizeof(us_int_msg));
-}
-
-/**
- * @brief Sends continue message to kernel.
- *
- * @return us_interaction_send_msg result.
- */
-static inline int app_manage_cont_apps(void)
-{
-       enum us_interaction_k2u_msg_t us_int_msg = US_INT_CONT_APPS;
-
-       return us_interaction_send_msg(&us_int_msg, sizeof(us_int_msg));
-}
-
-#endif /* __APP_MANAGE_H__ */
diff --git a/driver/device_driver.c b/driver/device_driver.c
deleted file mode 100644 (file)
index e473cb8..0000000
+++ /dev/null
@@ -1,564 +0,0 @@
-/**
- * driver/device_driver.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Provides SWAP device.
- */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/splice.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/uaccess.h>
-#include <linux/version.h>
-
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-
-#include "device_driver.h"
-#include "swap_driver_errors.h"
-#include "driver_to_buffer.h"
-#include "swap_ioctl.h"
-#include "driver_defs.h"
-#include "device_driver_to_driver_to_buffer.h"
-#include "driver_to_buffer.h"
-#include "driver_to_msg.h"
-
-/** SWAP device name as it is in /dev/. */
-#define SWAP_DEVICE_NAME "swap_device"
-
-/* swap_device driver routines */
-static ssize_t swap_device_read(struct file *filp, char __user *buf,
-                               size_t count, loff_t *f_pos);
-static long swap_device_ioctl(struct file *filp, unsigned int cmd,
-                             unsigned long arg);
-static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
-                                      struct pipe_inode_info *pipe, size_t len,
-                                      unsigned int flags);
-
-#ifdef CONFIG_COMPAT
-static long swap_compat_device_ioctl(struct file *filp, unsigned int cmd,
-                                    unsigned long arg)
-{
-       switch (cmd & ~IOCSIZE_MASK) {
-       case SWAP_DRIVER_BUFFER_INITIALIZE & ~IOCSIZE_MASK:
-       case SWAP_DRIVER_MSG & ~IOCSIZE_MASK:
-               /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case) */
-               if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
-                       cmd &= ~IOCSIZE_MASK;
-                       cmd |= sizeof(void *) << IOCSIZE_SHIFT;
-               }
-               break;
-       }
-
-       return swap_device_ioctl(filp, cmd, arg);
-}
-#else /* CONFIG_COMPAT */
-#define swap_compat_device_ioctl NULL
-#endif /* CONFIG_COMPAT */
-
-
-/**
- * @var swap_device_fops
- * @brief SWAP device file operations.
- */
-const struct file_operations swap_device_fops = {
-       .owner = THIS_MODULE,
-       .read = swap_device_read,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .unlocked_ioctl = swap_device_ioctl,
-       .compat_ioctl = swap_compat_device_ioctl,
-       .splice_read = swap_device_splice_read,
-};
-
-/* Typedefs for splice_* funcs. Prototypes are for linux-3.8.6 */
-/** Splice to pipe pointer type. */
-typedef ssize_t(*splice_to_pipe_p_t)(struct pipe_inode_info *pipe,
-                                        struct splice_pipe_desc *spd);
-/** Splice grow spd pointer type. */
-typedef int(*splice_grow_spd_p_t)(const struct pipe_inode_info *pipe,
-                                       struct splice_pipe_desc *spd);
-
-static splice_to_pipe_p_t splice_to_pipe_p;
-static splice_grow_spd_p_t splice_grow_spd_p;
-
-/* Device numbers */
-static dev_t swap_device_no;
-
-/* Device cdev struct */
-static struct cdev swap_device_cdev;
-
-/* Device class struct */
-static struct class *swap_device_class;
-
-/* Device device struct */
-static struct device *swap_device_device;
-
-/* Reading tasks queue */
-static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait);
-
-
-static atomic_t flag_wake_up = ATOMIC_INIT(0);
-
-static void __bottom_wake_up(void)
-{
-       if (waitqueue_active(&swap_device_wait))
-               wake_up_interruptible(&swap_device_wait);
-}
-
-static void bottom_wake_up(struct work_struct *work)
-{
-       if (atomic_read(&flag_wake_up)) {
-               atomic_set(&flag_wake_up, 0);
-               __bottom_wake_up();
-       }
-}
-
-static DECLARE_WORK(w_wake_up, bottom_wake_up);
-
-static void exit_w_wake_up(void)
-{
-       flush_scheduled_work();
-       __bottom_wake_up();
-}
-
-
-/*
- * Driver message handler
- */
-static DECLARE_RWSEM(dmsg_handler_sem);
-static struct driver_msg_handler *dmsg_handler;
-
-static int driver_msg_handler_call(void __user *data)
-{
-       int ret;
-
-       down_read(&dmsg_handler_sem);
-       if (dmsg_handler) {
-               ret = dmsg_handler->handler(data);
-       } else {
-               print_warn("dmsg_handler() is not register\n");
-               ret = -EINVAL;
-       }
-       up_read(&dmsg_handler_sem);
-
-       return ret;
-}
-
-/**
- * @brief Register message handler.
- *
- * @param msg_handler Pointer to message handler.
- * @return Void.
- */
-void driver_msg_handler_set(struct driver_msg_handler *msg_handler)
-{
-       down_write(&dmsg_handler_sem);
-       /* unregister dmsg_handler */
-       if (dmsg_handler) {
-               module_put(dmsg_handler->mod);
-               dmsg_handler = NULL;
-       }
-
-       /* register dmsg_handler */
-       if (msg_handler) {
-               BUG_ON(!try_module_get(msg_handler->mod));
-               dmsg_handler = msg_handler;
-       }
-       up_write(&dmsg_handler_sem);
-}
-EXPORT_SYMBOL_GPL(driver_msg_handler_set);
-
-
-/**
- * @brief We need this realization of splice_shrink_spd() because its desing
- * frequently changes in custom kernels.
- *
- * @param pipe Pointer to the pipe whereto splice data.
- * @param spd Pointer to the splice_pipe_desc structure.
- * @return Void.
- */
-void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe,
-                                  struct splice_pipe_desc *spd)
-{
-       if (pipe->buffers <= PIPE_DEF_BUFFERS)
-               return;
-
-       kfree(spd->pages);
-       kfree(spd->partial);
-}
-
-
-/* TODO Think of permanent major */
-
-/**
- * @brief Register device.
- *
- * @return 0 on success, negative error code otherwise.
- */
-int swap_device_init(void)
-{
-       int result;
-
-       /* Allocating device major and minor nums for swap_device */
-       result = alloc_chrdev_region(&swap_device_no, 0, 1, SWAP_DEVICE_NAME);
-       if (result < 0) {
-               print_crit("Major number allocation has failed\n");
-               result = -E_SD_ALLOC_CHRDEV_FAIL;
-               goto init_fail;
-       }
-
-       /* Creating device class. Using IS_ERR, because class_create
-        * returns ERR_PTR on error. */
-       swap_device_class = class_create(THIS_MODULE, SWAP_DEVICE_NAME);
-       if (IS_ERR(swap_device_class)) {
-               print_crit("Class creation has failed\n");
-               result = -E_SD_CLASS_CREATE_FAIL;
-               goto init_fail;
-       }
-
-       /* Cdev intialization and setting file operations */
-       cdev_init(&swap_device_cdev, &swap_device_fops);
-
-       /* Adding cdev to system */
-       result = cdev_add(&swap_device_cdev, swap_device_no, 1);
-       if (result < 0) {
-               print_crit("Device adding has failed\n");
-               result = -E_SD_CDEV_ADD_FAIL;
-               goto init_fail;
-       }
-
-       /* Create device struct */
-       swap_device_device = device_create(swap_device_class, NULL,
-                                          swap_device_no,
-                                          "%s", SWAP_DEVICE_NAME);
-       if (IS_ERR(swap_device_device)) {
-               print_crit("Device struct creating has failed\n");
-               result = -E_SD_DEVICE_CREATE_FAIL;
-               goto init_fail;
-       }
-
-       /* Find splice_* funcs addresses */
-       splice_to_pipe_p = (splice_to_pipe_p_t)swap_ksyms("splice_to_pipe");
-       if (!splice_to_pipe_p) {
-               print_err("splice_to_pipe() not found!\n");
-               result = -E_SD_NO_SPLICE_FUNCS;
-               goto init_fail;
-       }
-
-       splice_grow_spd_p = (splice_grow_spd_p_t)swap_ksyms("splice_grow_spd");
-       if (!splice_grow_spd_p) {
-               print_err("splice_grow_spd() not found!\n");
-               result = -E_SD_NO_SPLICE_FUNCS;
-               goto init_fail;
-       }
-
-       return 0;
-
-init_fail:
-       cdev_del(&swap_device_cdev);
-       if (swap_device_class)
-               class_destroy(swap_device_class);
-       if (swap_device_no)
-               unregister_chrdev_region(swap_device_no, 1);
-       return result;
-}
-
-/* TODO Check wether driver is registered */
-
-/**
- * @brief Unregister device.
- *
- * @return Void.
- */
-void swap_device_exit(void)
-{
-       exit_w_wake_up();
-
-       splice_to_pipe_p = NULL;
-       splice_grow_spd_p = NULL;
-
-       device_destroy(swap_device_class, swap_device_no);
-       cdev_del(&swap_device_cdev);
-       class_destroy(swap_device_class);
-       unregister_chrdev_region(swap_device_no, 1);
-}
-
-static ssize_t swap_device_read(struct file *filp, char __user *buf,
-                               size_t count, loff_t *f_pos)
-{
-       /* Wait queue item that consists current task. It is used to be added in
-        * swap_device_wait queue if there is no data to be read. */
-       DEFINE_WAIT(wait);
-       int result;
-
-       /* TODO : Think about spin_locks to prevent reading race condition. */
-       while ((result =
-               driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
-
-               /* Add process to the swap_device_wait queue and set the current
-                * task state TASK_INTERRUPTIBLE. If there is any data to be
-                * read, then the current task is removed from the
-                * swap_device_wait queue and its state is changed to this. */
-               prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
-
-               if (result < 0) {
-                       result = 0;
-                       goto swap_device_read_error;
-               } else if (result == E_SD_NO_DATA_TO_READ) {
-                       /* Yes, E_SD_NO_DATA_TO_READ should be positive,
-                        * cause it's not really an error */
-                       if (filp->f_flags & O_NONBLOCK) {
-                               result = -EAGAIN;
-                               goto swap_device_read_error;
-                       }
-                       if (signal_pending(current)) {
-                               result = -ERESTARTSYS;
-                               goto swap_device_read_error;
-                       }
-                       schedule();
-                       finish_wait(&swap_device_wait, &wait);
-               }
-       }
-
-       result = driver_to_buffer_read(buf, count);
-       /* If there is an error - return 0 */
-       if (result < 0)
-               result = 0;
-
-
-       return result;
-
-swap_device_read_error:
-       finish_wait(&swap_device_wait, &wait);
-
-       return result;
-}
-
-static long swap_device_ioctl(struct file *filp, unsigned int cmd,
-                                                        unsigned long arg)
-{
-       int result;
-
-       switch (cmd) {
-       case SWAP_DRIVER_BUFFER_INITIALIZE:
-       {
-               struct buffer_initialize initialize_struct;
-
-               result = copy_from_user(&initialize_struct, (void *)arg,
-                                       sizeof(struct buffer_initialize));
-               if (result)
-                       break;
-
-               result = driver_to_buffer_set_size(initialize_struct.size);
-               if (result < 0) {
-                       print_err("Wrong subbuffer size=%u\n",
-                                 initialize_struct.size);
-                       break;
-               }
-
-               result = driver_to_buffer_set_count(initialize_struct.count);
-               if (result < 0) {
-                       print_err("Wrong subbuffer count=%u\n",
-                                 initialize_struct.count);
-                       break;
-               }
-
-               result = driver_to_buffer_initialize();
-               if (result < 0) {
-                       print_err("Buffer initialization failed %d\n", result);
-                       break;
-               }
-               result = E_SD_SUCCESS;
-
-               break;
-       }
-       case SWAP_DRIVER_BUFFER_UNINITIALIZE:
-       {
-               result = driver_to_buffer_uninitialize();
-               if (result < 0)
-                       print_err("Buffer uninitialization failed %d\n",
-                                 result);
-               break;
-       }
-       case SWAP_DRIVER_NEXT_BUFFER_TO_READ:
-       {
-               /* Use this carefully */
-               result = driver_to_buffer_next_buffer_to_read();
-               if (result == E_SD_NO_DATA_TO_READ) {
-                       /* TODO Do what we usually do when there are no
-                        * subbuffers to read (make daemon sleep ?) */
-               }
-               break;
-       }
-       case SWAP_DRIVER_FLUSH_BUFFER:
-       {
-               result = driver_to_buffer_flush();
-               break;
-       }
-       case SWAP_DRIVER_MSG:
-       {
-               result = driver_msg_handler_call((void __user *)arg);
-               break;
-       }
-       case SWAP_DRIVER_WAKE_UP:
-       {
-               swap_device_wake_up_process();
-               result = E_SD_SUCCESS;
-               break;
-       }
-       default:
-               print_warn("Unknown command %d\n", cmd);
-               result = -EINVAL;
-               break;
-
-       }
-       return result;
-}
-
-static void swap_device_pipe_buf_release(struct pipe_inode_info *inode,
-                                        struct pipe_buffer *pipe)
-{
-       __free_page(pipe->page);
-}
-
-static void swap_device_page_release(struct splice_pipe_desc *spd,
-                                    unsigned int i)
-{
-       __free_page(spd->pages[i]);
-}
-
-static const struct pipe_buf_operations swap_device_pipe_buf_ops = {
-       .can_merge = 0,
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0)
-       .map = generic_pipe_buf_map,
-       .unmap = generic_pipe_buf_unmap,
-#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0) */
-       .confirm = generic_pipe_buf_confirm,
-       .release = swap_device_pipe_buf_release,
-       .steal = generic_pipe_buf_steal,
-       .get = generic_pipe_buf_get
-};
-
-static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
-                                      struct pipe_inode_info *pipe,
-                                      size_t len, unsigned int flags)
-{
-       /* Wait queue item that consists current task. It is used to be added in
-        * swap_device_wait queue if there is no data to be read. */
-       DEFINE_WAIT(wait);
-
-       int result;
-       struct page *pages[PIPE_DEF_BUFFERS];
-       struct partial_page partial[PIPE_DEF_BUFFERS];
-       struct splice_pipe_desc spd = {
-               .pages = pages,
-               .partial = partial,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 5))
-               .nr_pages_max = PIPE_DEF_BUFFERS,
-#endif
-               .nr_pages = 0,
-               .flags = flags,
-               .ops = &swap_device_pipe_buf_ops,
-               .spd_release = swap_device_page_release,
-       };
-
-       /* Get next buffer to read */
-       /* TODO : Think about spin_locks to prevent reading race condition.*/
-       while ((result =
-               driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
-
-               /* Add process to the swap_device_wait queue and set the current
-                * task state TASK_INTERRUPTIBLE. If there is any data to be
-                * read, then the current task is removed from the
-                * swap_device_wait queue and its state is changed. */
-               prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
-               if (result < 0) {
-                       print_err("driver_to_buffer_next_buffer_to_read error "
-                                 "%d\n", result);
-                       /* TODO Error return to OS */
-                       result = 0;
-                       goto swap_device_splice_read_error;
-               } else if (result == E_SD_NO_DATA_TO_READ) {
-                       if (filp->f_flags & O_NONBLOCK) {
-                               result = -EAGAIN;
-                               goto swap_device_splice_read_error;
-                       }
-                       if (signal_pending(current)) {
-                               result = -ERESTARTSYS;
-                               goto swap_device_splice_read_error;
-                       }
-                       schedule();
-                       finish_wait(&swap_device_wait, &wait);
-               }
-       }
-
-       if (splice_grow_spd_p(pipe, &spd)) {
-               result = -ENOMEM;
-               goto swap_device_splice_read_out;
-       }
-
-       result = driver_to_buffer_fill_spd(&spd);
-       if (result != 0) {
-               print_err("Cannot fill spd for splice\n");
-               goto swap_device_shrink_spd;
-       }
-
-       result = splice_to_pipe_p(pipe, &spd);
-
-swap_device_shrink_spd:
-       swap_device_splice_shrink_spd(pipe, &spd);
-
-swap_device_splice_read_out:
-       return result;
-
-swap_device_splice_read_error:
-       finish_wait(&swap_device_wait, &wait);
-
-       return result;
-}
-
-/**
- * @brief Wakes up daemon that splicing data from driver.
- *
- * @return Void.
- */
-void swap_device_wake_up_process(void)
-{
-       if (atomic_read(&flag_wake_up) == 0) {
-               atomic_set(&flag_wake_up, 1);
-               schedule_work(&w_wake_up);
-       }
-}
diff --git a/driver/device_driver.h b/driver/device_driver.h
deleted file mode 100644 (file)
index b8f821b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @file driver/device_driver.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * SWAP device driver interface declaration.
- */
-
-#ifndef __SWAP_DRIVER_DEVICE_DRIVER_H__
-#define __SWAP_DRIVER_DEVICE_DRIVER_H__
-
-/* Create and register device */
-int swap_device_init(void);
-
-/* Delete device */
-void swap_device_exit(void);
-
-#endif /* __SWAP_DRIVER_DEVICE_DRIVER_H__ */
diff --git a/driver/device_driver_to_driver_to_buffer.h b/driver/device_driver_to_driver_to_buffer.h
deleted file mode 100644 (file)
index 1e062e2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file device_driver_to_driver_to_buffer.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- * SWAP device interface for driver_to_buffer.
- */
-
-
-#ifndef __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__
-#define __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__
-
-void swap_device_wake_up_process(void);
-
-#endif /* __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__ */
diff --git a/driver/driver_debugfs.c b/driver/driver_debugfs.c
deleted file mode 100644 (file)
index fb801da..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, 2016
- *
- * @section DESCRIPTION
- *
- * SWAP debugfs interface definition.
- */
-
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/debugfs.h>
-#include <master/swap_debugfs.h>
-#include "driver_to_buffer.h"
-#include "swap_driver_errors.h"
-
-
-#define WRITER_DBG_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
-
-
-static int buf_enabled_set(u64 val)
-{
-       int ret = -EINVAL;
-
-       switch (val) {
-       case 0:
-               ret = driver_to_buffer_uninitialize();
-               break;
-       case 1:
-               ret = driver_to_buffer_initialize();
-               break;
-       }
-
-       return ret;
-}
-
-static u64 buf_enabled_get(void)
-{
-       return driver_to_buffer_enabled();
-}
-
-static struct dfs_setget_64 dfs_enabled = {
-       .set = buf_enabled_set,
-       .get = buf_enabled_get,
-};
-
-static int subbuf_size_set(u64 val)
-{
-
-       if (driver_to_buffer_set_size(val) != E_SD_SUCCESS)
-               return -EINVAL;
-
-       return 0;
-}
-
-static u64 subbuf_size_get(void)
-{
-       return driver_to_buffer_get_size();
-}
-
-static struct dfs_setget_64 dfs_subbuf_size = {
-       .set = subbuf_size_set,
-       .get = subbuf_size_get,
-};
-
-static int subbuf_count_set(u64 val)
-{
-       if (driver_to_buffer_set_count(val) != E_SD_SUCCESS)
-               return -EINVAL;
-
-       return 0;
-}
-
-static u64 subbuf_count_get(void)
-{
-       return driver_to_buffer_get_count();
-}
-
-static struct dfs_setget_64 dfs_subbuf_count = {
-       .set = subbuf_count_set,
-       .get = subbuf_count_get,
-};
-
-
-struct dbgfs_data {
-       const char *name;
-       struct dfs_setget_64 *setget;
-};
-
-static struct dbgfs_data dbgfs[] = {
-       {
-               .name = "buffer_enabled",
-               .setget = &dfs_enabled,
-       }, {
-               .name = "subbuf_size",
-               .setget = &dfs_subbuf_size,
-       }, {
-               .name = "subbuf_conunt",
-               .setget = &dfs_subbuf_count,
-       }
-};
-
-
-static struct dentry *driver_dir;
-
-void driver_debugfs_uninit(void)
-{
-       debugfs_remove_recursive(driver_dir);
-       driver_dir = NULL;
-}
-
-int driver_debugfs_init(void)
-{
-       int i;
-       struct dentry *swap_dir, *dentry;
-
-       swap_dir = swap_debugfs_getdir();
-       if (swap_dir == NULL)
-               return -ENOENT;
-
-       driver_dir = swap_debugfs_create_dir("driver", swap_dir);
-       if (driver_dir == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < ARRAY_SIZE(dbgfs); ++i) {
-               struct dbgfs_data *data = &dbgfs[i];
-               dentry = swap_debugfs_create_setget_u64(data->name,
-                                                       WRITER_DBG_PERMS,
-                                                       driver_dir,
-                                                       data->setget);
-               if (!dentry)
-                       goto fail;
-       }
-
-       return 0;
-fail:
-       driver_debugfs_uninit();
-       return -ENOMEM;
-}
diff --git a/driver/driver_debugfs.h b/driver/driver_debugfs.h
deleted file mode 100644 (file)
index 5624d05..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, 2016
- *
- * @section DESCRIPTION
- *
- * SWAP debugfs interface definition.
- */
-
-#ifndef DRIVER_DEBUGFS_H
-#define DRIVER_DEBUGFS_H
-
-
-int driver_debugfs_init(void);
-void driver_debugfs_uninit(void);
-
-#endif // DRIVER_DEBUGFS_H
diff --git a/driver/driver_defs.h b/driver/driver_defs.h
deleted file mode 100644 (file)
index 3318ae8..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @file driver/driver_defs.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- * Device driver defs.
- */
-
-#ifndef __SWAP_DRIVER_DEVICE_DEFS_H__
-#define __SWAP_DRIVER_DEVICE_DEFS_H__
-
-#include <linux/kernel.h>
-
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
-       printk(KERN_DEBUG "SWAP_DRIVER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...)   \
-       printk(KERN_INFO "SWAP_DRIVER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...)  \
-       printk(KERN_WARNING "SWAP_DRIVER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...)   \
-       printk(KERN_ERR "SWAP_DRIVER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...)  \
-       printk(KERN_CRIT "SWAP_DRIVER CRITICAL : " msg, ##args)
-
-#endif /* __SWAP_DRIVER_DEVICE_DEFS_H__ */
diff --git a/driver/driver_to_buffer.c b/driver/driver_to_buffer.c
deleted file mode 100644 (file)
index 80683a4..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-/**
- * driver/driver_to_buffer.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Driver and buffer interaction interface implementation.
- */
-
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/splice.h>
-#include <linux/uaccess.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-
-#include <buffer/swap_buffer_module.h>
-#include <buffer/swap_buffer_errors.h>
-#include <buffer/buffer_description.h>
-
-#include "driver_defs.h"
-#include "swap_driver_errors.h"
-#include "device_driver_to_driver_to_buffer.h"
-#include "app_manage.h"
-
-/** Maximum subbuffer size. Used for sanitization checks. */
-#define MAXIMUM_SUBBUFFER_SIZE (64 * 1024)
-
-/* Current busy buffer */
-static struct swap_subbuffer *busy_buffer;
-
-/* Buffers count ready to be read */
-static int buffers_to_read;
-
-/* Pages count in one subbuffer */
-static int pages_per_buffer;
-
-/* Used to sync changes of the buffers_to_read var */
-static spinlock_t buf_to_read;
-
-
-static inline void init_buffers_to_read(void)
-{
-       spin_lock_init(&buf_to_read);
-       buffers_to_read = 0;
-}
-
-static inline void inc_buffers_to_read(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&buf_to_read, flags);
-       buffers_to_read++;
-       spin_unlock_irqrestore(&buf_to_read, flags);
-}
-
-static inline void dec_buffers_to_read(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&buf_to_read, flags);
-       buffers_to_read--;
-       spin_unlock_irqrestore(&buf_to_read, flags);
-}
-
-static inline void set_buffers_to_read(int count)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&buf_to_read, flags);
-       buffers_to_read = count;
-       spin_unlock_irqrestore(&buf_to_read, flags);
-}
-
-static inline int something_to_read(void)
-{
-       unsigned long flags;
-       int result;
-
-       spin_lock_irqsave(&buf_to_read, flags);
-       result = buffers_to_read;
-       spin_unlock_irqrestore(&buf_to_read, flags);
-
-       return result;
-}
-
-/* TODO Get subbuffer for reading */
-static size_t driver_to_buffer_get(void)
-{
-       int result;
-
-       /* If there is no readable buffers, return error */
-       result = swap_buffer_get(&busy_buffer);
-       if (result == -E_SB_NO_READABLE_BUFFERS) {
-               busy_buffer = NULL;
-               return -E_SD_NO_DATA_TO_READ;
-       } else if (result < 0) {
-               print_err("swap_buffer_get unhandle error %d\n", result);
-               return -E_SD_BUFFER_ERROR;
-       }
-
-       return busy_buffer->full_buffer_part;
-}
-
-/* TODO Release subbuffer */
-static int driver_to_buffer_release(void)
-{
-       int result;
-
-       if (!busy_buffer)
-               return -E_SD_NO_BUSY_SUBBUFFER;
-
-       result = swap_buffer_release(&busy_buffer);
-       if (result == -E_SB_NO_SUBBUFFER_IN_BUSY) {
-               return -E_SD_WRONG_SUBBUFFER_PTR;
-       } else if (result < 0) {
-               print_err("swap_buffer_release unhandle error %d\n", result);
-               return -E_SD_BUFFER_ERROR;
-       }
-
-       busy_buffer = NULL;
-
-       return E_SD_SUCCESS;
-}
-
-static int driver_to_buffer_callback(bool wakeup)
-{
-       /* Increment buffers_to_read counter */
-       inc_buffers_to_read();
-       if (wakeup)
-               swap_device_wake_up_process();
-
-       return E_SD_SUCCESS;
-}
-
-/**
- * @brief Copies data from subbuffer to userspace.
- *
- * @param[out] buf Pointer to userspace memory area whereto copy data from
- * subbuffer.
- * @param count Size of data to be read.
- * @return Read data size on success, negative error code on error.
- */
-ssize_t driver_to_buffer_read(char __user *buf, size_t count)
-{
-       size_t bytes_to_copy;
-       size_t bytes_to_read = 0;
-       int page_counter = 0;
-
-       /* Reading from swap_device means reading only current busy_buffer.
-        * So, if there is no busy_buffer, we don't get next to read, we just
-        * read nothing. In this case, or if there is nothing to read from
-        * busy_buffer - return -E_SD_NO_DATA_TO_READ. It should be correctly
-        * handled in device_driver */
-       if (!busy_buffer || !busy_buffer->full_buffer_part)
-               return -E_SD_NO_DATA_TO_READ;
-
-       /* Bytes count that we're going to copy to user buffer is equal to user
-        * buffer size or to subbuffer readable size whichever is less */
-       bytes_to_copy = (count > busy_buffer->full_buffer_part) ?
-                   busy_buffer->full_buffer_part : count;
-
-       /* Copy data from each page to buffer */
-       while (bytes_to_copy > 0) {
-               /* Get size that should be copied from current page */
-               size_t read_from_this_page =
-                       (bytes_to_copy > PAGE_SIZE) ? PAGE_SIZE
-                       : bytes_to_copy;
-
-               /* Copy and add size to copied bytes count */
-
-               /* TODO Check with more than one page */
-               bytes_to_read += read_from_this_page -
-                        copy_to_user(
-                                buf, page_address(busy_buffer->data_buffer) +
-                                (sizeof(struct page *) *
-                                 page_counter),
-                                read_from_this_page);
-               bytes_to_copy -= read_from_this_page;
-               page_counter++;
-       }
-
-       return bytes_to_read;
-}
-
-/**
- * @brief Flushes SWAP buffer.
- *
- * @return 0.
- */
-int driver_to_buffer_flush(void)
-{
-       unsigned int flushed;
-
-       flushed = swap_buffer_flush();
-       set_buffers_to_read(flushed);
-       swap_device_wake_up_process();
-
-       return E_SD_SUCCESS;
-}
-
-/**
- * @brief Fills spd structure.
- *
- * @param[out] spd Pointer to the splice_pipe_desc struct that should be filled.
- * @return 0 on success, negative error code on error.
- */
-int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd)
-{
-       size_t data_to_splice = busy_buffer->full_buffer_part;
-       struct page **pages = spd->pages;
-       struct partial_page *partial = spd->partial;
-
-       while (data_to_splice) {
-               size_t read_from_current_page = min(data_to_splice,
-                                                   (size_t)PAGE_SIZE);
-
-               pages[spd->nr_pages] = alloc_page(GFP_KERNEL);
-               if (!pages[spd->nr_pages]) {
-                       print_err("Cannot alloc page for splice\n");
-                       return -ENOMEM;
-               }
-
-               /* FIXME: maybe there is more efficient way */
-               memcpy(page_address(pages[spd->nr_pages]),
-              page_address(&busy_buffer->data_buffer[spd->nr_pages]),
-              read_from_current_page);
-
-               /* Always beginning of the page */
-               partial[spd->nr_pages].offset = 0;
-               partial[spd->nr_pages].len = read_from_current_page;
-
-               /* Private is not used */
-               partial[spd->nr_pages].private = 0;
-
-               spd->nr_pages++;
-               data_to_splice -= read_from_current_page;
-
-               /* TODO: add check for pipe->buffers exceeding */
-               /* if (spd->nr_pages == pipe->buffers) { */
-               /*      break; */
-               /* } */
-       }
-       return 0;
-}
-
-/**
- * @brief Check for subbuffer ready to be read.
- *
- * @return 1 if there is subbuffer to be read, 0 - if there isn't.
- */
-int driver_to_buffer_buffer_to_read(void)
-{
-       return busy_buffer ? 1 : 0;
-}
-
-static size_t subbuf_size;
-static unsigned int subbuf_count;
-static bool buffer_enabled;
-static DEFINE_MUTEX(buffer_mtx);
-
-bool driver_to_buffer_enabled(void)
-{
-       return buffer_enabled;
-}
-
-enum _swap_driver_errors driver_to_buffer_set_size(size_t size)
-{
-       enum _swap_driver_errors ret = E_SD_SUCCESS;
-
-       if (!size || size > MAXIMUM_SUBBUFFER_SIZE)
-               return -E_SD_WRONG_ARGS;
-
-       mutex_lock(&buffer_mtx);
-       if (buffer_enabled) {
-               ret = -E_SD_BUFFER_ENABLED;
-               goto unlock;
-       }
-
-       subbuf_size = size;
-unlock:
-       mutex_unlock(&buffer_mtx);
-       return ret;
-}
-
-size_t driver_to_buffer_get_size(void)
-{
-       return subbuf_size;
-}
-
-enum _swap_driver_errors driver_to_buffer_set_count(unsigned int count)
-{
-       enum _swap_driver_errors ret = E_SD_SUCCESS;
-
-       if (!count)
-               return -E_SD_WRONG_ARGS;
-
-       mutex_lock(&buffer_mtx);
-       if (buffer_enabled) {
-               ret = -E_SD_BUFFER_ENABLED;
-               goto unlock;
-       }
-       subbuf_count = count;
-
-unlock:
-       mutex_unlock(&buffer_mtx);
-       return ret;
-}
-
-unsigned int driver_to_buffer_get_count(void)
-{
-       return subbuf_count;
-}
-
-/**
- * @brief Initializes SWAP buffer.
- *
- * @param size Size of one subbuffer.
- * @param count Count of subbuffers.
- * @return 0 on success, negative error code on error.
- */
-int driver_to_buffer_initialize(void)
-{
-       enum _swap_driver_errors result;
-       struct buffer_init_t buf_init = {
-               .subbuffer_size = subbuf_size,
-               .nr_subbuffers = subbuf_count,
-               .subbuffer_full_cb = driver_to_buffer_callback,
-               .lower_threshold = 20,
-               .low_mem_cb = app_manage_pause_apps,
-               .top_threshold = 80,
-               .enough_mem_cb = app_manage_cont_apps,
-       };
-
-       mutex_lock(&buffer_mtx);
-       if (buffer_enabled) {
-               result = -E_SD_BUFFER_ENABLED;
-               goto unlock;
-       }
-
-       result = swap_buffer_init(&buf_init);
-       if (result == -E_SB_NO_MEM_QUEUE_BUSY
-               || result == -E_SB_NO_MEM_BUFFER_STRUCT) {
-               result = -E_SD_NO_MEMORY;
-               goto unlock;
-       }
-
-       /* TODO Race condition: buffer can be used in other thread till */
-       /* we're in this func */
-       /* Initialize driver_to_buffer variables */
-       pages_per_buffer = result;
-       busy_buffer = NULL;
-       init_buffers_to_read();
-       result = E_SD_SUCCESS;
-       buffer_enabled = true;
-
-unlock:
-       mutex_unlock(&buffer_mtx);
-       return result;
-}
-
-/**
- * @brief Uninitializes buffer.
- *
- * @return 0 on success, negative error code on error.
- */
-int driver_to_buffer_uninitialize(void)
-{
-       int result;
-
-       mutex_lock(&buffer_mtx);
-       if (!buffer_enabled) {
-               result = -E_SD_BUFFER_DISABLED;
-               goto unlock;
-       }
-
-       /* Release occupied buffer */
-       if (busy_buffer) {
-               result = driver_to_buffer_release();
-               /* TODO Maybe release anyway */
-               if (result < 0)
-                       goto unlock;
-               busy_buffer = NULL;
-       }
-
-       result = swap_buffer_uninit();
-       if (result == -E_SB_UNRELEASED_BUFFERS) {
-               print_err("Can't uninit buffer! There are busy subbuffers!\n");
-               result = -E_SD_BUFFER_ERROR;
-       } else if (result < 0) {
-               print_err("swap_buffer_uninit error %d\n", result);
-               result = -E_SD_BUFFER_ERROR;
-       } else {
-               result = E_SD_SUCCESS;
-               buffer_enabled = false;
-       }
-
-       /* Reinit driver_to_buffer vars */
-       init_buffers_to_read();
-       pages_per_buffer = 0;
-
-unlock:
-       mutex_unlock(&buffer_mtx);
-       return result;
-}
-
-/**
- * @brief Get next buffer to read.
- *
- * @return 0 on success, negative error code on error, E_SD_NO_DATA_TO_READ if
- * there is nothing to be read.
- */
-int driver_to_buffer_next_buffer_to_read(void)
-{
-       int result;
-
-       /* If there is busy_buffer first release it */
-       if (busy_buffer) {
-               result = driver_to_buffer_release();
-               if (result)
-                       return result;
-       }
-
-       /* If there is no buffers to read, return E_SD_NO_DATA_TO_READ.
-        * SHOULD BE POSITIVE, cause there is no real error. */
-       if (!something_to_read())
-               return E_SD_NO_DATA_TO_READ;
-
-       /* Get next buffer to read */
-       result = driver_to_buffer_get();
-       if (result < 0) {
-               print_err("buffer_to_reads > 0, but there are no buffers to read\n");
-               return result;
-       }
-
-       /* Decrement buffers_to_read counter */
-       dec_buffers_to_read();
-
-       return E_SD_SUCCESS;
-}
diff --git a/driver/driver_to_buffer.h b/driver/driver_to_buffer.h
deleted file mode 100644 (file)
index 465968f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * @file driver/driver_to_buffer.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Driver and buffer interaction interface declaration.
- */
-
-#ifndef __SWAP_DRIVER_DRIVER_TO_BUFFER__
-#define __SWAP_DRIVER_DRIVER_TO_BUFFER__
-
-
-#include <linux/types.h>
-
-struct splice_pipe_desc;
-
-
-bool driver_to_buffer_enabled(void);
-
-enum _swap_driver_errors driver_to_buffer_set_size(size_t size);
-size_t driver_to_buffer_get_size(void);
-
-enum _swap_driver_errors driver_to_buffer_set_count(unsigned int count);
-unsigned int driver_to_buffer_get_count(void);
-
-int driver_to_buffer_initialize(void);
-int driver_to_buffer_uninitialize(void);
-ssize_t driver_to_buffer_read(char __user *buf, size_t count);
-int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd);
-int driver_to_buffer_buffer_to_read(void);
-int driver_to_buffer_next_buffer_to_read(void);
-int driver_to_buffer_flush(void);
-
-
-#endif /* __SWAP_DRIVER_DRIVER_TO_BUFFER__ */
diff --git a/driver/driver_to_msg.h b/driver/driver_to_msg.h
deleted file mode 100644 (file)
index f252155..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file driver/driver_to_msg.h
- * @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
- *
- * Driver and parser interaction interface declaration.
- */
-
-#ifndef __SWAP_DRIVER_DRIVER_TO_MSG__
-#define __SWAP_DRIVER_DRIVER_TO_MSG__
-
-#include <linux/compiler.h>
-
-struct module;
-
-struct driver_msg_handler {
-       struct module *mod;
-       int (*handler)(void __user *data);
-};
-
-/* Set the message handler */
-void driver_msg_handler_set(struct driver_msg_handler *msg_handler);
-
-#endif /* __SWAP_DRIVER_DRIVER_TO_MSG__ */
diff --git a/driver/swap_driver_errors.h b/driver/swap_driver_errors.h
deleted file mode 100644 (file)
index 7c6fce2..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * @file driver/swap_driver_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * SWAP driver error codes.
- */
-
-#ifndef __SWAP_DRIVER_ERRORS_H__
-#define __SWAP_DRIVER_ERRORS_H__
-
-
-/**
- * @enum _swap_driver_errors
- * @brief SWAP driver errors enumeration.
- */
-enum _swap_driver_errors {
-       /**
-        * @brief Success.
-        */
-       E_SD_SUCCESS = 0,
-       /**
-        * @brief Alloc_chrdev_region failed.
-        */
-       E_SD_ALLOC_CHRDEV_FAIL = 1,
-       /**
-        * @brief cdev_alloc failed.
-        */
-       E_SD_CDEV_ALLOC_FAIL = 2,
-       /**
-        * @brief cdev_add failed.
-        */
-       E_SD_CDEV_ADD_FAIL = 3,
-       /**
-        * @brief class_create failed.
-        */
-       E_SD_CLASS_CREATE_FAIL = 4,
-       /**
-        * @brief device_create failed.
-        */
-       E_SD_DEVICE_CREATE_FAIL = 5,
-       /**
-        * @brief splice_* funcs not found.
-        */
-       E_SD_NO_SPLICE_FUNCS = 6,
-       /**
-        * @brief swap_buffer_get tells us that there is no readable subbuffers.
-        */
-       E_SD_NO_DATA_TO_READ = 7,
-       /**
-        * @brief No busy subbuffer.
-        */
-       E_SD_NO_BUSY_SUBBUFFER = 8,
-       /**
-        * @brief Wrong subbuffer pointer passed to swap_buffer module.
-        */
-       E_SD_WRONG_SUBBUFFER_PTR = 9,
-       /**
-        * @brief Unhandled swap_buffer error.
-        */
-       E_SD_BUFFER_ERROR = 10,
-       /**
-        * @brief Write to subbuffer error.
-        */
-       E_SD_WRITE_ERROR = 11,
-       /**
-        * @brief Arguments, been passed to the func, doesn't pass sanity check.
-        */
-       E_SD_WRONG_ARGS = 12,
-       /**
-        * @brief No memory to allocate.
-        */
-       E_SD_NO_MEMORY = 13,
-       /**
-        * @brief swap_buffer uninitialization error.
-        */
-       E_SD_UNINIT_ERROR = 14,
-       /**
-        * @brief Netlink init error.
-        */
-       E_SD_NL_INIT_ERR = 15,
-       /**
-        * @brief Netlink message send error.
-        */
-       E_SD_NL_MSG_ERR = 16,
-       /**
-        * @brief No daemon pid in us_interaction.
-        */
-       E_SD_NO_DAEMON_PID = 17,
-       /**
-        * @brief Buffer already enabled
-        */
-       E_SD_BUFFER_ENABLED = 18,
-       /**
-        * @brief Buffer already disabled
-        */
-       E_SD_BUFFER_DISABLED = 19,
-};
-
-#endif /* __SWAP_DRIVER_ERRORS_H__ */
diff --git a/driver/swap_driver_module.c b/driver/swap_driver_module.c
deleted file mode 100644 (file)
index dcb69bb..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * driver/swap_driver_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * SWAP drive module interface implementation.
- */
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "driver_defs.h"
-#include "device_driver.h"
-#include "us_interaction.h"
-#include "driver_debugfs.h"
-
-static int fs_init(void)
-{
-       int ret;
-
-       ret = swap_device_init();
-       if (ret)
-               goto dev_init_fail;
-
-       ret = us_interaction_create();
-       if (ret)
-               print_err("Cannot initialize netlink socket\n");
-
-       ret = driver_debugfs_init();
-       if (ret)
-               goto us_int_destroy;
-
-       print_msg("Driver module initialized\n");
-
-       return ret;
-
-us_int_destroy:
-       us_interaction_destroy();
-dev_init_fail:
-       swap_device_exit();
-
-       return ret;
-}
-
-static void fs_uninit(void)
-{
-       driver_debugfs_uninit();
-       us_interaction_destroy();
-       swap_device_exit();
-       print_msg("Driver module uninitialized\n");
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, NULL, NULL, fs_init, fs_uninit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP device driver");
-MODULE_AUTHOR("Aksenov A.S.");
diff --git a/driver/swap_ioctl.h b/driver/swap_ioctl.h
deleted file mode 100644 (file)
index 9fd541c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file driver/swap_ioctl.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Provides ioctl commands and recources for SWAP driver.
- */
-
-#ifndef __SWAP_IOCTL_H__
-#define __SWAP_IOCTL_H__
-
-#include <linux/ioctl.h>
-
-/** SWAP device magic number. */
-#define SWAP_DRIVER_IOC_MAGIC 0xAF
-
-/**
- * @struct buffer_initialize
- * @brief SWAP buffer initialization struct.
- * @var buffer_initialize::size
- * Size of one subbuffer.
- * @var buffer_initialize::count
- * Count of subbuffers in the buffer.
- */
-struct buffer_initialize {
-       u32 size;
-       u32 count;
-} __packed;
-
-/* SWAP Device ioctl commands */
-
-/** Initialize buffer message. */
-#define SWAP_DRIVER_BUFFER_INITIALIZE          _IOW(SWAP_DRIVER_IOC_MAGIC, 1, \
-                                                    struct buffer_initialize *)
-/** Uninitialize buffer message. */
-#define SWAP_DRIVER_BUFFER_UNINITIALIZE                _IO(SWAP_DRIVER_IOC_MAGIC, 2)
-/** Set next buffer to read. */
-#define SWAP_DRIVER_NEXT_BUFFER_TO_READ                _IO(SWAP_DRIVER_IOC_MAGIC, 3)
-/** Flush buffers. */
-#define SWAP_DRIVER_FLUSH_BUFFER               _IO(SWAP_DRIVER_IOC_MAGIC, 4)
-/** Custom message. */
-#define SWAP_DRIVER_MSG                                _IOW(SWAP_DRIVER_IOC_MAGIC, 5, \
-                                                    void *)
-/** Force wake up daemon. */
-#define SWAP_DRIVER_WAKE_UP                    _IO(SWAP_DRIVER_IOC_MAGIC, 6)
-
-#endif /* __SWAP_IOCTL_H__ */
diff --git a/driver/us_interaction.c b/driver/us_interaction.c
deleted file mode 100644 (file)
index 9bac1be..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * driver/us_interaction.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * Kernel-to-user interface implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/connector.h>
-#include <linux/slab.h>
-
-#include "us_interaction.h"
-#include "us_interaction_msg.h"
-#include "swap_driver_errors.h"
-#include "driver_defs.h"
-
-
-/* Connector id struct */
-static struct cb_id cn_swap_id = {CN_SWAP_IDX, CN_SWAP_VAL};
-
-/* Swap connector name */
-static const char cn_swap_name[] = "cn_swap";
-
-/* Send messages counter */
-static u32 msg_counter;
-
-/**
- * @brief Sends message to userspace via netlink.
- *
- * @param data Pointer to the data to be send.
- * @param size Size of the data to be send.
- * @return 0 on success, error code on error.
- */
-int us_interaction_send_msg(const void *data, size_t size)
-{
-       struct cn_msg *msg;
-       int ret;
-
-       msg = kzalloc(sizeof(*msg) + size, GFP_ATOMIC);
-       if (msg == NULL)
-               return -E_SD_NO_MEMORY;
-
-       memcpy(&msg->id, &cn_swap_id, sizeof(msg->id));
-       msg->seq = msg_counter;
-       msg->len = size;
-       memcpy(msg->data, data, msg->len);
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 25)
-       ret = cn_netlink_send(msg, CN_DAEMON_GROUP, GFP_ATOMIC);
-#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0) */
-       ret = cn_netlink_send(msg, 0, CN_DAEMON_GROUP, GFP_ATOMIC);
-#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0) */
-       if (ret < 0)
-               goto fail_send;
-       kfree(msg);
-
-       msg_counter++;
-
-       return E_SD_SUCCESS;
-
-fail_send:
-       kfree(msg);
-
-       return ret;
-}
-
-static void us_interaction_recv_msg(struct cn_msg *msg,
-                                   struct netlink_skb_parms *nsp)
-{
-}
-
-/**
- * @brief Creates netlink connection.
- *
- * @return 0 on success, error code on error.
- */
-int us_interaction_create(void)
-{
-       int res;
-
-       res = cn_add_callback(&cn_swap_id,
-                             cn_swap_name,
-                             us_interaction_recv_msg);
-       if (res)
-               return -E_SD_NL_INIT_ERR;
-
-       return E_SD_SUCCESS;
-}
-
-/**
- * @brief Destroy netlink connection.
- *
- * @return Void.
- */
-void us_interaction_destroy(void)
-{
-       cn_del_callback(&cn_swap_id);
-}
diff --git a/driver/us_interaction.h b/driver/us_interaction.h
deleted file mode 100644 (file)
index 66f6343..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file driver/us_interaction.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * Kernel-to-user interface definition.
- */
-
-#ifndef __US_INTERACTION_H__
-#define __US_INTERACTION_H__
-
-#include <linux/version.h>
-
-#ifdef CONFIG_CONNECTOR
-
-int us_interaction_create(void);
-void us_interaction_destroy(void);
-int us_interaction_send_msg(const void *data, size_t size);
-
-#else /* CONFIG_CONNECTOR */
-
-static inline int us_interaction_create(void)
-{
-       return -EPERM;
-}
-
-static inline void us_interaction_destroy(void)
-{
-}
-
-static inline int us_interaction_send_msg(const void *data, size_t size)
-{
-       return -EPERM;
-}
-
-#endif /* CONFIG_CONNECTOR */
-
-#endif /* __US_INTERACTION_H__ */
diff --git a/driver/us_interaction_msg.h b/driver/us_interaction_msg.h
deleted file mode 100644 (file)
index d6bb4c9..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @file driver/us_interaction_msg.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * Netlink messages declaration.
- */
-
-#ifndef __US_INTERACTION_MSG_H__
-#define __US_INTERACTION_MSG_H__
-
-#define CN_SWAP_IDX     0x22    /**< Should be unique throughout the system */
-#define CN_SWAP_VAL     0x1     /**< Just the same in kernel and user */
-#define CN_DAEMON_GROUP 0x1     /**< Listener group. Connector works a bit
-                                * faster when using one */
-
-/**
- * @enum us_interaction_k2u_msg_t
- * @brief Kernel-to-user netlink messages headers.
- */
-enum us_interaction_k2u_msg_t {
-       /**
-        * @brief Make daemon pause apps.
-        */
-       US_INT_PAUSE_APPS = 1,
-       /**
-        * @brief Make daemon continue apps.
-        */
-       US_INT_CONT_APPS = 2
-};
-
-#endif /* __US_INTERACTION_MSG_H__ */
diff --git a/energy/Kbuild b/energy/Kbuild
deleted file mode 100644 (file)
index 80d23c9..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers \
-                       $(src)/../us_manager/Module.symvers \
-                       $(src)/../driver/Module.symvers
-
-
-
-
-
-###############################################################################
-###                      swap energy module description                     ###
-###############################################################################
-obj-m := swap_energy.o
-swap_energy-y := energy_module.o \
-                 energy.o \
-                 rational_debugfs.o \
-                 debugfs_energy.o \
-                 lcd/lcd_base.o \
-                 lcd/lcd_debugfs.o
-
-
-
-
-
-###############################################################################
-###                               math support                              ###
-###############################################################################
-# S6E8AA0:
-ifeq ($(CONFIG_LCD_S6E8AA0), y)
-    swap_energy-y += lcd/s6e8aa0.o
-    LCD_FUNC_LIST += s6e8aa0
-endif
-
-
-# PANEL_S6E8AA0:
-ifeq ($(CONFIG_DISPLAY_PANEL_S6E8AA0), y)
-    swap_energy-y += lcd/s6e8aa0_panel.o
-    LCD_FUNC_LIST += s6e8aa0_panel
-endif
-
-
-# MARU:
-ifeq ($(CONFIG_MARU_BACKLIGHT), y)
-    swap_energy-y += lcd/maru.o
-    LCD_FUNC_LIST += maru
-endif
-
-
-
-
-
-###############################################################################
-###                          description functions                          ###
-###############################################################################
-LCD_FUNC_ARGS := void
-LCD_FUNC_RET := struct lcd_ops *
-
-
-
-
-
-###############################################################################
-###                            generate defines                             ###
-###############################################################################
-LCD_PREFIX := lcd_energy_
-
-# add prefix
-TMP := $(foreach it, $(LCD_FUNC_LIST), $(LCD_PREFIX)$(it))
-LCD_FUNC_LIST := $(TMP)
-
-# generate DEFINITION_LCD_FUNC
-TMP := ($(LCD_FUNC_ARGS));
-DEFINITION_LCD_FUNC := DEFINITION_LCD_FUNC=\
-$(foreach it, $(LCD_FUNC_LIST), "extern" $(LCD_FUNC_RET) $(it)$(TMP))
-
-
-# generate DEFINITION_LCD_ARRAY
-COMMA := ,
-AND := &
-DEFINITION_LCD_ARRAY := DEFINITION_LCD_ARRAY=\
-"{" $(foreach it, $(LCD_FUNC_LIST), &$(it),) "}"
-
-
-# generate LCD_MAKE_FNAME
-LCD_MAKE_FNAME := LCD_MAKE_FNAME(name)=$(LCD_PREFIX)\#\#name
-
-
-
-
-
-###############################################################################
-###                  add generate defines to EXTRA_CFLAGS                   ###
-###############################################################################
-EXTRA_CFLAGS += -D"$(DEFINITION_LCD_FUNC)" \
-                -D"$(DEFINITION_LCD_ARRAY)" \
-                -D"$(LCD_MAKE_FNAME)"
diff --git a/energy/debugfs_energy.c b/energy/debugfs_energy.c
deleted file mode 100644 (file)
index b6ce420..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  energy/debugfs_energy.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/math64.h>
-#include <master/swap_debugfs.h>
-#include "energy.h"
-#include "debugfs_energy.h"
-#include "rational_debugfs.h"
-#include "lcd/lcd_debugfs.h"
-#include "lcd/lcd_base.h"
-
-
-/* CPU running */
-static DEFINE_RATIONAL(cpu0_running_coef); /* boot core uses distinct coeff */
-static DEFINE_RATIONAL(cpuN_running_coef);
-
-static u64 __energy_cpu0(enum parameter_energy pe)
-{
-       u64 times[NR_CPUS] = { 0 };
-       u64 val = 0;
-
-       /* TODO: make for only cpu0 */
-       if (get_parameter_energy(pe, times, sizeof(times)) == 0) {
-               val = div_u64(times[0] * cpu0_running_coef.num,
-                             cpu0_running_coef.denom);
-       }
-
-       return val;
-}
-
-static u64 __energy_cpuN(enum parameter_energy pe)
-{
-       u64 times[NR_CPUS] = { 0 };
-       u64 val = 0;
-
-       if (get_parameter_energy(pe, times, sizeof(times)) == 0) {
-               int i;
-
-               for (i = 1; i < NR_CPUS; i++)
-                       val += div_u64(times[i] * cpuN_running_coef.num,
-                                      cpuN_running_coef.denom);
-       }
-
-       return val;
-}
-
-static u64 cpu0_system(void)
-{
-       return __energy_cpu0(PE_TIME_SYSTEM);
-}
-
-static u64 cpuN_system(void)
-{
-       return __energy_cpuN(PE_TIME_SYSTEM);
-}
-
-static u64 cpu0_apps(void)
-{
-       return __energy_cpu0(PE_TIME_APPS);
-}
-
-static u64 cpuN_apps(void)
-{
-       return __energy_cpuN(PE_TIME_APPS);
-}
-
-
-/* CPU idle */
-static DEFINE_RATIONAL(cpu_idle_coef);
-
-static u64 cpu_idle_system(void)
-{
-       u64 time = 0;
-
-       get_parameter_energy(PE_TIME_IDLE, &time, sizeof(time));
-       return div_u64(time * cpu_idle_coef.num, cpu_idle_coef.denom);
-}
-
-
-/* flash read */
-static DEFINE_RATIONAL(fr_coef);
-
-static u64 fr_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_READ_SYSTEM, &byte, sizeof(byte));
-       return div_u64(byte * fr_coef.num, fr_coef.denom);
-}
-
-static u64 fr_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_READ_APPS, &byte, sizeof(byte));
-       return div_u64(byte * fr_coef.num, fr_coef.denom);
-}
-
-
-/* flash write */
-static DEFINE_RATIONAL(fw_coef);
-
-static u64 fw_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_WRITE_SYSTEM, &byte, sizeof(byte));
-       return div_u64(byte * fw_coef.num, fw_coef.denom);
-}
-
-static u64 fw_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_WRITE_APPS, &byte, sizeof(byte));
-       return div_u64(byte * fw_coef.num, fw_coef.denom);
-}
-
-
-/* wifi recv */
-static DEFINE_RATIONAL(wf_recv_coef);
-
-static u64 wf_recv_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_WF_RECV_SYSTEM, &byte, sizeof(byte));
-
-       return div_u64(byte * wf_recv_coef.num, wf_recv_coef.denom);
-}
-
-static u64 wf_recv_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_WF_RECV_APPS, &byte, sizeof(byte));
-
-       return div_u64(byte * wf_recv_coef.num, wf_recv_coef.denom);
-}
-
-/* wifi send */
-static DEFINE_RATIONAL(wf_send_coef);
-
-static u64 wf_send_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_WF_SEND_SYSTEM, &byte, sizeof(byte));
-
-       return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
-}
-
-static u64 wf_send_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_WF_SEND_APPS, &byte, sizeof(byte));
-
-       return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
-}
-
-/* l2cap_recv_acldata */
-static DEFINE_RATIONAL(l2cap_recv_acldata_coef);
-
-static u64 l2cap_recv_acldata_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_L2CAP_RECV_SYSTEM, &byte, sizeof(byte));
-
-       return div_u64(byte * l2cap_recv_acldata_coef.num,
-                      l2cap_recv_acldata_coef.denom);
-}
-
-static u64 l2cap_recv_acldata_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_L2CAP_RECV_APPS, &byte, sizeof(byte));
-
-       return div_u64(byte * l2cap_recv_acldata_coef.num,
-                      l2cap_recv_acldata_coef.denom);
-}
-
-/* sco_recv_scodata */
-static DEFINE_RATIONAL(sco_recv_scodata_coef);
-
-static u64 sco_recv_scodata_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_SCO_RECV_SYSTEM, &byte, sizeof(byte));
-
-       return div_u64(byte * sco_recv_scodata_coef.num,
-                      sco_recv_scodata_coef.denom);
-}
-
-static u64 sco_recv_scodata_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PE_SCO_RECV_APPS, &byte, sizeof(byte));
-
-       return div_u64(byte * sco_recv_scodata_coef.num,
-                      sco_recv_scodata_coef.denom);
-}
-
-/* hci_send_acl */
-static DEFINE_RATIONAL(hci_send_acl_coef);
-
-static u64 hci_send_acl_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PT_SEND_ACL_SYSTEM, &byte, sizeof(byte));
-
-       return div_u64(byte * hci_send_acl_coef.num, hci_send_acl_coef.denom);
-}
-
-static u64 hci_send_acl_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PT_SEND_ACL_APPS, &byte, sizeof(byte));
-
-       return div_u64(byte * hci_send_acl_coef.num, hci_send_acl_coef.denom);
-}
-
-/* hci_send_sco */
-static DEFINE_RATIONAL(hci_send_sco_coef);
-
-static u64 hci_send_sco_system(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PT_SEND_SCO_SYSTEM, &byte, sizeof(byte));
-
-       return div_u64(byte * hci_send_sco_coef.num, hci_send_sco_coef.denom);
-}
-
-static u64 hci_send_sco_apps(void)
-{
-       u64 byte = 0;
-
-       get_parameter_energy(PT_SEND_SCO_APPS, &byte, sizeof(byte));
-
-       return div_u64(byte * hci_send_sco_coef.num, hci_send_sco_coef.denom);
-}
-
-
-
-
-
-/* ============================================================================
- * ===                             PARAMETERS                               ===
- * ============================================================================
- */
-static int get_func_u64(void *data, u64 *val)
-{
-       u64 (*func)(void) = data;
-       *val = func();
-       return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_u64, get_func_u64, NULL, "%llu\n");
-
-
-struct param_data {
-       char *name;
-       struct rational *coef;
-       u64 (*system)(void);
-       u64 (*apps)(void);
-};
-
-static struct dentry *create_parameter(struct dentry *parent,
-                                      struct param_data *param)
-{
-       struct dentry *name, *system, *apps = NULL;
-
-       name = swap_debugfs_create_dir(param->name, parent);
-       if (name == NULL)
-               return NULL;
-
-       system = swap_debugfs_create_file("system", 0600, name, param->system,
-                                         &fops_get_u64);
-       if (system == NULL)
-               goto rm_name;
-
-       if (param->apps) {
-               apps = swap_debugfs_create_file("apps", 0600, name, param->apps,
-                                               &fops_get_u64);
-               if (apps == NULL)
-                       goto rm_system;
-       }
-
-       if (create_rational_files(name, param->coef,
-                                 "numerator", "denominator"))
-               goto rm_apps;
-
-       return name;
-
-rm_apps:
-       if (param->apps)
-               debugfs_remove(apps);
-rm_system:
-       debugfs_remove(system);
-rm_name:
-       debugfs_remove(name);
-
-       return NULL;
-}
-
-struct param_data parameters[] = {
-       {
-               .name = "cpu_running",
-               .coef = &cpu0_running_coef,
-               .system = cpu0_system,
-               .apps = cpu0_apps
-       },
-       {
-               .name = "cpuN_running",
-               .coef = &cpuN_running_coef,
-               .system = cpuN_system,
-               .apps = cpuN_apps
-       },
-       {
-               .name = "cpu_idle",
-               .coef = &cpu_idle_coef,
-               .system = cpu_idle_system,
-               .apps = NULL
-       },
-       {
-               .name = "flash_read",
-               .coef = &fr_coef,
-               .system = fr_system,
-               .apps = fr_apps
-       },
-       {
-               .name = "flash_write",
-               .coef = &fw_coef,
-               .system = fw_system,
-               .apps = fw_apps
-       },
-       {
-               .name = "wf_recv",
-               .coef = &wf_recv_coef,
-               .system = wf_recv_system,
-               .apps = wf_recv_apps
-       },
-       {
-               .name = "wf_send",
-               .coef = &wf_send_coef,
-               .system = wf_send_system,
-               .apps = wf_send_apps
-       },
-       {
-               .name = "sco_recv_scodata",
-               .coef = &sco_recv_scodata_coef,
-               .system = sco_recv_scodata_system,
-               .apps = sco_recv_scodata_apps
-       },
-       {
-               .name = "l2cap_recv_acldata",
-               .coef = &l2cap_recv_acldata_coef,
-               .system = l2cap_recv_acldata_system,
-               .apps = l2cap_recv_acldata_apps
-       },
-       {
-               .name = "hci_send_acl",
-               .coef = &hci_send_acl_coef,
-               .system = hci_send_acl_system,
-               .apps = hci_send_acl_apps
-       },
-       {
-               .name = "hci_send_sco",
-               .coef = &hci_send_sco_coef,
-               .system = hci_send_sco_system,
-               .apps = hci_send_sco_apps
-       }
-};
-
-enum {
-       parameters_cnt = sizeof(parameters) / sizeof(struct param_data)
-};
-
-
-
-
-
-/* ============================================================================
- * ===                              INIT/EXIT                               ===
- * ============================================================================
- */
-static struct dentry *energy_dir;
-
-/**
- * @brief Destroy debugfs for LCD
- *
- * @return Dentry of energy debugfs
- */
-struct dentry *get_energy_dir(void)
-{
-       return energy_dir;
-}
-
-/**
- * @brief Destroy debugfs for energy
- *
- * @return Void
- */
-void exit_debugfs_energy(void)
-{
-       lcd_exit();
-       exit_lcd_debugfs();
-
-       if (energy_dir)
-               debugfs_remove_recursive(energy_dir);
-
-       energy_dir = NULL;
-}
-
-/**
- * @brief Create debugfs for energy
- *
- * @return Error code
- */
-int init_debugfs_energy(void)
-{
-       int i;
-       struct dentry *swap_dir, *dentry;
-
-       swap_dir = swap_debugfs_getdir();
-       if (swap_dir == NULL)
-               return -ENOENT;
-
-       energy_dir = swap_debugfs_create_dir("energy", swap_dir);
-       if (energy_dir == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < parameters_cnt; ++i) {
-               dentry = create_parameter(energy_dir, &parameters[i]);
-               if (dentry == NULL)
-                       goto fail;
-       }
-
-       if (init_lcd_debugfs(energy_dir))
-               goto fail;
-
-       /* Actually, the only goal of lcd_init() is to register lcd screen's
-          debugfs, so it is called here. */
-       if (lcd_init()) {
-               exit_lcd_debugfs();
-       }
-
-       return 0;
-
-fail:
-       exit_debugfs_energy();
-       return -ENOMEM;
-}
diff --git a/energy/debugfs_energy.h b/energy/debugfs_energy.h
deleted file mode 100644 (file)
index e4b5e32..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef _DEBUGFS_ENERGY_H
-#define _DEBUGFS_ENERGY_H
-
-/**
- * @file energy/debugfs_energy.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- * Debugfs for energy
- */
-
-
-#include <linux/fs.h>
-#include <master/swap_initializer.h>
-
-
-struct dentry;
-
-
-/* based on define DEFINE_SIMPLE_ATTRIBUTE */
-#define SWAP_DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)      \
-static int __fops ## _open(struct inode *inode, struct file *file)     \
-{                                                                      \
-       int ret;                                                        \
-                                                                       \
-       ret = swap_init_simple_open(inode, file);                       \
-       if (ret)                                                        \
-               return ret;                                             \
-                                                                       \
-       __simple_attr_check_format(__fmt, 0ull);                        \
-       ret = simple_attr_open(inode, file, __get, __set, __fmt);       \
-       if (ret)                                                        \
-               swap_init_simple_release(inode, file);                  \
-                                                                       \
-       return ret;                                                     \
-}                                                                      \
-static int __fops ## _release(struct inode *inode, struct file *file)  \
-{                                                                      \
-       simple_attr_release(inode, file);                               \
-       swap_init_simple_release(inode, file);                          \
-                                                                       \
-       return 0;                                                       \
-}                                                                      \
-static const struct file_operations __fops = {                         \
-       .owner   = THIS_MODULE,                                         \
-       .open    = __fops ## _open,                                     \
-       .release = __fops ## _release,                                  \
-       .read    = simple_attr_read,                                    \
-       .write   = simple_attr_write,                                   \
-       .llseek  = generic_file_llseek,                                 \
-}
-
-
-int init_debugfs_energy(void);
-void exit_debugfs_energy(void);
-
-struct dentry *get_energy_dir(void);
-
-
-#endif /* _DEBUGFS_ENERGY_H */
diff --git a/energy/energy.c b/energy/energy.c
deleted file mode 100644 (file)
index 49ac721..0000000
+++ /dev/null
@@ -1,1353 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/energy/swap_energy.c
- *
- * 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, 2013
- *
- * 2013         Vasiliy Ulyanov <v.ulyanov@samsung.com>
- *              Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/file.h>
-#include <linux/spinlock.h>
-#include <linux/magic.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/net.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include <linux/fdtable.h>
-#include <net/sock.h>
-#include <ksyms/ksyms.h>
-#include <master/swap_deps.h>
-#include <swap-asm/swap_kprobes.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_feature.h>
-#include <linux/atomic.h>
-
-#ifdef CONFIG_SWAP_HOOK_SWITCH_TO
-# include <swap/hook_switch_to.h>
-#else /* CONFIG_SWAP_HOOK_SWITCH_TO */
-# include <kprobe/swap_kprobes.h>
-#endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
-
-#ifdef CONFIG_SWAP_HOOK_ENERGY
-# include <swap/hook_syscall.h>
-# include <swap/hook_energy.h>
-# include <kprobe/swap_td_raw.h>
-#else /* CONFIG_SWAP_HOOK_ENERGY */
-# include <kprobe/swap_kprobes.h>
-#endif /* CONFIG_SWAP_HOOK_ENERGY */
-
-#include "energy.h"
-#include "lcd/lcd_base.h"
-#include "tm_stat.h"
-
-
-#ifndef CONFIG_SWAP_HOOK_ENERGY
-/* ============================================================================
- * =                              ENERGY_XXX                                  =
- * ============================================================================
- */
-struct kern_probe {
-       const char *name;
-       struct kretprobe *rp;
-};
-
-static int energy_xxx_once(struct kern_probe p[], int size)
-{
-       int i;
-       const char *sym;
-
-       for (i = 0; i < size; ++i) {
-               struct kretprobe *rp = p[i].rp;
-
-               sym = p[i].name;
-               rp->kp.addr = swap_ksyms(sym);
-               if (rp->kp.addr == 0)
-                       goto not_found;
-       }
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-static int energy_xxx_set(struct kern_probe p[], int size, int *flag)
-{
-       int i, ret;
-
-       for (i = 0; i < size; ++i) {
-               ret = swap_register_kretprobe(p[i].rp);
-               if (ret)
-                       goto fail;
-       }
-
-       *flag = 1;
-       return 0;
-
-fail:
-       pr_err("swap_register_kretprobe(%s) ret=%d\n", p[i].name, ret);
-
-       for (--i; i != -1; --i)
-               swap_unregister_kretprobe(p[i].rp);
-
-       return ret;
-}
-
-static void energy_xxx_unset(struct kern_probe p[], int size, int *flag)
-{
-       int i;
-
-       if (*flag == 0)
-               return;
-
-       for (i = size - 1; i != -1; --i)
-               swap_unregister_kretprobe(p[i].rp);
-
-       *flag = 0;
-}
-#endif /* CONFIG_SWAP_HOOK_ENERGY */
-
-
-
-
-
-/* ============================================================================
- * =                              CPUS_TIME                                   =
- * ============================================================================
- */
-struct cpus_time {
-       spinlock_t lock; /* for concurrent access */
-       struct tm_stat tm[NR_CPUS];
-};
-
-#define cpus_time_lock(ct, flags) spin_lock_irqsave(&(ct)->lock, flags)
-#define cpus_time_unlock(ct, flags) spin_unlock_irqrestore(&(ct)->lock, flags)
-
-static void cpus_time_init(struct cpus_time *ct, u64 time)
-{
-       int cpu;
-
-       spin_lock_init(&ct->lock);
-
-       for (cpu = 0; cpu < NR_CPUS; ++cpu) {
-               tm_stat_init(&ct->tm[cpu]);
-               tm_stat_set_timestamp(&ct->tm[cpu], time);
-       }
-}
-
-static inline u64 cpu_time_get_running(struct cpus_time *ct, int cpu, u64 now)
-{
-       return tm_stat_current_running(&ct->tm[cpu], now);
-}
-
-static void *cpus_time_get_running_all(struct cpus_time *ct, u64 *buf, u64 now)
-{
-       int cpu;
-
-       for (cpu = 0; cpu < NR_CPUS; ++cpu)
-               buf[cpu] = tm_stat_current_running(&ct->tm[cpu], now);
-
-       return buf;
-}
-
-static void *cpus_time_sum_running_all(struct cpus_time *ct, u64 *buf, u64 now)
-{
-       int cpu;
-
-       for (cpu = 0; cpu < NR_CPUS; ++cpu)
-               buf[cpu] += tm_stat_current_running(&ct->tm[cpu], now);
-
-       return buf;
-}
-
-static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
-{
-       struct tm_stat *tm = &ct->tm[cpu];
-
-       if (unlikely(tm_stat_timestamp(tm))) /* should never happen */
-               printk(KERN_INFO "XXX %s[%d/%d]: WARNING tmstamp(%p) set on cpu(%d)\n",
-                      current->comm, current->tgid, current->pid, tm, cpu);
-       tm_stat_set_timestamp(&ct->tm[cpu], time);
-}
-
-static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 now,
-                                    u64 start_time)
-{
-       struct tm_stat *tm = &ct->tm[cpu];
-
-       if (unlikely(tm_stat_timestamp(tm) == 0)) {
-               /* not initialized. should happen only once per cpu/task */
-               printk(KERN_INFO "XXX %s[%d/%d]: nnitializing tmstamp(%p) "
-                      "on cpu(%d)\n",
-                      current->comm, current->tgid, current->pid, tm, cpu);
-               tm_stat_set_timestamp(tm, start_time);
-       }
-
-       tm_stat_update(tm, now);
-       tm_stat_set_timestamp(tm, 0); /* set timestamp to 0 */
-}
-
-
-
-
-
-struct energy_data {
-       /* for __switch_to */
-       struct cpus_time ct;
-
-       /* for sys_read */
-       atomic64_t bytes_read;
-
-       /*for sys_write */
-       atomic64_t bytes_written;
-
-       /*for recvmsg*/
-       atomic64_t bytes_recv;
-
-       /* for sock_send */
-       atomic64_t bytes_send;
-
-       /* for l2cap_recv */
-       atomic64_t bytes_l2cap_recv_acldata;
-
-       /* for sco_recv_scodata */
-       atomic64_t bytes_sco_recv_scodata;
-
-       /* for hci_send_acl */
-       atomic64_t bytes_hci_send_acl;
-
-       /* for hci_send_sco */
-       atomic64_t bytes_hci_send_sco;
-};
-
-static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
-
-static void init_ed(struct energy_data *ed)
-{
-       /* instead of get_ntime(), CPU time is initialized to 0 here. Timestamp
-        * value will be properly set when the corresponding __switch_to event
-        * occurs */
-       cpus_time_init(&ed->ct, 0);
-       atomic64_set(&ed->bytes_read, 0);
-       atomic64_set(&ed->bytes_written, 0);
-       atomic64_set(&ed->bytes_recv, 0);
-       atomic64_set(&ed->bytes_send, 0);
-       atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
-       atomic64_set(&ed->bytes_sco_recv_scodata, 0);
-       atomic64_set(&ed->bytes_hci_send_acl, 0);
-       atomic64_set(&ed->bytes_hci_send_sco, 0);
-}
-
-static void uninit_ed(struct energy_data *ed)
-{
-       cpus_time_init(&ed->ct, 0);
-       atomic64_set(&ed->bytes_read, 0);
-       atomic64_set(&ed->bytes_written, 0);
-       atomic64_set(&ed->bytes_recv, 0);
-       atomic64_set(&ed->bytes_send, 0);
-       atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
-       atomic64_set(&ed->bytes_sco_recv_scodata, 0);
-       atomic64_set(&ed->bytes_hci_send_acl, 0);
-       atomic64_set(&ed->bytes_hci_send_sco, 0);
-}
-
-static void *create_ed(void)
-{
-       struct energy_data *ed;
-
-       ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
-       if (ed)
-               init_ed(ed);
-
-       return (void *)ed;
-}
-
-static void destroy_ed(void *data)
-{
-       struct energy_data *ed = (struct energy_data *)data;
-       kfree(ed);
-}
-
-
-static int init_feature(void)
-{
-       feature_id = sspt_register_feature(create_ed, destroy_ed);
-
-       if (feature_id == SSPT_FEATURE_ID_BAD)
-               return -EPERM;
-
-       return 0;
-}
-
-static void uninit_feature(void)
-{
-       sspt_unregister_feature(feature_id);
-       feature_id = SSPT_FEATURE_ID_BAD;
-}
-
-static struct energy_data *get_energy_data(struct task_struct *task)
-{
-       void *data = NULL;
-       struct sspt_proc *proc;
-
-       proc = sspt_proc_by_task(task);
-       if (proc)
-               data = sspt_get_feature_data(proc->feature, feature_id);
-
-       return (struct energy_data *)data;
-}
-
-static int check_fs(unsigned long magic)
-{
-       switch (magic) {
-       case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
-       case MSDOS_SUPER_MAGIC:
-               return 1;
-       }
-
-       return 0;
-}
-
-static int check_ftype(int fd)
-{
-       int err, ret = 0;
-       struct kstat kstat;
-
-       err = vfs_fstat(fd, &kstat);
-       if (err == 0 && S_ISREG(kstat.mode))
-               ret = 1;
-
-       return ret;
-}
-
-static int check_file(int fd)
-{
-       struct file *file;
-
-       file = fget(fd);
-       if (file) {
-               int magic = 0;
-               if (file->f_path.dentry && file->f_path.dentry->d_sb)
-                       magic = file->f_path.dentry->d_sb->s_magic;
-
-               fput(file);
-
-               if (check_fs(magic) && check_ftype(fd))
-                       return 1;
-       }
-
-       return 0;
-}
-
-
-
-
-
-static struct cpus_time ct_idle;
-static struct energy_data ed_system;
-static u64 start_time;
-
-static void init_data_energy(void)
-{
-       start_time = get_ntime();
-       init_ed(&ed_system);
-       cpus_time_init(&ct_idle, 0);
-}
-
-static void uninit_data_energy(void)
-{
-       start_time = 0;
-       uninit_ed(&ed_system);
-       cpus_time_init(&ct_idle, 0);
-}
-
-
-
-
-
-/* ============================================================================
- * =                             __switch_to                                  =
- * ============================================================================
- */
-static void do_entry_handler_switch(struct task_struct *task)
-{
-       int cpu;
-       struct cpus_time *ct;
-       struct energy_data *ed;
-       unsigned long flags;
-
-       cpu = smp_processor_id();
-
-       ct = task->tgid ? &ed_system.ct : &ct_idle;
-       cpus_time_lock(ct, flags);
-       cpus_time_update_running(ct, cpu, get_ntime(), start_time);
-       cpus_time_unlock(ct, flags);
-
-       ed = get_energy_data(task);
-       if (ed) {
-               ct = &ed->ct;
-               cpus_time_lock(ct, flags);
-               cpus_time_update_running(ct, cpu, get_ntime(), start_time);
-               cpus_time_unlock(ct, flags);
-       }
-}
-
-static void do_ret_handler_switch(struct task_struct *task)
-{
-       int cpu;
-       struct cpus_time *ct;
-       struct energy_data *ed;
-       unsigned long flags;
-
-       cpu = smp_processor_id();
-
-       ct = task->tgid ? &ed_system.ct : &ct_idle;
-       cpus_time_lock(ct, flags);
-       cpus_time_save_entry(ct, cpu, get_ntime());
-       cpus_time_unlock(ct, flags);
-
-       ed = get_energy_data(task);
-       if (ed) {
-               ct = &ed->ct;
-               cpus_time_lock(ct, flags);
-               cpus_time_save_entry(ct, cpu, get_ntime());
-               cpus_time_unlock(ct, flags);
-       }
-}
-
-#ifndef CONFIG_SWAP_HOOK_SWITCH_TO
-static int ret_handler_switch(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       do_ret_handler_switch(current);
-       return 0;
-}
-
-static int entry_handler_switch(struct kretprobe_instance *ri,
-                               struct pt_regs *regs)
-{
-       do_entry_handler_switch(current);
-       return 0;
-}
-
-static struct kretprobe switch_to_krp = {
-       .entry_handler = entry_handler_switch,
-       .handler = ret_handler_switch,
-};
-#endif /* !CONFIG_SWAP_HOOK_SWITCH_TO */
-
-
-
-
-
-/* ============================================================================
- * =                                sys_read                                  =
- * ============================================================================
- */
-struct sys_read_data {
-       int fd;
-};
-
-#ifndef CONFIG_SWAP_HOOK_ENERGY
-static int entry_handler_sys_read(struct kretprobe_instance *ri,
-                                 struct pt_regs *regs)
-{
-       struct sys_read_data *srd = (struct sys_read_data *)ri->data;
-
-       srd->fd = (int)swap_get_sarg(regs, 0);
-
-       return 0;
-}
-
-static int ret_handler_sys_read(struct kretprobe_instance *ri,
-                               struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-
-       if (ret > 0) {
-               struct sys_read_data *srd;
-
-               srd = (struct sys_read_data *)ri->data;
-               if (check_file(srd->fd)) {
-                       struct energy_data *ed;
-
-                       ed = get_energy_data(current);
-                       if (ed)
-                               atomic64_add(ret, &ed->bytes_read);
-
-                       atomic64_add(ret, &ed_system.bytes_read);
-               }
-       }
-
-       return 0;
-}
-
-static struct kretprobe sys_read_krp = {
-       .entry_handler = entry_handler_sys_read,
-       .handler = ret_handler_sys_read,
-       .data_size = sizeof(struct sys_read_data)
-};
-
-
-
-
-
-/* ============================================================================
- * =                               sys_write                                  =
- * ============================================================================
- */
-static int entry_handler_sys_write(struct kretprobe_instance *ri,
-                                  struct pt_regs *regs)
-{
-       struct sys_read_data *srd = (struct sys_read_data *)ri->data;
-
-       srd->fd = (int)swap_get_sarg(regs, 0);
-
-       return 0;
-}
-
-static int ret_handler_sys_write(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-
-       if (ret > 0) {
-               struct sys_read_data *srd;
-
-               srd = (struct sys_read_data *)ri->data;
-               if (check_file(srd->fd)) {
-                       struct energy_data *ed;
-
-                       ed = get_energy_data(current);
-                       if (ed)
-                               atomic64_add(ret, &ed->bytes_written);
-
-                       atomic64_add(ret, &ed_system.bytes_written);
-               }
-       }
-
-       return 0;
-}
-
-static struct kretprobe sys_write_krp = {
-       .entry_handler = entry_handler_sys_write,
-       .handler = ret_handler_sys_write,
-       .data_size = sizeof(struct sys_read_data)
-};
-#endif /* !CONFIG_SWAP_HOOK_ENERGY */
-
-
-
-
-
-/* ============================================================================
- * =                                wifi                                      =
- * ============================================================================
- */
-static bool check_wlan0(struct socket *sock)
-{
-       /* FIXME: hardcode interface */
-       const char *name_intrf = "wlan0";
-
-       if (sock->sk->sk_dst_cache &&
-           sock->sk->sk_dst_cache->dev &&
-           !strcmp(sock->sk->sk_dst_cache->dev->name, name_intrf))
-               return true;
-
-       return false;
-}
-
-static bool check_socket(struct task_struct *task, struct socket *socket)
-{
-       bool ret = false;
-       unsigned int fd;
-       struct files_struct *files;
-
-       files = swap_get_files_struct(task);
-       if (files == NULL)
-               return false;
-
-       rcu_read_lock();
-       for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
-               if (fcheck_files(files, fd) == socket->file) {
-                       ret = true;
-                       goto unlock;
-               }
-       }
-
-unlock:
-       rcu_read_unlock();
-       swap_put_files_struct(files);
-       return ret;
-}
-
-static struct energy_data *get_energy_data_by_socket(struct task_struct *task,
-                                                    struct socket *socket)
-{
-       struct energy_data *ed;
-
-       ed = get_energy_data(task);
-       if (ed)
-               ed = check_socket(task, socket) ? ed : NULL;
-
-       return ed;
-}
-
-#ifndef CONFIG_SWAP_HOOK_ENERGY
-static int wf_sock_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct socket *socket = (struct socket *)swap_get_karg(regs, 0);
-
-       *(struct socket **)ri->data = socket;
-
-       return 0;
-}
-
-static int wf_sock_aio_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct kiocb *iocb = (struct kiocb *)swap_get_karg(regs, 0);
-       struct socket *socket = iocb->ki_filp->private_data;
-
-       *(struct socket **)ri->data = socket;
-
-       return 0;
-}
-#endif /* CONFIG_SWAP_HOOK_ENERGY */
-
-static void calc_wifi_recv_energy(struct socket *sock, int len)
-{
-       struct energy_data *ed;
-
-       if (len <= 0 || !check_wlan0(sock))
-               return;
-
-       ed = get_energy_data_by_socket(current, sock);
-       if (ed)
-               atomic64_add(len, &ed->bytes_recv);
-       atomic64_add(len, &ed_system.bytes_recv);
-}
-
-static void calc_wifi_send_energy(struct socket *sock, int len)
-{
-       struct energy_data *ed;
-
-       if (len <= 0 || !check_wlan0(sock))
-               return;
-
-       ed = get_energy_data_by_socket(current, sock);
-       if (ed)
-               atomic64_add(len, &ed->bytes_send);
-       atomic64_add(len, &ed_system.bytes_send);
-}
-
-#ifndef CONFIG_SWAP_HOOK_ENERGY
-static int wf_sock_recv_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-
-       calc_wifi_recv_energy(*(struct socket **)ri->data, ret);
-
-       return 0;
-}
-
-static int wf_sock_send_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-
-       calc_wifi_send_energy(*(struct socket **)ri->data, ret);
-
-       return 0;
-}
-
-static struct kretprobe sock_recv_krp = {
-       .entry_handler = wf_sock_eh,
-       .handler = wf_sock_recv_rh,
-       .data_size = sizeof(struct socket *)
-};
-
-static struct kretprobe sock_send_krp = {
-       .entry_handler = wf_sock_eh,
-       .handler = wf_sock_send_rh,
-       .data_size = sizeof(struct socket *)
-};
-
-static struct kretprobe sock_aio_read_krp = {
-       .entry_handler = wf_sock_aio_eh,
-       .handler = wf_sock_recv_rh,
-       .data_size = sizeof(struct socket *)
-};
-
-static struct kretprobe sock_aio_write_krp = {
-       .entry_handler = wf_sock_aio_eh,
-       .handler = wf_sock_send_rh,
-       .data_size = sizeof(struct socket *)
-};
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
-static const char sock_aio_read[] = "sock_read_iter";
-static const char sock_aio_write[] = "sock_write_iter";
-#else  /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
-static const char sock_aio_read[] = "sock_aio_read";
-static const char sock_aio_write[] = "sock_aio_write";
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
-
-static struct kern_probe wifi_probes[] = {
-       {
-               .name = "sock_recvmsg",
-               .rp = &sock_recv_krp,
-       },
-       {
-               .name = "sock_sendmsg",
-               .rp = &sock_send_krp,
-       },
-       {
-               .name = sock_aio_read,
-               .rp = &sock_aio_read_krp,
-       },
-       {
-               .name = sock_aio_write,
-               .rp = &sock_aio_write_krp,
-       }
-};
-
-enum { wifi_probes_cnt = ARRAY_SIZE(wifi_probes) };
-static int wifi_flag = 0;
-#endif /* !CONFIG_SWAP_HOOK_ENERGY */
-
-
-
-
-
-/* ============================================================================
- * =                                bluetooth                                 =
- * ============================================================================
- */
-
-struct swap_bt_data {
-       struct socket *socket;
-};
-
-static void calc_bt_recv_energy(struct socket *sock, int len)
-{
-       struct energy_data *ed;
-
-       if (len <= 0 || !sock)
-               return;
-
-       ed = get_energy_data_by_socket(current, sock);
-       if (ed)
-               atomic64_add(len, &ed->bytes_l2cap_recv_acldata);
-       atomic64_add(len, &ed_system.bytes_l2cap_recv_acldata);
-}
-
-static void calc_bt_send_energy(struct socket *sock, int len)
-{
-       struct energy_data *ed;
-
-       if (len <= 0 || !sock)
-               return;
-
-       ed = get_energy_data_by_socket(current, sock);
-       if (ed)
-               atomic64_add(len, &ed->bytes_hci_send_sco);
-       atomic64_add(len, &ed_system.bytes_hci_send_sco);
-}
-
-#ifndef CONFIG_SWAP_HOOK_ENERGY
-static int bt_entry_handler(struct kretprobe_instance *ri,
-                           struct pt_regs *regs)
-{
-       struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
-       struct socket *sock = (struct socket *)swap_get_sarg(regs, 1);
-
-       data->socket = sock ? sock : NULL;
-
-       return 0;
-}
-
-static int bt_recvmsg_handler(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
-
-       calc_bt_recv_energy(data->socket, ret);
-
-       return 0;
-}
-
-static int bt_sendmsg_handler(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
-
-       calc_bt_send_energy(data->socket, ret);
-
-       return 0;
-}
-
-static struct kretprobe rfcomm_sock_recvmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_recvmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kretprobe l2cap_sock_recvmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_recvmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kretprobe hci_sock_recvmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_recvmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kretprobe sco_sock_recvmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_recvmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-static struct kretprobe rfcomm_sock_sendmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_sendmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kretprobe l2cap_sock_sendmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_sendmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kretprobe hci_sock_sendmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_sendmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kretprobe sco_sock_sendmsg_krp = {
-       .entry_handler = bt_entry_handler,
-       .handler = bt_sendmsg_handler,
-       .data_size = sizeof(struct swap_bt_data)
-};
-
-static struct kern_probe bt_probes[] = {
-       {
-               .name = "rfcomm_sock_recvmsg",
-               .rp = &rfcomm_sock_recvmsg_krp,
-       },
-       {
-               .name = "l2cap_sock_recvmsg",
-               .rp = &l2cap_sock_recvmsg_krp,
-       },
-       {
-               .name = "hci_sock_recvmsg",
-               .rp = &hci_sock_recvmsg_krp,
-       },
-       {
-               .name = "sco_sock_recvmsg",
-               .rp = &sco_sock_recvmsg_krp,
-       },
-       {
-               .name = "rfcomm_sock_sendmsg",
-               .rp = &rfcomm_sock_sendmsg_krp,
-       },
-       {
-               .name = "l2cap_sock_sendmsg",
-               .rp = &l2cap_sock_sendmsg_krp,
-       },
-       {
-               .name = "hci_sock_sendmsg",
-               .rp = &hci_sock_sendmsg_krp,
-       },
-       {
-               .name = "sco_sock_sendmsg",
-               .rp = &sco_sock_sendmsg_krp,
-       }
-};
-
-enum { bt_probes_cnt = ARRAY_SIZE(bt_probes) };
-static int energy_bt_flag = 0;
-#endif /* CONFIG_SWAP_HOOK_ENERGY */
-
-enum parameter_type {
-       PT_CPU,
-       PT_READ,
-       PT_WRITE,
-       PT_WF_RECV,
-       PT_WF_SEND,
-       PT_L2CAP_RECV,
-       PT_SCO_RECV,
-       PT_SEND_ACL,
-       PT_SEND_SCO
-};
-
-struct cmd_pt {
-       enum parameter_type pt;
-       void *buf;
-       int sz;
-};
-
-static void callback_for_proc(struct sspt_proc *proc, void *data)
-{
-       void *f_data = sspt_get_feature_data(proc->feature, feature_id);
-       struct energy_data *ed = (struct energy_data *)f_data;
-
-       if (ed) {
-               unsigned long flags;
-               struct cmd_pt *cmdp = (struct cmd_pt *)data;
-               u64 *val = cmdp->buf;
-
-               switch (cmdp->pt) {
-               case PT_CPU:
-                       cpus_time_lock(&ed->ct, flags);
-                       cpus_time_sum_running_all(&ed->ct, val, get_ntime());
-                       cpus_time_unlock(&ed->ct, flags);
-                       break;
-               case PT_READ:
-                       *val += atomic64_read(&ed->bytes_read);
-                       break;
-               case PT_WRITE:
-                       *val += atomic64_read(&ed->bytes_written);
-                       break;
-               case PT_WF_RECV:
-                       *val += atomic64_read(&ed->bytes_recv);
-                       break;
-               case PT_WF_SEND:
-                       *val += atomic64_read(&ed->bytes_send);
-                       break;
-               case PT_L2CAP_RECV:
-                       *val += atomic64_read(&ed->bytes_l2cap_recv_acldata);
-                       break;
-               case PT_SCO_RECV:
-                       *val += atomic64_read(&ed->bytes_sco_recv_scodata);
-                       break;
-               case PT_SEND_ACL:
-                       *val += atomic64_read(&ed->bytes_hci_send_acl);
-                       break;
-               case PT_SEND_SCO:
-                       *val += atomic64_read(&ed->bytes_hci_send_sco);
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
-static int current_parameter_apps(enum parameter_type pt, void *buf, int sz)
-{
-       struct cmd_pt cmdp;
-
-       cmdp.pt = pt;
-       cmdp.buf = buf;
-       cmdp.sz = sz;
-
-       on_each_proc(callback_for_proc, (void *)&cmdp);
-
-       return 0;
-}
-
-/**
- * @brief Get energy parameter
- *
- * @param pe Type of energy parameter
- * @param buf Buffer
- * @param sz Buffer size
- * @return Error code
- */
-int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz)
-{
-       unsigned long flags;
-       u64 *val = buf; /* currently all parameters are u64 vals */
-       int ret = 0;
-
-       switch (pe) {
-       case PE_TIME_IDLE:
-               cpus_time_lock(&ct_idle, flags);
-               /* for the moment we consider only CPU[0] idle time */
-               *val = cpu_time_get_running(&ct_idle, 0, get_ntime());
-               cpus_time_unlock(&ct_idle, flags);
-               break;
-       case PE_TIME_SYSTEM:
-               cpus_time_lock(&ed_system.ct, flags);
-               cpus_time_get_running_all(&ed_system.ct, val, get_ntime());
-               cpus_time_unlock(&ed_system.ct, flags);
-               break;
-       case PE_TIME_APPS:
-               current_parameter_apps(PT_CPU, buf, sz);
-               break;
-       case PE_READ_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_read);
-               break;
-       case PE_WRITE_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_written);
-               break;
-       case PE_WF_RECV_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_recv);
-               break;
-       case PE_WF_SEND_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_send);
-               break;
-       case PE_L2CAP_RECV_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_l2cap_recv_acldata);
-               break;
-       case PE_SCO_RECV_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_sco_recv_scodata);
-               break;
-       case PT_SEND_ACL_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_hci_send_acl);
-               break;
-       case PT_SEND_SCO_SYSTEM:
-               *val = atomic64_read(&ed_system.bytes_hci_send_sco);
-               break;
-       case PE_READ_APPS:
-               current_parameter_apps(PT_READ, buf, sz);
-               break;
-       case PE_WRITE_APPS:
-               current_parameter_apps(PT_WRITE, buf, sz);
-               break;
-       case PE_WF_RECV_APPS:
-               current_parameter_apps(PT_WF_RECV, buf, sz);
-               break;
-       case PE_WF_SEND_APPS:
-               current_parameter_apps(PT_WF_SEND, buf, sz);
-               break;
-       case PE_L2CAP_RECV_APPS:
-               current_parameter_apps(PT_L2CAP_RECV, buf, sz);
-               break;
-       case PE_SCO_RECV_APPS:
-               current_parameter_apps(PT_SCO_RECV, buf, sz);
-               break;
-       case PT_SEND_ACL_APPS:
-               current_parameter_apps(PT_SEND_ACL, buf, sz);
-               break;
-       case PT_SEND_SCO_APPS:
-               current_parameter_apps(PT_SEND_SCO, buf, sz);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-#ifdef CONFIG_SWAP_HOOK_ENERGY
-static struct swap_hook_energy hook_energy = {
-       .bt_recvmsg = calc_bt_recv_energy,
-       .bt_sendmsg = calc_bt_send_energy,
-       .wifi_recvmsg = calc_wifi_recv_energy ,
-       .wifi_sendmsg = calc_wifi_send_energy
-};
-
-
-static struct td_raw sys_call_tdraw;
-
-static void entry_hook_sys_rw(struct hook_syscall *self, struct pt_regs *regs)
-{
-       struct sys_read_data *srd =
-               (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
-       srd->fd = (int)swap_get_sarg(regs, 0);
-}
-
-static void return_hook_sys_read(struct hook_syscall *self,
-                                struct pt_regs *regs)
-{
-       struct sys_read_data *srd;
-       struct energy_data *ed;
-       int ret = regs_return_value(regs);
-
-       if (ret <= 0)
-               return;
-
-       srd = (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
-       if (!check_file(srd->fd))
-               return;
-
-       ed = get_energy_data(current);
-       if (ed)
-               atomic64_add(ret, &ed->bytes_read);
-       atomic64_add(ret, &ed_system.bytes_read);
-}
-
-static void return_hook_sys_write(struct hook_syscall *self,
-                                 struct pt_regs *regs)
-{
-       struct sys_read_data *srd;
-       struct energy_data *ed;
-       int ret = regs_return_value(regs);
-
-       if (ret > 0)
-               return;
-
-       srd = (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
-       if (!check_file(srd->fd))
-               return;
-
-       ed = get_energy_data(current);
-       if (ed)
-               atomic64_add(ret, &ed->bytes_written);
-       atomic64_add(ret, &ed_system.bytes_written);
-}
-
-static struct hook_syscall sys_read_hook = {
-       .entry = entry_hook_sys_rw,
-       .exit = return_hook_sys_read
-};
-
-static struct hook_syscall sys_write_hook = {
-       .entry = entry_hook_sys_rw,
-       .exit = return_hook_sys_write
-};
-
-
-# ifdef CONFIG_SWAP_HOOK_SWITCH_TO
-static void handler_switch(struct task_struct *prev,
-                          struct task_struct *next)
-{
-       do_entry_handler_switch(prev);
-       do_ret_handler_switch(next);
-}
-
-static struct swap_hook_ctx switch_to_hook = {
-       .hook = handler_switch
-};
-# endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
-
-int do_set_energy(void)
-{
-       int ret = 0;
-
-       init_data_energy();
-
-       swap_hook_ctx_reg(&switch_to_hook);
-       ret = swap_td_raw_reg(&sys_call_tdraw, sizeof(struct sys_read_data));
-       if (ret)
-               return ret;
-
-       hook_syscall_reg(&sys_read_hook, __NR_read);
-       hook_syscall_reg(&sys_write_hook, __NR_write);
-
-       /* TODO: add compat mode support */
-
-       swap_hook_energy_set(&hook_energy);
-       /* TODO: init lcd */
-
-       return ret;
-}
-
-void do_unset_energy(void)
-{
-       /* TODO: uinit lcd */
-       swap_hook_energy_unset();
-       swap_hook_ctx_unreg(&switch_to_hook);
-       hook_syscall_unreg(&sys_write_hook);
-       hook_syscall_unreg(&sys_read_hook);
-
-       swap_td_raw_unreg(&sys_call_tdraw);
-       uninit_data_energy();
-}
-
-int energy_once(void)
-{
-       return 0;
-}
-#else /* CONFIG_SWAP_HOOK_ENERGY */
-
-int do_set_energy(void)
-{
-       int ret = 0;
-
-       init_data_energy();
-
-       ret = swap_register_kretprobe(&sys_read_krp);
-       if (ret) {
-               printk(KERN_INFO "swap_register_kretprobe(sys_read) "
-                      "result=%d!\n", ret);
-               return ret;
-       }
-
-       ret = swap_register_kretprobe(&sys_write_krp);
-       if (ret != 0) {
-               printk(KERN_INFO "swap_register_kretprobe(sys_write) "
-                      "result=%d!\n", ret);
-               goto unregister_sys_read;
-       }
-
-       ret = swap_register_kretprobe(&switch_to_krp);
-       if (ret) {
-               printk(KERN_INFO "swap_register_kretprobe(__switch_to) "
-                      "result=%d!\n",
-                      ret);
-               goto unregister_sys_write;
-       }
-
-       energy_xxx_set(bt_probes, bt_probes_cnt, &energy_bt_flag);
-       energy_xxx_set(wifi_probes, wifi_probes_cnt, &wifi_flag);
-
-       /* TODO: check return value */
-       lcd_set_energy();
-
-       return ret;
-
-unregister_sys_read:
-       swap_unregister_kretprobe(&sys_read_krp);
-
-unregister_sys_write:
-       swap_unregister_kretprobe(&sys_write_krp);
-
-       return ret;
-}
-
-void do_unset_energy(void)
-{
-       lcd_unset_energy();
-       energy_xxx_unset(wifi_probes, wifi_probes_cnt, &wifi_flag);
-       energy_xxx_unset(bt_probes, bt_probes_cnt, &energy_bt_flag);
-
-       swap_unregister_kretprobe(&switch_to_krp);
-       swap_unregister_kretprobe(&sys_write_krp);
-       swap_unregister_kretprobe(&sys_read_krp);
-
-       uninit_data_energy();
-}
-
-int energy_once(void)
-{
-       const char *sym;
-
-       sym = "__switch_to";
-       switch_to_krp.kp.addr = swap_ksyms(sym);
-       if (switch_to_krp.kp.addr == 0)
-               goto not_found;
-
-       sym = "sys_read";
-       sys_read_krp.kp.addr = swap_ksyms(sym);
-       if (sys_read_krp.kp.addr == 0)
-               goto not_found;
-
-       sym = "sys_write";
-       sys_write_krp.kp.addr = swap_ksyms(sym);
-       if (sys_write_krp.kp.addr == 0)
-               goto not_found;
-
-       energy_xxx_once(bt_probes, bt_probes_cnt);
-       energy_xxx_once(wifi_probes, wifi_probes_cnt);
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-#endif /* CONFIG_SWAP_HOOK_ENERGY */
-
-static DEFINE_MUTEX(mutex_enable);
-static int energy_enable;
-
-/**
- * @brief Start measuring the energy consumption
- *
- * @return Error code
- */
-int set_energy(void)
-{
-       int ret = -EINVAL;
-
-       mutex_lock(&mutex_enable);
-       if (energy_enable) {
-               printk(KERN_INFO "energy profiling is already run!\n");
-               goto unlock;
-       }
-
-       ret = do_set_energy();
-       if (ret == 0)
-               energy_enable = 1;
-
-unlock:
-       mutex_unlock(&mutex_enable);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(set_energy);
-
-/**
- * @brief Stop measuring the energy consumption
- *
- * @return Error code
- */
-int unset_energy(void)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_enable);
-       if (energy_enable == 0) {
-               printk(KERN_INFO "energy profiling is not running!\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       do_unset_energy();
-
-       energy_enable = 0;
-unlock:
-       mutex_unlock(&mutex_enable);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(unset_energy);
-
-/**
- * @brief Initialization energy
- *
- * @return Error code
- */
-int energy_init(void)
-{
-       int ret;
-
-       ret = init_feature();
-       if (ret)
-               printk(KERN_INFO "Cannot init feature\n");
-
-       return ret;
-}
-
-/**
- * @brief Deinitialization energy
- *
- * @return Void
- */
-void energy_uninit(void)
-{
-       uninit_feature();
-
-       if (energy_enable)
-               do_unset_energy();
-}
diff --git a/energy/energy.h b/energy/energy.h
deleted file mode 100644 (file)
index 7466570..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef _ENERGY_H
-#define _ENERGY_H
-
-/**
- * @file energy/energy.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENCE
- * 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
- *
- */
-
-
-#include <linux/types.h>
-
-
-/** Description of parameters */
-enum parameter_energy {
-       PE_TIME_IDLE,           /**< IDLE working time */
-       PE_TIME_SYSTEM,         /**< system working time */
-       PE_TIME_APPS,           /**< apps working time */
-       PE_READ_SYSTEM,         /**< number of bytes are read by system */
-       PE_WRITE_SYSTEM,        /**< number of bytes are write by system */
-       PE_READ_APPS,           /**< number of bytes are read by apps */
-       PE_WRITE_APPS,          /**< number of bytes are write by apps */
-       PE_WF_RECV_SYSTEM,      /**< number of bytes are receive by system through wifi */
-       PE_WF_SEND_SYSTEM,      /**< number of bytes are send by system through wifi */
-       PE_WF_RECV_APPS,        /**< number of bytes are receive by apps through wifi */
-       PE_WF_SEND_APPS,        /**< number of bytes are send by apps through wifi */
-       PE_L2CAP_RECV_SYSTEM,   /**< number of bytes(ACL packets) are recv by system through bluetooth */
-       PE_L2CAP_RECV_APPS,     /**< number of bytes(ACL packets) are recv by apps through bluetooth */
-       PE_SCO_RECV_SYSTEM,     /**< number of bytes(SCO packets) are recv by system through bluetooth */
-       PE_SCO_RECV_APPS,       /**< number of bytes(SCO packets) are recv by apps through bluetooth */
-       PT_SEND_ACL_SYSTEM,     /**< number of bytes(ACL packets) are send by system through bluetooth */
-       PT_SEND_ACL_APPS,       /**< number of bytes(ACL packets) are send by apps through bluetooth */
-       PT_SEND_SCO_SYSTEM,     /**< number of bytes(SCO packets) are send by system through bluetooth */
-       PT_SEND_SCO_APPS,       /**< number of bytes(SCO packets) are send by apps through bluetooth */
-};
-
-
-int energy_once(void);
-int energy_init(void);
-void energy_uninit(void);
-
-int set_energy(void);
-int unset_energy(void);
-
-int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz);
-
-#endif /* _ENERGY_H */
diff --git a/energy/energy_module.c b/energy/energy_module.c
deleted file mode 100644 (file)
index b4ac328..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  energy/energy_mod.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "energy.h"
-#include "debugfs_energy.h"
-
-
-SWAP_LIGHT_INIT_MODULE(energy_once, energy_init, energy_uninit,
-                      init_debugfs_energy, exit_debugfs_energy);
-
-MODULE_LICENSE("GPL");
diff --git a/energy/lcd/lcd_base.c b/energy/lcd/lcd_base.c
deleted file mode 100644 (file)
index 12ee466..0000000
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  energy/lcd/lcd_base.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/fb.h>
-#include <energy/tm_stat.h>
-#include <energy/debugfs_energy.h>
-#include "lcd_base.h"
-#include "lcd_debugfs.h"
-
-
-/**
- * @brief Read the number of file
- *
- * @param path of the file
- * @return Value or error(when negative)
- */
-int read_val(const char *path)
-{
-       int ret;
-       struct file *f;
-       unsigned long val;
-       enum { buf_len = 32 };
-       char buf[buf_len];
-
-       f = filp_open(path, O_RDONLY, 0);
-       if (IS_ERR(f)) {
-               printk(KERN_INFO "cannot open file \'%s\'", path);
-               return PTR_ERR(f);
-       }
-
-       ret = kernel_read(f, 0, buf, sizeof(buf));
-       filp_close(f, NULL);
-       if (ret < 0)
-               return ret;
-
-       buf[ret >= buf_len ? buf_len - 1 : ret] = '\0';
-
-       ret = kstrtoul(buf, 0, &val);
-       if (ret)
-               return ret;
-
-       return (int)val;
-}
-
-enum {
-       brt_no_init = -1,
-       brt_cnt = 10
-};
-
-enum power_t {
-       PW_ON,
-       PW_OFF
-};
-
-struct lcd_priv_data {
-       int min_brt;
-       int max_brt;
-
-       size_t tms_brt_cnt;
-       struct tm_stat *tms_brt;
-       spinlock_t lock_tms;
-       int brt_old;
-       enum power_t power;
-
-       u64 min_denom;
-       u64 min_num;
-       u64 max_denom;
-       u64 max_num;
-};
-
-static void *create_lcd_priv(struct lcd_ops *ops, size_t tms_brt_cnt)
-{
-       int i;
-       struct lcd_priv_data *lcd;
-
-       if (tms_brt_cnt <= 0) {
-               printk(KERN_INFO "error variable tms_brt_cnt=%zu\n",
-                      tms_brt_cnt);
-               return NULL;
-       }
-
-       lcd = kmalloc(sizeof(*lcd) + sizeof(*lcd->tms_brt) * tms_brt_cnt,
-                     GFP_KERNEL);
-       if (lcd == NULL) {
-               printk(KERN_INFO "error: %s - out of memory\n", __func__);
-               return NULL;
-       }
-
-       lcd->tms_brt = (void *)lcd + sizeof(*lcd);
-       lcd->tms_brt_cnt = tms_brt_cnt;
-
-       lcd->min_brt = ops->get(ops, LPD_MIN_BRIGHTNESS);
-       lcd->max_brt = ops->get(ops, LPD_MAX_BRIGHTNESS);
-
-       for (i = 0; i < tms_brt_cnt; ++i)
-               tm_stat_init(&lcd->tms_brt[i]);
-
-       spin_lock_init(&lcd->lock_tms);
-
-       lcd->brt_old = brt_no_init;
-       lcd->power = PW_OFF;
-
-       lcd->min_denom = 1;
-       lcd->min_num = 1;
-       lcd->max_denom = 1;
-       lcd->max_num = 1;
-
-       return (void *)lcd;
-}
-
-static void destroy_lcd_priv(void *data)
-{
-       kfree(data);
-}
-
-static struct lcd_priv_data *get_lcd_priv(struct lcd_ops *ops)
-{
-       return (struct lcd_priv_data *)ops->priv;
-}
-
-static void clean_brightness(struct lcd_ops *ops)
-{
-       struct lcd_priv_data *lcd = get_lcd_priv(ops);
-       int i;
-
-       spin_lock(&lcd->lock_tms);
-       for (i = 0; i < lcd->tms_brt_cnt; ++i)
-               tm_stat_init(&lcd->tms_brt[i]);
-
-       lcd->brt_old = brt_no_init;
-       spin_unlock(&lcd->lock_tms);
-}
-
-static int get_brt_num_of_array(struct lcd_priv_data *lcd, int brt)
-{
-       if (brt > lcd->max_brt || brt < lcd->min_brt) {
-               printk(KERN_INFO "LCD energy error: set brightness=%d, "
-                      "when brightness[%d..%d]\n",
-                      brt, lcd->min_brt, lcd->max_brt);
-               brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt;
-       }
-
-       return lcd->tms_brt_cnt * (brt - lcd->min_brt) /
-              (lcd->max_brt - lcd->min_brt + 1);
-}
-
-static void set_brightness(struct lcd_ops *ops, int brt)
-{
-       struct lcd_priv_data *lcd = get_lcd_priv(ops);
-       int n = get_brt_num_of_array(lcd, brt);
-
-       spin_lock(&lcd->lock_tms);
-
-       if (lcd->power == PW_ON && lcd->brt_old != n) {
-               u64 time = get_ntime();
-               if (lcd->brt_old != brt_no_init)
-                       tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
-
-               tm_stat_set_timestamp(&lcd->tms_brt[n], time);
-       }
-       lcd->brt_old = n;
-
-       spin_unlock(&lcd->lock_tms);
-}
-
-static void set_power_on_set_brt(struct lcd_priv_data *lcd)
-{
-       if (lcd->brt_old != brt_no_init) {
-               u64 time = get_ntime();
-               tm_stat_set_timestamp(&lcd->tms_brt[lcd->brt_old], time);
-       }
-}
-
-static void set_power_on(struct lcd_priv_data *lcd)
-{
-       if (lcd->power == PW_OFF)
-               set_power_on_set_brt(lcd);
-
-       lcd->power = PW_ON;
-}
-
-static void set_power_off_update_brt(struct lcd_priv_data *lcd)
-{
-       if (lcd->brt_old != brt_no_init) {
-               u64 time = get_ntime();
-               tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
-               lcd->brt_old = brt_no_init;
-       }
-}
-
-static void set_power_off(struct lcd_priv_data *lcd)
-{
-       if (lcd->power == PW_ON)
-               set_power_off_update_brt(lcd);
-
-       lcd->power = PW_OFF;
-}
-
-static void set_power(struct lcd_ops *ops, int val)
-{
-       struct lcd_priv_data *lcd = get_lcd_priv(ops);
-
-       spin_lock(&lcd->lock_tms);
-
-       switch (val) {
-       case FB_BLANK_UNBLANK:
-               set_power_on(lcd);
-               break;
-       case FB_BLANK_POWERDOWN:
-               set_power_off(lcd);
-               break;
-       default:
-               printk(KERN_INFO "LCD energy error: set power=%d\n", val);
-               break;
-       }
-
-       spin_unlock(&lcd->lock_tms);
-}
-
-static int func_notifier_lcd(struct lcd_ops *ops, enum lcd_action_type action,
-                            void *data)
-{
-       switch (action) {
-       case LAT_BRIGHTNESS:
-               set_brightness(ops, VOIDP2INT(data));
-               break;
-       case LAT_POWER:
-               set_power(ops, VOIDP2INT(data));
-               break;
-       default:
-               printk(KERN_INFO "LCD energy error: action=%d\n", action);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Get the array size of LCD
- *
- * @param ops LCD operations
- * @return Array size
- */
-size_t get_lcd_size_array(struct lcd_ops *ops)
-{
-       struct lcd_priv_data *lcd = get_lcd_priv(ops);
-
-       return lcd->tms_brt_cnt;
-}
-
-/**
- * @brief Get an array of times
- *
- * @param ops LCD operations
- * @param array_time[out] Array of times
- * @return Void
- */
-void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time)
-{
-       struct lcd_priv_data *lcd = get_lcd_priv(ops);
-       int i;
-
-       spin_lock(&lcd->lock_tms);
-       for (i = 0; i < lcd->tms_brt_cnt; ++i)
-               array_time[i] = tm_stat_running(&lcd->tms_brt[i]);
-
-       if (lcd->power == PW_ON && lcd->brt_old != brt_no_init) {
-               int old = lcd->brt_old;
-               struct tm_stat *tm = &lcd->tms_brt[old];
-
-               array_time[old] += get_ntime() - tm_stat_timestamp(tm);
-       }
-       spin_unlock(&lcd->lock_tms);
-}
-
-static int register_lcd(struct lcd_ops *ops)
-{
-       int ret = 0;
-
-       ops->priv = create_lcd_priv(ops, brt_cnt);
-
-       /* TODO: create init_func() for 'struct rational' */
-       ops->min_coef.num = 1;
-       ops->min_coef.denom = 1;
-       ops->max_coef.num = 1;
-       ops->max_coef.denom = 1;
-
-       ops->notifier = func_notifier_lcd;
-
-       ret = register_lcd_debugfs(ops);
-       if (ret)
-               destroy_lcd_priv(ops->priv);
-
-       return ret;
-}
-
-static void unregister_lcd(struct lcd_ops *ops)
-{
-       unregister_lcd_debugfs(ops);
-       destroy_lcd_priv(ops->priv);
-}
-
-
-
-
-/* ============================================================================
- * ===                          LCD_INIT/LCD_EXIT                           ===
- * ============================================================================
- */
-typedef struct lcd_ops *(*get_ops_t)(void);
-
-DEFINITION_LCD_FUNC;
-
-get_ops_t lcd_ops[] = DEFINITION_LCD_ARRAY;
-enum { lcd_ops_cnt = sizeof(lcd_ops) / sizeof(get_ops_t) };
-
-enum ST_LCD_OPS {
-       SLO_REGISTER    = 1 << 0,
-       SLO_SET         = 1 << 1
-};
-
-static DEFINE_MUTEX(lcd_lock);
-static enum ST_LCD_OPS stat_lcd_ops[lcd_ops_cnt];
-
-static void do_lcd_exit(void)
-{
-       int i;
-       struct lcd_ops *ops;
-
-       mutex_lock(&lcd_lock);
-       for (i = 0; i < lcd_ops_cnt; ++i) {
-               ops = lcd_ops[i]();
-
-               if (stat_lcd_ops[i] & SLO_SET) {
-                       ops->unset(ops);
-                       stat_lcd_ops[i] &= ~SLO_SET;
-               }
-
-               if (stat_lcd_ops[i] & SLO_REGISTER) {
-                       unregister_lcd(ops);
-                       stat_lcd_ops[i] &= ~SLO_REGISTER;
-               }
-       }
-       mutex_unlock(&lcd_lock);
-}
-
-/**
- * @brief LCD deinitialization
- *
- * @return Void
- */
-void lcd_exit(void)
-{
-       do_lcd_exit();
-}
-
-static int do_lcd_init(void)
-{
-       int i, ret, count = 0;
-       struct lcd_ops *ops;
-
-       mutex_lock(&lcd_lock);
-       for (i = 0; i < lcd_ops_cnt; ++i) {
-               ops = lcd_ops[i]();
-               if (ops == NULL) {
-                       printk(KERN_INFO "error %s [ops == NULL]\n", __func__);
-                       continue;
-               }
-
-               if (0 == ops->check(ops)) {
-                       printk(KERN_INFO "error checking %s\n", ops->name);
-                       continue;
-               }
-
-               ret = register_lcd(ops);
-               if (ret) {
-                       printk(KERN_INFO "error register_lcd %s\n", ops->name);
-                       continue;
-               }
-
-               stat_lcd_ops[i] |= SLO_REGISTER;
-               ++count;
-       }
-       mutex_unlock(&lcd_lock);
-
-       return count ? 0 : -EPERM;
-}
-
-/**
- * @brief LCD initialization
- *
- * @return Error code
- */
-int lcd_init(void)
-{
-       int ret;
-
-       ret = do_lcd_init();
-       if (ret)
-               printk(KERN_INFO "LCD is not supported\n");
-
-       return ret;
-}
-
-
-
-/* ============================================================================
- * ===                     LCD_SET_ENERGY/LCD_UNSET_ENERGY                  ===
- * ============================================================================
- */
-
-/**
- * @brief Start measuring the energy consumption of LСD
- *
- * @return Error code
- */
-int lcd_set_energy(void)
-{
-       int i, ret, count = 0;
-       struct lcd_ops *ops;
-
-       mutex_lock(&lcd_lock);
-       for (i = 0; i < lcd_ops_cnt; ++i) {
-               ops = lcd_ops[i]();
-               if (stat_lcd_ops[i] & SLO_REGISTER) {
-                       ret = ops->set(ops);
-                       if (ret) {
-                               printk(KERN_INFO "error %s set LCD energy",
-                                      ops->name);
-                               continue;
-                       }
-
-                       set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS));
-                       set_power(ops, ops->get(ops, LPD_POWER));
-
-                       stat_lcd_ops[i] |= SLO_SET;
-                       ++count;
-               }
-       }
-       mutex_unlock(&lcd_lock);
-
-       return count ? 0 : -EPERM;
-}
-
-/**
- * @brief Stop measuring the energy consumption of LСD
- *
- * @return Void
- */
-void lcd_unset_energy(void)
-{
-       int i, ret;
-       struct lcd_ops *ops;
-
-       mutex_lock(&lcd_lock);
-       for (i = 0; i < lcd_ops_cnt; ++i) {
-               ops = lcd_ops[i]();
-               if (stat_lcd_ops[i] & SLO_SET) {
-                       ret = ops->unset(ops);
-                       if (ret)
-                               printk(KERN_INFO "error %s unset LCD energy",
-                                      ops->name);
-
-                       clean_brightness(ops);
-                       stat_lcd_ops[i] &= ~SLO_SET;
-               }
-       }
-       mutex_unlock(&lcd_lock);
-}
diff --git a/energy/lcd/lcd_base.h b/energy/lcd/lcd_base.h
deleted file mode 100644 (file)
index 85d59c6..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef _LCD_BASE_H
-#define _LCD_BASE_H
-
-/**
- * @file energy/lcd/lcd_base.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- * Description of the interface for interacting with LСD
- */
-
-
-#include <linux/errno.h>
-#include <energy/rational_debugfs.h>
-
-
-#define VOIDP2INT(x)   ((int)(unsigned long)(x))
-#define INT2VOIDP(x)   ((void *)(unsigned long)(x))
-
-
-/** Description of actions */
-enum lcd_action_type {
-       LAT_BRIGHTNESS,         /**< LCD brightness */
-       LAT_POWER               /**< LCD power */
-};
-
-
-/** Description of parameters */
-enum lcd_parameter_type {
-       LPD_MIN_BRIGHTNESS,     /**< minimum brightness value */
-       LPD_MAX_BRIGHTNESS,     /**< maximum brightness value */
-       LPD_BRIGHTNESS,         /**< current brightness value */
-
-       LPD_POWER               /**< current power value */
-};
-
-struct lcd_ops;
-
-/**
- * @brief LCD callback type
- *
- * @param ops LCD operations
- * @return Error code
- */
-typedef int (*call_lcd)(struct lcd_ops *ops);
-
-/**
- * @brief LCD notifier type
- *
- * @param ops LCD operations
- * @param action Event type
- * @param data Date
- * @return Error code
- */
-typedef int (*notifier_lcd)(struct lcd_ops *ops, enum lcd_action_type action,
-                           void *data);
-
-/**
- * @brief LCD parameter type
- *
- * @param ops LCD operations
- * @param type Requested parameter type
- * @return Requested parameter value
- *
- */
-typedef unsigned long (*get_parameter_lcd)(struct lcd_ops *ops,
-                                          enum lcd_parameter_type type);
-
-
-/**
- * @struct lcd_ops
- * @breaf set of operations available for LСD
- */
-struct lcd_ops {
-       char *name;                     /**< LCD driver name */
-       notifier_lcd notifier;          /**< Notifier */
-       get_parameter_lcd get;          /**< Method to obtain the parameters */
-
-       call_lcd check;                 /**< LCD check on device */
-       call_lcd set;                   /**< LCD initialization */
-       call_lcd unset;                 /**< LCD deinitialization */
-
-       /* for debugfs */
-       struct dentry *dentry;          /**< Dentry of debugfs for this LCD */
-       struct rational min_coef;       /**< Minimum coefficient */
-       struct rational max_coef;       /**< Maximum coefficient */
-
-       void *priv;                     /**< Private data */
-};
-
-size_t get_lcd_size_array(struct lcd_ops *ops);
-void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time);
-
-int read_val(const char *path);
-
-int lcd_set_energy(void);
-void lcd_unset_energy(void);
-
-int lcd_init(void);
-void lcd_exit(void);
-
-#endif /* _LCD_BASE_H */
diff --git a/energy/lcd/lcd_debugfs.c b/energy/lcd/lcd_debugfs.c
deleted file mode 100644 (file)
index a3cac95..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  energy/lcd/lcd_debugfs.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <master/swap_debugfs.h>
-#include <energy/lcd/lcd_base.h>
-#include <energy/debugfs_energy.h>
-#include <energy/rational_debugfs.h>
-
-
-static int get_system(void *data, u64 *val)
-{
-       struct lcd_ops *ops = (struct lcd_ops *)data;
-       const size_t size = get_lcd_size_array(ops);
-       const size_t size_1 = size - 1;
-       u64 i_max, j_min, t, e = 0;
-       u64 *array_time;
-       int i, j;
-
-       array_time = kmalloc(sizeof(*array_time) * size, GFP_KERNEL);
-       if (array_time == NULL)
-               return -ENOMEM;
-
-       get_lcd_array_time(ops, array_time);
-
-       for (i = 0; i < size; ++i) {
-               t = array_time[i];
-
-               /* e = (i * max + (k - i) * min) * t / k */
-               j = size_1 - i;
-               i_max = div_u64(i * ops->max_coef.num * t,
-                               ops->max_coef.denom);
-               j_min = div_u64(j * ops->min_coef.num * t,
-                               ops->min_coef.denom);
-               e += div_u64(i_max + j_min, size_1);
-       }
-
-       kfree(array_time);
-
-       *val = e;
-
-       return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_system, get_system, NULL, "%llu\n");
-
-
-static struct dentry *lcd_dir;
-
-/**
- * @brief Register LCD in debugfs
- *
- * @param ops LCD operations
- * @return Error code
- */
-int register_lcd_debugfs(struct lcd_ops *ops)
-{
-       int ret;
-       struct dentry *dentry, *system;
-
-       if (lcd_dir == NULL)
-               return -EINVAL;
-
-       dentry = swap_debugfs_create_dir(ops->name, lcd_dir);
-       if (dentry == NULL)
-               return -ENOMEM;
-
-       ret = create_rational_files(dentry, &ops->min_coef,
-                                   "min_num", "min_denom");
-       if (ret)
-               goto fail;
-
-       ret = create_rational_files(dentry, &ops->max_coef,
-                                   "max_num", "max_denom");
-       if (ret)
-               goto fail;
-
-       system = swap_debugfs_create_file("system", 0600, dentry, (void *)ops,
-                                         &fops_get_system);
-       if (system == NULL)
-               goto fail;
-
-       ops->dentry = dentry;
-
-       return 0;
-fail:
-       debugfs_remove_recursive(dentry);
-       return -ENOMEM;
-}
-
-/**
- * @brief Unregister LCD in debugfs
- *
- * @param ops LCD operations
- * @return Void
- */
-void unregister_lcd_debugfs(struct lcd_ops *ops)
-{
-       debugfs_remove_recursive(ops->dentry);
-}
-
-/**
- * @brief Destroy debugfs for LCD
- *
- * @return Void
- */
-void exit_lcd_debugfs(void)
-{
-       if (lcd_dir)
-               debugfs_remove_recursive(lcd_dir);
-
-       lcd_dir = NULL;
-}
-
-/**
- * @brief Create debugfs for LCD
- *
- * @param dentry Dentry
- * @return Error code
- */
-int init_lcd_debugfs(struct dentry *energy_dir)
-{
-       lcd_dir = swap_debugfs_create_dir("lcd", energy_dir);
-       if (lcd_dir == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
diff --git a/energy/lcd/lcd_debugfs.h b/energy/lcd/lcd_debugfs.h
deleted file mode 100644 (file)
index 369748c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _LCD_DEBUGFS_H
-#define _LCD_DEBUGFS_H
-
-/**
- * @file energy/lcd/lcd_debugfs.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- * Debugfs for LСD
- *
- */
-
-
-struct dentry;
-struct lcd_ops;
-
-int register_lcd_debugfs(struct lcd_ops *ops);
-void unregister_lcd_debugfs(struct lcd_ops *ops);
-
-int init_lcd_debugfs(struct dentry *energy_dir);
-void exit_lcd_debugfs(void);
-
-#endif /* _LCD_DEBUGFS_H */
diff --git a/energy/lcd/maru.c b/energy/lcd/maru.c
deleted file mode 100644 (file)
index e6a9c2c..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  energy/lcd/maru.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <kprobe/swap_kprobes.h>
-#include <linux/backlight.h>
-#include "lcd_base.h"
-
-
-
-static const char path_backlight[]     =
-       "/sys/class/backlight/emulator/brightness";
-static const char path_backlight_min[] =
-       "/sys/class/backlight/emulator/min_brightness";
-static const char path_backlight_max[] =
-       "/sys/class/backlight/emulator/max_brightness";
-static const char path_power[]         =
-       "/sys/class/lcd/emulator/lcd_power";
-
-static const char * const all_path[] = {
-       path_backlight,
-       path_backlight_min,
-       path_backlight_max,
-       path_power
-};
-
-enum {
-       all_path_cnt = sizeof(all_path) / sizeof(char *)
-};
-
-
-static int maru_check(struct lcd_ops *ops)
-{
-       int i;
-
-       for (i = 0; i < all_path_cnt; ++i) {
-               int ret = read_val(all_path[i]);
-
-               if (IS_ERR_VALUE(ret))
-                       return 0;
-       }
-
-       return 1;
-}
-
-static unsigned long maru_get_parameter(struct lcd_ops *ops,
-                                       enum lcd_parameter_type type)
-{
-       switch (type) {
-       case LPD_MIN_BRIGHTNESS:
-               return read_val(path_backlight_min);
-       case LPD_MAX_BRIGHTNESS:
-               return read_val(path_backlight_max);
-       case LPD_BRIGHTNESS:
-               return read_val(path_backlight);
-       case LPD_POWER:
-               return read_val(path_power);
-       default:
-               return -EINVAL;
-       }
-}
-
-
-
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
-                                      struct pt_regs *regs);
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
-                                    struct pt_regs *regs);
-
-static struct kretprobe set_backlight_krp = {
-       .kp.symbol_name = "marubl_send_intensity",
-       .entry_handler = entry_handler_set_backlight,
-       .handler = ret_handler_set_backlight,
-       .data_size = sizeof(int)
-};
-
-
-
-
-
-static int maru_set(struct lcd_ops *ops)
-{
-       return swap_register_kretprobe(&set_backlight_krp);
-}
-
-static int maru_unset(struct lcd_ops *ops)
-{
-       swap_unregister_kretprobe(&set_backlight_krp);
-       return 0;
-}
-
-static struct lcd_ops maru_ops = {
-       .name = "maru",
-       .check = maru_check,
-       .set = maru_set,
-       .unset = maru_unset,
-       .get = maru_get_parameter
-};
-
-struct lcd_ops *LCD_MAKE_FNAME(maru)(void)
-{
-       return &maru_ops;
-}
-
-
-
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
-                                      struct pt_regs *regs)
-{
-       int *brightness = (int *)ri->data;
-       struct backlight_device *bd;
-
-       bd = (struct backlight_device *)swap_get_karg(regs, 0);
-       *brightness = bd->props.brightness;
-
-       return 0;
-}
-
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
-                                    struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       int *brightness = (int *)ri->data;
-
-       if (!ret && maru_ops.notifier)
-               maru_ops.notifier(&maru_ops, LAT_BRIGHTNESS,
-                                 INT2VOIDP(*brightness));
-
-       return 0;
-}
diff --git a/energy/lcd/s6e8aa0.c b/energy/lcd/s6e8aa0.c
deleted file mode 100644 (file)
index 241003b..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-#include <kprobe/swap_kprobes.h>
-#include "lcd_base.h"
-
-
-static const char path_backlight[] =
-       "/sys/class/backlight/s6e8aa0-bl/brightness";
-static const char path_backlight_min[] =
-       "/sys/class/backlight/s6e8aa0-bl/min_brightness";
-static const char path_backlight_max[] =
-       "/sys/class/backlight/s6e8aa0-bl/max_brightness";
-static const char path_power[] =
-       "/sys/class/lcd/s6e8aa0/lcd_power";
-
-static const char * const all_path[] = {
-       path_backlight,
-       path_backlight_min,
-       path_backlight_max,
-       path_power
-};
-
-enum {
-       all_path_cnt = sizeof(all_path) / sizeof(char *)
-};
-
-
-
-static int s6e8aa0_check(struct lcd_ops *ops)
-{
-       int i;
-
-       for (i = 0; i < all_path_cnt; ++i) {
-               int ret = read_val(all_path[i]);
-
-               if (IS_ERR_VALUE(ret))
-                       return 0;
-       }
-
-       return 1;
-}
-
-static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
-                                          enum lcd_parameter_type type)
-{
-       switch (type) {
-       case LPD_MIN_BRIGHTNESS:
-               return read_val(path_backlight_min);
-       case LPD_MAX_BRIGHTNESS:
-               return read_val(path_backlight_max);
-       case LPD_BRIGHTNESS:
-               return read_val(path_backlight);
-       case LPD_POWER:
-               return read_val(path_power);
-       default:
-               return -EINVAL;
-       }
-}
-
-
-
-static int entry_handler_set_power(struct kretprobe_instance *ri,
-                                  struct pt_regs *regs);
-static int ret_handler_set_power(struct kretprobe_instance *ri,
-                                struct pt_regs *regs);
-
-static struct kretprobe set_power_krp = {
-       .kp.symbol_name = "s6e8aa0_set_power",
-       .entry_handler = entry_handler_set_power,
-       .handler = ret_handler_set_power,
-       .data_size = sizeof(int)
-};
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
-                                      struct pt_regs *regs);
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
-                                    struct pt_regs *regs);
-
-static struct kretprobe set_backlight_krp = {
-       .kp.symbol_name = "s6e8aa0_gamma_ctrl",
-       .entry_handler = entry_handler_set_backlight,
-       .handler = ret_handler_set_backlight,
-       .data_size = sizeof(int)
-};
-
-int s6e8aa0_set(struct lcd_ops *ops)
-{
-       int ret;
-
-       ret = swap_register_kretprobe(&set_power_krp);
-       if (ret)
-               return ret;
-
-       ret = swap_register_kretprobe(&set_backlight_krp);
-       if (ret)
-               swap_unregister_kretprobe(&set_power_krp);
-
-       return ret;
-}
-
-int s6e8aa0_unset(struct lcd_ops *ops)
-{
-       swap_unregister_kretprobe(&set_backlight_krp);
-       swap_unregister_kretprobe(&set_power_krp);
-
-       return 0;
-}
-
-static struct lcd_ops s6e8aa0_ops = {
-       .name = "s6e8aa0",
-       .check = s6e8aa0_check,
-       .set = s6e8aa0_set,
-       .unset = s6e8aa0_unset,
-       .get = s6e8aa0_get_parameter
-};
-
-struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0)(void)
-{
-       return &s6e8aa0_ops;
-}
-
-
-
-
-
-/* ============================================================================
- * ===                               POWER                                  ===
- * ============================================================================
- */
-static int entry_handler_set_power(struct kretprobe_instance *ri,
-                                  struct pt_regs *regs)
-{
-       int *power = (int *)ri->data;
-
-       *power = (int)swap_get_karg(regs, 1);
-
-       return 0;
-}
-
-static int ret_handler_set_power(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       int *power = (int *)ri->data;
-
-       if (!ret && s6e8aa0_ops.notifier)
-               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER, INT2VOIDP(*power));
-
-       return 0;
-}
-
-
-
-
-
-/* ============================================================================
- * ===                              BACKLIGHT                               ===
- * ============================================================================
- */
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
-                                      struct pt_regs *regs)
-{
-       int *brightness = (int *)ri->data;
-       *brightness = (int)swap_get_karg(regs, 1);
-
-       return 0;
-}
-
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
-                                    struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       int *brightness = (int *)ri->data;
-
-       if (!ret && s6e8aa0_ops.notifier)
-               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
-                                    INT2VOIDP(*brightness));
-
-       return 0;
-}
diff --git a/energy/lcd/s6e8aa0_panel.c b/energy/lcd/s6e8aa0_panel.c
deleted file mode 100644 (file)
index e2cd8fa..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-#include <kprobe/swap_kprobes.h>
-#include <linux/backlight.h>
-#include "lcd_base.h"
-
-
-static const char path_backlight[] =
-       "/sys/class/backlight/s6e8aa0-bl/brightness";
-static const char path_backlight_max[] =
-       "/sys/class/backlight/s6e8aa0-bl/max_brightness";
-static const char path_power[] =
-       "/sys/class/lcd/s6e8aa0/lcd_power";
-
-static const char * const all_path[] = {
-       path_backlight,
-       path_backlight_max,
-       path_power
-};
-
-enum {
-       all_path_cnt = sizeof(all_path) / sizeof(char *)
-};
-
-
-
-static int s6e8aa0_check(struct lcd_ops *ops)
-{
-       int i;
-
-       for (i = 0; i < all_path_cnt; ++i) {
-               int ret = read_val(all_path[i]);
-
-               if (IS_ERR_VALUE(ret))
-                       return 0;
-       }
-
-       return 1;
-}
-
-static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
-                                          enum lcd_parameter_type type)
-{
-       switch (type) {
-       case LPD_MIN_BRIGHTNESS:
-               return 0;
-       case LPD_MAX_BRIGHTNESS:
-               return read_val(path_backlight_max);
-       case LPD_BRIGHTNESS:
-               return read_val(path_backlight);
-       case LPD_POWER:
-               return read_val(path_power);
-       }
-
-       return -EINVAL;
-}
-
-
-
-static int entry_handler_set_power(struct kretprobe_instance *ri,
-                                  struct pt_regs *regs);
-static int ret_handler_set_power(struct kretprobe_instance *ri,
-                                struct pt_regs *regs);
-
-static struct kretprobe set_power_krp = {
-       .kp.symbol_name = "s6e8aa0_set_power",
-       .entry_handler = entry_handler_set_power,
-       .handler = ret_handler_set_power,
-       .data_size = sizeof(int)
-};
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
-                                      struct pt_regs *regs);
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
-                                    struct pt_regs *regs);
-
-static struct kretprobe set_backlight_krp = {
-       .kp.symbol_name = "s6e8aa0_update_status",
-       .entry_handler = entry_handler_set_backlight,
-       .handler = ret_handler_set_backlight,
-       .data_size = sizeof(int)
-};
-
-int s6e8aa0_set(struct lcd_ops *ops)
-{
-       int ret;
-
-       ret = swap_register_kretprobe(&set_power_krp);
-       if (ret)
-               return ret;
-
-       ret = swap_register_kretprobe(&set_backlight_krp);
-       if (ret)
-               swap_unregister_kretprobe(&set_power_krp);
-
-       return ret;
-}
-
-int s6e8aa0_unset(struct lcd_ops *ops)
-{
-       swap_unregister_kretprobe(&set_backlight_krp);
-       swap_unregister_kretprobe(&set_power_krp);
-
-       return 0;
-}
-
-static struct lcd_ops s6e8aa0_ops = {
-       .name = "s6e8aa0_panel",
-       .check = s6e8aa0_check,
-       .set = s6e8aa0_set,
-       .unset = s6e8aa0_unset,
-       .get = s6e8aa0_get_parameter
-};
-
-struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0_panel)(void)
-{
-       return &s6e8aa0_ops;
-}
-
-
-
-
-
-/* ============================================================================
- * ===                               POWER                                  ===
- * ============================================================================
- */
-static int entry_handler_set_power(struct kretprobe_instance *ri,
-                                  struct pt_regs *regs)
-{
-       int *power = (int *)ri->data;
-
-       *power = (int)swap_get_karg(regs, 1);
-
-       return 0;
-}
-
-static int ret_handler_set_power(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       int *power = (int *)ri->data;
-
-       if (!ret && s6e8aa0_ops.notifier)
-               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER,
-                                    INT2VOIDP(*power));
-
-       return 0;
-}
-
-
-
-
-
-/* ============================================================================
- * ===                              BACKLIGHT                               ===
- * ============================================================================
- */
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
-                                      struct pt_regs *regs)
-{
-       int *brightness = (int *)ri->data;
-       struct backlight_device *bd;
-
-       bd = (struct backlight_device *)swap_get_karg(regs, 0);
-       *brightness = bd->props.brightness;
-
-       return 0;
-}
-
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
-                                    struct pt_regs *regs)
-{
-       int ret = regs_return_value(regs);
-       int *brightness = (int *)ri->data;
-
-       if (!ret && s6e8aa0_ops.notifier)
-               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
-                                    INT2VOIDP(*brightness));
-
-       return 0;
-}
diff --git a/energy/rational_debugfs.c b/energy/rational_debugfs.c
deleted file mode 100644 (file)
index 16c73d5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  energy/rational_debugfs.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/dcache.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <master/swap_debugfs.h>
-#include "debugfs_energy.h"
-#include "rational_debugfs.h"
-
-
-static int denom_set(void *data, u64 val)
-{
-       if (val == 0)
-               return -EINVAL;
-
-       *(u64 *)data = val;
-       return 0;
-}
-
-static int denom_get(void *data, u64 *val)
-{
-       *val = *(u64 *)data;
-       return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_denom, denom_get, denom_set, "%llu\n");
-
-/**
- * @brief Create file in debugfs for rational struct
- *
- * @param parent Dentry parent
- * @param r Pointer to the rational struct
- * @param num_name File name of numerator
- * @param denom_name File name of denominator
- * @return Error code
- */
-int create_rational_files(struct dentry *parent, struct rational *r,
-                         const char *num_name, const char *denom_name)
-{
-       struct dentry *d_num, *d_denom;
-
-       d_num = swap_debugfs_create_u64(num_name, 0600, parent, &r->num);
-       if (d_num == NULL)
-               return -ENOMEM;
-
-       d_denom = swap_debugfs_create_file(denom_name, 0600, parent, &r->denom,
-                                          &fops_denom);
-       if (d_denom == NULL) {
-               debugfs_remove(d_num);
-               return -ENOMEM;
-       }
-
-       return 0;
-}
diff --git a/energy/rational_debugfs.h b/energy/rational_debugfs.h
deleted file mode 100644 (file)
index 6a30155..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _RATIONAL_DEBUGFS_H
-#define _RATIONAL_DEBUGFS_H
-
-/**
- * @file energy/rational_debugfs.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-
-#include <linux/types.h>
-
-
-/**
- * @struct rational
- * @brief Description of rational number
- */
-struct rational {
-       u64 num;                /**< Numerator */
-       u64 denom;              /**< Denominator */
-};
-
-
-/**
- * @def DEFINE_RATIONAL
- * Initialize of rational struct @hideinitializer
- */
-#define DEFINE_RATIONAL(rational_name)         \
-       struct rational rational_name = {       \
-               .num = 1,                       \
-               .denom = 1                      \
-       }
-
-
-struct dentry;
-
-int create_rational_files(struct dentry *parent, struct rational *r,
-                         const char *num_name, const char *denom_name);
-
-
-#endif /* _RATIONAL_DEBUGFS_H */
diff --git a/energy/tm_stat.h b/energy/tm_stat.h
deleted file mode 100644 (file)
index 67278b1..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef _TM_STAT_H
-#define _TM_STAT_H
-
-/**
- * @file energy/tm_stat.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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 COPYFIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- */
-
-
-#include <linux/types.h>
-#include <linux/time.h>
-
-
-/**
- * @struct tm_stat
- * @brief Description of statistic time
- */
-struct tm_stat {
-       u64 timestamp;          /**< Time stamp */
-       u64 running;            /**< Running time */
-};
-
-/**
- * @def DEFINE_TM_STAT
- * Initialize of tm_stat struct @hideinitializer
- */
-#define DEFINE_TM_STAT(tm_name)                \
-       struct tm_stat tm_name = {      \
-               .timestamp = 0,         \
-               .running = 0            \
-       }
-
-
-static inline u64 get_ntime(void)
-{
-       struct timespec ts;
-       getnstimeofday(&ts);
-       return timespec_to_ns(&ts);
-}
-
-static inline void tm_stat_init(struct tm_stat *tm)
-{
-       tm->timestamp = 0;
-       tm->running = 0;
-}
-
-static inline void tm_stat_set_timestamp(struct tm_stat *tm, u64 time)
-{
-       tm->timestamp = time;
-}
-
-static inline u64 tm_stat_timestamp(struct tm_stat *tm)
-{
-       return tm->timestamp;
-}
-
-static inline void tm_stat_update(struct tm_stat *tm, u64 time)
-{
-       tm->running += time - tm->timestamp;
-}
-
-static inline u64 tm_stat_running(struct tm_stat *tm)
-{
-       return tm->running;
-}
-
-static inline u64 tm_stat_current_running(struct tm_stat *tm, u64 now)
-{
-       if (unlikely(now < tm->timestamp))
-               printk(KERN_INFO "XXX %p WARNING now(%llu) < tmstmp(%llu)\n",
-                      tm, now, tm->timestamp);
-       return tm->timestamp ? tm->running + now - tm->timestamp : tm->running;
-}
-
-#endif /* _TM_STAT_H */
diff --git a/fbiprobe/Kbuild b/fbiprobe/Kbuild
deleted file mode 100644 (file)
index 3d90976..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_fbiprobe.o
-swap_fbiprobe-y := fbiprobe.o \
-                   fbi_msg.o
diff --git a/fbiprobe/fbi_msg.c b/fbiprobe/fbi_msg.c
deleted file mode 100644 (file)
index d2bd34a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * fbiprobe/fbi_msg.c
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @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, 2015
- *
- * @section DESCRIPTION
- *
- * Packing and writing data.
- */
-
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <writer/swap_msg.h>
-
-struct msg_fbi {
-       u32 var_id;
-       u32 size;
-       char var_data[0];
-} __packed;
-
-
-static char *pack_fbi_info(char *payload, unsigned long var_id, size_t size,
-                          char *msg_buf)
-{
-       struct msg_fbi *fbi_m = (struct msg_fbi *)payload;
-
-       fbi_m->var_id = var_id;
-       fbi_m->size = size;
-       if (size != 0) {
-               /* FIXME Possible out of buffer! */
-               memcpy(&fbi_m->var_data, msg_buf, size);
-       }
-
-       /*
-        * If size is 0 that mean we cannot get data for this probe.
-        * But we pack it like error code
-        */
-
-       return payload + sizeof(struct msg_fbi) + size;
-}
-
-void fbi_msg(unsigned long var_id, size_t size, char *msg_buf)
-{
-       struct swap_msg *m;
-       void *p;
-       void *buf_end;
-
-       m = swap_msg_get(MSG_FBI);
-       p = swap_msg_payload(m);
-
-       buf_end = pack_fbi_info(p, var_id, size, msg_buf);
-
-       swap_msg_flush(m, buf_end - p);
-
-       swap_msg_put(m);
-}
diff --git a/fbiprobe/fbi_msg.h b/fbiprobe/fbi_msg.h
deleted file mode 100644 (file)
index 69fd209..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * @file fbiprobe/fbi_msg.h
- *
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * Function body instrumetation
- *
- */
-
-#ifndef __FBI_MSG_H__
-#define __FBI_MSG_H__
-
-#include <linux/types.h>
-
-void fbi_msg(unsigned long var_id, size_t size, char *msg_buf);
-
-#endif /* __FBI_MSG_H__ */
diff --git a/fbiprobe/fbi_probe_module.h b/fbiprobe/fbi_probe_module.h
deleted file mode 100644 (file)
index cac6f4a..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * @file fbiprobe/fbi_probe.h
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @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, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI implement, portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumentation.
- *
- */
-
-#ifndef __FBI_PROBE_MODULE_H__
-#define __FBI_PROBE_MODULE_H__
-
-#include <linux/kernel.h>
-
-/* MESSAGES */
-
-#define MODULE_NAME "SWAP_FBI_PROBE"
-
-/* FBI_DEBUG_ON:
- * val | DEBUG | MSG | WARN | ERR | CRITICAL|
- * ----+-------+-----+------+-----+---------|
- * 0   | OFF   | OFF | OFF  | OFF | OFF     |
- * 1   | OFF   | OFF | OFF  | OFF | ON      |
- * 2   | OFF   | OFF | OFF  | ON  | ON      |
- * 3   | OFF   | OFF | ON   | ON  | ON      |
- * 4   | OFF   | ON  | ON   | ON  | ON      |
- * 5   | ON    | ON  | ON   | ON  | ON      |
- */
-
-#define FBI_DEBUG_LEVEL 3
-
-/** Prints debug message.*/
-#if (FBI_DEBUG_LEVEL >= 5)
-#define print_debug(msg, args...) \
-       printk(KERN_DEBUG MODULE_NAME " DEBUG : " msg, ##args)
-#else
-#define print_debug(msg, args...)
-#endif
-
-/** Prints info message.*/
-#if (FBI_DEBUG_LEVEL >= 4)
-#define print_msg(msg, args...)   \
-       printk(KERN_INFO MODULE_NAME " : " msg, ##args)
-#else
-#define print_msg(msg, args...)
-#endif
-
-/** Prints warning message.*/
-#if (FBI_DEBUG_LEVEL >= 3)
-#define print_warn(msg, args...)  \
-       printk(KERN_WARNING MODULE_NAME " WARNING : " msg, ##args)
-#else
-#define print_warn(msg, args...)
-#endif
-
-/** Prints error message.*/
-#if (FBI_DEBUG_LEVEL >= 2)
-#define print_err(msg, args...)   \
-       printk(KERN_ERR MODULE_NAME " ERROR : " msg, ##args)
-#else
-#define print_err(msg, args...)
-#endif
-
-/** Prints critical error message.*/
-#if (FBI_DEBUG_LEVEL >= 1)
-#define print_crit(msg, args...)  \
-       printk(KERN_CRIT MODULE_NAME " CRITICAL : " msg, ##args)
-#else
-#define print_crit(msg, args...)
-#endif
-
-#endif /* __FBI_PROBE_MODULE_H__ */
diff --git a/fbiprobe/fbiprobe.c b/fbiprobe/fbiprobe.c
deleted file mode 100644 (file)
index 39e6477..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * @file fbiprobe/fbi_probe.c
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @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, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI implement, portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumetation
- *
- */
-
-#include "fbiprobe.h"
-#include "fbi_probe_module.h"
-#include "fbi_msg.h"
-#include "regs.h"
-
-#include <us_manager/us_manager.h>
-#include <us_manager/probes/probes.h>
-#include <us_manager/probes/register_probes.h>
-
-#include <uprobe/swap_uprobes.h>
-#include <us_manager/sspt/sspt_ip.h>
-
-#include <kprobe/swap_kprobes_deps.h>
-#include <linux/module.h>
-
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/dcache.h>
-#include <linux/mm_types.h>
-
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-
-#define DIRECT_ADDR (0xFF)
-#define MAX_STRING_LEN (512)
-
-/* on fails. return NULL, set size to 0 */
-/* you shoud free allocated data buffer */
-static char *fbi_probe_alloc_and_read_from_addr(const struct fbi_var_data *fbid,
-                                               unsigned long addr,
-                                               uint32_t *size)
-{
-       uint8_t i, j;
-       char *buf = NULL;
-       struct fbi_step *step;
-
-       *size = 0;
-
-       /* get final variable address */
-       step = fbid->steps;
-       for (i = 0; i != fbid->steps_count; i++) {
-               /* dereference */
-               for (j = 0; j != step->ptr_order; j++) {
-                       unsigned long new_addr;
-                       /* equel to: addr = *addr */
-                       if (!read_proc_vm_atomic(current, addr, &new_addr,
-                                                sizeof(new_addr))) {
-                               print_warn("p = 0x%lx step #%d ptr_order #%d\n",
-                                          addr, i + 1, j + 1);
-                               goto exit_fail;
-                       }
-                       addr = new_addr;
-                       print_debug("dereference addr = 0x%lx;\n", addr);
-               }
-
-               /* offset */
-               addr += step->data_offset;
-               print_debug("addr + offset = 0x%lx;\n", addr);
-               step++;
-       }
-
-       /* calculate data size */
-       if (fbid->data_size == 0) {
-               /*
-                * that mean variable is string and
-                * we need to calculate string length
-                */
-
-               *size = strnlen_user((const char __user *)addr, MAX_STRING_LEN);
-               if (*size == 0) {
-                       print_warn("Cannot get string from 0x%lx\n", addr);
-                       goto exit_fail;
-               }
-       } else {
-               /* else use size from fbi struct */
-               *size = fbid->data_size;
-       }
-
-       buf = kmalloc(*size, GFP_KERNEL);
-       if (buf == NULL) {
-               print_warn("Not enough memory\n");
-               goto exit_fail_size_0;
-       }
-
-       if (!read_proc_vm_atomic(current, addr, buf, *size)) {
-               print_warn("Error reading data at 0x%lx, task %d\n",
-                          addr, current->pid);
-               goto exit_fail_free_buf;
-       }
-
-       if (fbid->data_size == 0) {
-               /*
-                * that mean variable is string and
-                * we need to add terminate '\0'
-                */
-               buf[*size - 1] = '\0';
-       }
-
-       return buf;
-
-exit_fail_free_buf:
-       kfree(buf);
-       buf = NULL;
-exit_fail_size_0:
-       *size = 0;
-exit_fail:
-       return NULL;
-
-}
-
-static int fbi_probe_get_data_from_reg(const struct fbi_var_data *fbi_i,
-                                      struct pt_regs *regs)
-{
-       unsigned long *reg_ptr;
-
-       reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
-       if (reg_ptr == NULL) {
-               print_err("fbi_probe_get_data_from_reg: Wrong register number!\n");
-               return 0;
-       }
-
-       fbi_msg(fbi_i->var_id, fbi_i->data_size, (char *)reg_ptr);
-
-       return 0;
-}
-
-static int fbi_probe_get_data_from_ptrs(const struct fbi_var_data *fbi_i,
-                                       struct pt_regs *regs)
-{
-       unsigned long *reg_ptr;
-       unsigned long addr;
-       uint32_t size = 0;
-       void *buf = NULL;
-
-       reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
-       if (reg_ptr == NULL) {
-               print_err("fbi_probe_get_data_from_ptrs: Wrong register number!\n");
-               goto send_msg;
-       }
-
-       addr = *reg_ptr + fbi_i->reg_offset;
-       print_warn("reg = %p; off = 0x%llx; addr = 0x%lx!\n", reg_ptr,
-                  fbi_i->reg_offset, addr);
-
-       buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
-
-send_msg:
-       /* If buf is NULL size will be 0.
-        * That mean we cannot get data for this probe.
-        * But we should send probe message with packed data size 0
-        * as error message.
-        */
-       fbi_msg(fbi_i->var_id, size, buf);
-
-       if (buf != NULL)
-               kfree(buf);
-       else
-               print_err("cannot get data from ptrs\n");
-
-       return 0;
-}
-
-static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm,
-                                                    struct dentry *dentry)
-{
-       struct vm_area_struct *vma;
-
-       /* FIXME: down_write(&mm->mmap_sem); up_write(&mm->mmap_sem); */
-       /* TODO FILTER vma */
-       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if (vma->vm_file &&
-                  (vma->vm_file->f_path.dentry == dentry))
-                       /* found */
-                       goto exit;
-       }
-
-       /* not found */
-       vma = NULL;
-exit:
-       return vma;
-}
-
-static int fbi_probe_get_data_from_direct_addr(const struct fbi_var_data *fbi_i,
-                                              struct sspt_ip *ip,
-                                              struct pt_regs *regs)
-{
-       struct vm_area_struct *vma;
-       unsigned long addr;
-       uint32_t size = 0;
-       char *buf;
-
-       /* register offset is global address */
-       vma = find_vma_exe_by_dentry(current->mm, ip->page->file->dentry);
-       if (vma == NULL) {
-               print_warn("cannot locate dentry\n");
-               goto exit;
-       }
-
-       addr = vma->vm_start + fbi_i->reg_offset;
-
-       print_debug("DIRECT_ADDR reg_offset = %llx\n", fbi_i->reg_offset);
-       print_debug("DIRECT_ADDR vm_start   = %lx\n", vma->vm_start);
-       print_debug("DIRECT_ADDR res_addr   = %lx\n", addr);
-
-       buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
-       /* If buf is NULL size will be 0.
-        * That mean we cannot get data for this probe.
-        * But we should send probe message with packed data size 0
-        * as error message.
-        */
-       fbi_msg(fbi_i->var_id, size, buf);
-
-       if (buf != NULL) {
-               kfree(buf);
-       } else {
-               print_warn("get data by direct addr failed (0x%lx :0x%llx)\n",
-                          addr, fbi_i->reg_offset);
-       }
-exit:
-       return 0;
-}
-
-static int fbi_probe_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct sspt_ip *ip = container_of(p, struct sspt_ip, uprobe);
-       struct fbi_info *fbi_i = &ip->desc->info.fbi_i;
-       struct fbi_var_data *fbi_d = NULL;
-       uint8_t i;
-
-       if (ip->desc->type != SWAP_FBIPROBE) {
-               /* How this can occure? Doesn't matter, just print and go */
-               print_err("Not FBI probe in FBI handler!\n");
-               return 0;
-       }
-
-       for (i = 0; i != fbi_i->var_count; i++) {
-               fbi_d = &fbi_i->vars[i];
-               if (fbi_d->reg_n == DIRECT_ADDR) {
-                       if (0 != fbi_probe_get_data_from_direct_addr(fbi_d, ip,
-                                                                    regs))
-                               print_err("fbi_probe_get_data_from_direct_addr error\n");
-               } else if (fbi_d->steps_count == 0) {
-                       if (0 != fbi_probe_get_data_from_reg(fbi_d, regs))
-                               print_err("fbi_probe_get_data_from_reg error\n");
-               } else {
-                       if (0 != fbi_probe_get_data_from_ptrs(fbi_d, regs))
-                               print_err("fbi_probe_get_data_from_ptrs error\n");
-               }
-       }
-
-       return 0;
-}
-
-/* FBI probe interfaces */
-void fbi_probe_cleanup(struct probe_info *probe_i)
-{
-       uint8_t i;
-       struct fbi_info *fbi_i = &(probe_i->fbi_i);
-
-       for (i = 0; i != fbi_i->var_count; i++) {
-               if (fbi_i->vars[i].steps != NULL) {
-                       if (fbi_i->vars[i].steps != NULL)
-                               kfree(fbi_i->vars[i].steps);
-                       fbi_i->vars[i].steps = NULL;
-                       fbi_i->vars[i].steps_count = 0;
-               }
-       }
-
-       kfree(fbi_i->vars);
-       fbi_i->vars = NULL;
-}
-
-void fbi_probe_init(struct sspt_ip *ip)
-{
-       ip->uprobe.pre_handler = (uprobe_pre_handler_t)fbi_probe_handler;
-}
-
-void fbi_probe_uninit(struct sspt_ip *ip)
-{
-       if (ip != NULL)
-               fbi_probe_cleanup(&ip->desc->info);
-}
-
-static int fbi_probe_register_probe(struct sspt_ip *ip)
-{
-       return swap_register_uprobe(&ip->uprobe);
-}
-
-static void fbi_probe_unregister_probe(struct sspt_ip *ip, int disarm)
-{
-       __swap_unregister_uprobe(&ip->uprobe, disarm);
-}
-
-static struct uprobe *fbi_probe_get_uprobe(struct sspt_ip *ip)
-{
-       return &ip->uprobe;
-}
-
-int fbi_probe_copy(struct probe_info *dest, const struct probe_info *source)
-{
-       uint8_t steps_count;
-       size_t steps_size;
-       size_t vars_size;
-       struct fbi_var_data *vars;
-       struct fbi_step *steps_source;
-       struct fbi_step *steps_dest = NULL;
-       uint8_t i, n;
-       int ret = 0;
-
-       memcpy(dest, source, sizeof(*source));
-
-       vars_size = source->fbi_i.var_count * sizeof(*source->fbi_i.vars);
-       vars = kmalloc(vars_size, GFP_KERNEL);
-       if (vars == NULL)
-               return -ENOMEM;
-
-       memcpy(vars, source->fbi_i.vars, vars_size);
-
-       for (i = 0; i != source->fbi_i.var_count; i++) {
-               steps_dest = NULL;
-               steps_count = vars[i].steps_count;
-               steps_size = sizeof(*steps_source) * steps_count;
-               steps_source = vars[i].steps;
-
-               if (steps_size != 0 && steps_source != NULL) {
-                       steps_dest = kmalloc(steps_size, GFP_KERNEL);
-                       if (steps_dest == NULL) {
-                               print_err("can not alloc data\n");
-                               n = i;
-                               ret = -ENOMEM;
-                               goto err;
-                       }
-
-                       memcpy(steps_dest, steps_source, steps_size);
-               }
-               vars[i].steps = steps_dest;
-       }
-
-       dest->fbi_i.vars = vars;
-
-       return ret;
-err:
-       for (i = 0; i < n; i++)
-               kfree(vars[i].steps);
-       kfree(vars);
-       return ret;
-}
-
-/* Register */
-static struct probe_iface fbi_probe_iface = {
-       .init = fbi_probe_init,
-       .uninit = fbi_probe_uninit,
-       .reg = fbi_probe_register_probe,
-       .unreg = fbi_probe_unregister_probe,
-       .get_uprobe = fbi_probe_get_uprobe,
-       .copy = fbi_probe_copy,
-       .cleanup = fbi_probe_cleanup
-};
-
-static int __init fbiprobe_module_init(void)
-{
-       int ret = 0;
-       ret = swap_register_probe_type(SWAP_FBIPROBE, &fbi_probe_iface);
-       print_debug("Init done. Result=%d\n", ret);
-       return ret;
-}
-
-static void __exit fbiprobe_module_exit(void)
-{
-       swap_unregister_probe_type(SWAP_FBIPROBE);
-}
-
-module_init(fbiprobe_module_init);
-module_exit(fbiprobe_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP fbiprobe");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>; Vitaliy Cherepanov <v.cherepanov@samsung.com>");
-
diff --git a/fbiprobe/fbiprobe.h b/fbiprobe/fbiprobe.h
deleted file mode 100644 (file)
index 2e158c2..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * @file fbi_probe/fbi_probe.h
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * 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, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI implement, portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumentation.
- *
- */
-
-#ifndef __FBI_PROBE_H__
-#define __FBI_PROBE_H__
-
-#include <linux/types.h>
-
-/* FBI step */
-struct fbi_step {
-       uint8_t ptr_order;         /* Specifies what is located on the address:
-                                   * ptr_order = 0  -  variable
-                                   * ptr_order = 1  -  pointer to variable
-                                   * ptr_order = 2  -  pointer to pointer
-                                   * etc. */
-
-       uint64_t data_offset;
-} __packed;
-
-/* FBI var data */
-struct fbi_var_data {
-       /* Variable position is evaluated by the following rule:
-        * var_position = *(pointer_to_register) - reg_offset
-        * It is expected that the offset is not null only when we're taking
-        * var value from stack.
-        */
-       uint64_t var_id;           /* Variable identifier
-                                   * Used to specify var */
-       uint64_t reg_offset;       /* Offset relative to the registers value
-                                   * address, specified with reg_n */
-       uint8_t reg_n;             /* Register number. Hope times of cpu
-                                   * with more than 2 million ones are very
-                                   * far from us */
-       uint32_t data_size;        /* Data size to be read */
-
-       uint8_t steps_count;       /* Count of steps to extract variable
-                                   * value */
-       struct fbi_step *steps;    /* extract steps */
-};
-
-/* FBI info */
-struct fbi_info {
-       uint8_t var_count;
-       struct fbi_var_data *vars;
-};
-
-#endif /* __FBI_PROBE_H__ */
diff --git a/fbiprobe/regs.h b/fbiprobe/regs.h
deleted file mode 100644 (file)
index 6ad231a..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * @file fbiprobe/fbi_probe.h
- *
- * @author Aleksandr Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @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, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumetation
- *
- */
-
-#ifndef __REGS_H__
-#define __REGS_H__
-
-#include <linux/ptrace.h>
-
-#include "fbi_probe_module.h"
-/* This function is used to compare register number and its name on x86 arch.
- * For ARM it is dumb.
- * List of registers and their nums on x86:
- * ax       0
- * bx       1
- * cx       2
- * dx       3
- * si       4
- * di       5
- * bp       6
- * sp       7
- */
-
-static inline unsigned long *get_ptr_by_num(struct pt_regs *regs,
-                                           unsigned char reg_num)
-{
-       unsigned long *reg = NULL;
-       /* FIXME: bad way to use "sizeof(long) " */
-       if (reg_num < sizeof(struct pt_regs) / sizeof(long)) {
-               reg = (unsigned long *)regs;
-               reg =  &reg[reg_num];
-       }
-
-       return reg;
-}
-
-#endif /* __REGS_H__ */
diff --git a/got_patcher/Kbuild b/got_patcher/Kbuild
deleted file mode 100644 (file)
index bd078f4..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_gtp.o
-swap_gtp-y := gt_module.o \
-              gt_debugfs.o
diff --git a/got_patcher/gt.h b/got_patcher/gt.h
deleted file mode 100644 (file)
index ba5924e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __GT_H__
-#define __GT_H__
-
-#define GT_PREFIX "SWAP GOT PATCHER: "
-
-#endif /* __GT_H__ */
diff --git a/got_patcher/gt_debugfs.c b/got_patcher/gt_debugfs.c
deleted file mode 100644 (file)
index 362c5d1..0000000
+++ /dev/null
@@ -1,618 +0,0 @@
-#include <linux/debugfs.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "gt.h"
-#include "gt_debugfs.h"
-#include "gt_module.h"
-
-#define GT_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
-
-static const char GT_FOLDER[] = "got_patcher";
-static const char GT_LINKER[] = "linker";
-static const char GT_PATH[] = "path";
-static const char GT_FIXUP_ADDR[] = "dl_fixup_addr";
-static const char GT_RELOC_ADDR[] = "dl_reloc_addr";
-static const char GT_ENABLE[] = "enable";
-static const char GT_BY_PATH[] = "by_path";
-static const char GT_BY_PID[] = "by_pid";
-static const char GT_BY_ID[] = "by_id";
-static const char GT_ADD[] = "add";
-static const char GT_DEL[] = "del";
-static const char GT_DEL_ALL[] = "del_all";
-static const char GT_LIST_TARGETS[] = "list_targets";
-static const char GT_HANDLER[] = "handler";
-static const char GT_HANDLER_FIXUP_OFF[] = "fixup_handler_off";
-static const char GT_HANDLER_RELOC_OFF[] = "reloc_handler_off";
-static const char GT_PROC_FEATURES_OFF[] = "proc_features_off";
-static const char GT_PTHREAD[] = "pthread";
-static const char GT_MINIMAL_INIT[] = "minimal_init_off";
-
-static struct dentry *gt_root;
-
-
-/* Type for function that handles string grabbed from userspace */
-typedef int (*sh_t)(char *);
-
-/* Type for function that handles unsigned long grabbed from userspace */
-typedef int (*ulh_t)(unsigned long);
-
-/* Type for function that handles pid grabbed from userspace */
-typedef int (*ph_t)(pid_t);
-
-
-static ssize_t get_string_and_call(const char __user *buf, size_t len,
-                                  sh_t cb)
-{
-       char *string;
-       ssize_t ret;
-
-       string = kmalloc(len, GFP_KERNEL);
-       if (string == NULL) {
-               ret = -ENOMEM;
-               goto get_string_write_out;
-       }
-
-       if (copy_from_user(string, buf, len)) {
-               ret = -EINVAL;
-               goto get_string_write_out;
-       }
-
-       string[len - 1] = '\0';
-
-       ret = cb(string);
-
-get_string_write_out:
-       kfree(string);
-
-       return ret == 0 ? len : ret;
-}
-
-static ssize_t get_ul_and_call(const char __user *buf, size_t len, ulh_t cb)
-{
-       ssize_t ret;
-       char *ulstring;
-       unsigned long ul;
-
-       ulstring = kmalloc(len, GFP_KERNEL);
-       if (ulstring == NULL) {
-               ret = -ENOMEM;
-               goto get_ul_write_out;
-       }
-
-       if (copy_from_user(ulstring, buf, len)) {
-               ret = -EINVAL;
-               goto get_ul_write_out;
-       }
-
-       ulstring[len - 1] = '\0';
-
-       ret = kstrtoul(ulstring, 16, &ul);
-       if (ret != 0)
-               goto get_ul_write_out;
-
-       ret = cb(ul);
-
-get_ul_write_out:
-       kfree(ulstring);
-
-       return ret == 0 ? len : ret;
-}
-
-static ssize_t get_pid_and_call(const char __user *buf, size_t len, ph_t cb)
-{
-       ssize_t ret;
-       char *pidstring;
-       pid_t pid;
-
-       pidstring = kmalloc(len, GFP_KERNEL);
-       if (pidstring == NULL) {
-               ret = -ENOMEM;
-               goto get_pid_write_out;
-       }
-
-       if (copy_from_user(pidstring, buf, len)) {
-               ret = -EINVAL;
-               goto get_pid_write_out;
-       }
-
-       pidstring[len - 1] = '\0';
-
-       ret = kstrtoul(pidstring, 10, (unsigned long *)&pid);
-       if (ret != 0)
-               goto get_pid_write_out;
-
-       ret = cb(pid);
-
-get_pid_write_out:
-       kfree(pidstring);
-
-       return ret == 0 ? len : ret;
-}
-
-/* ===========================================================================
- * =                              TARGETS                                    =
- * ===========================================================================
- */
-
-static ssize_t handler_path_write(struct file *file, const char __user *buf,
-                                 size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_set_handler_path);
-}
-
-static ssize_t handler_fixup_off_write(struct file *file,
-                                      const char __user *buf, size_t len,
-                                      loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, gtm_set_handler_fixup_off);
-}
-
-static ssize_t handler_reloc_off_write(struct file *file,
-                                      const char __user *buf, size_t len,
-                                      loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, gtm_set_handler_reloc_off);
-}
-
-static ssize_t proc_features_off_write(struct file *file,
-                                      const char __user *buf, size_t len,
-                                      loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, gtm_set_proc_features_off);
-}
-
-static const struct file_operations handler_path_fops = {
-       .owner = THIS_MODULE,
-       .write = handler_path_write,
-};
-
-static const struct file_operations handler_fixup_off_fops = {
-       .owner = THIS_MODULE,
-       .write = handler_fixup_off_write,
-};
-
-static const struct file_operations handler_reloc_off_fops = {
-       .owner = THIS_MODULE,
-       .write = handler_reloc_off_write,
-};
-
-static const struct file_operations proc_features_off_fops = {
-       .owner = THIS_MODULE,
-       .write = proc_features_off_write,
-};
-
-/* ===========================================================================
- * =                              TARGETS                                    =
- * ===========================================================================
- */
-
-static ssize_t by_path_add_write(struct file *file, const char __user *buf,
-                                size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_add_by_path);
-}
-
-static ssize_t by_path_del_write(struct file *file, const char __user *buf,
-                                size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_del_by_path);
-}
-
-static ssize_t by_pid_add_write(struct file *file, const char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       return get_pid_and_call(buf, len, gtm_add_by_pid);
-}
-
-static ssize_t by_pid_del_write(struct file *file, const char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       return get_pid_and_call(buf, len, gtm_del_by_pid);
-}
-
-static ssize_t by_id_add_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_add_by_id);
-}
-
-static ssize_t by_id_del_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_del_by_id);
-}
-
-static ssize_t del_all_write(struct file *file, const char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-
-       ret = gtm_del_all();
-
-       return ret == 0 ? len : ret;
-}
-
-static ssize_t target_read(struct file *file, char __user *buf,
-                          size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *targets;
-
-       ret = gtm_get_targets(&targets);
-       if (ret < 0)
-               return ret;
-
-       ret = simple_read_from_buffer(buf, len, ppos, targets, ret);
-       kfree(targets);
-
-       return ret;
-}
-
-static const struct file_operations by_path_add_fops = {
-       .owner = THIS_MODULE,
-       .write = by_path_add_write,
-};
-
-static const struct file_operations by_path_del_fops = {
-       .owner = THIS_MODULE,
-       .write = by_path_del_write,
-};
-
-static const struct file_operations by_pid_add_fops = {
-       .owner = THIS_MODULE,
-       .write = by_pid_add_write,
-};
-
-static const struct file_operations by_pid_del_fops = {
-       .owner = THIS_MODULE,
-       .write = by_pid_del_write,
-};
-
-static const struct file_operations by_id_add_fops = {
-       .owner = THIS_MODULE,
-       .write = by_id_add_write,
-};
-
-static const struct file_operations by_id_del_fops = {
-       .owner = THIS_MODULE,
-       .write = by_id_del_write,
-};
-
-static const struct file_operations del_all_fops = {
-       .owner = THIS_MODULE,
-       .write = del_all_write,
-};
-
-static const struct file_operations target_fops = {
-       .owner = THIS_MODULE,
-       .read = target_read,
-};
-
-/* ===========================================================================
- * =                              ENABLE                                     =
- * ===========================================================================
- */
-
-static ssize_t enable_read(struct file *file, char __user *buf,
-                          size_t len, loff_t *ppos)
-{
-       char val[2];
-
-       val[0] = (gtm_status() == GT_ON ? '1' : '0');
-       val[1] = '\0';
-
-       return simple_read_from_buffer(buf, len, ppos, val, 2);
-}
-
-static ssize_t enable_write(struct file *file, const char __user *buf,
-                           size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char val[2];
-       size_t val_size;
-
-       val_size = min(len, (sizeof(val) - 1));
-       if (copy_from_user(val, buf, val_size))
-               return -EFAULT;
-
-       val[1] = '\0';
-       switch(val[0]) {
-       case '0':
-               ret = gtm_switch(GT_OFF);
-               break;
-       case '1':
-               ret = gtm_switch(GT_ON);
-               break;
-       default:
-               printk(GT_PREFIX "Invalid state!\n");
-               return -EINVAL;
-       }
-
-       return ret == 0 ? len : ret;
-}
-
-static const struct file_operations enable_fops = {
-       .owner = THIS_MODULE,
-       .write = enable_write,
-       .read = enable_read,
-};
-
-
-/* ===========================================================================
- * =                              LINKER                                     =
- * ===========================================================================
- */
-
-static ssize_t linker_path_write(struct file *file, const char __user *buf,
-                                size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_set_linker_path);
-}
-
-static ssize_t fixup_off_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, gtm_set_fixup_off);
-}
-
-static ssize_t reloc_off_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, gtm_set_reloc_off);
-}
-
-static const struct file_operations linker_path_fops = {
-       .owner = THIS_MODULE,
-       .write = linker_path_write,
-};
-
-static const struct file_operations fixup_off_fops = {
-       .owner = THIS_MODULE,
-       .write = fixup_off_write,
-};
-
-static const struct file_operations reloc_off_fops = {
-       .owner = THIS_MODULE,
-       .write = reloc_off_write,
-};
-
-
-
-/* ===========================================================================
- * =                             PTHREAD                                     =
- * ===========================================================================
- */
-
-static ssize_t pthread_path_write(struct file *file, const char __user *buf,
-                                 size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, gtm_set_pthread_path);
-}
-
-static ssize_t init_off_write(struct file *file, const char __user *buf,
-                             size_t len, loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, gtm_set_init_off);
-}
-
-static const struct file_operations pthread_path_fops = {
-       .owner = THIS_MODULE,
-       .write = pthread_path_write,
-};
-
-static const struct file_operations pthread_init_off_fops = {
-       .owner = THIS_MODULE,
-       .write = init_off_write,
-};
-
-
-
-
-int gtd_init(void)
-{
-       struct dentry *swap_dentry, *root, *linker, *by_path, *by_pid,
-                     *by_id, *handler, *pthread, *dentry;
-       int ret;
-
-       ret = -ENODEV;
-       if (!debugfs_initialized())
-               goto fail;
-
-       ret = -ENOENT;
-       swap_dentry = swap_debugfs_getdir();
-       if (!swap_dentry)
-               goto fail;
-
-       ret = -ENOMEM;
-       root = swap_debugfs_create_dir(GT_FOLDER, swap_dentry);
-       if (IS_ERR_OR_NULL(root))
-               goto fail;
-
-       gt_root = root;
-
-       linker = swap_debugfs_create_dir(GT_LINKER, root);
-       if (IS_ERR_OR_NULL(linker)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_PATH, GT_DEFAULT_PERMS, linker,
-                                         NULL, &linker_path_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_FIXUP_ADDR, GT_DEFAULT_PERMS,
-                                         linker, NULL, &fixup_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_RELOC_ADDR, GT_DEFAULT_PERMS,
-                                         linker, NULL, &reloc_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       by_path = swap_debugfs_create_dir(GT_BY_PATH, root);
-       if (IS_ERR_OR_NULL(by_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_ADD, GT_DEFAULT_PERMS, by_path,
-                                         NULL, &by_path_add_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_DEL, GT_DEFAULT_PERMS, by_path,
-                                         NULL, &by_path_del_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       by_pid = swap_debugfs_create_dir(GT_BY_PID, root);
-       if (IS_ERR_OR_NULL(by_pid)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_ADD, GT_DEFAULT_PERMS, by_pid,
-                                         NULL, &by_pid_add_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_DEL, GT_DEFAULT_PERMS, by_pid,
-                                         NULL, &by_pid_del_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       by_id = swap_debugfs_create_dir(GT_BY_ID, root);
-       if (IS_ERR_OR_NULL(by_id)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_ADD, GT_DEFAULT_PERMS, by_id,
-                                         NULL, &by_id_add_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_DEL, GT_DEFAULT_PERMS, by_id,
-                                         NULL, &by_id_del_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_DEL_ALL, GT_DEFAULT_PERMS, root,
-                                         NULL, &del_all_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_LIST_TARGETS, GT_DEFAULT_PERMS, root,
-                                         NULL, &target_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_ENABLE, GT_DEFAULT_PERMS, root,
-                                         NULL, &enable_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       handler = swap_debugfs_create_dir(GT_HANDLER, root);
-       if (IS_ERR_OR_NULL(handler)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_PATH, GT_DEFAULT_PERMS, handler,
-                                         NULL, &handler_path_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_HANDLER_FIXUP_OFF,
-                                         GT_DEFAULT_PERMS, handler,
-                                         NULL, &handler_fixup_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_HANDLER_RELOC_OFF,
-                                         GT_DEFAULT_PERMS, handler, NULL,
-                                         &handler_reloc_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_PROC_FEATURES_OFF,
-                                         GT_DEFAULT_PERMS, handler, NULL,
-                                         &proc_features_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       pthread = swap_debugfs_create_dir(GT_PTHREAD, root);
-       if (IS_ERR_OR_NULL(pthread)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_PATH, GT_DEFAULT_PERMS, pthread,
-                                         NULL, &pthread_path_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(GT_MINIMAL_INIT, GT_DEFAULT_PERMS,
-                                         pthread, NULL,
-                                         &pthread_init_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       return 0;
-
-remove:
-       debugfs_remove_recursive(root);
-
-fail:
-       printk(GT_PREFIX "Debugfs initialization failure: %d\n", ret);
-
-       return ret;
-}
-
-void gtd_exit(void)
-{
-       if (gt_root)
-               debugfs_remove_recursive(gt_root);
-       gt_root = NULL;
-}
diff --git a/got_patcher/gt_debugfs.h b/got_patcher/gt_debugfs.h
deleted file mode 100644 (file)
index e6d5329..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __GT_DEBUGFS_H__
-#define __GT_DEBUGFS_H__
-
-int gtd_init(void);
-void gtd_exit(void);
-
-#endif /* __GT_DEBUGFS_H__ */
diff --git a/got_patcher/gt_module.c b/got_patcher/gt_module.c
deleted file mode 100644 (file)
index 0779177..0000000
+++ /dev/null
@@ -1,1069 +0,0 @@
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/namei.h>
-#include <linux/slab.h>
-#include <linux/limits.h>
-#include <kprobe/swap_ktd.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/probes/probe_info_new.h>
-#include <us_manager/us_common_file.h>
-#include <loader/loader.h>
-#include <master/swap_initializer.h>
-#include "gt.h"
-#include "gt_module.h"
-#include "gt_debugfs.h"
-
-
-enum task_id_t {
-       GT_SET_BY_DENTRY,
-       GT_SET_BY_PID,
-       GT_SET_BY_ID,
-};
-
-struct l_probe_el {
-       struct list_head list;
-
-       struct pf_group *pfg;
-       enum task_id_t task_id;
-       union {
-               pid_t tgid;
-               struct dentry *dentry;
-               char *id;
-       };
-
-       struct probe_new p_fixup;
-       struct probe_new p_reloc;
-       struct probe_new p_init;
-};
-
-struct bin_data_t {
-       struct dentry *dentry;
-       unsigned long off;
-};
-
-typedef unsigned long (*rh_t)(struct uretprobe_instance *, struct pt_regs *,
-                             struct hd_t *);
-
-/* Typedef for compare function that removes data from list */
-typedef bool (*cf_t)(struct l_probe_el*, void *);
-
-static LIST_HEAD(_reg_probes);
-static LIST_HEAD(_unreg_probes);
-static DEFINE_MUTEX(_linker_probes_lock);
-
-static enum gt_status _status = GT_OFF;
-static struct bin_data_t _linker_fixup;
-static struct bin_data_t _linker_reloc;
-static struct bin_data_t _handler_fixup;
-static struct bin_data_t _handler_reloc;
-static struct bin_data_t _proc_features;
-static struct bin_data_t _pthread_init;
-
-
-static inline void _lock_probes_list(void)
-{
-       mutex_lock(&_linker_probes_lock);
-}
-
-static inline void _unlock_probes_list(void)
-{
-       mutex_unlock(&_linker_probes_lock);
-}
-
-static inline bool _is_enable(void)
-{
-       return _status == GT_ON;
-}
-
-static inline bool _is_bin_data_available(struct bin_data_t *bin_data)
-{
-       return (bin_data->dentry && bin_data->off);
-}
-
-static inline bool _is_linker_data_available(void)
-{
-       return _is_bin_data_available(&_linker_fixup) &&
-              _is_bin_data_available(&_linker_reloc);
-}
-
-static inline bool _is_handler_data_available(void)
-{
-       return _is_bin_data_available(&_handler_fixup) &&
-              _is_bin_data_available(&_handler_reloc) &&
-              _is_bin_data_available(&_proc_features);
-}
-
-static inline bool _is_pthread_data_available(void)
-{
-       return _is_bin_data_available(&_pthread_init);
-}
-
-
-
-
-/* ===========================================================================
- * =                           TASK DATA MANIPULATION                        =
- * ===========================================================================
- */
-
-static void gt_ktd_init(struct task_struct *task, void *data)
-{
-       bool *in_handler = (bool *)data;
-
-       *in_handler = false;
-}
-
-static void gt_ktd_exit(struct task_struct *task, void *data)
-{
-}
-
-static struct ktask_data gt_ktd = {
-       .init = gt_ktd_init,
-       .exit = gt_ktd_exit,
-       .size = sizeof(bool),
-};
-
-static inline bool _is_in_handler(void)
-{
-       return *(bool *)swap_ktd(&gt_ktd, current);
-}
-
-static inline void _set_in_handler(bool is_in_handler)
-{
-       *(bool *)swap_ktd(&gt_ktd, current) = is_in_handler;
-}
-
-static inline bool _check_by_dentry(struct l_probe_el *l_probe, void *data)
-{
-       struct dentry *dentry = (struct dentry *)data;
-
-       if (l_probe->task_id == GT_SET_BY_DENTRY &&
-           l_probe->dentry == dentry)
-               return true;
-
-       return false;
-}
-
-static inline bool _check_by_pid(struct l_probe_el *l_probe, void *data)
-{
-       pid_t tgid = *(pid_t *)data;
-
-       if (l_probe->task_id == GT_SET_BY_PID &&
-           l_probe->tgid == tgid)
-               return true;
-
-       return false;
-}
-
-static inline bool _check_by_id(struct l_probe_el *l_probe, void *data)
-{
-       char *id = (char *)data;
-
-       if (l_probe->task_id == GT_SET_BY_ID &&
-           strncmp(l_probe->id, id, PATH_MAX))
-               return true;
-
-       return false;
-}
-
-static inline bool _del_all(struct l_probe_el *l_probe, void *data)
-{
-       return true;
-}
-
-/* ===========================================================================
- * =                            LINKER HANDLERS                              =
- * ===========================================================================
- */
-
-static unsigned long _redirect_to_handler(struct uretprobe_instance *ri,
-                                         struct pt_regs *regs,
-                                         struct hd_t *hd, unsigned long off)
-{
-       unsigned long base;
-       unsigned long vaddr;
-
-       base = lpd_get_handlers_base(hd);
-       if (base == 0)
-               return 0;
-
-       vaddr = base + off;
-       loader_module_prepare_ujump(ri, regs, vaddr);
-
-       return vaddr;
-}
-
-static unsigned long _redirect_to_fixup_handler(struct uretprobe_instance *ri,
-                                               struct pt_regs *regs,
-                                               struct hd_t *hd)
-{
-       return _redirect_to_handler(ri, regs, hd, _handler_fixup.off);
-}
-
-static unsigned long _redirect_to_reloc_handler(struct uretprobe_instance *ri,
-                                               struct pt_regs *regs,
-                                               struct hd_t *hd)
-{
-       return _redirect_to_handler(ri, regs, hd, _handler_reloc.off);
-}
-
-static unsigned long _redirect_to_proc_features(struct uretprobe_instance *ri,
-                                               struct pt_regs *regs,
-                                               struct hd_t *hd)
-{
-       return _redirect_to_handler(ri, regs, hd, _proc_features.off);
-}
-
-
-
-static int _process_eh(struct uretprobe_instance *ri, struct pt_regs *regs,
-                      rh_t rh, struct dentry *dentry)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-       struct hd_t *hd;
-       unsigned long vaddr = 0;
-       unsigned long old_pc = swap_get_upc(regs);
-
-       if ((dentry == NULL) || _is_in_handler())
-               goto out_set_orig;
-
-       hd = lpd_get_hd(pd, dentry);
-       if (hd == NULL)
-               goto out_set_orig;
-
-       if ((lpd_get_state(hd) == NOT_LOADED || lpd_get_state(hd) == FAILED) &&
-           lpd_get_init_state(pd)) {
-               vaddr = loader_not_loaded_entry(ri, regs, pd, hd);
-       } else if (lpd_get_state(hd) == LOADED) {
-               _set_in_handler(true);
-               vaddr = rh(ri, regs, hd);
-       }
-
-out_set_orig:
-       loader_set_priv_origin(ri, vaddr);
-
-       /* PC change check */
-       return old_pc != swap_get_upc(regs);
-}
-
-static int dl_fixup_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       return _process_eh(ri, regs, &_redirect_to_fixup_handler,
-                          _handler_fixup.dentry);
-}
-
-
-
-static void _restore_exec(struct uretprobe_instance *ri, struct hd_t *hd)
-{
-       if (_is_in_handler())
-               _set_in_handler(false);
-}
-
-static int _process_rh(struct uretprobe_instance *ri, struct pt_regs *regs,
-                      rh_t rh, struct dentry *dentry)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-       struct hd_t *hd;
-
-       if (dentry == NULL)
-               return 0;
-
-       hd = lpd_get_hd(pd, dentry);
-       if (hd == NULL)
-               return 0;
-
-       switch (lpd_get_state(hd)) {
-       case NOT_LOADED:
-               break;
-       case LOADING:
-               loader_loading_ret(ri, regs, pd, hd);
-               /* Patch all binaries */
-               if (lpd_get_state(hd))
-                       rh(ri, regs, hd);
-               break;
-       case LOADED:
-               /* TODO Check does we need this if library is loaded
-                * with RTLD_NOW ? */
-               _restore_exec(ri, hd);
-               break;
-       case FAILED:
-               loader_failed_ret(ri, regs, pd, hd);
-               break;
-       case ERROR:
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int common_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       return _process_rh(ri, regs, &_redirect_to_proc_features,
-                          _proc_features.dentry);
-}
-
-/* TODO Make ordinary interface. Now real data_size is set in init, because
- * it is unknown in this module during compile time. */
-static struct probe_desc pin_fixup = MAKE_URPROBE(dl_fixup_eh, common_rh, 0);
-
-
-static int dl_reloc_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       return _process_eh(ri, regs, &_redirect_to_reloc_handler,
-                          _handler_reloc.dentry);
-}
-
-/* TODO Make ordinary interface. Now real data_size is set in init, because
- * it is unknown in this module during compile time. */
-static struct probe_desc pin_reloc = MAKE_URPROBE(dl_reloc_eh, common_rh, 0);
-
-
-static int pthread_init_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-
-       /* Wait until pthread is inited, if it is going to be inited before
-        * loading our library */
-       lpd_set_init_state(pd, false);
-
-       return 0;
-}
-
-static int pthread_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-
-       lpd_set_init_state(pd, true);
-
-       return 0;
-}
-
-/* TODO Make ordinary interface. Now real data_size is set in init, because
- * it is unknown in this module during compile time. */
-static struct probe_desc pin_pinit = MAKE_URPROBE(pthread_init_eh,
-                                                pthread_init_rh, 0);
-
-
-static int _register_probe_el_no_lock(struct l_probe_el *l_probe)
-{
-       int ret;
-
-       /* register 'fix_up' */
-       l_probe->p_fixup.desc = &pin_fixup;
-       l_probe->p_fixup.offset = _linker_fixup.off;
-       ret = pin_register(&l_probe->p_fixup, l_probe->pfg,
-                          _linker_fixup.dentry);
-       if (ret != 0) {
-               printk(GT_PREFIX "Error register linker fixup probe. "
-                                "Linker dentry %s, "
-                                "dl_fixup() offset = 0x%lx\n",
-                                _linker_fixup.dentry->d_name.name,
-                                _linker_fixup.off);
-               return ret;
-       }
-
-       /* register 'reloc' */
-       l_probe->p_reloc.desc = &pin_reloc;
-       l_probe->p_reloc.offset = _linker_reloc.off;
-       ret = pin_register(&l_probe->p_reloc, l_probe->pfg,
-                          _linker_reloc.dentry);
-       if (ret != 0) {
-               printk(GT_PREFIX "Error register linker reloc probe. "
-                                 "Linker dentry %s, "
-                                "dl_reloc() offset = 0x%lx\n",
-                                _linker_reloc.dentry->d_name.name,
-                                _linker_reloc.off);
-
-               goto reg_probe_el_fail;
-       }
-
-       /* register 'init' */
-       l_probe->p_init.desc = &pin_pinit;
-       l_probe->p_init.offset = _pthread_init.off;
-       ret = pin_register(&l_probe->p_init, l_probe->pfg,
-                          _pthread_init.dentry);
-       if (ret != 0) {
-               printk(GT_PREFIX "Error register pthread minimal init. "
-                                "Pthread dentry %s, "
-                                "__pthread_minimal_init() offset = 0x%lx\n",
-                                _pthread_init.dentry->d_name.name,
-                                _pthread_init.off);
-
-               goto reg_probe_pthread_fail;
-       }
-
-       return 0;
-
-reg_probe_pthread_fail:
-       pin_unregister(&l_probe->p_reloc, l_probe->pfg);
-
-reg_probe_el_fail:
-       pin_unregister(&l_probe->p_fixup, l_probe->pfg);
-
-       return ret;
-}
-
-static int _unregister_probe_el_no_lock(struct l_probe_el *l_probe)
-{
-       pin_unregister(&l_probe->p_init, l_probe->pfg);
-       pin_unregister(&l_probe->p_reloc, l_probe->pfg);
-       pin_unregister(&l_probe->p_fixup, l_probe->pfg);
-
-       return 0;
-}
-
-static int _disable_got_patcher(void)
-{
-       struct l_probe_el *l_probe;
-       int ret = 0;
-
-       if (!_is_linker_data_available())
-               return -EINVAL;
-
-       _lock_probes_list();
-
-       list_for_each_entry(l_probe, &_reg_probes, list) {
-               ret = _unregister_probe_el_no_lock(l_probe);
-               if (ret == 0)
-                       list_move_tail(&l_probe->list, &_unreg_probes);
-       }
-
-       _unlock_probes_list();
-
-       _status = GT_OFF;
-
-       return ret;
-}
-
-static int _enable_got_patcher(void)
-{
-       struct l_probe_el *l_probe;
-       int ret;
-
-       if (!_is_linker_data_available() || !_is_handler_data_available() ||
-           !_is_pthread_data_available())
-               return -EINVAL;
-
-       _lock_probes_list();
-
-       list_for_each_entry(l_probe, &_unreg_probes, list) {
-               ret = _register_probe_el_no_lock(l_probe);
-               if (ret == 0)
-                       list_move_tail(&l_probe->list, &_reg_probes);
-               else
-                       goto enable_patcher_fail_unlock;
-       }
-
-       _unlock_probes_list();
-
-       _status = GT_ON;
-
-       return 0;
-enable_patcher_fail_unlock:
-       _unlock_probes_list();
-
-       printk(GT_PREFIX "Error registering linker probes, disabling...");
-       _disable_got_patcher();
-
-       return ret;
-}
-
-
-/* ===========================================================================
- * =                           LIST MANIPULATIONS                           =
- * ===========================================================================
- */
-static struct l_probe_el *_create_linker_probe_el(void)
-{
-       struct l_probe_el *l_probe;
-
-       l_probe = kzalloc(sizeof(*l_probe), GFP_KERNEL);
-       if (l_probe == NULL)
-               return NULL;
-
-       INIT_LIST_HEAD(&l_probe->list);
-
-       return l_probe;
-}
-
-static void _destroy_linker_probe_el_no_lock(struct l_probe_el *l_probe)
-{
-       if (l_probe->pfg)
-               put_pf_group(l_probe->pfg);
-
-       if (l_probe->task_id == GT_SET_BY_DENTRY && l_probe->dentry != NULL)
-               swap_put_dentry(l_probe->dentry);
-
-       if (l_probe->task_id == GT_SET_BY_ID && l_probe->id != NULL)
-               kfree(l_probe->id);
-
-       kfree(l_probe);
-}
-
-static void _clean_linker_probes(void)
-{
-       struct l_probe_el *l_probe, *n;
-       int ret;
-
-       _lock_probes_list();
-
-       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
-               ret = _unregister_probe_el_no_lock(l_probe);
-               if (ret != 0)
-                       printk(GT_PREFIX "Cannot remove linker probe!\n");
-               list_del(&l_probe->list);
-               _destroy_linker_probe_el_no_lock(l_probe);
-       }
-
-       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
-               list_del(&l_probe->list);
-               _destroy_linker_probe_el_no_lock(l_probe);
-       }
-
-       _unlock_probes_list();
-}
-
-
-/* ===========================================================================
- * =                          STRING MANIPULATIONS                           =
- * ===========================================================================
- */
-
-static size_t _get_dentry_len(struct dentry *dentry)
-{
-       return strnlen(dentry->d_name.name, PATH_MAX);
-}
-
-static size_t _get_pid_len(pid_t pid)
-{
-       /* FIXME Return constant - maximum digits for 10-based unsigned long on
-        * 64 bit architecture to avoid complicated evaluations. */
-        return 20;
-}
-
-static size_t _get_id_len(char *id)
-{
-       return strnlen(id, PATH_MAX);
-}
-
-static size_t _get_item_len(struct l_probe_el *l_probe)
-{
-       if (l_probe->task_id == GT_SET_BY_DENTRY)
-               return _get_dentry_len(l_probe->dentry);
-       else if (l_probe->task_id == GT_SET_BY_PID)
-               return _get_pid_len(l_probe->tgid);
-       else if (l_probe->task_id == GT_SET_BY_ID)
-               return _get_id_len(l_probe->id);
-
-       printk(GT_PREFIX "Error! Unknown process identificator!\n");
-       return 0;
-}
-
-static char *_copy_dentry_item(char *dest, struct dentry *dentry)
-{
-       size_t len;
-
-       len = strnlen(dentry->d_name.name, PATH_MAX);
-       memcpy(dest, dentry->d_name.name, len);
-
-       return (dest + len);
-}
-
-static char *_copy_pid_item(char *dest, pid_t pid)
-{
-       int ret;
-       size_t len;
-
-       len = _get_pid_len(pid);
-
-       ret = snprintf(dest, len, "%lu", (unsigned long)pid);
-       if (ret >= len)
-               printk(GT_PREFIX "PID string is truncated!\n");
-
-       return (dest + ret);
-}
-
-static char *_copy_id_item(char *dest, char *id)
-{
-       size_t len;
-
-       len = strnlen(id, PATH_MAX);
-       memcpy(dest, id, len);
-
-       return (dest + len);
-}
-
-static char *_copy_item(char *dest, struct l_probe_el *l_probe)
-{
-       if (l_probe->task_id == GT_SET_BY_DENTRY)
-               return _copy_dentry_item(dest, l_probe->dentry);
-       else if (l_probe->task_id == GT_SET_BY_PID)
-               return _copy_pid_item(dest, l_probe->tgid);
-       else if (l_probe->task_id == GT_SET_BY_ID)
-               return _copy_id_item(dest, l_probe->id);
-
-       printk(GT_PREFIX "Error! Unknown process identificator!\n");
-       return dest;
-}
-
-static char *_add_separator(char *dest)
-{
-       const char sep = ':';
-
-       *dest = sep;
-
-       return (dest + 1);
-}
-
-static int _add_to_list(struct l_probe_el *l_probe)
-{
-       int ret = 0;
-
-       _lock_probes_list();
-       if (_is_enable()) {
-               ret = _register_probe_el_no_lock(l_probe);
-               if (ret == 0)
-                       list_add_tail(&l_probe->list, &_reg_probes);
-       } else {
-               list_add_tail(&l_probe->list, &_unreg_probes);
-       }
-
-       _unlock_probes_list();
-
-       return ret;
-}
-
-static int _remove_from_list(cf_t cb, void *data)
-{
-       struct l_probe_el *l_probe, *n;
-       int ret = 0;
-
-       _lock_probes_list();
-
-       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
-               if (cb(l_probe, data)) {
-                       ret = _unregister_probe_el_no_lock(l_probe);
-                       if (ret == 0) {
-                               list_del(&l_probe->list);
-                               _destroy_linker_probe_el_no_lock(l_probe);
-                       }
-                       goto remove_from_list_unlock;
-               }
-       }
-
-       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
-               if (cb(l_probe, data)) {
-                       list_del(&l_probe->list);
-                       _destroy_linker_probe_el_no_lock(l_probe);
-                       goto remove_from_list_unlock;
-               }
-       }
-
-remove_from_list_unlock:
-       _unlock_probes_list();
-
-       return ret;
-}
-
-
-
-
-int gtm_set_linker_path(char *path)
-{
-       struct dentry *dentry;
-
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL)
-               return -EINVAL;
-
-       /* We use get_dentry only once, so use put dentry also only once */
-       if (_linker_fixup.dentry != NULL ||
-           _linker_reloc.dentry != NULL) {
-               if (_linker_fixup.dentry != NULL)
-                       swap_put_dentry(_linker_fixup.dentry);
-               else
-                       swap_put_dentry(_linker_reloc.dentry);
-       }
-
-       _linker_fixup.dentry = dentry;
-       _linker_reloc.dentry = dentry;
-
-       return 0;
-}
-
-int gtm_set_fixup_off(unsigned long offset)
-{
-       _linker_fixup.off = offset;
-
-       return 0;
-}
-
-int gtm_set_reloc_off(unsigned long offset)
-{
-       _linker_reloc.off = offset;
-
-       return 0;
-}
-
-int gtm_switch(enum gt_status stat)
-{
-       int ret;
-
-       switch (stat) {
-       case GT_ON:
-               ret = _enable_got_patcher();
-               break;
-       case GT_OFF:
-               ret = _disable_got_patcher();
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-enum gt_status gtm_status(void)
-{
-       return _status;
-}
-
-int gtm_add_by_path(char *path)
-{
-       struct dentry *dentry;
-       struct pf_group *pfg;
-       struct l_probe_el *l_probe;
-       int ret;
-
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL)
-               return -EINVAL;
-
-       pfg = get_pf_group_by_dentry(dentry, dentry);
-       if (pfg == NULL) {
-               ret = -ENOMEM;
-               goto add_by_path_put_dentry;
-       }
-
-       l_probe = _create_linker_probe_el();
-       if (l_probe == NULL) {
-               ret = -ENOMEM;
-               goto add_by_path_put_pfg;
-       }
-
-       l_probe->pfg = pfg;
-       l_probe->task_id = GT_SET_BY_DENTRY;
-       l_probe->dentry = dentry;
-
-       ret = _add_to_list(l_probe);
-       if (ret != 0)
-               goto add_by_path_free;
-
-       return 0;
-
-add_by_path_free:
-       kfree(l_probe);
-
-add_by_path_put_pfg:
-       put_pf_group(pfg);
-
-add_by_path_put_dentry:
-       swap_put_dentry(dentry);
-
-       return ret;
-}
-
-int gtm_add_by_pid(pid_t pid)
-{
-       struct pf_group *pfg;
-       struct l_probe_el *l_probe;
-       int ret;
-
-       /* TODO Add dentry as private data */
-       pfg = get_pf_group_by_tgid(pid, NULL);
-       if (pfg == NULL)
-               return -ENOMEM;
-
-       l_probe = _create_linker_probe_el();
-       if (l_probe == NULL) {
-               ret = -ENOMEM;
-               goto add_by_pid_put_pfg;
-       }
-
-       l_probe->pfg = pfg;
-       l_probe->task_id = GT_SET_BY_PID;
-       l_probe->tgid = pid;
-
-       ret = _add_to_list(l_probe);
-       if (ret != 0)
-               goto add_by_pid_free;
-
-       return 0;
-
-add_by_pid_free:
-       kfree(l_probe);
-
-add_by_pid_put_pfg:
-       put_pf_group(pfg);
-
-       return ret;
-}
-
-int gtm_add_by_id(char *id)
-{
-       char *new_id;
-       struct pf_group *pfg;
-       struct l_probe_el *l_probe;
-       size_t len;
-       int ret;
-
-       len = strnlen(id, PATH_MAX);
-       new_id = kmalloc(len, GFP_KERNEL);
-       if (new_id == NULL)
-               return -ENOMEM;
-
-       /* TODO Add dentry as private data */
-       pfg = get_pf_group_by_comm(id, NULL);
-       if (pfg == NULL) {
-               ret = -ENOMEM;
-               goto add_by_id_free_id;
-       }
-
-       l_probe = _create_linker_probe_el();
-       if (l_probe == NULL) {
-               ret = -ENOMEM;
-               goto add_by_id_put_pfg;
-       }
-
-       l_probe->pfg = pfg;
-       l_probe->task_id = GT_SET_BY_ID;
-       l_probe->id = new_id;
-
-       ret = _add_to_list(l_probe);
-       if (ret != 0)
-               goto add_by_id_free;
-
-       return 0;
-
-add_by_id_free:
-       kfree(l_probe);
-
-add_by_id_put_pfg:
-       put_pf_group(pfg);
-
-add_by_id_free_id:
-       kfree(new_id);
-
-       return ret;
-}
-
-int gtm_del_by_path(char *path)
-{
-       struct dentry *dentry;
-       int ret = 0;
-
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL)
-               return -EINVAL;
-
-       ret = _remove_from_list(_check_by_dentry, dentry);
-
-       return ret;
-}
-
-int gtm_del_by_pid(pid_t pid)
-{
-       int ret = 0;
-
-       ret = _remove_from_list(_check_by_pid, &pid);
-
-       return ret;
-}
-
-int gtm_del_by_id(char *id)
-{
-       int ret = 0;
-
-       ret = _remove_from_list(_check_by_id, id);
-
-       return ret;
-}
-
-int gtm_del_all(void)
-{
-       int ret = 0;
-
-       ret = _remove_from_list(_del_all, NULL);
-
-       return ret;
-}
-
-ssize_t gtm_get_targets(char **targets)
-{
-       struct l_probe_el *l_probe;
-       char *ptr;
-       size_t len = 0;
-
-       _lock_probes_list();
-       list_for_each_entry(l_probe, &_reg_probes, list) {
-               /* Add separator */
-               len += _get_item_len(l_probe) + 1;
-       }
-
-       list_for_each_entry(l_probe, &_unreg_probes, list) {
-               /* Add separator */
-               len += _get_item_len(l_probe) + 1;
-       }
-       _unlock_probes_list();
-
-       *targets = kmalloc(len, GFP_KERNEL);
-       if (*targets == NULL)
-               return -ENOMEM;
-
-       ptr = *targets;
-
-       _lock_probes_list();
-
-       list_for_each_entry(l_probe, &_reg_probes, list) {
-               ptr = _copy_item(ptr, l_probe);
-               ptr = _add_separator(ptr);
-       }
-
-       list_for_each_entry(l_probe, &_unreg_probes, list) {
-               ptr = _copy_item(ptr, l_probe);
-               ptr = _add_separator(ptr);
-       }
-
-       _unlock_probes_list();
-
-       *targets[len - 1] = '\0';
-
-       return len;
-}
-
-int gtm_set_handler_path(char *path)
-{
-       struct dentry *dentry;
-       int ret;
-
-       /* We use get_dentry only once, so use put dentry also only once */
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL)
-               return -EINVAL;
-
-       if (_handler_fixup.dentry)
-               swap_put_dentry(_handler_fixup.dentry);
-
-       if (_handler_reloc.dentry)
-               swap_put_dentry(_handler_reloc.dentry);
-
-       if (_proc_features.dentry)
-               swap_put_dentry(_proc_features.dentry);
-
-       _handler_fixup.dentry = dentry;
-       _handler_reloc.dentry = dentry;
-       _proc_features.dentry = dentry;
-
-       /* TODO Do smth with this:
-        * make interface for loader to remove handlers
-        * and add/delete when gtm_set_handler() is called
-        * Check container_of() may be useful */
-       ret = loader_add_handler(path);
-
-       return ret;
-}
-
-int gtm_set_handler_fixup_off(unsigned long offset)
-{
-       _handler_fixup.off = offset;
-
-       return 0;
-}
-
-int gtm_set_handler_reloc_off(unsigned long offset)
-{
-       _handler_reloc.off = offset;
-
-       return 0;
-}
-
-int gtm_set_proc_features_off(unsigned long offset)
-{
-       _proc_features.off = offset;
-
-       return 0;
-}
-
-int gtm_set_pthread_path(char *path)
-{
-       struct dentry *dentry;
-
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL)
-               return -EINVAL;
-
-       if (_pthread_init.dentry != NULL)
-               swap_put_dentry(_pthread_init.dentry);
-
-       _pthread_init.dentry = dentry;
-
-       return 0;
-}
-
-int gtm_set_init_off(unsigned long offset)
-{
-       _pthread_init.off = offset;
-
-       return 0;
-}
-
-static int gtm_init(void)
-{
-       int ret;
-
-       ret = gtd_init();
-       if (ret)
-               goto gtd_init_err;
-
-       ret = swap_ktd_reg(&gt_ktd);
-       if (ret)
-               goto gtd_ktd_reg_err;
-
-       return 0;
-
-gtd_ktd_reg_err:
-       gtd_exit();
-
-gtd_init_err:
-       return ret;
-}
-
-static void gtm_exit(void)
-{
-       swap_ktd_unreg(&gt_ktd);
-       gtd_exit();
-
-       _clean_linker_probes();
-
-       /* We use get_dentry only once, so use put dentry also only once */
-       if (_handler_fixup.dentry != NULL ||
-           _handler_reloc.dentry != NULL) {
-               if (_handler_fixup.dentry != NULL)
-                       swap_put_dentry(_handler_fixup.dentry);
-               else
-                       swap_put_dentry(_handler_reloc.dentry);
-               _handler_reloc.dentry = NULL;
-               _handler_fixup.dentry = NULL;
-       }
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, gtm_init, gtm_exit, NULL, NULL);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP GOT Patcher Module");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/got_patcher/gt_module.h b/got_patcher/gt_module.h
deleted file mode 100644 (file)
index 7e1b151..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __GT_MODULE_H__
-#define __GT_MODULE_H__
-
-#include <linux/types.h>
-
-enum gt_status {
-       GT_ON,
-       GT_OFF
-};
-
-/* Linker data */
-int gtm_set_linker_path(char *path);
-int gtm_set_fixup_off(unsigned long offset);
-int gtm_set_reloc_off(unsigned long offset);
-int gtm_switch(enum gt_status stat);
-enum gt_status gtm_status(void);
-
-/* Target processes data */
-int gtm_add_by_path(char *path);
-int gtm_add_by_pid(pid_t pid);
-int gtm_add_by_id(char *id);
-int gtm_del_by_path(char *path);
-int gtm_del_by_pid(pid_t pid);
-int gtm_del_by_id(char *id);
-int gtm_del_all(void);
-/* Returns len on success, error code on fail.
- * Allocates memory with malloc(), caller should free it */
-ssize_t gtm_get_targets(char **targets);
-
-/* Handlers data */
-int gtm_set_handler_path(char *path);
-int gtm_set_handler_fixup_off(unsigned long offset);
-int gtm_set_handler_reloc_off(unsigned long offset);
-int gtm_set_proc_features_off(unsigned long offset);
-
-/* Pthread data */
-int gtm_set_pthread_path(char *path);
-int gtm_set_init_off(unsigned long offset);
-
-#endif /* __GT_MODULE_H__ */
diff --git a/kprobe/Kbuild b/kprobe/Kbuild
deleted file mode 100644 (file)
index e6d12ca..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_kprobe.o
-swap_kprobe-y := \
-       swap_kprobes_deps.o \
-       swap_slots.o \
-       swap_td_raw.o \
-       swap_ktd.o
-
-
-### ARM64
-swap_kprobe-$(CONFIG_ARM64) += \
-       arch/arm64/swap-asm/simulate-insn.o \
-       arch/arm64/swap-asm/condn-helpers.o
-
-
-ifeq ($(CONFIG_SWAP_KERNEL_IMMUTABLE), y)
-
-swap_kprobe-y += swap_no_kprobes.o
-
-else # CONFIG_SWAP_KERNEL_IMMUTABLE
-
-swap_kprobe-y += swap_kprobes.o
-
-### ARM
-swap_kprobe-$(CONFIG_ARM) += \
-       arch/arm/swap-asm/swap_kprobes.o \
-       ../arch/arm/probes/probes_arm.o
-
-ifeq ($(CONFIG_STRICT_MEMORY_RWX), y)
-swap_kprobe-$(CONFIG_ARM) += arch/arm/swap-asm/memory_rwx.o
-endif #ifeq ($(CONFIG_STRICT_MEMORY_RWX), y)
-
-
-### ARM64
-swap_kprobe-$(CONFIG_ARM64) += arch/arm64/swap-asm/swap_kprobes.o \
-                               arch/arm64/swap-asm/dbg_interface.o \
-                               arch/arm64/swap-asm/kprobes-arm64.o
-
-
-### X86
-swap_kprobe-$(CONFIG_X86) += arch/x86/swap-asm/swap_kprobes.o
-
-endif # CONFIG_SWAP_KERNEL_IMMUTABLE
diff --git a/kprobe/arch/arm/swap-asm/memory_rwx.c b/kprobe/arch/arm/swap-asm/memory_rwx.c
deleted file mode 100644 (file)
index c7a9510..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @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, 2014
- */
-
-
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <asm/mmu_writeable.h>
-
-
-#include <ksyms/ksyms.h>
-
-
-static struct mm_struct *swap_init_mm;
-static int (*swap_set_memory_ro)(unsigned long addr, int numpages);
-static int (*swap_set_memory_rw)(unsigned long addr, int numpages);
-
-
-static int get_pte_cb(pte_t *ptep, pgtable_t token,
-                     unsigned long addr, void *data)
-{
-       *(pte_t *)data = *ptep;
-
-       return 1;
-}
-
-static pte_t get_pte(unsigned long page_addr)
-{
-       pte_t pte = 0;
-
-       apply_to_page_range(swap_init_mm, page_addr,
-                           PAGE_SIZE, get_pte_cb, &pte);
-
-       return pte;
-}
-
-static void write_to_module(unsigned long addr, unsigned long val)
-{
-       unsigned long *maddr = (unsigned long *)addr;
-       unsigned long page_addr = addr & PAGE_MASK;
-       pte_t pte;
-
-       pte = get_pte(page_addr);
-       if (pte_write(pte) == 0) {
-               unsigned long flags;
-               DEFINE_SPINLOCK(mem_lock);
-
-               spin_lock_irqsave(&mem_lock, flags);
-               if (swap_set_memory_rw(page_addr, 1) == 0) {
-                       *maddr = val;
-                       swap_set_memory_ro(page_addr, 1);
-               } else {
-                       printk(KERN_INFO "RWX: failed to write memory %08lx (%08lx)\n",
-                              addr, val);
-               }
-               spin_unlock_irqrestore(&mem_lock, flags);
-       } else {
-               *maddr = val;
-       }
-
-       flush_icache_range(addr, addr + sizeof(long));
-}
-
-void mem_rwx_write_u32(unsigned long addr, unsigned long val)
-{
-       if (addr < MODULES_VADDR || addr >= MODULES_END) {
-               /*
-                * if addr doesn't belongs kernel space,
-                * segmentation fault will occur
-                */
-               mem_text_write_kernel_word((long *)addr, val);
-       } else {
-               write_to_module(addr, val);
-       }
-}
-
-int mem_rwx_once(void)
-{
-       const char *sym;
-
-       sym = "set_memory_ro";
-       swap_set_memory_ro = (void *)swap_ksyms(sym);
-       if (swap_set_memory_ro == NULL)
-               goto not_found;
-
-       sym = "set_memory_rw";
-       swap_set_memory_rw = (void *)swap_ksyms(sym);
-       if (swap_set_memory_rw == NULL)
-               goto not_found;
-
-       sym = "init_mm";
-       swap_init_mm = (void *)swap_ksyms(sym);
-       if (swap_init_mm == NULL)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
diff --git a/kprobe/arch/arm/swap-asm/memory_rwx.h b/kprobe/arch/arm/swap-asm/memory_rwx.h
deleted file mode 100644 (file)
index f533965..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @file kprobe/arch/asm-arm/memory_rwx.h
- *
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @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, 2014
- */
-
-
-#ifndef _MEMORY_RWX_H
-#define _MEMORY_RWX_H
-
-
-int mem_rwx_once(void);
-void mem_rwx_write_u32(unsigned long addr, unsigned long val);
-
-
-#endif /* _MEMORY_RWX_H */
diff --git a/kprobe/arch/arm/swap-asm/swap_kprobes.c b/kprobe/arch/arm/swap-asm/swap_kprobes.c
deleted file mode 100644 (file)
index 5b510cf..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/**
- * kprobe/arch/asm-arm/swap_kprobes.c
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation; Support x86.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Alexander Shirshikov <a.shirshikov@samsung.com>: initial implementation for Thumb
- * @author Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
- * @author Stanislav Andreev <s.andreev@samsung.com>: redesign of kprobe functionality -
- * kprobe_handler() now called via undefined instruction hooks
- * @author Stanislav Andreev <s.andreev@samsung.com>: hash tables search implemented for uprobes
- *
- * @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, 2006-2014
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe implementation for ARM architecture.
- */
-
-
-#include <linux/kconfig.h>
-
-#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
-# error "Kernel is immutable"
-#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
-
-
-#include <linux/module.h>
-#include <asm/cacheflush.h>
-#include <asm/traps.h>
-#include <linux/ptrace.h>
-#include <linux/list.h>
-#include <linux/hash.h>
-#include <ksyms/ksyms.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kdebug.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <arch/arm/probes/probes_arm.h>
-#include "swap_kprobes.h"
-
-
-static void (*__swap_register_undef_hook)(struct undef_hook *hook);
-static void (*__swap_unregister_undef_hook)(struct undef_hook *hook);
-
-
-/**
- * @brief Creates trampoline for kprobe.
- *
- * @param p Pointer to kp_core.
- * @param sm Pointer to slot manager
- * @return 0 on success, error code on error.
- */
-int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
-{
-       u32 *tramp;
-       int ret;
-
-       tramp = swap_slot_alloc(sm);
-       if (tramp == NULL)
-               return -ENOMEM;
-
-       p->opcode = *(unsigned long *)p->addr;
-       ret = make_trampoline_arm(p->addr, p->opcode, tramp);
-       if (ret) {
-               swap_slot_free(sm, tramp);
-               return ret;
-       }
-
-       flush_icache_range((unsigned long)tramp,
-                          (unsigned long)tramp + KPROBES_TRAMP_LEN);
-
-       p->ainsn.insn = (unsigned long *)tramp;
-
-       return 0;
-}
-
-/**
- * @brief Prepares singlestep for current CPU.
- *
- * @param p Pointer to kprobe.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-static void prepare_singlestep(struct kp_core *p, struct pt_regs *regs)
-{
-       regs->ARM_pc = (unsigned long)p->ainsn.insn;
-}
-
-static void save_previous_kp_core(struct kp_core_ctlblk *kcb)
-{
-       kcb->prev_kp_core.p = kp_core_running();
-       kcb->prev_kp_core.status = kcb->kp_core_status;
-}
-
-/**
- * @brief Restores previous kp_core.
- *
- * @param kcb Pointer to kp_core_ctlblk which contains previous kp_core.
- * @return Void.
- */
-void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
-{
-       kp_core_running_set(kcb->prev_kp_core.p);
-       kcb->kp_core_status = kcb->prev_kp_core.status;
-}
-
-static int kprobe_handler(struct pt_regs *regs)
-{
-       struct kp_core *p, *cur;
-       struct kp_core_ctlblk *kcb;
-       struct kctx *ctx = current_kctx;
-
-       if (regs->ARM_pc == sched_addr)
-               switch_to_bits_set(ctx, SWITCH_TO_KP);
-
-       kcb = kp_core_ctlblk();
-       cur = kp_core_running();
-
-       rcu_read_lock();
-       p = kp_core_by_addr(regs->ARM_pc);
-       if (p)
-               kp_core_get(p);
-       rcu_read_unlock();
-
-       if (p) {
-               if (cur) {
-                       /* Kprobe is pending, so we're recursing. */
-                       switch (kcb->kp_core_status) {
-                       case KPROBE_HIT_ACTIVE:
-                       case KPROBE_HIT_SSDONE:
-                               /* A pre- or post-handler probe got us here. */
-                               save_previous_kp_core(kcb);
-                               kp_core_running_set(p);
-                               kcb->kp_core_status = KPROBE_REENTER;
-                               prepare_singlestep(p, regs);
-                               restore_previous_kp_core(kcb);
-                               break;
-                       default:
-                               /* impossible cases */
-                               BUG();
-                       }
-               } else {
-                       kp_core_running_set(p);
-                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
-
-                       if (!(regs->ARM_cpsr & PSR_I_BIT))
-                               local_irq_enable();
-
-                       if (!p->handlers.pre(p, regs)) {
-                               kcb->kp_core_status = KPROBE_HIT_SS;
-                               prepare_singlestep(p, regs);
-                               kp_core_running_set(NULL);
-                       }
-               }
-               kp_core_put(p);
-       } else {
-               goto no_kprobe;
-       }
-
-       switch_to_bits_reset(ctx, SWITCH_TO_KP);
-
-       return 0;
-
-no_kprobe:
-       printk(KERN_INFO "no_kprobe: Not one of ours: let kernel handle it %p\n",
-                       (unsigned long *)regs->ARM_pc);
-       return 1;
-}
-
-/**
- * @brief Trap handler.
- *
- * @param regs Pointer to CPU register data.
- * @param instr Instruction.
- * @return kprobe_handler result.
- */
-int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
-{
-       int ret;
-
-       if (likely(instr == BREAK_ARM)) {
-               ret = kprobe_handler(regs);
-       } else {
-               struct kp_core *p;
-
-               rcu_read_lock();
-               p = kp_core_by_addr(regs->ARM_pc);
-
-               /* skip false exeption */
-               ret = p && (p->opcode == instr) ? 0 : 1;
-               rcu_read_unlock();
-       }
-
-       return ret;
-}
-
-/**
- * @brief Probe pre handler.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0.
- */
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct jprobe *jp = container_of(p, struct jprobe, kp);
-       entry_point_t entry = (entry_point_t)jp->entry;
-
-       if (entry) {
-               entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
-                     regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
-       } else {
-               swap_jprobe_return();
-       }
-
-       return 0;
-}
-
-/**
- * @brief Jprobe return stub.
- *
- * @return Void.
- */
-void swap_jprobe_return(void)
-{
-}
-EXPORT_SYMBOL_GPL(swap_jprobe_return);
-
-/**
- * @brief Break handler stub.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0.
- */
-int swap_longjmp_break_handler (struct kprobe *p, struct pt_regs *regs)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_longjmp_break_handler);
-
-#ifdef CONFIG_STRICT_MEMORY_RWX
-#include "memory_rwx.h"
-
-static void write_u32(unsigned long addr, unsigned long val)
-{
-       mem_rwx_write_u32(addr, val);
-}
-#else /* CONFIG_STRICT_MEMORY_RWX */
-static void write_u32(unsigned long addr, unsigned long val)
-{
-       *(long *)addr = val;
-       flush_icache_range(addr, addr + sizeof(long));
-}
-#endif /* CONFIG_STRICT_MEMORY_RWX */
-
-/**
- * @brief Arms kprobe.
- *
- * @param p Pointer to target kprobe.
- * @return Void.
- */
-void arch_kp_core_arm(struct kp_core *core)
-{
-       write_u32(core->addr, BREAK_ARM);
-}
-
-/**
- * @brief Disarms kprobe.
- *
- * @param p Pointer to target kprobe.
- * @return Void.
- */
-void arch_kp_core_disarm(struct kp_core *core)
-{
-       write_u32(core->addr, core->opcode);
-}
-
-/**
- * @brief Kretprobe trampoline. Provides jumping to probe handler.
- *
- * @return Void.
- */
-void __naked swap_kretprobe_trampoline(void)
-{
-       __asm__ __volatile__ (
-               "stmdb  sp!, {r0 - r11}\n"
-               "mov    r0, sp\n"               /* struct pt_regs -> r0 */
-               "bl     swap_trampoline_handler\n"
-               "mov    lr, r0\n"
-               "ldmia  sp!, {r0 - r11}\n"
-               "bx     lr\n"
-               : : : "memory");
-}
-
-/**
- * @brief Prepares kretprobes, saves ret address, makes function return to
- * trampoline.
- *
- * @param ri Pointer to kretprobe_instance.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       unsigned long *ptr_ret_addr;
-
-       /* for __switch_to probe */
-       if ((unsigned long)ri->rp->kp.addr == sched_addr) {
-               struct thread_info *tinfo = (struct thread_info *)regs->ARM_r2;
-
-               ptr_ret_addr = (unsigned long *)&tinfo->cpu_context.pc;
-               ri->sp = NULL;
-               ri->task = tinfo->task;
-               switch_to_bits_set(kctx_by_task(tinfo->task), SWITCH_TO_RP);
-       } else {
-               ptr_ret_addr = (unsigned long *)&regs->ARM_lr;
-               ri->sp = (unsigned long *)regs->ARM_sp;
-       }
-
-       /* Save the return address */
-       ri->ret_addr = (unsigned long *)*ptr_ret_addr;
-
-       /* Replace the return addr with trampoline addr */
-       *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline;
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                                   jumper                                   *
- ******************************************************************************
- */
-struct cb_data {
-       unsigned long ret_addr;
-       unsigned long r0;
-
-       jumper_cb_t cb;
-       char data[0];
-};
-
-static unsigned long __used get_r0(struct cb_data *data)
-{
-       return data->r0;
-}
-
-static unsigned long __used jump_handler(struct cb_data *data)
-{
-       unsigned long ret_addr = data->ret_addr;
-
-       /* call callback */
-       data->cb(data->data);
-
-       /* FIXME: potential memory leak, when process kill */
-       kfree(data);
-
-       return ret_addr;
-}
-
-/* FIXME: restore condition flags */
-
-/**
- * @brief Jumper trampoline.
- *
- * @return Void.
- */
-void jump_trampoline(void);
-__asm(
-       "jump_trampoline:\n"
-
-       "push   {r0 - r12}\n"
-       "mov    r1, r0\n"       /* data --> r1 */
-       "bl     get_r0\n"
-       "str    r0, [sp]\n"     /* restore r0 */
-       "mov    r0, r1\n"       /* data --> r0 */
-       "bl     jump_handler\n"
-       "mov    lr, r0\n"
-       "pop    {r0 - r12}\n"
-       "bx     lr\n"
-);
-
-/**
- * @brief Get jumper address.
- *
- * @return Jumper address.
- */
-unsigned long get_jump_addr(void)
-{
-       return (unsigned long)&jump_trampoline;
-}
-EXPORT_SYMBOL_GPL(get_jump_addr);
-
-/**
- * @brief Set jumper probe callback.
- *
- * @param ret_addr Jumper probe return address.
- * @param regs Pointer to CPU registers data.
- * @param cb Jumper callback of jumper_cb_t type.
- * @param data Data that should be stored in cb_data.
- * @param size Size of the data.
- * @return 0.
- */
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
-               jumper_cb_t cb, void *data, size_t size)
-{
-       struct cb_data *cb_data;
-
-       cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
-       if (cb_data == NULL)
-               return -ENOMEM;
-
-       /* save data */
-       if (size)
-               memcpy(cb_data->data, data, size);
-
-       /* save info for restore */
-       cb_data->ret_addr = ret_addr;
-       cb_data->cb = cb;
-       cb_data->r0 = regs->ARM_r0;
-
-       /* save cb_data to r0 */
-       regs->ARM_r0 = (long)cb_data;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(set_jump_cb);
-
-
-
-
-/**
- * @brief Registers hook on specified instruction.
- *
- * @param hook Pointer to struct undef_hook.
- * @return Void.
- */
-void swap_register_undef_hook(struct undef_hook *hook)
-{
-       __swap_register_undef_hook(hook);
-}
-EXPORT_SYMBOL_GPL(swap_register_undef_hook);
-
-/**
- * @brief Unregisters hook.
- *
- * @param hook Pointer to struct undef_hook.
- * @return Void.
- */
-void swap_unregister_undef_hook(struct undef_hook *hook)
-{
-       __swap_unregister_undef_hook(hook);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_undef_hook);
-
-/* kernel probes hook */
-static struct undef_hook undef_ho_k = {
-       .instr_mask     = 0,
-       .instr_val      = 0,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = SVC_MODE,
-       .fn             = kprobe_trap_handler
-};
-
-/**
- * @brief Arch-dependend module deps initialization stub.
- *
- * @return 0.
- */
-int arch_init_module_deps(void)
-{
-       const char *sym;
-#ifdef CONFIG_STRICT_MEMORY_RWX
-       int ret;
-
-       ret = mem_rwx_once();
-       if (ret)
-               return ret;
-#endif /* CONFIG_STRICT_MEMORY_RWX */
-
-       sym = "register_undef_hook";
-       __swap_register_undef_hook = (void *)swap_ksyms(sym);
-       if (__swap_register_undef_hook == NULL)
-               goto not_found;
-
-       sym = "unregister_undef_hook";
-       __swap_unregister_undef_hook = (void *)swap_ksyms(sym);
-       if (__swap_unregister_undef_hook == NULL)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-/**
- * @brief Initializes kprobes module for ARM arch.
- *
- * @return 0 on success, error code on error.
- */
-int swap_arch_init_kprobes(void)
-{
-       swap_register_undef_hook(&undef_ho_k);
-
-       return 0;
-}
-
-/**
- * @brief Uninitializes kprobe module.
- *
- * @return Void.
- */
-void swap_arch_exit_kprobes(void)
-{
-       swap_unregister_undef_hook(&undef_ho_k);
-}
-
-
-/* export symbol for probes_arm.h */
-EXPORT_SYMBOL_GPL(noret_arm);
-EXPORT_SYMBOL_GPL(make_trampoline_arm);
-
-#include <arch/arm/probes/tramps_arm.h>
-/* export symbol for tramps_arm.h */
-EXPORT_SYMBOL_GPL(gen_insn_execbuf);
-EXPORT_SYMBOL_GPL(pc_dep_insn_execbuf);
-EXPORT_SYMBOL_GPL(b_r_insn_execbuf);
-EXPORT_SYMBOL_GPL(b_cond_insn_execbuf);
-EXPORT_SYMBOL_GPL(blx_off_insn_execbuf);
diff --git a/kprobe/arch/arm/swap-asm/swap_kprobes.h b/kprobe/arch/arm/swap-asm/swap_kprobes.h
deleted file mode 100644 (file)
index 0ef86f2..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/**
- * @file kprobe/arch/asm-arm/swap_kprobes.h
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- *             initial implementation for ARM/MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com>:
- *             User-Space Probes initial implementation;
- *             Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- *             redesign module for separating core and arch parts
- * @author Alexander Shirshikov <a.shirshikov@samsung.com>:
- *              initial implementation for Thumb
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * ARM arch-dependent kprobes interface declaration.
- */
-
-
-#ifndef _SWAP_ASM_ARM_KPROBES_H
-#define _SWAP_ASM_ARM_KPROBES_H
-
-#include <linux/sched.h>
-#include <linux/compiler.h>
-#include <arch/arm/probes/probes.h>
-
-typedef unsigned long kprobe_opcode_t;
-
-
-/** Kprobes trampoline length */
-#define KPROBES_TRAMP_LEN              PROBES_TRAMP_LEN
-
-/** User register offset */
-#define UREGS_OFFSET 8
-
-/**
- * @struct prev_kp_core
- * @brief Stores previous kp_core.
- * @var prev_kp_core::p
- * Pointer to kp_core struct.
- * @var prev_kp_core::status
- * Kprobe status.
- */
-struct prev_kp_core {
-       struct kp_core *p;
-       unsigned long status;
-};
-
-/**
- * @brief Gets task pc.
- *
- * @param p Pointer to task_struct
- * @return Value in pc.
- */
-static inline unsigned long arch_get_task_pc(struct task_struct *p)
-{
-       return task_thread_info(p)->cpu_context.pc;
-}
-
-/**
- * @brief Sets task pc.
- *
- * @param p Pointer to task_struct.
- * @param val Value that should be set.
- * @return Void.
- */
-static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
-{
-       task_thread_info(p)->cpu_context.pc = val;
-}
-
-/**
- * @brief Gets syscall registers.
- *
- * @param sp Pointer to stack.
- * @return Pointer to CPU regs data.
- */
-static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
-{
-       return (struct pt_regs *)(sp + UREGS_OFFSET);
-}
-
-/**
- * @brief Gets stack pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @return Stack address.
- */
-static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
-{
-       return regs->ARM_sp;
-}
-
-/**
- * @brief Sets stack pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @param sp New stack pointer value.
- * @return Void
- */
-static inline void swap_set_stack_ptr(struct pt_regs *regs, unsigned long sp)
-{
-       regs->ARM_sp = sp;
-}
-
-/**
- * @brief Gets instruction pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @return Pointer to pc.
- */
-static inline unsigned long swap_get_kpc(struct pt_regs *regs)
-{
-       return regs->ARM_pc | !!thumb_mode(regs);
-}
-
-/**
- * @brief Sets instruction pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @param val Address that should be stored in pc.
- * @return Void.
- */
-static inline void swap_set_kpc(struct pt_regs *regs, unsigned long val)
-{
-       if (val & 1) {
-               regs->ARM_pc = val & ~1;
-               regs->ARM_cpsr |= PSR_T_BIT;
-       } else {
-               regs->ARM_pc = val;
-               regs->ARM_cpsr &= ~PSR_T_BIT;
-       }
-}
-
-/**
- * @brief Gets specified argument.
- *
- * @param regs Pointer to CPU registers data.
- * @param num Number of the argument.
- * @return Argument value.
- */
-static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
-{
-       return regs->uregs[num];
-}
-
-/**
- * @brief Sets specified argument.
- *
- * @param regs Pointer to CPU registers data.
- * @param num Number of the argument.
- * @param val New argument value.
- * @return Void.
- */
-static inline void swap_set_arg(struct pt_regs *regs, int num,
-                               unsigned long val)
-{
-       regs->uregs[num] = val;
-}
-
-/**
- * @struct kp_core_ctlblk
- * @brief Per-cpu kp_core control block.
- * @var kp_core_ctlblk::kp_core_status
- * Kprobe status.
- * @var kp_core_ctlblk::prev_kp_core
- * Previous kp_core.
- */
-struct kp_core_ctlblk {
-       unsigned long kp_core_status;
-       struct prev_kp_core prev_kp_core;
-};
-
-/**
- * @struct swap_arch_specific_insn
- * @brief Architecture specific copy of original instruction.
- * @var swap_arch_specific_insn::insn
- * Copy of the original instruction.
- */
-struct swap_arch_specific_insn {
-       kprobe_opcode_t *insn;
-};
-
-typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
-                                         unsigned long, unsigned long,
-                                         unsigned long, unsigned long);
-
-struct undef_hook;
-
-void swap_register_undef_hook(struct undef_hook *hook);
-void swap_unregister_undef_hook(struct undef_hook *hook);
-
-int arch_init_module_deps(void);
-
-struct slot_manager;
-struct kretprobe;
-struct kretprobe_instance;
-struct kp_core;
-struct kprobe;
-
-int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                struct pt_regs *regs);
-
-void arch_kp_core_arm(struct kp_core *p);
-void arch_kp_core_disarm(struct kp_core *p);
-
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
-int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs);
-
-void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
-
-void __naked swap_kretprobe_trampoline(void);
-
-/**
- * @brief Gets arguments of kernel functions.
- *
- * @param regs Pointer to CPU registers data.
- * @param n Number of the argument.
- * @return Argument value.
- */
-static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
-{
-       switch (n) {
-       case 0:
-               return regs->ARM_r0;
-       case 1:
-               return regs->ARM_r1;
-       case 2:
-               return regs->ARM_r2;
-       case 3:
-               return regs->ARM_r3;
-       }
-
-       return *((unsigned long *)regs->ARM_sp + n - 4);
-}
-
-/**
- * @brief swap_get_karg wrapper.
- *
- * @param regs Pointer to CPU registers data.
- * @param n Number of the argument.
- * @return Argument value.
- */
-static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
-{
-       return swap_get_karg(regs, n);
-}
-
-/* jumper */
-typedef unsigned long (*jumper_cb_t)(void *);
-
-unsigned long get_jump_addr(void);
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
-               jumper_cb_t cb, void *data, size_t size);
-
-int swap_arch_init_kprobes(void);
-void swap_arch_exit_kprobes(void);
-
-/* void gen_insn_execbuf (void); */
-/* void pc_dep_insn_execbuf (void); */
-/* void gen_insn_execbuf_holder (void); */
-/* void pc_dep_insn_execbuf_holder (void); */
-
-#endif /* _SWAP_ASM_ARM_KPROBES_H */
diff --git a/kprobe/arch/arm/swap-asm/swap_probes.h b/kprobe/arch/arm/swap-asm/swap_probes.h
deleted file mode 100644 (file)
index 3cbd18a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_ARM_PROBES_H
-#define _SWAP_ASM_ARM_PROBES_H
-
-
-#define BREAK_ARM                      0xffffdeff
-#define BREAK_THUMB                    (BREAK_ARM & 0xffff)
-#define RET_BREAK_ARM                  BREAK_ARM
-#define RET_BREAK_THUMB                        BREAK_THUMB
-
-#define PROBES_TRAMP_LEN               (9 * 4)
-#define PROBES_TRAMP_INSN_IDX          2
-#define PROBES_TRAMP_RET_BREAK_IDX     5
-
-
-#endif /* _SWAP_ASM_ARM_PROBES_H */
diff --git a/kprobe/arch/arm64/swap-asm/condn-helpers.c b/kprobe/arch/arm64/swap-asm/condn-helpers.c
deleted file mode 100644 (file)
index 708fb7f..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/condn-helpers.c
- *
- * Copyright (C) 2013 Linaro Limited
- *
- * Copied from: arch/arm/kernel/kprobes-common.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- * Description:
- *
- *  AArch64 and AArch32 shares same conditional(CNZV) flags encoding.
- *  This file implements conditional check helpers compatible with
- *  both AArch64 and AArch32 modes. Uprobes on v8 can handle both 32-bit
- *  & 64-bit user-space instructions, so we abstract the common functions
- *  in this file. While AArch64 and AArch32 specific instruction handling
- *  are implemented in separate files, this file contains common bits.
- */
-
-
-#include <linux/module.h>
-#include "condn-helpers.h"
-
-
-static unsigned long __check_eq(unsigned long pstate)
-{
-       return pstate & PSR_Z_BIT;
-}
-
-static unsigned long __check_ne(unsigned long pstate)
-{
-       return (~pstate) & PSR_Z_BIT;
-}
-
-static unsigned long __check_cs(unsigned long pstate)
-{
-       return pstate & PSR_C_BIT;
-}
-
-static unsigned long __check_cc(unsigned long pstate)
-{
-       return (~pstate) & PSR_C_BIT;
-}
-
-static unsigned long __check_mi(unsigned long pstate)
-{
-       return pstate & PSR_N_BIT;
-}
-
-static unsigned long __check_pl(unsigned long pstate)
-{
-       return (~pstate) & PSR_N_BIT;
-}
-
-static unsigned long __check_vs(unsigned long pstate)
-{
-       return pstate & PSR_V_BIT;
-}
-
-static unsigned long __check_vc(unsigned long pstate)
-{
-       return (~pstate) & PSR_V_BIT;
-}
-
-static unsigned long __check_hi(unsigned long pstate)
-{
-       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
-       return pstate & PSR_C_BIT;
-}
-
-static unsigned long __check_ls(unsigned long pstate)
-{
-       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
-       return (~pstate) & PSR_C_BIT;
-}
-
-static unsigned long __check_ge(unsigned long pstate)
-{
-       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
-       return (~pstate) & PSR_N_BIT;
-}
-
-static unsigned long __check_lt(unsigned long pstate)
-{
-       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
-       return pstate & PSR_N_BIT;
-}
-
-static unsigned long __check_gt(unsigned long pstate)
-{
-       /*PSR_N_BIT ^= PSR_V_BIT */
-       unsigned long temp = pstate ^ (pstate << 3);
-
-       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
-       return (~temp) & PSR_N_BIT;
-}
-
-static unsigned long __check_le(unsigned long pstate)
-{
-       /*PSR_N_BIT ^= PSR_V_BIT */
-       unsigned long temp = pstate ^ (pstate << 3);
-
-       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
-       return temp & PSR_N_BIT;
-}
-
-static unsigned long __check_al(unsigned long pstate)
-{
-       return true;
-}
-
-probes_pstate_check_t * const probe_condition_checks[16] = {
-       &__check_eq, &__check_ne, &__check_cs, &__check_cc,
-       &__check_mi, &__check_pl, &__check_vs, &__check_vc,
-       &__check_hi, &__check_ls, &__check_ge, &__check_lt,
-       &__check_gt, &__check_le, &__check_al, &__check_al
-};
-EXPORT_SYMBOL_GPL(probe_condition_checks);
diff --git a/kprobe/arch/arm64/swap-asm/condn-helpers.h b/kprobe/arch/arm64/swap-asm/condn-helpers.h
deleted file mode 100644 (file)
index 088974d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _ASM_CONDN_HELPER_H
-#define _ASM_CONDN_HELPER_H
-
-/*
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-typedef unsigned long (probes_pstate_check_t)(unsigned long);
-
-
-extern probes_pstate_check_t * const probe_condition_checks[16];
-
-
-#endif /* _ASM_CONDN_HELPER_H */
diff --git a/kprobe/arch/arm64/swap-asm/dbg_interface.c b/kprobe/arch/arm64/swap-asm/dbg_interface.c
deleted file mode 100644 (file)
index 56543b7..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/kconfig.h>
-
-#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
-# error "Kernel is immutable"
-#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
-
-
-#include <linux/module.h>
-#include <linux/rwlock.h>
-#include <asm/debug-monitors.h>
-#include <ksyms/ksyms.h>
-#include "dbg_interface.h"
-
-
-
-
-/* ============================================================================
- * =                               BRK IMPLEMENT                              =
- * ============================================================================
- */
-static LIST_HEAD(brk_list);
-static DEFINE_RWLOCK(brk_list_lock);
-
-void dbg_brk_hook_reg(struct brk_hook *hook)
-{
-       write_lock(&brk_list_lock);
-       list_add(&hook->list, &brk_list);
-       write_unlock(&brk_list_lock);
-}
-EXPORT_SYMBOL_GPL(dbg_brk_hook_reg);
-
-void dbg_brk_hook_unreg(struct brk_hook *hook)
-{
-       write_lock(&brk_list_lock);
-       list_del(&hook->list);
-       write_unlock(&brk_list_lock);
-}
-EXPORT_SYMBOL_GPL(dbg_brk_hook_unreg);
-
-static enum dbg_code call_brk_hook(struct pt_regs *regs, unsigned int esr)
-{
-       struct brk_hook *hook;
-       enum dbg_code (*fn)(struct pt_regs *regs, unsigned int esr) = NULL;
-
-       read_lock(&brk_list_lock);
-       list_for_each_entry(hook, &brk_list, list)
-               if (((esr & hook->esr_mask) == hook->esr_val) &&
-                   ((regs->pstate & hook->spsr_mask) == hook->spsr_val))
-                       fn = hook->fn;
-       read_unlock(&brk_list_lock);
-
-       return fn ? fn(regs, esr) : DBG_ERROR;
-}
-
-
-typedef int (*dbg_fn_t)(unsigned long addr, unsigned int esr,
-                       struct pt_regs *regs);
-
-static dbg_fn_t *brk_handler_ptr;
-static dbg_fn_t orig_brk_handler;
-
-static int brk_handler(unsigned long addr, unsigned int esr,
-                      struct pt_regs *regs)
-{
-       /* call the registered breakpoint handler */
-       if (call_brk_hook(regs, esr) == DBG_HANDLED)
-               return 0;
-
-       return orig_brk_handler(addr, esr, regs);
-}
-
-static void init_brk(dbg_fn_t *fn)
-{
-       brk_handler_ptr = fn;
-       orig_brk_handler = *brk_handler_ptr;
-       *brk_handler_ptr = brk_handler;
-}
-
-static void uninit_brk(void)
-{
-       *brk_handler_ptr = orig_brk_handler;
-}
-
-
-
-
-
-
-/* ============================================================================
- * =                                INIT / EXIT                               =
- * ============================================================================
- */
-int dbg_iface_init(void)
-{
-       struct fault_info {
-               int (*fn)(unsigned long addr, unsigned int esr,
-                         struct pt_regs *regs);
-               int sig;
-               int code;
-               const char *name;
-       };
-
-       struct fault_info *debug_finfo;
-       struct fault_info *finfo_brk;
-
-       debug_finfo = (struct fault_info *)swap_ksyms("debug_fault_info");
-       if (debug_finfo == NULL) {
-               pr_err("cannot found 'debug_fault_info'\n");
-               return -EINVAL;
-       }
-
-       finfo_brk = &debug_finfo[DBG_ESR_EVT_BRK];
-
-       init_brk(&finfo_brk->fn);
-
-       return 0;
-}
-
-void dbg_iface_uninit(void)
-{
-       uninit_brk();
-}
diff --git a/kprobe/arch/arm64/swap-asm/dbg_interface.h b/kprobe/arch/arm64/swap-asm/dbg_interface.h
deleted file mode 100644 (file)
index 3a65f69..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef _ASM_DBG_INTERFACE_H
-#define _ASM_DBG_INTERFACE_H
-
-/*
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/list.h>
-#include <linux/types.h>
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
-# include <asm/esr.h>
-#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
-# define ESR_ELx_IL       (1 << 25)
-# define ESR_ELx_EC_MASK  0xfc000000
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
-
-#define ESR_ELx_EC_BRK   0xf0000000
-#define BRK_COMM_MASK    0x0000ffff
-
-#define DBG_BRK_ESR_MASK (ESR_ELx_EC_MASK | ESR_ELx_IL | BRK_COMM_MASK)
-#define DBG_BRK_ESR(x)   (ESR_ELx_EC_BRK | ESR_ELx_IL | (BRK_COMM_MASK & (x)))
-
-#define MAKE_BRK(v)      ((((v) & 0xffff) << 5) | 0xd4200000)
-
-
-enum dbg_code {
-       DBG_HANDLED,
-       DBG_ERROR,
-};
-
-
-struct brk_hook {
-       struct list_head list;
-       u32 spsr_mask;
-       u32 spsr_val;
-       u32 esr_mask;
-       u32 esr_val;
-       enum dbg_code (*fn)(struct pt_regs *regs, unsigned int esr);
-};
-
-
-void dbg_brk_hook_reg(struct brk_hook *hook);
-void dbg_brk_hook_unreg(struct brk_hook *hook);
-
-int dbg_iface_init(void);
-void dbg_iface_uninit(void);
-
-
-#endif /* _ASM_DBG_INTERFACE_H */
diff --git a/kprobe/arch/arm64/swap-asm/kprobes-arm64.c b/kprobe/arch/arm64/swap-asm/kprobes-arm64.c
deleted file mode 100644 (file)
index 14aff81..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/kprobes-arm64.c
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <kprobe/swap_kprobes.h>
-
-#include "probes-decode.h"
-#include "kprobes-arm64.h"
-#include "simulate-insn.h"
-#include "condn-helpers.h"
-
-
-/*
- * condition check functions for kp_cores simulation
- */
-static unsigned long __check_pstate(struct kp_core *p, struct pt_regs *regs)
-{
-       struct swap_arch_specific_insn *asi = &p->ainsn;
-       unsigned long pstate = regs->pstate & 0xffffffff;
-
-       return asi->pstate_cc(pstate);
-}
-
-static unsigned long __check_cbz(struct kp_core *p, struct pt_regs *regs)
-{
-       return check_cbz((u32)p->opcode, regs);
-}
-
-static unsigned long __check_cbnz(struct kp_core *p, struct pt_regs *regs)
-{
-       return check_cbnz((u32)p->opcode, regs);
-}
-
-static unsigned long __check_tbz(struct kp_core *p, struct pt_regs *regs)
-{
-       return check_tbz((u32)p->opcode, regs);
-}
-
-static unsigned long __check_tbnz(struct kp_core *p, struct pt_regs *regs)
-{
-       return check_tbnz((u32)p->opcode, regs);
-}
-
-/*
- * prepare functions for instruction simulation
- */
-static void prepare_none(struct kp_core *p, struct swap_arch_specific_insn *asi)
-{
-}
-
-static void prepare_bcond(struct kp_core *p,
-                         struct swap_arch_specific_insn *asi)
-{
-       kprobe_opcode_t insn = p->opcode;
-
-       asi->check_condn = __check_pstate;
-       asi->pstate_cc = probe_condition_checks[insn & 0xf];
-}
-
-static void prepare_cbz_cbnz(struct kp_core *p,
-                            struct swap_arch_specific_insn *asi)
-{
-       kprobe_opcode_t insn = p->opcode;
-
-       asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz;
-}
-
-static void prepare_tbz_tbnz(struct kp_core *p,
-                            struct swap_arch_specific_insn *asi)
-{
-       kprobe_opcode_t insn = p->opcode;
-
-       asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz;
-}
-
-
-/* Load literal (PC-relative) instructions
- * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
- *
- * opcode[26]: V=0, Load GP registers, simulate them.
- * Encoding: xx01 1000 xxxx xxxx xxxx xxxx xxxx xxxx
- *     opcode[31:30]: op = 00, 01 - LDR literal
- *     opcode[31:30]: op = 10,    - LDRSW literal
- *
- * 1.   V=1 -Load FP/AdvSIMD registers
- *     Encoding: xx01 1100 xxxx xxxx xxxx xxxx xxxx xxxx
- * 2.   V=0,opc=11 -PRFM(Prefetch literal)
- *     Encoding: 1101 1000 xxxx xxxx xxxx xxxx xxxx xxxx
- *     Reject FP/AdvSIMD literal load & PRFM literal.
- */
-static const struct aarch64_decode_item load_literal_subtable[] = {
-       DECODE_REJECT(0x1C000000, 0x3F000000),
-       DECODE_REJECT(0xD8000000, 0xFF000000),
-       DECODE_LITERAL(0x18000000, 0xBF000000, prepare_none,
-                      simulate_ldr_literal),
-       DECODE_LITERAL(0x98000000, 0xFF000000, prepare_none,
-                      simulate_ldrsw_literal),
-       DECODE_END,
-};
-
-/* AArch64 instruction decode table for kp_cores:
- * The instruction will fall into one of the 3 groups:
- *  1. Single stepped out-of-the-line slot.
- *     -Most instructions fall in this group, those does not
- *      depend on PC address.
- *
- *  2. Should be simulated because of PC-relative/literal access.
- *     -All branching and PC-relative insrtcutions are simulated
- *      in C code, making use of saved pt_regs
- *      Catch: SIMD/NEON register context are not saved while
- *      entering debug exception, so are rejected for now.
- *
- *  3. Cannot be probed(not safe) so are rejected.
- *     - Exception generation and exception return instructions
- *     - Exclusive monitor(LDREX/STREX family)
- *
- */
-static const struct aarch64_decode_item aarch64_decode_table[] = {
-       /*
-        * Data processing - PC relative(literal) addressing:
-        * Encoding: xxx1 0000 xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_LITERAL(0x10000000, 0x1F000000, prepare_none,
-                       simulate_adr_adrp),
-
-       /*
-        * Data processing - Add/Substract Immediate:
-        * Encoding: xxx1 0001 xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x11000000, 0x1F000000),
-
-       /*
-        * Data processing
-        * Encoding:
-        *      xxx1 0010 0xxx xxxx xxxx xxxx xxxx xxxx (Logical)
-        *      xxx1 0010 1xxx xxxx xxxx xxxx xxxx xxxx (Move wide)
-        *      xxx1 0011 0xxx xxxx xxxx xxxx xxxx xxxx (Bitfield)
-        *      xxx1 0011 1xxx xxxx xxxx xxxx xxxx xxxx (Extract)
-        */
-       DECODE_SINGLESTEP(0x12000000, 0x1E000000),
-
-       /*
-        * Data processing - SIMD/FP/AdvSIMD/Crypto-AES/SHA
-        * Encoding: xxx0 111x xxxx xxxx xxxx xxxx xxxx xxxx
-        * Encoding: xxx1 111x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x0E000000, 0x0E000000),
-
-       /*
-        * Data processing - Register
-        * Encoding: xxxx 101x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x0A000000, 0x0E000000),
-
-       /* Branching Instructions
-        *
-        * Encoding:
-        *  x001 01xx xxxx xxxx xxxx xxxx xxxx xxxx (uncondtional Branch)
-        *  x011 010x xxxx xxxx xxxx xxxx xxxx xxxx (compare & branch)
-        *  x011 011x xxxx xxxx xxxx xxxx xxxx xxxx (Test & Branch)
-        *  0101 010x xxxx xxxx xxxx xxxx xxxx xxxx (Conditional, immediate)
-        *  1101 011x xxxx xxxx xxxx xxxx xxxx xxxx (Unconditional,register)
-        */
-       DECODE_BRANCH(0x14000000, 0x7C000000, prepare_none,
-                       simulate_b_bl),
-       DECODE_BRANCH(0x34000000, 0x7E000000, prepare_cbz_cbnz,
-                     simulate_cbz_cbnz),
-       DECODE_BRANCH(0x36000000, 0x7E000000, prepare_tbz_tbnz,
-                     simulate_tbz_tbnz),
-       DECODE_BRANCH(0x54000000, 0xFE000000, prepare_bcond,
-                       simulate_b_cond),
-       DECODE_BRANCH(0xD6000000, 0xFE000000, prepare_none,
-                     simulate_br_blr_ret),
-
-       /* System insn:
-        * Encoding: 1101 0101 00xx xxxx xxxx xxxx xxxx xxxx
-        *
-        * Note: MSR immediate (update PSTATE daif) is not safe handling
-        * within kp_cores, rejected.
-        *
-        * Don't re-arrange these decode table entries.
-        */
-       DECODE_REJECT(0xD500401F, 0xFFF8F01F),
-       DECODE_SINGLESTEP(0xD5000000, 0xFFC00000),
-
-       /* Exception Generation:
-        * Encoding:  1101 0100 xxxx xxxx xxxx xxxx xxxx xxxx
-        * Instructions: SVC, HVC, SMC, BRK, HLT, DCPS1, DCPS2, DCPS3
-        */
-       DECODE_REJECT(0xD4000000, 0xFF000000),
-
-       /*
-        * Load/Store - Exclusive monitor
-        * Encoding: xx00 1000 xxxx xxxx xxxx xxxx xxxx xxxx
-        *
-        * Reject exlusive monitor'ed instructions
-        */
-       DECODE_REJECT(0x08000000, 0x3F000000),
-
-       /*
-        * Load/Store - PC relative(literal):
-        * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE(0x18000000, 0x3B000000, load_literal_subtable),
-
-       /*
-        * Load/Store - Register Pair
-        * Encoding:
-        *      xx10 1x00 0xxx xxxx xxxx xxxx xxxx xxxx
-        *      xx10 1x00 1xxx xxxx xxxx xxxx xxxx xxxx
-        *      xx10 1x01 0xxx xxxx xxxx xxxx xxxx xxxx
-        *      xx10 1x01 1xxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x28000000, 0x3A000000),
-
-       /*
-        * Load/Store - Register
-        * Encoding:
-        *      xx11 1x00 xx0x xxxx xxxx 00xx xxxx xxxx (unscaled imm)
-        *      xx11 1x00 xx0x xxxx xxxx 01xx xxxx xxxx (imm post-indexed)
-        *      xx11 1x00 xx0x xxxx xxxx 10xx xxxx xxxx (unpriviledged)
-        *      xx11 1x00 xx0x xxxx xxxx 11xx xxxx xxxx (imm pre-indexed)
-        *
-        *      xx11 1x00 xx10 xxxx xxxx xx10 xxxx xxxx (register offset)
-        *
-        *      xx11 1x01 xxxx xxxx xxxx xxxx xxxx xxxx (unsigned imm)
-        */
-       DECODE_SINGLESTEP(0x38000000, 0x3B200000),
-       DECODE_SINGLESTEP(0x38200200, 0x38300300),
-       DECODE_SINGLESTEP(0x39000000, 0x3B000000),
-
-       /*
-        * Load/Store - AdvSIMD
-        * Encoding:
-        *  0x00 1100 0x00 0000 xxxx xxxx xxxx xxxx (Multiple-structure)
-        *  0x00 1100 1x0x xxxx xxxx xxxx xxxx xxxx (Multi-struct post-indexed)
-        *  0x00 1101 0xx0 0000 xxxx xxxx xxxx xxxx (Single-structure))
-        *  0x00 1101 1xxx xxxx xxxx xxxx xxxx xxxx (Single-struct post-index)
-        */
-       DECODE_SINGLESTEP(0x0C000000, 0xBFBF0000),
-       DECODE_SINGLESTEP(0x0C800000, 0xBFA00000),
-       DECODE_SINGLESTEP(0x0D000000, 0xBF9F0000),
-       DECODE_SINGLESTEP(0x0D800000, 0xBF800000),
-
-       /* Unallocated:         xxx0 0xxx xxxx xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT(0x00000000, 0x18000000),
-       DECODE_END,
-};
-
-static int kp_core_decode_insn(kprobe_opcode_t insn,
-                              struct swap_arch_specific_insn *asi,
-                              const struct aarch64_decode_item *tbl)
-{
-       unsigned int entry, ret = INSN_REJECTED;
-
-       for (entry = 0; !decode_table_end(tbl[entry]); entry++) {
-               if (decode_table_hit(tbl[entry], insn))
-                       break;
-       }
-
-       switch (decode_get_type(tbl[entry])) {
-       case DECODE_TYPE_END:
-       case DECODE_TYPE_REJECT:
-       default:
-               ret = INSN_REJECTED;
-               break;
-
-       case DECODE_TYPE_SINGLESTEP:
-               ret = INSN_GOOD;
-               break;
-
-       case DECODE_TYPE_SIMULATE:
-               asi->prepare = decode_prepare_fn(tbl[entry]);
-               asi->handler = decode_handler_fn(tbl[entry]);
-               ret = INSN_GOOD_NO_SLOT;
-               break;
-
-       case DECODE_TYPE_TABLE:
-               /* recurse with next level decode table */
-               ret = kp_core_decode_insn(insn, asi,
-                                         decode_sub_table(tbl[entry]));
-       };
-
-       return ret;
-}
-
-/* Return:
- *   INSN_REJECTED     If instruction is one not allowed to kprobe,
- *   INSN_GOOD         If instruction is supported and uses instruction slot,
- *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
- */
-enum kp_core_insn arm_kp_core_decode_insn(kprobe_opcode_t insn,
-                                         struct swap_arch_specific_insn *asi)
-{
-       return kp_core_decode_insn(insn, asi, aarch64_decode_table);
-}
diff --git a/kprobe/arch/arm64/swap-asm/kprobes-arm64.h b/kprobe/arch/arm64/swap-asm/kprobes-arm64.h
deleted file mode 100644 (file)
index db7480a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/kprobes-arm64.h
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM_KERNEL_KPROBES_ARM64_H
-#define _ARM_KERNEL_KPROBES_ARM64_H
-
-enum kp_core_insn {
-       INSN_REJECTED,
-       INSN_GOOD_NO_SLOT,
-       INSN_GOOD,
-};
-
-extern kp_core_pstate_check_t * const kp_core_condition_checks[16];
-
-enum kp_core_insn arm_kp_core_decode_insn(kprobe_opcode_t insn,
-                                         struct swap_arch_specific_insn *asi);
-
-#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/kprobe/arch/arm64/swap-asm/probes-decode.h b/kprobe/arch/arm64/swap-asm/probes-decode.h
deleted file mode 100644 (file)
index 0a210ef..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/probes-decode.h
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM_KERNEL_PROBES_DECODE_H
-#define _ARM_KERNEL_PROBES_DECODE_H
-
-/*
- * The following definitions and macros are used to build instruction
- * decoding tables.
- */
-enum decode_type {
-       DECODE_TYPE_END,
-       DECODE_TYPE_SINGLESTEP,
-       DECODE_TYPE_SIMULATE,
-       DECODE_TYPE_TABLE,
-       DECODE_TYPE_REJECT,
-};
-
-struct aarch64_decode_item;
-
-struct aarch64_decode_header {
-       enum decode_type type;
-       u32 mask;
-       u32 val;
-};
-
-struct aarch64_decode_actions {
-       kp_core_prepare_t *prepare;
-       kp_core_handler_t *handler;
-};
-
-struct aarch64_decode_table {
-       const struct aarch64_decode_item *tbl;
-};
-
-union aarch64_decode_handler {
-       struct aarch64_decode_actions actions;
-       struct aarch64_decode_table table;
-};
-
-struct aarch64_decode_item {
-       struct aarch64_decode_header header;
-       union aarch64_decode_handler decode;
-};
-
-#define decode_get_type(_entry)         ((_entry).header.type)
-
-#define decode_table_end(_entry)               \
-       ((_entry).header.type == DECODE_TYPE_END)
-
-#define decode_table_hit(_entry, insn)         \
-       ((insn & (_entry).header.mask) == (_entry).header.val)
-
-#define decode_prepare_fn(_entry)      ((_entry).decode.actions.prepare)
-#define decode_handler_fn(_entry)      ((_entry).decode.actions.handler)
-#define decode_sub_table(_entry)       ((_entry).decode.table.tbl)
-
-#define DECODE_ADD_HEADER(_type, _val, _mask)  \
-       .header = {                             \
-               .type = _type,                  \
-               .mask = _mask,                  \
-               .val = _val,                    \
-       }
-
-#define DECODE_ADD_ACTION(_prepare, _handler)  \
-       .decode = {                             \
-               .actions = {                    \
-                       .prepare = _prepare,    \
-                       .handler = _handler,    \
-               }                               \
-       }
-
-#define DECODE_ADD_TABLE(_table)               \
-       .decode = {                             \
-               .table = {.tbl = _table}        \
-       }
-
-#define DECODE_REJECT(_v, _m)                                  \
-       { DECODE_ADD_HEADER(DECODE_TYPE_REJECT, _v, _m) }
-
-#define DECODE_SINGLESTEP(_v, _m)                              \
-       { DECODE_ADD_HEADER(DECODE_TYPE_SINGLESTEP, _v, _m) }
-
-#define DECODE_SIMULATE(_v, _m, _p, _h)                                \
-       { DECODE_ADD_HEADER(DECODE_TYPE_SIMULATE, _v, _m),      \
-         DECODE_ADD_ACTION(_p, _h) }
-
-#define DECODE_TABLE(_v, _m, _table)                           \
-       { DECODE_ADD_HEADER(DECODE_TYPE_TABLE, _v, _m),         \
-         DECODE_ADD_TABLE(_table) }
-
-#define DECODE_LITERAL(_v, _m, _p, _h) DECODE_SIMULATE(_v, _m, _p, _h)
-#define DECODE_BRANCH(_v, _m, _p, _h)  DECODE_SIMULATE(_v, _m, _p, _h)
-
-/* should be the last element in decode structure */
-#define DECODE_END     { .header = {.type = DECODE_TYPE_END, } }
-
-#endif /* _ARM_KERNEL_PROBES_DECODE_H */
diff --git a/kprobe/arch/arm64/swap-asm/simulate-insn.c b/kprobe/arch/arm64/swap-asm/simulate-insn.c
deleted file mode 100644 (file)
index c959a1d..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/simulate-insn.c
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/ptrace.h>
-
-#include "simulate-insn.h"
-
-#define sign_extend(x, signbit)                \
-       ((x) | (0 - ((x) & ((long)1 << (signbit)))))
-
-#define bbl_displacement(insn)         \
-       sign_extend(((insn) & 0x3ffffff) << 2, 27)
-
-#define bcond_displacement(insn)       \
-       sign_extend(((insn >> 5) & 0xfffff) << 2, 21)
-
-#define cbz_displacement(insn) \
-       sign_extend(((insn >> 5) & 0xfffff) << 2, 21)
-
-#define tbz_displacement(insn) \
-       sign_extend(((insn >> 5) & 0x3fff) << 2, 15)
-
-#define ldr_displacement(insn) \
-       sign_extend(((insn >> 5) & 0xfffff) << 2, 21)
-
-
-unsigned long check_cbz(u32 opcode, struct pt_regs *regs)
-{
-       int xn = opcode & 0x1f;
-
-       return (opcode & (1 << 31)) ?
-           !(regs->regs[xn]) : !(regs->regs[xn] & 0xffffffff);
-}
-EXPORT_SYMBOL_GPL(check_cbz);
-
-unsigned long check_cbnz(u32 opcode, struct pt_regs *regs)
-{
-       int xn = opcode & 0x1f;
-
-       return (opcode & (1 << 31)) ?
-           (regs->regs[xn]) : (regs->regs[xn] & 0xffffffff);
-}
-EXPORT_SYMBOL_GPL(check_cbnz);
-
-unsigned long check_tbz(u32 opcode, struct pt_regs *regs)
-{
-       int xn = opcode & 0x1f;
-       int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
-
-       return ~((regs->regs[xn] >> bit_pos) & 0x1);
-}
-EXPORT_SYMBOL_GPL(check_tbz);
-
-unsigned long check_tbnz(u32 opcode, struct pt_regs *regs)
-{
-       int xn = opcode & 0x1f;
-       int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
-
-       return (regs->regs[xn] >> bit_pos) & 0x1;
-}
-EXPORT_SYMBOL_GPL(check_tbnz);
-
-/*
- * instruction simulate functions
- */
-void simulate_none(u32 opcode, long addr, struct pt_regs *regs)
-{
-}
-
-void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs)
-{
-       long res, imm, xn, shift;
-
-       xn = opcode & 0x1f;
-       shift = (opcode >> 31) ? 12 : 0;        /* check insn ADRP/ADR */
-       imm = ((opcode >> 3) & 0xffffc) | ((opcode >> 29) & 0x3);
-       res = addr + 8 + (sign_extend(imm, 20) << shift);
-
-       regs->regs[xn] = opcode & 0x80000000 ? res & 0xfffffffffffff000 : res;
-       regs->pc += 4;
-}
-EXPORT_SYMBOL_GPL(simulate_adr_adrp);
-
-void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs)
-{
-       int disp = bbl_displacement(opcode);
-
-       /* Link register is x30 */
-       if (opcode & (1 << 31))
-               regs->regs[30] = addr + 4;
-
-       regs->pc = addr + disp;
-}
-EXPORT_SYMBOL_GPL(simulate_b_bl);
-
-void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
-{
-       int disp = bcond_displacement(opcode);
-
-       regs->pc = addr + disp;
-}
-EXPORT_SYMBOL_GPL(simulate_b_cond);
-
-void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs)
-{
-       int xn = (opcode >> 5) & 0x1f;
-
-       /* Link register is x30 */
-       if (((opcode >> 21) & 0x3) == 1)
-               regs->regs[30] = addr + 4;
-
-       regs->pc = regs->regs[xn];
-}
-EXPORT_SYMBOL_GPL(simulate_br_blr_ret);
-
-void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
-{
-       int disp = cbz_displacement(opcode);
-
-       regs->pc = addr + disp;
-}
-EXPORT_SYMBOL_GPL(simulate_cbz_cbnz);
-
-void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs)
-{
-       int disp = tbz_displacement(opcode);
-
-       regs->pc = addr + disp;
-}
-EXPORT_SYMBOL_GPL(simulate_tbz_tbnz);
-
-void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs)
-{
-       u64 *load_addr;
-       int xn = opcode & 0x1f;
-       int disp = ldr_displacement(opcode);
-
-       load_addr = (u64 *) (addr + disp);
-
-       if (opcode & (1 << 30)) /* x0-x31 */
-               regs->regs[xn] = *load_addr;
-       else                    /* w0-w31 */
-               *(u32 *) (&regs->regs[xn]) = (*(u32 *) (load_addr));
-}
-EXPORT_SYMBOL_GPL(simulate_ldr_literal);
-
-void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs)
-{
-       u64 *load_addr;
-       long data;
-       int xn = opcode & 0x1f;
-       int disp = ldr_displacement(opcode);
-
-       load_addr = (u64 *) (addr + disp);
-       data = *load_addr;
-
-       regs->regs[xn] = sign_extend(data, 63);
-}
-EXPORT_SYMBOL_GPL(simulate_ldrsw_literal);
diff --git a/kprobe/arch/arm64/swap-asm/simulate-insn.h b/kprobe/arch/arm64/swap-asm/simulate-insn.h
deleted file mode 100644 (file)
index 07a4939..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/simulate-insn.h
- *
- * Copyright (C) 2013 Linaro Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM_KERNEL_SIMULATE_INSN_H
-#define _ARM_KERNEL_SIMULATE_INSN_H
-
-unsigned long check_cbz(u32 opcode, struct pt_regs *regs);
-unsigned long check_cbnz(u32 opcode, struct pt_regs *regs);
-unsigned long check_tbz(u32 opcode, struct pt_regs *regs);
-unsigned long check_tbnz(u32 opcode, struct pt_regs *regs);
-void simulate_none(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs);
-
-#endif /* _ARM_KERNEL_SIMULATE_INSN_H */
diff --git a/kprobe/arch/arm64/swap-asm/swap_kprobes.c b/kprobe/arch/arm64/swap-asm/swap_kprobes.c
deleted file mode 100644 (file)
index 77970ef..0000000
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Copied from: arch/arm64/kernel/kprobes.c
- *
- * Kprobes support for ARM64
- *
- * Copyright (C) 2013 Linaro Limited.
- * Author: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
- *
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/kconfig.h>
-
-#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
-# error "Kernel is immutable"
-#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
-
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <asm/cacheflush.h>
-#include <asm/debug-monitors.h>
-#include <ksyms/ksyms.h>
-#include <kprobe/swap_ktd.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include "swap_kprobes.h"
-#include "kprobes-arm64.h"
-#include "dbg_interface.h"
-
-
-#define BRK_BP                 0x63
-#define BRK_PSEUDO_SS          0x64
-#define BRK64_OPCODE_BP                MAKE_BRK(BRK_BP)
-#define BRK64_OPCODE_PSEUDO_SS MAKE_BRK(BRK_PSEUDO_SS)
-
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
-static u32 conv_inst(u32 inst)
-{
-       return swab32(inst);
-}
-#else /* CONFIG_CPU_BIG_ENDIAN */
-static u32 conv_inst(u32 inst)
-{
-       return inst;
-}
-#endif /* CONFIG_CPU_BIG_ENDIAN */
-
-
-static void flush_icache(unsigned long addr, size_t size)
-{
-       flush_icache_range(addr, addr + size);
-}
-
-static void write_u32(u32 *addr, u32 val)
-{
-       *addr = val;
-       flush_icache((unsigned long)addr, sizeof(val));
-}
-
-void arch_kp_core_arm(struct kp_core *p)
-{
-       write_u32((u32 *)p->addr, conv_inst(BRK64_OPCODE_BP));
-}
-
-void arch_kp_core_disarm(struct kp_core *p)
-{
-       write_u32((u32 *)p->addr, p->opcode);
-}
-
-
-struct restore_data {
-       unsigned long restore_addr;
-};
-
-static void ktd_restore_init(struct task_struct *task, void *data)
-{
-       struct restore_data *rdata = (struct restore_data *)data;
-
-       rdata->restore_addr = 0;
-}
-
-static void ktd_restore_exit(struct task_struct *task, void *data)
-{
-       struct restore_data *rdata = (struct restore_data *)data;
-
-       WARN(rdata->restore_addr, "restore_addr=%lx", rdata->restore_addr);
-}
-
-struct ktask_data ktd_restore = {
-       .init = ktd_restore_init,
-       .exit = ktd_restore_exit,
-       .size = sizeof(struct restore_data),
-};
-
-static DEFINE_PER_CPU(struct restore_data, per_cpu_restore_i);
-static DEFINE_PER_CPU(struct restore_data, per_cpu_restore_st);
-
-static struct restore_data *current_restore_td(void)
-{
-       if (swap_in_interrupt())
-               return &__get_cpu_var(per_cpu_restore_i);
-       else if (switch_to_bits_get(current_kctx, SWITCH_TO_ALL))
-               return &__get_cpu_var(per_cpu_restore_st);
-
-       return (struct restore_data *)swap_ktd(&ktd_restore, current);
-}
-
-
-static void arch_prepare_ss_slot(struct kp_core *p)
-{
-       /* prepare insn slot */
-       p->ainsn.insn[0] = p->opcode;
-       p->ainsn.insn[1] = conv_inst(BRK64_OPCODE_PSEUDO_SS);
-
-       flush_icache((unsigned long)p->ainsn.insn, KPROBES_TRAMP_LEN);
-}
-
-static void arch_prepare_simulate(struct kp_core *p)
-{
-       if (p->ainsn.prepare)
-               p->ainsn.prepare(p, &p->ainsn);
-}
-
-int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
-{
-       kprobe_opcode_t insn;
-
-       /* copy instruction */
-       insn = *(kprobe_opcode_t *)p->addr;
-       p->opcode = insn;
-
-       /* decode instruction */
-       switch (arm_kp_core_decode_insn(insn, &p->ainsn)) {
-       case INSN_REJECTED:     /* insn not supported */
-               return -EINVAL;
-
-       case INSN_GOOD_NO_SLOT: /* insn need simulation */
-               p->ainsn.insn = NULL;
-               arch_prepare_simulate(p);
-               break;
-
-       case INSN_GOOD:         /* instruction uses slot */
-               p->ainsn.insn = swap_slot_alloc(sm);
-               if (!p->ainsn.insn)
-                       return -ENOMEM;
-
-               arch_prepare_ss_slot(p);
-               break;
-       };
-
-       return 0;
-}
-
-static void save_previous_kp_core(struct kp_core_ctlblk *kcb,
-                                 unsigned long restore_addr)
-{
-       kcb->prev_kp_core.p = kp_core_running();
-       kcb->prev_kp_core.status = kcb->kp_core_status;
-       kcb->prev_kp_core.restore_addr = restore_addr;
-}
-
-void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
-{
-       kp_core_running_set(kcb->prev_kp_core.p);
-       kcb->kp_core_status = kcb->prev_kp_core.status;
-       current_restore_td()->restore_addr = kcb->prev_kp_core.restore_addr;
-}
-
-static void set_ss_context(struct kp_core_ctlblk *kcb, unsigned long addr)
-{
-       kcb->ss_ctx.ss_status = KP_CORE_STEP_PENDING;
-       kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
-}
-
-static void clear_ss_context(struct kp_core_ctlblk *kcb)
-{
-       kcb->ss_ctx.ss_status = KP_CORE_STEP_NONE;
-       kcb->ss_ctx.match_addr = 0;
-}
-
-static void nop_singlestep_skip(struct pt_regs *regs)
-{
-       /* set return addr to next pc to continue */
-       regs->pc += sizeof(kprobe_opcode_t);
-}
-
-static int post_kp_core_handler(struct kp_core_ctlblk *kcb,
-                               struct pt_regs *regs);
-
-static void arch_simulate_insn(struct kp_core *p, struct pt_regs *regs)
-{
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       if (p->ainsn.handler)
-               p->ainsn.handler(p->opcode, (long)p->addr, regs);
-
-       /* single step simulated, now go for post processing */
-       post_kp_core_handler(kcb, regs);
-}
-
-static bool is_ss_setup(struct restore_data *restore)
-{
-       return !!restore->restore_addr;
-}
-
-static void setup_singlestep(struct kp_core *p, struct pt_regs *regs,
-                            struct kp_core_ctlblk *kcb, int reenter)
-{
-       struct restore_data *restore = current_restore_td();
-
-       if (reenter) {
-               save_previous_kp_core(kcb, restore->restore_addr);
-               kp_core_running_set(p);
-               kcb->kp_core_status = KPROBE_REENTER;
-       } else {
-               kcb->kp_core_status = KPROBE_HIT_SS;
-       }
-
-       if (p->ainsn.insn) {
-               unsigned long slot = (unsigned long)p->ainsn.insn;
-
-               /* prepare for single stepping */
-               restore->restore_addr = regs->pc + 4;
-               regs->pc = slot;
-
-               set_ss_context(kcb, slot);      /* mark pending ss */
-       } else  {
-               restore->restore_addr = 0;      /* reset */
-
-               /* insn simulation */
-               arch_simulate_insn(p, regs);
-       }
-}
-
-static int reenter_kp_core(struct kp_core *p, struct pt_regs *regs,
-                          struct kp_core_ctlblk *kcb)
-{
-       switch (kcb->kp_core_status) {
-       case KPROBE_HIT_SSDONE:
-       case KPROBE_HIT_ACTIVE:
-               if (!p->ainsn.check_condn || p->ainsn.check_condn(p, regs)) {
-                       setup_singlestep(p, regs, kcb, 1);
-               } else  {
-                       /* condition failed, it's NOP so skip stepping */
-                       nop_singlestep_skip(regs);
-               }
-               break;
-       case KPROBE_HIT_SS:
-               pr_warn("Unrecoverable kp_core detected at %lx\n", p->addr);
-               BUG();
-       default:
-               WARN_ON(1);
-               return 0;
-       }
-
-       return 1;
-}
-
-static int post_kp_core_handler(struct kp_core_ctlblk *kcb,
-                               struct pt_regs *regs)
-{
-       struct kp_core *cur = kp_core_running();
-       struct restore_data *restore = current_restore_td();
-
-       if (cur == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-
-       /* return addr restore if non-branching insn */
-       if (is_ss_setup(restore)) {
-               regs->pc = restore->restore_addr;
-               restore->restore_addr = 0;
-               kp_core_put(cur);
-       } else {
-               WARN_ON(1);
-       }
-
-       /* restore back original saved kp_core variables and continue */
-       if (kcb->kp_core_status == KPROBE_REENTER) {
-               restore_previous_kp_core(kcb);
-       } else  { /* call post handler */
-               kcb->kp_core_status = KPROBE_HIT_SSDONE;
-               kp_core_running_set(NULL);
-       }
-
-       return 1;
-}
-
-static enum dbg_code kprobe_handler(struct pt_regs *regs, unsigned int esr)
-{
-       struct kp_core *p, *cur;
-       struct kp_core_ctlblk *kcb;
-       unsigned long addr = regs->pc;
-       struct restore_data *restore = current_restore_td();
-
-       kcb = kp_core_ctlblk();
-       cur = kp_core_running();
-
-       rcu_read_lock();
-       p = kp_core_by_addr(addr);
-       if (p)
-               kp_core_get(p);
-       rcu_read_unlock();
-
-       if (p) {
-               if (cur && reenter_kp_core(p, regs, kcb)) {
-                       if (!is_ss_setup(restore))
-                               kp_core_put(p);
-
-                       return DBG_HANDLED;
-               } else if (!p->ainsn.check_condn ||
-                       p->ainsn.check_condn(p, regs)) {
-                       /* Probe hit and conditional execution check ok. */
-                       kp_core_running_set(p);
-                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
-
-                       if (!(regs->pstate & PSR_I_BIT))
-                               local_irq_enable();
-
-                       if (!p->handlers.pre(p, regs)) {
-                               kcb->kp_core_status = KPROBE_HIT_SS;
-                               setup_singlestep(p, regs, kcb, 0);
-                       }
-
-                       local_irq_disable();
-               } else {
-                       /*
-                        * Breakpoint hit but conditional check failed,
-                        * so just skip handling since it is NOP.
-                        */
-                       nop_singlestep_skip(regs);
-               }
-
-               if (!is_ss_setup(restore))
-                       kp_core_put(p);
-       } else if (*(kprobe_opcode_t *)addr != BRK64_OPCODE_BP) {
-               /*
-                * The breakpoint instruction was removed right
-                * after we hit it.  Another cpu has removed
-                * either a probepoint or a debugger breakpoint
-                * at this address.  In either case, no further
-                * handling of this interrupt is appropriate.
-                * Return back to original instruction, and continue.
-                */
-       } else {
-               pr_info("no_kprobe: pc=%llx\n", regs->pc);
-       }
-
-       return DBG_HANDLED;
-}
-
-static enum dbg_code kp_core_ss_hit(struct kp_core_ctlblk *kcb,
-                                   unsigned long addr)
-{
-       if ((kcb->ss_ctx.ss_status == KP_CORE_STEP_PENDING)
-           && (kcb->ss_ctx.match_addr == addr)) {
-               /* clear pending ss */
-               clear_ss_context(kcb);
-               return DBG_HANDLED;
-       }
-
-       /* not ours, kp_cores should ignore it */
-       return DBG_ERROR;
-}
-
-static enum dbg_code kprobe_ss_handler(struct pt_regs *regs, unsigned int esr)
-{
-       enum dbg_code ret;
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       /* check, and return error if this is not our step */
-       ret = kp_core_ss_hit(kcb, regs->pc);
-       if (ret == DBG_HANDLED) {
-               /* single step complete, call post handlers */
-               post_kp_core_handler(kcb, regs);
-       }
-
-       return ret;
-}
-
-static struct brk_hook dbg_bp = {
-       .spsr_mask = PSR_MODE_MASK,
-       .spsr_val = PSR_MODE_EL1h,
-       .esr_mask = DBG_BRK_ESR_MASK,
-       .esr_val = DBG_BRK_ESR(BRK_BP),
-       .fn = kprobe_handler,
-};
-
-static struct brk_hook dbg_ss = {
-       .spsr_mask = PSR_MODE_MASK,
-       .spsr_val = PSR_MODE_EL1h,
-       .esr_mask = DBG_BRK_ESR_MASK,
-       .esr_val = DBG_BRK_ESR(BRK_PSEUDO_SS),
-       .fn = kprobe_ss_handler,
-};
-
-
-
-
-
-/* ============================================================================
- * =                               KRETPROBE                                  =
- * ============================================================================
- */
-void swap_kretprobe_trampoline(void);
-__asm(
-       ".text\n"
-       ".global swap_kretprobe_trampoline\n"
-       "swap_kretprobe_trampoline:\n"
-       "stp    x6, x7, [sp,#-16]!\n"
-       "stp    x4, x5, [sp,#-16]!\n"
-       "stp    x2, x3, [sp,#-16]!\n"
-       "stp    x0, x1, [sp,#-16]!\n"
-       "mov    x0, sp\n"                       /* struct pt_regs (x0..x7) */
-       "bl     swap_trampoline_handler\n"
-       "mov    x30, x0\n"                      /* set real lr */
-       "ldp    x0, x1, [sp],#16\n"
-       "ldp    x2, x3, [sp],#16\n"
-       "ldp    x4, x5, [sp],#16\n"
-       "ldp    x6, x7, [sp],#16\n"
-       "ret\n"
-);
-
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       ri->ret_addr = (unsigned long *)regs->regs[30]; /* lr */
-       regs->regs[30] = (unsigned long)&swap_kretprobe_trampoline;
-       ri->sp = (unsigned long *)regs->sp;
-}
-
-
-
-
-
-/* ============================================================================
- * =                                 JUMPER                                   =
- * ============================================================================
- */
-struct cb_data {
-       unsigned long ret_addr;
-       unsigned long x0;
-
-       jumper_cb_t cb;
-       char data[0];
-};
-
-static unsigned long __used get_x0(struct cb_data *data)
-{
-       return data->x0;
-}
-
-static unsigned long __used jump_handler(struct cb_data *data)
-{
-       unsigned long ret_addr = data->ret_addr;
-
-       /* call callback */
-       data->cb(data->data);
-
-       /* FIXME: potential memory leak, when process kill */
-       kfree(data);
-
-       return ret_addr;
-}
-
-void jump_trampoline(void);
-__asm(
-       ".text\n"
-       "jump_trampoline:\n"
-
-       "stp    x6, x7, [sp,#-16]!\n"
-       "stp    x4, x5, [sp,#-16]!\n"
-       "stp    x2, x3, [sp,#-16]!\n"
-       "stp    x0, x1, [sp,#-16]!\n"
-       "mov    x1, x0\n"               /* data --> x1 */
-       "bl     get_x0\n"
-       "str    x0, [sp]\n"             /* restore x0 */
-       "mov    x0, x1\n"               /* data --> x0 */
-       "bl     jump_handler\n"
-       "mov    x30, x0\n"              /* set lr */
-       "ldp    x0, x1, [sp],#16\n"
-       "ldp    x2, x3, [sp],#16\n"
-       "ldp    x4, x5, [sp],#16\n"
-       "ldp    x6, x7, [sp],#16\n"
-       "ret\n"
-);
-
-unsigned long get_jump_addr(void)
-{
-       return (unsigned long)&jump_trampoline;
-}
-EXPORT_SYMBOL_GPL(get_jump_addr);
-
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
-               jumper_cb_t cb, void *data, size_t size)
-{
-       struct cb_data *cb_data;
-
-       cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
-       if (cb_data == NULL)
-               return -ENOMEM;
-
-       /* save data */
-       if (size)
-               memcpy(cb_data->data, data, size);
-
-       /* save info for restore */
-       cb_data->ret_addr = ret_addr;
-       cb_data->cb = cb;
-       cb_data->x0 = regs->regs[0];
-
-       /* save cb_data to x0 */
-       regs->regs[0] = (long)cb_data;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(set_jump_cb);
-
-
-
-
-
-/* ============================================================================
- * =                          ARCH INIT/EXIT KPROBES                          =
- * ============================================================================
- */
-int arch_init_module_deps(void)
-{
-       return 0;
-}
-
-int swap_arch_init_kprobes(void)
-{
-       int ret;
-
-       ret = swap_ktd_reg(&ktd_restore);
-       if (ret)
-               return ret;
-
-       ret = dbg_iface_init();
-       if (ret)
-               swap_ktd_unreg(&ktd_restore);
-
-       dbg_brk_hook_reg(&dbg_ss);
-       dbg_brk_hook_reg(&dbg_bp);
-
-       return 0;
-}
-
-void swap_arch_exit_kprobes(void)
-{
-       dbg_brk_hook_unreg(&dbg_ss);
-       dbg_brk_hook_unreg(&dbg_bp);
-       dbg_iface_uninit();
-       swap_ktd_unreg(&ktd_restore);
-}
diff --git a/kprobe/arch/arm64/swap-asm/swap_kprobes.h b/kprobe/arch/arm64/swap-asm/swap_kprobes.h
deleted file mode 100644 (file)
index 7975938..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef _ASM_ARM64_KPROBES_H
-#define _ASM_ARM64_KPROBES_H
-
-/*
- * Copied from: arch/arm64/kernel/kprobes.h
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/types.h>
-
-
-#define MAX_INSN_SIZE          2
-#define KPROBES_TRAMP_LEN      (MAX_INSN_SIZE * 4)  /* 4 - instruction size */
-
-
-struct kprobe;
-struct kp_core;
-struct slot_manager;
-struct swap_arch_specific_insn;
-struct kretprobe_instance;
-
-
-typedef u32 kprobe_opcode_t;
-typedef unsigned long (kp_core_pstate_check_t)(unsigned long);
-typedef unsigned long (kp_core_condition_check_t)(struct kp_core *,
-                                                 struct pt_regs *);
-typedef void (kp_core_prepare_t)(struct kp_core *,
-                                struct swap_arch_specific_insn *);
-typedef void (kp_core_handler_t)(u32 opcode, long addr, struct pt_regs *);
-
-
-/* architecture specific copy of original instruction */
-struct swap_arch_specific_insn {
-       kprobe_opcode_t *insn;
-       kp_core_pstate_check_t *pstate_cc;
-       kp_core_condition_check_t *check_condn;
-       kp_core_prepare_t *prepare;
-       kp_core_handler_t *handler;
-};
-
-struct prev_kp_core {
-       struct kp_core *p;
-       unsigned int status;
-       unsigned long restore_addr;     /* restore address after single step */
-};
-
-enum ss_status {
-       KP_CORE_STEP_NONE,
-       KP_CORE_STEP_PENDING,
-};
-
-/* Single step context for kp_core */
-struct kp_core_step_ctx {
-       enum ss_status ss_status;
-       unsigned long match_addr;
-};
-
-/* kp_core control block */
-struct kp_core_ctlblk {
-       unsigned int kp_core_status;
-       struct prev_kp_core prev_kp_core;
-       struct kp_core_step_ctx ss_ctx;
-};
-
-
-static inline unsigned long swap_get_karg(struct pt_regs *regs,
-                                         unsigned long n)
-{
-       return n < 8 ?  regs->regs[n] : *(((long *)regs->sp) + (n - 8));
-}
-
-static inline unsigned long swap_get_sarg(struct pt_regs *regs,
-                                         unsigned long n)
-{
-       return swap_get_karg(regs, n);
-}
-
-static inline unsigned long swap_get_kpc(struct pt_regs *regs)
-{
-       return regs->pc;
-}
-
-static inline void swap_set_kpc(struct pt_regs *regs, unsigned long val)
-{
-       regs->pc = val;
-}
-
-
-void arch_kp_core_arm(struct kp_core *p);
-void arch_kp_core_disarm(struct kp_core *p);
-
-int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
-void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
-
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                struct pt_regs *regs);
-void swap_kretprobe_trampoline(void);
-
-
-static inline unsigned long arch_get_task_pc(struct task_struct *p)
-{
-       WARN(1, "not implemented"); /* FIXME: to implement */
-       return 0xdeadc0de;
-}
-
-static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
-{
-       WARN(1, "not implemented"); /* FIXME: to implement */
-}
-
-static inline int swap_setjmp_pre_handler(struct kprobe *p,
-                                         struct pt_regs *regs)
-{
-       WARN(1, "not implemented"); /* FIXME: to implement */
-       return 0;
-}
-
-/* jumper */
-typedef unsigned long (*jumper_cb_t)(void *);
-
-unsigned long get_jump_addr(void);
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
-               jumper_cb_t cb, void *data, size_t size);
-
-
-int arch_init_module_deps(void);
-
-int swap_arch_init_kprobes(void);
-void swap_arch_exit_kprobes(void);
-
-
-#endif /* _ASM_ARM64_KPROBES_H */
diff --git a/kprobe/arch/arm64/swap-asm/swap_probes.h b/kprobe/arch/arm64/swap-asm/swap_probes.h
deleted file mode 100644 (file)
index 3cbd18a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_ASM_ARM_PROBES_H
-#define _SWAP_ASM_ARM_PROBES_H
-
-
-#define BREAK_ARM                      0xffffdeff
-#define BREAK_THUMB                    (BREAK_ARM & 0xffff)
-#define RET_BREAK_ARM                  BREAK_ARM
-#define RET_BREAK_THUMB                        BREAK_THUMB
-
-#define PROBES_TRAMP_LEN               (9 * 4)
-#define PROBES_TRAMP_INSN_IDX          2
-#define PROBES_TRAMP_RET_BREAK_IDX     5
-
-
-#endif /* _SWAP_ASM_ARM_PROBES_H */
diff --git a/kprobe/arch/asm-mips/dbi_kprobes.c b/kprobe/arch/asm-mips/dbi_kprobes.c
deleted file mode 100644 (file)
index bc4abb4..0000000
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/kprobe/arch/asm-mips/dbi_kprobes.c
- *
- * 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, 2006-2010
- *
- * 2006-2007    Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- *             initial implementation for ARM/MIPS
- * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
- *              Probes initial implementation; Support x86/ARM/MIPS for both
- *             user-space and kernel space.
- * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module
- *             for separating core and arch parts
- * 2012                Stanislav Andreev <s.andreev@samsung.com>: added time debug
- *              profiling support; BUG() message fix
- */
-
-#include "dbi_kprobes.h"
-#include <kprobe/dbi_kprobes.h>
-
-#include <kprobe/dbi_kdebug.h>
-#include <kprobe/dbi_insn_slots.h>
-#include <kprobe/dbi_kprobes_deps.h>
-#include <kprobe/dbi_uprobes.h>
-#include <ksyms/ksyms.h>
-
-unsigned int *arr_traps_original;
-
-
-unsigned int arr_traps_template[] = {  0x3c010000,   /* lui  a1       [0] */
-                                      0x24210000,   /* addiu a1, a1  [1] */
-                                      0x00200008,   /* jr a1         [2] */
-                                      0x00000000,   /* nop */
-                                      0xffffffff    /* end */
-};
-
-struct kprobe trampoline_p = {
-       .addr = (kprobe_opcode_t *)&kretprobe_trampoline,
-       .pre_handler = trampoline_probe_handler
-};
-
-void gen_insn_execbuf(void);
-
-void gen_insn_execbuf_holder(void)
-{
-       asm volatile(".global gen_insn_execbuf\n"
-                    "gen_insn_execbuf:\n"
-                    "nop\n"                  /* original instruction */
-                    "nop\n"                 /* ssbreak */
-                    "nop\n");               /* retbreak */
-}
-
-
-int arch_check_insn(struct arch_specific_insn *ainsn)
-{
-       int ret = 0;
-
-       switch (MIPS_INSN_OPCODE(ainsn->insn[0])) {
-       case MIPS_BEQ_OPCODE:   /* B, BEQ */
-       case MIPS_BEQL_OPCODE:  /* BEQL */
-       case MIPS_BNE_OPCODE:   /* BNE */
-       case MIPS_BNEL_OPCODE:  /* BNEL */
-       case MIPS_BGTZ_OPCODE:  /* BGTZ */
-       case MIPS_BGTZL_OPCODE: /* BGTZL */
-       case MIPS_BLEZ_OPCODE:  /* BLEZ */
-       case MIPS_BLEZL_OPCODE: /* BLEZL */
-       case MIPS_J_OPCODE:     /* J */
-       case MIPS_JAL_OPCODE:   /* JAL */
-               DBPRINTF("arch_check_insn: opcode");
-               ret = -EFAULT;
-               break;
-       case MIPS_REGIMM_OPCODE:
-               /* BAL, BGEZ, BGEZAL, BGEZALL, BGEZL,
-                * BLTZ, BLTZAL, BLTZALL, BLTZL */
-               switch (MIPS_INSN_RT(ainsn->insn[0])) {
-               case MIPS_BLTZ_RT:
-               case MIPS_BGEZ_RT:
-               case MIPS_BLTZL_RT:
-               case MIPS_BGEZL_RT:
-               case MIPS_BLTZAL_RT:
-               case MIPS_BGEZAL_RT:
-               case MIPS_BLTZALL_RT:
-               case MIPS_BGEZALL_RT:
-                       DBPRINTF("arch_check_insn: REGIMM opcode\n");
-                       ret = -EFAULT;
-                       break;
-               }
-               break;
-               /* BC1F, BC1FL, BC1T, BC1TL */
-       case MIPS_COP1_OPCODE:
-               /* BC2F, BC2FL, BC2T, BC2TL */
-       case MIPS_COP2_OPCODE:
-               if (MIPS_INSN_RS(ainsn->insn[0]) == MIPS_BC_RS) {
-                       DBPRINTF("arch_check_insn: COP1 opcode\n");
-                       ret = -EFAULT;
-               }
-               break;
-       case MIPS_SPECIAL_OPCODE:
-               /* BREAK, JALR, JALR.HB, JR, JR.HB */
-               switch (MIPS_INSN_FUNC(ainsn->insn[0])) {
-               case MIPS_JR_FUNC:
-               case MIPS_JALR_FUNC:
-               case MIPS_BREAK_FUNC:
-               case MIPS_SYSCALL_FUNC:
-                       DBPRINTF("arch_check_insn: SPECIAL opcode\n");
-                       ret = -EFAULT;
-                       break;
-               }
-               break;
-       }
-       return ret;
-}
-
-int arch_prepare_kprobe(struct kprobe *p)
-{
-       kprobe_opcode_t insns[KPROBES_TRAMP_LEN];
-
-       int ret = 0;
-       if (!ret) {
-               kprobe_opcode_t insn[MAX_INSN_SIZE];
-               struct arch_specific_insn ainsn;
-               /* insn: must be on special executable page on i386. */
-               p->ainsn.insn = get_insn_slot(NULL, 0);
-               if (!p->ainsn.insn)
-                       return -ENOMEM;
-               memcpy(insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
-               ainsn.insn = insn;
-               ret = arch_check_insn(&ainsn);
-               if (!ret) {
-                       p->opcode = *p->addr;
-                       p->ainsn.boostable = 0;
-                       memcpy(insns, gen_insn_execbuf, sizeof(insns));
-                       insns[KPROBES_TRAMP_INSN_IDX] = insn[0];
-                       insns[KPROBES_TRAMP_SS_BREAK_IDX] =
-                               BREAKPOINT_INSTRUCTION;
-                       insns[KPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION;
-                       DBPRINTF("arch_prepare_kprobe: insn %lx", insn[0]);
-                       DBPRINTF("arch_prepare_kprobe: to %p - %lx %lx %lx",
-                                       p->ainsn.insn, insns[0],
-                                insns[1], insns[2]);
-                       memcpy(p->ainsn.insn, insns, sizeof(insns));
-               } else {
-                       free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
-               }
-       }
-
-       return ret;
-}
-
-int arch_prepare_uprobe(struct kprobe *p, struct task_struct *task, int atomic)
-{
-       int ret = 0;
-       kprobe_opcode_t insns[UPROBES_TRAMP_LEN];
-
-       if ((unsigned long) p->addr & 0x01) {
-               DBPRINTF("Attempt to register kprobe at an unaligned address");
-               ret = -EINVAL;
-       }
-
-       if (!ret) {
-               kprobe_opcode_t insn[MAX_INSN_SIZE];
-               struct arch_specific_insn ainsn;
-
-               if (!read_proc_vm_atomic(task, (unsigned long) p->addr,
-                                        &insn,
-                                        MAX_INSN_SIZE *
-                                        sizeof(kprobe_opcode_t)))
-                       panic("failed to read memory %p!\n", p->addr);
-               ainsn.insn = insn;
-               ret = arch_check_insn(&ainsn);
-               if (!ret) {
-                       p->opcode = insn[0];
-                       p->ainsn.insn = get_insn_slot(task, atomic);
-                       if (!p->ainsn.insn)
-                               return -ENOMEM;
-                       p->ainsn.boostable = 0;
-                       memcpy(insns, gen_insn_execbuf, sizeof(insns));
-                       insns[UPROBES_TRAMP_INSN_IDX] = insn[0];
-                       insns[UPROBES_TRAMP_SS_BREAK_IDX] =
-                               BREAKPOINT_INSTRUCTION;
-                       insns[UPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION;
-                       DBPRINTF("arch_prepare_uprobe: insn %lx", insn[0]);
-                       DBPRINTF("arch_prepare_uprobe: to %p - %lx %lx %lx",
-                                p->ainsn.insn, insns[0], insns[1], insns[2]);
-
-                       if (!write_proc_vm_atomic(task,
-                                                 (unsigned long) p->ainsn.insn,
-                                                 insns, sizeof(insns))) {
-                               panic("failed to write memory %p!\n",
-                                     p->ainsn.insn);
-                               DBPRINTF("failed to write insn slot to "
-                                        "process memory: insn %p, addr %p, "
-                                        "probe %p!",
-                                        insn, p->ainsn.insn, p->addr);
-                               /* printk("failed to write insn slot to process
-                                * memory: %p/%d insn %lx, addr %p,
-                                * probe %p!\n",task, task->pid, insn,
-                                * p->ainsn.insn, p->addr);*/
-                               free_insn_slot(&uprobe_insn_pages, task,
-                                              p->ainsn.insn);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       return ret;
-}
-
-void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
-{
-       if (p->ss_addr) {
-               regs->cp0_epc = (unsigned long)p->ss_addr;
-               p->ss_addr = NULL;
-       } else
-               regs->cp0_epc = (unsigned long)p->ainsn.insn;
-}
-
-
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *cur_p)
-{
-       if (kcb->prev_kprobe.kp != NULL) {
-               panic("no space to save new probe[]: task = %d/%s, prev %d/%p,"
-                     " current %d/%p, new %d/%p,",
-                     current->pid, current->comm, kcb->prev_kprobe.kp->tgid,
-                     kcb->prev_kprobe.kp->addr, kprobe_running()->tgid,
-                     kprobe_running()->addr, cur_p->tgid, cur_p->addr);
-       }
-
-       kcb->prev_kprobe.kp = kprobe_running();
-       kcb->prev_kprobe.status = kcb->kprobe_status;
-}
-
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
-{
-       __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
-       kcb->kprobe_status = kcb->prev_kprobe.status;
-       kcb->prev_kprobe.kp = NULL;
-       kcb->prev_kprobe.status = 0;
-}
-
-void set_current_kprobe(struct kprobe *p,
-                       struct pt_regs *regs,
-                       struct kprobe_ctlblk *kcb)
-{
-       __get_cpu_var(current_kprobe) = p;
-       DBPRINTF("set_current_kprobe[]: p=%p addr=%p\n", p, p->addr);
-}
-
-int kprobe_handler(struct pt_regs *regs)
-{
-       struct kprobe *p = 0;
-       int ret = 0, pid = 0, retprobe = 0, reenter = 0;
-       kprobe_opcode_t *addr = NULL, *ssaddr = 0;
-       struct kprobe_ctlblk *kcb;
-
-       /* We're in an interrupt, but this is clear and BUG()-safe. */
-
-       addr = (kprobe_opcode_t *) regs->cp0_epc;
-       DBPRINTF("regs->regs[ 31 ] = 0x%lx\n", regs->regs[31]);
-
-       preempt_disable();
-
-       kcb = get_kprobe_ctlblk();
-
-       if (user_mode(regs)) {
-               /* DBPRINTF("exception[%lu] from user mode %s/%u addr %p(%lx).",
-                * nCount, current->comm,
-                * current->pid, addr, regs->uregs[14]); */
-               pid = current->tgid;
-       }
-
-       /* Check we're not actually recursing */
-       if (kprobe_running()) {
-               DBPRINTF("lock???");
-               p = get_kprobe(addr, pid);
-               if (p) {
-                       if (!pid && (addr ==
-                                    (kprobe_opcode_t *)kretprobe_trampoline)) {
-                               save_previous_kprobe(kcb, p);
-                               kcb->kprobe_status = KPROBE_REENTER;
-                               reenter = 1;
-                       } else {
-                               /* We have reentered the kprobe_handler(), since
-                                * another probe was hit while within the
-                                * handler. We here save the original kprobes
-                                * variables and just single step on the
-                                * instruction of the new probe without calling
-                                * any user handlers.
-                                */
-                               if (!p->ainsn.boostable) {
-                                       save_previous_kprobe(kcb, p);
-                                       set_current_kprobe(p, regs, kcb);
-                               }
-                               kprobes_inc_nmissed_count(p);
-                               prepare_singlestep(p, regs);
-                               if (!p->ainsn.boostable)
-                                       kcb->kprobe_status = KPROBE_REENTER;
-                               preempt_enable_no_resched();
-                               return 1;
-                       }
-               } else {
-                       if (pid) {
-                               /* we can reenter probe upon
-                                * uretprobe exception */
-                               DBPRINTF("check for UNDEF_INSTRUCTION %p\n",
-                                        addr);
-                               /* UNDEF_INSTRUCTION from user space */
-                               p = get_kprobe_by_insn_slot(
-                                       addr-UPROBES_TRAMP_RET_BREAK_IDX,
-                                       pid, current);
-                               if (p) {
-                                       save_previous_kprobe(kcb, p);
-                                       kcb->kprobe_status = KPROBE_REENTER;
-                                       reenter = 1;
-                                       retprobe = 1;
-                                       DBPRINTF("uretprobe %p\n", addr);
-                               }
-                       }
-                       if (!p) {
-                               p = __get_cpu_var(current_kprobe);
-                               DBPRINTF("kprobe_running !!! p = 0x%p "
-                                        "p->break_handler = 0x%p", p,
-                                        p->break_handler);
-                               /* if (p->break_handler &&
-                                * p->break_handler(p, regs)) {
-                                * DBPRINTF("kprobe_running !!! goto ss");
-                                * goto ss_probe;
-                                * } */
-                               DBPRINTF("unknown uprobe at %p cur at %p/%p\n",
-                                        addr, p->addr, p->ainsn.insn);
-                               if (pid)
-                                       ssaddr = p->ainsn.insn +
-                                               UPROBES_TRAMP_SS_BREAK_IDX;
-                               else
-                                       ssaddr = p->ainsn.insn +
-                                               KPROBES_TRAMP_SS_BREAK_IDX;
-                               if (addr == ssaddr) {
-                                       regs->cp0_epc =
-                                               (unsigned long)(p->addr + 1);
-                                       DBPRINTF("finish step at %p cur at "
-                                                "%p/%p, redirect to %lx\n",
-                                                addr, p->addr,
-                                                p->ainsn.insn, regs->cp0_epc);
-
-                                       if (kcb->kprobe_status ==
-                                           KPROBE_REENTER) {
-                                               restore_previous_kprobe(kcb);
-                                       } else {
-                                               reset_current_kprobe();
-                                       }
-                               }
-                               DBPRINTF("kprobe_running !!! goto no");
-                               ret = 1;
-                               /* If it's not ours, can't be delete race,
-                                * (we hold lock). */
-                               DBPRINTF("no_kprobe");
-                               goto no_kprobe;
-                       }
-               }
-       }
-
-       /* if(einsn != UNDEF_INSTRUCTION) { */
-       DBPRINTF("get_kprobe %p-%d", addr, pid);
-       if (!p)
-               p = get_kprobe(addr, pid);
-       if (!p) {
-               if (pid) {
-                       DBPRINTF("search UNDEF_INSTRUCTION %p\n", addr);
-                       /*  UNDEF_INSTRUCTION from user space */
-                       p = get_kprobe_by_insn_slot(
-                               addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
-                       if (!p) {
-                               /* Not one of ours: let kernel handle it */
-                               DBPRINTF("no_kprobe");
-                               /* printk("no_kprobe2 ret = %d\n", ret); */
-                               goto no_kprobe;
-                       }
-                       retprobe = 1;
-                       DBPRINTF("uretprobe %p\n", addr);
-               } else {
-                       /* Not one of ours: let kernel handle it */
-                       DBPRINTF("no_kprobe");
-                       /* printk(KERN_INFO "no_kprobe2 ret = %d\n", ret); */
-                       goto no_kprobe;
-               }
-       }
-
-       set_current_kprobe(p, regs, kcb);
-       if (!reenter)
-               kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-
-       if (retprobe)           /* (einsn == UNDEF_INSTRUCTION) */
-               ret = trampoline_probe_handler(p, regs);
-       else if (p->pre_handler) {
-               ret = p->pre_handler(p, regs);
-               if (!p->ainsn.boostable)
-                       kcb->kprobe_status = KPROBE_HIT_SS;
-               else if (p->pre_handler != trampoline_probe_handler) {
-                       reset_current_kprobe();
-               }
-       }
-
-       if (ret) {
-               DBPRINTF("p->pre_handler[] 1");
-               /* handler has already set things up, so skip ss setup */
-               return 1;
-       }
-       DBPRINTF("p->pre_handler 0");
-
-no_kprobe:
-       preempt_enable_no_resched();
-       return ret;
-}
-
-void patch_suspended_task_ret_addr(struct task_struct *p, struct kretprobe *rp)
-{
-       DBPRINTF("patch_suspended_task_ret_addr is not implemented");
-}
-
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct jprobe *jp = container_of(p, struct jprobe, kp);
-       kprobe_pre_entry_handler_t pre_entry;
-       entry_point_t entry;
-
-       DBPRINTF("pjp = 0x%p jp->entry = 0x%p", jp, jp->entry);
-       entry = (entry_point_t) jp->entry;
-       pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
-       /* if(!entry) */
-       /*       DIE("entry NULL", regs) */
-       DBPRINTF("entry = 0x%p jp->entry = 0x%p", entry, jp->entry);
-
-       /* call handler for all kernel probes and user space
-        * ones which belong to current tgid */
-       if (!p->tgid || (p->tgid == current->tgid)) {
-               if (!p->tgid && (p->addr == sched_addr) && sched_rp) {
-                       struct task_struct *p, *g;
-                       rcu_read_lock();
-                       /* swapper task */
-                       if (current != &init_task)
-                               patch_suspended_task_ret_addr(&init_task,
-                                                             sched_rp);
-                       /*  other tasks */
-                       do_each_thread(g, p) {
-                               if (p == current)
-                                       continue;
-                               patch_suspended_task_ret_addr(p, sched_rp);
-                       } while_each_thread(g, p);
-                       rcu_read_unlock();
-               }
-               if (pre_entry)
-                       p->ss_addr = (void *)pre_entry(jp->priv_arg, regs);
-               if (entry) {
-                       entry(regs->regs[4], regs->regs[5], regs->regs[6],
-                             regs->regs[7], regs->regs[8], regs->regs[9]);
-               } else {
-                       if (p->tgid)
-                               arch_ujprobe_return();
-                       else
-                               dbi_jprobe_return();
-               }
-       } else if (p->tgid)
-               arch_ujprobe_return();
-
-       prepare_singlestep(p, regs);
-
-       return 1;
-}
-
-
-void dbi_jprobe_return(void)
-{
-       preempt_enable_no_resched();
-}
-
-void arch_ujprobe_return(void)
-{
-       preempt_enable_no_resched();
-}
-
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       return 0;
-}
-
-void arch_arm_kprobe(struct kprobe *p)
-{
-       *p->addr = BREAKPOINT_INSTRUCTION;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
-}
-
-void arch_disarm_kprobe(struct kprobe *p)
-{
-       *p->addr = p->opcode;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
-}
-
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *node, *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address =
-               (unsigned long) &kretprobe_trampoline;
-       struct kretprobe *crp = NULL;
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-
-       DBPRINTF("start");
-
-       if (p && p->tgid) {
-               /*  in case of user space retprobe trampoline
-                * is at the Nth instruction of US tramp */
-               trampoline_address =
-                       (unsigned long)(p->ainsn.insn +
-                                       UPROBES_TRAMP_RET_BREAK_IDX);
-       }
-
-       INIT_HLIST_HEAD(&empty_rp);
-       spin_lock_irqsave(&kretprobe_lock, flags);
-       head = kretprobe_inst_table_head(current);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more then one
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, node, tmp, head, hlist)
-       {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs, ri->rp->priv_arg);
-
-               orig_ret_address = (unsigned long) ri->ret_addr;
-               recycle_rp_inst(ri);
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-       /* BUG_ON(!orig_ret_address ||
-        * (orig_ret_address == trampoline_address)); */
-       if (trampoline_address != (unsigned long) &kretprobe_trampoline)
-               if (ri->rp)
-                       BUG_ON(ri->rp->kp.tgid == 0);
-
-       if (ri->rp && ri->rp->kp.tgid)
-               BUG_ON(trampoline_address ==
-                      (unsigned long) &kretprobe_trampoline);
-
-       regs->regs[31] = orig_ret_address;
-       DBPRINTF("regs->cp0_epc = 0x%lx", regs->cp0_epc);
-       if (trampoline_address != (unsigned long) &kretprobe_trampoline)
-               regs->cp0_epc = orig_ret_address;
-       else
-               regs->cp0_epc = regs->cp0_epc + 4;
-       DBPRINTF("regs->cp0_epc = 0x%lx", regs->cp0_epc);
-       DBPRINTF("regs->cp0_status = 0x%lx", regs->cp0_status);
-
-       if (p) { /*  ARM, MIPS, X86 user space */
-               if (kcb->kprobe_status == KPROBE_REENTER)
-                       restore_previous_kprobe(kcb);
-               else
-                       reset_current_kprobe();
-       }
-
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-       hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist)
-       {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-       preempt_enable_no_resched();
-       /*
-        * By returning a non-zero value, we are telling
-        * kprobe_handler() that we don't want the post_handler
-        * to run (and have re-enabled preemption)
-        */
-       return 1;
-}
-
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
-{
-
-       struct kretprobe_instance *ri;
-
-       DBPRINTF("start\n");
-       /* TODO: test - remove retprobe after func entry but before its exit */
-       ri = get_free_rp_inst(rp);
-       if (ri != NULL) {
-               ri->rp = rp;
-               ri->task = current;
-               ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
-               if (rp->kp.tgid)
-                       regs->regs[31] =
-                               (unsigned long)(rp->kp.ainsn.insn +
-                                               UPROBES_TRAMP_RET_BREAK_IDX);
-               else    /* Replace the return addr with trampoline addr */
-                       regs->regs[31] = (unsigned long) &kretprobe_trampoline;
-               add_rp_inst(ri);
-       } else {
-               DBPRINTF("WARNING: missed retprobe %p\n", rp->kp.addr);
-               rp->nmissed++;
-       }
-}
-
-DECLARE_MOD_CB_DEP(flush_icache_range, \
-               void, unsigned long __user start, unsigned long __user end);
-DECLARE_MOD_CB_DEP(flush_icache_page, \
-               void, struct vm_area_struct *vma, struct page *page);
-DECLARE_MOD_CB_DEP(flush_cache_page, \
-               void, struct vm_area_struct *vma, unsigned long page);
-
-int arch_init_module_deps()
-{
-       INIT_MOD_DEP_CB(flush_icache_range, r4k_flush_icache_range);
-       INIT_MOD_DEP_CB(flush_icache_page, r4k_flush_icache_page);
-       INIT_MOD_DEP_CB(flush_cache_page, r4k_flush_cache_page);
-
-       return 0;
-}
-
-
-int __init arch_init_kprobes(void)
-{
-       unsigned int do_bp_handler;
-       unsigned int kprobe_handler_addr;
-
-       unsigned int insns_num = 0;
-       unsigned int code_size = 0;
-
-       unsigned int reg_hi;
-       unsigned int reg_lo;
-
-       int ret;
-
-       if (arch_init_module_dependencies()) {
-               DBPRINTF("Unable to init module dependencies\n");
-               return -1;
-       }
-
-       do_bp_handler = (unsigned int)swap_ksyms("do_bp");
-
-       kprobe_handler_addr = (unsigned int) &kprobe_handler;
-       insns_num = sizeof(arr_traps_template) / sizeof(arr_traps_template[0]);
-       code_size = insns_num * sizeof(unsigned int);
-       DBPRINTF("insns_num = %d\n", insns_num);
-       /*  Save original code */
-       arr_traps_original = kmalloc(code_size, GFP_KERNEL);
-       if (!arr_traps_original) {
-               DBPRINTF("Unable to allocate space for "
-                        "original code of <do_bp>!\n");
-               return -1;
-       }
-       memcpy(arr_traps_original, (void *) do_bp_handler, code_size);
-
-       reg_hi = HIWORD(kprobe_handler_addr);
-       reg_lo = LOWORD(kprobe_handler_addr);
-       if (reg_lo >= 0x8000)
-               reg_hi += 0x0001;
-       arr_traps_template[REG_HI_INDEX] |= reg_hi;
-       arr_traps_template[REG_LO_INDEX] |= reg_lo;
-
-       /*  Insert new code */
-       memcpy((void *) do_bp_handler, arr_traps_template, code_size);
-       flush_icache_range(do_bp_handler, do_bp_handler + code_size);
-       ret = dbi_register_kprobe(&trampoline_p);
-       if (ret != 0) {
-               /* dbi_unregister_jprobe(&do_exit_p, 0); */
-               return ret;
-       }
-}
-
-void __exit dbi_arch_exit_kprobes(void)
-{
-       unsigned int do_bp_handler;
-
-       unsigned int insns_num = 0;
-       unsigned int code_size = 0;
-
-       /*  Get instruction address */
-       do_bp_handler = (unsigned int)swap_ksyms("do_undefinstr");
-
-       /* dbi_unregister_jprobe(&do_exit_p, 0); */
-
-       /*  Replace back the original code */
-
-       insns_num = sizeof(arr_traps_template) / sizeof(arr_traps_template[0]);
-       code_size = insns_num * sizeof(unsigned int);
-       memcpy((void *) do_bp_handler, arr_traps_original, code_size);
-       flush_icache_range(do_bp_handler, do_bp_handler + code_size);
-       kfree(arr_traps_original);
-       arr_traps_original = NULL;
-}
-
-
diff --git a/kprobe/arch/asm-mips/dbi_kprobes.h b/kprobe/arch/asm-mips/dbi_kprobes.h
deleted file mode 100644 (file)
index 23b36f5..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _SRC_ASM_MIPS_KPROBES_H
-#define _SRC_ASM_MIPS_KPROBES_H
-
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/kprobe/arch/asm-mips/dbi_kprobes.h
- *
- * 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, 2006-2010
- *
- * 2006-2007    Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- *             initial implementation for ARM/MIPS
- * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
- *              Probes initial implementation; Support x86/ARM/MIPS for both
- *             user-space and kernel space.
- * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- *             redesign module for separating core and arch parts
- *
- */
-
-#include <kprobe/dbi_kprobes_deps.h>
-#include <kprobe/dbi_kprobes.h>
-
-typedef unsigned long kprobe_opcode_t;
-
-#define BREAKPOINT_INSTRUCTION         0x0000000d
-
-#ifndef KPROBES_RET_PROBE_TRAMP
-#define UNDEF_INSTRUCTION              0x0000004d
-#endif
-
-#define MAX_INSN_SIZE                  1
-
-# define UPROBES_TRAMP_LEN             3
-# define UPROBES_TRAMP_INSN_IDX        0
-# define UPROBES_TRAMP_SS_BREAK_IDX    1
-# define UPROBES_TRAMP_RET_BREAK_IDX   2
-# define KPROBES_TRAMP_LEN             UPROBES_TRAMP_LEN
-# define KPROBES_TRAMP_INSN_IDX        UPROBES_TRAMP_INSN_IDX
-# define KPROBES_TRAMP_SS_BREAK_IDX    UPROBES_TRAMP_SS_BREAK_IDX
-# define KPROBES_TRAMP_RET_BREAK_IDX   UPROBES_TRAMP_RET_BREAK_IDX
-
-#define REG_HI_INDEX                   0
-#define REG_LO_INDEX                   1
-#define NOTIFIER_CALL_CHAIN_INDEX      0
-
-
-#define MIPS_INSN_OPCODE_MASK  0xFC000000
-#define MIPS_INSN_RS_MASK      0x03E00000
-#define MIPS_INSN_RT_MASK      0x001F0000
-/* #define MIPS_INSN_UN_MASK     0x0000FFC0 */
-#define MIPS_INSN_FUNC_MASK     0x0000003F
-#define MIPS_INSN_OPCODE(insn) (insn & MIPS_INSN_OPCODE_MASK)
-#define MIPS_INSN_RS(insn)      (insn & MIPS_INSN_RS_MASK)
-#define MIPS_INSN_RT(insn)      (insn & MIPS_INSN_RT_MASK)
-#define MIPS_INSN_FUNC(insn)   (insn & MIPS_INSN_FUNC_MASK)
-/* opcodes 31..26 */
-#define MIPS_BEQ_OPCODE                0x10000000
-#define MIPS_BNE_OPCODE                0x14000000
-#define MIPS_BLEZ_OPCODE       0x18000000
-#define MIPS_BGTZ_OPCODE       0x1C000000
-#define MIPS_BEQL_OPCODE       0x50000000
-#define MIPS_BNEL_OPCODE       0x54000000
-#define MIPS_BLEZL_OPCODE      0x58000000
-#define MIPS_BGTZL_OPCODE      0x5C000000
-#define MIPS_REGIMM_OPCODE     0x04000000
-#define MIPS_SPECIAL_OPCODE    0x00000000
-#define MIPS_COP1_OPCODE       0x44000000
-#define MIPS_COP2_OPCODE       0x48000000
-#define MIPS_J_OPCODE          0x08000000
-#define MIPS_JAL_OPCODE                0x0C000000
-#define MIPS_JALX_OPCODE       0x74000000
-/*  rs 25..21 */
-#define MIPS_BC_RS             0x01000000
-/*  rt 20..16 */
-#define MIPS_BLTZ_RT           0x00000000
-#define MIPS_BGEZ_RT           0x00010000
-#define MIPS_BLTZL_RT          0x00020000
-#define MIPS_BGEZL_RT          0x00030000
-#define MIPS_BLTZAL_RT         0x00100000
-#define MIPS_BGEZAL_RT         0x00110000
-#define MIPS_BLTZALL_RT                0x00120000
-#define MIPS_BGEZALL_RT                0x00130000
-/*  unnamed 15..6 */
-/*  function 5..0 */
-#define MIPS_JR_FUNC           0x00000008
-#define MIPS_JALR_FUNC         0x00000009
-#define MIPS_BREAK_FUNC                0x0000000D
-#define MIPS_SYSCALL_FUNC      0x0000000C
-
-
-/* per-cpu kprobe control block */
-struct kprobe_ctlblk {
-       unsigned long kprobe_status;
-       struct prev_kprobe prev_kprobe;
-};
-
-/* Architecture specific copy of original instruction */
-struct arch_specific_insn {
-       /* copy of the original instruction */
-       kprobe_opcode_t *insn;
-       /*
-        * If this flag is not 0, this kprobe can be boost when its
-        * post_handler and break_handler is not set.
-        */
-       int boostable;
-};
-
-typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
-                                         unsigned long, unsigned long,
-                                         unsigned long, unsigned long);
-
-
-void gen_insn_execbuf_holder(void);
-
-void patch_suspended_task_ret_addr(struct task_struct *p, struct kretprobe *rp);
-int arch_init_module_deps(void);
-
-#endif /*  _SRC_ASM_MIPS_KPROBES_H */
diff --git a/kprobe/arch/x86/swap-asm/swap_kprobes.c b/kprobe/arch/x86/swap-asm/swap_kprobes.c
deleted file mode 100644 (file)
index 72b47e1..0000000
+++ /dev/null
@@ -1,1059 +0,0 @@
-/**
- * arch/asm-x86/swap_kprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
- *
- * @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) IBM Corporation, 2002, 2004
- *
- * @section DESCRIPTION
- *
- * SWAP krpobes arch-dependend part for x86.
- */
-
-
-#include <linux/kconfig.h>
-
-#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
-# error "Kernel is immutable"
-#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
-
-
-#include<linux/module.h>
-#include <linux/kdebug.h>
-
-#include "swap_kprobes.h"
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_td_raw.h>
-#include <kprobe/swap_kdebug.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kprobes_deps.h>
-
-
-static int (*swap_fixup_exception)(struct pt_regs *regs);
-static void *(*swap_text_poke)(void *addr, const void *opcode, size_t len);
-static void (*swap_show_registers)(struct pt_regs *regs);
-
-
-#define SWAP_SAVE_REGS_STRING                  \
-       /* Skip cs, ip, orig_ax and gs. */      \
-       "subl $16, %esp\n"                      \
-       "pushl %fs\n"                           \
-       "pushl %es\n"                           \
-       "pushl %ds\n"                           \
-       "pushl %eax\n"                          \
-       "pushl %ebp\n"                          \
-       "pushl %edi\n"                          \
-       "pushl %esi\n"                          \
-       "pushl %edx\n"                          \
-       "pushl %ecx\n"                          \
-       "pushl %ebx\n"
-#define SWAP_RESTORE_REGS_STRING               \
-       "popl %ebx\n"                           \
-       "popl %ecx\n"                           \
-       "popl %edx\n"                           \
-       "popl %esi\n"                           \
-       "popl %edi\n"                           \
-       "popl %ebp\n"                           \
-       "popl %eax\n"                           \
-       /* Skip ds, es, fs, gs, orig_ax, and ip. Note: don't pop cs here*/\
-       "addl $24, %esp\n"
-
-
-/*
- * Function return probe trampoline:
- *      - init_kprobes() establishes a probepoint here
- *      - When the probed function returns, this probe
- *        causes the handlers to fire
- */
-__asm(
-       ".global swap_kretprobe_trampoline\n"
-       "swap_kretprobe_trampoline:\n"
-       "pushf\n"
-       SWAP_SAVE_REGS_STRING
-       "movl %esp, %eax\n"
-       "call swap_trampoline_handler\n"
-       /* move eflags to cs */
-       "movl 56(%esp), %edx\n"
-       "movl %edx, 52(%esp)\n"
-       /* replace saved flags with true return address. */
-       "movl %eax, 56(%esp)\n"
-       SWAP_RESTORE_REGS_STRING
-       "popf\n"
-       "ret\n"
-);
-
-/* insert a jmp code */
-static __always_inline void set_jmp_op(void *from, void *to)
-{
-       struct __arch_jmp_op {
-               char op;
-               long raddr;
-       } __packed * jop;
-       jop = (struct __arch_jmp_op *) from;
-       jop->raddr = (long) (to) - ((long) (from) + 5);
-       jop->op = RELATIVEJUMP_INSTRUCTION;
-}
-
-/**
- * @brief Check if opcode can be boosted.
- *
- * @param opcodes Opcode to check.
- * @return Non-zero if opcode can be boosted.
- */
-int swap_can_boost(kprobe_opcode_t *opcodes)
-{
-#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf) \
-       (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) |   \
-         (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) |   \
-         (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) |   \
-         (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf))    \
-        << (row % 32))
-       /*
-        * Undefined/reserved opcodes, conditional jump, Opcode Extension
-        * Groups, and some special opcodes can not be boost.
-        */
-       static const unsigned long twobyte_is_boostable[256 / 32] = {
-               /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
-               W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) |
-               W(0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
-               W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
-               W(0x30, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
-               W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
-               W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
-               W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1) |
-               W(0x70, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1),
-               W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
-               W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
-               W(0xa0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1) |
-               W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1),
-               W(0xc0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) |
-               W(0xd0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1),
-               W(0xe0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1) |
-               W(0xf0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0)
-               /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
-
-       };
-#undef W
-       kprobe_opcode_t opcode;
-       kprobe_opcode_t *orig_opcodes = opcodes;
-retry:
-       if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
-               return 0;
-       opcode = *(opcodes++);
-
-       /* 2nd-byte opcode */
-       if (opcode == 0x0f) {
-               if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
-                       return 0;
-               return test_bit(*opcodes, twobyte_is_boostable);
-       }
-
-       switch (opcode & 0xf0) {
-       case 0x60:
-               if (0x63 < opcode && opcode < 0x67)
-                       goto retry;     /* prefixes */
-               /* can't boost Address-size override and bound */
-               return (opcode != 0x62 && opcode != 0x67);
-       case 0x70:
-               return 0;       /* can't boost conditional jump */
-       case 0xc0:
-               /* can't boost software-interruptions */
-               return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf;
-       case 0xd0:
-               /* can boost AA* and XLAT */
-               return (opcode == 0xd4 || opcode == 0xd5 || opcode == 0xd7);
-       case 0xe0:
-               /* can boost in/out and absolute jmps */
-               return ((opcode & 0x04) || opcode == 0xea);
-       case 0xf0:
-               if ((opcode & 0x0c) == 0 && opcode != 0xf1)
-                       goto retry;     /* lock/rep(ne) prefix */
-               /* clear and set flags can be boost */
-               return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe));
-       default:
-               if (opcode == 0x26 || opcode == 0x36 || opcode == 0x3e)
-                       goto retry;     /* prefixes */
-               /* can't boost CS override and call */
-               return (opcode != 0x2e && opcode != 0x9a);
-       }
-}
-EXPORT_SYMBOL_GPL(swap_can_boost);
-
-/*
- * returns non-zero if opcode modifies the interrupt flag.
- */
-static int is_IF_modifier(kprobe_opcode_t opcode)
-{
-       switch (opcode) {
-       case 0xfa:              /* cli */
-       case 0xfb:              /* sti */
-       case 0xcf:              /* iret/iretd */
-       case 0x9d:              /* popf/popfd */
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * @brief Creates trampoline for kprobe.
- *
- * @param p Pointer to kprobe.
- * @param sm Pointer to slot manager
- * @return 0 on success, error code on error.
- */
-int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
-{
-       /* insn: must be on special executable page on i386. */
-       p->ainsn.insn = swap_slot_alloc(sm);
-       if (p->ainsn.insn == NULL)
-               return -ENOMEM;
-
-       memcpy(p->ainsn.insn, (void *)p->addr, MAX_INSN_SIZE);
-
-       p->opcode = *(char *)p->addr;
-       p->ainsn.boostable = swap_can_boost((void *)p->addr) ? 0 : -1;
-
-       return 0;
-}
-
-/**
- * @brief Prepares singlestep for current CPU.
- *
- * @param p Pointer to kprobe.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-static void prepare_singlestep(struct kp_core *p, struct pt_regs *regs)
-{
-       regs->flags |= TF_MASK;
-       regs->flags &= ~IF_MASK;
-
-       /* single step inline if the instruction is an int3 */
-       if (p->opcode == BREAKPOINT_INSTRUCTION)
-               regs->ip = (unsigned long)p->addr;
-       else
-               regs->ip = (unsigned long)p->ainsn.insn;
-}
-
-/**
- * @brief Saves previous kprobe.
- *
- * @param kcb Pointer to kp_core_ctlblk struct whereto save current kprobe.
- * @param p_run Pointer to kprobe.
- * @return Void.
- */
-static void save_previous_kp_core(struct kp_core_ctlblk *kcb, struct kp_core *cur)
-{
-       if (kcb->prev_kp_core.p != NULL) {
-               panic("no space to save new probe[]: "
-                     "task = %d/%s, prev %08lx, current %08lx, new %08lx,",
-                     current->pid, current->comm, kcb->prev_kp_core.p->addr,
-                     kp_core_running()->addr, cur->addr);
-       }
-
-
-       kcb->prev_kp_core.p = kp_core_running();
-       kcb->prev_kp_core.status = kcb->kp_core_status;
-}
-
-/**
- * @brief Restores previous kp_core.
- *
- * @param kcb Pointer to kp_core_ctlblk which contains previous kp_core.
- * @return Void.
- */
-void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
-{
-       kp_core_running_set(kcb->prev_kp_core.p);
-       kcb->kp_core_status = kcb->prev_kp_core.status;
-       kcb->prev_kp_core.p = NULL;
-       kcb->prev_kp_core.status = 0;
-}
-
-static void set_current_kp_core(struct kp_core *p, struct pt_regs *regs,
-                               struct kp_core_ctlblk *kcb)
-{
-       kp_core_running_set(p);
-       kcb->kp_core_saved_eflags = kcb->kp_core_old_eflags =
-               (regs->EREG(flags) & (TF_MASK | IF_MASK));
-       if (is_IF_modifier(p->opcode))
-               kcb->kp_core_saved_eflags &= ~IF_MASK;
-}
-
-static int setup_singlestep(struct kp_core *p, struct pt_regs *regs,
-                           struct kp_core_ctlblk *kcb)
-{
-#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
-       if (p->ainsn.boostable == 1) {
-               /* Boost up -- we can execute copied instructions directly */
-               kp_core_running_set(NULL);
-               regs->ip = (unsigned long)p->ainsn.insn;
-
-               return 1;
-       }
-#endif /* !CONFIG_PREEMPT */
-
-       prepare_singlestep(p, regs);
-       kcb->kp_core_status = KPROBE_HIT_SS;
-
-       return 1;
-}
-
-
-struct regs_td {
-       struct pt_regs *sp_regs;
-       struct pt_regs regs;
-};
-
-static struct td_raw kp_tdraw;
-static DEFINE_PER_CPU(struct regs_td, per_cpu_regs_td_i);
-static DEFINE_PER_CPU(struct regs_td, per_cpu_regs_td_st);
-
-static struct regs_td *current_regs_td(void)
-{
-       if (swap_in_interrupt())
-               return &__get_cpu_var(per_cpu_regs_td_i);
-       else if (switch_to_bits_get(current_kctx, SWITCH_TO_ALL))
-               return &__get_cpu_var(per_cpu_regs_td_st);
-
-       return (struct regs_td *)swap_td_raw(&kp_tdraw, current);
-}
-
-/** Stack address. */
-unsigned long swap_kernel_sp(struct pt_regs *regs)
-{
-       struct pt_regs *sp_regs = current_regs_td()->sp_regs;
-
-       if (sp_regs == NULL)
-               sp_regs = regs;
-
-       return kernel_stack_pointer(sp_regs);
-}
-EXPORT_SYMBOL_GPL(swap_kernel_sp);
-
-void exec_trampoline(void);
-void exec_trampoline_int3(void);
-__asm(
-       ".text\n"
-       "exec_trampoline:\n"
-       "call   exec_handler\n"
-       "exec_trampoline_int3:\n"
-       "int3\n"
-);
-
-static int __used exec_handler(void)
-{
-       struct kp_core *p = kp_core_running();
-       struct pt_regs *regs = &current_regs_td()->regs;
-
-       return p->handlers.pre(p, regs);
-}
-
-static int after_exec_trampoline(struct pt_regs *regs)
-{
-       int ret = (int)regs->ax;
-       struct kp_core *p = kp_core_running();
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       /*
-        * Restore regs from stack.
-        * Don't restore SP and SS registers because they are invalid (- 8)
-        */
-       memcpy(regs, &current_regs_td()->regs, sizeof(*regs) - 8);
-
-       if (ret) {
-               kp_core_put(p);
-               return 1;
-       }
-
-       setup_singlestep(p, regs, kcb);
-       if (!(regs->flags & TF_MASK))
-               kp_core_put(p);
-
-       return 1;
-}
-
-#define KSTAT_NOT_FOUND                0x00
-#define KSTAT_FOUND            0x01
-#define KSTAT_PREPARE_KCB      0x02
-
-static unsigned long kprobe_pre_handler(struct kp_core *p,
-                                       struct pt_regs *regs,
-                                       struct kp_core_ctlblk *kcb)
-{
-       int ret = KSTAT_NOT_FOUND;
-       unsigned long addr = regs->ip - 1;
-
-       /* Check we're not actually recursing */
-       if (kp_core_running()) {
-               if (p) {
-                       if (kcb->kp_core_status == KPROBE_HIT_SS &&
-                           *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
-                               regs->flags &= ~TF_MASK;
-                               regs->flags |= kcb->kp_core_saved_eflags;
-                               goto out;
-                       }
-
-                       /* We have reentered the kprobe_handler(), since
-                        * another probe was hit while within the handler.
-                        * We here save the original kprobes variables and
-                        * just single step on the instruction of the new probe
-                        * without calling any user handlers.
-                        */
-                       save_previous_kp_core(kcb, p);
-                       set_current_kp_core(p, regs, kcb);
-                       prepare_singlestep(p, regs);
-                       kcb->kp_core_status = KPROBE_REENTER;
-
-                       ret = KSTAT_FOUND;
-                       goto out;
-               } else {
-                       if (*(char *)addr != BREAKPOINT_INSTRUCTION) {
-                               /* The breakpoint instruction was removed by
-                                * another cpu right after we hit, no further
-                                * handling of this interrupt is appropriate
-                                */
-                               regs->EREG(ip) -= sizeof(kprobe_opcode_t);
-
-                               ret = KSTAT_FOUND;
-                               goto out;
-                       }
-
-                       goto out;
-               }
-       }
-
-       if (!p) {
-               if (*(char *)addr != BREAKPOINT_INSTRUCTION) {
-                       /*
-                        * The breakpoint instruction was removed right
-                        * after we hit it.  Another cpu has removed
-                        * either a probepoint or a debugger breakpoint
-                        * at this address.  In either case, no further
-                        * handling of this interrupt is appropriate.
-                        * Back up over the (now missing) int3 and run
-                        * the original instruction.
-                        */
-                       regs->EREG(ip) -= sizeof(kprobe_opcode_t);
-
-                       ret = KSTAT_FOUND;
-               }
-
-               goto out;
-       }
-
-       set_current_kp_core(p, regs, kcb);
-       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
-
-       ret = KSTAT_PREPARE_KCB;
-out:
-       return ret;
-}
-
-static int __kprobe_handler(struct pt_regs *regs)
-{
-       int ret;
-       struct kp_core *p;
-       struct kp_core_ctlblk *kcb;
-       unsigned long addr = regs->ip - 1;
-       struct kctx *ctx = current_kctx;
-
-       if (addr == sched_addr)
-               switch_to_bits_set(ctx, SWITCH_TO_KP);
-
-       kcb = kp_core_ctlblk();
-
-       rcu_read_lock();
-       p = kp_core_by_addr(addr);
-       kp_core_get(p);
-       rcu_read_unlock();
-
-       if (able2resched(ctx)) {
-               ret = kprobe_pre_handler(p, regs, kcb);
-               if (ret == KSTAT_PREPARE_KCB) {
-                       struct regs_td *rtd = current_regs_td();
-
-                       /* save regs to stack */
-                       rtd->regs = *regs;
-                       rtd->sp_regs = regs;
-
-                       regs->ip = (unsigned long)exec_trampoline;
-                       return 1;
-               }
-
-               if (!(regs->flags & TF_MASK))
-                       kp_core_put(p);
-       } else {
-               ret = kprobe_pre_handler(p, regs, kcb);
-               if (ret == KSTAT_PREPARE_KCB) {
-                       int rr;
-
-                       current_regs_td()->sp_regs = NULL;
-                       rr = p->handlers.pre(p, regs);
-                       if (rr) {
-                               switch_to_bits_reset(ctx, SWITCH_TO_KP);
-                               kp_core_put(p);
-                               return 1;
-                       }
-
-                       setup_singlestep(p, regs, kcb);
-               }
-
-               /*
-                * If TF is enabled then processing instruction
-                * takes place in two stages.
-                */
-               if (regs->flags & TF_MASK) {
-                       preempt_disable();
-               } else {
-                       switch_to_bits_reset(ctx, SWITCH_TO_KP);
-                       kp_core_put(p);
-               }
-       }
-
-       return !!ret;
-}
-
-static int kprobe_handler(struct pt_regs *regs)
-{
-       int ret;
-
-       if (regs->ip == (unsigned long)exec_trampoline_int3 + 1)
-               ret = after_exec_trampoline(regs);
-       else
-               ret = __kprobe_handler(regs);
-
-       return ret;
-}
-
-/**
- * @brief Probe pre handler.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0.
- */
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct jprobe *jp = container_of(p, struct jprobe, kp);
-       kprobe_pre_entry_handler_t pre_entry;
-
-       unsigned long addr;
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
-
-       kcb->jprobe_saved_regs = *regs;
-       kcb->jprobe_saved_esp = (unsigned long *)swap_kernel_sp(regs);
-       addr = (unsigned long)(kcb->jprobe_saved_esp);
-
-       /* TBD: As Linus pointed out, gcc assumes that the callee
-        * owns the argument space and could overwrite it, e.g.
-        * tailcall optimization. So, to be absolutely safe
-        * we also save and restore enough stack bytes to cover
-        * the argument area. */
-       memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
-              MIN_STACK_SIZE(addr));
-       regs->EREG(flags) &= ~IF_MASK;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
-       trace_hardirqs_off();
-#endif
-
-       regs->EREG(ip) = (unsigned long)(jp->entry);
-
-       return 1;
-}
-
-/**
- * @brief Jprobe return end.
- *
- * @return Void.
- */
-void swap_jprobe_return_end(void);
-
-/**
- * @brief Jprobe return code.
- *
- * @return Void.
- */
-void swap_jprobe_return(void)
-{
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       asm volatile("       xchgl   %%ebx,%%esp\n"
-                    "       int3\n"
-                    "       .globl swap_jprobe_return_end\n"
-                    "       swap_jprobe_return_end:\n"
-                    "       nop\n"
-                    : : "b" (kcb->jprobe_saved_esp) : "memory");
-}
-EXPORT_SYMBOL_GPL(swap_jprobe_return);
-
-void arch_ujprobe_return(void)
-{
-}
-
-/*
- * Called after single-stepping.  p->addr is the address of the
- * instruction whose first byte has been replaced by the "int 3"
- * instruction.  To avoid the SMP problems that can occur when we
- * temporarily put back the original opcode to single-step, we
- * single-stepped a copy of the instruction.  The address of this
- * copy is p->ainsn.insn.
- *
- * This function prepares to return from the post-single-step
- * interrupt.  We have to fix up the stack as follows:
- *
- * 0) Except in the case of absolute or indirect jump or call instructions,
- * the new eip is relative to the copied instruction.  We need to make
- * it relative to the original instruction.
- *
- * 1) If the single-stepped instruction was pushfl, then the TF and IF
- * flags are set in the just-pushed eflags, and may need to be cleared.
- *
- * 2) If the single-stepped instruction was a call, the return address
- * that is atop the stack is the address following the copied instruction.
- * We need to make it the address following the original instruction.
- *
- * This function also checks instruction size for preparing direct execution.
- */
-static void resume_execution(struct kp_core *p,
-                            struct pt_regs *regs,
-                            struct kp_core_ctlblk *kcb)
-{
-       unsigned long *tos;
-       unsigned long copy_eip = (unsigned long) p->ainsn.insn;
-       unsigned long orig_eip = (unsigned long) p->addr;
-       kprobe_opcode_t insns[2];
-
-       regs->EREG(flags) &= ~TF_MASK;
-
-       tos = (unsigned long *)swap_kernel_sp(regs);
-       insns[0] = p->ainsn.insn[0];
-       insns[1] = p->ainsn.insn[1];
-
-       switch (insns[0]) {
-       case 0x9c: /* pushfl */
-               *tos &= ~(TF_MASK | IF_MASK);
-               *tos |= kcb->kp_core_old_eflags;
-               break;
-       case 0xc2: /* iret/ret/lret */
-       case 0xc3:
-       case 0xca:
-       case 0xcb:
-       case 0xcf:
-       case 0xea: /* jmp absolute -- eip is correct */
-               /* eip is already adjusted, no more changes required */
-               p->ainsn.boostable = 1;
-               goto no_change;
-       case 0xe8: /* call relative - Fix return addr */
-               *tos = orig_eip + (*tos - copy_eip);
-               break;
-       case 0x9a: /* call absolute -- same as call absolute, indirect */
-               *tos = orig_eip + (*tos - copy_eip);
-               goto no_change;
-       case 0xff:
-               if ((insns[1] & 0x30) == 0x10) {
-                       /*
-                        * call absolute, indirect
-                        * Fix return addr; eip is correct.
-                        * But this is not boostable
-                        */
-                       *tos = orig_eip + (*tos - copy_eip);
-                       goto no_change;
-               } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
-                                                          * indirect */
-                        ((insns[1] & 0x31) == 0x21)) {
-                       /* jmp far, absolute indirect */
-                       /* eip is correct. And this is boostable */
-                       p->ainsn.boostable = 1;
-                       goto no_change;
-               }
-       default:
-               break;
-       }
-
-       if (p->ainsn.boostable == 0) {
-               if ((regs->EREG(ip) > copy_eip) &&
-                   (regs->EREG(ip) - copy_eip) + 5 < MAX_INSN_SIZE) {
-                       /*
-                        * These instructions can be executed directly if it
-                        * jumps back to correct address.
-                        */
-                       set_jmp_op((void *)regs->EREG(ip),
-                                  (void *)orig_eip +
-                                  (regs->EREG(ip) - copy_eip));
-                       p->ainsn.boostable = 1;
-               } else {
-                       p->ainsn.boostable = -1;
-               }
-       }
-
-       regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
-
-no_change:
-       return;
-}
-
-/*
- * Interrupts are disabled on entry as trap1 is an interrupt gate and they
- * remain disabled thoroughout this function.
- */
-static int post_kprobe_handler(struct pt_regs *regs)
-{
-       struct kctx *ctx = current_kctx;
-       struct kp_core *cur = kp_core_running();
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       if (!cur)
-               return 0;
-
-       resume_execution(cur, regs, kcb);
-       regs->flags |= kcb->kp_core_saved_eflags;
-#ifndef CONFIG_X86
-       trace_hardirqs_fixup_flags(regs->EREG(flags));
-#endif /* CONFIG_X86 */
-       /* Restore back the original saved kprobes variables and continue. */
-       if (kcb->kp_core_status == KPROBE_REENTER) {
-               restore_previous_kp_core(kcb);
-               goto out;
-       }
-       kp_core_running_set(NULL);
-
-out:
-       if (!able2resched(ctx))
-               swap_preempt_enable_no_resched();
-
-       switch_to_bits_reset(ctx, SWITCH_TO_KP);
-       kp_core_put(cur);
-
-       /*
-        * if somebody else is singlestepping across a probe point, eflags
-        * will have TF set, in which case, continue the remaining processing
-        * of do_debug, as if this is not a probe hit.
-        */
-       if (regs->EREG(flags) & TF_MASK)
-               return 0;
-
-       return 1;
-}
-
-static int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
-{
-       struct kp_core *cur = kp_core_running();
-       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
-
-       switch (kcb->kp_core_status) {
-       case KPROBE_HIT_SS:
-       case KPROBE_REENTER:
-               /*
-                * We are here because the instruction being single
-                * stepped caused a page fault. We reset the current
-                * kprobe and the eip points back to the probe address
-                * and allow the page fault handler to continue as a
-                * normal page fault.
-                */
-               regs->ip = cur->addr;
-               regs->flags |= kcb->kp_core_old_eflags;
-               if (kcb->kp_core_status == KPROBE_REENTER)
-                       restore_previous_kp_core(kcb);
-               else
-                       kp_core_running_set(NULL);
-               break;
-       case KPROBE_HIT_ACTIVE:
-       case KPROBE_HIT_SSDONE:
-               /*
-                * In case the user-specified fault handler returned
-                * zero, try to fix up.
-                */
-               if (swap_fixup_exception(regs))
-                       return 1;
-
-               /*
-                * fixup_exception() could not handle it,
-                * Let do_page_fault() fix it.
-                */
-               break;
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int kprobe_exceptions_notify(struct notifier_block *self,
-                                   unsigned long val, void *data)
-{
-       struct die_args *args = (struct die_args *) data;
-       int ret = NOTIFY_DONE;
-
-       DBPRINTF("val = %ld, data = 0x%X", val, (unsigned int) data);
-
-       if (args->regs == NULL || swap_user_mode(args->regs))
-               return ret;
-
-       DBPRINTF("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP);
-       switch (val) {
-#ifdef CONFIG_KPROBES
-       case DIE_INT3:
-#else
-       case DIE_TRAP:
-#endif
-               DBPRINTF("before kprobe_handler ret=%d %p",
-                        ret, args->regs);
-               if (kprobe_handler (args->regs))
-                       ret = NOTIFY_STOP;
-               DBPRINTF("after kprobe_handler ret=%d %p",
-                        ret, args->regs);
-               break;
-       case DIE_DEBUG:
-               if (post_kprobe_handler(args->regs))
-                       ret = NOTIFY_STOP;
-               break;
-       case DIE_GPF:
-               if (kp_core_running() &&
-                   kprobe_fault_handler(args->regs, args->trapnr))
-                       ret = NOTIFY_STOP;
-               break;
-       default:
-               break;
-       }
-       DBPRINTF("ret=%d", ret);
-       /* if(ret == NOTIFY_STOP) */
-       /*      handled_exceptions++; */
-
-       return ret;
-}
-
-static struct notifier_block kprobe_exceptions_nb = {
-       .notifier_call = kprobe_exceptions_notify,
-       .priority = INT_MAX
-};
-
-/**
- * @brief Arms kp_core.
- *
- * @param core Pointer to target kp_core.
- * @return Void.
- */
-void arch_kp_core_arm(struct kp_core *p)
-{
-       swap_text_poke((void *)p->addr,
-                      ((unsigned char[]){BREAKPOINT_INSTRUCTION}), 1);
-}
-
-/**
- * @brief Disarms kp_core.
- *
- * @param core Pointer to target kp_core.
- * @return Void.
- */
-void arch_kp_core_disarm(struct kp_core *p)
-{
-       swap_text_poke((void *)p->addr, &p->opcode, 1);
-}
-
-/**
- * @brief Prepares kretprobes, saves ret address, makes function return to
- * trampoline.
- *
- * @param ri Pointer to kretprobe_instance.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       unsigned long *ptr_ret_addr = (unsigned long *)swap_kernel_sp(regs);
-
-       /* for __switch_to probe */
-       if ((unsigned long)ri->rp->kp.addr == sched_addr) {
-               struct task_struct *next = (struct task_struct *)swap_get_karg(regs, 1);
-               ri->sp = NULL;
-               ri->task = next;
-               switch_to_bits_set(kctx_by_task(next), SWITCH_TO_RP);
-       } else {
-               ri->sp = ptr_ret_addr;
-       }
-
-       /* Save the return address */
-       ri->ret_addr = (unsigned long *)*ptr_ret_addr;
-
-       /* Replace the return addr with trampoline addr */
-       *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline;
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                                   jumper                                   *
- ******************************************************************************
- */
-struct cb_data {
-       unsigned long ret_addr;
-       unsigned long bx;
-
-       jumper_cb_t cb;
-       char data[0];
-};
-
-static unsigned long __used get_bx(struct cb_data *data)
-{
-       return data->bx;
-}
-
-static unsigned long __used jump_handler(struct cb_data *data)
-{
-       unsigned long ret_addr = data->ret_addr;
-
-       /* call callback */
-       data->cb(data->data);
-
-       /* FIXME: potential memory leak, when process kill */
-       kfree(data);
-
-       return ret_addr;
-}
-
-void jump_trampoline(void);
-__asm(
-       "jump_trampoline:\n"
-       "pushf\n"
-       SWAP_SAVE_REGS_STRING
-       "movl   %ebx, %eax\n"   /* data --> ax */
-       "call   get_bx\n"
-       "movl   %eax, (%esp)\n" /* restore bx */
-       "movl   %ebx, %eax\n"   /* data --> ax */
-       "call   jump_handler\n"
-       /* move flags to cs */
-       "movl 56(%esp), %edx\n"
-       "movl %edx, 52(%esp)\n"
-       /* replace saved flags with true return address. */
-       "movl %eax, 56(%esp)\n"
-       SWAP_RESTORE_REGS_STRING
-       "popf\n"
-       "ret\n"
-);
-
-unsigned long get_jump_addr(void)
-{
-       return (unsigned long)&jump_trampoline;
-}
-EXPORT_SYMBOL_GPL(get_jump_addr);
-
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
-               jumper_cb_t cb, void *data, size_t size)
-{
-       struct cb_data *cb_data;
-
-       cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
-       if (cb_data == NULL)
-               return -ENOMEM;
-
-       /* save data */
-       if (size)
-               memcpy(cb_data->data, data, size);
-
-       /* save info for restore */
-       cb_data->ret_addr = ret_addr;
-       cb_data->cb = cb;
-       cb_data->bx = regs->bx;
-
-       /* save cb_data to bx */
-       regs->bx = (long)cb_data;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(set_jump_cb);
-
-
-
-
-
-/**
- * @brief Initializes x86 module deps.
- *
- * @return 0 on success, negative error code on error.
- */
-int arch_init_module_deps()
-{
-       const char *sym;
-
-       sym = "fixup_exception";
-       swap_fixup_exception = (void *)swap_ksyms(sym);
-       if (swap_fixup_exception == NULL)
-               goto not_found;
-
-       sym = "text_poke";
-       swap_text_poke = (void *)swap_ksyms(sym);
-       if (swap_text_poke == NULL)
-               goto not_found;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
-       sym = "show_registers";
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */
-       sym = "show_regs";
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */
-       swap_show_registers = (void *)swap_ksyms(sym);
-       if (swap_show_registers == NULL)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol %s(...) not found\n", sym);
-       return -ESRCH;
-}
-
-/**
- * @brief Initializes kprobes module for ARM arch.
- *
- * @return 0 on success, error code on error.
- */
-int swap_arch_init_kprobes(void)
-{
-       int ret;
-
-       ret = swap_td_raw_reg(&kp_tdraw, sizeof(struct regs_td));
-       if (ret)
-               return ret;
-
-       ret = register_die_notifier(&kprobe_exceptions_nb);
-       if (ret)
-               swap_td_raw_unreg(&kp_tdraw);
-
-       return ret;
-}
-
-/**
- * @brief Uninitializes kprobe module.
- *
- * @return Void.
- */
-void swap_arch_exit_kprobes(void)
-{
-       unregister_die_notifier(&kprobe_exceptions_nb);
-       swap_td_raw_unreg(&kp_tdraw);
-}
diff --git a/kprobe/arch/x86/swap-asm/swap_kprobes.h b/kprobe/arch/x86/swap-asm/swap_kprobes.h
deleted file mode 100644 (file)
index 7aed0bb..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/**
- * @file kprobe/arch/asm-x86/swap_kprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @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) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent kprobes interface for x86 arch.
- */
-
-#ifndef _SWAP_ASM_X86_KPROBES_H
-#define _SWAP_ASM_X86_KPROBES_H
-
-
-#include <linux/version.h>
-#include <kprobe/swap_kprobes_deps.h>
-
-/**
- * @brief Opcode type.
- */
-typedef u8 kprobe_opcode_t;
-
-#define BREAKPOINT_INSTRUCTION          0xcc
-#define RELATIVEJUMP_INSTRUCTION        0xe9
-
-#define BP_INSN_SIZE                    1
-#define MAX_INSN_SIZE                   16
-#define MAX_STACK_SIZE                  64
-
-#define MIN_STACK_SIZE(ADDR)   (((MAX_STACK_SIZE) <                      \
-                       (((unsigned long)current_thread_info())  \
-                        + THREAD_SIZE - (ADDR)))                 \
-               ? (MAX_STACK_SIZE)                        \
-               : (((unsigned long)current_thread_info()) \
-                       + THREAD_SIZE - (ADDR)))
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
-
-#define EREG(rg)                e##rg
-#define XREG(rg)                x##rg
-#define ORIG_EAX_REG            orig_eax
-
-#else
-
-#define EREG(rg)                rg
-#define XREG(rg)                rg
-#define ORIG_EAX_REG            orig_ax
-
-#endif /*  LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
-#define TF_MASK                         X86_EFLAGS_TF
-#define IF_MASK                                X86_EFLAGS_IF
-#endif
-#define UPROBES_TRAMP_LEN               (MAX_INSN_SIZE+sizeof(kprobe_opcode_t))
-#define UPROBES_TRAMP_INSN_IDX         0
-#define UPROBES_TRAMP_RET_BREAK_IDX     MAX_INSN_SIZE
-#define KPROBES_TRAMP_LEN              MAX_INSN_SIZE
-#define KPROBES_TRAMP_INSN_IDX          0
-
-static inline int swap_user_mode(struct pt_regs *regs)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
-       return user_mode(regs);
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
-       return user_mode_vm(regs);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
-}
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
-#define swap_in_interrupt()    (in_interrupt() & ~HARDIRQ_OFFSET)
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
-
-static inline unsigned long arch_get_task_pc(struct task_struct *p)
-{
-       /* FIXME: Not implemented yet */
-       return 0;
-}
-
-static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
-{
-       /* FIXME: Not implemented yet */
-}
-
-static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
-{
-       return NULL; /* FIXME currently not implemented for x86 */
-}
-
-static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
-{
-       return regs->EREG(sp);
-}
-
-static inline void swap_set_stack_ptr(struct pt_regs *regs, unsigned long sp)
-{
-       regs->EREG(sp) = sp;
-}
-
-static inline unsigned long swap_get_kpc(struct pt_regs *regs)
-{
-       return regs->ip;
-}
-
-static inline void swap_set_kpc(struct pt_regs *regs, unsigned long val)
-{
-       regs->ip = val;
-}
-
-static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
-{
-       unsigned long arg = 0;
-       read_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
-                       &arg, sizeof(arg));
-       return arg;
-}
-
-static inline void swap_set_arg(struct pt_regs *regs, int num,
-                               unsigned long val)
-{
-       write_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
-                       &val, sizeof(val));
-}
-
-/**
- * @struct prev_kp_core
- * @brief Stores previous kp_core.
- * @var prev_kp_core::kp
- * Pointer to kp_core struct.
- * @var prev_kp_core::status
- * kp_core status.
- */
-struct prev_kp_core {
-       struct kp_core *p;
-       unsigned long status;
-};
-
-/**
- * @struct kp_core_ctlblk
- * @brief Per-cpu kp_core control block.
- * @var kp_core_ctlblk::kp_core_status
- * kp_core status.
- * @var kp_core_ctlblk::prev_kp_core
- * Previous kp_core.
- */
-struct kp_core_ctlblk {
-       unsigned long kp_core_status;
-       struct prev_kp_core prev_kp_core;
-       struct pt_regs jprobe_saved_regs;
-       unsigned long kp_core_old_eflags;
-       unsigned long kp_core_saved_eflags;
-       unsigned long *jprobe_saved_esp;
-       kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
-};
-
-
-/**
- * @struct swap_arch_specific_insn
- * @brief Architecture specific copy of original instruction.
- * @var swap_arch_specific_insn::insn
- * Copy of the original instruction.
- * @var swap_arch_specific_insn::boostable
- * If this flag is not 0, this kp_core can be boost when its
- * post_handler and break_handler is not set.
- */
-struct swap_arch_specific_insn {
-       kprobe_opcode_t *insn;
-       int boostable;
-};
-
-/**
- * @brief Entry point.
- */
-typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
-                                         unsigned long, unsigned long,
-                                         unsigned long, unsigned long);
-
-int arch_init_module_deps(void);
-
-struct kprobe;
-struct kp_core;
-struct slot_manager;
-struct kretprobe_instance;
-
-int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
-void arch_kp_core_arm(struct kp_core *core);
-void arch_kp_core_disarm(struct kp_core *core);
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                struct pt_regs *regs);
-void swap_kretprobe_trampoline(void);
-
-void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
-int swap_can_boost(kprobe_opcode_t *opcodes);
-static inline int arch_check_insn(struct swap_arch_specific_insn *ainsn)
-{
-       return 0;
-}
-
-unsigned long swap_kernel_sp(struct pt_regs *regs);
-
-static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
-{
-       switch (n) {
-       case 0:
-               return regs->ax;
-       case 1:
-               return regs->dx;
-       case 2:
-               return regs->cx;
-       }
-
-       /*
-        * 2 = 3 - 1
-        * 3 - arguments from registers
-        * 1 - return address saved on top of the stack
-        */
-       return *((unsigned long *)swap_kernel_sp(regs) + n - 2);
-}
-
-static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
-{
-       /* 1 - return address saved on top of the stack */
-       return *((unsigned long *)kernel_stack_pointer(regs) + n + 1);
-}
-
-/* jumper */
-typedef unsigned long (*jumper_cb_t)(void *);
-
-unsigned long get_jump_addr(void);
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
-               jumper_cb_t cb, void *data, size_t size);
-
-int swap_arch_init_kprobes(void);
-void swap_arch_exit_kprobes(void);
-
-#endif /* _SWAP_ASM_X86_KPROBES_H */
diff --git a/kprobe/swap_kdebug.h b/kprobe/swap_kdebug.h
deleted file mode 100644 (file)
index 4c3be6e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file kprobe/swap_kdebug.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Header for debug purposes.
- */
-
-
-#ifndef _SWAP_KPROBE_DEBUG_H
-#define _SWAP_KPROBE_DEBUG_H
-
-/* #define _DEBUG */
-
-#ifdef _DEBUG
-#define DBPRINTF(format, args...) do { \
-               if (1) { \
-                       char *f = __FILE__; \
-                       char *n = strrchr(f, '/'); \
-                       printk(KERN_INFO "%s : %u : %s : " format "\n" , \
-                              (n) ? n+1 : f, __LINE__, __func__, ##args); \
-               } \
-       } while (0)
-#else
-#define DBPRINTF(format, args...)
-#endif
-
-
-#endif /* _SWAP_KPROBE_DEBUG_H */
diff --git a/kprobe/swap_kprobes.c b/kprobe/swap_kprobes.c
deleted file mode 100644 (file)
index 3981ffe..0000000
+++ /dev/null
@@ -1,1300 +0,0 @@
-/**
- * kprobe/swap_kprobes.c
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM and MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @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) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe implementation. Dynamic kernel functions instrumentation.
- */
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-#include <linux/config.h>
-#endif
-
-#include <linux/hash.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/stop_machine.h>
-#include <linux/delay.h>
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-#include <swap-asm/swap_kprobes.h>
-#include "swap_ktd.h"
-#include "swap_slots.h"
-#include "swap_ktd.h"
-#include "swap_td_raw.h"
-#include "swap_kdebug.h"
-#include "swap_kprobes.h"
-#include "swap_kprobes_deps.h"
-
-
-#define KRETPROBE_STACK_DEPTH 64
-
-
-/**
- * @var sched_addr
- * @brief Scheduler address.
- */
-unsigned long sched_addr;
-static unsigned long exit_addr;
-static unsigned long do_group_exit_addr;
-static unsigned long sys_exit_group_addr;
-static unsigned long sys_exit_addr;
-
-/**
- * @var sm
- * @brief Current slot manager. Slots are the places where trampolines are
- * located.
- */
-struct slot_manager sm;
-
-static DEFINE_SPINLOCK(kretprobe_lock);        /* Protects kretprobe_inst_table */
-
-static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
-static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
-
-/**
- * @var kprobe_count
- * @brief Count of kprobes.
- */
-atomic_t kprobe_count;
-EXPORT_SYMBOL_GPL(kprobe_count);
-
-
-static void *(*__module_alloc)(unsigned long size);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
-static void (*__module_free)(void *module_region);
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
-static void (*__module_free)(struct module *mod, void *module_region);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
-
-static void *wrapper_module_alloc(unsigned long size)
-{
-       return __module_alloc(size);
-}
-
-static void wrapper_module_free(void *module_region)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
-       __module_free(module_region);
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
-       __module_free(NULL, module_region);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
-}
-
-static void *sm_alloc(struct slot_manager *sm)
-{
-       return wrapper_module_alloc(PAGE_SIZE);
-}
-
-static void sm_free(struct slot_manager *sm, void *ptr)
-{
-       wrapper_module_free(ptr);
-}
-
-static void init_sm(void)
-{
-       sm.slot_size = KPROBES_TRAMP_LEN;
-       sm.alloc = sm_alloc;
-       sm.free = sm_free;
-       INIT_HLIST_HEAD(&sm.page_list);
-}
-
-static void exit_sm(void)
-{
-       /* FIXME: free */
-}
-
-static struct hlist_head *kpt_head_by_addr(unsigned long addr)
-{
-       return &kprobe_table[hash_ptr((void *)addr, KPROBE_HASH_BITS)];
-}
-
-static void kretprobe_assert(struct kretprobe_instance *ri,
-                            unsigned long orig_ret_address,
-                            unsigned long trampoline_address)
-{
-       if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
-               struct task_struct *task;
-               if (ri == NULL)
-                       panic("kretprobe BUG!: ri = NULL\n");
-
-               task = ri->task;
-
-               if (task == NULL)
-                       panic("kretprobe BUG!: task = NULL\n");
-
-               if (ri->rp == NULL)
-                       panic("kretprobe BUG!: ri->rp = NULL\n");
-
-               panic("kretprobe BUG!: "
-                     "Processing kretprobe %p @ %08lx (%d/%d - %s)\n",
-                     ri->rp, ri->rp->kp.addr, ri->task->tgid,
-                     ri->task->pid, ri->task->comm);
-       }
-}
-
-struct kpc_data {
-       struct kp_core *running;
-       struct kp_core_ctlblk ctlblk;
-};
-
-struct kctx {
-       struct kpc_data kpc;
-       unsigned long st_flags;
-};
-
-static void ktd_cur_init(struct task_struct *task, void *data)
-{
-       struct kctx *ctx = (struct kctx *)data;
-
-       memset(ctx, 0, sizeof(*ctx));
-}
-
-static void ktd_cur_exit(struct task_struct *task, void *data)
-{
-       struct kctx *ctx = (struct kctx *)data;
-
-       WARN(ctx->kpc.running, "running=%p\n", ctx->kpc.running);
-}
-
-struct ktask_data ktd_cur = {
-       .init = ktd_cur_init,
-       .exit = ktd_cur_exit,
-       .size = sizeof(struct kctx),
-};
-
-struct kctx *kctx_by_task(struct task_struct *task)
-{
-       return (struct kctx *)swap_ktd(&ktd_cur, task);
-}
-
-void switch_to_bits_set(struct kctx *ctx, unsigned long mask)
-{
-       ctx->st_flags |= mask;
-}
-
-void switch_to_bits_reset(struct kctx *ctx, unsigned long mask)
-{
-       ctx->st_flags &= ~mask;
-}
-
-unsigned long switch_to_bits_get(struct kctx *ctx, unsigned long mask)
-{
-       return ctx->st_flags & mask;
-}
-
-static DEFINE_PER_CPU(struct kpc_data, per_cpu_kpc_data_i);
-static DEFINE_PER_CPU(struct kpc_data, per_cpu_kpc_data_st);
-
-static struct kpc_data *kp_core_data(void)
-{
-       struct kctx *ctx = current_kctx;
-
-       if (swap_in_interrupt())
-               return &__get_cpu_var(per_cpu_kpc_data_i);
-       else if (switch_to_bits_get(ctx, SWITCH_TO_ALL))
-               return &__get_cpu_var(per_cpu_kpc_data_st);
-
-       return &ctx->kpc;
-}
-
-static int kprobe_cur_reg(void)
-{
-       return swap_ktd_reg(&ktd_cur);
-}
-
-static void kprobe_cur_unreg(void)
-{
-       swap_ktd_unreg(&ktd_cur);
-}
-
-struct kp_core *kp_core_running(void)
-{
-       return kp_core_data()->running;
-}
-
-void kp_core_running_set(struct kp_core *p)
-{
-       kp_core_data()->running = p;
-}
-
-/**
- * @brief Gets kp_core_ctlblk for the current CPU.
- *
- * @return Current CPU struct kp_core_ctlblk.
- */
-struct kp_core_ctlblk *kp_core_ctlblk(void)
-{
-       return &kp_core_data()->ctlblk;
-}
-
-/*
- * This routine is called either:
- *     - under the kprobe_mutex - during kprobe_[un]register()
- *                             OR
- *     - with preemption disabled - from arch/xxx/kernel/kprobes.c
- */
-
-/**
- * @brief Gets kp_core.
- *
- * @param addr Probe address.
- * @return kprobe_core for addr.
- */
-struct kp_core *kp_core_by_addr(unsigned long addr)
-{
-       struct hlist_head *head;
-       struct kp_core *core;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       head = kpt_head_by_addr(addr);
-       swap_hlist_for_each_entry_rcu(core, node, head, hlist) {
-               if (core->addr == addr)
-                       return core;
-       }
-
-       return NULL;
-}
-
-
-static int alloc_nodes_kretprobe(struct kretprobe *rp);
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
-{
-       struct kretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
-               return ri;
-       }
-
-       if (!alloc_nodes_kretprobe(rp)) {
-               swap_hlist_for_each_entry(ri, node, &rp->free_instances,
-                                         uflist) {
-                       return ri;
-               }
-       }
-
-       return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance *
-get_free_rp_inst_no_alloc(struct kretprobe *rp)
-{
-       struct kretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
-               return ri;
-       }
-
-       return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
-{
-       struct kretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
-               return ri;
-       }
-
-       return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static void add_rp_inst(struct kretprobe_instance *ri)
-{
-       /*
-        * Remove rp inst off the free list -
-        * Add it back when probed function returns
-        */
-       hlist_del(&ri->uflist);
-
-       /* Add rp inst onto table */
-       INIT_HLIST_NODE(&ri->hlist);
-
-       hlist_add_head(&ri->hlist,
-                      &kretprobe_inst_table[hash_ptr(ri->task,
-                                                     KPROBE_HASH_BITS)]);
-
-       /* Also add this rp inst to the used list. */
-       INIT_HLIST_NODE(&ri->uflist);
-       hlist_add_head(&ri->uflist, &ri->rp->used_instances);
-}
-
-/* Called with kretprobe_lock held */
-static void recycle_rp_inst(struct kretprobe_instance *ri)
-{
-       if (ri->rp) {
-               hlist_del(&ri->hlist);
-               /* remove rp inst off the used list */
-               hlist_del(&ri->uflist);
-               /* put rp inst back onto the free list */
-               INIT_HLIST_NODE(&ri->uflist);
-               hlist_add_head(&ri->uflist, &ri->rp->free_instances);
-       }
-}
-
-static struct hlist_head *kretprobe_inst_table_head(void *hash_key)
-{
-       return &kretprobe_inst_table[hash_ptr(hash_key, KPROBE_HASH_BITS)];
-}
-
-static void free_rp_inst(struct kretprobe *rp)
-{
-       struct kretprobe_instance *ri;
-       while ((ri = get_free_rp_inst_no_alloc(rp)) != NULL) {
-               hlist_del(&ri->uflist);
-               kfree(ri);
-       }
-}
-
-static void kp_core_remove(struct kp_core *core)
-{
-       /* TODO: check boostable for x86 and MIPS */
-       swap_slot_free(&sm, core->ainsn.insn);
-}
-
-static void kp_core_wait(struct kp_core *p)
-{
-       int ms = 1;
-
-       while (atomic_read(&p->usage)) {
-               msleep(ms);
-               ms += ms < 7 ? 1 : 0;
-       }
-}
-
-static struct kp_core *kp_core_create(unsigned long addr)
-{
-       struct kp_core *core;
-
-       core = kzalloc(sizeof(*core), GFP_KERNEL);
-       if (core) {
-               INIT_HLIST_NODE(&core->hlist);
-               core->addr = addr;
-               atomic_set(&core->usage, 0);
-               rwlock_init(&core->handlers.lock);
-       }
-
-       return core;
-}
-
-static void kp_core_free(struct kp_core *core)
-{
-       WARN_ON(atomic_read(&core->usage));
-       kfree(core);
-}
-
-static int pre_handler_one(struct kp_core *core, struct pt_regs *regs)
-{
-       int ret = 0;
-       struct kprobe *p = core->handlers.kps[0];
-
-       if (p && p->pre_handler)
-               ret = p->pre_handler(p, regs);
-
-       return ret;
-}
-
-static int pre_handler_multi(struct kp_core *core, struct pt_regs *regs)
-{
-       int i, ret = 0;
-
-       /* TODO: add sync use kprobe */
-       for (i = 0; i < ARRAY_SIZE(core->handlers.kps); ++i) {
-               struct kprobe *p = core->handlers.kps[i];
-
-               if (p && p->pre_handler) {
-                       ret = p->pre_handler(p, regs);
-                       if (ret)
-                               break;
-               }
-       }
-
-       return ret;
-}
-
-static int kp_core_add_kprobe(struct kp_core *core, struct kprobe *p)
-{
-       int i, ret = 0;
-       unsigned long flags;
-       struct kp_handlers *h = &core->handlers;
-
-       write_lock_irqsave(&h->lock, flags);
-       if (h->pre == NULL) {
-               h->pre = pre_handler_one;
-       } else if (h->pre == pre_handler_one) {
-               h->pre = pre_handler_multi;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(core->handlers.kps); ++i) {
-               if (core->handlers.kps[i])
-                       continue;
-
-               core->handlers.kps[i] = p;
-               goto unlock;
-       }
-
-       pr_err("all kps slots is busy\n");
-       ret = -EBUSY;
-unlock:
-       write_unlock_irqrestore(&h->lock, flags);
-       return ret;
-}
-
-static void kp_core_del_kprobe(struct kp_core *core, struct kprobe *p)
-{
-       int i, cnt = 0;
-       unsigned long flags;
-       struct kp_handlers *h = &core->handlers;
-
-       write_lock_irqsave(&h->lock, flags);
-       for (i = 0; i < ARRAY_SIZE(h->kps); ++i) {
-               if (h->kps[i] == p)
-                       h->kps[i] = NULL;
-
-               if (h->kps[i] == NULL)
-                       ++cnt;
-       }
-       write_unlock_irqrestore(&h->lock, flags);
-
-       if (cnt == ARRAY_SIZE(h->kps)) {
-               arch_kp_core_disarm(core);
-               synchronize_sched();
-
-               hlist_del_rcu(&core->hlist);
-               synchronize_rcu();
-
-               kp_core_wait(core);
-               kp_core_remove(core);
-               kp_core_free(core);
-       }
-}
-
-static DEFINE_MUTEX(kp_mtx);
-/**
- * @brief Registers kprobe.
- *
- * @param p Pointer to the target kprobe.
- * @return 0 on success, error code on error.
- */
-int swap_register_kprobe(struct kprobe *p)
-{
-       struct kp_core *core;
-       unsigned long addr;
-       int ret = 0;
-       /*
-        * If we have a symbol_name argument look it up,
-        * and add it to the address.  That way the addr
-        * field can either be global or relative to a symbol.
-        */
-       if (p->symbol_name) {
-               if (p->addr)
-                       return -EINVAL;
-               p->addr = swap_ksyms(p->symbol_name);
-       }
-
-       if (!p->addr)
-               return -EINVAL;
-
-       addr = p->addr + p->offset;
-
-       mutex_lock(&kp_mtx);
-       core = kp_core_by_addr(addr);
-       if (core == NULL) {
-               core = kp_core_create(addr);
-               if (core == NULL) {
-                       pr_err("Out of memory\n");
-                       ret = -ENOMEM;
-                       goto unlock;
-               }
-
-               ret = arch_kp_core_prepare(core, &sm);
-               if (ret) {
-                       kp_core_free(core);
-                       goto unlock;
-               }
-
-               ret = kp_core_add_kprobe(core, p);
-               if (ret) {
-                       kp_core_free(core);
-                       goto unlock;
-               }
-
-               hlist_add_head_rcu(&core->hlist, kpt_head_by_addr(core->addr));
-               arch_kp_core_arm(core);
-       } else {
-               ret = kp_core_add_kprobe(core, p);
-       }
-
-unlock:
-       mutex_unlock(&kp_mtx);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_kprobe);
-
-/**
- * @brief Unregistes kprobe.
- *
- * @param kp Pointer to the target kprobe.
- * @return Void.
- */
-void swap_unregister_kprobe(struct kprobe *p)
-{
-       unsigned long addr = p->addr + p->offset;
-       struct kp_core *core;
-
-       mutex_lock(&kp_mtx);
-       core = kp_core_by_addr(addr);
-       BUG_ON(core == NULL);
-
-       kp_core_del_kprobe(core, p);
-       mutex_unlock(&kp_mtx);
-
-       /* Set 0 addr for reusability if symbol_name is used */
-       if (p->symbol_name)
-               p->addr = 0;
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kprobe);
-
-/**
- * @brief Registers jprobe.
- *
- * @param jp Pointer to the target jprobe.
- * @return swap_register_kprobe result.
- */
-int swap_register_jprobe(struct jprobe *jp)
-{
-       /* Todo: Verify probepoint is a function entry point */
-       jp->kp.pre_handler = swap_setjmp_pre_handler;
-
-       return swap_register_kprobe(&jp->kp);
-}
-EXPORT_SYMBOL_GPL(swap_register_jprobe);
-
-/**
- * @brief Unregisters jprobe.
- *
- * @param jp Pointer to the target jprobe.
- * @return Void.
- */
-void swap_unregister_jprobe(struct jprobe *jp)
-{
-       swap_unregister_kprobe(&jp->kp);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_jprobe);
-
-/*
- * This kprobe pre_handler is registered with every kretprobe. When probe
- * hits it will set up the return probe.
- */
-static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
-{
-       struct kretprobe *rp = container_of(p, struct kretprobe, kp);
-       struct kretprobe_instance *ri;
-       unsigned long flags = 0;
-
-       /* TODO: consider to only swap the RA
-        * after the last pre_handler fired */
-       spin_lock_irqsave(&kretprobe_lock, flags);
-
-       /* TODO: test - remove retprobe after func entry but before its exit */
-       ri = get_free_rp_inst(rp);
-       if (ri != NULL) {
-               int skip = 0;
-
-               ri->rp = rp;
-               ri->task = current;
-
-               if (rp->entry_handler)
-                       skip = rp->entry_handler(ri, regs);
-
-               if (skip) {
-                       add_rp_inst(ri);
-                       recycle_rp_inst(ri);
-               } else {
-                       swap_arch_prepare_kretprobe(ri, regs);
-                       add_rp_inst(ri);
-               }
-       } else {
-               ++rp->nmissed;
-       }
-
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-
-       return 0;
-}
-
-/**
- * @brief Trampoline probe handler.
- *
- * @param p Pointer to the fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return orig_ret_address
- */
-unsigned long swap_trampoline_handler(struct pt_regs *regs)
-{
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address;
-
-       struct kp_core_ctlblk *kcb;
-
-       struct hlist_node *tmp;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       trampoline_address = (unsigned long)&swap_kretprobe_trampoline;
-
-       kcb = kp_core_ctlblk();
-
-       spin_lock_irqsave(&kretprobe_lock, flags);
-
-       /*
-        * We are using different hash keys (current and mm) for finding kernel
-        * space and user space probes.  Kernel space probes can change mm field
-        * in task_struct.  User space probes can be shared between threads of
-        * one process so they have different current but same mm.
-        */
-       head = kretprobe_inst_table_head(current);
-
-#ifdef CONFIG_X86
-       regs->XREG(cs) = __KERNEL_CS | get_kernel_rpl();
-       regs->EREG(ip) = trampoline_address;
-       regs->ORIG_EAX_REG = 0xffffffff;
-#endif
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more then one
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-               if (ri->rp && ri->rp->handler) {
-                       /*
-                        * Set fake current probe, we don't
-                        * want to go into recursion
-                        */
-                       kp_core_running_set((struct kp_core *)0xfffff);
-                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
-                       ri->rp->handler(ri, regs);
-                       kp_core_running_set(NULL);
-               }
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri);
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       if (kcb->kp_core_status == KPROBE_REENTER)
-               restore_previous_kp_core(kcb);
-       else
-               kp_core_running_set(NULL);
-
-       switch_to_bits_reset(current_kctx, SWITCH_TO_RP);
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-
-       /*
-        * By returning a non-zero value, we are telling
-        * kprobe_handler() that we don't want the post_handler
-        * to run (and have re-enabled preemption)
-        */
-
-       return orig_ret_address;
-}
-
-#define SCHED_RP_NR 200
-#define COMMON_RP_NR 10
-
-static int alloc_nodes_kretprobe(struct kretprobe *rp)
-{
-       int alloc_nodes;
-       struct kretprobe_instance *inst;
-       int i;
-
-       DBPRINTF("Alloc aditional mem for retprobes");
-
-       if (rp->kp.addr == sched_addr) {
-               rp->maxactive += SCHED_RP_NR; /* max (100, 2 * NR_CPUS); */
-               alloc_nodes = SCHED_RP_NR;
-       } else {
-#if 1/* def CONFIG_PREEMPT */
-               rp->maxactive += max(COMMON_RP_NR, 2 * NR_CPUS);
-#else
-               rp->maxacpptive += NR_CPUS;
-#endif
-               alloc_nodes = COMMON_RP_NR;
-       }
-
-       for (i = 0; i < alloc_nodes; i++) {
-               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_ATOMIC);
-               if (inst == NULL) {
-                       free_rp_inst(rp);
-                       return -ENOMEM;
-               }
-               INIT_HLIST_NODE(&inst->uflist);
-               hlist_add_head(&inst->uflist, &rp->free_instances);
-       }
-
-       DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
-                 (unsigned long) (*(rp->kp.addr)),
-                 (unsigned long) (*(rp->kp.addr + 1)),
-                 (unsigned long) (*(rp->kp.addr + 2)));
-       return 0;
-}
-
-/**
- * @brief Registers kretprobes.
- *
- * @param rp Pointer to the target kretprobe.
- * @return 0 on success, error code on error.
- */
-int swap_register_kretprobe(struct kretprobe *rp)
-{
-       int ret = 0;
-       struct kretprobe_instance *inst;
-       int i;
-       DBPRINTF("START");
-
-       rp->kp.pre_handler = pre_handler_kretprobe;
-
-       /* Pre-allocate memory for max kretprobe instances */
-       if (rp->kp.addr == exit_addr) {
-               rp->kp.pre_handler = NULL; /* not needed for do_exit */
-               rp->maxactive = 0;
-       } else if (rp->kp.addr == do_group_exit_addr) {
-               rp->kp.pre_handler = NULL;
-               rp->maxactive = 0;
-       } else if (rp->kp.addr == sys_exit_group_addr) {
-               rp->kp.pre_handler = NULL;
-               rp->maxactive = 0;
-       } else if (rp->kp.addr == sys_exit_addr) {
-               rp->kp.pre_handler = NULL;
-               rp->maxactive = 0;
-       } else if (rp->maxactive <= 0) {
-#if 1/* def CONFIG_PREEMPT */
-               rp->maxactive = max(COMMON_RP_NR, 2 * NR_CPUS);
-#else
-               rp->maxactive = NR_CPUS;
-#endif
-       }
-       INIT_HLIST_HEAD(&rp->used_instances);
-       INIT_HLIST_HEAD(&rp->free_instances);
-       for (i = 0; i < rp->maxactive; i++) {
-               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_KERNEL);
-               if (inst == NULL) {
-                       free_rp_inst(rp);
-                       return -ENOMEM;
-               }
-               INIT_HLIST_NODE(&inst->uflist);
-               hlist_add_head(&inst->uflist, &rp->free_instances);
-       }
-
-       DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
-                 (unsigned long) (*(rp->kp.addr)),
-                 (unsigned long) (*(rp->kp.addr + 1)),
-                 (unsigned long) (*(rp->kp.addr + 2)));
-       rp->nmissed = 0;
-       /* Establish function entry probe point */
-       ret = swap_register_kprobe(&rp->kp);
-       if (ret != 0)
-               free_rp_inst(rp);
-
-       DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
-                 (unsigned long) (*(rp->kp.addr)),
-                 (unsigned long) (*(rp->kp.addr + 1)),
-                 (unsigned long) (*(rp->kp.addr + 2)));
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_kretprobe);
-
-static int swap_disarm_krp_inst(struct kretprobe_instance *ri);
-
-static void swap_disarm_krp(struct kretprobe *rp)
-{
-       struct kretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
-               if (swap_disarm_krp_inst(ri) != 0) {
-                       printk(KERN_INFO "%s (%d/%d): cannot disarm "
-                              "krp instance (%08lx)\n",
-                              ri->task->comm, ri->task->tgid, ri->task->pid,
-                              rp->kp.addr);
-               }
-       }
-}
-
-
-struct unreg_krp_args {
-       struct kretprobe **rps;
-       size_t size;
-       int rp_disarm;
-};
-
-static int __swap_unregister_kretprobes_top(void *data)
-{
-       struct unreg_krp_args *args = data;
-       struct kretprobe **rps = args->rps;
-       size_t size = args->size;
-       int rp_disarm = args->rp_disarm;
-       unsigned long flags;
-       const size_t end = ((size_t) 0) - 1;
-
-       for (--size; size != end; --size) {
-               if (rp_disarm) {
-                       spin_lock_irqsave(&kretprobe_lock, flags);
-                       swap_disarm_krp(rps[size]);
-                       spin_unlock_irqrestore(&kretprobe_lock, flags);
-               }
-       }
-
-       return 0;
-}
-
-/**
- * @brief Kretprobes unregister top. Unregisters kprobes.
- *
- * @param rps Pointer to the array of pointers to the target kretprobes.
- * @param size Size of rps array.
- * @param rp_disarm Disarm flag. If set kretprobe is disarmed.
- * @return Void.
- */
-void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size,
-                                  int rp_disarm)
-{
-       struct unreg_krp_args args = {
-               .rps = rps,
-               .size = size,
-               .rp_disarm = rp_disarm,
-       };
-       const size_t end = ((size_t)0) - 1;
-
-       for (--size; size != end; --size)
-               swap_unregister_kprobe(&rps[size]->kp);
-
-       if (rp_disarm) {
-               int ret;
-
-               ret = stop_machine(__swap_unregister_kretprobes_top,
-                                  &args, NULL);
-               if (ret)
-                       pr_err("%s failed (%d)\n", __func__, ret);
-       } else {
-               __swap_unregister_kretprobes_top(&args);
-       }
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_top);
-
-/**
- * @brief swap_unregister_kretprobes_top wrapper for a single kretprobe.
- *
- * @param rp Pointer to the target kretprobe.
- * @param rp_disarm Disarm flag.
- * @return Void.
- */
-void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm)
-{
-       swap_unregister_kretprobes_top(&rp, 1, rp_disarm);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_top);
-
-/**
- * @brief Kretprobe unregister bottom. Here is kretprobe memory is released.
- *
- * @param rp Pointer to the target kretprobe.
- * @return Void.
- */
-void swap_unregister_kretprobe_bottom(struct kretprobe *rp)
-{
-       unsigned long flags;
-       struct kretprobe_instance *ri;
-
-       spin_lock_irqsave(&kretprobe_lock, flags);
-
-       while ((ri = get_used_rp_inst(rp)) != NULL)
-               recycle_rp_inst(ri);
-       free_rp_inst(rp);
-
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_bottom);
-
-/**
- * @brief swap_unregister_kretprobe_bottom wrapper for several kretprobes.
- *
- * @param rps Pointer to the array of the target kretprobes pointers.
- * @param size Size of rps array.
- * @return Void.
- */
-void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size)
-{
-       const size_t end = ((size_t) 0) - 1;
-
-       for (--size; size != end; --size)
-               swap_unregister_kretprobe_bottom(rps[size]);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_bottom);
-
-/**
- * @brief Unregisters kretprobes.
- *
- * @param rpp Pointer to the array of the target kretprobes pointers.
- * @param size Size of rpp array.
- * @return Void.
- */
-void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size)
-{
-       swap_unregister_kretprobes_top(rpp, size, 1);
-
-       if (!in_atomic())
-               synchronize_sched();
-
-       swap_unregister_kretprobes_bottom(rpp, size);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobes);
-
-/**
- * @brief swap_unregister_kretprobes wrapper for a single kretprobe.
- *
- * @param rp Pointer to the target kretprobe.
- * @return Void.
- */
-void swap_unregister_kretprobe(struct kretprobe *rp)
-{
-       swap_unregister_kretprobes(&rp, 1);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobe);
-
-static inline void rm_task_trampoline(struct task_struct *p,
-                                     struct kretprobe_instance *ri)
-{
-       arch_set_task_pc(p, (unsigned long)ri->ret_addr);
-}
-
-static int swap_disarm_krp_inst(struct kretprobe_instance *ri)
-{
-       unsigned long *tramp = (unsigned long *)&swap_kretprobe_trampoline;
-       unsigned long *sp = ri->sp;
-       unsigned long *found = NULL;
-       int retval = -ENOENT;
-
-       if (!sp) {
-               unsigned long pc = arch_get_task_pc(ri->task);
-
-               printk(KERN_INFO "---> [%d] %s (%d/%d): pc = %08lx, ra = %08lx, tramp= %08lx (%08lx)\n",
-                      task_cpu(ri->task),
-                      ri->task->comm, ri->task->tgid, ri->task->pid,
-                      pc, (long unsigned int)ri->ret_addr,
-                      (long unsigned int)tramp,
-                      (ri->rp ? ri->rp->kp.addr : 0));
-
-               /* __switch_to retprobe handling */
-               if (pc == (unsigned long)tramp) {
-                       rm_task_trampoline(ri->task, ri);
-                       return 0;
-               }
-
-               return -EINVAL;
-       }
-
-       while (sp > ri->sp - KRETPROBE_STACK_DEPTH) {
-               if (*sp == (unsigned long)tramp) {
-                       found = sp;
-                       break;
-               }
-               sp--;
-       }
-
-       if (found) {
-               printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
-                      "found at %08lx (%08lx /%+ld) - %08lx\n",
-                      task_cpu(ri->task),
-                      ri->task->comm, ri->task->tgid, ri->task->pid,
-                      (long unsigned int)tramp,
-                      (long unsigned int)found, (long unsigned int)ri->sp,
-                      (unsigned long)(found - ri->sp), ri->rp ? ri->rp->kp.addr : 0);
-               *found = (unsigned long)ri->ret_addr;
-               retval = 0;
-       } else {
-               printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
-                      "NOT found at sp = %08lx - %08lx\n",
-                      task_cpu(ri->task),
-                      ri->task->comm, ri->task->tgid, ri->task->pid,
-                      (long unsigned int)tramp,
-                      (long unsigned int)ri->sp,
-                      ri->rp ? ri->rp->kp.addr : 0);
-       }
-
-       return retval;
-}
-
-static void krp_inst_flush(struct task_struct *task)
-{
-       unsigned long flags;
-       struct kretprobe_instance *ri;
-       struct hlist_node *tmp;
-       struct hlist_head *head;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       spin_lock_irqsave(&kretprobe_lock, flags);
-       head = kretprobe_inst_table_head(task);
-       swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
-               if (ri->task == task) {
-                       printk("task[%u %u %s]: flush krp_inst, ret_addr=%p\n",
-                               task->tgid, task->pid, task->comm,
-                               ri->ret_addr);
-                       recycle_rp_inst(ri);
-               }
-       }
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-}
-
-static void do_put_task_handler(struct task_struct *task)
-{
-       /* task has died */
-       krp_inst_flush(task);
-       swap_ktd_put_task(task);
-}
-
-#ifdef CONFIG_SWAP_HOOK_TASKDATA
-
-#include <swap/hook_taskdata.h>
-
-static struct hook_taskdata put_hook = {
-       .owner = THIS_MODULE,
-       .put_task = do_put_task_handler,
-};
-
-static int put_task_once(void)
-{
-       return 0;
-}
-
-static int put_task_init(void)
-{
-       return hook_taskdata_reg(&put_hook);
-}
-
-static void put_task_uninit(void)
-{
-       hook_taskdata_unreg(&put_hook);
-}
-
-#else /* CONFIG_SWAP_HOOK_TASKDATA */
-
-/* Handler is called the last because it is registered the first */
-static int put_task_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct task_struct *t = (struct task_struct *)swap_get_karg(regs, 0);
-
-       do_put_task_handler(t);
-
-       return 0;
-}
-
-static struct kprobe put_task_kp = {
-       .pre_handler = put_task_handler,
-};
-
-static int put_task_once(void)
-{
-       const char *sym = "__put_task_struct";
-
-       put_task_kp.addr = swap_ksyms(sym);
-       if (put_task_kp.addr == 0) {
-               pr_err("ERROR: symbol '%s' not found\n", sym);
-               return -ESRCH;
-       }
-
-       return 0;
-}
-
-static int put_task_init(void)
-{
-       return swap_register_kprobe(&put_task_kp);
-}
-
-static void put_task_uninit(void)
-{
-       swap_unregister_kprobe(&put_task_kp);
-}
-
-#endif /* CONFIG_SWAP_HOOK_TASKDATA */
-
-
-static int init_module_deps(void)
-{
-       int ret;
-
-       sched_addr = swap_ksyms("__switch_to");
-       exit_addr = swap_ksyms("do_exit");
-       sys_exit_group_addr = swap_ksyms("sys_exit_group");
-       do_group_exit_addr = swap_ksyms("do_group_exit");
-       sys_exit_addr = swap_ksyms("sys_exit");
-
-       if (sched_addr == 0 ||
-           exit_addr == 0 ||
-           sys_exit_group_addr == 0 ||
-           do_group_exit_addr == 0 ||
-           sys_exit_addr == 0) {
-               return -ESRCH;
-       }
-
-       ret = init_module_dependencies();
-       if (ret)
-               return ret;
-
-       return arch_init_module_deps();
-}
-
-static int once(void)
-{
-       int i, ret;
-       const char *sym;
-
-       ret = put_task_once();
-       if (ret)
-               return ret;
-
-       sym = "module_alloc";
-       __module_alloc = (void *)swap_ksyms(sym);
-       if (__module_alloc == NULL)
-               goto not_found;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
-       sym = "module_memfree";
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
-       sym = "module_free";
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
-       __module_free = (void *)swap_ksyms(sym);
-       if (__module_free == NULL)
-               goto not_found;
-
-       ret = init_module_deps();
-       if (ret)
-               return ret;
-
-       /*
-        * FIXME allocate the probe table, currently defined statically
-        * initialize all list heads
-        */
-       for (i = 0; i < KPROBE_TABLE_SIZE; ++i) {
-               INIT_HLIST_HEAD(&kprobe_table[i]);
-               INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
-       }
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-static int init_kprobes(void)
-{
-       int ret;
-
-       init_sm();
-       atomic_set(&kprobe_count, 0);
-
-       ret = swap_td_raw_init();
-       if (ret)
-               return ret;
-
-       ret = swap_arch_init_kprobes();
-       if (ret)
-               goto td_raw_uninit;
-
-       ret = swap_ktd_init();
-       if (ret)
-               goto arch_kp_exit;
-
-       ret = kprobe_cur_reg();
-       if (ret)
-               goto ktd_uninit;
-
-       ret = put_task_init();
-       if (ret)
-               goto cur_uninit;
-
-       return 0;
-
-cur_uninit:
-       kprobe_cur_unreg();
-ktd_uninit:
-       swap_ktd_uninit_top();
-       swap_ktd_uninit_bottom();
-arch_kp_exit:
-       swap_arch_exit_kprobes();
-td_raw_uninit:
-       swap_td_raw_uninit();
-       return ret;
-}
-
-static void exit_kprobes(void)
-{
-       swap_ktd_uninit_top();
-       put_task_uninit();
-       kprobe_cur_unreg();
-       swap_ktd_uninit_bottom();
-       swap_arch_exit_kprobes();
-       swap_td_raw_uninit();
-       exit_sm();
-}
-
-SWAP_LIGHT_INIT_MODULE(once, init_kprobes, exit_kprobes, NULL, NULL);
-
-MODULE_LICENSE("GPL");
diff --git a/kprobe/swap_kprobes.h b/kprobe/swap_kprobes.h
deleted file mode 100644 (file)
index 646a368..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/**
- * @file kprobe/swap_kprobes.h
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM and MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @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) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe interface definition.
- */
-
-
-#ifndef _SWAP_KPROBES_H
-#define _SWAP_KPROBES_H
-
-
-#include <linux/kconfig.h>
-
-#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
-# error "Kernel is immutable"
-#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
-
-
-#include <linux/version.h>     /*  LINUX_VERSION_CODE, KERNEL_VERSION() */
-#include <linux/notifier.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-#include <linux/pagemap.h>
-
-#include <swap-asm/swap_kprobes.h>
-
-
-/* kp_core_status settings */
-/** Kprobe hit active */
-#define KPROBE_HIT_ACTIVE      0x00000001
-/** Kprobe hit ss */
-#define KPROBE_HIT_SS          0x00000002
-/** Kprobe reenter */
-#define KPROBE_REENTER         0x00000004
-/** Kprobe hit ss done */
-#define KPROBE_HIT_SSDONE      0x00000008
-
-/** High word */
-#define HIWORD(x)               (((x) & 0xFFFF0000) >> 16)
-/** Low word */
-#define LOWORD(x)               ((x) & 0x0000FFFF)
-
-/** Invalid value */
-#define INVALID_VALUE           0xFFFFFFFF
-/** Invalid pointer */
-#define INVALID_POINTER         (void *)INVALID_VALUE
-
-/** Jprobe entry */
-#define JPROBE_ENTRY(pentry)    (kprobe_opcode_t *)pentry
-
-
-struct kprobe;
-struct pt_regs;
-struct kretprobe;
-struct kretprobe_instance;
-
-/**
- * @brief Kprobe pre-handler pointer.
- */
-typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
-
-/**
- * @brief Kprobe break handler pointer.
- */
-typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *);
-
-/**
- * @brief Kprobe post handler pointer.
- */
-typedef void (*kprobe_post_handler_t) (struct kprobe *,
-                                      struct pt_regs *,
-                                      unsigned long flags);
-
-/**
- * @brief Kprobe fault handler pointer.
- */
-typedef int (*kprobe_fault_handler_t) (struct kprobe *,
-                                      struct pt_regs *,
-                                      int trapnr);
-
-/**
- * @brief Kretprobe handler pointer.
- */
-typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
-                                   struct pt_regs *);
-
-struct kprobe;
-struct kp_core;
-
-struct kp_handlers {
-       int (*pre)(struct kp_core *, struct pt_regs *);
-
-       rwlock_t lock;
-       struct kprobe *kps[4];
-};
-
-struct kp_core {
-       struct hlist_node hlist;
-       atomic_t usage;
-
-       struct kp_handlers handlers;
-
-       unsigned long addr;
-       kprobe_opcode_t opcode;
-
-       struct swap_arch_specific_insn ainsn;
-};
-
-/**
- * @struct kprobe
- * @brief Main kprobe struct.
- */
-struct kprobe {
-       unsigned long addr;     /**< Location of the probe point. */
-       char *symbol_name;      /**< Symbol name of the probe point. */
-       unsigned long offset;   /**< Offset into the symbol.*/
-       /**< Called before addr is executed. */
-       kprobe_pre_handler_t pre_handler;
-};
-
-/**
- * @brief Kprobe pre-entry handler pointer.
- */
-typedef unsigned long (*kprobe_pre_entry_handler_t) (void *priv_arg,
-                                                    struct pt_regs *regs);
-
-
-/**
- * @struct jprobe
- * @brief Special probe type that uses setjmp-longjmp type tricks to resume
- * execution at a specified entry with a matching prototype corresponding
- * to the probed function - a trick to enable arguments to become
- * accessible seamlessly by probe handling logic.
- * Note:
- * Because of the way compilers allocate stack space for local variables
- * etc upfront, regardless of sub-scopes within a function, this mirroring
- * principle currently works only for probes placed on function entry points.
- */
-struct jprobe {
-       struct kprobe kp;                   /**< This probes kprobe.*/
-       kprobe_opcode_t *entry;             /**< Probe handling code to jump to.*/
-       /** Handler which will be called before 'entry'. */
-       kprobe_pre_entry_handler_t pre_entry;
-       void *priv_arg;                     /**< Private args.*/
-};
-
-
-/**
- * @struct jprobe_instance
- * @brief Jprobe instance struct.
- */
-struct jprobe_instance {
-       /*  either on free list or used list */
-       struct hlist_node uflist;            /**< Jprobes hash list. */
-       struct hlist_node hlist;             /**< Jprobes hash list. */
-       struct jprobe *jp;                   /**< Pointer to the target jprobe. */
-       /** Pointer to the target task_struct. */
-       struct task_struct *task;
-};
-
-
-
-
-
-/**
- * @struct kretprobe
- * @brief Function-return probe
- * Note: User needs to provide a handler function, and initialize maxactive.
- */
-struct kretprobe {
-       struct kprobe kp;                    /**< Kprobe of this kretprobe.*/
-       kretprobe_handler_t handler;         /**< Handler of this kretprobe.*/
-       kretprobe_handler_t entry_handler;   /**< Entry handler of this kretprobe.*/
-       /** The maximum number of instances of the probed function that can be
-        * active concurrently. */
-       int maxactive;
-       /** Tracks the number of times the probed function's return was ignored,
-        * due to maxactive being too low. */
-       int nmissed;
-       size_t data_size;                    /**< Size of the data. */
-       /** List of this probe's free_instances. */
-       struct hlist_head free_instances;
-       /** List of this probe's used_instances. */
-       struct hlist_head used_instances;
-
-#ifdef CONFIG_ARM
-       unsigned arm_noret:1;    /**< No-return flag for ARM.*/
-       unsigned thumb_noret:1;  /**< No-return flag for Thumb.*/
-#endif
-
-};
-
-/**
- * @struct kretprobe_instance
- * @brief Instance of kretprobe.
- */
-struct kretprobe_instance {
-       /*  either on free list or used list */
-       struct hlist_node uflist;       /**< Kretprobe hash list.*/
-       struct hlist_node hlist;        /**< Kretprobe hash list.*/
-       struct kretprobe *rp;           /**< Pointer to this instance's kretprobe.*/
-       unsigned long *ret_addr;        /**< Return address.*/
-       unsigned long *sp;              /**< Stack pointer.*/
-       struct task_struct *task;       /**< Pointer to the target task_struct.*/
-       char data[0];                   /**< Pointer to data.*/
-};
-
-
-/*
- * Large value for fast but memory consuming implementation
- * it is good when a lot of probes are instrumented
- */
-/* #define KPROBE_HASH_BITS 6 */
-#define KPROBE_HASH_BITS 16
-#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
-
-
-static void inline kp_core_get(struct kp_core *p)
-{
-       atomic_inc(&p->usage);
-}
-
-static void inline kp_core_put(struct kp_core *p)
-{
-       atomic_dec(&p->usage);
-}
-
-
-/* Get the kp_core at this addr (if any) - called with rcu_read_lock() */
-struct kp_core *kp_core_by_addr(unsigned long addr);
-
-int swap_register_kprobe(struct kprobe *p);
-void swap_unregister_kprobe(struct kprobe *p);
-
-int swap_register_jprobe(struct jprobe *p);
-void swap_unregister_jprobe(struct jprobe *p);
-void swap_jprobe_return(void);
-
-
-int swap_register_kretprobe(struct kretprobe *rp);
-void swap_unregister_kretprobe(struct kretprobe *rp);
-void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size);
-
-/*
- * use:
- *     swap_unregister_kretprobe[s]_top();
- *     synchronize_sched();
- *     swap_unregister_kretprobe[s]_bottom();
- *
- * rp_disarm - indicates the need for restoration of the return address
- */
-void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm);
-void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size,
-                                  int rp_disarm);
-void swap_unregister_kretprobe_bottom(struct kretprobe *rp);
-void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size);
-
-
-unsigned long swap_trampoline_handler(struct pt_regs *regs);
-
-
-extern atomic_t kprobe_count;
-extern unsigned long sched_addr;
-
-struct kp_core *kp_core_running(void);
-void kp_core_running_set(struct kp_core *p);
-struct kp_core_ctlblk *kp_core_ctlblk(void);
-
-
-struct kctx;
-
-/* for __switch_to support */
-#define SWITCH_TO_KP   0b0001
-#define SWITCH_TO_RP   0b0010
-#define SWITCH_TO_ALL  (SWITCH_TO_KP | SWITCH_TO_RP)
-
-#define current_kctx   kctx_by_task(current)
-struct kctx *kctx_by_task(struct task_struct *task);
-
-void switch_to_bits_set(struct kctx *ctx, unsigned long mask);
-void switch_to_bits_reset(struct kctx *ctx, unsigned long mask);
-unsigned long switch_to_bits_get(struct kctx *ctx, unsigned long mask);
-
-
-#ifndef swap_in_interrupt
-#define swap_in_interrupt()    in_interrupt()
-#endif /* swap_in_interrupt */
-
-static inline int able2resched(struct kctx *ctx)
-{
-       if (swap_in_interrupt() || switch_to_bits_get(ctx, SWITCH_TO_ALL))
-               return 0;
-
-       return 1;
-}
-
-
-#endif /* _SWAP_KPROBES_H */
-
diff --git a/kprobe/swap_kprobes_deps.c b/kprobe/swap_kprobes_deps.c
deleted file mode 100644 (file)
index 9a54bb8..0000000
+++ /dev/null
@@ -1,1471 +0,0 @@
-/**
- * kprobe/swap_kprobes_deps.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe kernel-dependent dependencies.
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-
-#include <asm/pgtable.h>
-
-#include "swap_kprobes_deps.h"
-#include "swap_kdebug.h"
-
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
-/* kernel define 'pgd_offset_k' redefinition */
-#undef pgd_offset_k
-#define pgd_offset_k(addr)     pgd_offset(init_task.active_mm, addr)
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
-#ifndef is_zero_pfn
-
-static unsigned long swap_zero_pfn ;
-
-#endif /* is_zero_pfn */
-#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
-static inline void *swap_kmap_atomic(struct page *page)
-{
-       return kmap_atomic(page);
-}
-static inline void swap_kunmap_atomic(void *kvaddr)
-{
-       kunmap_atomic(kvaddr);
-}
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36) */
-static inline void *swap_kmap_atomic(struct page *page)
-{
-       return kmap_atomic(page, KM_USER0);
-}
-
-static inline void swap_kunmap_atomic(void *kvaddr)
-{
-       kunmap_atomic(kvaddr, KM_USER0);
-}
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36) */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
-DECLARE_MOD_FUNC_DEP(do_mmap, unsigned long, struct file *file,
-                    unsigned long addr, unsigned long len, unsigned long prot,
-                    unsigned long flags, vm_flags_t vm_flags,
-                    unsigned long pgoff, unsigned long *populate);
-DECLARE_MOD_DEP_WRAPPER(swap_do_mmap,
-                       unsigned long,
-                       struct file *file, unsigned long addr,
-                       unsigned long len, unsigned long prot,
-                       unsigned long flags, vm_flags_t vm_flags,
-                       unsigned long pgoff, unsigned long *populate)
-IMP_MOD_DEP_WRAPPER(do_mmap, file, addr, len,
-                   prot, flags, vm_flags, pgoff, populate)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-DECLARE_MOD_FUNC_DEP(do_mmap_pgoff, unsigned long, struct file *file,
-                    unsigned long addr, unsigned long len, unsigned long prot,
-                    unsigned long flags, unsigned long pgoff,
-                    unsigned long *populate);
-DECLARE_MOD_DEP_WRAPPER(swap_do_mmap_pgoff,
-                       unsigned long,
-                       struct file *file, unsigned long addr,
-                       unsigned long len, unsigned long prot,
-                       unsigned long flags, unsigned long pgoff,
-                       unsigned long *populate)
-IMP_MOD_DEP_WRAPPER(do_mmap_pgoff, file, addr, len,
-                   prot, flags, pgoff, populate)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-DECLARE_MOD_FUNC_DEP(do_mmap_pgoff, unsigned long, struct file *file,
-                    unsigned long addr, unsigned long len, unsigned long prot,
-                    unsigned long flags, unsigned long pgoff);
-DECLARE_MOD_DEP_WRAPPER(swap_do_mmap_pgoff,
-                       unsigned long,
-                       struct file *file, unsigned long addr,
-                       unsigned long len, unsigned long prot,
-                       unsigned long flags, unsigned long pgoff)
-IMP_MOD_DEP_WRAPPER(do_mmap_pgoff, file, addr, len, prot, flags, pgoff)
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
-EXPORT_SYMBOL_GPL(swap_do_mmap);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-EXPORT_SYMBOL_GPL(swap_do_mmap_pgoff);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
-
-/* copy_to_user_page */
-#ifndef copy_to_user_page
-static DECLARE_MOD_FUNC_DEP(copy_to_user_page, void, struct vm_area_struct *vma,
-                           struct page *page, unsigned long uaddr, void *dst,
-                           const void *src, unsigned long len);
-DECLARE_MOD_DEP_WRAPPER(swap_copy_to_user_page,
-                       void,
-                       struct vm_area_struct *vma, struct page *page,
-                       unsigned long uaddr, void *dst, const void *src,
-                       unsigned long len)
-IMP_MOD_DEP_WRAPPER(copy_to_user_page, vma, page, uaddr, dst, src, len)
-#else /* copy_to_user_page */
-#define swap_copy_to_user_page copy_to_user_page
-#endif /* copy_to_user_page */
-
-
-static DECLARE_MOD_FUNC_DEP(find_extend_vma, struct vm_area_struct *,
-                           struct mm_struct *mm, unsigned long addr);
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
-static DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm,
-                           struct vm_area_struct *vma, unsigned long address,
-                           int write_access);
-#endif
-#else
-static DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm,
-                           struct vm_area_struct *vma, unsigned long address,
-                           unsigned int flags);
-#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
-
-#ifdef __HAVE_ARCH_GATE_AREA
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-static DECLARE_MOD_FUNC_DEP(get_gate_vma, struct vm_area_struct *,
-                           struct mm_struct *mm);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-static DECLARE_MOD_FUNC_DEP(get_gate_vma, struct vm_area_struct *,
-                           struct task_struct *tsk);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-DECLARE_MOD_FUNC_DEP(in_gate_area, int, struct mm_struct *mm,
-                    unsigned long addr);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-DECLARE_MOD_FUNC_DEP(in_gate_area, int, struct task_struct *task,
-                    unsigned long addr);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-static DECLARE_MOD_FUNC_DEP(in_gate_area_no_mm, int, unsigned long addr);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-static DECLARE_MOD_FUNC_DEP(in_gate_area_no_task, int, unsigned long addr);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#endif /* __HAVE_ARCH_GATE_AREA */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-static DECLARE_MOD_FUNC_DEP(follow_page_mask, \
-               struct page *, struct vm_area_struct *vma, \
-               unsigned long address, unsigned int foll_flags, \
-               unsigned int *page_mask);
-DECLARE_MOD_DEP_WRAPPER(swap_follow_page_mask,
-                       struct page *,
-                       struct vm_area_struct *vma, unsigned long address,
-                       unsigned int foll_flags, unsigned int *page_mask)
-IMP_MOD_DEP_WRAPPER(follow_page_mask, vma, address, foll_flags, page_mask)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-static DECLARE_MOD_FUNC_DEP(follow_page, \
-               struct page *, struct vm_area_struct *vma, \
-               unsigned long address, unsigned int foll_flags);
-DECLARE_MOD_DEP_WRAPPER(swap_follow_page,
-                       struct page *,
-                       struct vm_area_struct *vma, unsigned long address,
-                       unsigned int foll_flags)
-IMP_MOD_DEP_WRAPPER(follow_page, vma, address, foll_flags)
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-
-static DECLARE_MOD_FUNC_DEP(__flush_anon_page, \
-               void, struct vm_area_struct *vma, struct page *page, \
-               unsigned long vmaddr);
-static DECLARE_MOD_FUNC_DEP(vm_normal_page, \
-               struct page *, struct vm_area_struct *vma, \
-               unsigned long addr, pte_t pte);
-
-
-#if (LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 16))
-static DECLARE_MOD_FUNC_DEP(put_task_struct, \
-               void, struct task_struct *tsk);
-#else
-static DECLARE_MOD_FUNC_DEP(put_task_struct, \
-               void, struct rcu_head *rhp);
-#endif
-
-DECLARE_MOD_DEP_WRAPPER(swap_find_extend_vma,
-                       struct vm_area_struct *,
-                       struct mm_struct *mm, unsigned long addr)
-IMP_MOD_DEP_WRAPPER(find_extend_vma, mm, addr)
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
-DECLARE_MOD_DEP_WRAPPER(swap_handle_mm_fault,
-                       int,
-                       struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, int write_access)
-{
-       if (in_atomic())
-               return VM_FAULT_ERROR | VM_FAULT_OOM;
-
-       IMP_MOD_DEP_WRAPPER(handle_mm_fault, mm, vma, address, write_access)
-}
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) */
-#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
-DECLARE_MOD_DEP_WRAPPER(swap_handle_mm_fault,
-                       int,
-                       struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, unsigned int flags)
-{
-       if (in_atomic())
-               return VM_FAULT_ERROR | VM_FAULT_OOM;
-
-       IMP_MOD_DEP_WRAPPER(handle_mm_fault, mm, vma, address, flags)
-}
-#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
-
-struct vm_area_struct *swap_get_gate_vma(struct mm_struct *mm)
-{
-#ifdef __HAVE_ARCH_GATE_AREA
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-IMP_MOD_DEP_WRAPPER(get_gate_vma, mm)
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-IMP_MOD_DEP_WRAPPER(get_gate_vma, tsk)
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#else /* __HAVE_ARCH_GATE_AREA */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-       return get_gate_vma(mm);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-       return get_gate_vma(tsk);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#endif /* __HAVE_ARCH_GATE_AREA */
-}
-
-#ifdef CONFIG_HUGETLB_PAGE
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
-DECLARE_MOD_FUNC_DEP(follow_hugetlb_page,                              \
-                    int,                                               \
-                    struct mm_struct *mm, struct vm_area_struct *vma,  \
-                    struct page **pages, struct vm_area_struct **vmas, \
-                    unsigned long *position, int *length, int i,       \
-                    unsigned int flags);
-DECLARE_MOD_DEP_WRAPPER(swap_follow_hugetlb_page,
-                       int,
-                       struct mm_struct *mm, struct vm_area_struct *vma,
-                       struct page **pages, struct vm_area_struct **vmas,
-                       unsigned long *position, int *length, int i,
-                       unsigned int flags)
-IMP_MOD_DEP_WRAPPER(follow_hugetlb_page,                               \
-                   mm, vma, pages, vmas, position, length, i, flags)
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) */
-DECLARE_MOD_FUNC_DEP(follow_hugetlb_page,                              \
-                    long,                                              \
-                    struct mm_struct *mm, struct vm_area_struct *vma,  \
-                    struct page **pages, struct vm_area_struct **vmas, \
-                    unsigned long *position, unsigned long *nr_pages,  \
-                    long i, unsigned int flags);
-DECLARE_MOD_DEP_WRAPPER(swap_follow_hugetlb_page,
-                       long,
-                       struct mm_struct *mm, struct vm_area_struct *vma,
-                       struct page **pages, struct vm_area_struct **vmas,
-                       unsigned long *position, unsigned long *nr_pages,
-                       long i, unsigned int flags)
-IMP_MOD_DEP_WRAPPER(follow_hugetlb_page,                               \
-                   mm, vma, pages, vmas, position, nr_pages, i, flags)
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) */
-
-#else /* CONFIG_HUGETLB_PAGE */
-#define swap_follow_hugetlb_page follow_hugetlb_page
-#endif /* CONFIG_HUGETLB_PAGE */
-
-static inline int swap_in_gate_area(struct task_struct *task,
-                                   unsigned long addr)
-{
-#ifdef __HAVE_ARCH_GATE_AREA
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-       struct mm_struct *mm;
-
-       if (task == NULL)
-               return 0;
-
-       mm = task->mm;
-       IMP_MOD_DEP_WRAPPER(in_gate_area, mm, addr)
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-       IMP_MOD_DEP_WRAPPER(in_gate_area, task, addr)
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#else /*__HAVE_ARCH_GATE_AREA */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-       struct mm_struct *mm;
-
-       if (task == NULL)
-               return 0;
-
-       mm = task->mm;
-       return in_gate_area(mm, addr);
-#else
-       return in_gate_area(task, addr);
-#endif
-#endif/*__HAVE_ARCH_GATE_AREA */
-}
-
-
-#ifdef __HAVE_ARCH_GATE_AREA
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-DECLARE_MOD_DEP_WRAPPER(swap_in_gate_area_no_mm, int, unsigned long addr)
-IMP_MOD_DEP_WRAPPER(in_gate_area_no_mm, addr)
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-DECLARE_MOD_DEP_WRAPPER(swap_in_gate_area_no_task, int, unsigned long addr)
-IMP_MOD_DEP_WRAPPER(in_gate_area_no_task, addr)
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#endif /* __HAVE_ARCH_GATE_AREA */
-
-static inline int swap_in_gate_area_no_xxx(unsigned long addr)
-{
-#ifdef __HAVE_ARCH_GATE_AREA
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-       return swap_in_gate_area_no_mm(addr);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-       return swap_in_gate_area_no_task(addr);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#else /* __HAVE_ARCH_GATE_AREA */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-       return in_gate_area_no_mm(addr);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-       return in_gate_area_no_task(addr);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#endif /* __HAVE_ARCH_GATE_AREA */
-}
-
-DECLARE_MOD_DEP_WRAPPER(swap__flush_anon_page,
-                       void,
-                       struct vm_area_struct *vma, struct page *page,
-                       unsigned long vmaddr)
-IMP_MOD_DEP_WRAPPER(__flush_anon_page, vma, page, vmaddr)
-
-static inline void swap_flush_anon_page(struct vm_area_struct *vma,
-                                       struct page *page,
-                                       unsigned long vmaddr)
-{
-#if defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM)
-       if (PageAnon(page))
-               swap__flush_anon_page(vma, page, vmaddr);
-#else /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
-       flush_anon_page(vma, page, vmaddr);
-#endif /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
-}
-
-DECLARE_MOD_DEP_WRAPPER(swap_vm_normal_page,
-                       struct page *,
-                       struct vm_area_struct *vma, unsigned long addr,
-                       pte_t pte)
-IMP_MOD_DEP_WRAPPER(vm_normal_page, vma, addr, pte)
-
-
-
-/**
- * @brief Initializes module dependencies.
- *
- * @return 0.
- */
-int init_module_dependencies(void)
-{
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
-       INIT_MOD_DEP_VAR(handle_mm_fault, handle_mm_fault);
-#endif
-
-#ifndef copy_to_user_page
-       INIT_MOD_DEP_VAR(copy_to_user_page, copy_to_user_page);
-#endif /* copy_to_user_page */
-
-       INIT_MOD_DEP_VAR(find_extend_vma, find_extend_vma);
-
-#ifdef CONFIG_HUGETLB_PAGE
-       INIT_MOD_DEP_VAR(follow_hugetlb_page, follow_hugetlb_page);
-#endif
-
-#ifdef __HAVE_ARCH_GATE_AREA
-       INIT_MOD_DEP_VAR(in_gate_area, in_gate_area);
-       INIT_MOD_DEP_VAR(get_gate_vma, get_gate_vma);
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-       INIT_MOD_DEP_VAR(in_gate_area_no_mm, in_gate_area_no_mm);
-#else /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))  */
-       INIT_MOD_DEP_VAR(in_gate_area_no_task, in_gate_area_no_task);
-#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))  */
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-       INIT_MOD_DEP_VAR(follow_page_mask, follow_page_mask);
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-       INIT_MOD_DEP_VAR(follow_page, follow_page);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-
-#ifndef is_zero_pfn
-       swap_zero_pfn = page_to_pfn(ZERO_PAGE(0));
-#endif /* is_zero_pfn */
-#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))  */
-
-#if defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM)
-       INIT_MOD_DEP_VAR(__flush_anon_page, __flush_anon_page);
-#endif /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
-
-       INIT_MOD_DEP_VAR(vm_normal_page, vm_normal_page);
-
-#if (LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 16))
-# if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11))
-       INIT_MOD_DEP_VAR(put_task_struct, put_task_struct);
-# else
-       INIT_MOD_DEP_VAR(put_task_struct, __put_task_struct);
-# endif
-#else /*2.6.16 */
-       INIT_MOD_DEP_VAR(put_task_struct, __put_task_struct_cb);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
-       INIT_MOD_DEP_VAR(do_mmap, do_mmap);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-       INIT_MOD_DEP_VAR(do_mmap_pgoff, do_mmap_pgoff);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
-
-       return 0;
-}
-
-
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-
-static int do_access_process_vm(struct task_struct *tsk, struct mm_struct *mm,
-                               unsigned long addr, void *buf, int len,
-                               int write)
-{
-       struct vm_area_struct *vma;
-       void *old_buf = buf;
-
-       while (len) {
-               int bytes, ret, offset;
-               void *maddr;
-               struct page *page = NULL;
-
-# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
-               ret = get_user_pages(tsk, mm, addr, 1, write, 1, &page, &vma);
-# else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */
-               ret = get_user_pages_remote(tsk, mm, addr, 1,
-                                           FOLL_WRITE | FOLL_FORCE,
-                                           &page, &vma);
-# endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */
-
-               if (ret <= 0) {
-#ifndef CONFIG_HAVE_IOREMAP_PROT
-                       break;
-#else
-                       /*
-                        * Check if this is a VM_IO | VM_PFNMAP VMA, which
-                        * we can access using slightly different code.
-                        */
-                       vma = find_vma(mm, addr);
-                       if (!vma || vma->vm_start > addr)
-                               break;
-                       if (vma->vm_ops && vma->vm_ops->access)
-                               ret = vma->vm_ops->access(vma, addr, buf, len,
-                                                         write);
-                       if (ret <= 0)
-                               break;
-                       bytes = ret;
-#endif
-               } else {
-                       bytes = len;
-                       offset = addr & (PAGE_SIZE-1);
-                       if (bytes > PAGE_SIZE-offset)
-                               bytes = PAGE_SIZE-offset;
-
-                       maddr = kmap(page);
-                       if (write) {
-                               swap_copy_to_user_page(vma, page, addr,
-                                                      maddr + offset,
-                                                      buf, bytes);
-                               set_page_dirty_lock(page);
-                       } else {
-                               copy_from_user_page(vma, page, addr,
-                                                   buf, maddr + offset, bytes);
-                       }
-                       kunmap(page);
-                       put_page(page);
-               }
-               len -= bytes;
-               buf += bytes;
-               addr += bytes;
-       }
-
-       return buf - old_buf;
-}
-
-int swap_access_process_vm(struct task_struct *tsk, unsigned long addr,
-                          void *buf, int len, int write)
-{
-       int ret;
-       struct mm_struct *mm;
-
-       mm = get_task_mm(tsk);
-       if (!mm)
-               return 0;
-
-       ret = do_access_process_vm(tsk, mm, addr, buf, len, write);
-       mmput(mm);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_access_process_vm);
-
-#else /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38) /* FIXME: must be < 32 */
-#define GUP_FLAGS_WRITE                  0x1
-#define GUP_FLAGS_FORCE                  0x2
-#define GUP_FLAGS_IGNORE_VMA_PERMISSIONS 0x4
-#define GUP_FLAGS_IGNORE_SIGKILL         0x8
-#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
-static inline int use_zero_page(struct vm_area_struct *vma)
-{
-       /*
-        * We don't want to optimize FOLL_ANON for make_pages_present()
-        * when it tries to page in a VM_LOCKED region. As to VM_SHARED,
-        * we want to get the page from the page tables to make sure
-        * that we serialize and update with any other user of that
-        * mapping.
-        */
-       if (vma->vm_flags & (VM_LOCKED | VM_SHARED))
-               return 0;
-       /*
-        * And if we have a fault routine, it's not an anonymous region.
-        */
-       return !vma->vm_ops || !vma->vm_ops->fault;
-}
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
-
-#ifdef __HAVE_COLOR_ZERO_PAGE
-
-static inline int swap_is_zero_pfn(unsigned long pfn)
-{
-       unsigned long offset_from_zero_pfn = pfn - swap_zero_pfn;
-       return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
-}
-
-#else /* __HAVE_COLOR_ZERO_PAGE */
-
-static inline int swap_is_zero_pfn(unsigned long pfn)
-{
-       return pfn == swap_zero_pfn;
-}
-#endif /* __HAVE_COLOR_ZERO_PAGE */
-
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */
-
-static inline int swap_is_zero_pfn(unsigned long pfn)
-{
-#ifndef is_zero_pfn
-       return pfn == swap_zero_pfn;
-#else /* is_zero_pfn */
-       return is_zero_pfn(pfn);
-#endif /* is_zero_pfn */
-}
-
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */
-
-static inline int stack_guard_page(struct vm_area_struct *vma,
-                                  unsigned long addr)
-{
-       return stack_guard_page_start(vma, addr) ||
-                       stack_guard_page_end(vma, addr+PAGE_SIZE);
-}
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-
-/**
- * @brief Gets user pages uprobe.
- *
- * @param tsk Pointer to the task_struct.
- * @param mm Pointer to the mm_struct.
- * @param start Starting address.
- * @param nr_pages Pages number.
- * @param gup_flags Flags.
- * @param pages Pointer to the array of pointers to the target page structs.
- * @param vmas Pointer to the array of pointers to the target vm_area_struct.
- * @param nonblocking Pointer to int.
- * @return negative error code on error, positive result otherwise.
- */
-long __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long start, unsigned long nr_pages,
-               unsigned int gup_flags, struct page **pages,
-               struct vm_area_struct **vmas, int *nonblocking)
-{
-       long i;
-       unsigned long vm_flags;
-       unsigned int page_mask;
-
-       if (!nr_pages)
-               return 0;
-
-       VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
-
-       /*
-        * Require read or write permissions.
-        * If FOLL_FORCE is set, we only require the "MAY" flags.
-        */
-       vm_flags  = (gup_flags & FOLL_WRITE) ?
-                       (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
-       vm_flags &= (gup_flags & FOLL_FORCE) ?
-                       (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
-
-       /*
-        * If FOLL_FORCE and FOLL_NUMA are both set, handle_mm_fault
-        * would be called on PROT_NONE ranges. We must never invoke
-        * handle_mm_fault on PROT_NONE ranges or the NUMA hinting
-        * page faults would unprotect the PROT_NONE ranges if
-        * _PAGE_NUMA and _PAGE_PROTNONE are sharing the same pte/pmd
-        * bitflag. So to avoid that, don't set FOLL_NUMA if
-        * FOLL_FORCE is set.
-        */
-       if (!(gup_flags & FOLL_FORCE))
-               gup_flags |= FOLL_NUMA;
-
-       i = 0;
-
-       do {
-               struct vm_area_struct *vma;
-
-               vma = swap_find_extend_vma(mm, start);
-               if (!vma && swap_in_gate_area(tsk, start)) {
-                       unsigned long pg = start & PAGE_MASK;
-                       pgd_t *pgd;
-                       pud_t *pud;
-                       pmd_t *pmd;
-                       pte_t *pte;
-
-                       /* user gate pages are read-only */
-                       if (gup_flags & FOLL_WRITE)
-                               return i ? : -EFAULT;
-                       if (pg > TASK_SIZE)
-                               pgd = pgd_offset_k(pg);
-                       else
-                               pgd = pgd_offset_gate(mm, pg);
-                       BUG_ON(pgd_none(*pgd));
-                       pud = pud_offset(pgd, pg);
-                       BUG_ON(pud_none(*pud));
-                       pmd = pmd_offset(pud, pg);
-                       if (pmd_none(*pmd))
-                               return i ? : -EFAULT;
-                       VM_BUG_ON(pmd_trans_huge(*pmd));
-                       pte = pte_offset_map(pmd, pg);
-                       if (pte_none(*pte)) {
-                               pte_unmap(pte);
-                               return i ? : -EFAULT;
-                       }
-                       vma = swap_get_gate_vma(mm);
-                       if (pages) {
-                               struct page *page;
-
-                               page = swap_vm_normal_page(vma, start, *pte);
-                               if (!page) {
-                                       if (!(gup_flags & FOLL_DUMP) &&
-                                            swap_is_zero_pfn(pte_pfn(*pte)))
-                                               page = pte_page(*pte);
-                                       else {
-                                               pte_unmap(pte);
-                                               return i ? : -EFAULT;
-                                       }
-                               }
-                               pages[i] = page;
-                               get_page(page);
-                       }
-                       pte_unmap(pte);
-                       page_mask = 0;
-                       goto next_page;
-               }
-
-               if (!vma ||
-                   (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
-                   !(vm_flags & vma->vm_flags))
-                       return i ? : -EFAULT;
-
-               if (is_vm_hugetlb_page(vma)) {
-                       i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
-                                       &start, &nr_pages, i, gup_flags);
-                       continue;
-               }
-
-               do {
-                       struct page *page;
-                       unsigned int foll_flags = gup_flags;
-                       unsigned int page_increm;
-
-                       /*
-                        * If we have a pending SIGKILL, don't keep faulting
-                        * pages and potentially allocating memory.
-                        */
-                       if (unlikely(fatal_signal_pending(current)))
-                               return i ? i : -ERESTARTSYS;
-
-                       /* cond_resched(); */
-                       while (!(page = swap_follow_page_mask(vma, start,
-                                               foll_flags, &page_mask))) {
-                               int ret;
-                               unsigned int fault_flags = 0;
-
-                               /* For mlock, just skip the stack guard page. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
-                               if (foll_flags & FOLL_POPULATE) {
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
-                               if (foll_flags & FOLL_MLOCK) {
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
-                                       if (stack_guard_page(vma, start))
-                                               goto next_page;
-                               }
-                               if (foll_flags & FOLL_WRITE)
-                                       fault_flags |= FAULT_FLAG_WRITE;
-                               if (nonblocking)
-                                       fault_flags |= FAULT_FLAG_ALLOW_RETRY;
-                               if (foll_flags & FOLL_NOWAIT)
-                                       fault_flags |=
-                                               (FAULT_FLAG_ALLOW_RETRY |
-                                                FAULT_FLAG_RETRY_NOWAIT);
-
-                               ret = swap_handle_mm_fault(mm, vma, start,
-                                                       fault_flags);
-
-                               if (ret & VM_FAULT_ERROR) {
-                                       if (ret & VM_FAULT_OOM)
-                                               return i ? i : -ENOMEM;
-                                       if (ret & (VM_FAULT_HWPOISON |
-                                                  VM_FAULT_HWPOISON_LARGE)) {
-                                               if (i)
-                                                       return i;
-                                               else if (gup_flags &
-                                                        FOLL_HWPOISON)
-                                                       return -EHWPOISON;
-                                               else
-                                                       return -EFAULT;
-                                       }
-                                       if (ret & VM_FAULT_SIGBUS)
-                                               return i ? i : -EFAULT;
-                                       BUG();
-                               }
-
-                               if (tsk) {
-                                       if (ret & VM_FAULT_MAJOR)
-                                               tsk->maj_flt++;
-                                       else
-                                               tsk->min_flt++;
-                               }
-
-                               if (ret & VM_FAULT_RETRY) {
-                                       if (nonblocking)
-                                               *nonblocking = 0;
-                                       return i;
-                               }
-
-                               /*
-                                * The VM_FAULT_WRITE bit tells us that
-                                * do_wp_page has broken COW when necessary,
-                                * even if maybe_mkwrite decided not to set
-                                * pte_write. We can thus safely do subsequent
-                                * page lookups as if they were reads. But only
-                                * do so when looping for pte_write is futile:
-                                * in some cases userspace may also be wanting
-                                * to write to the gotten user page, which a
-                                * read fault here might prevent (a readonly
-                                * page might get reCOWed by userspace write).
-                                */
-                               if ((ret & VM_FAULT_WRITE) &&
-                                   !(vma->vm_flags & VM_WRITE))
-                                       foll_flags &= ~FOLL_WRITE;
-
-                               /* cond_resched(); */
-                       }
-                       if (IS_ERR(page))
-                               return i ? i : PTR_ERR(page);
-                       if (pages) {
-                               pages[i] = page;
-
-                               swap_flush_anon_page(vma, page, start);
-                               flush_dcache_page(page);
-                               page_mask = 0;
-                       }
-next_page:
-                       if (vmas) {
-                               vmas[i] = vma;
-                               page_mask = 0;
-                       }
-                       page_increm = 1 + (~(start >> PAGE_SHIFT) & page_mask);
-                       if (page_increm > nr_pages)
-                               page_increm = nr_pages;
-                       i += page_increm;
-                       start += page_increm * PAGE_SIZE;
-                       nr_pages -= page_increm;
-               } while (nr_pages && start < vma->vm_end);
-       } while (nr_pages);
-       return i;
-}
-
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-
-static int __get_user_pages_uprobe(struct task_struct *tsk,
-                                  struct mm_struct *mm, unsigned long start,
-                                  int nr_pages, unsigned int gup_flags,
-                                  struct page **pages,
-                                  struct vm_area_struct **vmas,
-                                  int *nonblocking)
-{
-       int i;
-       unsigned long vm_flags;
-
-       if (nr_pages <= 0)
-               return 0;
-
-       VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
-
-       /*
-        * Require read or write permissions.
-        * If FOLL_FORCE is set, we only require the "MAY" flags.
-        */
-       vm_flags  = (gup_flags & FOLL_WRITE) ?
-                       (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
-       vm_flags &= (gup_flags & FOLL_FORCE) ?
-                       (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
-       i = 0;
-
-       do {
-               struct vm_area_struct *vma;
-
-               vma = swap_find_extend_vma(mm, start);
-               if (!vma && swap_in_gate_area_no_xxx(start)) {
-                       unsigned long pg = start & PAGE_MASK;
-                       pgd_t *pgd;
-                       pud_t *pud;
-                       pmd_t *pmd;
-                       pte_t *pte;
-
-                       /* user gate pages are read-only */
-                       if (gup_flags & FOLL_WRITE)
-                               return i ? : -EFAULT;
-                       if (pg > TASK_SIZE)
-                               pgd = pgd_offset_k(pg);
-                       else
-                               pgd = pgd_offset_gate(mm, pg);
-                       BUG_ON(pgd_none(*pgd));
-                       pud = pud_offset(pgd, pg);
-                       BUG_ON(pud_none(*pud));
-                       pmd = pmd_offset(pud, pg);
-                       if (pmd_none(*pmd))
-                               return i ? : -EFAULT;
-                       VM_BUG_ON(pmd_trans_huge(*pmd));
-                       pte = pte_offset_map(pmd, pg);
-                       if (pte_none(*pte)) {
-                               pte_unmap(pte);
-                               return i ? : -EFAULT;
-                       }
-                       vma = swap_get_gate_vma(mm);
-                       if (pages) {
-                               struct page *page;
-
-                               page = swap_vm_normal_page(vma, start, *pte);
-                               if (!page) {
-                                       if (!(gup_flags & FOLL_DUMP) &&
-                                               swap_is_zero_pfn(pte_pfn(*pte)))
-                                               page = pte_page(*pte);
-                                       else {
-                                               pte_unmap(pte);
-                                               return i ? : -EFAULT;
-                                       }
-                               }
-                               pages[i] = page;
-                               get_page(page);
-                       }
-                       pte_unmap(pte);
-                       goto next_page;
-               }
-
-               if (!vma ||
-                       (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
-                       !(vm_flags & vma->vm_flags)) {
-                       return i ? : -EFAULT;
-               }
-
-               if (is_vm_hugetlb_page(vma)) {
-                       i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
-                                       &start, &nr_pages, i, gup_flags);
-                       continue;
-               }
-
-               do {
-                       struct page *page;
-                       unsigned int foll_flags = gup_flags;
-
-                       /*
-                        * If we have a pending SIGKILL, don't keep faulting
-                        * pages and potentially allocating memory.
-                        */
-                       if (unlikely(fatal_signal_pending(current)))
-                               return i ? i : -ERESTARTSYS;
-
-                       /* cond_resched(); */
-                       while (!(page = swap_follow_page(vma, start,
-                                                        foll_flags))) {
-                               int ret;
-                               unsigned int fault_flags = 0;
-
-                               /* For mlock, just skip the stack guard page. */
-                               if (foll_flags & FOLL_MLOCK) {
-                                       if (stack_guard_page(vma, start))
-                                               goto next_page;
-                               }
-                               if (foll_flags & FOLL_WRITE)
-                                       fault_flags |= FAULT_FLAG_WRITE;
-                               if (nonblocking)
-                                       fault_flags |= FAULT_FLAG_ALLOW_RETRY;
-                               if (foll_flags & FOLL_NOWAIT)
-                                       fault_flags |=
-                                               (FAULT_FLAG_ALLOW_RETRY |
-                                               FAULT_FLAG_RETRY_NOWAIT);
-
-                               ret = swap_handle_mm_fault(mm, vma, start,
-                                                       fault_flags);
-
-                               if (ret & VM_FAULT_ERROR) {
-                                       if (ret & VM_FAULT_OOM)
-                                               return i ? i : -ENOMEM;
-                                       if (ret & (VM_FAULT_HWPOISON |
-                                                  VM_FAULT_HWPOISON_LARGE)) {
-                                               if (i)
-                                                       return i;
-                                               else if (gup_flags &
-                                                        FOLL_HWPOISON)
-                                                       return -EHWPOISON;
-                                               else
-                                                       return -EFAULT;
-                                       }
-                                       if (ret & VM_FAULT_SIGBUS)
-                                               return i ? i : -EFAULT;
-                                       BUG();
-                               }
-
-                               if (tsk) {
-                                       if (ret & VM_FAULT_MAJOR)
-                                               tsk->maj_flt++;
-                                       else
-                                               tsk->min_flt++;
-                               }
-
-                               if (ret & VM_FAULT_RETRY) {
-                                       if (nonblocking)
-                                               *nonblocking = 0;
-                                       return i;
-                               }
-
-                               /*
-                                * The VM_FAULT_WRITE bit tells us that
-                                * do_wp_page has broken COW when necessary,
-                                * even if maybe_mkwrite decided not to set
-                                * pte_write. We can thus safely do subsequent
-                                * page lookups as if they were reads. But only
-                                * do so when looping for pte_write is futile:
-                                * in some cases userspace may also be wanting
-                                * to write to the gotten user page, which a
-                                * read fault here might prevent (a readonly
-                                * page might get reCOWed by userspace write).
-                                */
-                               if ((ret & VM_FAULT_WRITE) &&
-                                       !(vma->vm_flags & VM_WRITE))
-                                       foll_flags &= ~FOLL_WRITE;
-
-                               /* cond_resched(); */
-                       }
-                       if (IS_ERR(page))
-                               return i ? i : PTR_ERR(page);
-                       if (pages) {
-                               pages[i] = page;
-
-                               swap_flush_anon_page(vma, page, start);
-                               flush_dcache_page(page);
-                       }
-next_page:
-                       if (vmas)
-                               vmas[i] = vma;
-                       i++;
-                       start += PAGE_SIZE;
-                       nr_pages--;
-               } while (nr_pages && start < vma->vm_end);
-       } while (nr_pages);
-
-       return i;
-}
-
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-
-static int __get_user_pages_uprobe(struct task_struct *tsk,
-                                  struct mm_struct *mm,
-                                  unsigned long start, int len, int flags,
-                                  struct page **pages,
-                                  struct vm_area_struct **vmas)
-{
-       int i;
-       unsigned int vm_flags = 0;
-       int write = !!(flags & GUP_FLAGS_WRITE);
-       int force = !!(flags & GUP_FLAGS_FORCE);
-       int ignore = !!(flags & GUP_FLAGS_IGNORE_VMA_PERMISSIONS);
-
-       if (len <= 0)
-               return 0;
-       /*
-        * Require read or write permissions.
-        * If 'force' is set, we only require the "MAY" flags.
-        */
-       vm_flags  = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
-       vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
-       i = 0;
-
-       do {
-               struct vm_area_struct *vma;
-               unsigned int foll_flags;
-
-               vma = find_vma(mm, start);
-               if (!vma && swap_in_gate_area(tsk, start)) {
-                       unsigned long pg = start & PAGE_MASK;
-                       struct vm_area_struct *gate_vma =
-                               swap_get_gate_vma(tsk);
-                       pgd_t *pgd;
-                       pud_t *pud;
-                       pmd_t *pmd;
-                       pte_t *pte;
-
-                       /* user gate pages are read-only */
-                       if (!ignore && write)
-                               return i ? : -EFAULT;
-                       if (pg > TASK_SIZE)
-                               pgd = pgd_offset_k(pg);
-                       else
-                               pgd = pgd_offset_gate(mm, pg);
-                       BUG_ON(pgd_none(*pgd));
-                       pud = pud_offset(pgd, pg);
-                       BUG_ON(pud_none(*pud));
-                       pmd = pmd_offset(pud, pg);
-                       if (pmd_none(*pmd))
-                               return i ? : -EFAULT;
-                       pte = pte_offset_map(pmd, pg);
-                       if (pte_none(*pte)) {
-                               pte_unmap(pte);
-                               return i ? : -EFAULT;
-                       }
-                       if (pages) {
-                               struct page *page =
-                                       swap_vm_normal_page(gate_vma, start,
-                                                           *pte);
-                               pages[i] = page;
-                               if (page)
-                                       get_page(page);
-                       }
-                       pte_unmap(pte);
-                       if (vmas)
-                               vmas[i] = gate_vma;
-                       i++;
-                       start += PAGE_SIZE;
-                       len--;
-                       continue;
-               }
-
-               if (!vma ||
-                       (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
-                       (!ignore && !(vm_flags & vma->vm_flags)))
-                       return i ? : -EFAULT;
-
-               if (is_vm_hugetlb_page(vma)) {
-                       i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
-                                               &start, &len, i, write);
-                       continue;
-               }
-
-               foll_flags = FOLL_TOUCH;
-               if (pages)
-                       foll_flags |= FOLL_GET;
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
-               if (!write && use_zero_page(vma))
-                       foll_flags |= FOLL_ANON;
-#endif
-#endif
-
-               do {
-                       struct page *page;
-
-                       if (write)
-                               foll_flags |= FOLL_WRITE;
-
-
-                       /* cond_resched(); */
-
-                       DBPRINTF("pages = %p vma = %p\n", pages, vma);
-                       while (!(page = swap_follow_page(vma, start,
-                                                        foll_flags))) {
-                               int ret;
-                               ret = swap_handle_mm_fault(mm, vma, start,
-                                               foll_flags & FOLL_WRITE);
-
-#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
-                               if (ret & VM_FAULT_WRITE)
-                                       foll_flags &= ~FOLL_WRITE;
-
-                               switch (ret & ~VM_FAULT_WRITE) {
-                               case VM_FAULT_MINOR:
-                                       tsk->min_flt++;
-                                       break;
-                               case VM_FAULT_MAJOR:
-                                       tsk->maj_flt++;
-                                       break;
-                               case VM_FAULT_SIGBUS:
-                                       return i ? i : -EFAULT;
-                               case VM_FAULT_OOM:
-                                       return i ? i : -ENOMEM;
-                               default:
-                                       BUG();
-                               }
-
-#else
-                               if (ret & VM_FAULT_ERROR) {
-                                       if (ret & VM_FAULT_OOM)
-                                               return i ? i : -ENOMEM;
-                                       else if (ret & VM_FAULT_SIGBUS)
-                                               return i ? i : -EFAULT;
-                                       BUG();
-                               }
-                               if (ret & VM_FAULT_MAJOR)
-                                       tsk->maj_flt++;
-                               else
-                                       tsk->min_flt++;
-
-                               /*
-                                * The VM_FAULT_WRITE bit tells us that
-                                * do_wp_page has broken COW when necessary,
-                                * even if maybe_mkwrite decided not to set
-                                * pte_write. We can thus safely do subsequent
-                                * page lookups as if they were reads. But only
-                                * do so when looping for pte_write is futile:
-                                * in some cases userspace may also be wanting
-                                * to write to the gotten user page, which a
-                                * read fault here might prevent (a readonly
-                                * page might get reCOWed by userspace write).
-                                */
-                               if ((ret & VM_FAULT_WRITE) &&
-                                               !(vma->vm_flags & VM_WRITE))
-                                       foll_flags &= ~FOLL_WRITE;
-
-                               /* cond_resched(); */
-#endif
-
-                       }
-
-                       if (IS_ERR(page))
-                               return i ? i : PTR_ERR(page);
-                       if (pages) {
-                               pages[i] = page;
-
-                               swap_flush_anon_page(vma, page, start);
-                               flush_dcache_page(page);
-                       }
-                       if (vmas)
-                               vmas[i] = vma;
-                       i++;
-                       start += PAGE_SIZE;
-                       len--;
-               } while (len && start < vma->vm_end);
-       } while (len);
-       return i;
-}
-#endif
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-
-/**
- * @brief Gets user pages uprobe.
- *
- * @param tsk Pointer to the task_struct.
- * @param mm Pointer to the mm_struct.
- * @param start Starting address.
- * @param len Length.
- * @param write Write flag.
- * @param force Force flag.
- * @param pages Pointer to the array of pointers to the target page structs.
- * @param vmas Pointer to the array of pointers to the target vm_area_struct.
- * @return negative error code on error, positive result otherwise.
- */
-int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long start, int len, int write, int force,
-               struct page **pages, struct vm_area_struct **vmas)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) /* FIXME: must be >= 32! */
-       int flags = FOLL_TOUCH;
-
-       if (pages)
-               flags |= FOLL_GET;
-       if (write)
-               flags |= FOLL_WRITE;
-       if (force)
-               flags |= FOLL_FORCE;
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-       int flags = 0;
-
-       if (write)
-               flags |= GUP_FLAGS_WRITE;
-       if (force)
-               flags |= GUP_FLAGS_FORCE;
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-
-       return __get_user_pages_uprobe(tsk, mm,
-                               start, len, flags,
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
-                                               pages, vmas, NULL);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-                                               pages, vmas);
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
-#else
-       return get_user_pages(tsk, mm, start, len, write, force, pages, vmas);
-#endif
-}
-
-#define ACCESS_PROCESS_OPTIMIZATION 0
-
-#if ACCESS_PROCESS_OPTIMIZATION
-
-#define GET_STEP_X(LEN, STEP) (((LEN) >= (STEP)) ? (STEP) : (LEN) % (STEP))
-#define GET_STEP_4(LEN) GET_STEP_X((LEN), 4)
-
-static void read_data_current(unsigned long addr, void *buf, int len)
-{
-       int step;
-       int pos = 0;
-
-       for (step = GET_STEP_4(len); len; len -= step) {
-               switch (GET_STEP_4(len)) {
-               case 1:
-                       get_user(*(u8 *)(buf + pos),
-                                (unsigned long *)(addr + pos));
-                       step = 1;
-                       break;
-
-               case 2:
-               case 3:
-                       get_user(*(u16 *)(buf + pos),
-                                (unsigned long *)(addr + pos));
-                       step = 2;
-                       break;
-
-               case 4:
-                       get_user(*(u32 *)(buf + pos),
-                                (unsigned long *)(addr + pos));
-                       step = 4;
-                       break;
-               }
-
-               pos += step;
-       }
-}
-
-/* not working */
-static void write_data_current(unsigned long addr, void *buf, int len)
-{
-       int step;
-       int pos = 0;
-
-       for (step = GET_STEP_4(len); len; len -= step) {
-               switch (GET_STEP_4(len)) {
-               case 1:
-                       put_user(*(u8 *)(buf + pos),
-                                (unsigned long *)(addr + pos));
-                       step = 1;
-                       break;
-
-               case 2:
-               case 3:
-                       put_user(*(u16 *)(buf + pos),
-                                (unsigned long *)(addr + pos));
-                       step = 2;
-                       break;
-
-               case 4:
-                       put_user(*(u32 *)(buf + pos),
-                                (unsigned long *)(addr + pos));
-                       step = 4;
-                       break;
-               }
-
-               pos += step;
-       }
-}
-#endif
-
-/**
- * @brief Read-write task memory.
- *
- * @param tsk Pointer to the target task task_struct.
- * @param addr Address to read-write.
- * @param buf Pointer to buffer where to put-get data.
- * @param len Buffer length.
- * @param write Write flag. If 0 - reading, if 1 - writing.
- * @return Read-write size, error code on error.
- */
-int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr,
-                            void *buf, int len, int write)
-{
-       struct mm_struct *mm;
-       struct vm_area_struct *vma;
-       void *old_buf = buf;
-       int atomic;
-
-       if (len <= 0)
-               return -1;
-
-#if ACCESS_PROCESS_OPTIMIZATION
-       if (write == 0 && tsk == current) {
-               read_data_current(addr, buf, len);
-               return len;
-       }
-#endif
-
-       mm = tsk->mm; /* function 'get_task_mm' is to be called */
-       if (!mm)
-               return 0;
-
-       /* FIXME: danger: write memory in atomic context */
-       atomic = in_atomic();
-       WARN_ON(atomic);
-
-       /* ignore errors, just check how much was successfully transferred */
-       while (len) {
-               int bytes, ret, offset;
-               void *maddr;
-               struct page *page = NULL;
-
-               ret = get_user_pages_uprobe(tsk, mm, addr, 1,
-                                               write, 1, &page, &vma);
-
-               if (ret <= 0) {
-                       /*
-                        * Check if this is a VM_IO | VM_PFNMAP VMA, which
-                        * we can access using slightly different code.
-                        */
-#ifdef CONFIG_HAVE_IOREMAP_PROT
-                       vma = find_vma(mm, addr);
-                       if (!vma)
-                               break;
-                       if (vma->vm_ops && vma->vm_ops->access)
-                               ret = vma->vm_ops->access(vma, addr, buf,
-                                                       len, write);
-                       if (ret <= 0)
-#endif
-                               break;
-                       bytes = ret;
-               } else {
-                       bytes = len;
-                       offset = addr & (PAGE_SIZE-1);
-                       if (bytes > PAGE_SIZE-offset)
-                               bytes = PAGE_SIZE-offset;
-
-                       maddr = atomic ? swap_kmap_atomic(page) : kmap(page);
-
-                       if (write) {
-                               swap_copy_to_user_page(vma, page, addr,
-                                                       maddr + offset,
-                                                      buf, bytes);
-                               set_page_dirty_lock(page);
-                       } else {
-                               copy_from_user_page(vma, page, addr,
-                                                   buf, maddr + offset,
-                                                   bytes);
-                       }
-
-                       atomic ? swap_kunmap_atomic(maddr) : kunmap(page);
-                       page_cache_release(page);
-               }
-               len -= bytes;
-               buf += bytes;
-               addr += bytes;
-       }
-
-       return buf - old_buf;
-}
-EXPORT_SYMBOL_GPL(access_process_vm_atomic);
-
-#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-
-/**
- * @brief Page present.
- *
- * @param mm Pointer to the target mm_struct.
- * @param address Address.
- */
-int page_present(struct mm_struct *mm, unsigned long address)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-       unsigned long pfn;
-
-       pgd = pgd_offset(mm, address);
-       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-               goto out;
-
-       pud = pud_offset(pgd, address);
-       if (pud_none(*pud) || unlikely(pud_bad(*pud)))
-               goto out;
-
-       pmd = pmd_offset(pud, address);
-       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-               goto out;
-
-       ptep = pte_offset_map(pmd, address);
-       if (pte_none(*ptep)) {
-               pte_unmap(ptep);
-               goto out;
-       }
-
-       pte = *ptep;
-       pte_unmap(ptep);
-       if (pte_present(pte)) {
-               pfn = pte_pfn(pte);
-               if (pfn_valid(pfn))
-                       return 1;
-       }
-
-out:
-       return 0;
-}
-EXPORT_SYMBOL_GPL(page_present);
-
diff --git a/kprobe/swap_kprobes_deps.h b/kprobe/swap_kprobes_deps.h
deleted file mode 100644 (file)
index 8d4f345..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * @file kprobe/swap_kprobes_deps.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe kernel-dependent dependencies.
- */
-
-#ifndef _SWAP_KPROBES_DEPS_H
-#define _SWAP_KPROBES_DEPS_H
-
-#include <linux/version.h>     /* LINUX_VERSION_CODE, KERNEL_VERSION() */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/hugetlb.h>
-#include <linux/mempolicy.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <ksyms/ksyms.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-#define DECLARE_NODE_PTR_FOR_HLIST(var_name)
-#define swap_hlist_for_each_entry_rcu(tpos, pos, head, member) \
-       hlist_for_each_entry_rcu(tpos, head, member)
-#define swap_hlist_for_each_entry_safe(tpos, pos, n, head, member) \
-       hlist_for_each_entry_safe(tpos, n, head, member)
-#define swap_hlist_for_each_entry(tpos, pos, head, member) \
-       hlist_for_each_entry(tpos, head, member)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-#define DECLARE_NODE_PTR_FOR_HLIST(var_name) struct hlist_node *var_name
-#define swap_hlist_for_each_entry_rcu(tpos, pos, head, member) \
-       hlist_for_each_entry_rcu(tpos, pos, head, member)
-#define swap_hlist_for_each_entry_safe(tpos, pos, n, head, member) \
-       hlist_for_each_entry_safe(tpos, pos, n, head, member)
-#define swap_hlist_for_each_entry(tpos, pos, head, member) \
-       hlist_for_each_entry(tpos, pos, head, member)
-
-#define list_first_entry_or_null(ptr, type, member) \
-       (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
-
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12))
-#define synchronize_sched      synchronize_kernel
-#endif
-
-
-/*
- * swap_preempt_enable_no_resched()
- */
-#if (defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)))
-
-#ifdef CONFIG_PREEMPT_COUNT
-#define swap_preempt_enable_no_resched() \
-do { \
-       barrier(); \
-       preempt_count_dec(); \
-} while (0)
-#else /* !CONFIG_PREEMPT_COUNT */
-#define swap_preempt_enable_no_resched() barrier()
-#endif /* CONFIG_PREEMPT_COUNT */
-
-#else /* !(defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) */
-#define swap_preempt_enable_no_resched() preempt_enable_no_resched()
-#endif /* !(defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) */
-
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0)
-    #define task_job(task) (task->jobctl)
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0) */
-    #define task_job(task) (task->group_stop)
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0) */
-
-
-
-/* --------------------- Declaration of module dependencies ----------------- */
-
-#define DECLARE_MOD_FUNC_DEP(name, ret, ...) ret(*__ref_##name)(__VA_ARGS__)
-#define DECLARE_MOD_CB_DEP(name, ret, ...) ret(*name)(__VA_ARGS__)
-
-
-/* ---------------- Implementation of module dependencies wrappers ---------- */
-
-#define DECLARE_MOD_DEP_WRAPPER(name, ret, ...) ret name(__VA_ARGS__)
-#define IMP_MOD_DEP_WRAPPER(name, ...) \
-{ \
-       return __ref_##name(__VA_ARGS__); \
-}
-
-
-/* --------------------- Module dependencies initialization ----------------- */
-
-#define INIT_MOD_DEP_VAR(dep, name) \
-{ \
-       __ref_##dep = (void *) swap_ksyms(#name); \
-       if (!__ref_##dep) { \
-               DBPRINTF(#name " is not found! Oops. Where is it?"); \
-               return -ESRCH; \
-       } \
-}
-
-#define INIT_MOD_DEP_CB(dep, name) \
-{ \
-       dep = (void *) swap_ksyms(#name); \
-       if (!dep) { \
-               DBPRINTF(#name " is not found! Oops. Where is it?"); \
-               return -ESRCH; \
-       } \
-}
-
-
-int init_module_dependencies(void);
-
-
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-
-int swap_access_process_vm(struct task_struct *tsk, unsigned long addr,
-                          void *buf, int len, int write);
-
-# define read_proc_vm_atomic(tsk, addr, buf, len) \
-       swap_access_process_vm(tsk, addr, buf, len, 0)
-# define write_proc_vm_atomic(tsk, addr, buf, len) \
-       swap_access_process_vm(tsk, addr, buf, len, 1)
-
-#else /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-
-int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr,
-                            void *buf, int len, int write);
-
-# define read_proc_vm_atomic(tsk, addr, buf, len) \
-       access_process_vm_atomic(tsk, addr, buf, len, 0)
-# define write_proc_vm_atomic(tsk, addr, buf, len) \
-       access_process_vm_atomic(tsk, addr, buf, len, 1)
-
-#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-
-int page_present(struct mm_struct *mm, unsigned long addr);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
-unsigned long swap_do_mmap(struct file *file, unsigned long addr,
-                          unsigned long len, unsigned long prot,
-                          unsigned long flags, vm_flags_t vm_flags,
-                          unsigned long pgoff, unsigned long *populate);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-unsigned long swap_do_mmap_pgoff(struct file *file, unsigned long addr,
-                                unsigned long len, unsigned long prot,
-                                unsigned long flags, unsigned long pgoff,
-                                unsigned long *populate);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-unsigned long swap_do_mmap_pgoff(struct file *file, unsigned long addr,
-                                unsigned long len, unsigned long prot,
-                                unsigned long flags, unsigned long pgoff);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0)
-#define swap_hlist_add_after(node, prev) hlist_add_behind(node, prev)
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
-#define swap_hlist_add_after(node, prev) hlist_add_after(node, prev)
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 18, 0)
-#define __get_cpu_var(var) (*this_cpu_ptr(&(var)))
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 18, 0) */
-
-#endif /* _SWAP_KPROBES_DEPS_H */
diff --git a/kprobe/swap_ktd.c b/kprobe/swap_ktd.c
deleted file mode 100644 (file)
index 4947d37..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <ksyms/ksyms.h>
-#include "swap_ktd.h"
-#include "swap_td_raw.h"
-
-
-#define KTD_PREFIX             "[SWAP_KTD] "
-#define kTD_JOBCTL_PREPARE     (1 << 31)
-#define KTD_BIT_MAX            (sizeof(unsigned long) * 8)
-
-
-struct td {
-       struct list_head list;
-       struct task_struct *task;
-
-       spinlock_t flags_lock;
-       unsigned long init_flags;
-};
-
-
-static struct td_raw td_raw;
-static LIST_HEAD(prepare_list);
-static DEFINE_RWLOCK(prepare_lock);
-static int preparing_cnt = 0;
-
-
-static DEFINE_MUTEX(mutex_ktd_nr);
-static struct ktask_data *ktd_array[KTD_BIT_MAX];
-
-
-static bool ktd_init_is(struct ktask_data *ktd, struct td *td)
-{
-       return !!(td->init_flags & (1 << ktd->nr_bit));
-}
-
-static void ktd_init(struct ktask_data *ktd, struct td *td,
-                    struct task_struct *task)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&td->flags_lock, flags);
-       if (ktd_init_is(ktd, td))
-               goto unlock;
-
-       if (ktd->init)
-               ktd->init(task, swap_td_raw(&ktd->td_raw, task));
-
-       td->init_flags |= 1 << ktd->nr_bit;
-
-unlock:
-       spin_unlock_irqrestore(&td->flags_lock, flags);
-}
-
-static void ktd_exit_no_lock(struct ktask_data *ktd, struct td *td,
-                            struct task_struct *task)
-{
-       if (ktd_init_is(ktd, td)) {
-               if (ktd->exit)
-                       ktd->exit(task, swap_td_raw(&ktd->td_raw, task));
-
-               td->init_flags &= ~(1 << ktd->nr_bit);
-       }
-}
-
-static void ktd_exit_all(struct td *td, struct task_struct *task)
-{
-       unsigned long flags;
-       unsigned long init_flags;
-       int nr_bit = 0;
-
-       spin_lock_irqsave(&td->flags_lock, flags);
-       init_flags = td->init_flags;
-       do {
-               if (init_flags & 1)
-                       ktd_exit_no_lock(ktd_array[nr_bit], td, task);
-
-               ++nr_bit;
-               init_flags >>= 1;
-       } while (init_flags);
-       td->init_flags = 0;
-       spin_unlock_irqrestore(&td->flags_lock, flags);
-}
-
-
-static bool task_prepare_is(struct task_struct *task)
-{
-       return !!(task_job(task) & kTD_JOBCTL_PREPARE);
-}
-
-static void task_prepare_set(struct task_struct *task)
-{
-       if (!(task_job(task) & kTD_JOBCTL_PREPARE))
-               task_job(task) |= kTD_JOBCTL_PREPARE;
-       else
-               WARN(1, KTD_PREFIX "already prepare");
-
-       ++preparing_cnt;
-}
-
-static void task_prepare_clear(struct task_struct *task)
-{
-       if (task_job(task) & kTD_JOBCTL_PREPARE)
-               task_job(task) &= ~kTD_JOBCTL_PREPARE;
-       else
-               WARN(1, KTD_PREFIX "is not prepare");
-
-       --preparing_cnt;
-}
-
-static struct task_struct *task_by_td(struct td *td)
-{
-       return td->task;
-}
-
-static struct td *td_by_task(struct task_struct *task)
-{
-       return (struct td *)swap_td_raw(&td_raw, task);
-}
-
-
-static void task_prepare(struct task_struct *task, struct td *td,
-                        struct ktask_data *ktd)
-{
-       unsigned long flags;
-
-       write_lock_irqsave(&prepare_lock, flags);
-
-       /* skip multi-preparing task */
-       if (task_prepare_is(task))
-               goto unlock;
-
-       task_prepare_set(task);
-
-       INIT_LIST_HEAD(&td->list);
-       td->task = task;
-       spin_lock_init(&td->flags_lock);
-       td->init_flags = 0;
-
-       /* add to prepare_list */
-       list_add(&td->list, &prepare_list);
-
-unlock:
-       write_unlock_irqrestore(&prepare_lock, flags);
-}
-
-static void ktd_exit_all(struct td *td, struct task_struct *task);
-
-static void td_prepare_clear_no_lock(struct td *td, struct task_struct *task)
-{
-       if (task_prepare_is(task)) {
-               task_prepare_clear(task);
-
-               ktd_exit_all(td, task);
-
-               /* delete from prepare_list */
-               list_del(&td->list);
-       }
-}
-
-static void td_prepare_clear(struct td *td, struct task_struct *task)
-{
-       unsigned long flags;
-
-       write_lock_irqsave(&prepare_lock, flags);
-       td_prepare_clear_no_lock(td, task);
-       write_unlock_irqrestore(&prepare_lock, flags);
-}
-
-void *swap_ktd(struct ktask_data *ktd, struct task_struct *task)
-{
-       struct td *td = td_by_task(task);
-
-       if (!likely(task_prepare_is(task)))
-               task_prepare(task, td, ktd);
-
-       if (!likely(ktd_init_is(ktd, td)))
-               ktd_init(ktd, td, task);
-
-       return swap_td_raw(&ktd->td_raw, task);
-}
-EXPORT_SYMBOL_GPL(swap_ktd);
-
-
-static int ktd_nr_get_free_bit(void)
-{
-       int bit;
-
-       for (bit = 0; bit < KTD_BIT_MAX; ++bit) {
-               if (ktd_array[bit] == NULL)
-                       return bit;
-       }
-
-       return -ENOMEM;
-}
-
-int swap_ktd_reg(struct ktask_data *ktd)
-{
-       int ret;
-       int free_bit;
-
-       mutex_lock(&mutex_ktd_nr);
-       free_bit = ktd_nr_get_free_bit();
-
-       if (free_bit < 0) {
-               ret = free_bit;
-               goto unlock;
-       }
-
-       ret = swap_td_raw_reg(&ktd->td_raw, ktd->size);
-       if (ret)
-               goto unlock;
-
-       ktd->nr_bit = free_bit;
-       ktd_array[free_bit] = ktd;
-unlock:
-       mutex_unlock(&mutex_ktd_nr);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_ktd_reg);
-
-void swap_ktd_unreg(struct ktask_data *ktd)
-{
-       struct td *td;
-       unsigned long flags;
-
-       /* exit all task */
-       read_lock_irqsave(&prepare_lock, flags);
-       list_for_each_entry(td, &prepare_list, list) {
-               spin_lock(&td->flags_lock);
-               ktd_exit_no_lock(ktd, td, task_by_td(td));
-               spin_unlock(&td->flags_lock);
-       }
-       read_unlock_irqrestore(&prepare_lock, flags);
-
-       mutex_lock(&mutex_ktd_nr);
-
-       ktd_array[ktd->nr_bit] = NULL;
-       swap_td_raw_unreg(&ktd->td_raw);
-
-       mutex_unlock(&mutex_ktd_nr);
-}
-EXPORT_SYMBOL_GPL(swap_ktd_unreg);
-
-
-static void do_put_task(struct task_struct *task)
-{
-       if (task_prepare_is(task))
-               td_prepare_clear(td_by_task(task), task);
-}
-
-#ifdef CONFIG_SWAP_HOOK_TASKDATA
-
-#include <swap/hook_taskdata.h>
-
-static struct hook_taskdata hook_taskdata = {
-       .owner = THIS_MODULE,
-       .put_task = do_put_task,
-};
-
-static int taskdata_init(void)
-{
-       return hook_taskdata_reg(&hook_taskdata);
-}
-
-static void taskdata_uninit(void)
-{
-       hook_taskdata_unreg(&hook_taskdata);
-}
-
-void swap_ktd_put_task(struct task_struct *task)
-{
-}
-
-#else /* CONFIG_SWAP_HOOK_TASKDATA */
-
-static int taskdata_init(void)
-{
-       return 0;
-}
-
-static void taskdata_uninit(void)
-{
-}
-
-void swap_ktd_put_task(struct task_struct *task)
-{
-       do_put_task(task);
-}
-
-#endif /* CONFIG_SWAP_HOOK_TASKDATA */
-
-int swap_ktd_init(void)
-{
-       int ret;
-
-       WARN(preparing_cnt, KTD_PREFIX "preparing_cnt=%d", preparing_cnt);
-
-       preparing_cnt = 0;
-
-       ret = swap_td_raw_reg(&td_raw, sizeof(struct td));
-       if (ret) {
-               pr_err(KTD_PREFIX "registration failed, ret=%d", ret);
-               return ret;
-       }
-
-       ret = taskdata_init();
-       if (ret) {
-               swap_td_raw_unreg(&td_raw);
-               pr_err(KTD_PREFIX "failed to initialize, ret=%d\n", ret);
-       }
-
-       return ret;
-}
-
-void swap_ktd_uninit_top(void)
-{
-       struct td *td;
-       unsigned long flags;
-
-       /* get injected tasks */
-       write_lock_irqsave(&prepare_lock, flags);
-       list_for_each_entry(td, &prepare_list, list) {
-               get_task_struct(task_by_td(td));
-       }
-       write_unlock_irqrestore(&prepare_lock, flags);
-}
-
-void swap_ktd_uninit_bottom(void)
-{
-       struct td *td, *n;
-       unsigned long flags;
-
-       /* remove td injection from tasks and put tasks */
-       write_lock_irqsave(&prepare_lock, flags);
-       list_for_each_entry_safe(td, n, &prepare_list, list) {
-               struct task_struct *task = task_by_td(td);
-
-               td_prepare_clear_no_lock(td, task);
-               put_task_struct(task);
-       }
-       write_unlock_irqrestore(&prepare_lock, flags);
-
-       taskdata_uninit();
-       swap_td_raw_unreg(&td_raw);
-
-       WARN(preparing_cnt, KTD_PREFIX "preparing_cnt=%d", preparing_cnt);
-}
diff --git a/kprobe/swap_ktd.h b/kprobe/swap_ktd.h
deleted file mode 100644 (file)
index 664f539..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_TD_H
-#define _SWAP_TD_H
-
-
-#include <linux/list.h>
-#include "swap_td_raw.h"
-
-struct task_struct;
-
-struct ktask_data {
-       int nr_bit;
-       struct td_raw td_raw;
-
-       /* init() and exit() may be called in atomic context */
-       void (*init)(struct task_struct *, void *);
-       void (*exit)(struct task_struct *, void *);
-       unsigned long size;
-};
-
-
-int swap_ktd_reg(struct ktask_data *ktd);
-void swap_ktd_unreg(struct ktask_data *ktd);
-
-void *swap_ktd(struct ktask_data *ktd, struct task_struct *task);
-
-int swap_ktd_init(void);
-void swap_ktd_uninit_top(void);
-void swap_ktd_uninit_bottom(void);
-void swap_ktd_put_task(struct task_struct *task);
-
-
-#endif /* _SWAP_TD_H */
diff --git a/kprobe/swap_no_kprobes.c b/kprobe/swap_no_kprobes.c
deleted file mode 100644 (file)
index ecec419..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <kprobe/swap_ktd.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <master/swap_initializer.h>
-
-
-static void ktd_uninit(void)
-{
-       swap_ktd_uninit_top();
-       swap_ktd_uninit_bottom();
-}
-
-SWAP_LIGHT_INIT_MODULE(init_module_dependencies, swap_ktd_init, ktd_uninit, NULL, NULL);
-
-MODULE_LICENSE("GPL");
diff --git a/kprobe/swap_slots.c b/kprobe/swap_slots.c
deleted file mode 100644 (file)
index 58869e4..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/**
- * kprobe/swap_slots.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @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) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2012
- *
- * @section DESCRIPTION
- *
- * SWAP slots implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/rculist.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#include "swap_slots.h"
-#include "swap_kprobes_deps.h"
-
-
-/**
- * @struct chunk
- * @brief Chunk of memory for trampolines.
- * @var chunk::data
- * Chunk data.
- * @var chunk::first_available
- * Index of the first available block.
- * @var chunk::count_available
- * Count of the blocks.
- * @var chunk::lock
- * Chunk's lock.
- * @var chunk::size
- * Count of the blocks in chunk.
- * @var chunk::index
- * Pointer to allocated memory.
- */
-struct chunk {
-       unsigned long *data;
-       unsigned long first_available;
-       unsigned long count_available;
-
-       spinlock_t    lock;
-       unsigned long size;
-       unsigned long *index;
-};
-
-/**
- * @struct fixed_alloc
- * @brief Item of fixed allocs list.
- * @var fixed_alloc::hlist
- * Fixed alloc hash list node.
- * @var fixed_alloc::chunk
- * Chunk.
- */
-struct fixed_alloc {
-       struct hlist_node hlist;
-       struct chunk chunk;
-};
-
-static int chunk_init(struct chunk *chunk, void *data,
-                     size_t size, size_t size_block)
-{
-       unsigned long i;
-       unsigned long *p;
-
-       spin_lock_init(&chunk->lock);
-       chunk->data = (unsigned long *)data;
-       chunk->first_available = 0;
-       chunk->count_available = size / size_block;
-       chunk->size = chunk->count_available;
-
-       chunk->index = kmalloc(sizeof(*chunk->index)*chunk->count_available,
-                              GFP_ATOMIC);
-
-       if (chunk->index == NULL) {
-               pr_err("%s: failed to allocate memory\n", __func__);
-               return -ENOMEM;
-       }
-
-       p = chunk->index;
-       for (i = 0; i != chunk->count_available; ++p)
-               *p = ++i;
-
-       return 0;
-}
-
-static void chunk_uninit(struct chunk *chunk)
-{
-       kfree(chunk->index);
-}
-
-static void *chunk_allocate(struct chunk *chunk, size_t size_block)
-{
-       unsigned long *ret;
-
-       if (!chunk->count_available)
-               return NULL;
-
-       spin_lock(&chunk->lock);
-       ret = chunk->data + chunk->first_available*size_block;
-       chunk->first_available = chunk->index[chunk->first_available];
-       --chunk->count_available;
-       spin_unlock(&chunk->lock);
-
-       return ret;
-}
-
-static void chunk_deallocate(struct chunk *chunk, void *p, size_t size_block)
-{
-       unsigned long idx = ((unsigned long *)p - chunk->data)/size_block;
-
-       spin_lock(&chunk->lock);
-       chunk->index[idx] = chunk->first_available;
-       chunk->first_available = idx;
-       ++chunk->count_available;
-       spin_unlock(&chunk->lock);
-}
-
-static inline int chunk_check_ptr(struct chunk *chunk, void *p, size_t size)
-{
-       if ((chunk->data                             <= (unsigned long *)p) &&
-           ((chunk->data + size/sizeof(chunk->data))  > (unsigned long *)p))
-               return 1;
-
-       return 0;
-}
-
-static inline int chunk_free(struct chunk *chunk)
-{
-       return (chunk->count_available == chunk->size);
-}
-
-static struct fixed_alloc *create_fixed_alloc(struct slot_manager *sm)
-{
-       int ret;
-       void *data;
-       struct fixed_alloc *fa;
-
-       fa = kmalloc(sizeof(*fa), GFP_ATOMIC);
-       if (fa == NULL)
-               return NULL;
-
-       data = sm->alloc(sm);
-       if (data == NULL)
-               goto free_fa;
-
-       ret = chunk_init(&fa->chunk, data,
-                        PAGE_SIZE / sizeof(unsigned long), sm->slot_size);
-       if (ret)
-               goto free_sm;
-
-       return fa;
-
-free_sm:
-       sm->free(sm, data);
-free_fa:
-       kfree(fa);
-       return NULL;
-}
-
-static void free_fixed_alloc(struct slot_manager *sm, struct fixed_alloc *fa)
-{
-       chunk_uninit(&fa->chunk);
-       sm->free(sm, fa->chunk.data);
-       kfree(fa);
-}
-
-
-/**
- * @brief Allocates slot for slot manager.
- *
- * @param[in,out] sm Slot manager that should be filled.
- * @return Pointer to allocated slot.
- */
-void *swap_slot_alloc(struct slot_manager *sm)
-{
-       void *free_slot;
-       struct fixed_alloc *fa;
-       DECLARE_NODE_PTR_FOR_HLIST(pos);
-
-       swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
-               free_slot = chunk_allocate(&fa->chunk, sm->slot_size);
-               if (free_slot)
-                       return free_slot;
-       }
-
-       fa = create_fixed_alloc(sm);
-       if (fa == NULL)
-               return NULL;
-
-       INIT_HLIST_NODE(&fa->hlist);
-       hlist_add_head_rcu(&fa->hlist, &sm->page_list);
-
-       return chunk_allocate(&fa->chunk, sm->slot_size);
-}
-EXPORT_SYMBOL_GPL(swap_slot_alloc);
-
-/**
- * @brief Releases allocated slot.
- *
- * @param sm Pointer to the target slot manager.
- * @param slot Pointer to the target slot.
- * @return Void.
- */
-void swap_slot_free(struct slot_manager *sm, void *slot)
-{
-       struct fixed_alloc *fa;
-       DECLARE_NODE_PTR_FOR_HLIST(pos);
-
-       if (slot == NULL)
-               return;
-
-       swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
-               if (!chunk_check_ptr(&fa->chunk, slot, PAGE_SIZE))
-                       continue;
-
-               chunk_deallocate(&fa->chunk, slot, sm->slot_size);
-
-               if (chunk_free(&fa->chunk)) {
-                       hlist_del_rcu(&fa->hlist);
-                       free_fixed_alloc(sm, fa);
-               }
-
-               return;
-       }
-
-       panic("%s: slot=%p is not data base\n", __func__, slot);
-}
-EXPORT_SYMBOL_GPL(swap_slot_free);
diff --git a/kprobe/swap_slots.h b/kprobe/swap_slots.h
deleted file mode 100644 (file)
index 129a439..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file kprobe/swap_slots.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @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) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP slots interface declaration.
- */
-
-#ifndef _SWAP_SLOTS_H
-#define _SWAP_SLOTS_H
-
-#include <linux/types.h>
-
-/**
- * @struct slot_manager
- * @brief Manage slots.
- * @var slot_manager::slot_size
- * Size of the slot.
- * @var slot_manager::alloc
- * Memory allocation callback.
- * @var slot_manager::free
- * Memory release callback.
- * @var slot_manager::page_list
- * List of pages.
- * @var slot_manager::data
- * Slot manager data. task_struct pointer usually stored here.
- */
-struct slot_manager {
-       unsigned long slot_size;        /* FIXME: allocated in long (4 byte) */
-       void *(*alloc)(struct slot_manager *sm);
-       void (*free)(struct slot_manager *sm, void *ptr);
-       struct hlist_head page_list;
-       void *data;
-};
-
-void *swap_slot_alloc(struct slot_manager *sm);
-void swap_slot_free(struct slot_manager *sm, void *slot);
-
-#endif /* _SWAP_SLOTS_H */
diff --git a/kprobe/swap_td_raw.c b/kprobe/swap_td_raw.c
deleted file mode 100644 (file)
index 9985d06..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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
- *
- * 2014         Vasiliy Ulyanov <v.ulyanov@samsung.com>
- * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <linux/module.h>
-#include "swap_td_raw.h"
-
-
-#define TD_OFFSET              1  /* skip STACK_END_MAGIC */
-#define TD_PREFIX              "[SWAP_TD_RAW] "
-#define TD_STACK_USAGE_MAX     0x200
-#define TD_CHUNK_MIN           sizeof(long)
-
-
-static DEFINE_MUTEX(mutex_stack_usage);
-static unsigned long stack_usage = 0;
-static LIST_HEAD(td_raw_list);
-
-
-/*
- * take small area from stack
- *
- * 0x00 +--------------------------+
- *      |      STACK_END_MAGIC     |
- *      +--------------------------+  <-- bottom of stack;
- *      |                          |
- *      |           stack          |
- *      |                          |
- * 0xff
- *
- */
-
-static void *bottom_of_stack(struct task_struct *task)
-{
-       return (void *)(end_of_stack(task) + TD_OFFSET);
-}
-
-int swap_td_raw_reg(struct td_raw *raw, unsigned long size)
-{
-       int ret = 0;
-
-       size = (size / TD_CHUNK_MIN + !!(size % TD_CHUNK_MIN)) * TD_CHUNK_MIN;
-
-       mutex_lock(&mutex_stack_usage);
-       if (stack_usage + size > TD_STACK_USAGE_MAX) {
-               pr_warn(TD_PREFIX "free stack ended: usage=%ld size=%ld\n",
-                       stack_usage, size);
-               ret = -ENOMEM;
-               goto unlock;
-       }
-
-       raw->offset = stack_usage;
-
-       INIT_LIST_HEAD(&raw->list);
-       list_add(&raw->list, &td_raw_list);
-
-       stack_usage += size;
-
-unlock:
-       mutex_unlock(&mutex_stack_usage);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_td_raw_reg);
-
-void swap_td_raw_unreg(struct td_raw *raw)
-{
-       mutex_lock(&mutex_stack_usage);
-
-       list_del(&raw->list);
-       if (list_empty(&td_raw_list))
-               stack_usage = 0;
-
-       mutex_unlock(&mutex_stack_usage);
-}
-EXPORT_SYMBOL_GPL(swap_td_raw_unreg);
-
-void *swap_td_raw(struct td_raw *raw, struct task_struct *task)
-{
-       return bottom_of_stack(task) + raw->offset;
-}
-EXPORT_SYMBOL_GPL(swap_td_raw);
-
-int swap_td_raw_init(void)
-{
-       WARN_ON(stack_usage);
-
-       stack_usage = 0;
-
-       return 0;
-}
-
-void swap_td_raw_uninit(void)
-{
-       WARN_ON(!list_empty(&td_raw_list));
-       WARN_ON(stack_usage);
-}
diff --git a/kprobe/swap_td_raw.h b/kprobe/swap_td_raw.h
deleted file mode 100644 (file)
index 079b153..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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
- *
- * 2014         Vasiliy Ulyanov <v.ulyanov@samsung.com>
- * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_TD_RAW_H
-#define _SWAP_TD_RAW_H
-
-
-#include <linux/list.h>
-
-
-struct td_raw {
-       struct list_head list;
-       unsigned long offset;
-};
-
-
-int swap_td_raw_reg(struct td_raw *raw, unsigned long size);
-void swap_td_raw_unreg(struct td_raw *raw);
-
-void *swap_td_raw(struct td_raw *raw, struct task_struct *task);
-
-int swap_td_raw_init(void);
-void swap_td_raw_uninit(void);
-
-
-#endif /* _SWAP_TD_RAW_H */
diff --git a/ks_features/Kbuild b/ks_features/Kbuild
deleted file mode 100644 (file)
index 94a041a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers \
-                       $(src)/../writer/Module.symvers
-
-obj-m := swap_ks_features.o
-swap_ks_features-y := ks_features.o \
-                      ks_features_data.o \
-                      ks_map.o \
-                      file_ops.o \
-                      ksf_msg.o
diff --git a/ks_features/features_data.c b/ks_features/features_data.c
deleted file mode 100644 (file)
index 5b847e4..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/**
- * ks_features/features_data.c
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @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
- *
- * SWAP kernel features
- */
-
-
-#include "ksf_msg.h"
-#include "syscall_list.h"
-
-
-/**
- * @struct feature
- * Feature description.
- * @var feature::cnt
- * Syscalls count.
- * @var feature::feature_list
- * Pointer to feature's syscall list.
- * @var feature::type
- * Featue subtype.
- * @var feature::enable
- * Is feature enable.
- */
-struct feature {
-       size_t cnt;
-       enum syscall_id *feature_list;
-       enum probe_t type;
-
-       unsigned enable:1;
-};
-
-/**
- * @def X
- * X-macros for syscall list.
- */
-#define X(name, args) id_sys_##name,
-/**
- * @enum syscall_id
- * Syscall list
- */
-enum syscall_id {
-       SYSCALL_LIST
-};
-#undef X
-
-static enum syscall_id id_none[] = {};
-
-static enum syscall_id id_file[] = {
-       id_sys_acct,
-       id_sys_mount,
-/* TODO:
- *     id_sys_umount,
- */
-       id_sys_truncate,
-/* TODO:
- *     id_sys_stat,
- */
-       id_sys_statfs,
-       id_sys_statfs64,
-/* TODO:
- *     id_sys_lstat,
- */
-       id_sys_stat64,
-       id_sys_fstat64,
-       id_sys_lstat64,
-       id_sys_truncate64,
-       id_sys_ftruncate64,
-       id_sys_setxattr,
-       id_sys_getxattr,
-       id_sys_listxattr,
-       id_sys_removexattr,
-       id_sys_chroot,
-       id_sys_mknod,
-       id_sys_link,
-       id_sys_symlink,
-       id_sys_unlink,
-       id_sys_rename,
-       id_sys_chmod,
-       id_sys_readlink,
-       id_sys_creat,
-       id_sys_open,
-       id_sys_access,
-       id_sys_chown,
-/* TODO:
- *     id_sys_chown16,
- *     id_sys_utime,
- */
-       id_sys_utimes,
-       id_sys_pread64,
-       id_sys_pwrite64,
-       id_sys_preadv,
-       id_sys_pwritev,
-       id_sys_getcwd,
-       id_sys_mkdir,
-       id_sys_chdir,
-       id_sys_rmdir,
-       id_sys_swapon,
-       id_sys_swapoff,
-       id_sys_uselib,
-       id_sys_mknodat,
-       id_sys_mkdirat,
-       id_sys_unlinkat,
-       id_sys_symlinkat,
-       id_sys_linkat,
-       id_sys_renameat,
-       id_sys_futimesat,
-       id_sys_faccessat,
-       id_sys_fchmodat,
-       id_sys_fchownat,
-       id_sys_openat,
-/* TODO:
- *     id_sys_newfstatat,
- */
-       id_sys_readlinkat,
-       id_sys_utimensat,
-       id_sys_fanotify_mark,
-       id_sys_execve,
-       id_sys_name_to_handle_at,
-       id_sys_open_by_handle_at
-};
-
-static enum syscall_id id_ipc[] = {
-       id_sys_msgget,
-       id_sys_msgsnd,
-       id_sys_msgrcv,
-       id_sys_msgctl,
-       id_sys_semget,
-       id_sys_semop,
-       id_sys_semctl,
-       id_sys_semtimedop,
-       id_sys_shmat,
-       id_sys_shmget,
-       id_sys_shmdt,
-       id_sys_shmctl,
-/* TODO:
- *     id_sys_ipc
- */
-};
-
-static enum syscall_id id_net[] = {
-       id_sys_shutdown,
-       id_sys_sendfile,
-       id_sys_sendfile64,
-       id_sys_setsockopt,
-       id_sys_getsockopt,
-       id_sys_bind,
-       id_sys_connect,
-       id_sys_accept,
-       id_sys_accept4,
-       id_sys_getsockname,
-       id_sys_getpeername,
-       id_sys_send,
-       id_sys_sendto,
-       id_sys_sendmsg,
-       id_sys_sendmmsg,
-       id_sys_recv,
-       id_sys_recvfrom,
-       id_sys_recvmsg,
-       id_sys_recvmmsg,
-       id_sys_socket,
-       id_sys_socketpair,
-/* TODO:
- *     id_sys_socketcall,
- */
-       id_sys_listen
-};
-
-static enum syscall_id id_process[] = {
-       id_sys_exit,
-       id_sys_exit_group,
-       id_sys_wait4,
-       id_sys_waitid,
-/* TODO:
- *     id_sys_waitpid,
- */
-       id_sys_rt_tgsigqueueinfo,
-       id_sys_unshare,
-       id_sys_fork,
-       id_sys_vfork,
-/* TODO: add support CONFIG_CLONE_BACKWARDS
- *     id_sys_clone,
- *     id_sys_clone,
- */
-       id_sys_execve
-};
-
-static enum syscall_id id_signal[] = {
-       id_sys_sigpending,
-       id_sys_sigprocmask,
-/* TODO:
- *     id_sys_sigaltstack,
- */
-/* TODO: add support CONFIG_OLD_SIGSUSPEND and CONFIG_OLD_SIGSUSPEND3
- *     id_sys_sigsuspend,
- *     id_sys_sigsuspend,
- */
-       id_sys_rt_sigsuspend,
-       id_sys_sigaction,
-       id_sys_rt_sigaction,
-       id_sys_rt_sigprocmask,
-       id_sys_rt_sigtimedwait,
-       id_sys_rt_tgsigqueueinfo,
-       id_sys_kill,
-       id_sys_tgkill,
-/* TODO:
- *     id_sys_signal,
- */
-       id_sys_pause,
-       id_sys_signalfd,
-       id_sys_signalfd4
-};
-
-static enum syscall_id id_desc[] = {
-       id_sys_fgetxattr,
-       id_sys_flistxattr,
-       id_sys_fremovexattr,
-/* TODO:
- *     id_sys_fadvise64_64,
- */
-       id_sys_pipe2,
-       id_sys_dup3,
-       id_sys_sendfile,
-       id_sys_sendfile64,
-       id_sys_preadv,
-       id_sys_pwritev,
-       id_sys_epoll_create1,
-       id_sys_epoll_ctl,
-       id_sys_epoll_wait,
-       id_sys_epoll_pwait,
-       id_sys_inotify_init,
-       id_sys_inotify_init1,
-       id_sys_inotify_add_watch,
-       id_sys_inotify_rm_watch,
-       id_sys_mknodat,
-       id_sys_mkdirat,
-       id_sys_unlinkat,
-       id_sys_symlinkat,
-       id_sys_linkat,
-       id_sys_renameat,
-       id_sys_futimesat,
-       id_sys_faccessat,
-       id_sys_fchmodat,
-       id_sys_fchownat,
-       id_sys_openat,
-/* TODO:
- *     id_sys_newfstatat,
- */
-       id_sys_readlinkat,
-       id_sys_utimensat,
-       id_sys_splice,
-       id_sys_vmsplice,
-       id_sys_tee,
-       id_sys_signalfd,
-       id_sys_signalfd4,
-       id_sys_timerfd_create,
-       id_sys_timerfd_settime,
-       id_sys_timerfd_gettime,
-       id_sys_eventfd,
-       id_sys_eventfd2,
-       id_sys_fallocate,
-       id_sys_pselect6,
-       id_sys_ppoll,
-       id_sys_fanotify_init,
-       id_sys_fanotify_mark,
-       id_sys_syncfs,
-/* TODO:
- *     id_sys_mmap_pgoff,
- *     id_sys_old_mmap,
- */
-       id_sys_name_to_handle_at,
-       id_sys_setns
-};
-
-/**
- * @def CREATE_FEATURE
- * Feature initialization.
- */
-#define CREATE_FEATURE(x, _type)                               \
-{                                                              \
-       .cnt = sizeof(x) / sizeof(enum syscall_id),             \
-       .feature_list = x,                                      \
-       .type = _type,                                          \
-       .enable = 0                                             \
-}
-
-static struct feature features[] = {
-       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)
-};
-
-/**
- * @enum
- * Defines feature_cnt.
- */
-enum {
-       feature_cnt = sizeof(features) / sizeof(struct feature)
-};
-
-static int feature_index(struct feature *f)
-{
-       return f - features;
-}
diff --git a/ks_features/file_ops.c b/ks_features/file_ops.c
deleted file mode 100644 (file)
index 7954528..0000000
+++ /dev/null
@@ -1,751 +0,0 @@
-#include <linux/kconfig.h>
-
-#ifndef CONFIG_SWAP_HOOK_SYSCALL
-
-#include <linux/module.h>
-#include <linux/dcache.h>
-#include <linux/percpu.h>
-#include <linux/namei.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <writer/event_filter.h>
-#include "ks_map.h"
-#include "ksf_msg.h"
-#include "file_ops.h"
-
-#define FOPS_PREFIX "[FILE_OPS] "
-
-#define PT_FILE 0x4 /* probe type FILE(04) */
-
-/* path buffer size */
-enum { PATH_LEN = 512 };
-
-struct file_probe {
-       int id;
-       const char *args;
-       int subtype;
-       struct kretprobe rp;
-};
-
-#define to_file_probe(_rp) container_of(_rp, struct file_probe, rp)
-
-/* common private data */
-struct file_private {
-       struct dentry *dentry;
-};
-
-/* open/creat private data */
-struct open_private {
-       int dfd;
-       const char __user *name;
-       int ret;
-};
-
-/* locks private data */
-struct flock_private {
-       struct dentry *dentry;
-       int subtype;
-};
-
-#define DECLARE_HANDLER(_name) \
-       int _name(struct kretprobe_instance *, struct pt_regs *)
-
-/* generic handlers forward declaration */
-static DECLARE_HANDLER(generic_entry_handler);
-static DECLARE_HANDLER(generic_ret_handler);
-/* open/creat handlers */
-static DECLARE_HANDLER(open_entry_handler);
-static DECLARE_HANDLER(open_ret_handler);
-/* lock handlers */
-static DECLARE_HANDLER(lock_entry_handler);
-static DECLARE_HANDLER(lock_ret_handler);
-/* filp_close helper handlers */
-static DECLARE_HANDLER(filp_close_entry_handler);
-static DECLARE_HANDLER(filp_close_ret_handler);
-
-#define FILE_OPS_OPEN_LIST \
-       X(sys_open, sdd), \
-       X(sys_openat, dsdd), \
-       X(sys_creat, sd)
-
-#define FILE_OPS_CLOSE_LIST \
-       X(sys_close, d)
-
-#define FILE_OPS_READ_LIST \
-       X(sys_read, dpd), \
-       X(sys_readv, dpd), \
-       X(sys_pread64, dpxx), \
-       X(sys_preadv, dpxxx)
-
-#define FILE_OPS_WRITE_LIST \
-       X(sys_write, dpd), \
-       X(sys_writev, dpd), \
-       X(sys_pwrite64, dpxx), \
-       X(sys_pwritev, dpxxx)
-
-#define FILE_OPS_LOCK_LIST \
-       X(sys_fcntl, ddd), \
-       X(sys_fcntl64, ddd), \
-       X(sys_flock, dd)
-
-#define FILE_OPS_LIST \
-       FILE_OPS_OPEN_LIST, \
-       FILE_OPS_CLOSE_LIST, \
-       FILE_OPS_READ_LIST, \
-       FILE_OPS_WRITE_LIST, \
-       FILE_OPS_LOCK_LIST
-
-#define X(_name, _args) \
-       id_##_name
-enum {
-       FILE_OPS_LIST
-};
-#undef X
-
-#define __FILE_PROBE_INITIALIZER(_name, _args, _subtype, _dtype, _entry, _ret) \
-       { \
-               .id = id_##_name, \
-               .args = #_args, \
-               .subtype = _subtype, \
-               .rp = { \
-                       .kp.symbol_name = #_name, \
-                       .data_size = sizeof(_dtype), \
-                       .entry_handler = _entry, \
-                       .handler = _ret, \
-               } \
-       }
-
-static struct file_probe fprobes[] = {
-#define X(_name, _args) \
-       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_OPEN, \
-                                               struct open_private, \
-                                               open_entry_handler, \
-                                               open_ret_handler)
-       FILE_OPS_OPEN_LIST,
-#undef X
-
-#define X(_name, _args) \
-       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_CLOSE, \
-                                               struct file_private, \
-                                               generic_entry_handler, \
-                                               generic_ret_handler)
-       FILE_OPS_CLOSE_LIST,
-#undef X
-
-#define X(_name, _args) \
-       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_READ, \
-                                               struct file_private, \
-                                               generic_entry_handler, \
-                                               generic_ret_handler)
-       FILE_OPS_READ_LIST,
-#undef X
-
-#define X(_name, _args) \
-       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_WRITE, \
-                                               struct file_private, \
-                                               generic_entry_handler, \
-                                               generic_ret_handler)
-       FILE_OPS_WRITE_LIST,
-#undef X
-
-#define X(_name, _args) \
-       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_OTHER, \
-                                               struct flock_private, \
-                                               lock_entry_handler, \
-                                               lock_ret_handler)
-       FILE_OPS_LOCK_LIST
-#undef X
-};
-
-static void *fops_key_func(void *);
-static int fops_cmp_func(void *, void *);
-
-/* percpu buffer to hold the filepath inside handlers */
-static DEFINE_PER_CPU(char[PATH_LEN], __path_buf);
-
-/* map to hold 'interesting' files */
-static DEFINE_MAP(__map, fops_key_func, fops_cmp_func);
-static DEFINE_RWLOCK(__map_lock);
-
-/* enabled/disabled flag */
-static int fops_enabled;
-static DEFINE_MUTEX(fops_lock);
-
-/* GET/PUT debug stuff */
-static int file_get_put_balance;
-static int dentry_get_put_balance;
-
-/* helper probe */
-static struct kretprobe filp_close_krp = {
-       .kp.symbol_name = "filp_close",
-       .data_size = 0,
-       .entry_handler = filp_close_entry_handler,
-       .handler = filp_close_ret_handler
-};
-
-/* should be called only from handlers (with preemption disabled) */
-static inline char *fops_path_buf(void)
-{
-       return __get_cpu_var(__path_buf);
-}
-
-static inline unsigned fops_dcount(const struct dentry *dentry)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
-       return dentry->d_count;
-#else
-       return d_count(dentry);
-#endif
-}
-
-/* kernel function args */
-#define fops_karg(_type, _regs, _idx) ((_type)swap_get_karg(_regs, _idx))
-/* syscall args */
-#define fops_sarg(_type, _regs, _idx) ((_type)swap_get_sarg(_regs, _idx))
-/* retval */
-#define fops_ret(_type, _regs) ((_type)regs_return_value(_regs))
-
-#define F_ADDR(_rp) ((unsigned long)(_rp)->kp.addr) /* function address */
-#define R_ADDR(_ri) ((unsigned long)(_ri)->ret_addr) /* return adress */
-
-static void *fops_key_func(void *data)
-{
-       /* use ((struct dentry *)data)->d_inode pointer as map key to handle
-        * symlinks/hardlinks the same way as the original file */
-       return data;
-}
-
-static int fops_cmp_func(void *key_a, void *key_b)
-{
-       return key_a - key_b;
-}
-
-static inline struct map *__get_map(void)
-{
-       return &__map;
-}
-
-static inline struct map *get_map_read(void)
-{
-       read_lock(&__map_lock);
-
-       return __get_map();
-}
-
-static inline void put_map_read(struct map *map)
-{
-       read_unlock(&__map_lock);
-}
-
-static inline struct map *get_map_write(void)
-{
-       write_lock(&__map_lock);
-
-       return __get_map();
-}
-
-static inline void put_map_write(struct map *map)
-{
-       write_unlock(&__map_lock);
-}
-
-static struct file *__fops_fget(int fd)
-{
-       struct file *file;
-
-       file = fget(fd);
-       if (IS_ERR_OR_NULL(file))
-               file = NULL;
-       else
-               file_get_put_balance++;
-
-       return file;
-}
-
-static void __fops_fput(struct file *file)
-{
-       file_get_put_balance--;
-       fput(file);
-}
-
-static struct dentry *__fops_dget(struct dentry *dentry)
-{
-       dentry_get_put_balance++;
-
-       return dget(dentry);
-}
-
-static void __fops_dput(struct dentry *dentry)
-{
-       dentry_get_put_balance--;
-       dput(dentry);
-}
-
-static int fops_dinsert(struct dentry *dentry)
-{
-       struct map *map;
-       int ret;
-
-       map = get_map_write();
-       ret = insert(map, __fops_dget(dentry));
-       put_map_write(map);
-
-       if (ret)
-               __fops_dput(dentry);
-
-       /* it's ok if dentry is already inserted */
-       return ret == -EEXIST ? 0 : ret;
-}
-
-static struct dentry *fops_dsearch(struct dentry *dentry)
-{
-       struct dentry *found;
-       struct map *map;
-
-       map = get_map_read();
-       found = search(map, map->key_f(dentry));
-       put_map_read(map);
-
-       return found;
-}
-
-static struct dentry *fops_dremove(struct dentry *dentry)
-{
-       struct dentry *removed;
-       struct map *map;
-
-       map = get_map_write();
-       removed = remove(map, map->key_f(dentry));
-       put_map_write(map);
-
-       if (removed)
-               __fops_dput(removed);
-
-       return removed;
-}
-
-static int fops_fcheck(struct task_struct *task, struct file *file)
-{
-       struct dentry *dentry;
-
-       if (!task || !file)
-               return -EINVAL;
-
-       dentry = file->f_path.dentry;
-
-       /* check if it is a regular file */
-       if (!S_ISREG(dentry->d_inode->i_mode))
-               return -EBADF;
-
-       if (check_event(task))
-               /* it is 'our' task: just add the dentry to the map */
-               return fops_dinsert(dentry) ? : -EAGAIN;
-       else
-               /* not 'our' task: check if the file is 'interesting' */
-               return fops_dsearch(dentry) ? 0 : -ESRCH;
-}
-
-static char *fops_fpath(struct file *file, char *buf, int buflen)
-{
-       char *filename;
-
-       path_get(&file->f_path);
-       filename = d_path(&file->f_path, buf, buflen);
-       path_put(&file->f_path);
-
-       if (IS_ERR_OR_NULL(filename)) {
-               printk(FOPS_PREFIX "d_path FAILED: %ld\n", PTR_ERR(filename));
-               buf[0] = '\0';
-               filename = buf;
-       }
-
-       return filename;
-}
-
-static int generic_entry_handler(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-
-       if (rp) {
-               struct file_probe *fprobe = to_file_probe(rp);
-               struct file_private *priv = (struct file_private *)ri->data;
-               int fd = fops_sarg(int, regs, 0);
-               struct file *file = __fops_fget(fd);
-
-               if (fops_fcheck(current, file) == 0) {
-                       char *buf = fops_path_buf();
-
-                       ksf_msg_file_entry(fd, fprobe->subtype,
-                                          fops_fpath(file, buf, PATH_LEN));
-
-                       priv->dentry = file->f_path.dentry;
-               } else {
-                       priv->dentry = NULL;
-               }
-
-               if (file)
-                       __fops_fput(file);
-       }
-
-       return 0;
-}
-
-static int generic_ret_handler(struct kretprobe_instance *ri,
-                              struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-       struct file_private *priv = (struct file_private *)ri->data;
-
-       if (rp && priv->dentry)
-               ksf_msg_file_exit(regs, 'x');
-
-       return 0;
-}
-
-static int open_private_init(const char *args, struct pt_regs *regs,
-                            struct open_private *priv)
-{
-       int ret = 0;
-
-       switch (args[0]) {
-       case 'd': /* file name: relative to fd */
-               if (args[1] != 's') {
-                       ret = -EINVAL;
-                       break;
-               }
-               priv->dfd = fops_sarg(int, regs, 0);
-               priv->name = fops_sarg(const char __user *, regs, 1);
-               break;
-       case 's': /* file name: absolute or relative to CWD */
-               priv->dfd = AT_FDCWD;
-               priv->name = fops_sarg(const char __user *, regs, 0);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       priv->ret = ret;
-
-       return ret;
-}
-
-static int open_entry_handler(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-
-       if (rp) {
-               struct file_probe *fprobe = to_file_probe(rp);
-               struct open_private *priv = (struct open_private *)ri->data;
-
-               open_private_init(fprobe->args, regs, priv);
-               /* FIXME entry event will be sent in open_ret_handler: cannot
-                * perform a file lookup in atomic context */
-       }
-
-       return 0;
-}
-
-static int open_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-       struct open_private *priv = (struct open_private *)ri->data;
-
-       if (rp && priv->ret == 0) {
-               struct file_probe *fprobe = to_file_probe(rp);
-               int fd = fops_ret(int, regs);
-               struct file *file = __fops_fget(fd);
-
-               if (fops_fcheck(current, file) == 0) {
-                       char *buf = fops_path_buf();
-                       const char *path = fops_fpath(file, buf, PATH_LEN);
-
-                       ksf_msg_file_entry_open(fd, fprobe->subtype,
-                                               path, priv->name);
-                       ksf_msg_file_exit(regs, 'x');
-               }
-
-               if (file)
-                       __fops_fput(file);
-       }
-
-       return 0;
-}
-
-/* wrapper for 'struct flock*' data */
-struct lock_arg {
-       int type;
-       int whence;
-       s64 start;
-       s64 len;
-};
-
-/* TODO copy_from_user */
-#define __lock_arg_init(_type, _regs, _arg) \
-       do { \
-               _type __user *flock = fops_sarg(_type __user *, _regs, 2); \
-               _arg->type = flock->l_type; \
-               _arg->whence = flock->l_whence; \
-               _arg->start = flock->l_start; \
-               _arg->len = flock->l_len; \
-       } while (0)
-
-static int lock_arg_init(int id, struct pt_regs *regs, struct lock_arg *arg)
-{
-       unsigned int cmd = fops_sarg(unsigned int, regs, 1);
-       int ret = 0;
-
-       switch (id) {
-       case id_sys_fcntl:
-               if (cmd == F_SETLK || cmd == F_SETLKW)
-                       __lock_arg_init(struct flock, regs, arg);
-               else
-                       ret = -EINVAL;
-               break;
-       case id_sys_fcntl64:
-               if (cmd == F_SETLK64 || cmd == F_SETLKW64)
-                       __lock_arg_init(struct flock64, regs, arg);
-               else if (cmd == F_SETLK || cmd == F_SETLKW)
-                       __lock_arg_init(struct flock, regs, arg);
-               else
-                       ret = -EINVAL;
-               break;
-       case id_sys_flock: /* TODO is it really needed? */
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static int lock_entry_handler(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-
-       if (rp) {
-               struct file_probe *fprobe = to_file_probe(rp);
-               struct flock_private *priv = (struct flock_private *)ri->data;
-               int fd = fops_sarg(int, regs, 0);
-               struct file *file = __fops_fget(fd);
-
-               if (fops_fcheck(current, file) == 0) {
-                       int subtype = fprobe->subtype;
-                       struct lock_arg arg;
-                       char *buf, *filepath;
-
-                       buf = fops_path_buf();
-                       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;
-                               ksf_msg_file_entry_lock(fd, subtype, filepath,
-                                                       arg.type, arg.whence,
-                                                       arg.start, arg.len);
-                       } else {
-                               ksf_msg_file_entry(fd, subtype, filepath);
-                       }
-
-                       priv->dentry = file->f_path.dentry;
-                       priv->subtype = subtype;
-               } else {
-                       priv->dentry = NULL;
-               }
-
-               if (file)
-                       __fops_fput(file);
-       }
-
-       return 0;
-}
-
-static int lock_ret_handler(struct kretprobe_instance *ri,
-                           struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-       struct flock_private *priv = (struct flock_private *)ri->data;
-
-       if (rp && priv->dentry)
-               ksf_msg_file_exit(regs, 'x');
-
-       return 0;
-}
-
-static int filp_close_entry_handler(struct kretprobe_instance *ri,
-                                   struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-       struct file *file = fops_karg(struct file *, regs, 0);
-
-       if (rp && file && file_count(file)) {
-               struct dentry *dentry = file->f_path.dentry;
-
-               /* release the file if it is going to be removed soon */
-               if (dentry && fops_dcount(dentry) == 2)
-                       fops_dremove(dentry);
-       }
-
-       return 0;
-}
-
-static int filp_close_ret_handler(struct kretprobe_instance *ri,
-                                 struct pt_regs *regs)
-{
-       return 0;
-}
-
-static void fops_unregister_probes(struct file_probe *fprobes, int cnt)
-{
-       int i = cnt;
-
-       /* probes are unregistered in reverse order */
-       while (--i >= 0) {
-               struct kretprobe *rp = &fprobes[i].rp;
-
-               swap_unregister_kretprobe(rp);
-               printk(FOPS_PREFIX "'%s/%08lx' kretprobe unregistered  (%d)\n",
-                      rp->kp.symbol_name, F_ADDR(rp), i);
-       }
-
-       /* unregister helper probes */
-       swap_unregister_kretprobe(&filp_close_krp);
-}
-
-static int fops_register_probes(struct file_probe *fprobes, int cnt)
-{
-       struct kretprobe *rp = &filp_close_krp;
-       int ret, i = 0;
-
-       /* register helper probes */
-       ret = swap_register_kretprobe(rp);
-       if (ret)
-               goto fail;
-
-       /* register syscalls */
-       for (i = 0; i < cnt; i++) {
-               rp = &fprobes[i].rp;
-
-               if (!rp->entry_handler)
-                       rp->entry_handler = generic_entry_handler;
-
-               if (!rp->handler)
-                       rp->handler = generic_ret_handler;
-
-               ret = swap_register_kretprobe(rp);
-               if (ret)
-                       goto fail_unreg;
-
-               printk(FOPS_PREFIX "'%s/%08lx' kretprobe registered (%d)\n",
-                      rp->kp.symbol_name, F_ADDR(rp), i);
-       }
-
-       return 0;
-
-fail_unreg:
-       fops_unregister_probes(fprobes, i);
-
-fail:
-       printk(FOPS_PREFIX "Failed to register probe: %s\n",
-              rp->kp.symbol_name);
-
-       return ret;
-}
-
-static char *__fops_dpath(struct dentry *dentry, char *buf, int buflen)
-{
-       static const char *NA = "N/A";
-       char *filename = dentry_path_raw(dentry, buf, buflen);
-
-       if (IS_ERR_OR_NULL(filename)) {
-               printk(FOPS_PREFIX "dentry_path_raw FAILED: %ld\n",
-                      PTR_ERR(filename));
-               strncpy(buf, NA, buflen);
-               filename = buf;
-       }
-
-       return filename;
-}
-
-/* just a simple wrapper for passing to clear function */
-static int __fops_dput_wrapper(void *data, void *arg)
-{
-       static char buf[PATH_LEN]; /* called under write lock => static is ok */
-       struct dentry *dentry = data;
-       struct inode *inode = dentry->d_inode;
-
-       printk(FOPS_PREFIX "Releasing dentry(%p/%p/%d): %s\n",
-              dentry, inode, inode ? inode->i_nlink : 0,
-             __fops_dpath(dentry, buf, PATH_LEN));
-       __fops_dput(dentry);
-
-       return 0;
-}
-
-bool file_ops_is_init(void)
-{
-       return fops_enabled;
-}
-
-int file_ops_init(void)
-{
-       int ret = -EINVAL;
-
-       mutex_lock(&fops_lock);
-
-       if (fops_enabled) {
-               printk(FOPS_PREFIX "Handlers already enabled\n");
-               goto unlock;
-       }
-
-       ret = fops_register_probes(fprobes, ARRAY_SIZE(fprobes));
-       if (ret == 0)
-               fops_enabled = 1;
-
-unlock:
-       mutex_unlock(&fops_lock);
-
-       return ret;
-}
-
-void file_ops_exit(void)
-{
-       struct map *map;
-
-       mutex_lock(&fops_lock);
-
-       if (!fops_enabled) {
-               printk(FOPS_PREFIX "Handlers not enabled\n");
-               goto unlock;
-       }
-
-       /* 1. unregister probes */
-       fops_unregister_probes(fprobes, ARRAY_SIZE(fprobes));
-
-       /* 2. clear the map */
-       map = get_map_write();
-       printk(FOPS_PREFIX "Clearing map: entries(%d)\n", map->size);
-       clear(map, __fops_dput_wrapper, NULL);
-       WARN(file_get_put_balance, "File GET/PUT balance: %d\n",
-            file_get_put_balance);
-       WARN(dentry_get_put_balance, "Dentry GET/PUT balance: %d\n",
-            dentry_get_put_balance);
-       put_map_write(map);
-
-       /* 3. drop the flag */
-       fops_enabled = 0;
-
-unlock:
-       mutex_unlock(&fops_lock);
-}
-
-#endif /* CONFIG_SWAP_HOOK_SYSCALL */
diff --git a/ks_features/file_ops.h b/ks_features/file_ops.h
deleted file mode 100644 (file)
index b8344e7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __FILE_OPS__
-#define __FILE_OPS__
-
-#include <linux/types.h>
-#include <linux/printk.h>
-
-
-#define FOPS_PREFIX "[FILE_OPS] "
-
-
-/* TODO: add support CONFIG_SWAP_HOOK_SYSCALL */
-#ifdef CONFIG_SWAP_HOOK_SYSCALL
-
-static inline bool file_ops_is_init(void)
-{
-       return 0;
-}
-
-static inline bool file_ops_init(void)
-{
-       pr_info(FOPS_PREFIX "file_ops is not supported\n");
-       return 0;
-}
-
-void file_ops_exit(void)
-{
-}
-
-#else /* CONFIG_SWAP_HOOK_SYSCALL */
-
-bool file_ops_is_init(void);
-int file_ops_init(void);
-void file_ops_exit(void);
-
-#endif /* CONFIG_SWAP_HOOK_SYSCALL */
-
-#endif /* __FILE_OPS__ */
diff --git a/ks_features/ks_feature_hook.c b/ks_features/ks_feature_hook.c
deleted file mode 100644 (file)
index a0e60f7..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @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, 2016
- *
- * @section DESCRIPTION
- *
- *  SWAP kernel features
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-#include <writer/event_filter.h>
-#include <swap/hook_syscall.h>
-#include <asm/syscall.h>
-#include "ksf_msg.h"
-#include "ks_features.h"
-#include "syscall_list.h"
-#include "features_data.c"
-#include "writer/kernel_operations.h"
-#include "ks_features_data.h"
-
-
-static void syscall_entry_hendler(struct hook_syscall *self,
-                                 struct pt_regs *regs)
-{
-       if (check_event(current)) {
-               struct ks_probe *ksp = container_of(self, struct ks_probe, hook);
-               const char *fmt = ksp->args;
-               const unsigned long func_addr = ksp->sys_addr;
-               enum probe_t type = ksp->type;
-
-               ksf_msg_entry(regs, func_addr, type, fmt);
-       }
-}
-
-static void syscall_exit_hendler(struct hook_syscall *self,
-                                struct pt_regs *regs)
-{
-       if (check_event(current)) {
-               struct ks_probe *ksp = container_of(self, struct ks_probe, hook);
-               const unsigned long func_addr = ksp->sys_addr;
-               const unsigned long ret_addr = get_regs_ret_func(regs);
-               enum probe_t type = ksp->type;
-
-               ksf_msg_exit(regs, func_addr, ret_addr, type, 'x');
-       }
-}
-
-static int register_syscall(size_t id)
-{
-       int ret = 0;
-
-       if (id >= syscall_cnt)
-               return -EINVAL;
-
-       ksp[id].hook.entry = syscall_entry_hendler;
-       ksp[id].hook.exit = syscall_exit_hendler;
-#ifdef CONFIG_COMPAT
-       /* FIXME: add hook_syscall_reg() */
-       ret = hook_syscall_reg_compat(&ksp[id].hook, ksp[id].id);
-#else
-       ret = hook_syscall_reg(&ksp[id].hook, ksp[id].id);
-#endif
-
-       if (ret) {
-               pr_err("ERROR: cannot register hook '%s' id=%zd sysid=%u\n",
-                      get_sys_name(id), id, ksp[id].id);
-       }
-
-       return ret;
-}
-
-static int unregister_syscall(size_t id)
-{
-       if (id >= syscall_cnt)
-               return -EINVAL;
-
-#ifdef CONFIG_COMPAT
-       /* FIXME: add hook_syscall_unreg() */
-       hook_syscall_unreg_compat(&ksp[id].hook);
-#else
-       hook_syscall_unreg(&ksp[id].hook);
-#endif
-
-       return 0;
-}
-
-static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
-{
-       size_t i;
-       int ret = 0;
-
-       for (i = 0; i < cnt; i++) {
-               ret = unregister_syscall(id_p[i]);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static int init_syscalls(void)
-{
-       size_t i, sys_id;
-       unsigned long addr;
-       const char *name;
-       const char *sys_call_table_name;
-       unsigned long *syscall_table;
-
-#ifdef CONFIG_COMPAT
-       sys_call_table_name = "compat_sys_call_table";
-#else
-       sys_call_table_name = "sys_call_table";
-#endif
-
-       syscall_table = (unsigned long *)swap_ksyms(sys_call_table_name);
-       if (syscall_table == NULL) {
-               pr_warn("WARN: '%s' not found\n", sys_call_table_name);
-               return 0;
-       }
-
-       for (i = 0; i < syscall_cnt; ++i) {
-               name = get_sys_name(i);
-               sys_id = ksp[i].id;
-               addr = syscall_table[sys_id];
-               if (addr == 0)
-                       pr_warn("WARN: %s() not found\n", name);
-
-               ksp[i].sys_addr = addr;
-       }
-
-       return 0;
-}
diff --git a/ks_features/ks_feature_kprobe.c b/ks_features/ks_feature_kprobe.c
deleted file mode 100644 (file)
index 5a47056..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @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, 2016
- *
- * @section DESCRIPTION
- *
- *  SWAP kernel features
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <ksyms/ksyms.h>
-#include <kprobe/swap_kprobes.h>
-#include <master/swap_initializer.h>
-#include <writer/event_filter.h>
-#include "ksf_msg.h"
-#include "ks_features.h"
-#include "features_data.c"
-#include "ks_features_data.h"
-
-
-/* ========================= HANDLERS ========================= */
-static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-
-       if (rp && check_event(current)) {
-               struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
-               const char *fmt = ksp->args;
-               const unsigned long addr = ksp->rp.kp.addr;
-               enum probe_t type = ksp->type;
-
-               ksf_msg_entry(regs, addr, type, fmt);
-       }
-
-       return 0;
-}
-
-static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct kretprobe *rp = ri->rp;
-
-       if (rp && check_event(current)) {
-               struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
-               const unsigned long func_addr = rp->kp.addr;
-               const unsigned long ret_addr = (unsigned long)ri->ret_addr;
-               enum probe_t type = ksp->type;
-
-               ksf_msg_exit(regs, func_addr, ret_addr, type, 'x');
-       }
-
-       return 0;
-}
-
-/* ========================= HANDLERS ========================= */
-
-
-
-
-
-static int register_syscall(size_t id)
-{
-       int ret;
-
-       if (ksp[id].rp.kp.addr == 0)
-               return 0;
-
-       ksp[id].rp.entry_handler = entry_handler;
-       ksp[id].rp.handler = ret_handler;
-
-       ret = swap_register_kretprobe(&ksp[id].rp);
-
-       return ret;
-}
-
-static int unregister_syscall(size_t id)
-{
-       if (ksp[id].rp.kp.addr == 0)
-               return 0;
-
-       swap_unregister_kretprobe(&ksp[id].rp);
-
-       return 0;
-}
-
-static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
-{
-       struct kretprobe **rpp;
-       const size_t end = ((size_t) 0) - 1;
-       size_t i = 0, id;
-       int ret = 0;
-
-       if (cnt == 1)
-               return unregister_syscall(id_p[0]);
-
-       rpp = kmalloc(sizeof(*rpp) * cnt, GFP_KERNEL);
-       --cnt;
-       if (rpp == NULL) {
-               for (; cnt != end; --cnt) {
-                       ret = unregister_syscall(id_p[cnt]);
-                       if (ret)
-                               return ret;
-               }
-               return ret;
-       }
-
-       for (; cnt != end; --cnt) {
-               id = id_p[cnt];
-               if (ksp[id].rp.kp.addr) {
-                               rpp[i] = &ksp[id].rp;
-                               ++i;
-               }
-       }
-
-       swap_unregister_kretprobes(rpp, i);
-       kfree(rpp);
-
-       return 0;
-}
-
-static int init_syscalls(void)
-{
-       size_t i;
-       unsigned long addr, ni_syscall;
-       const char *name;
-
-       ni_syscall = swap_ksyms("sys_ni_syscall");
-
-       for (i = 0; i < syscall_cnt; ++i) {
-               name = get_sys_name(i);
-               addr = swap_ksyms(name);
-               if (addr == 0) {
-                       pr_err("ERROR: %s() not found\n", name);
-               } else if (ni_syscall == addr) {
-                       pr_err("WARN: %s is not install\n", name);
-                       addr = 0;
-               }
-
-               ksp[i].rp.kp.addr = addr;
-       }
-
-       return 0;
-}
diff --git a/ks_features/ks_features.c b/ks_features/ks_features.c
deleted file mode 100644 (file)
index aa2adab..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/**
- * ks_features/ks_features.c
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @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
- *
- *  SWAP kernel features
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-#include <writer/event_filter.h>
-#include "ksf_msg.h"
-#include "ks_features.h"
-#include "file_ops.h"
-
-#ifdef CONFIG_SWAP_HOOK_SYSCALL
-# include "ks_feature_hook.c"
-#else /* CONFIG_SWAP_HOOK_SYSCALL */
-# include "ks_feature_kprobe.c"
-#endif /* CONFIG_SWAP_HOOK_SYSCALL */
-
-
-
-/* ====================== SWITCH_CONTEXT ======================= */
-static DEFINE_MUTEX(mutex_sc_enable);
-static int sc_enable;
-
-
-#ifdef CONFIG_SWAP_HOOK_SWITCH_TO
-
-#include <swap/hook_switch_to.h>
-
-
-static void ksf_switch(struct task_struct *prev, struct task_struct *next)
-{
-       if (check_event(prev))
-               ksf_switch_entry(prev);
-       if (check_event(next))
-               ksf_switch_exit(next);
-}
-
-static struct swap_hook_ctx hook_ctx = {
-       .hook = ksf_switch,
-};
-
-/**
- * @brief Get scheduler address.
- *
- * @return 0 on success, negative error code on error.
- */
-int init_switch_context(void)
-{
-       return 0;
-}
-
-static int register_ctx_handler(void)
-{
-       return swap_hook_ctx_reg(&hook_ctx);
-}
-
-static void unregister_ctx_handler(void)
-{
-       swap_hook_ctx_unreg(&hook_ctx);
-}
-
-#else  /* CONFIG_SWAP_HOOK_SWITCH_TO */
-
-static int switch_entry_handler(struct kretprobe_instance *ri,
-                               struct pt_regs *regs)
-{
-       if (check_event(current))
-               ksf_switch_entry(current);
-
-       return 0;
-}
-
-static int switch_ret_handler(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       if (check_event(current))
-               ksf_switch_exit(current);
-
-       return 0;
-}
-
-/**
- * @var switch_rp
- * Kretprobe for scheduler.
- */
-struct kretprobe switch_rp = {
-       .entry_handler = switch_entry_handler,
-       .handler = switch_ret_handler
-};
-
-/**
- * @brief Get scheduler address.
- *
- * @return 0 on success, negative error code on error.
- */
-int init_switch_context(void)
-{
-       switch_rp.kp.addr = swap_ksyms("__switch_to");
-       if (switch_rp.kp.addr == 0) {
-               printk(KERN_INFO "ERROR: not found '__switch_to'\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int register_ctx_handler(void)
-{
-       return swap_register_kretprobe(&switch_rp);
-}
-
-static void unregister_ctx_handler(void)
-{
-       swap_unregister_kretprobe(&switch_rp);
-}
-#endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
-
-
-/**
- * @brief Unregisters probe on context switching.
- *
- * @return Void.
- */
-void exit_switch_context(void)
-{
-       if (sc_enable)
-               unregister_ctx_handler();
-}
-
-static int register_switch_context(void)
-{
-       int ret = -EINVAL;
-
-       mutex_lock(&mutex_sc_enable);
-       if (sc_enable) {
-               printk(KERN_INFO "switch context profiling is already run!\n");
-               goto unlock;
-       }
-
-       ret = register_ctx_handler();
-       if (ret == 0)
-               sc_enable = 1;
-
-unlock:
-       mutex_unlock(&mutex_sc_enable);
-
-       return ret;
-}
-
-static int unregister_switch_context(void)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_sc_enable);
-       if (sc_enable == 0) {
-               printk(KERN_INFO "switch context profiling is not running!\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       unregister_ctx_handler();
-
-       sc_enable = 0;
-unlock:
-       mutex_unlock(&mutex_sc_enable);
-
-       return ret;
-}
-/* ====================== SWITCH_CONTEXT ======================= */
-
-
-
-
-static void set_pst(struct feature *f, size_t id)
-{
-       ksp[id].type |= f->type;
-}
-
-static void unset_pst(struct feature *f, size_t id)
-{
-       ksp[id].type &= !f->type;
-}
-
-static void do_uninstall_features(struct feature *f, size_t i)
-{
-       int ret;
-       size_t *id_p;
-       size_t id;
-       size_t cnt = 0;
-       const size_t end = ((size_t) 0) - 1;
-
-       id_p = kmalloc(sizeof(id) * (i + 1), GFP_KERNEL);
-       /* NULL check is below in loop */
-
-       for (; i != end; --i) {
-               id = f->feature_list[i];
-
-               if (get_counter(id) == 0) {
-                       printk(KERN_INFO "syscall %s not installed\n",
-                              get_sys_name(id));
-                       kfree(id_p);
-                       BUG();
-               }
-
-               dec_counter(id);
-
-               if (get_counter(id) == 0) {
-                       if (id_p != NULL) {
-                               id_p[cnt] = id;
-                               ++cnt;
-                       } else {
-                               ret = unregister_syscall(id);
-                               if (ret)
-                                       printk(KERN_INFO "syscall %s uninstall error, ret=%d\n",
-                                                  get_sys_name(id), ret);
-                       }
-               }
-
-               unset_pst(f, id);
-       }
-
-       if (id_p != NULL) {
-               unregister_multiple_syscalls(id_p, cnt);
-               kfree(id_p);
-       }
-}
-
-static int do_install_features(struct feature *f)
-{
-       int ret;
-       size_t i, id;
-
-       for (i = 0; i < f->cnt; ++i) {
-               id = f->feature_list[i];
-               set_pst(f, id);
-
-               if (get_counter(id) == 0) {
-                       ret = register_syscall(id);
-                       if (ret) {
-                               printk(KERN_INFO "syscall %s install error, ret=%d\n",
-                                      get_sys_name(id), ret);
-
-                               do_uninstall_features(f, --i);
-                               return ret;
-                       }
-               }
-
-               inc_counter(id);
-       }
-
-       return 0;
-}
-
-static DEFINE_MUTEX(mutex_features);
-
-static int install_features(struct feature *f)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_features);
-       if (f->enable) {
-               printk(KERN_INFO "energy profiling is already run!\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       ret = do_install_features(f);
-
-       f->enable = 1;
-unlock:
-       mutex_unlock(&mutex_features);
-       return ret;
-}
-
-static int uninstall_features(struct feature *f)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_features);
-       if (f->enable == 0) {
-               printk(KERN_INFO "feature[%d] is not running!\n",
-                      feature_index(f));
-               ret = -EINVAL;
-               goto unlock;
-       }
-       do_uninstall_features(f, f->cnt - 1);
-       f->enable = 0;
-unlock:
-       mutex_unlock(&mutex_features);
-
-       return ret;
-}
-
-static struct feature *get_feature(enum feature_id id)
-{
-       if (id < 0 || id >= (int)feature_cnt)
-               return NULL;
-
-       return &features[id];
-}
-
-/**
- * @brief Sets probes related to specified feature.
- *
- * @param id Feature id.
- * @return 0 on success, negative error code on error.
- */
-int set_feature(enum feature_id id)
-{
-       struct feature *f;
-       int ret;
-
-       switch (id) {
-       case FID_SYSFILE_ACTIVITY:
-               ret = file_ops_init();
-               break;
-       case FID_SWITCH:
-               ret = register_switch_context();
-               break;
-       default:
-               f = get_feature(id);
-               ret = f ? install_features(f) : -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(set_feature);
-
-/**
- * @brief Unsets probes related to specified feature.
- *
- * @param id Feature id.
- * @return 0 on success, negative error code on error.
- */
-int unset_feature(enum feature_id id)
-{
-       struct feature *f;
-       int ret = 0;
-
-       switch (id) {
-       case FID_SYSFILE_ACTIVITY:
-               file_ops_exit();
-               break;
-       case FID_SWITCH:
-               ret = unregister_switch_context();
-               break;
-       default:
-               f = get_feature(id);
-               ret = f ? uninstall_features(f) : -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(unset_feature);
-
-static int init_syscall_features(void)
-{
-       return init_syscalls();
-}
-
-static void uninit_syscall_features(void)
-{
-       size_t id;
-
-       for (id = 0; id < syscall_cnt; ++id) {
-               if (get_counter(id) > 0)
-                       unregister_syscall(id);
-       }
-}
-
-
-static int once(void)
-{
-       int ret;
-
-       ret = init_switch_context();
-       if (ret)
-               return ret;
-
-       ret = init_syscall_features();
-
-       return ret;
-}
-
-static void core_uninit(void)
-{
-       uninit_syscall_features();
-       exit_switch_context();
-
-       if (file_ops_is_init())
-               file_ops_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(once, NULL, core_uninit, NULL, NULL);
-
-MODULE_LICENSE("GPL");
-
-/* debug */
-static void print_feature(struct feature *f)
-{
-       size_t i;
-
-       for (i = 0; i < f->cnt; ++i)
-               printk(KERN_INFO "    feature[%3zu]: %s\n", i,
-                      get_sys_name(f->feature_list[i]));
-}
-
-/**
- * @brief Prints features.
- *
- * @return Void.
- */
-void print_features(void)
-{
-       int i;
-
-       printk(KERN_INFO "print_features:\n");
-       for (i = 0; i < feature_cnt; ++i) {
-               printk(KERN_INFO "feature: %d\n", i);
-               print_feature(&features[i]);
-       }
-}
-
-/**
- * @brief Prints all syscalls.
- *
- * @return Void.
- */
-void print_all_syscall(void)
-{
-       int i;
-
-       printk(KERN_INFO "SYSCALL:\n");
-       for (i = 0; i < syscall_cnt; ++i)
-               printk(KERN_INFO "    [%2d] %s\n",
-                      get_counter(i), get_sys_name(i));
-}
-/* debug */
diff --git a/ks_features/ks_features.h b/ks_features/ks_features.h
deleted file mode 100644 (file)
index d75da5e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file ks_features/ks_features.h
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @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
- *
- * SWAP kernel features interface declaration.
- */
-
-
-#ifndef _KS_FEATURES_H
-#define _KS_FEATURES_H
-
-/**
- * @enum feature_id
- * Features ids
- */
-enum feature_id {
-       FID_FILE = 1,                   /**< File probes */
-       FID_IPC = 2,                    /**< Hz probes */
-       FID_PROCESS = 3,                /**< Process probes */
-       FID_SIGNAL = 4,                 /**< Signal probes */
-       FID_NET = 5,                    /**< Network probes */
-       FID_DESC = 6,                   /**< Description probes */
-       FID_SWITCH = 7,                 /**< Switch context probes */
-       FID_SYSFILE_ACTIVITY = 8        /**< System file activity */
-};
-
-int set_feature(enum feature_id id);
-int unset_feature(enum feature_id id);
-
-/* debug */
-void print_features(void);
-void print_all_syscall(void);
-/* debug */
-
-#endif /*  _KS_FEATURES_H */
diff --git a/ks_features/ks_features_data.c b/ks_features/ks_features_data.c
deleted file mode 100644 (file)
index 78ef3a0..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * @author Vitaliy Cherepanov: SWAP ks_features_data implement
- *
- * @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, 2016
- *
- * @section DESCRIPTION
- *
- *  SWAP kernel features
- */
-
-#include "syscall_list.h"
-#include "ks_features_data.h"
-#include "ksf_msg.h"
-
-
-/**
- * @struct ks_probe
- * @brief Kernel-space probe. Struct used as a container of syscall probes.
- * @var ks_probe::rp
- * Pointer to kretprobe.
- * @var ks_probe::counter
- * Installed probes counter.
- * @var ks_probe::args
- * Pointer to args format string.
- * @var ks_probe::type
- * Probe sub type.
- */
-
-#define CREATE_RP(name)                                                \
-{                                                              \
-       .entry_handler = NULL,                                  \
-       .handler = NULL                                         \
-}
-
-#define CREATE_HOOK_SYSCALL(name)                              \
-{                                                              \
-       .entry = NULL,                                  \
-       .exit = NULL                                    \
-}
-
-#define SYSCALL_NAME_STR(name) #name
-
-#ifdef CONFIG_SWAP_HOOK_SYSCALL
-
-#include <asm/unistd32.h>      /* FIXME: for only arm64 compat mode */
-
-#define X(name__, args__)                                      \
-{                                                              \
-       .hook = CREATE_HOOK_SYSCALL(name__),                    \
-       .sys_addr = 0xdeadbeef,                                 \
-       .counter = 0,                                           \
-       .args = #args__,                                        \
-       .type = PT_KS_NONE,                                     \
-       .name = SYSCALL_NAME_STR(sys_ ## name__),               \
-       .id = __NR_ ## name__,                                  \
-},
-#else /* !CONFIG_SWAP_HOOK_SYSCALL */
-#define X(name__, args__)                                      \
-{                                                              \
-       .rp = CREATE_RP(name__),                                \
-       .counter = 0,                                           \
-       .args = #args__,                                        \
-       .type = PT_KS_NONE,                                     \
-       .name = SYSCALL_NAME_STR(sys_ ## name__),               \
-},
-#endif /* CONFIG_SWAP_HOOK_SYSCALL */
-
-struct ks_probe ksp[syscall_cnt] = {
-       SYSCALL_LIST
-};
-
-#undef X
-
-const char *get_sys_name(size_t id)
-{
-       return ksp[id].name;
-}
-
-int get_counter(size_t id)
-{
-       return ksp[id].counter;
-}
-
-void inc_counter(size_t id)
-{
-       ++ksp[id].counter;
-}
-
-void dec_counter(size_t id)
-{
-       --ksp[id].counter;
-}
-
diff --git a/ks_features/ks_features_data.h b/ks_features/ks_features_data.h
deleted file mode 100644 (file)
index e68a1b1..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * ks_features/ks_features_data.h
- * @author Vitaliy Cherepanov: SWAP ks_features implement
- *
- * @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, 2016
- *
- * @section DESCRIPTION
- *
- *  SWAP kernel features
- */
-
-/**
- * @struct ks_probe
- * @brief Kernel-space probe. Struct used as a container of syscall probes.
- * @var ks_probe::rp
- * Pointer to kretprobe.
- * @var ks_probe::counter
- * Installed probes counter.
- * @var ks_probe::args
- * Pointer to args format string.
- * @var ks_probe::type
- * Probe sub type.
- */
-#ifndef __KS_FEATURE_DATA_H__
-#define __KS_FEATURE_DATA_H__
-
-#include "syscall_list.h"
-
-#ifdef CONFIG_SWAP_HOOK_SYSCALL
-# include <swap/hook_syscall.h>
-#else
-# include "kprobe/swap_kprobes.h"
-#endif
-
-struct ks_probe {
-#ifdef CONFIG_SWAP_HOOK_SYSCALL
-       struct hook_syscall hook;
-       u64 sys_addr;
-#else /* CONFIG_SWAP_HOOK_SYSCALL */
-       struct kretprobe rp;
-#endif /* CONFIG_SWAP_HOOK_SYSCALL */
-
-       int counter;
-       char *args;
-       int type;
-
-       const char *name;
-       unsigned int id;
-};
-
-/**
- * @enum
- * Syscall name count defenition
- */
-#define X(name__, args__) + 1
-enum {
-       syscall_cnt = 0 SYSCALL_LIST
-};
-#undef X
-
-extern struct ks_probe ksp[syscall_cnt];
-
-const char *get_sys_name(size_t id);
-int get_counter(size_t id);
-void inc_counter(size_t id);
-void dec_counter(size_t id);
-
-#endif /* __KS_FEATURE_DATA_H__ */
diff --git a/ks_features/ks_map.c b/ks_features/ks_map.c
deleted file mode 100644 (file)
index 6be2f2e..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include "ks_map.h"
-
-struct entry {
-       struct rb_node node;
-       void *data;
-};
-
-static inline void *entry_data(struct entry *entry)
-{
-       return entry->data;
-}
-
-static struct entry *alloc_entry(struct map *map, void *data)
-{
-       struct entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
-
-       if (entry) {
-               entry->data = data;
-               RB_CLEAR_NODE(&entry->node);
-       }
-
-       return entry;
-}
-
-static void *free_entry(struct map *map, struct entry *entry)
-{
-       void *data = entry_data(entry);
-
-       kfree(entry);
-
-       return data;
-}
-
-static struct entry *__search(struct map *map, void *key)
-{
-       struct rb_root *root = &map->root;
-       struct rb_node *node = root->rb_node;
-       key_func_t key_f = map->key_f;
-       cmp_func_t cmp_f = map->cmp_f;
-
-       while (node) {
-               struct entry *entry = rb_entry(node, struct entry, node);
-               int result = cmp_f(key_f(entry_data(entry)), key);
-
-               if (result < 0)
-                       node = node->rb_left;
-               else if (result > 0)
-                       node = node->rb_right;
-               else
-                       return entry;
-       }
-
-       return NULL;
-}
-
-void *search(struct map *map, void *key)
-{
-       struct entry *entry = __search(map, key);
-
-       return entry ? entry_data(entry) : NULL;
-}
-
-static void *__remove(struct map *map, struct entry *entry)
-{
-       struct rb_root *root = &map->root;
-
-       rb_erase(&entry->node, root);
-       RB_CLEAR_NODE(&entry->node);
-       map->size--;
-
-       return free_entry(map, entry);
-}
-
-void *remove(struct map *map, void *key)
-{
-       struct entry *entry = __search(map, key);
-
-       /* Removes entry from the tree but does not free the data */
-       return entry ? __remove(map, entry) : NULL;
-}
-
-static void *__replace(struct map *map, struct entry *old, struct entry *new)
-{
-       struct rb_root *root = &map->root;
-
-       rb_replace_node(&old->node, &new->node, root);
-
-       return free_entry(map, old);
-}
-
-void *replace(struct map *map, void *data)
-{
-       struct entry *old, *new;
-
-       old = __search(map, map->key_f(data));
-       if (old) {
-               new = alloc_entry(map, data);
-               if (!new)
-                       return ERR_PTR(-ENOMEM);
-
-               return __replace(map, old, new);
-       }
-
-       return ERR_PTR(-ESRCH);
-}
-
-int insert(struct map *map, void *data)
-{
-       struct rb_root *root = &map->root;
-       struct rb_node **new = &(root->rb_node), *parent = NULL;
-       key_func_t key_f = map->key_f;
-       cmp_func_t cmp_f = map->cmp_f;
-       void *key = key_f(data);
-       struct entry *entry;
-
-       /* Figure out where to put new node */
-       while (*new) {
-               struct entry *this = rb_entry(*new, struct entry, node);
-               int result = cmp_f(key_f(entry_data(this)), key);
-
-               parent = *new;
-               if (result < 0)
-                       new = &((*new)->rb_left);
-               else if (result > 0)
-                       new = &((*new)->rb_right);
-               else /* entry already inserted */
-                       return -EEXIST;
-       }
-
-       entry = alloc_entry(map, data);
-       if (!entry)
-               return -ENOMEM;
-
-       /* Add new node and rebalance tree. */
-       rb_link_node(&entry->node, parent, new);
-       rb_insert_color(&entry->node, root);
-       map->size++;
-
-       return 0;
-}
-
-int for_each_entry(struct map *map, act_func_t func, void *arg)
-{
-       struct rb_root *root = &map->root;
-       struct rb_node *node = rb_first(root);
-       int ret = 0;
-
-       while (node) {
-               struct entry *entry = rb_entry(node, struct entry, node);
-
-               /* Stop iteration if actor returns non zero */
-               ret = func(entry_data(entry), arg);
-               if (ret)
-                       break;
-
-               node = rb_next(node);
-       }
-
-       return ret;
-}
-
-int for_each_entry_reverse(struct map *map, act_func_t func, void *arg)
-{
-       struct rb_root *root = &map->root;
-       struct rb_node *node = rb_last(root);
-       int ret = 0;
-
-       while (node) {
-               struct entry *entry = rb_entry(node, struct entry, node);
-
-               /* Stop iteration if actor returns non zero */
-               ret = func(entry_data(entry), arg);
-               if (ret)
-                       break;
-
-               node = rb_prev(node);
-       }
-
-       return ret;
-}
-
-void clear(struct map *map, act_func_t destructor, void *arg)
-{
-       struct rb_root *root = &map->root;
-       struct rb_node *node = root->rb_node;
-
-       while (node) {
-               struct entry *entry = rb_entry(node, struct entry, node);
-               void *data = __remove(map, entry);
-
-               /* call the data 'destructor' if supplied */
-               if (destructor)
-                       destructor(data, arg);
-
-               node = root->rb_node;
-       }
-
-       WARN(map->size, "ks_map size: %d\n", map->size);
-       map->root = RB_ROOT;
-}
diff --git a/ks_features/ks_map.h b/ks_features/ks_map.h
deleted file mode 100644 (file)
index 8d86a9c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __KS_MAP__
-#define __KS_MAP__
-
-#include <linux/rbtree.h>
-
-typedef void *(*key_func_t)(void *);
-typedef int (*cmp_func_t)(void *, void *);
-typedef int (*act_func_t)(void *, void *);
-
-struct map {
-       struct rb_root root;
-       int size;
-       key_func_t key_f;
-       cmp_func_t cmp_f;
-};
-
-#define __MAP_INITIALIZER(_key_f, _cmp_f) \
-       { \
-               .root = RB_ROOT, \
-               .size = 0, \
-               .key_f = _key_f, \
-               .cmp_f = _cmp_f \
-       }
-
-#define DEFINE_MAP(_name, _key_f, _cmp_f) \
-       struct map _name = __MAP_INITIALIZER(_key_f, _cmp_f)
-
-void *search(struct map *map, void *key);
-void *remove(struct map *map, void *key);
-void *replace(struct map *map, void *data);
-int insert(struct map *map, void *data);
-int for_each_entry(struct map *map, act_func_t func, void *arg);
-int for_each_entry_reverse(struct map *map, act_func_t act, void *arg);
-void clear(struct map *map, act_func_t destructor, void *arg);
-
-#endif /* __KS_MAP__ */
diff --git a/ks_features/ksf_msg.c b/ks_features/ksf_msg.c
deleted file mode 100644 (file)
index e1d0b65..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <writer/swap_msg.h>
-#include <writer/kernel_operations.h>
-#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 = raw_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");
-               goto put_msg;
-       }
-
-       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 task_struct *task, enum swap_msg_id id)
-{
-       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 = raw_smp_processor_id();
-
-       swap_msg_flush_wakeupoff(m, sizeof(*mcs));
-       swap_msg_put(m);
-}
-
-void ksf_switch_entry(struct task_struct *task)
-{
-       context_switch(task, MSG_CONTEXT_SWITCH_ENTRY);
-}
-
-void ksf_switch_exit(struct task_struct *task)
-{
-       context_switch(task, MSG_CONTEXT_SWITCH_EXIT);
-}
diff --git a/ks_features/ksf_msg.h b/ks_features/ksf_msg.h
deleted file mode 100644 (file)
index 102cd46..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#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 task_struct *task);
-void ksf_switch_exit(struct task_struct *task);
-
-
-#endif /* _KSF_MSG_H */
diff --git a/ks_features/syscall_list.h b/ks_features/syscall_list.h
deleted file mode 100644 (file)
index 380e53f..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
- * @file ks_features/syscall_list.h
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @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
- *
- * Syscalls list.
- */
-
-
-#ifndef _SYSCALL_LIST_H
-#define _SYSCALL_LIST_H
-
-#define SYSCALL_LIST \
-       X(accept4, dpdd) \
-       X(accept, dpd) \
-       X(access, sd) \
-       X(acct, s) \
-       X(bind, dpd) \
-       X(chdir, s) \
-       X(chmod, sd) \
-/* TODO: X(chown16, sdd) */ \
-       X(chown, sdd) \
-       X(chroot, s) \
-       X(clone, ddddd) \
-       X(connect, dpd) \
-       X(creat, sd) \
-       X(dup3, ddd) \
-       X(epoll_create1, d) \
-       X(epoll_ctl, dddp) \
-       X(epoll_pwait, dpddpx) \
-       X(epoll_wait, dpdd) \
-       X(eventfd2, dd) \
-       X(eventfd, d) \
-       X(execve, spp) \
-       X(exit, d) \
-       X(exit_group, d) \
-       X(faccessat, dsd) \
-/* TODO: X(fadvise64_64, dxxd) */ \
-       X(fallocate, ddxx) \
-       X(fanotify_init, dd) \
-       X(fanotify_mark, ddxds) \
-       X(fchmodat, dsd) \
-       X(fchownat, dsddd) \
-       X(fgetxattr, dspx) \
-       X(flistxattr, dpx) \
-       X(fork, /* empty */) \
-       X(fremovexattr, ds) \
-       X(fstat64, xp) \
-       X(ftruncate64, dx) \
-       X(futimesat, dsp) \
-       X(getcwd, px) \
-       X(getpeername, dpd) \
-       X(getsockname, dpd) \
-       X(getsockopt, dddpd) \
-       X(getxattr, sspx) \
-       X(inotify_add_watch, dsd) \
-       X(inotify_init, /* empty */) \
-       X(inotify_init1, d) \
-       X(inotify_rm_watch, dd) \
-/* TODO: X(ipc, ddxxpx) */\
-       X(kill, dd) \
-       X(linkat, dsdsd) \
-       X(link, ss) \
-       X(listen, dd) \
-       X(listxattr, spx) \
-       X(lstat64, sp) \
-/* TODO: X(lstat, sp) */ \
-       X(mkdirat, dsd) \
-       X(mkdir, sd) \
-       X(mknodat, dsdd) \
-       X(mknod, sdd) \
-/* TODO: X(mmap_pgoff, xxxxxx) */ \
-       X(mount, pppxp) \
-       X(msgctl, ddp) \
-       X(msgget, dd) \
-       X(msgrcv, dpxxd) \
-       X(msgsnd, dpxd) \
-       X(name_to_handle_at, dspdd) \
-/* TODO: X(newfstatat, dspd) */ \
-/* TODO: X(old_mmap, p) */ \
-       X(openat, dsdd) \
-       X(open_by_handle_at, dpd) \
-       X(open, sdd) \
-       X(pause, /* empty */) \
-       X(pipe2, dd) \
-       X(ppoll, pdpp) \
-       X(pread64, dpxx) \
-       X(preadv, xpxxx) \
-       X(pselect6, dxxxpp) \
-       X(pwrite64, dsxx) \
-       X(pwritev, xpxxx) \
-       X(readlinkat, dspd) \
-       X(readlink, spd) \
-       X(recv, dpxd) \
-       X(recvfrom, dpxdpd) \
-       X(recvmmsg, dpddp) \
-       X(recvmsg, dpd) \
-       X(removexattr, ss) \
-       X(renameat, dsds) \
-       X(rename, ss) \
-       X(rmdir, s) \
-       X(rt_sigaction, dpp) \
-       X(rt_sigprocmask, dppx) \
-       X(rt_sigsuspend, px) \
-       X(rt_sigtimedwait, pppx) \
-       X(rt_tgsigqueueinfo, dddp) \
-       X(semctl, dddx) \
-       X(semget, ddd) \
-       X(semop, dpd) \
-       X(semtimedop, dpdp) \
-       X(send, dpxd) \
-       X(sendfile64, ddlxx) \
-       X(sendfile, ddxx) \
-       X(sendmmsg, dpdd) \
-       X(sendmsg, dpd) \
-       X(sendto, dpxdpd) \
-       X(setns, dd) \
-       X(setsockopt, dddpd) \
-       X(setxattr, sspxd) \
-       X(shmat, dpd) \
-       X(shmctl, ddp) \
-       X(shmdt, p) \
-       X(shmget, dxd) \
-       X(shutdown, dd) \
-       X(sigaction, dpp) \
-/* TODO: X(sigaltstack, pp) */ \
-/* TODO: X(signal, dp) */ \
-       X(signalfd4, dpxd) \
-       X(signalfd, dpx) \
-       X(sigpending, p) \
-       X(sigprocmask, dpp) \
-/* TODO: X(sigsuspend, ddp) */ \
-/* TODO: X(sigsuspend, p) */ \
-/* TODO: X(socketcall, dx) */\
-       X(socket, ddd) \
-       X(socketpair, dddd) \
-       X(splice, dxdxxd) \
-       X(stat64, sp) \
-       X(statfs64, sxp) \
-       X(statfs, sp) \
-/* TODO: X(stat, sp) */ \
-       X(swapoff, s) \
-       X(swapon, sd) \
-       X(symlinkat, sds) \
-       X(symlink, ss) \
-       X(syncfs, d) \
-       X(tee, ddxd) \
-       X(tgkill, ddd) \
-       X(timerfd_create, dd) \
-       X(timerfd_gettime, dp) \
-       X(timerfd_settime, ddpp) \
-       X(truncate64, sx) \
-       X(truncate, sx) \
-/* TODO: X(umount, pd) */\
-       X(unlinkat, dsd) \
-       X(unlink, s) \
-       X(unshare, x) \
-       X(uselib, s) \
-       X(utimensat, dspd) \
-/* TODO: X(utime, pp) */\
-       X(utimes, pp) \
-       X(vfork, /* empty */) \
-       X(vmsplice, dpxd) \
-       X(wait4, dddp) \
-       X(waitid, ddpdp)
-/* TODO: X(waitpid, ddd) */
-
-#endif /* _SYSCALL_LIST_H */
diff --git a/ks_manager/Kbuild b/ks_manager/Kbuild
deleted file mode 100644 (file)
index 220e7c2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers
-
-obj-m := swap_ks_manager.o
-swap_ks_manager-y := ks_manager.o
diff --git a/ks_manager/ks_manager.c b/ks_manager/ks_manager.c
deleted file mode 100644 (file)
index 2a554e1..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/ks_manager/ks_manager.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include "ks_manager.h"
-
-struct probe {
-       struct hlist_node hlist;
-       struct kern_probe p;
-};
-
-static HLIST_HEAD(list_probes);
-
-static struct probe *create_probe(unsigned long addr, void *pre_handler,
-                                 void *jp_handler, void *rp_handler)
-{
-       struct probe *p = kzalloc(sizeof(*p), GFP_KERNEL);
-
-       if (p == NULL)
-               return NULL;
-
-       p->p.jp.kp.addr = p->p.rp.kp.addr = addr;
-       p->p.jp.pre_entry = pre_handler;
-       p->p.jp.entry = jp_handler;
-       p->p.rp.handler = rp_handler;
-       INIT_HLIST_NODE(&p->hlist);
-
-       return p;
-}
-
-static void free_probe(struct probe *p)
-{
-       kfree(p);
-}
-
-static void add_probe_to_list(struct probe *p)
-{
-       hlist_add_head(&p->hlist, &list_probes);
-}
-
-static void remove_probe_to_list(struct probe *p)
-{
-       hlist_del(&p->hlist);
-}
-
-static struct probe *find_probe(unsigned long addr)
-{
-       struct probe *p;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       /* check if such probe does exist */
-       swap_hlist_for_each_entry(p, node, &list_probes, hlist)
-               if ((unsigned long)p->p.jp.kp.addr == addr)
-                       return p;
-
-       return NULL;
-}
-
-int ksm_register_probe(unsigned long addr, void *pre_handler,
-                      void *jp_handler, void *rp_handler)
-{
-       int ret;
-       struct probe *p;
-
-       p = create_probe(addr, pre_handler, jp_handler, rp_handler);
-       if (!p)
-               return -ENOMEM;
-
-       ret = swap_register_jprobe(&p->p.jp);
-       if (ret)
-               goto free;
-
-       ret = swap_register_kretprobe(&p->p.rp);
-       if (ret)
-               goto unregister_jprobe;
-
-       add_probe_to_list(p);
-       return 0;
-
-unregister_jprobe:
-       swap_unregister_jprobe(&p->p.jp);
-free:
-       free_probe(p);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ksm_register_probe);
-
-static void do_ksm_unregister_probe(struct probe *p)
-{
-       remove_probe_to_list(p);
-       swap_unregister_kretprobe(&p->p.rp);
-       swap_unregister_jprobe(&p->p.jp);
-       free_probe(p);
-}
-
-int ksm_unregister_probe(unsigned long addr)
-{
-       struct probe *p;
-
-       p = find_probe(addr);
-       if (p == NULL)
-               return -EINVAL;
-
-       do_ksm_unregister_probe(p);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ksm_unregister_probe);
-
-int ksm_unregister_probe_all(void)
-{
-       struct probe *p;
-       struct hlist_node *n;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry_safe(p, node, n, &list_probes, hlist) {
-               do_ksm_unregister_probe(p);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ksm_unregister_probe_all);
-
-static int __init init_ks_manager(void)
-{
-       return 0;
-}
-
-static void __exit exit_ks_manager(void)
-{
-       ksm_unregister_probe_all();
-}
-
-module_init(init_ks_manager);
-module_exit(exit_ks_manager);
-
-MODULE_LICENSE("GPL");
diff --git a/ks_manager/ks_manager.h b/ks_manager/ks_manager.h
deleted file mode 100644 (file)
index 42ca724..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _KS_MANAGER_H
-#define _KS_MANAGER_H
-
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/ks_manager/ks_manager.h
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include <kprobe/swap_kprobes.h>
-
-struct kern_probe {
-       struct jprobe jp;
-       struct kretprobe rp;
-};
-
-int ksm_register_probe(unsigned long addr, void *pre_handler,
-                      void *jp_handler, void *rp_handler);
-int ksm_unregister_probe(unsigned long addr);
-
-int ksm_unregister_probe_all(void);
-
-#endif /* _KS_MANAGER_H */
diff --git a/ksyms/Kbuild b/ksyms/Kbuild
deleted file mode 100644 (file)
index c602e93..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_ksyms.o
-swap_ksyms-y := ksyms_module.o
-
-ifeq ($(CONFIG_KALLSYMS),y)
-       swap_ksyms-y += ksyms.o
-else
-       swap_ksyms-y += no_ksyms.o
-endif
diff --git a/ksyms/ksyms.c b/ksyms/ksyms.c
deleted file mode 100644 (file)
index d44b45a..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @file ksyms/ksyms.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * SWAP ksyms module.
- */
-
-
-#include "ksyms.h"
-#include "ksyms_init.h"
-#include <linux/kallsyms.h>
-#include <linux/module.h>
-#include <linux/percpu.h>
-
-/**
- * @struct symbol_data
- * @brief Stores symbols data.
- * @var symbol_data::name
- * Pointer to symbol name string.
- * @var symbol_data::len
- * Symbol name length.
- * @var symbol_data::addr
- * Symbol address.
- */
-struct symbol_data {
-       const char *name;
-       size_t len;
-       unsigned long addr;
-};
-
-static int symbol_cb(void *data, const char *sym, struct module *mod,
-                    unsigned long addr)
-{
-       struct symbol_data *sym_data_p = (struct symbol_data *)data;
-
-       /* We expect that real symbol name should have at least the same
-        * length as symbol name we are looking for. */
-       if (strncmp(sym_data_p->name, sym, sym_data_p->len) == 0) {
-               sym_data_p->addr = addr;
-               /* Return != 0 to stop loop over the symbols */
-               return 1;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Search of symbol address based on substring.
- *
- * @param name Pointer to the substring.
- * @return Symbol address.
- */
-unsigned long swap_ksyms_substr(const char *name)
-{
-       struct symbol_data sym_data = {
-               .name = name,
-               .len = strlen(name),
-               .addr = 0
-       };
-       kallsyms_on_each_symbol(symbol_cb, (void *)&sym_data);
-
-       return sym_data.addr;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms_substr);
diff --git a/ksyms/ksyms.h b/ksyms/ksyms.h
deleted file mode 100644 (file)
index 3348b7f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file ksyms/ksyms.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- * @sectoin DESCRIPTION
- *
- * SWAP symbols searching module.
- */
-
-#ifndef __KSYMS_H__
-#define __KSYMS_H__
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
-#include <linux/autoconf.h>
-#else
-#include <generated/autoconf.h>
-#endif
-
-#include <linux/kallsyms.h>
-
-#ifdef CONFIG_KALLSYMS
-
-static inline int swap_get_ksyms(void)
-{
-       return 0;
-}
-
-static inline void swap_put_ksyms(void)
-{
-}
-
-static inline unsigned long swap_ksyms(const char *name)
-{
-       return kallsyms_lookup_name(name);
-}
-
-#else /* !CONFIG_KALLSYMS */
-
-int swap_get_ksyms(void);
-void swap_put_ksyms(void);
-unsigned long swap_ksyms(const char *name);
-
-#endif /*CONFIG_KALLSYMS*/
-
-unsigned long swap_ksyms_substr(const char *name);
-
-#endif /*__KSYMS_H__*/
diff --git a/ksyms/ksyms_init.h b/ksyms/ksyms_init.h
deleted file mode 100644 (file)
index 6235a59..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @file ksyms/ksyms_init.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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 LICENSE
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * SWAP symbols searching module initialization interface.
- */
-
-#ifndef __KSYMS_INIT_H__
-#define __KSYMS_INIT_H__
-
-#ifdef CONFIG_KALLSYMS
-
-static inline int ksyms_init(void)
-{
-       return 0;
-}
-
-static inline void ksyms_exit(void)
-{
-}
-
-#else /* CONFIG_KALLSYMS */
-
-int ksyms_init(void);
-void ksyms_exit(void);
-
-#endif /* CONFIG_KALLSYMS */
-
-#endif /* __KSYMS_INIT_H__ */
diff --git a/ksyms/ksyms_module.c b/ksyms/ksyms_module.c
deleted file mode 100644 (file)
index 22eaaf0..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * @file ksyms/ksyms_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * SWAP symbols searching module initialization implementation.
- */
-
-#include "ksyms_init.h"
-
-#include <linux/module.h>
-
-/**
- * @brief Init ksyms module.
- *
- * @return 0 on success.
- */
-int __init swap_ksyms_init(void)
-{
-       int ret = ksyms_init();
-
-       printk(KERN_INFO "SWAP_KSYMS: Module initialized\n");
-
-       return ret;
-}
-
-/**
- * @brief Exit ksyms module.
- *
- * @return Void.
- */
-void __exit swap_ksyms_exit(void)
-{
-       ksyms_exit();
-
-       printk(KERN_INFO "SWAP_KSYMS: Module uninitialized\n");
-}
-
-module_init(swap_ksyms_init);
-module_exit(swap_ksyms_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP ksyms module");
-MODULE_AUTHOR("Vyacheslav Cherkashin <v.cherkashin@samaung.com>");
diff --git a/ksyms/no_ksyms.c b/ksyms/no_ksyms.c
deleted file mode 100644 (file)
index a5ecb81..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/**
- * @file ksyms/no_ksyms.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- * SWAP symbols searching implementation.
- */
-
-#include "ksyms.h"
-#include "ksyms_init.h"
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/semaphore.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-
-/**
- * @def KSYMS_ERR
- * Error message define.
- */
-#define KSYMS_ERR(format, args...) \
-       do { \
-               char *f = __FILE__; \
-               char *n = strrchr(f, '/'); \
-               printk(KERN_INFO "%s:%u \'%s\' ERROR: " format "\n" ,  \
-                      (n) ? n+1 : f, __LINE__, __func__, ##args); \
-       } while (0)
-
-/**
- * @struct sys_map_item
- * @brief System map list item info.
- * @var sys_map_item::list
- * List pointer.
- * @var sys_map_item::addr
- * Symbol address.
- * @var sys_map_item::name
- * Symbol name.
- */
-struct sys_map_item {
-       struct list_head list;
-
-       unsigned long addr;
-       char *name;
-};
-
-static char *sm_path;
-module_param(sm_path, charp, 0);
-
-/**
- * @var smi_list
- * List of sys_map_item.
- */
-LIST_HEAD(smi_list);
-static struct file *file;
-
-static int cnt_init_sm;
-
-/**
- * @var cnt_init_sm_lock
- * System map items list lock.
- */
-DEFINE_SEMAPHORE(cnt_init_sm_lock);
-
-static int file_open(void)
-{
-       struct file *f = filp_open(sm_path, O_RDONLY, 0);
-
-       if (IS_ERR(f)) {
-               KSYMS_ERR("cannot open file \'%s\'", sm_path);
-               return PTR_ERR(f);
-       }
-
-       file = f;
-
-       return 0;
-}
-
-static void file_close(void)
-{
-       if (file) {
-               int ret = filp_close(file, NULL);
-               file = NULL;
-
-               if (ret) {
-                       KSYMS_ERR("while closing file \'%s\' err=%d",
-                                 sm_path, ret);
-               }
-       }
-}
-
-static int file_check(void)
-{
-       int ret = file_open();
-       if (ret == 0)
-               file_close();
-
-       return ret;
-}
-
-static long file_size(struct file *file)
-{
-       struct kstat st;
-       if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st))
-               return -1;
-
-       if (!S_ISREG(st.mode))
-               return -1;
-
-       if (st.size != (long)st.size)
-               return -1;
-
-       return st.size;
-}
-
-static struct sys_map_item *create_smi(unsigned long addr, const char *name)
-{
-       struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL);
-
-       if (smi == NULL) {
-               KSYMS_ERR("not enough memory");
-               return NULL;
-       }
-
-       smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
-       if (smi->name == NULL) {
-               kfree(smi);
-               KSYMS_ERR("not enough memory");
-               return NULL;
-       }
-
-       INIT_LIST_HEAD(&smi->list);
-       smi->addr = addr;
-       strcpy(smi->name, name);
-
-       return smi;
-}
-
-static void free_smi(struct sys_map_item *smi)
-{
-       kfree(smi->name);
-       kfree(smi);
-}
-
-static void add_smi(struct sys_map_item *smi)
-{
-       list_add_tail(&smi->list, &smi_list);
-}
-
-static int is_endline(char c)
-{
-       return c == '\n' || c == '\r' || c == '\0';
-}
-
-static int is_symbol_attr(char c)
-{
-       return c == 't' || c == 'T';
-}
-
-static struct sys_map_item *get_sys_map_item(char *begin, char *end)
-{
-       struct sys_map_item *smi = NULL;
-       int n, len = end - begin;
-       unsigned long addr;
-       char attr, name[128], *line;
-
-       line = kmalloc(len + 1, GFP_KERNEL);
-       memcpy(line, begin, len);
-       line[len] = '\0';
-
-       n = sscanf(line, "%lx %c %127s", &addr, &attr, name);
-       name[127] = '\0';
-
-       if (n != 3) {
-               KSYMS_ERR("parsing line: \"%s\"", line);
-               attr = '\0';
-       }
-
-       kfree(line);
-
-       if (is_symbol_attr(attr))
-               smi = create_smi(addr, name);
-
-       return smi;
-}
-
-
-static void parsing(char *buf, int size)
-{
-       struct sys_map_item *smi;
-       char *start, *end, *c;
-
-       start = buf;
-       end = buf + size;
-
-       for (c = start; c < end; ++c) {
-               if (is_endline(*c)) {
-                       smi = get_sys_map_item(start, c);
-                       if (smi)
-                               add_smi(smi);
-
-                       for (start = c; c < end; ++c) {
-                               if (!is_endline(*c)) {
-                                       start = c;
-                                       break;
-                               }
-                       }
-               }
-       }
-}
-
-static int create_sys_map(void)
-{
-       char *data;
-       long size;
-       int ret = file_open();
-
-       if (ret)
-               return ret;
-
-       size = file_size(file);
-       if (size < 0) {
-               KSYMS_ERR("cannot get file size");
-               ret = size;
-               goto close;
-       }
-
-       data = vmalloc(size);
-       if (data == NULL) {
-               KSYMS_ERR("not enough memory");
-               ret = -1;
-               goto close;
-       }
-
-       if (kernel_read(file, 0, data, size) != size) {
-               KSYMS_ERR("reading file %s", sm_path);
-               ret = -1;
-               goto free;
-       }
-
-       parsing(data, size);
-
-free:
-       vfree(data);
-
-close:
-       file_close();
-
-       return 0;
-}
-
-static void free_sys_map(void)
-{
-       struct sys_map_item *smi, *n;
-       list_for_each_entry_safe(smi, n, &smi_list, list) {
-               list_del(&smi->list);
-               free_smi(smi);
-       }
-}
-
-/**
- * @brief Generates symbols list.
- *
- * @return 0 on success.
- */
-int swap_get_ksyms(void)
-{
-       int ret = 0;
-
-       down(&cnt_init_sm_lock);
-       if (cnt_init_sm == 0)
-               ret = create_sys_map();
-
-       ++cnt_init_sm;
-       up(&cnt_init_sm_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_get_ksyms);
-
-/**
- * @brief Frees symbols list.
- *
- * @return Void.
- */
-void swap_put_ksyms(void)
-{
-       down(&cnt_init_sm_lock);
-       --cnt_init_sm;
-       if (cnt_init_sm == 0)
-               free_sys_map();
-
-       if (cnt_init_sm < 0) {
-               KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm);
-               cnt_init_sm = 0;
-       }
-
-       up(&cnt_init_sm_lock);
-}
-EXPORT_SYMBOL_GPL(swap_put_ksyms);
-
-/**
- * @brief Searches for symbol by its exact name.
- *
- * @param name Pointer the name string.
- * @return Symbol's address.
- */
-unsigned long swap_ksyms(const char *name)
-{
-       struct sys_map_item *smi;
-
-       list_for_each_entry(smi, &smi_list, list) {
-               if (strcmp(name, smi->name) == 0)
-                       return smi->addr;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms);
-
-/**
- * @brief Searches for symbol by substring of its name.
- *
- * @param name Pointer to the name substring.
- * @return Symbol's address.
- */
-unsigned long swap_ksyms_substr(const char *name)
-{
-       struct sys_map_item *smi;
-       size_t len = strlen(name);
-
-       list_for_each_entry(smi, &smi_list, list) {
-               if (strncmp(name, smi->name, len) == 0)
-                       return smi->addr;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms_substr);
-
-/**
- * @brief SWAP ksyms module initialization.
- *
- * @return 0 on success, negative error code on error.
- */
-int ksyms_init(void)
-{
-       int ret = 0;
-
-       if (sm_path == NULL) {
-               KSYMS_ERR("sm_path=NULL");
-               return -EINVAL;
-       }
-
-       ret = file_check();
-       if (ret)
-               return -EINVAL;
-
-       /* TODO: calling func 'swap_get_ksyms' in
-        * module used func 'swap_ksyms' */
-       swap_get_ksyms();
-
-       return 0;
-}
-
-/**
- * @brief SWAP ksyms module deinitialization.
- *
- * @return Void.
- */
-void ksyms_exit(void)
-{
-       down(&cnt_init_sm_lock);
-
-       if (cnt_init_sm > 0)
-               free_sys_map();
-
-       up(&cnt_init_sm_lock);
-}
diff --git a/loader/Kbuild b/loader/Kbuild
deleted file mode 100644 (file)
index 92e5e6f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_loader.o
-swap_loader-y := loader_module.o \
-                 loader_debugfs.o \
-                 loader_storage.o \
-                 loader_pd.o
diff --git a/loader/loader.h b/loader/loader.h
deleted file mode 100644 (file)
index 9ba5ced..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef __LOADER__
-#define __LOADER__
-
-struct pd_t;
-struct hd_t;
-struct uretprobe_instance;
-struct task_struct;
-
-/* process loader states */
-enum ps_t {
-       NOT_LOADED,
-       LOADING,
-       LOADED,
-       FAILED,
-       ERROR
-};
-
-void loader_module_prepare_ujump(struct uretprobe_instance *ri,
-                                 struct pt_regs *regs, unsigned long addr);
-
-unsigned long loader_not_loaded_entry(struct uretprobe_instance *ri,
-                                      struct pt_regs *regs, struct pd_t *pd,
-                                      struct hd_t *hd);
-void loader_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                        struct pd_t *pd, struct hd_t *hd);
-void loader_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                       struct pd_t *pd, struct hd_t *hd);
-
-void loader_set_rp_data_size(struct uretprobe *rp);
-void loader_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr);
-unsigned long loader_get_priv_origin(struct uretprobe_instance *ri);
-int loader_add_handler(const char *path);
-
-
-struct pd_t *lpd_get(struct sspt_proc *proc);
-struct pd_t *lpd_get_by_task(struct task_struct *task);
-struct hd_t *lpd_get_hd(struct pd_t *pd, struct dentry *dentry);
-
-bool lpd_get_init_state(struct pd_t *pd);
-void lpd_set_init_state(struct pd_t *pd, bool state);
-
-struct dentry *lpd_get_dentry(struct hd_t *hd);
-struct pd_t *lpd_get_parent_pd(struct hd_t *hd);
-enum ps_t lpd_get_state(struct hd_t *hd);
-unsigned long lpd_get_handlers_base(struct hd_t *hd);
-void *lpd_get_handle(struct hd_t *hd);
-long lpd_get_attempts(struct hd_t *hd);
-void lpd_dec_attempts(struct hd_t *hd);
-
-
-#endif /* __LOADER__ */
diff --git a/loader/loader_debugfs.c b/loader/loader_debugfs.c
deleted file mode 100644 (file)
index 861bbe3..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/limits.h>
-#include <asm/uaccess.h>
-#include <master/swap_debugfs.h>
-#include <us_manager/us_common_file.h>
-#include "loader_defs.h"
-#include "loader_debugfs.h"
-#include "loader_module.h"
-#include "loader_storage.h"
-
-static const char LOADER_FOLDER[] = "loader";
-static const char LOADER_LOADER[] = "loader";
-static const char LOADER_LOADER_OFFSET[] = "loader_offset";
-static const char LOADER_LOADER_PATH[] = "loader_path";
-static const char LOADER_LINKER_DATA[] = "linker";
-static const char LOADER_LINKER_PATH[] = "linker_path";
-static const char LOADER_LINKER_R_STATE_OFFSET[] = "r_state_offset";
-
-struct loader_info {
-       char *path;
-       unsigned long offset;
-       struct dentry *dentry;
-};
-
-static struct dentry *loader_root;
-static struct loader_info __loader_info;
-
-static unsigned long r_state_offset = 0;
-static DEFINE_SPINLOCK(__dentry_lock);
-
-static inline void dentry_lock(void)
-{
-       spin_lock(&__dentry_lock);
-}
-
-static inline void dentry_unlock(void)
-{
-       spin_unlock(&__dentry_lock);
-}
-
-
-static void set_loader_file(char *path)
-{
-       __loader_info.path = path;
-       dentry_lock();
-       __loader_info.dentry = swap_get_dentry(__loader_info.path);
-       dentry_unlock();
-}
-
-struct dentry *ld_get_loader_dentry(void)
-{
-       struct dentry *dentry;
-
-       dentry_lock();
-       dentry = __loader_info.dentry;
-       dentry_unlock();
-
-       return dentry;
-}
-
-unsigned long ld_get_loader_offset(void)
-{
-       /* TODO Think about sync */
-       return __loader_info.offset;
-}
-
-static void clean_loader_info(void)
-{
-       if (__loader_info.path != NULL)
-               kfree(__loader_info.path);
-       __loader_info.path = NULL;
-
-       dentry_lock();
-       if (__loader_info.dentry != NULL)
-               swap_put_dentry(__loader_info.dentry);
-
-       __loader_info.dentry = NULL;
-       __loader_info.offset = 0;
-
-       dentry_unlock();
-}
-
-struct dentry *swap_debugfs_create_ptr(const char *name, mode_t mode,
-                                      struct dentry *parent,
-                                      unsigned long *value)
-{
-       struct dentry *dentry;
-
-#if BITS_PER_LONG == 32
-       dentry = swap_debugfs_create_x32(name, mode, parent, (u32 *)value);
-#elif BITS_PER_LONG == 64
-       dentry = swap_debugfs_create_x64(name, mode, parent, (u64 *)value);
-#else
-#error Unsupported BITS_PER_LONG value
-#endif
-
-       return dentry;
-}
-
-
-/* ===========================================================================
- * =                              LOADER PATH                                =
- * ===========================================================================
- */
-
-static ssize_t loader_path_write(struct file *file, const char __user *buf,
-                                size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *path;
-
-       if (loader_module_is_running())
-               return -EBUSY;
-
-       clean_loader_info();
-
-       path = kmalloc(len, GFP_KERNEL);
-       if (path == NULL) {
-               return -ENOMEM;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       path[len - 1] = '\0';
-       set_loader_file(path);
-
-       ret = len;
-
-       return ret;
-err:
-       kfree(path);
-       return ret;
-}
-
-
-static const struct file_operations loader_path_file_ops = {
-       .owner = THIS_MODULE,
-       .write = loader_path_write,
-};
-
-
-/* ===========================================================================
- * =                            LINKER PATH                                  =
- * ===========================================================================
- */
-
-
-static ssize_t linker_path_write(struct file *file, const char __user *buf,
-                                 size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *path;
-
-       path = kmalloc(len, GFP_KERNEL);
-       if (path == NULL) {
-               ret = -ENOMEM;
-               goto linker_path_write_out;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto linker_path_write_out;
-       }
-
-       path[len - 1] = '\0';
-
-       if (ls_set_linker_info(path) != 0) {
-               printk(LOADER_PREFIX "Cannot set linker path %s\n", path);
-               ret = -EINVAL;
-               goto linker_path_write_out;
-       }
-
-       ret = len;
-
-linker_path_write_out:
-       kfree(path);
-
-       return ret;
-}
-
-static const struct file_operations linker_path_file_ops = {
-       .owner = THIS_MODULE,
-       .write = linker_path_write,
-};
-
-
-
-
-
-unsigned long ld_r_state_offset(void)
-{
-       return r_state_offset;
-}
-
-int ld_init(void)
-{
-       struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
-                 *linker_dir, *linker_path, *r_state_path;
-       int ret;
-
-       ret = -ENODEV;
-       if (!debugfs_initialized())
-               goto fail;
-
-       ret = -ENOENT;
-       swap_dentry = swap_debugfs_getdir();
-       if (!swap_dentry)
-               goto fail;
-
-       ret = -ENOMEM;
-       root = swap_debugfs_create_dir(LOADER_FOLDER, swap_dentry);
-       if (IS_ERR_OR_NULL(root))
-               goto fail;
-
-       loader_root = root;
-
-       loader = swap_debugfs_create_dir(LOADER_LOADER, root);
-       if (IS_ERR_OR_NULL(root)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       open_p = swap_debugfs_create_ptr(LOADER_LOADER_OFFSET,
-                                        LOADER_DEFAULT_PERMS, loader,
-                                        &__loader_info.offset);
-       if (IS_ERR_OR_NULL(open_p)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       lib_path = swap_debugfs_create_file(LOADER_LOADER_PATH,
-                                           LOADER_DEFAULT_PERMS, loader, NULL,
-                                           &loader_path_file_ops);
-       if (IS_ERR_OR_NULL(lib_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       linker_dir = swap_debugfs_create_dir(LOADER_LINKER_DATA, root);
-       if (IS_ERR_OR_NULL(linker_dir)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       linker_path = swap_debugfs_create_file(LOADER_LINKER_PATH,
-                                              LOADER_DEFAULT_PERMS, linker_dir,
-                                              NULL, &linker_path_file_ops);
-       if (IS_ERR_OR_NULL(linker_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       r_state_path = swap_debugfs_create_ptr(LOADER_LINKER_R_STATE_OFFSET,
-                                              LOADER_DEFAULT_PERMS, linker_dir,
-                                              &r_state_offset);
-       if (IS_ERR_OR_NULL(r_state_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       return 0;
-
-remove:
-
-       debugfs_remove_recursive(root);
-
-fail:
-       printk(LOADER_PREFIX "Debugfs initialization failure: %d\n", ret);
-
-       return ret;
-}
-
-void ld_exit(void)
-{
-       if (loader_root)
-               debugfs_remove_recursive(loader_root);
-       loader_root = NULL;
-
-       loader_module_set_not_ready();
-       clean_loader_info();
-}
diff --git a/loader/loader_debugfs.h b/loader/loader_debugfs.h
deleted file mode 100644 (file)
index d961325..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LOADER_DEBUGFS_H__
-#define __LOADER_DEBUGFS_H__
-
-struct dentry;
-
-int ld_init(void);
-void ld_exit(void);
-
-struct dentry *ld_get_loader_dentry(void);
-unsigned long ld_get_loader_offset(void);
-
-unsigned long ld_r_state_offset(void);
-
-#endif /* __LOADER_DEBUGFS_H__ */
diff --git a/loader/loader_defs.h b/loader/loader_defs.h
deleted file mode 100644 (file)
index 0025f76..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __LOADER_DEFS_H__
-#define __LOADER_DEFS_H__
-
-#define LOADER_PREFIX "SWAP_LOADER: "
-#define LOADER_MAX_ATTEMPTS 10
-#define LOADER_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
-
-#endif /* __LOADER_DEFS_H__ */
diff --git a/loader/loader_module.c b/loader/loader_module.c
deleted file mode 100644 (file)
index e262c99..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/dcache.h>
-#include <linux/namei.h>
-#include <linux/mman.h>
-#include <linux/err.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/callbacks.h>
-#include <us_manager/usm_hook.h>
-#include <writer/kernel_operations.h>
-#include <master/swap_initializer.h>
-#include "loader_defs.h"
-#include "loader_debugfs.h"
-#include "loader_module.h"
-#include "loader.h"
-#include "loader_storage.h"
-#include "loader_pd.h"
-
-
-struct us_priv {
-       struct pt_regs regs;
-       unsigned long arg0;
-       unsigned long arg1;
-       unsigned long raddr;
-       unsigned long origin;
-};
-
-static atomic_t dentry_balance = ATOMIC_INIT(0);
-
-enum loader_status_t {
-       SWAP_LOADER_NOT_READY = 0,
-       SWAP_LOADER_READY = 1,
-       SWAP_LOADER_RUNNING = 2
-};
-
-static enum loader_status_t __loader_status = SWAP_LOADER_NOT_READY;
-
-static int __loader_cbs_start_h = -1;
-static int __loader_cbs_stop_h = -1;
-
-
-
-bool loader_module_is_running(void)
-{
-       if (__loader_status == SWAP_LOADER_RUNNING)
-               return true;
-
-       return false;
-}
-
-bool loader_module_is_ready(void)
-{
-       if (__loader_status == SWAP_LOADER_READY)
-               return true;
-
-       return false;
-}
-
-bool loader_module_is_not_ready(void)
-{
-       if (__loader_status == SWAP_LOADER_NOT_READY)
-               return true;
-
-       return false;
-}
-
-void loader_module_set_ready(void)
-{
-       __loader_status = SWAP_LOADER_READY;
-}
-
-void loader_module_set_running(void)
-{
-       __loader_status = SWAP_LOADER_RUNNING;
-}
-
-void loader_module_set_not_ready(void)
-{
-       __loader_status = SWAP_LOADER_NOT_READY;
-}
-
-static inline void __prepare_ujump(struct uretprobe_instance *ri,
-                                  struct pt_regs *regs,
-                                  unsigned long vaddr)
-{
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-       ri->preload.use = true;
-       ri->preload.thumb = !!thumb_mode(regs);
-#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-
-       swap_set_upc(regs, vaddr);
-}
-
-static inline void __save_uregs(struct uretprobe_instance *ri,
-                               struct pt_regs *regs)
-{
-       struct us_priv *priv = (struct us_priv *)ri->data;
-
-       priv->regs = *regs;
-       priv->arg0 = swap_get_uarg(regs, 0);
-       priv->arg1 = swap_get_uarg(regs, 1);
-       priv->raddr = swap_get_uret_addr(regs);
-}
-
-static inline void __restore_uregs(struct uretprobe_instance *ri,
-                                  struct pt_regs *regs)
-{
-       struct us_priv *priv = (struct us_priv *)ri->data;
-
-       *regs = priv->regs;
-       swap_put_uarg(regs, 0, priv->arg0);
-       swap_put_uarg(regs, 1, priv->arg1);
-       swap_set_uret_addr(regs, priv->raddr);
-#ifdef CONFIG_X86_32
-       /* need to do it only on x86 */
-       regs->EREG(ip) -= 1;
-#endif /* CONFIG_X86_32 */
-       /* we have just restored the registers => no need to do it in
-        * trampoline_uprobe_handler */
-       ri->ret_addr = NULL;
-}
-
-static inline void print_regs(const char *prefix, struct pt_regs *regs,
-                             struct uretprobe_instance *ri, struct hd_t *hd)
-{
-       struct dentry *dentry = lpd_get_dentry(hd);
-
-#if defined(CONFIG_ARM)
-       printk(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), "
-              "r0(%08lx), r1(%08lx), r2(%08lx), r3(%08lx), "
-              "r4(%08lx), r5(%08lx), r6(%08lx), r7(%08lx), "
-              "sp(%08lx), lr(%08lx), pc(%08lx)\n",
-              current->comm, current->tgid, current->pid,
-              dentry != NULL ? (char *)(dentry->d_name.name) :
-                               (char *)("NULL"),
-              (int)lpd_get_state(hd),
-              prefix, (unsigned long)ri->rp->up.addr,
-              regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3,
-              regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7,
-              regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
-#elif defined(CONFIG_X86_32)
-       printk(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), "
-              "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n",
-              current->comm, current->tgid, current->pid,
-              dentry != NULL ? (char *)(dentry->d_name.name) :
-                               (char *)("NULL"),
-              (int)lpd_get_state(hd),
-              prefix, (unsigned long)ri->rp->up.addr,
-              regs->EREG(ip), swap_get_uarg(regs, 0), swap_get_uarg(regs, 1),
-              swap_get_uret_addr(regs));
-#elif defined(CONFIG_ARM64)
-       printk(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%016lx), "
-              "x0(%016lx), x1(%016lx), x2(%016lx), x3(%016lx), "
-              "x4(%016lx), x5(%016lx), x6(%016lx), x7(%016lx), "
-              "sp(%016lx), lr(%016lx), pc(%016lx)\n",
-              current->comm, current->tgid, current->pid,
-              dentry != NULL ? (char *)(dentry->d_name.name) :
-                               (char *)("NULL"),
-              (int)lpd_get_state(hd),
-              prefix, (unsigned long)ri->rp->up.addr,
-              (long)regs->regs[0], (long)regs->regs[1],
-              (long)regs->regs[2], (long)regs->regs[3],
-              (long)regs->regs[4], (long)regs->regs[5],
-              (long)regs->regs[6], (long)regs->regs[7],
-              (long)regs->sp, swap_get_uret_addr(regs), (long)regs->pc);
-       (void)dentry;
-#else /* CONFIG_arch */
-# error "this architecture is not supported"
-#endif /* CONFIG_arch */
-}
-
-static inline unsigned long get_r_state_addr(struct vm_area_struct *linker_vma)
-{
-       unsigned long start_addr;
-       unsigned long offset = ld_r_state_offset();
-
-       if (linker_vma == NULL)
-               return 0;
-
-       start_addr = linker_vma->vm_start;
-
-       return (offset ? start_addr + offset : 0);
-}
-
-static struct vm_area_struct *__get_linker_vma(struct task_struct *task)
-{
-       struct vm_area_struct *vma = NULL;
-       struct bin_info *ld_info;
-
-       ld_info = ls_get_linker_info();
-       if (ld_info == NULL) {
-               printk(LOADER_PREFIX "Cannot get linker info [%u %u %s]!\n",
-                      task->tgid, task->pid, task->comm);
-               return NULL;
-       }
-
-       for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
-               if (vma->vm_file && vma->vm_flags & VM_EXEC
-                   && vma->vm_file->f_path.dentry == ld_info->dentry) {
-                               ls_put_linker_info(ld_info);
-                               return vma;
-               }
-       }
-
-       ls_put_linker_info(ld_info);
-       return NULL;
-}
-
-
-
-
-
-
-
-
-
-static bool __is_proc_mmap_mappable(struct task_struct *task)
-{
-       struct vm_area_struct *linker_vma = __get_linker_vma(task);
-       struct sspt_proc *proc;
-       unsigned long r_state_addr;
-       unsigned int state;
-
-       if (linker_vma == NULL)
-               return false;
-
-       r_state_addr = get_r_state_addr(linker_vma);
-       if (r_state_addr == 0)
-               return false;
-
-       proc = sspt_proc_get_by_task(task);
-       if (proc) {
-               proc->r_state_addr = r_state_addr;
-               sspt_proc_put(proc);
-       }
-
-       if (get_user(state, (unsigned long *)r_state_addr))
-               return false;
-
-       return !state;
-}
-
-static bool __should_we_load_handlers(struct task_struct *task,
-                                        struct pt_regs *regs)
-{
-       if (!__is_proc_mmap_mappable(task))
-               return false;
-
-       return true;
-}
-
-
-
-
-
-static void mmap_handler(struct sspt_proc *proc, struct vm_area_struct *vma)
-{
-       struct pd_t *pd;
-       unsigned long vaddr = vma->vm_start;
-       struct dentry *dentry = vma->vm_file->f_path.dentry;
-
-       pd = lpd_get(proc);
-       if (pd == NULL) {
-               printk(LOADER_PREFIX "%d: No process data! Current %d %s\n",
-                      __LINE__, current->tgid, current->comm);
-               return;
-       }
-
-       if (dentry == ld_get_loader_dentry()) {
-               lpd_set_loader_base(pd, vaddr);
-       } else {
-               struct hd_t *hd;
-
-               hd = lpd_get_hd(pd, dentry);
-               if (hd)
-                       lpd_set_handlers_base(hd, vaddr);
-       }
-}
-
-
-static struct usm_hook usm_hook = {
-       .owner = THIS_MODULE,
-       .mmap = mmap_handler,
-};
-
-static bool mmap_rp_inst = false;
-static DEFINE_MUTEX(mmap_rp_mtx);
-
-static void loader_start_cb(void)
-{
-       int res;
-
-       mutex_lock(&mmap_rp_mtx);
-       res = usm_hook_reg(&usm_hook);
-       if (res != 0)
-               pr_err(LOADER_PREFIX "Cannot register usm_hook\n");
-       else
-               mmap_rp_inst = true;
-       mutex_unlock(&mmap_rp_mtx);
-}
-
-static void loader_stop_cb(void)
-{
-       mutex_lock(&mmap_rp_mtx);
-       if (mmap_rp_inst) {
-               usm_hook_unreg(&usm_hook);
-               mmap_rp_inst = false;
-       }
-       mutex_unlock(&mmap_rp_mtx);
-}
-
-static unsigned long __not_loaded_entry(struct uretprobe_instance *ri,
-                                       struct pt_regs *regs,
-                                       struct pd_t *pd, struct hd_t *hd)
-{
-       char __user *path = NULL;
-       unsigned long vaddr = 0;
-       unsigned long base;
-
-       /* if linker is still doing its work, we do nothing */
-       if (!__should_we_load_handlers(current, regs))
-               return 0;
-
-       base = lpd_get_loader_base(pd);
-       if (base == 0)
-               return 0;   /* loader isn't mapped */
-
-       /* jump to loader code if ready */
-       vaddr = base + ld_get_loader_offset();
-       if (vaddr) {
-               /* save original regs state */
-               __save_uregs(ri, regs);
-               print_regs("ORIG", regs, ri, hd);
-
-               path = lpd_get_path(pd, hd);
-
-               /* set dlopen args: filename, flags */
-               swap_put_uarg(regs, 0, (unsigned long)path);
-               swap_put_uarg(regs, 1, 2 /* RTLD_NOW */);
-
-               /* do the jump to dlopen */
-               __prepare_ujump(ri, regs, vaddr);
-               /* set new state */
-               lpd_set_state(hd, LOADING);
-       }
-
-       return vaddr;
-}
-
-static void __loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                         struct pd_t *pd, struct hd_t *hd)
-{
-       struct us_priv *priv = (struct us_priv *)ri->data;
-       unsigned long vaddr = 0;
-
-       /* check if loading has been completed */
-       vaddr = lpd_get_loader_base(pd) +
-               ld_get_loader_offset();
-       if (vaddr && (priv->origin == vaddr)) {
-               lpd_set_handle(hd,
-                                     (void __user *)regs_return_value(regs));
-
-               /* restore original regs state */
-               __restore_uregs(ri, regs);
-               print_regs("REST", regs, ri, hd);
-               /* check if loading done */
-
-               if (lpd_get_handle(hd)) {
-                       lpd_set_state(hd, LOADED);
-               } else {
-                       lpd_dec_attempts(hd);
-                       lpd_set_state(hd, FAILED);
-               }
-       }
-}
-
-static void __failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                        struct pd_t *pd, struct hd_t *hd)
-{
-       if (lpd_get_attempts(hd))
-               lpd_set_state(hd, NOT_LOADED);
-}
-
-
-
-unsigned long loader_not_loaded_entry(struct uretprobe_instance *ri,
-                                      struct pt_regs *regs, struct pd_t *pd,
-                                      struct hd_t *hd)
-{
-       return __not_loaded_entry(ri, regs, pd, hd);
-}
-EXPORT_SYMBOL_GPL(loader_not_loaded_entry);
-
-void loader_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                        struct pd_t *pd, struct hd_t *hd)
-{
-       __loading_ret(ri, regs, pd, hd);
-}
-EXPORT_SYMBOL_GPL(loader_loading_ret);
-
-void loader_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                       struct pd_t *pd, struct hd_t *hd)
-{
-       __failed_ret(ri, regs, pd, hd);
-}
-EXPORT_SYMBOL_GPL(loader_failed_ret);
-
-void loader_module_prepare_ujump(struct uretprobe_instance *ri,
-                                 struct pt_regs *regs, unsigned long addr)
-{
-       __prepare_ujump(ri, regs, addr);
-}
-EXPORT_SYMBOL_GPL(loader_module_prepare_ujump);
-
-void loader_set_rp_data_size(struct uretprobe *rp)
-{
-       rp->data_size = sizeof(struct us_priv);
-}
-EXPORT_SYMBOL_GPL(loader_set_rp_data_size);
-
-void loader_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr)
-{
-       struct us_priv *priv = (struct us_priv *)ri->data;
-
-       priv->origin = addr;
-}
-EXPORT_SYMBOL_GPL(loader_set_priv_origin);
-
-unsigned long loader_get_priv_origin(struct uretprobe_instance *ri)
-{
-       struct us_priv *priv = (struct us_priv *)ri->data;
-
-       return priv->origin;
-}
-EXPORT_SYMBOL_GPL(loader_get_priv_origin);
-
-
-int loader_set(void)
-{
-       if (loader_module_is_running())
-               return -EBUSY;
-
-       return 0;
-}
-
-void loader_unset(void)
-{
-       mutex_lock(&mmap_rp_mtx);
-       if (mmap_rp_inst) {
-               usm_hook_unreg(&usm_hook);
-               mmap_rp_inst = false;
-       }
-       mutex_unlock(&mmap_rp_mtx);
-
-       /*module_put(THIS_MODULE);*/
-       loader_module_set_not_ready();
-}
-
-int loader_add_handler(const char *path)
-{
-       return ls_add_handler(path);
-}
-EXPORT_SYMBOL_GPL(loader_add_handler);
-
-
-static int loader_module_init(void)
-{
-       int ret;
-
-       ret = ld_init();
-       if (ret)
-               goto out_err;
-
-       ret = ls_init();
-       if (ret)
-               goto exit_debugfs;
-
-       ret = lpd_init();
-       if (ret)
-               goto exit_storage;
-
-       /* TODO do not forget to remove set (it is just for debugging) */
-       ret = loader_set();
-       if (ret)
-               goto exit_pd;
-
-       __loader_cbs_start_h = us_manager_reg_cb(START_CB, loader_start_cb);
-       if (__loader_cbs_start_h < 0)
-               goto exit_start_cb;
-
-       __loader_cbs_stop_h = us_manager_reg_cb(STOP_CB, loader_stop_cb);
-       if (__loader_cbs_stop_h < 0)
-               goto exit_stop_cb;
-
-       return 0;
-
-exit_stop_cb:
-       us_manager_unreg_cb(__loader_cbs_start_h);
-
-exit_start_cb:
-       loader_unset();
-
-exit_pd:
-       lpd_uninit();
-
-exit_storage:
-       ls_exit();
-
-exit_debugfs:
-       ld_exit();
-
-out_err:
-       return ret;
-}
-
-static void loader_module_exit(void)
-{
-       int balance;
-
-       us_manager_unreg_cb(__loader_cbs_start_h);
-       us_manager_unreg_cb(__loader_cbs_stop_h);
-       loader_unset();
-       lpd_uninit();
-       ls_exit();
-       ld_exit();
-
-       balance = atomic_read(&dentry_balance);
-       atomic_set(&dentry_balance, 0);
-
-       WARN(balance, "Bad GET/PUT dentry balance: %d\n", balance);
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, loader_module_init, loader_module_exit,
-                      NULL, NULL);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP Loader Module");
-MODULE_AUTHOR("Vasiliy Ulyanov <v.ulyanov@samsung.com>"
-              "Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/loader/loader_module.h b/loader/loader_module.h
deleted file mode 100644 (file)
index 801e5db..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __LOADER_MODULE_H__
-#define __LOADER_MODULE_H__
-
-#include <linux/types.h>
-
-struct dentry;
-
-bool loader_module_is_ready(void);
-bool loader_module_is_running(void);
-bool loader_module_is_not_ready(void);
-void loader_module_set_ready(void);
-void loader_module_set_running(void);
-void loader_module_set_not_ready(void);
-
-struct dentry *get_dentry(const char *filepath);
-void put_dentry(struct dentry *dentry);
-
-
-
-#endif /* __LOADER_MODULE_H__ */
diff --git a/loader/loader_pd.c b/loader/loader_pd.c
deleted file mode 100644 (file)
index a7597e3..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/dcache.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/module.h>
-#include <linux/hardirq.h>
-#include <linux/list.h>
-#include <us_manager/us_manager_common.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include "loader_pd.h"
-#include "loader.h"
-#include "loader_debugfs.h"
-#include "loader_storage.h"
-#include "loader_defs.h"
-
-
-struct pd_t {
-       unsigned long loader_base;
-       unsigned long data_page;
-       struct list_head handlers;
-       bool is_pthread_init;
-};
-
-struct hd_t {
-       struct list_head list;
-       struct dentry *dentry;
-       enum ps_t state;
-       struct pd_t *parent;
-       unsigned long base;
-       unsigned long offset;
-       void __user *handle;
-       long attempts;
-};
-
-
-static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
-{
-       struct file *file = vma->vm_file;
-
-       return (file && (vma->vm_flags & VM_EXEC) &&
-               (file->f_path.dentry == dentry));
-}
-
-static inline unsigned long __get_loader_base(struct pd_t *pd)
-{
-       return pd->loader_base;
-}
-
-static inline void __set_loader_base(struct pd_t *pd,
-                                    unsigned long addr)
-{
-       pd->loader_base = addr;
-}
-
-static inline unsigned long __get_data_page(struct pd_t *pd)
-{
-       return pd->data_page;
-}
-
-static inline void __set_data_page(struct pd_t *pd, unsigned long page)
-{
-       pd->data_page = page;
-}
-
-
-
-static inline enum ps_t __get_state(struct hd_t *hd)
-{
-       return hd->state;
-}
-
-static inline void __set_state(struct hd_t *hd, enum ps_t state)
-{
-       hd->state = state;
-}
-
-static inline unsigned long __get_handlers_base(struct hd_t *hd)
-{
-       return hd->base;
-}
-
-static inline void __set_handlers_base(struct hd_t *hd,
-                                      unsigned long addr)
-{
-       hd->base = addr;
-}
-
-static inline unsigned long __get_offset(struct hd_t *hd)
-{
-       return hd->offset;
-}
-
-static inline void *__get_handle(struct hd_t *hd)
-{
-       return hd->handle;
-}
-
-static inline void __set_handle(struct hd_t *hd, void __user *handle)
-{
-       hd->handle = handle;
-}
-
-static inline long __get_attempts(struct hd_t *hd)
-{
-       return hd->attempts;
-}
-
-static inline void __set_attempts(struct hd_t *hd, long attempts)
-{
-       hd->attempts = attempts;
-}
-
-
-
-static struct vm_area_struct *find_vma_by_dentry(struct mm_struct *mm,
-                                                struct dentry *dentry)
-{
-       struct vm_area_struct *vma;
-
-       for (vma = mm->mmap; vma; vma = vma->vm_next)
-               if (check_vma(vma, dentry))
-                       return vma;
-
-       return NULL;
-}
-
-static struct pd_t *__create_pd(void)
-{
-       struct pd_t *pd;
-       unsigned long page;
-
-       pd = kzalloc(sizeof(*pd), GFP_ATOMIC);
-       if (pd == NULL)
-               return NULL;
-
-       down_write(&current->mm->mmap_sem);
-       page = __swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
-                             MAP_ANONYMOUS | MAP_PRIVATE, 0);
-       up_write(&current->mm->mmap_sem);
-       if (IS_ERR_VALUE(page)) {
-               printk(KERN_ERR LOADER_PREFIX
-                      "Cannot alloc page for %u\n", current->tgid);
-               goto create_pd_fail;
-       }
-
-       __set_data_page(pd, page);
-       pd->is_pthread_init = true;
-       INIT_LIST_HEAD(&pd->handlers);
-
-       return pd;
-
-create_pd_fail:
-       kfree(pd);
-
-       return NULL;
-}
-
-static size_t __copy_path(char *src, unsigned long page, unsigned long offset)
-{
-       unsigned long dest = page + offset;
-       size_t len = strnlen(src, PATH_MAX);
-
-       /* set handler path */
-       if (copy_to_user((void __user *)dest, src, len) != 0) {
-               printk(KERN_ERR LOADER_PREFIX
-                      "Cannot copy string to user!\n");
-               return 0;
-       }
-
-       return len;
-}
-
-static void __set_ld_mapped(struct pd_t *pd, struct mm_struct *mm)
-{
-       struct vm_area_struct *vma;
-       struct dentry *ld = ld_get_loader_dentry();
-
-       down_read(&mm->mmap_sem);
-       if (ld) {
-               vma = find_vma_by_dentry(mm, ld);
-               if (vma)
-                       __set_loader_base(pd, vma->vm_start);
-       }
-       up_read(&mm->mmap_sem);
-}
-
-static void __set_handler_mapped(struct hd_t *hd, struct mm_struct *mm)
-{
-       struct vm_area_struct *vma;
-       struct dentry *handlers = hd->dentry;
-
-       down_read(&mm->mmap_sem);
-       if (handlers) {
-               vma = find_vma_by_dentry(mm, handlers);
-               if (vma) {
-                       __set_handlers_base(hd, vma->vm_start);
-                       __set_state(hd, LOADED);
-                       goto set_handler_mapped_out;
-               }
-       }
-       __set_state(hd, NOT_LOADED);
-
-set_handler_mapped_out:
-       up_read(&mm->mmap_sem);
-}
-
-
-static int __get_handlers(struct pd_t *pd, struct task_struct *task)
-{
-       struct list_head *handlers = NULL;
-       struct bin_info_el *bin;
-       struct hd_t *hd;
-       unsigned long offset = 0;
-       size_t len;
-       int ret = 0;
-
-       handlers = ls_get_handlers();
-       if (handlers == NULL)
-               return -EINVAL;
-
-       list_for_each_entry(bin, handlers, list) {
-               len = __copy_path(bin->path, pd->data_page, offset);
-               if (len == 0) {
-                       ret = -EINVAL;
-                       goto get_handlers_out;
-               }
-
-               hd = kzalloc(sizeof(*hd), GFP_ATOMIC);
-               if (hd == NULL) {
-                       printk(KERN_ERR LOADER_PREFIX "No atomic mem!\n");
-                       ret = -ENOMEM;
-                       goto get_handlers_out;
-               }
-
-
-               INIT_LIST_HEAD(&hd->list);
-               hd->parent = pd;
-               hd->dentry = bin->dentry;
-               hd->offset = offset;
-               __set_handler_mapped(hd, task->mm);
-               __set_attempts(hd, LOADER_MAX_ATTEMPTS);
-               list_add_tail(&hd->list, &pd->handlers);
-
-               /* inc handlers path's on page */
-               offset += len + 1;
-       }
-
-get_handlers_out:
-       /* TODO Cleanup already created */
-       ls_put_handlers();
-
-       return ret;
-}
-
-
-
-enum ps_t lpd_get_state(struct hd_t *hd)
-{
-       if (hd == NULL)
-               return 0;
-
-       return __get_state(hd);
-}
-EXPORT_SYMBOL_GPL(lpd_get_state);
-
-void lpd_set_state(struct hd_t *hd, enum ps_t state)
-{
-       if (hd == NULL) {
-               printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n",
-                      __LINE__, current->tgid, current->comm);
-               return;
-       }
-
-       __set_state(hd, state);
-}
-
-unsigned long lpd_get_loader_base(struct pd_t *pd)
-{
-       if (pd == NULL)
-               return 0;
-
-       return __get_loader_base(pd);
-}
-
-void lpd_set_loader_base(struct pd_t *pd, unsigned long vaddr)
-{
-       __set_loader_base(pd, vaddr);
-}
-
-unsigned long lpd_get_handlers_base(struct hd_t *hd)
-{
-       if (hd == NULL)
-               return 0;
-
-       return __get_handlers_base(hd);
-}
-EXPORT_SYMBOL_GPL(lpd_get_handlers_base);
-
-void lpd_set_handlers_base(struct hd_t *hd, unsigned long vaddr)
-{
-       __set_handlers_base(hd, vaddr);
-}
-
-char __user *lpd_get_path(struct pd_t *pd, struct hd_t *hd)
-{
-       unsigned long page = __get_data_page(pd);
-       unsigned long offset = __get_offset(hd);
-
-       return (char __user *)(page + offset);
-}
-
-
-
-void *lpd_get_handle(struct hd_t *hd)
-{
-       if (hd == NULL)
-               return NULL;
-
-       return __get_handle(hd);
-}
-
-void lpd_set_handle(struct hd_t *hd, void __user *handle)
-{
-       if (hd == NULL) {
-               printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n",
-                      __LINE__, current->tgid, current->comm);
-               return;
-       }
-
-       __set_handle(hd, handle);
-}
-
-long lpd_get_attempts(struct hd_t *hd)
-{
-       if (hd == NULL)
-               return -EINVAL;
-
-       return __get_attempts(hd);
-}
-
-void lpd_dec_attempts(struct hd_t *hd)
-{
-       long attempts;
-
-       if (hd == NULL) {
-               printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n",
-                      __LINE__, current->tgid, current->comm);
-               return;
-       }
-
-       attempts = __get_attempts(hd);
-       attempts--;
-       __set_attempts(hd, attempts);
-}
-
-struct dentry *lpd_get_dentry(struct hd_t *hd)
-{
-       return hd->dentry;
-}
-
-struct pd_t *lpd_get_parent_pd(struct hd_t *hd)
-{
-       return hd->parent;
-}
-EXPORT_SYMBOL_GPL(lpd_get_parent_pd);
-
-struct pd_t *lpd_get(struct sspt_proc *proc)
-{
-       return (struct pd_t *)proc->private_data;
-}
-EXPORT_SYMBOL_GPL(lpd_get);
-
-struct pd_t *lpd_get_by_task(struct task_struct *task)
-{
-       struct sspt_proc *proc = sspt_proc_by_task(task);
-
-       return lpd_get(proc);
-}
-EXPORT_SYMBOL_GPL(lpd_get_by_task);
-
-struct hd_t *lpd_get_hd(struct pd_t *pd, struct dentry *dentry)
-{
-       struct hd_t *hd;
-
-       list_for_each_entry(hd, &pd->handlers, list) {
-               if (hd->dentry == dentry)
-                       return hd;
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(lpd_get_hd);
-
-/* TODO Move it to GOT patcher, only it uses this */
-bool lpd_get_init_state(struct pd_t *pd)
-{
-       return pd->is_pthread_init;
-}
-EXPORT_SYMBOL_GPL(lpd_get_init_state);
-
-/* TODO Move it to GOT patcher, only it uses this */
-void lpd_set_init_state(struct pd_t *pd, bool state)
-{
-       pd->is_pthread_init = state;
-}
-EXPORT_SYMBOL_GPL(lpd_set_init_state);
-
-static struct pd_t *do_create_pd(struct task_struct *task)
-{
-       struct pd_t *pd;
-       int ret;
-
-       pd = __create_pd();
-       if (pd == NULL) {
-               ret = -ENOMEM;
-               goto create_pd_exit;
-       }
-
-       ret = __get_handlers(pd, task);
-       if (ret)
-               goto free_pd;
-
-       __set_ld_mapped(pd, task->mm);
-
-       return pd;
-
-free_pd:
-       kfree(pd);
-
-create_pd_exit:
-       printk(KERN_ERR LOADER_PREFIX "do_pd_create_pd: error=%d\n", ret);
-       return NULL;
-}
-
-static void *pd_create(struct sspt_proc *proc)
-{
-       struct pd_t *pd;
-
-       pd = do_create_pd(proc->leader);
-
-       return (void *)pd;
-}
-
-static void pd_destroy(struct sspt_proc *proc, void *data)
-{
-       /* FIXME: to be implemented */
-}
-
-struct sspt_proc_cb pd_cb = {
-       .priv_create = pd_create,
-       .priv_destroy = pd_destroy
-};
-
-int lpd_init(void)
-{
-       int ret;
-
-       ret = sspt_proc_cb_set(&pd_cb);
-
-       return ret;
-}
-
-void lpd_uninit(void)
-{
-       sspt_proc_cb_set(NULL);
-
-       /* TODO Cleanup */
-}
diff --git a/loader/loader_pd.h b/loader/loader_pd.h
deleted file mode 100644 (file)
index aa9da45..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __LOADER_PD_H__
-#define __LOADER_PD_H__
-
-#include <loader/loader.h>
-
-struct pd_t;
-struct hd_t;
-struct sspt_proc;
-struct dentry;
-struct list_head;
-
-
-unsigned long lpd_get_loader_base(struct pd_t *pd);
-void lpd_set_loader_base(struct pd_t *pd, unsigned long vaddr);
-
-void lpd_set_state(struct hd_t *hd, enum ps_t state);
-void lpd_set_handlers_base(struct hd_t *hd, unsigned long vaddr);
-void lpd_set_handle(struct hd_t *hd, void __user *handle);
-
-char __user *lpd_get_path(struct pd_t *pd, struct hd_t *hd);
-
-int lpd_init(void);
-void lpd_uninit(void);
-
-
-#endif /* __LOADER_PD_H__*/
diff --git a/loader/loader_storage.c b/loader/loader_storage.c
deleted file mode 100644 (file)
index 2be688e..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <ks_features/ks_map.h>
-#include <us_manager/us_common_file.h>
-#include "loader_defs.h"
-#include "loader_module.h"
-#include "loader_storage.h"
-
-static struct bin_info __linker_info = { NULL, NULL };
-
-static LIST_HEAD(handlers_list);
-
-
-static bool __check_dentry_already_exist(struct dentry *dentry)
-{
-       struct bin_info_el *bin;
-       bool ret = false;
-
-       list_for_each_entry(bin, &handlers_list, list) {
-               if (bin->dentry == dentry) {
-                       ret = true;
-                       goto out;
-               }
-       }
-
-out:
-       return ret;
-}
-
-static inline int __add_handler(const char *path)
-{
-       struct dentry *dentry;
-       size_t len = strnlen(path, PATH_MAX);
-       struct bin_info_el *bin;
-       int ret = 0;
-
-       dentry = swap_get_dentry(path);
-       if (!dentry) {
-               ret = -ENOENT;
-               goto add_handler_out;
-       }
-
-       if (__check_dentry_already_exist(dentry)) {
-               ret = 1;
-               goto add_handler_fail_release_dentry;
-       }
-
-       bin = kmalloc(sizeof(*bin), GFP_KERNEL);
-       if (bin == NULL) {
-               ret = -ENOMEM;
-               goto add_handler_fail_release_dentry;
-       }
-
-       bin->path = kmalloc(len + 1, GFP_KERNEL);
-       if (bin->path == NULL) {
-               ret = -ENOMEM;
-               goto add_handler_fail_free_bin;
-       }
-
-       INIT_LIST_HEAD(&bin->list);
-       strncpy(bin->path, path, len);
-       bin->path[len] = '\0';
-       bin->dentry = dentry;
-       list_add_tail(&bin->list, &handlers_list);
-
-       return ret;
-
-add_handler_fail_free_bin:
-       kfree(bin);
-
-add_handler_fail_release_dentry:
-       swap_put_dentry(dentry);
-
-add_handler_out:
-       return ret;
-}
-
-static inline void __remove_handler(struct bin_info_el *bin)
-{
-       list_del(&bin->list);
-       swap_put_dentry(bin->dentry);
-       kfree(bin->path);
-       kfree(bin);
-}
-
-static inline void __remove_handlers(void)
-{
-       struct bin_info_el *bin, *tmp;
-
-       list_for_each_entry_safe(bin, tmp, &handlers_list, list)
-               __remove_handler(bin);
-}
-
-static inline struct bin_info *__get_linker_info(void)
-{
-       return &__linker_info;
-}
-
-static inline bool __check_linker_info(void)
-{
-       return (__linker_info.dentry != NULL); /* TODO */
-}
-
-static inline int __init_linker_info(char *path)
-{
-       struct dentry *dentry;
-       size_t len = strnlen(path, PATH_MAX);
-       int ret = 0;
-
-
-       __linker_info.path = kmalloc(len + 1, GFP_KERNEL);
-       if (__linker_info.path == NULL) {
-               ret = -ENOMEM;
-               goto init_linker_fail;
-       }
-
-       dentry = swap_get_dentry(path);
-       if (!dentry) {
-               ret = -ENOENT;
-               goto init_linker_fail_free;
-       }
-
-       strncpy(__linker_info.path, path, len);
-       __linker_info.path[len] = '\0';
-       __linker_info.dentry = dentry;
-
-       return ret;
-
-init_linker_fail_free:
-       kfree(__linker_info.path);
-
-init_linker_fail:
-
-       return ret;
-}
-
-static inline void __drop_linker_info(void)
-{
-       kfree(__linker_info.path);
-       __linker_info.path = NULL;
-
-       if (__linker_info.dentry)
-               swap_put_dentry(__linker_info.dentry);
-       __linker_info.dentry = NULL;
-}
-
-
-
-
-int ls_add_handler(const char *path)
-{
-       int ret;
-
-       /* If ret is positive - handler was not added, because it is
-        * already exists */
-       ret = __add_handler(path);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-struct list_head *ls_get_handlers(void)
-{
-       /* TODO counter, syncs */
-       return &handlers_list;
-}
-
-void ls_put_handlers(void)
-{
-       /* TODO dec counter, release sync */
-}
-
-int ls_set_linker_info(char *path)
-{
-       return __init_linker_info(path);
-}
-
-struct bin_info *ls_get_linker_info(void)
-{
-       struct bin_info *info = __get_linker_info();
-
-       if (__check_linker_info())
-               return info;
-
-       return NULL;
-}
-
-void ls_put_linker_info(struct bin_info *info)
-{
-}
-
-int ls_init(void)
-{
-       return 0;
-}
-
-void ls_exit(void)
-{
-       __drop_linker_info();
-       __remove_handlers();
-}
diff --git a/loader/loader_storage.h b/loader/loader_storage.h
deleted file mode 100644 (file)
index 69d2121..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __LOADER_STORAGE_H__
-#define __LOADER_STORAGE_H__
-
-struct list_head;
-struct dentry;
-
-struct bin_info {
-       char *path;
-       /* ghot */
-       struct dentry *dentry;
-};
-
-struct bin_info_el {
-       struct list_head list;
-       char *path;
-       /* ghot */
-       struct dentry *dentry;
-};
-
-
-
-int ls_add_handler(const char *path);
-struct list_head *ls_get_handlers(void);
-void ls_put_handlers(void);
-
-int ls_set_linker_info(char *path);
-struct bin_info *ls_get_linker_info(void);
-void ls_put_linker_info(struct bin_info *info);
-
-int ls_init(void);
-void ls_exit(void);
-
-#endif /* __LOADER_HANDLERS_H__ */
diff --git a/master/Kbuild b/master/Kbuild
deleted file mode 100644 (file)
index 4265607..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_master.o
-swap_master-y := master_module.o \
-                 swap_debugfs.o \
-                 swap_initializer.o \
-                 swap_deps.o \
-                 wait.o
diff --git a/master/master_module.c b/master/master_module.c
deleted file mode 100644 (file)
index e3b7553..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include "swap_debugfs.h"
-#include "swap_initializer.h"
-
-
-static int __init master_init(void)
-{
-       return swap_debugfs_init();
-}
-
-static void __exit master_exit(void)
-{
-       swap_debugfs_uninit();
-}
-
-module_init(master_init);
-module_exit(master_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/master/swap_debugfs.c b/master/swap_debugfs.c
deleted file mode 100644 (file)
index 661305b..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/version.h>
-#include "swap_initializer.h"
-#include "swap_debugfs.h"
-
-
-static int change_permission(struct dentry *dentry)
-{
-       const int system_fw = 202;
-
-       /* set UNIX permissions */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-       dentry->d_inode->i_uid = KUIDT_INIT(system_fw);
-       dentry->d_inode->i_gid = KGIDT_INIT(system_fw);
-#else
-       dentry->d_inode->i_uid = system_fw;
-       dentry->d_inode->i_gid = system_fw;
-#endif
-
-       return 0;
-}
-
-struct dentry *swap_debugfs_create_file(const char *name, umode_t mode,
-                                       struct dentry *parent, void *data,
-                                       const struct file_operations *fops)
-{
-       struct dentry *dentry;
-
-       dentry = debugfs_create_file(name, mode, parent, data, fops);
-       if (dentry) {
-               if (change_permission(dentry)) {
-                       debugfs_remove(dentry);
-                       return NULL;
-               }
-       }
-
-       return dentry;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_file);
-
-struct dentry *swap_debugfs_create_dir(const char *name, struct dentry *parent)
-{
-       struct dentry *dentry;
-
-       dentry = debugfs_create_dir(name, parent);
-       if (dentry) {
-               if (change_permission(dentry)) {
-                       debugfs_remove(dentry);
-                       return NULL;
-               }
-       }
-
-       return dentry;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_dir);
-
-struct dentry *swap_debugfs_create_x32(const char *name, umode_t mode,
-                                      struct dentry *parent, u32 *value)
-{
-       struct dentry *dentry;
-
-       dentry = debugfs_create_x32(name, mode, parent, value);
-       if (dentry) {
-               if (change_permission(dentry)) {
-                       debugfs_remove(dentry);
-                       return NULL;
-               }
-       }
-
-       return dentry;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_x32);
-
-struct dentry *swap_debugfs_create_x64(const char *name, umode_t mode,
-                                      struct dentry *parent, u64 *value)
-{
-       struct dentry *dentry;
-
-       dentry = debugfs_create_x64(name, mode, parent, value);
-       if (dentry) {
-               if (change_permission(dentry)) {
-                       debugfs_remove(dentry);
-                       return NULL;
-               }
-       }
-
-       return dentry;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_x64);
-
-struct dentry *swap_debugfs_create_u64(const char *name, umode_t mode,
-                                      struct dentry *parent, u64 *value)
-{
-       struct dentry *dentry;
-
-       dentry = debugfs_create_u64(name, mode, parent, value);
-       if (dentry) {
-               if (change_permission(dentry)) {
-                       debugfs_remove(dentry);
-                       return NULL;
-               }
-       }
-
-       return dentry;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_u64);
-
-
-/* based on define DEFINE_SIMPLE_ATTRIBUTE */
-#define SWAP_DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)      \
-static int __fops ## _open(struct inode *inode, struct file *file)     \
-{                                                                      \
-       int ret;                                                        \
-                                                                       \
-       ret = swap_init_simple_open(inode, file);                       \
-       if (ret)                                                        \
-               return ret;                                             \
-                                                                       \
-       __simple_attr_check_format(__fmt, 0ull);                        \
-       ret = simple_attr_open(inode, file, __get, __set, __fmt);       \
-       if (ret)                                                        \
-               swap_init_simple_release(inode, file);                  \
-                                                                       \
-       return ret;                                                     \
-}                                                                      \
-static int __fops ## _release(struct inode *inode, struct file *file)  \
-{                                                                      \
-       simple_attr_release(inode, file);                               \
-       swap_init_simple_release(inode, file);                          \
-                                                                       \
-       return 0;                                                       \
-}                                                                      \
-static const struct file_operations __fops = {                         \
-       .owner   = THIS_MODULE,                                         \
-       .open    = __fops ## _open,                                     \
-       .release = __fops ## _release,                                  \
-       .read    = simple_attr_read,                                    \
-       .write   = simple_attr_write,                                   \
-       .llseek  = generic_file_llseek,                                 \
-}
-
-
-static int fset_u64(void *data, u64 val)
-{
-       struct dfs_setget_64 *setget = data;
-
-       return setget->set(val);
-}
-
-static int fget_u64(void *data, u64 *val)
-{
-       struct dfs_setget_64 *setget = data;
-
-       *val = setget->get();
-       return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_u64, fget_u64, fset_u64, "%llu\n");
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_u64_ro, fget_u64, NULL, "%llu\n");
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_u64_wo, NULL, fset_u64, "%llu\n");
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_x64, fget_u64, fset_u64, "0x%08llx\n");
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_x64_ro, fget_u64, NULL, "0x%08llx\n");
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_x64_wo, NULL, fset_u64, "0x%08llx\n");
-
-static struct dentry *do_create_dfs_file(const char *name, umode_t mode,
-                                        struct dentry *parent, void *data,
-                                        const struct file_operations *fops,
-                                        const struct file_operations *fops_ro,
-                                        const struct file_operations *fops_wo)
-{
-       /* if there are no write bits set, make read only */
-       if (!(mode & S_IWUGO))
-               return swap_debugfs_create_file(name, mode, parent,
-                                               data, fops_ro);
-       /* if there are no read bits set, make write only */
-       if (!(mode & S_IRUGO))
-               return swap_debugfs_create_file(name, mode, parent,
-                                               data, fops_wo);
-
-       return swap_debugfs_create_file(name, mode, parent, data, fops);
-}
-
-struct dentry *swap_debugfs_create_setget_u64(const char *name, umode_t mode,
-                                             struct dentry *parent,
-                                             struct dfs_setget_64 *setget)
-{
-       return do_create_dfs_file(name, mode, parent, setget,
-                                 &fops_setget_u64,
-                                 &fops_setget_u64_ro,
-                                 &fops_setget_u64_wo);
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_setget_u64);
-
-struct dentry *swap_debugfs_create_setget_x64(const char *name, umode_t mode,
-                                             struct dentry *parent,
-                                             struct dfs_setget_64 *setget)
-{
-       return do_create_dfs_file(name, mode, parent, setget,
-                                 &fops_setget_x64,
-                                 &fops_setget_x64_ro,
-                                 &fops_setget_x64_wo);
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_create_setget_x64);
-
-
-static int set_enable(int enable)
-{
-       int ret = 0, change, enable_current;
-
-       enable_current = swap_init_stat_get();
-
-       change = ((!!enable_current) << 1) | (!!enable);
-       switch (change) {
-       case 0b01: /* init */
-               ret = swap_init_init();
-               break;
-       case 0b10: /* uninit */
-               ret = swap_init_uninit();
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       swap_init_stat_put();
-
-       return ret;
-}
-
-static ssize_t read_enable(struct file *file, char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       char buf[3];
-       int enable;
-
-       enable = swap_init_stat_get();
-       swap_init_stat_put();
-
-       if (enable)
-               buf[0] = '1';
-       else
-               buf[0] = '0';
-       buf[1] = '\n';
-       buf[2] = '\0';
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static int do_write_enable(const char *buf, size_t size)
-{
-       if (size < 1)
-               return -EINVAL;
-
-       switch (buf[0]) {
-       case '1':
-               return set_enable(1);
-       case '0':
-               return set_enable(0);
-       }
-
-       return -EINVAL;
-}
-
-static ssize_t write_enable(struct file *file, const char __user *user_buf,
-                           size_t count, loff_t *ppos)
-{
-       int ret;
-       char buf[32];
-       size_t buf_size;
-
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       ret = do_write_enable(buf, buf_size);
-
-       return ret ? ret : count;
-}
-
-static const struct file_operations fops_enable = {
-       .owner = THIS_MODULE,
-       .read = read_enable,
-       .write = write_enable,
-       .llseek = default_llseek,
-};
-
-
-static struct dentry *swap_dir;
-
-/**
- * @brief Get debugfs dir.
- *
- * @return Pointer to dentry stuct.
- */
-struct dentry *swap_debugfs_getdir(void)
-{
-       return swap_dir;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_getdir);
-
-static int debugfs_dir_init(void)
-{
-       swap_dir = swap_debugfs_create_dir("swap", NULL);
-       if (swap_dir == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-
-static void debugfs_dir_exit(void)
-{
-       struct dentry *dir = swap_dir;
-
-       swap_dir = NULL;
-       debugfs_remove_recursive(dir);
-}
-
-/**
- * @brief Initializes SWAP debugfs.
- *
- * @return 0 on success, negative error code on error.
- */
-int swap_debugfs_init(void)
-{
-       int ret;
-       struct dentry *dentry;
-
-       ret = debugfs_dir_init();
-       if (ret)
-               return ret;
-
-       dentry = swap_debugfs_create_file("enable", 0600, swap_dir, NULL,
-                                         &fops_enable);
-       if (dentry == NULL) {
-               debugfs_dir_exit();
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Deinitializes SWAP debugfs and recursively removes all its files.
- *
- * @return Void.
- */
-void swap_debugfs_uninit(void)
-{
-       debugfs_dir_exit();
-}
diff --git a/master/swap_debugfs.h b/master/swap_debugfs.h
deleted file mode 100644 (file)
index 2717db9..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, 2015
- *
- * @section DESCRIPTION
- *
- * SWAP debugfs interface definition.
- */
-
-#ifndef _SWAP_DEBUGFS_H
-#define _SWAP_DEBUGFS_H
-
-
-#include <linux/types.h>
-
-
-struct dfs_setget_64 {
-       int (*set)(u64 val);
-       u64 (*get)(void);
-};
-
-struct dentry;
-struct file_operations;
-
-struct dentry *swap_debugfs_create_setget_u64(const char *name, umode_t mode,
-                                             struct dentry *parent,
-                                             struct dfs_setget_64 *setget);
-
-struct dentry *swap_debugfs_create_setget_x64(const char *name, umode_t mode,
-                                             struct dentry *parent,
-                                             struct dfs_setget_64 *setget);
-
-struct dentry *swap_debugfs_create_file(const char *name, umode_t mode,
-                                       struct dentry *parent, void *data,
-                                       const struct file_operations *fops);
-struct dentry *swap_debugfs_create_dir(const char *name, struct dentry *parent);
-
-struct dentry *swap_debugfs_create_x32(const char *name, umode_t mode,
-                                      struct dentry *parent, u32 *value);
-struct dentry *swap_debugfs_create_x64(const char *name, umode_t mode,
-                                      struct dentry *parent, u64 *value);
-struct dentry *swap_debugfs_create_u64(const char *name, umode_t mode,
-                                      struct dentry *parent, u64 *value);
-
-struct dentry *swap_debugfs_getdir(void);
-
-int swap_debugfs_init(void);
-void swap_debugfs_uninit(void);
-
-
-#endif /* _SWAP_DEBUGFS_H */
diff --git a/master/swap_deps.c b/master/swap_deps.c
deleted file mode 100644 (file)
index 0c566c1..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <ksyms/ksyms.h>
-#include "swap_deps.h"
-
-
-static struct files_struct *(*__get_files_struct)(struct task_struct *);
-static void (*__put_files_struct)(struct files_struct *fs);
-
-struct files_struct *swap_get_files_struct(struct task_struct *task)
-{
-       return __get_files_struct(task);
-}
-EXPORT_SYMBOL_GPL(swap_get_files_struct);
-
-void swap_put_files_struct(struct files_struct *fs)
-{
-       __put_files_struct(fs);
-}
-EXPORT_SYMBOL_GPL(swap_put_files_struct);
-
-
-int chef_once(void)
-{
-       const char *sym;
-       static unsigned once_flag = 0;
-
-       if (once_flag)
-               return 0;
-
-       sym = "get_files_struct";
-       __get_files_struct = (void *)swap_ksyms(sym);
-       if (__get_files_struct == NULL)
-               goto not_found;
-
-       sym = "put_files_struct";
-       __put_files_struct = (void *)swap_ksyms(sym);
-       if (__put_files_struct == NULL)
-               goto not_found;
-
-       once_flag = 1;
-       return 0;
-
-not_found:
-       printk("ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
diff --git a/master/swap_deps.h b/master/swap_deps.h
deleted file mode 100644 (file)
index ca4c978..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_DEPS_H
-#define _SWAP_DEPS_H
-
-
-struct task_struct;
-struct files_struct;
-
-
-struct files_struct *swap_get_files_struct(struct task_struct *task);
-void swap_put_files_struct(struct files_struct *fs);
-
-
-int chef_once(void);
-
-
-#endif /* _SWAP_DEPS_H */
diff --git a/master/swap_initializer.c b/master/swap_initializer.c
deleted file mode 100644 (file)
index a7ea8c3..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include "swap_initializer.h"
-#include "swap_deps.h"
-
-
-enum init_level {
-       IL_CORE,
-       IL_FS
-};
-
-static swap_init_t sis_get_fn_init(struct swap_init_struct *init,
-                                  enum init_level level)
-{
-       switch (level) {
-       case IL_CORE:
-               return init->core_init;
-       case IL_FS:
-               return init->fs_init;
-       default:
-               return NULL;
-       }
-}
-
-static swap_uninit_t sis_get_fn_uninit(struct swap_init_struct *init,
-                                      enum init_level level)
-{
-       switch (level) {
-       case IL_CORE:
-               return init->core_uninit;
-       case IL_FS:
-               return init->fs_uninit;
-       }
-
-       return NULL;
-}
-
-static void sis_set_flag(struct swap_init_struct *init,
-                        enum init_level level, bool val)
-{
-       switch (level) {
-       case IL_CORE:
-               init->core_flag = val;
-               break;
-       case IL_FS:
-               init->fs_flag = val;
-               break;
-       }
-}
-
-static bool sis_get_flag(struct swap_init_struct *init, enum init_level level)
-{
-       switch (level) {
-       case IL_CORE:
-               return init->core_flag;
-       case IL_FS:
-               return init->fs_flag;
-       }
-
-       return false;
-}
-
-static int sis_once(struct swap_init_struct *init)
-{
-       swap_init_t once;
-
-       once = init->once;
-       if (!init->once_flag && once) {
-               int ret;
-
-               ret = once();
-               if (ret)
-                       return ret;
-
-               init->once_flag = true;
-       }
-
-       return 0;
-}
-
-static int sis_init_level(struct swap_init_struct *init, enum init_level level)
-{
-       int ret;
-       swap_init_t fn;
-
-       if (sis_get_flag(init, level))
-               return -EPERM;
-
-       fn = sis_get_fn_init(init, level);
-       if (fn) {
-               ret = fn();
-               if (ret)
-                       return ret;
-       }
-
-       sis_set_flag(init, level, true);
-       return 0;
-}
-
-static void sis_uninit_level(struct swap_init_struct *init,
-                            enum init_level level)
-{
-       if (sis_get_flag(init, level)) {
-               swap_uninit_t fn = sis_get_fn_uninit(init, level);
-               if (fn)
-                       fn();
-               sis_set_flag(init, level, false);
-       }
-}
-
-static int sis_init(struct swap_init_struct *init)
-{
-       int ret;
-
-       ret = sis_once(init);
-       if (ret)
-               return ret;
-
-       ret = sis_init_level(init, IL_CORE);
-       if (ret)
-               return ret;
-
-       ret = sis_init_level(init, IL_FS);
-       if (ret)
-               sis_uninit_level(init, IL_CORE);
-
-       return ret;
-}
-
-static void sis_uninit(struct swap_init_struct *init)
-{
-       sis_uninit_level(init, IL_FS);
-       sis_uninit_level(init, IL_CORE);
-}
-
-static LIST_HEAD(init_list);
-static DEFINE_MUTEX(inst_mutex);
-static unsigned init_flag;
-
-static int do_once(void)
-{
-       int ret;
-       struct swap_init_struct *init;
-
-       ret = chef_once();
-       if (ret)
-               return ret;
-
-       list_for_each_entry(init, &init_list, list) {
-               ret = sis_once(init);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static void do_uninit_level(enum init_level level)
-{
-       struct swap_init_struct *init;
-
-       list_for_each_entry_reverse(init, &init_list, list)
-               sis_uninit_level(init, level);
-}
-
-static int do_init_level(enum init_level level)
-{
-       int ret;
-       struct swap_init_struct *init;
-
-       list_for_each_entry(init, &init_list, list) {
-               ret = sis_init_level(init, level);
-               if (ret) {
-                       do_uninit_level(level);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static int do_init(void)
-{
-       int ret;
-
-       ret = do_once();
-       if (ret)
-               return ret;
-
-       ret = do_init_level(IL_CORE);
-       if (ret)
-               return ret;
-
-       ret = do_init_level(IL_FS);
-       if (ret)
-               do_uninit_level(IL_CORE);
-
-       init_flag = 1;
-
-       return 0;
-}
-
-static void do_uninit(void)
-{
-       do_uninit_level(IL_FS);
-       do_uninit_level(IL_CORE);
-
-       init_flag = 0;
-}
-
-
-static atomic_t init_use = ATOMIC_INIT(0);
-
-enum init_stat_t {
-       IS_OFF,
-       IS_SWITCHING,
-       IS_ON,
-};
-
-static enum init_stat_t init_stat;
-static DEFINE_SPINLOCK(init_stat_lock);
-
-
-static bool swap_init_try_get(void)
-{
-       spin_lock(&init_stat_lock);
-       if (init_stat != IS_ON) {
-               spin_unlock(&init_stat_lock);
-               return false;
-       }
-       spin_unlock(&init_stat_lock);
-
-       atomic_inc(&init_use);
-
-       return true;
-}
-
-static void swap_init_put(void)
-{
-       atomic_dec(&init_use);
-}
-
-int swap_init_simple_open(struct inode *inode, struct file *file)
-{
-       if (swap_init_try_get() == false)
-               return -EBUSY;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_init_simple_open);
-
-int swap_init_simple_release(struct inode *inode, struct file *file)
-{
-       swap_init_put();
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_init_simple_release);
-
-int swap_init_init(void)
-{
-       int ret;
-
-       spin_lock(&init_stat_lock);
-       init_stat = IS_SWITCHING;
-       spin_unlock(&init_stat_lock);
-
-       ret = do_init();
-
-       spin_lock(&init_stat_lock);
-       init_stat = ret ? IS_OFF : IS_ON;
-       spin_unlock(&init_stat_lock);
-
-       return ret;
-}
-
-int swap_init_uninit(void)
-{
-       spin_lock(&init_stat_lock);
-       init_stat = IS_SWITCHING;
-       if (atomic_read(&init_use)) {
-               init_stat = IS_ON;
-               spin_unlock(&init_stat_lock);
-               return -EBUSY;
-       }
-       spin_unlock(&init_stat_lock);
-
-       do_uninit();
-
-       spin_lock(&init_stat_lock);
-       init_stat = IS_OFF;
-       spin_unlock(&init_stat_lock);
-
-       return 0;
-}
-
-
-int swap_init_stat_get(void)
-{
-       mutex_lock(&inst_mutex);
-
-       return init_flag;
-}
-
-void swap_init_stat_put(void)
-{
-       mutex_unlock(&inst_mutex);
-}
-
-int swap_init_register(struct swap_init_struct *init)
-{
-       int ret = 0;
-
-       mutex_lock(&inst_mutex);
-       if (init_flag)
-               ret = sis_init(init);
-
-       if (ret == 0)
-               list_add_tail(&init->list, &init_list);
-       mutex_unlock(&inst_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_init_register);
-
-void swap_init_unregister(struct swap_init_struct *init)
-{
-       mutex_lock(&inst_mutex);
-       list_del(&init->list);
-       sis_uninit(init);
-       mutex_unlock(&inst_mutex);
-}
-EXPORT_SYMBOL_GPL(swap_init_unregister);
diff --git a/master/swap_initializer.h b/master/swap_initializer.h
deleted file mode 100644 (file)
index e0e6314..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, 2015
- *
- * @section DESCRIPTION
- *
- * SWAP event notification interface.
- */
-
-#ifndef _SWAP_INITIALIZER_H
-#define _SWAP_INITIALIZER_H
-
-
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/module.h>
-
-
-struct file;
-struct inode;
-
-
-typedef int (*swap_init_t)(void);
-typedef void (*swap_uninit_t)(void);
-
-
-struct swap_init_struct {
-       swap_init_t once;       /* to call only on the first initialization */
-
-       swap_init_t core_init;
-       swap_uninit_t core_uninit;
-
-       swap_init_t fs_init;
-       swap_uninit_t fs_uninit;
-
-       /* private fields */
-       struct list_head list;
-       unsigned once_flag:1;
-       unsigned core_flag:1;
-       unsigned fs_flag:1;
-};
-
-
-int swap_init_simple_open(struct inode *inode, struct file *file);
-int swap_init_simple_release(struct inode *inode, struct file *file);
-
-int swap_init_init(void);
-int swap_init_uninit(void);
-
-int swap_init_stat_get(void);
-void swap_init_stat_put(void);
-
-int swap_init_register(struct swap_init_struct *init);
-void swap_init_unregister(struct swap_init_struct *init);
-
-
-#define SWAP_LIGHT_INIT_MODULE(_once, _init, _uninit, _fs_init, _fs_uninit) \
-       static struct swap_init_struct __init_struct = {                \
-               .once = _once,                                          \
-               .core_init = _init,                                     \
-               .core_uninit = _uninit,                                 \
-               .fs_init = _fs_init,                                    \
-               .fs_uninit = _fs_uninit,                                \
-               .list = LIST_HEAD_INIT(__init_struct.list),             \
-               .once_flag = false,                                     \
-               .core_flag = false,                                     \
-               .fs_flag = false                                        \
-       };                                                              \
-       static int __init __init_mod(void)                              \
-       {                                                               \
-               return swap_init_register(&__init_struct);              \
-       }                                                               \
-       static void __exit __exit_mod(void)                             \
-       {                                                               \
-               swap_init_unregister(&__init_struct);                   \
-       }                                                               \
-       module_init(__init_mod);                                        \
-       module_exit(__exit_mod)
-
-
-#endif /* _SWAP_INITIALIZER_H */
diff --git a/master/wait.c b/master/wait.c
deleted file mode 100644 (file)
index c0ee359..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This code copied from linux kernel 3.11+
- * commit cb65537ee1134d3cc55c1fa83952bc8eb1212833
- */
-
-
-#include "wait.h"
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
-
-#include <linux/wait.h>
-#include <linux/module.h>
-
-
-#define WAIT_ATOMIC_T_BIT_NR -1
-#define __WAIT_ATOMIC_T_KEY_INITIALIZER(p)                             \
-       { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, }
-
-
-/*
- * Manipulate the atomic_t address to produce a better bit waitqueue table hash
- * index (we're keying off bit -1, but that would produce a horrible hash
- * value).
- */
-static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p)
-{
-       if (BITS_PER_LONG == 64) {
-               unsigned long q = (unsigned long)p;
-               return bit_waitqueue((void *)(q & ~1), q & 1);
-       }
-       return bit_waitqueue(p, 0);
-}
-
-static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync,
-                                 void *arg)
-{
-       struct wait_bit_key *key = arg;
-       struct wait_bit_queue *wait_bit
-               = container_of(wait, struct wait_bit_queue, wait);
-       atomic_t *val = key->flags;
-
-       if (wait_bit->key.flags != key->flags ||
-           wait_bit->key.bit_nr != key->bit_nr ||
-           atomic_read(val) != 0)
-               return 0;
-       return autoremove_wake_function(wait, mode, sync, key);
-}
-
-/*
- * To allow interruptible waiting and asynchronous (i.e. nonblocking) waiting,
- * the actions of __wait_on_atomic_t() are permitted return codes.  Nonzero
- * return codes halt waiting and return.
- */
-static int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
-                             int (*action)(atomic_t *), unsigned mode)
-{
-       atomic_t *val;
-       int ret = 0;
-
-       do {
-               prepare_to_wait(wq, &q->wait, mode);
-               val = q->key.flags;
-               if (atomic_read(val) == 0)
-                       ret = (*action)(val);
-       } while (!ret && atomic_read(val) != 0);
-       finish_wait(wq, &q->wait);
-       return ret;
-}
-
-#define DEFINE_WAIT_ATOMIC_T(name, p)                                  \
-       struct wait_bit_queue name = {                                  \
-               .key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p),              \
-               .wait = {                                               \
-                       .private        = current,                      \
-                       .func           = wake_atomic_t_function,       \
-                       .task_list      =                               \
-                               LIST_HEAD_INIT((name).wait.task_list),  \
-               },                                                      \
-       }
-
-int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *),
-                                        unsigned mode)
-{
-       wait_queue_head_t *wq = atomic_t_waitqueue(p);
-       DEFINE_WAIT_ATOMIC_T(wait, p);
-
-       return __wait_on_atomic_t(wq, &wait, action, mode);
-}
-EXPORT_SYMBOL(out_of_line_wait_on_atomic_t);
-
-/**
- * wake_up_atomic_t - Wake up a waiter on a atomic_t
- * @word: The word being waited on, a kernel virtual address
- * @bit: The bit of the word being waited on
- *
- * Wake up anyone waiting for the atomic_t to go to zero.
- *
- * Abuse the bit-waker function and its waitqueue hash table set (the atomic_t
- * check is done by the waiter's wake function, not the by the waker itself).
- */
-void wake_up_atomic_t(atomic_t *p)
-{
-       __wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR);
-}
-EXPORT_SYMBOL(wake_up_atomic_t);
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */
diff --git a/master/wait.h b/master/wait.h
deleted file mode 100644 (file)
index bb1ca4b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * This code copied from linux kernel 3.11+
- * commit cb65537ee1134d3cc55c1fa83952bc8eb1212833
- */
-
-
-#ifndef _SWAP_WAIT_H
-#define _SWAP_WAIT_H
-
-
-#include <linux/version.h>
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
-
-
-#include <linux/atomic.h>
-
-
-void wake_up_atomic_t(atomic_t *);
-int out_of_line_wait_on_atomic_t(atomic_t *, int (*)(atomic_t *), unsigned);
-
-static inline
-int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode)
-{
-       if (atomic_read(val) == 0)
-               return 0;
-       return out_of_line_wait_on_atomic_t(val, action, mode);
-}
-
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */
-
-#include <linux/wait.h>
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */
-
-#endif /* _SWAP_WAIT_H */
diff --git a/modules/Doxyfile b/modules/Doxyfile
new file mode 100644 (file)
index 0000000..3fa14b4
--- /dev/null
@@ -0,0 +1,2310 @@
+# Doxyfile 1.8.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "SWAP Modules"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/modules/Kbuild b/modules/Kbuild
new file mode 100644 (file)
index 0000000..007e021
--- /dev/null
@@ -0,0 +1,30 @@
+extra_cflags := -I$(M) -I$(M)/kprobe/arch/$(LINKNAME)/ -I$(M)/uprobe/arch/$(LINKNAME)/
+extra_cflags += $(MCFLAGS)
+EXTRA_CFLAGS := $(extra_cflags)
+export extra_cflags
+
+obj-m := master/ \
+         buffer/ \
+         ksyms/ \
+         driver/ \
+         writer/ \
+         kprobe/ \
+         uprobe/ \
+         us_manager/ \
+         ks_features/ \
+         loader/ \
+         sampler/ \
+         energy/ \
+         parser/ \
+         retprobe/ \
+         preload/ \
+         fbiprobe/ \
+         wsp/ \
+         nsp/ \
+         task_ctx/ \
+         uihv/ \
+         got_patcher/
+
+ifneq ($(CONFIG_SWAP_KERNEL_IMMUTABLE), y)
+obj-m += ks_manager/
+endif # CONFIG_SWAP_KERNEL_IMMUTABLE
diff --git a/modules/arch/arm/probes/compat_arm64.h b/modules/arch/arm/probes/compat_arm64.h
new file mode 100644 (file)
index 0000000..e85766e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_COMPAT_ARM64_H
+#define _SWAP_ASM_COMPAT_ARM64_H
+
+
+#ifdef CONFIG_ARM64
+
+# define PSR_T_BIT             COMPAT_PSR_T_BIT
+
+# define ARM_r0                        compat_usr(0)
+# define ARM_r1                        compat_usr(1)
+# define ARM_r2                        compat_usr(2)
+# define ARM_r3                        compat_usr(3)
+# define ARM_r4                        compat_usr(4)
+# define ARM_r5                        compat_usr(5)
+# define ARM_r6                        compat_usr(6)
+# define ARM_r7                        compat_usr(7)
+# define ARM_r8                        compat_usr(8)
+# define ARM_r9                        compat_usr(9)
+# define ARM_r10               compat_usr(10)
+# define ARM_fp                        compat_fp
+# define ARM_ip                        compat_usr(12)
+# define ARM_sp                        compat_sp
+# define ARM_lr                        compat_lr
+# define ARM_pc                        pc
+# define ARM_cpsr              pstate
+
+# define thumb_mode(regs)      compat_thumb_mode(regs)
+
+#endif /* CONFIG_ARM64 */
+
+
+#endif /* _SWAP_ASM_COMPAT_ARM64_H */
+
+
+
+
+
+
diff --git a/modules/arch/arm/probes/decode_arm_old.h b/modules/arch/arm/probes/decode_arm_old.h
new file mode 100644 (file)
index 0000000..ae6b6c8
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_DECODE_ARM_OLD_H
+#define _SWAP_ASM_DECODE_ARM_OLD_H
+
+
+#define ARM_INSN_MATCH(name, insn) \
+       ((insn & MASK_ARM_INSN_##name) == PTRN_ARM_INSN_##name)
+#define ARM_INSN_REG_RN(insn)                  ((insn & 0x000F0000) >> 16)
+#define ARM_INSN_REG_SET_RN(insn, nreg)                { insn &= ~0x000F0000; insn |= nreg << 16; }
+#define ARM_INSN_REG_RD(insn)                  ((insn & 0x0000F000) >> 12)
+#define ARM_INSN_REG_SET_RD(insn, nreg)                { insn &= ~0x0000F000; insn |= nreg << 12; }
+#define ARM_INSN_REG_RS(insn)                  ((insn & 0x00000F00) >> 8)
+#define ARM_INSN_REG_SET_RS(insn, nreg)                { insn &= ~0x00000F00; insn |= nreg << 8; }
+#define ARM_INSN_REG_RM(insn)                  (insn & 0x0000000F)
+#define ARM_INSN_REG_SET_RM(insn, nreg)                { insn &= ~0x0000000F; insn |= nreg; }
+#define ARM_INSN_REG_MR(insn, nreg)            (insn & (1 << nreg))
+#define ARM_INSN_REG_SET_MR(insn, nreg)                { insn |= (1 << nreg); }
+#define ARM_INSN_REG_CLEAR_MR(insn, nreg)      { insn &= ~(1 << nreg); }
+
+
+/* Undefined */
+#define MASK_ARM_INSN_UNDEF            0x0FF00000
+#define PTRN_ARM_INSN_UNDEF            0x03000000
+
+/* Architecturally undefined */
+#define MASK_ARM_INSN_AUNDEF           0x0FF000F0
+#define PTRN_ARM_INSN_AUNDEF           0x07F000F0
+
+/* Branches */
+#define MASK_ARM_INSN_B                        0x0F000000
+#define PTRN_ARM_INSN_B                        0x0A000000
+
+#define MASK_ARM_INSN_BL               0x0F000000
+#define PTRN_ARM_INSN_BL               0x0B000000
+
+#define MASK_ARM_INSN_BLX1             0xFE000000
+#define PTRN_ARM_INSN_BLX1             0xFA000000
+
+#define MASK_ARM_INSN_BLX2             0x0FF000F0
+#define PTRN_ARM_INSN_BLX2             0x01200030
+
+#define MASK_ARM_INSN_BX               0x0FF000F0
+#define PTRN_ARM_INSN_BX               0x01200010
+
+#define MASK_ARM_INSN_BXJ              0x0FF000F0
+#define PTRN_ARM_INSN_BXJ              0x01200020
+
+/* Software interrupts */
+#define MASK_ARM_INSN_SWI              0x0F000000
+#define PTRN_ARM_INSN_SWI              0x0F000000
+
+/* Break */
+#define MASK_ARM_INSN_BREAK            0xFFF000F0
+#define PTRN_ARM_INSN_BREAK            0xE1200070
+/* A8-56 ARM DDI 046B if cond != â€˜1110’ then UNPREDICTABLE; */
+
+/* CLZ */
+#define MASK_ARM_INSN_CLZ              0x0FFF0FF0
+#define PTRN_ARM_INSN_CLZ              0x016F0F10
+
+/* Data processing immediate shift */
+#define MASK_ARM_INSN_DPIS             0x0E000010
+#define PTRN_ARM_INSN_DPIS             0x00000000
+
+/* Data processing register shift */
+#define MASK_ARM_INSN_DPRS             0x0E000090
+#define PTRN_ARM_INSN_DPRS             0x00000010
+
+/* Data processing immediate */
+#define MASK_ARM_INSN_DPI              0x0E000000
+#define PTRN_ARM_INSN_DPI              0x02000000
+
+/* Load immediate offset */
+#define MASK_ARM_INSN_LIO              0x0E100000
+#define PTRN_ARM_INSN_LIO              0x04100000
+
+/* Store immediate offset */
+#define MASK_ARM_INSN_SIO              MASK_ARM_INSN_LIO
+#define PTRN_ARM_INSN_SIO              0x04000000
+
+/* Load register offset */
+#define MASK_ARM_INSN_LRO              0x0E100010
+#define PTRN_ARM_INSN_LRO              0x06100000
+
+/* Store register offset */
+#define MASK_ARM_INSN_SRO              MASK_ARM_INSN_LRO
+#define PTRN_ARM_INSN_SRO              0x06000000
+
+/* Load multiple */
+#define MASK_ARM_INSN_LM               0x0E100000
+#define PTRN_ARM_INSN_LM               0x08100000
+
+/* Store multiple */
+#define MASK_ARM_INSN_SM               MASK_ARM_INSN_LM
+#define PTRN_ARM_INSN_SM               0x08000000
+
+
+/* Coprocessor load/store and double register transfers */
+#define MASK_ARM_INSN_CLS              0x0E000000
+#define PTRN_ARM_INSN_CLS              0x0C000000
+
+/*  Coprocessor register transfers */
+#define MASK_ARM_INSN_CRT              0x0F000010
+#define PTRN_ARM_INSN_CRT              0x0E000010
+
+
+#endif /* _SWAP_ASM_DECODE_ARM_OLD_H */
diff --git a/modules/arch/arm/probes/decode_thumb.c b/modules/arch/arm/probes/decode_thumb.c
new file mode 100644 (file)
index 0000000..a35f262
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include "decode_thumb.h"
+#include "tramps_thumb.h"
+#include "compat_arm64.h"
+
+
+#define GET_BIT(x, n)          ((x >> n) & 0x1)
+#define GET_FIELD(x, s, l)      ((x >> s) & ((1 << l) - 1))
+#define SET_FIELD(x, s, l, v)  ({              \
+       typeof(x) mask = (((1 << l) - 1) << s); \
+       (x & ~mask) | ((v << s) & mask);        \
+})
+
+
+typedef union thumb_insn {
+       u32 val;
+       struct {
+               u16 hw1;
+               u16 hw2;
+       } __packed;
+} thumb_insn_t;
+
+typedef int (*decode_handler_t)(thumb_insn_t insn, struct decode_info *info);
+
+
+static void make_def(void *tramp, u32 insn, u32 vaddr, bool t2)
+{
+       u32 ret_addr;
+       u16 *tr = tramp;
+
+       /*
+        * thumb  - +2
+        * thumb2 - +4
+        */
+       ret_addr = vaddr + (2 << t2);
+       tr[4] = insn & 0x0000ffff;
+       if (t2)
+               tr[5] = insn >> 16;
+
+       tr[13] = RET_BREAK_THUMB;
+       tr[16] = (ret_addr & 0x0000ffff) | 0x1;
+       tr[17] = ret_addr >> 16;
+}
+
+static void tt_make_common(void *tramp, u32 insn, u32 vaddr, bool t2)
+{
+       memcpy(tramp, gen_insn_execbuf_thumb, sizeof(gen_insn_execbuf_thumb));
+       make_def(tramp, insn, vaddr, t2);
+}
+
+static void tt_make_pc_deps(void *tramp, u32 mod_insn, u32 vaddr, bool t2)
+{
+       u32 pc_val = vaddr + 4;
+       u16 *tr = tramp;
+
+       memcpy(tramp, pc_dep_insn_execbuf_thumb,
+              sizeof(pc_dep_insn_execbuf_thumb));
+       make_def(tramp, mod_insn, vaddr, t2);
+
+       /* save PC value */
+       tr[14] = pc_val & 0x0000ffff;
+       tr[15] = pc_val >> 16;
+}
+
+
+static bool bad_reg(int n)
+{
+       return n == 13 || n == 15;
+}
+
+static int thumb_not_implement(thumb_insn_t insn, struct decode_info *info)
+{
+       return -EFAULT;
+}
+
+static int thumb_unpredictable(thumb_insn_t insn, struct decode_info *info)
+{
+       return -EINVAL;
+}
+
+/* hw1[1110 100x x1xx ????] */
+static int t32_ldrd_strd(thumb_insn_t insn, struct decode_info *info)
+{
+       int w = GET_BIT(insn.hw1, 5);
+       int n = GET_FIELD(insn.hw1, 0, 4);
+       int t = GET_FIELD(insn.hw2, 12, 4);
+       int t2 = GET_FIELD(insn.hw2, 8, 4);
+
+       if (bad_reg(t) || bad_reg(t2))
+               return thumb_unpredictable(insn, info);
+
+       /* check load flag */
+       if (GET_BIT(insn.hw1, 4)) {
+               /* LDRD */
+               if ((w && (n == 15)) || t == t2)
+                       return thumb_unpredictable(insn, info);
+
+               if (n == 15) {
+                       /* change PC -> SP */
+                       insn.hw1 = SET_FIELD(insn.hw1, 0, 4, 13);
+                       tt_make_pc_deps(info->tramp, insn.val,
+                                       info->vaddr, true);
+
+                       return 0;
+               }
+       } else {
+               /* STRD */
+               if ((w && t == n) || (w && t2 == n) || (n == 15))
+                       return thumb_unpredictable(insn, info);
+       }
+
+       tt_make_common(info->tramp, insn.val, info->vaddr, true);
+
+       return 0;
+}
+
+static int t32_b1110_100x_x1(thumb_insn_t insn, struct decode_info *info)
+{
+       /* check PW bits */
+       if (insn.hw1 & 0x120)
+               return t32_ldrd_strd(insn, info);
+
+       return thumb_not_implement(insn, info);
+}
+
+static int t32_b1110_100(thumb_insn_t insn, struct decode_info *info)
+{
+       if (GET_BIT(insn.hw1, 6))
+               return t32_b1110_100x_x1(insn, info);
+
+       return thumb_not_implement(insn, info);
+}
+
+static void t32_simulate_branch(u32 insn, struct arch_insn_arm *ainsn,
+                               struct pt_regs *regs)
+{
+       u32 pc = regs->ARM_pc;
+       thumb_insn_t i = { .val = insn };
+
+       s32 offset = GET_FIELD(i.hw2, 0, 11);           /* imm11 */
+       offset += GET_FIELD(i.hw1, 0, 10) << 11;        /* imm10 */
+       offset += GET_BIT(i.hw2, 13) << 21;             /* J1 */
+       offset += GET_BIT(i.hw2, 11) << 22;             /* J2 */
+
+       /* check S bit */
+       if (GET_BIT(i.hw1, 10))
+               offset -= 0x00800000;   /* Apply sign bit */
+       else
+               offset ^= 0x00600000;   /* Invert J1 and J2 */
+
+       /* check link */
+       if (GET_BIT(i.hw2, 14)) {
+               /* BL or BLX */
+               regs->ARM_lr = regs->ARM_pc | 1;
+               if (!GET_BIT(i.hw2, 12)) {
+                       /* BLX so switch to ARM mode */
+                       regs->ARM_cpsr &= ~PSR_T_BIT;
+                       pc &= ~3;
+               }
+       }
+
+       regs->ARM_pc = pc + (offset * 2);
+}
+
+static int t32_branch(thumb_insn_t insn, struct decode_info *info)
+{
+       info->handeler = t32_simulate_branch;
+
+       return 0;
+}
+
+static decode_handler_t table_branches[8] = {
+       /* hw2[14 12 0] */
+       /* Bc   0  0 0  */      thumb_not_implement,
+       /* Bc   0  0 1  */      thumb_not_implement,
+       /* B    0  1 0  */      t32_branch,
+       /* B    0  1 1  */      t32_branch,
+       /* BLX  1  0 0  */      t32_branch,
+       /* res  1  0 1  */      thumb_unpredictable,
+       /* BL   1  1 0  */      t32_branch,
+       /* BL   1  1 1  */      t32_branch,
+};
+
+
+
+static int t32_b1111_0xxx_xxxx_xxxx_1(thumb_insn_t insn,
+                                     struct decode_info *info)
+{
+       u32 s = GET_BIT(insn.hw2, 14) << 2 |
+               GET_BIT(insn.hw2, 12) << 1 |
+               GET_BIT(insn.hw2, 0);
+
+       return table_branches[s](insn, info);
+}
+
+static int b111(thumb_insn_t insn, struct decode_info *info)
+{
+       /* hw1[111x xxx? ???? ????] */
+       switch (GET_FIELD(insn.hw1, 9, 4)) {
+       case 0b0100:
+               return t32_b1110_100(insn, info);
+       }
+
+       /* [1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx] */
+       if (GET_FIELD(insn.hw1, 11, 2) == 0b10 && GET_BIT(insn.hw2, 15) == 1)
+               return t32_b1111_0xxx_xxxx_xxxx_1(insn, info);
+
+       return thumb_not_implement(insn, info);
+}
+
+
+decode_handler_t table_xxx[8] = {
+       /* 000 */       thumb_not_implement,
+       /* 001 */       thumb_not_implement,
+       /* 010 */       thumb_not_implement,
+       /* 011 */       thumb_not_implement,
+       /* 100 */       thumb_not_implement,
+       /* 101 */       thumb_not_implement,
+       /* 110 */       thumb_not_implement,
+       /* 111 */       b111,
+};
+
+
+int decode_thumb(u32 insn, struct decode_info *info)
+{
+       thumb_insn_t tinsn = { .val = insn };
+
+       /* check first 3 bits hw1[xxx? ???? ???? ????] */
+       return table_xxx[GET_FIELD(tinsn.hw1, 13, 3)](tinsn, info);
+}
diff --git a/modules/arch/arm/probes/decode_thumb.h b/modules/arch/arm/probes/decode_thumb.h
new file mode 100644 (file)
index 0000000..63d47db
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _ARM_DECODE_THUMB_H
+#define _ARM_DECODE_THUMB_H
+
+
+#include "probes.h"
+
+
+struct decode_info {
+       u32 vaddr;
+       void *tramp;
+       probe_handler_arm_t handeler;
+};
+
+
+int decode_thumb(u32 insn, struct decode_info *info);
+
+
+#endif /* _ARM_DECODE_THUMB_H */
diff --git a/modules/arch/arm/probes/decode_thumb_old.h b/modules/arch/arm/probes/decode_thumb_old.h
new file mode 100644 (file)
index 0000000..df1faba
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_DECODE_THUMB_OLD_H
+#define _SWAP_ASM_DECODE_THUMB_OLD_H
+
+
+/* == THUMB == */
+#define THUMB_INSN_MATCH(name, insn) \
+       (((insn & 0x0000FFFF) & MASK_THUMB_INSN_##name) == \
+        PTRN_THUMB_INSN_##name)
+
+
+/* Undefined */
+#define MASK_THUMB_INSN_UNDEF  0xFE00
+#define PTRN_THUMB_INSN_UNDEF  0xDE00
+
+/* Branches */
+#define MASK_THUMB_INSN_B1     0xF000
+#define PTRN_THUMB_INSN_B1     0xD000          /* b<cond> label */
+
+#define MASK_THUMB_INSN_B2     0xF800
+#define PTRN_THUMB_INSN_B2     0xE000          /* b label */
+
+#define MASK_THUMB_INSN_CBZ    0xF500
+#define PTRN_THUMB_INSN_CBZ    0xB100          /* CBZ/CBNZ */
+
+#define MASK_THUMB_INSN_BLX2   0xFF80          /* blx reg */
+#define PTRN_THUMB_INSN_BLX2   0x4780
+
+#define MASK_THUMB_INSN_BX     0xFF80
+#define PTRN_THUMB_INSN_BX     0x4700
+
+/* Software interrupts */
+#define MASK_THUMB_INSN_SWI    0xFF00
+#define PTRN_THUMB_INSN_SWI    0xDF00
+
+/* Break */
+#define MASK_THUMB_INSN_BREAK  0xFF00
+#define PTRN_THUMB_INSN_BREAK  0xBE00
+
+/* Data processing immediate */
+#define MASK_THUMB_INSN_DP     0xFC00
+#define PTRN_THUMB_INSN_DP     0x4000
+
+#define MASK_THUMB_INSN_APC    0xF800
+#define PTRN_THUMB_INSN_APC    0xA000          /* ADD Rd, [PC, #<imm8> * 4] */
+
+#define MASK_THUMB_INSN_MOV3   0xFF00
+#define PTRN_THUMB_INSN_MOV3   0x4600          /* MOV Rd, PC */
+
+/* Load immediate offset */
+#define MASK_THUMB_INSN_LIO1   0xF800
+#define PTRN_THUMB_INSN_LIO1   0x6800          /* LDR */
+
+#define MASK_THUMB_INSN_LIO2   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_LIO2   0x7800          /* LDRB */
+
+#define MASK_THUMB_INSN_LIO3   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_LIO3   0x8800          /* LDRH */
+
+#define MASK_THUMB_INSN_LIO4   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_LIO4   0x9800          /* LDR SP relative */
+
+/* Store immediate offset */
+#define MASK_THUMB_INSN_SIO1   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_SIO1   0x6000          /* STR */
+
+#define MASK_THUMB_INSN_SIO2   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_SIO2   0x7000          /* STRB */
+
+#define MASK_THUMB_INSN_SIO3   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_SIO3   0x8000          /* STRH */
+
+#define MASK_THUMB_INSN_SIO4   MASK_THUMB_INSN_LIO1
+#define PTRN_THUMB_INSN_SIO4   0x9000          /* STR SP relative */
+
+/* Load register offset */
+#define MASK_THUMB_INSN_LRO1   0xFE00
+#define PTRN_THUMB_INSN_LRO1   0x5600          /* LDRSB */
+
+#define MASK_THUMB_INSN_LRO2   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_LRO2   0x5800          /* LDR */
+
+#define MASK_THUMB_INSN_LRO3   0xf800
+#define PTRN_THUMB_INSN_LRO3   0x4800          /* LDR Rd, [PC, #<imm8> * 4] */
+
+#define MASK_THUMB_INSN_LRO4   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_LRO4   0x5A00          /* LDRH */
+
+#define MASK_THUMB_INSN_LRO5   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_LRO5   0x5C00          /* LDRB */
+
+#define MASK_THUMB_INSN_LRO6   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_LRO6   0x5E00          /* LDRSH */
+
+/* Store register offset */
+#define MASK_THUMB_INSN_SRO1   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_SRO1   0x5000          /* STR */
+
+#define MASK_THUMB_INSN_SRO2   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_SRO2   0x5200          /* STRH */
+
+#define MASK_THUMB_INSN_SRO3   MASK_THUMB_INSN_LRO1
+#define PTRN_THUMB_INSN_SRO3   0x5400          /* STRB */
+
+
+/* == THUMB2 == */
+#define THUMB2_INSN_MATCH(name, insn) \
+       ((insn & MASK_THUMB2_INSN_##name) == PTRN_THUMB2_INSN_##name)
+
+#define THUMB2_INSN_REG_RT(insn)       ((insn & 0xf0000000) >> 28)
+#define THUMB2_INSN_REG_RT2(insn)      ((insn & 0x0f000000) >> 24)
+#define THUMB2_INSN_REG_RN(insn)       (insn & 0x0000000f)
+#define THUMB2_INSN_REG_RD(insn)       ((insn & 0x0f000000) >> 24)
+#define THUMB2_INSN_REG_RM(insn)       ((insn & 0x000f0000) >> 16)
+
+
+/* Branches */
+#define MASK_THUMB2_INSN_B1    0xD000F800
+#define PTRN_THUMB2_INSN_B1    0x8000F000
+
+#define MASK_THUMB2_INSN_B2    0xD000F800
+#define PTRN_THUMB2_INSN_B2    0x9000F000
+
+#define MASK_THUMB2_INSN_BL    0xD000F800
+#define PTRN_THUMB2_INSN_BL    0xD000F000      /* bl imm  swapped */
+
+#define MASK_THUMB2_INSN_BLX1  0xD001F800
+#define PTRN_THUMB2_INSN_BLX1  0xC000F000
+
+#define MASK_THUMB2_INSN_BXJ   0xD000FFF0
+#define PTRN_THUMB2_INSN_BXJ   0x8000F3C0
+
+/* Data processing register shift */
+#define MASK_THUMB2_INSN_DPRS  0xFFE00000
+#define PTRN_THUMB2_INSN_DPRS  0xEA000000
+
+/* Data processing immediate */
+#define MASK_THUMB2_INSN_DPI   0xFBE08000
+#define PTRN_THUMB2_INSN_DPI   0xF2000000
+
+#define MASK_THUMB2_INSN_RSBW  0x8000fbe0
+#define PTRN_THUMB2_INSN_RSBW  0x0000f1c0      /* RSB{S}.W Rd,Rn,#<const> */
+
+#define MASK_THUMB2_INSN_RORW  0xf0f0ffe0
+#define PTRN_THUMB2_INSN_RORW  0xf000fa60      /* ROR{S}.W Rd, Rn, Rm */
+
+#define MASK_THUMB2_INSN_ROR   0x0030ffef
+#define PTRN_THUMB2_INSN_ROR   0x0030ea4f      /* ROR{S} Rd, Rm, #<imm> */
+
+#define MASK_THUMB2_INSN_LSLW1 0xf0f0ffe0
+#define PTRN_THUMB2_INSN_LSLW1 0xf000fa00      /* LSL{S}.W Rd, Rn, Rm */
+
+#define MASK_THUMB2_INSN_LSLW2 0x0030ffef
+#define PTRN_THUMB2_INSN_LSLW2 0x0000ea4f      /* LSL{S}.W Rd, Rm, #<imm5>*/
+
+#define MASK_THUMB2_INSN_LSRW1 0xf0f0ffe0
+#define PTRN_THUMB2_INSN_LSRW1 0xf000fa20      /* LSR{S}.W Rd, Rn, Rm */
+
+#define MASK_THUMB2_INSN_LSRW2 0x0030ffef
+#define PTRN_THUMB2_INSN_LSRW2 0x0010ea4f      /* LSR{S}.W Rd, Rm, #<imm5> */
+
+#define MASK_THUMB2_INSN_TEQ1  0x8f00fbf0
+#define PTRN_THUMB2_INSN_TEQ1  0x0f00f090      /* TEQ Rn, #<const> */
+
+#define MASK_THUMB2_INSN_TEQ2  0x0f00fff0
+#define PTRN_THUMB2_INSN_TEQ2  0x0f00ea90      /* TEQ Rn, Rm{,<shift>} */
+
+#define MASK_THUMB2_INSN_TST1  0x8f00fbf0
+#define PTRN_THUMB2_INSN_TST1  0x0f00f010      /* TST Rn, #<const> */
+
+#define MASK_THUMB2_INSN_TST2  0x0f00fff0
+#define PTRN_THUMB2_INSN_TST2  0x0f00ea10      /* TST Rn, Rm{,<shift>} */
+
+/* Load immediate offset */
+#define MASK_THUMB2_INSN_LDRW  0x0000fff0
+#define PTRN_THUMB2_INSN_LDRW  0x0000f850      /* LDR.W Rt, [Rn, #-<imm12>] */
+
+#define MASK_THUMB2_INSN_LDRW1 MASK_THUMB2_INSN_LDRW
+#define PTRN_THUMB2_INSN_LDRW1 0x0000f8d0      /* LDR.W Rt, [Rn, #<imm12>] */
+
+#define MASK_THUMB2_INSN_LDRBW MASK_THUMB2_INSN_LDRW
+#define PTRN_THUMB2_INSN_LDRBW 0x0000f810      /* LDRB.W Rt, [Rn, #-<imm8>] */
+
+#define MASK_THUMB2_INSN_LDRBW1        MASK_THUMB2_INSN_LDRW
+#define PTRN_THUMB2_INSN_LDRBW1        0x0000f890      /* LDRB.W Rt, [Rn, #<imm12>] */
+
+#define MASK_THUMB2_INSN_LDRHW MASK_THUMB2_INSN_LDRW
+#define PTRN_THUMB2_INSN_LDRHW 0x0000f830      /* LDRH.W Rt, [Rn, #-<imm8>] */
+
+#define MASK_THUMB2_INSN_LDRHW1        MASK_THUMB2_INSN_LDRW
+#define PTRN_THUMB2_INSN_LDRHW1        0x0000f8b0      /* LDRH.W Rt, [Rn, #<imm12>] */
+
+#define MASK_THUMB2_INSN_LDRD  0x0000fed0
+#define PTRN_THUMB2_INSN_LDRD  0x0000e850      /* LDRD Rt, Rt2, [Rn, #-<imm8>] */
+
+#define MASK_THUMB2_INSN_LDRD1 MASK_THUMB2_INSN_LDRD
+#define PTRN_THUMB2_INSN_LDRD1 0x0000e8d0      /* LDRD Rt, Rt2, [Rn, #<imm8>] */
+
+#define MASK_THUMB2_INSN_LDRWL 0x0fc0fff0
+#define PTRN_THUMB2_INSN_LDRWL 0x0000f850      /* LDR.W Rt, [Rn,Rm,LSL #<imm2>] */
+
+#define MASK_THUMB2_INSN_LDREX 0x0f00ffff
+#define PTRN_THUMB2_INSN_LDREX 0x0f00e85f      /* LDREX Rt, [PC, #<imm8>] */
+
+#define MASK_THUMB2_INSN_MUL   0xf0f0fff0
+#define PTRN_THUMB2_INSN_MUL   0xf000fb00      /* MUL Rd, Rn, Rm */
+
+#define MASK_THUMB2_INSN_DP    0x0000ff00
+#define PTRN_THUMB2_INSN_DP    0x0000eb00      /* ADD/SUB/SBC/...Rd,Rn,Rm{,<shift>} */
+
+/* Store immediate offset */
+#define MASK_THUMB2_INSN_STRW  0x0fc0fff0
+#define PTRN_THUMB2_INSN_STRW  0x0000f840      /* STR.W Rt,[Rn,Rm,{LSL #<imm2>}] */
+
+#define MASK_THUMB2_INSN_STRW1 0x0000fff0
+#define PTRN_THUMB2_INSN_STRW1 0x0000f8c0      /* STR.W Rt, [Rn, #imm12]
+                                                * STR.W Rt, [PC, #imm12] shall be
+                                                * skipped, because it hangs
+                                                * on Tegra. WTF */
+
+#define MASK_THUMB2_INSN_STRHW MASK_THUMB2_INSN_STRW
+#define PTRN_THUMB2_INSN_STRHW 0x0000f820      /* STRH.W Rt,[Rn,Rm,{LSL #<imm2>}] */
+
+#define MASK_THUMB2_INSN_STRHW1        0x0000fff0
+#define PTRN_THUMB2_INSN_STRHW1        0x0000f8a0      /* STRH.W Rt, [Rn, #<imm12>] */
+
+#define MASK_THUMB2_INSN_STRHT 0x0f00fff0      /* strht r1, [pc, #imm] illegal
+                                                * instruction on Tegra. WTF */
+#define PTRN_THUMB2_INSN_STRHT 0x0e00f820      /* STRHT Rt, [Rn, #<imm8>] */
+
+#define MASK_THUMB2_INSN_STRT  0x0f00fff0
+#define PTRN_THUMB2_INSN_STRT  0x0e00f840      /* STRT Rt, [Rn, #<imm8>] */
+
+#define MASK_THUMB2_INSN_STRBW MASK_THUMB2_INSN_STRW
+#define PTRN_THUMB2_INSN_STRBW 0x0000f800      /* STRB.W Rt,[Rn,Rm,{LSL #<imm2>}] */
+
+#define MASK_THUMB2_INSN_STRBW1        0x0000fff0
+#define PTRN_THUMB2_INSN_STRBW1        0x0000f880      /* STRB.W Rt, [Rn, #<imm12>]
+                                                * STRB.W Rt, [PC, #imm12] shall be
+                                                * skipped, because it hangs
+                                                * on Tegra. WTF */
+
+#define MASK_THUMB2_INSN_STRBT 0x0f00fff0
+#define PTRN_THUMB2_INSN_STRBT 0x0e00f800      /* STRBT Rt, [Rn, #<imm8>}] */
+
+#define MASK_THUMB2_INSN_STRD  0x0000fe50
+#define PTRN_THUMB2_INSN_STRD  0x0000e840      /* STR{D,EX,EXB,EXH,EXD} Rt, Rt2, [Rn, #<imm8>] */
+
+/* Load register offset */
+#define MASK_THUMB2_INSN_ADR   0x8000fa1f
+#define PTRN_THUMB2_INSN_ADR   0x0000f20f
+
+/* Load multiple */
+#define MASK_THUMB2_INSN_LDMIA 0x8000ffd0
+#define PTRN_THUMB2_INSN_LDMIA 0x8000e890      /* LDMIA(.W) Rn(!),{Rx-PC} */
+
+#define MASK_THUMB2_INSN_LDMDB 0x8000ffd0
+#define PTRN_THUMB2_INSN_LDMDB 0x8000e910      /* LDMDB(.W) Rn(!), {Rx-PC} */
+
+
+#endif /* _SWAP_ASM_DECODE_THUMB_OLD_H */
diff --git a/modules/arch/arm/probes/probes.c b/modules/arch/arm/probes/probes.c
new file mode 100644 (file)
index 0000000..0f2818b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include "probes.h"
+#include "probes_arm.h"
+#include "probes_thumb.h"
+
+
+int make_tramp(struct arch_insn_arm *ainsn, u32 vaddr, u32 insn,
+              u32 *tramp, u32 tramp_len)
+{
+       int ret;
+       int thumb_mode = vaddr & 1;
+
+       vaddr &= ~1;
+       if (thumb_mode)
+               ret = make_trampoline_thumb(ainsn, vaddr, insn,
+                                           tramp, tramp_len);
+       else
+               ret = make_trampoline_arm(vaddr, insn, tramp);
+
+       return ret;
+}
diff --git a/modules/arch/arm/probes/probes.h b/modules/arch/arm/probes/probes.h
new file mode 100644 (file)
index 0000000..4dcda9d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_PROBES_H
+#define _SWAP_ASM_PROBES_H
+
+
+#include <linux/types.h>
+#include <swap-asm/swap_probes.h>
+
+
+struct pt_regs;
+struct arch_insn_arm;
+
+
+typedef void (*probe_handler_arm_t)(u32 insn, struct arch_insn_arm *ainsn,
+                                   struct pt_regs *regs);
+
+
+struct arch_insn_arm {
+       probe_handler_arm_t handler;
+};
+
+
+int make_tramp(struct arch_insn_arm *ainsn, u32 vaddr, u32 insn,
+              u32 *tramp, u32 tramp_len);
+
+
+#endif /* _SWAP_ASM_PROBES_H */
+
diff --git a/modules/arch/arm/probes/probes_arm.c b/modules/arch/arm/probes/probes_arm.c
new file mode 100644 (file)
index 0000000..114eeb4
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>      /* nedded for printk.h */
+#include <linux/linkage.h>     /* needed for printk.h */
+#include <linux/printk.h>
+#include "probes.h"
+#include "tramps_arm.h"
+#include "decode_arm_old.h"
+
+
+#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
+#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
+
+
+static u32 get_addr_b(u32 insn, u32 addr)
+{
+       /* real position less then PC by 8 */
+       return ((s32)addr + 8 + branch_displacement(insn));
+}
+
+static int prep_pc_dep_insn_execbuf(u32 *insns, u32 insn, int uregs)
+{
+       int i;
+
+       if (uregs & 0x10) {
+               int reg_mask = 0x1;
+               /* search in reg list */
+               for (i = 0; i < 13; i++, reg_mask <<= 1) {
+                       if (!(insn & reg_mask))
+                               break;
+               }
+       } else {
+               for (i = 0; i < 13; i++) {
+                       if ((uregs & 0x1) && (ARM_INSN_REG_RN(insn) == i))
+                               continue;
+                       if ((uregs & 0x2) && (ARM_INSN_REG_RD(insn) == i))
+                               continue;
+                       if ((uregs & 0x4) && (ARM_INSN_REG_RS(insn) == i))
+                               continue;
+                       if ((uregs & 0x8) && (ARM_INSN_REG_RM(insn) == i))
+                               continue;
+                       break;
+               }
+       }
+
+       if (i == 13) {
+               pr_err("there are no free register %x in insn %x!",
+                      uregs, insn);
+               return -EINVAL;
+       }
+
+       /* set register to save */
+       ARM_INSN_REG_SET_RD(insns[0], i);
+       /* set register to load address to */
+       ARM_INSN_REG_SET_RD(insns[1], i);
+       /* set instruction to execute and patch it */
+       if (uregs & 0x10) {
+               ARM_INSN_REG_CLEAR_MR(insn, 15);
+               ARM_INSN_REG_SET_MR(insn, i);
+       } else {
+               if ((uregs & 0x1) && (ARM_INSN_REG_RN(insn) == 15))
+                       ARM_INSN_REG_SET_RN(insn, i);
+               if ((uregs & 0x2) && (ARM_INSN_REG_RD(insn) == 15))
+                       ARM_INSN_REG_SET_RD(insn, i);
+               if ((uregs & 0x4) && (ARM_INSN_REG_RS(insn) == 15))
+                       ARM_INSN_REG_SET_RS(insn, i);
+               if ((uregs & 0x8) && (ARM_INSN_REG_RM(insn) == 15))
+                       ARM_INSN_REG_SET_RM(insn, i);
+       }
+
+       insns[PROBES_TRAMP_INSN_IDX] = insn;
+       /* set register to restore */
+       ARM_INSN_REG_SET_RD(insns[3], i);
+
+       return 0;
+}
+
+static int arch_check_insn_arm(u32 insn)
+{
+       /* check instructions that can change PC by nature */
+       if (
+        /* ARM_INSN_MATCH(UNDEF, insn) || */
+           ARM_INSN_MATCH(AUNDEF, insn) ||
+           ARM_INSN_MATCH(SWI, insn) ||
+           ARM_INSN_MATCH(BREAK, insn) ||
+           ARM_INSN_MATCH(BXJ, insn)) {
+               goto bad_insn;
+#ifndef CONFIG_CPU_V7
+       /* check instructions that can write result to PC */
+       } else if ((ARM_INSN_MATCH(DPIS, insn) ||
+                   ARM_INSN_MATCH(DPRS, insn) ||
+                   ARM_INSN_MATCH(DPI, insn) ||
+                   ARM_INSN_MATCH(LIO, insn) ||
+                   ARM_INSN_MATCH(LRO, insn)) &&
+                  (ARM_INSN_REG_RD(insn) == 15)) {
+               goto bad_insn;
+#endif /* CONFIG_CPU_V7 */
+       /* check special instruction loads store multiple registers */
+       } else if ((ARM_INSN_MATCH(LM, insn) || ARM_INSN_MATCH(SM, insn)) &&
+                       /* store PC or load to PC */
+                  (ARM_INSN_REG_MR(insn, 15) ||
+                        /* store/load with PC update */
+                   ((ARM_INSN_REG_RN(insn) == 15) && (insn & 0x200000)))) {
+               goto bad_insn;
+       }
+
+       return 0;
+
+bad_insn:
+       return -EFAULT;
+}
+
+static int make_branch_tarmpoline(u32 addr, u32 insn, u32 *tramp)
+{
+       int ok = 0;
+
+       /* B */
+       if (ARM_INSN_MATCH(B, insn) &&
+           !ARM_INSN_MATCH(BLX1, insn)) {
+               /* B check can be false positive on BLX1 instruction */
+               memcpy(tramp, b_cond_insn_execbuf, sizeof(b_cond_insn_execbuf));
+               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
+               tramp[0] |= insn & 0xf0000000;
+               tramp[6] = get_addr_b(insn, addr);
+               tramp[7] = addr + 4;
+               ok = 1;
+       /* BX, BLX (Rm) */
+       } else if (ARM_INSN_MATCH(BX, insn) ||
+                  ARM_INSN_MATCH(BLX2, insn)) {
+               memcpy(tramp, b_r_insn_execbuf, sizeof(b_r_insn_execbuf));
+               tramp[0] = insn;
+               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
+               tramp[7] = addr + 4;
+               ok = 1;
+       /* BL, BLX (Off) */
+       } else if (ARM_INSN_MATCH(BLX1, insn)) {
+               memcpy(tramp, blx_off_insn_execbuf, sizeof(blx_off_insn_execbuf));
+               tramp[0] |= 0xe0000000;
+               tramp[1] |= 0xe0000000;
+               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
+               tramp[6] = get_addr_b(insn, addr) +
+                          2 * (insn & 01000000) + 1; /* jump to thumb */
+               tramp[7] = addr + 4;
+               ok = 1;
+       /* BL */
+       } else if (ARM_INSN_MATCH(BL, insn)) {
+               memcpy(tramp, blx_off_insn_execbuf, sizeof(blx_off_insn_execbuf));
+               tramp[0] |= insn & 0xf0000000;
+               tramp[1] |= insn & 0xf0000000;
+               tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
+               tramp[6] = get_addr_b(insn, addr);
+               tramp[7] = addr + 4;
+               ok = 1;
+       }
+
+       return ok;
+}
+
+/**
+ * @brief Creates ARM trampoline.
+ *
+ * @param addr Probe address.
+ * @param insn Instuction at this address.
+ * @param tramp Pointer to memory for trampoline.
+ * @return 0 on success, error code on error.
+ */
+int make_trampoline_arm(u32 addr, u32 insn, u32 *tramp)
+{
+       int ret, uregs, pc_dep;
+
+       if (addr & 0x03) {
+               pr_err("Error in %s at %d: attempt to register probe "
+                      "at an unaligned address\n", __FILE__, __LINE__);
+               return -EINVAL;
+       }
+
+       ret = arch_check_insn_arm(insn);
+       if (ret)
+               return ret;
+
+       if (make_branch_tarmpoline(addr, insn, tramp))
+               return 0;
+
+       uregs = pc_dep = 0;
+       /* Rm */
+       if (ARM_INSN_MATCH(CLZ, insn)) {
+               uregs = 0xa;
+               if (ARM_INSN_REG_RM(insn) == 15)
+                       pc_dep = 1;
+       /* Rn, Rm ,Rd */
+       } else if (ARM_INSN_MATCH(DPIS, insn) || ARM_INSN_MATCH(LRO, insn) ||
+           ARM_INSN_MATCH(SRO, insn)) {
+               uregs = 0xb;
+               if ((ARM_INSN_REG_RN(insn) == 15) ||
+                   (ARM_INSN_REG_RM(insn) == 15) ||
+                   (ARM_INSN_MATCH(SRO, insn) &&
+                    (ARM_INSN_REG_RD(insn) == 15))) {
+                       pc_dep = 1;
+               }
+       /* Rn ,Rd */
+       } else if (ARM_INSN_MATCH(DPI, insn) || ARM_INSN_MATCH(LIO, insn) ||
+                  ARM_INSN_MATCH(SIO, insn)) {
+               uregs = 0x3;
+               if ((ARM_INSN_REG_RN(insn) == 15) ||
+                   (ARM_INSN_MATCH(SIO, insn) &&
+                   (ARM_INSN_REG_RD(insn) == 15))) {
+                       pc_dep = 1;
+               }
+       /* Rn, Rm, Rs */
+       } else if (ARM_INSN_MATCH(DPRS, insn)) {
+               uregs = 0xd;
+               if ((ARM_INSN_REG_RN(insn) == 15) ||
+                   (ARM_INSN_REG_RM(insn) == 15) ||
+                   (ARM_INSN_REG_RS(insn) == 15)) {
+                       pc_dep = 1;
+               }
+       /* register list */
+       } else if (ARM_INSN_MATCH(SM, insn)) {
+               uregs = 0x10;
+               if (ARM_INSN_REG_MR(insn, 15))
+                       pc_dep = 1;
+       }
+
+       /* check instructions that can write result to SP and uses PC */
+       if (pc_dep && (ARM_INSN_REG_RD(insn) == 13)) {
+               pr_err("Error in %s at %d: instruction check failed (arm)\n",
+                      __FILE__, __LINE__);
+               return -EFAULT;
+       }
+
+       if (unlikely(uregs && pc_dep)) {
+               memcpy(tramp, pc_dep_insn_execbuf, sizeof(pc_dep_insn_execbuf));
+               if (prep_pc_dep_insn_execbuf(tramp, insn, uregs) != 0) {
+                       pr_err("Error in %s at %d: failed "
+                              "to prepare exec buffer for insn %x!",
+                              __FILE__, __LINE__, insn);
+                       return -EINVAL;
+               }
+
+               tramp[6] = addr + 8;
+       } else {
+               memcpy(tramp, gen_insn_execbuf, sizeof(gen_insn_execbuf));
+               tramp[PROBES_TRAMP_INSN_IDX] = insn;
+       }
+
+       /* TODO: remove for probe */
+       tramp[PROBES_TRAMP_RET_BREAK_IDX] = RET_BREAK_ARM;
+       tramp[7] = addr + 4;
+
+       return 0;
+}
+
+int noret_arm(u32 opcode)
+{
+       return !!(ARM_INSN_MATCH(BL, opcode) ||
+                 ARM_INSN_MATCH(BLX1, opcode) ||
+                 ARM_INSN_MATCH(BLX2, opcode));
+}
diff --git a/modules/arch/arm/probes/probes_arm.h b/modules/arch/arm/probes/probes_arm.h
new file mode 100644 (file)
index 0000000..c324985
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_PROBES_ARM_H
+#define _SWAP_ASM_PROBES_ARM_H
+
+
+int make_trampoline_arm(u32 addr, u32 insn, u32 *tramp);
+int noret_arm(u32 opcode);
+
+
+#endif /* _SWAP_ASM_PROBES_ARM_H */
diff --git a/modules/arch/arm/probes/probes_thumb.c b/modules/arch/arm/probes/probes_thumb.c
new file mode 100644 (file)
index 0000000..e94e3e2
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include "tramps_thumb.h"
+#include "decode_thumb.h"
+#include "decode_thumb_old.h"
+
+
+static inline s32 branch_t16_dest(u32 insn, unsigned int insn_addr)
+{
+       s32 offset = insn & 0x3ff;
+       offset -= insn & 0x400;
+       return insn_addr + 4 + offset * 2;
+}
+
+static inline s32 branch_cond_t16_dest(u32 insn, unsigned int insn_addr)
+{
+       s32 offset = insn & 0x7f;
+       offset -= insn & 0x80;
+       return insn_addr + 4 + offset * 2;
+}
+
+static inline s32 branch_t32_dest(u32 insn, unsigned int insn_addr)
+{
+       unsigned int poff = insn & 0x3ff;
+       unsigned int offset = (insn & 0x07fe0000) >> 17;
+
+       poff -= (insn & 0x400);
+
+       if (insn & (1 << 12))
+               return insn_addr + 4 + (poff << 12) + offset * 4;
+
+       return (insn_addr + 4 + (poff << 12) + offset * 4) & ~3;
+}
+
+static inline s32 cbz_t16_dest(u32 insn, unsigned int insn_addr)
+{
+       unsigned int i = (insn & 0x200) >> 3;
+       unsigned int offset = (insn & 0xf8) >> 2;
+       return insn_addr + 4 + i + offset;
+}
+
+/* is instruction Thumb2 and NOT a branch, etc... */
+static int is_thumb2(u32 insn)
+{
+       return ((insn & 0xf800) == 0xe800 ||
+               (insn & 0xf800) == 0xf000 ||
+               (insn & 0xf800) == 0xf800);
+}
+
+static int prep_pc_dep_insn_execbuf_thumb(u32 *insns, u32 insn, int uregs)
+{
+       unsigned char mreg = 0;
+       unsigned char reg = 0;
+
+       if (THUMB_INSN_MATCH(APC, insn) ||
+           THUMB_INSN_MATCH(LRO3, insn)) {
+               reg = ((insn & 0xffff) & uregs) >> 8;
+       } else if (THUMB_INSN_MATCH(MOV3, insn)) {
+               if (((((unsigned char)insn) & 0xff) >> 3) == 15)
+                       reg = (insn & 0xffff) & uregs;
+               else
+                       return 0;
+       } else if (THUMB2_INSN_MATCH(ADR, insn)) {
+               reg = ((insn >> 16) & uregs) >> 8;
+               if (reg == 15)
+                       return 0;
+       } else if (THUMB2_INSN_MATCH(LDRW, insn) ||
+                  THUMB2_INSN_MATCH(LDRW1, insn) ||
+                  THUMB2_INSN_MATCH(LDRHW, insn) ||
+                  THUMB2_INSN_MATCH(LDRHW1, insn) ||
+                  THUMB2_INSN_MATCH(LDRWL, insn)) {
+               reg = ((insn >> 16) & uregs) >> 12;
+               if (reg == 15)
+                       return 0;
+       /*
+        * LDRB.W PC, [PC, #immed] => PLD [PC, #immed], so Rt == PC is skipped
+        */
+       } else if (THUMB2_INSN_MATCH(LDRBW, insn) ||
+                  THUMB2_INSN_MATCH(LDRBW1, insn) ||
+                  THUMB2_INSN_MATCH(LDREX, insn)) {
+               reg = ((insn >> 16) & uregs) >> 12;
+       } else if (THUMB2_INSN_MATCH(DP, insn)) {
+               reg = ((insn >> 16) & uregs) >> 12;
+               if (reg == 15)
+                       return 0;
+       } else if (THUMB2_INSN_MATCH(RSBW, insn)) {
+               reg = ((insn >> 12) & uregs) >> 8;
+               if (reg == 15)
+                       return 0;
+       } else if (THUMB2_INSN_MATCH(RORW, insn)) {
+               reg = ((insn >> 12) & uregs) >> 8;
+               if (reg == 15)
+                       return 0;
+       } else if (THUMB2_INSN_MATCH(ROR, insn) ||
+                  THUMB2_INSN_MATCH(LSLW1, insn) ||
+                  THUMB2_INSN_MATCH(LSLW2, insn) ||
+                  THUMB2_INSN_MATCH(LSRW1, insn) ||
+                  THUMB2_INSN_MATCH(LSRW2, insn)) {
+               reg = ((insn >> 12) & uregs) >> 8;
+               if (reg == 15)
+                       return 0;
+       } else if (THUMB2_INSN_MATCH(TEQ1, insn) ||
+                  THUMB2_INSN_MATCH(TST1, insn)) {
+               reg = 15;
+       } else if (THUMB2_INSN_MATCH(TEQ2, insn) ||
+                  THUMB2_INSN_MATCH(TST2, insn)) {
+               reg = THUMB2_INSN_REG_RM(insn);
+       }
+
+       if ((THUMB2_INSN_MATCH(STRW, insn) ||
+            THUMB2_INSN_MATCH(STRBW, insn) ||
+            THUMB2_INSN_MATCH(STRD, insn) ||
+            THUMB2_INSN_MATCH(STRHT, insn) ||
+            THUMB2_INSN_MATCH(STRT, insn) ||
+            THUMB2_INSN_MATCH(STRHW1, insn) ||
+            THUMB2_INSN_MATCH(STRHW, insn)) &&
+           THUMB2_INSN_REG_RT(insn) == 15) {
+               reg = THUMB2_INSN_REG_RT(insn);
+       }
+
+       if (reg == 6 || reg == 7) {
+               *((u16 *)insns + 0) =
+                       (*((u16 *)insns + 0) & 0x00ff) |
+                       ((1 << mreg) | (1 << (mreg + 1)));
+               *((u16 *)insns + 1) =
+                       (*((u16 *)insns + 1) & 0xf8ff) | (mreg << 8);
+               *((u16 *)insns + 2) =
+                       (*((u16 *)insns + 2) & 0xfff8) | (mreg + 1);
+               *((u16 *)insns + 3) =
+                       (*((u16 *)insns + 3) & 0xffc7) | (mreg << 3);
+               *((u16 *)insns + 7) =
+                       (*((u16 *)insns + 7) & 0xf8ff) | (mreg << 8);
+               *((u16 *)insns + 8) =
+                       (*((u16 *)insns + 8) & 0xffc7) | (mreg << 3);
+               *((u16 *)insns + 9) =
+                       (*((u16 *)insns + 9) & 0xffc7) | ((mreg + 1) << 3);
+               *((u16 *)insns + 10) =
+                       (*((u16 *)insns + 10) & 0x00ff) |
+                       ((1 << mreg) | (1 << (mreg + 1)));
+       }
+
+       if (THUMB_INSN_MATCH(APC, insn)) {
+               /* ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4 */
+               *((u16 *)insns + 4) = ((insn & 0xffff) | 0x800);
+       } else if (THUMB_INSN_MATCH(LRO3, insn)) {
+               /* LDR Rd, [PC, #immed_8*4] ->
+                * LDR Rd, [SP, #immed_8*4] */
+               *((u16 *)insns + 4) = ((insn & 0xffff) + 0x5000);
+       } else if (THUMB_INSN_MATCH(MOV3, insn)) {
+               /* MOV Rd, PC -> MOV Rd, SP */
+               *((u16 *)insns + 4) = ((insn & 0xffff) ^ 0x10);
+       } else if (THUMB2_INSN_MATCH(ADR, insn)) {
+               /* ADDW Rd,PC,#imm -> ADDW Rd,SP,#imm */
+               insns[2] = (insn & 0xfffffff0) | 0x0d;
+       } else if (THUMB2_INSN_MATCH(LDRW, insn) ||
+                  THUMB2_INSN_MATCH(LDRBW, insn) ||
+                  THUMB2_INSN_MATCH(LDRHW, insn)) {
+               /* LDR.W Rt, [PC, #-<imm_12>] ->
+                * LDR.W Rt, [SP, #-<imm_8>]
+                * !!!!!!!!!!!!!!!!!!!!!!!!
+                * !!! imm_12 vs. imm_8 !!!
+                * !!!!!!!!!!!!!!!!!!!!!!!! */
+               insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;
+       } else if (THUMB2_INSN_MATCH(LDRW1, insn) ||
+                  THUMB2_INSN_MATCH(LDRBW1, insn) ||
+                  THUMB2_INSN_MATCH(LDRHW1, insn) ||
+                  THUMB2_INSN_MATCH(LDRD, insn) ||
+                  THUMB2_INSN_MATCH(LDRD1, insn) ||
+                  THUMB2_INSN_MATCH(LDREX, insn)) {
+               /* LDRx.W Rt, [PC, #+<imm_12>] ->
+                * LDRx.W Rt, [SP, #+<imm_12>]
+                (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>] */
+               insns[2] = (insn & 0xfffffff0) | 0xd;
+       } else if (THUMB2_INSN_MATCH(MUL, insn)) {
+               /* MUL Rd, Rn, SP */
+               insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
+       } else if (THUMB2_INSN_MATCH(DP, insn)) {
+               if (THUMB2_INSN_REG_RM(insn) == 15)
+                       /* DP Rd, Rn, PC */
+                       insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
+               else if (THUMB2_INSN_REG_RN(insn) == 15)
+                       /* DP Rd, PC, Rm */
+                       insns[2] = (insn & 0xfffffff0) | 0xd;
+       } else if (THUMB2_INSN_MATCH(LDRWL, insn)) {
+               /* LDRx.W Rt, [PC, #<imm_12>] ->
+                * LDRx.W Rt, [SP, #+<imm_12>]
+                * (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>] */
+               insns[2] = (insn & 0xfffffff0) | 0xd;
+       } else if (THUMB2_INSN_MATCH(RSBW, insn)) {
+               /*  RSB{S}.W Rd, PC, #<const> -> RSB{S}.W Rd, SP, #<const> */
+               insns[2] = (insn & 0xfffffff0) | 0xd;
+       } else if (THUMB2_INSN_MATCH(RORW, insn) ||
+                  THUMB2_INSN_MATCH(LSLW1, insn) ||
+                  THUMB2_INSN_MATCH(LSRW1, insn)) {
+               if ((THUMB2_INSN_REG_RM(insn) == 15) &&
+                   (THUMB2_INSN_REG_RN(insn) == 15))
+                       /*  ROR.W Rd, PC, PC */
+                       insns[2] = (insn & 0xfffdfffd);
+               else if (THUMB2_INSN_REG_RM(insn) == 15)
+                       /*  ROR.W Rd, Rn, PC */
+                       insns[2] = (insn & 0xfff0ffff) | 0xd0000;
+               else if (THUMB2_INSN_REG_RN(insn) == 15)
+                       /*  ROR.W Rd, PC, Rm */
+                       insns[2] = (insn & 0xfffffff0) | 0xd;
+       } else if (THUMB2_INSN_MATCH(ROR, insn) ||
+                  THUMB2_INSN_MATCH(LSLW2, insn) ||
+                  THUMB2_INSN_MATCH(LSRW2, insn)) {
+               /*  ROR{S} Rd, PC, #<const> -> ROR{S} Rd, SP, #<const> */
+               insns[2] = (insn & 0xfff0ffff) | 0xd0000;
+       }
+
+       if (THUMB2_INSN_MATCH(STRW, insn) ||
+           THUMB2_INSN_MATCH(STRBW, insn)) {
+               /*  STRx.W Rt, [Rn, SP] */
+               insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
+       } else if (THUMB2_INSN_MATCH(STRD, insn) ||
+                  THUMB2_INSN_MATCH(STRHT, insn) ||
+                  THUMB2_INSN_MATCH(STRT, insn) ||
+                  THUMB2_INSN_MATCH(STRHW1, insn)) {
+               if (THUMB2_INSN_REG_RN(insn) == 15)
+                       /*  STRD/T/HT{.W} Rt, [SP, ...] */
+                       insns[2] = (insn & 0xfffffff0) | 0xd;
+               else
+                       insns[2] = insn;
+       } else if (THUMB2_INSN_MATCH(STRHW, insn) &&
+                  (THUMB2_INSN_REG_RN(insn) == 15)) {
+               if (THUMB2_INSN_REG_RN(insn) == 15)
+                       /*  STRH.W Rt, [SP, #-<imm_8>] */
+                       insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;
+               else
+                       insns[2] = insn;
+       }
+
+       /*  STRx PC, xxx */
+       if ((reg == 15) && (THUMB2_INSN_MATCH(STRW, insn)   ||
+                           THUMB2_INSN_MATCH(STRBW, insn)  ||
+                           THUMB2_INSN_MATCH(STRD, insn)   ||
+                           THUMB2_INSN_MATCH(STRHT, insn)  ||
+                           THUMB2_INSN_MATCH(STRT, insn)   ||
+                           THUMB2_INSN_MATCH(STRHW1, insn) ||
+                           THUMB2_INSN_MATCH(STRHW, insn))) {
+               insns[2] = (insns[2] & 0x0fffffff) | 0xd0000000;
+       }
+
+       if (THUMB2_INSN_MATCH(TEQ1, insn) ||
+           THUMB2_INSN_MATCH(TST1, insn)) {
+               /*  TEQ SP, #<const> */
+               insns[2] = (insn & 0xfffffff0) | 0xd;
+       } else if (THUMB2_INSN_MATCH(TEQ2, insn) ||
+                  THUMB2_INSN_MATCH(TST2, insn)) {
+               if ((THUMB2_INSN_REG_RN(insn) == 15) &&
+                   (THUMB2_INSN_REG_RM(insn) == 15))
+                       /*  TEQ/TST PC, PC */
+                       insns[2] = (insn & 0xfffdfffd);
+               else if (THUMB2_INSN_REG_RM(insn) == 15)
+                       /*  TEQ/TST Rn, PC */
+                       insns[2] = (insn & 0xfff0ffff) | 0xd0000;
+               else if (THUMB2_INSN_REG_RN(insn) == 15)
+                       /*  TEQ/TST PC, Rm */
+                       insns[2] = (insn & 0xfffffff0) | 0xd;
+       }
+
+       return 0;
+}
+
+static int arch_check_insn_thumb(u32 insn)
+{
+       int ret = 0;
+
+       /* check instructions that can change PC */
+       if (THUMB_INSN_MATCH(UNDEF, insn) ||
+           THUMB2_INSN_MATCH(BLX1, insn) ||
+           THUMB2_INSN_MATCH(BL, insn) ||
+           THUMB_INSN_MATCH(SWI, insn) ||
+           THUMB_INSN_MATCH(BREAK, insn) ||
+           THUMB2_INSN_MATCH(B1, insn) ||
+           THUMB2_INSN_MATCH(B2, insn) ||
+           THUMB2_INSN_MATCH(BXJ, insn) ||
+           (THUMB2_INSN_MATCH(ADR, insn) &&
+            THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRW, insn) && THUMB2_INSN_REG_RT(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRW1, insn) &&
+            THUMB2_INSN_REG_RT(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRHW, insn) &&
+            THUMB2_INSN_REG_RT(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRHW1, insn) &&
+            THUMB2_INSN_REG_RT(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRWL, insn) &&
+            THUMB2_INSN_REG_RT(insn) == 15) ||
+           THUMB2_INSN_MATCH(LDMIA, insn) ||
+           THUMB2_INSN_MATCH(LDMDB, insn) ||
+           (THUMB2_INSN_MATCH(DP, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(RSBW, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(RORW, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(ROR, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LSLW1, insn) &&
+            THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LSLW2, insn) &&
+            THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LSRW1, insn) &&
+            THUMB2_INSN_REG_RD(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LSRW2, insn) &&
+            THUMB2_INSN_REG_RD(insn) == 15) ||
+           /* skip PC, #-imm12 -> SP, #-imm8 and Tegra-hanging instructions */
+           (THUMB2_INSN_MATCH(STRW1, insn) &&
+            THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(STRBW1, insn) &&
+            THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(STRHW1, insn) &&
+            THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(STRW, insn) && THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(STRHW, insn) &&
+            THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRW, insn) && THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRBW, insn) &&
+            THUMB2_INSN_REG_RN(insn) == 15) ||
+           (THUMB2_INSN_MATCH(LDRHW, insn) &&
+            THUMB2_INSN_REG_RN(insn) == 15) ||
+           /* skip STRDx/LDRDx Rt, Rt2, [Rd, ...] */
+           (THUMB2_INSN_MATCH(LDRD, insn) || THUMB2_INSN_MATCH(LDRD1, insn) ||
+            THUMB2_INSN_MATCH(STRD, insn))) {
+               ret = -EFAULT;
+       }
+
+       return ret;
+}
+
+static int do_make_trampoline_thumb(u32 vaddr, u32 insn,
+                                   u32 *tramp, size_t tramp_len)
+{
+       int ret;
+       int uregs = 0;
+       int pc_dep = 0;
+       unsigned int addr;
+
+       ret = arch_check_insn_thumb(insn);
+       if (ret)
+               return ret;
+
+       if (THUMB_INSN_MATCH(APC, insn) || THUMB_INSN_MATCH(LRO3, insn)) {
+               uregs = 0x0700;         /* 8-10 */
+               pc_dep = 1;
+       } else if (THUMB_INSN_MATCH(MOV3, insn) &&
+                  (((((unsigned char)insn) & 0xff) >> 3) == 15)) {
+               /* MOV Rd, PC */
+               uregs = 0x07;
+               pc_dep = 1;
+       } else if THUMB2_INSN_MATCH(ADR, insn) {
+               uregs = 0x0f00;         /* Rd 8-11 */
+               pc_dep = 1;
+       } else if (((THUMB2_INSN_MATCH(LDRW, insn) ||
+                    THUMB2_INSN_MATCH(LDRW1, insn) ||
+                    THUMB2_INSN_MATCH(LDRBW, insn) ||
+                    THUMB2_INSN_MATCH(LDRBW1, insn) ||
+                    THUMB2_INSN_MATCH(LDRHW, insn) ||
+                    THUMB2_INSN_MATCH(LDRHW1, insn) ||
+                    THUMB2_INSN_MATCH(LDRWL, insn)) &&
+                   THUMB2_INSN_REG_RN(insn) == 15) ||
+                    THUMB2_INSN_MATCH(LDREX, insn) ||
+                    ((THUMB2_INSN_MATCH(STRW, insn) ||
+                      THUMB2_INSN_MATCH(STRBW, insn) ||
+                      THUMB2_INSN_MATCH(STRHW, insn) ||
+                      THUMB2_INSN_MATCH(STRHW1, insn)) &&
+                     (THUMB2_INSN_REG_RN(insn) == 15 ||
+                      THUMB2_INSN_REG_RT(insn) == 15)) ||
+                    ((THUMB2_INSN_MATCH(STRT, insn) ||
+                      THUMB2_INSN_MATCH(STRHT, insn)) &&
+                      (THUMB2_INSN_REG_RN(insn) == 15 ||
+                       THUMB2_INSN_REG_RT(insn) == 15))) {
+               uregs = 0xf000;         /* Rt 12-15 */
+               pc_dep = 1;
+       } else if ((THUMB2_INSN_MATCH(LDRD, insn) ||
+                   THUMB2_INSN_MATCH(LDRD1, insn)) &&
+                  (THUMB2_INSN_REG_RN(insn) == 15)) {
+               uregs = 0xff00;         /* Rt 12-15, Rt2 8-11 */
+               pc_dep = 1;
+       } else if (THUMB2_INSN_MATCH(MUL, insn) &&
+                  THUMB2_INSN_REG_RM(insn) == 15) {
+               uregs = 0xf;
+               pc_dep = 1;
+       } else if (THUMB2_INSN_MATCH(DP, insn) &&
+                  (THUMB2_INSN_REG_RN(insn) == 15 ||
+                   THUMB2_INSN_REG_RM(insn) == 15)) {
+               uregs = 0xf000;         /* Rd 12-15 */
+               pc_dep = 1;
+       } else if (THUMB2_INSN_MATCH(STRD, insn) &&
+                  ((THUMB2_INSN_REG_RN(insn) == 15) ||
+                   (THUMB2_INSN_REG_RT(insn) == 15) ||
+                   THUMB2_INSN_REG_RT2(insn) == 15)) {
+               uregs = 0xff00;         /* Rt 12-15, Rt2 8-11 */
+               pc_dep = 1;
+       } else if (THUMB2_INSN_MATCH(RSBW, insn) &&
+                  THUMB2_INSN_REG_RN(insn) == 15) {
+               uregs = 0x0f00;         /* Rd 8-11 */
+               pc_dep = 1;
+       } else if (THUMB2_INSN_MATCH(RORW, insn) &&
+                  (THUMB2_INSN_REG_RN(insn) == 15 ||
+                   THUMB2_INSN_REG_RM(insn) == 15)) {
+               uregs = 0x0f00;
+               pc_dep = 1;
+       } else if ((THUMB2_INSN_MATCH(ROR, insn) ||
+                   THUMB2_INSN_MATCH(LSLW2, insn) ||
+                   THUMB2_INSN_MATCH(LSRW2, insn)) &&
+                  THUMB2_INSN_REG_RM(insn) == 15) {
+               uregs = 0x0f00;         /* Rd 8-11 */
+               pc_dep = 1;
+       } else if ((THUMB2_INSN_MATCH(LSLW1, insn) ||
+                   THUMB2_INSN_MATCH(LSRW1, insn)) &&
+                  (THUMB2_INSN_REG_RN(insn) == 15 ||
+                   THUMB2_INSN_REG_RM(insn) == 15)) {
+               uregs = 0x0f00;         /* Rd 8-11 */
+               pc_dep = 1;
+       } else if ((THUMB2_INSN_MATCH(TEQ1, insn) ||
+                   THUMB2_INSN_MATCH(TST1, insn)) &&
+                  THUMB2_INSN_REG_RN(insn) == 15) {
+               uregs = 0xf0000;        /* Rn 0-3 (16-19) */
+               pc_dep = 1;
+       } else if ((THUMB2_INSN_MATCH(TEQ2, insn) ||
+                   THUMB2_INSN_MATCH(TST2, insn)) &&
+                  (THUMB2_INSN_REG_RN(insn) == 15 ||
+                   THUMB2_INSN_REG_RM(insn) == 15)) {
+               uregs = 0xf0000;        /* Rn 0-3 (16-19) */
+               pc_dep = 1;
+       }
+
+       if (unlikely(uregs && pc_dep)) {
+               memcpy(tramp, pc_dep_insn_execbuf_thumb, tramp_len);
+               prep_pc_dep_insn_execbuf_thumb(tramp, insn, uregs);
+
+               addr = vaddr + 4;
+               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
+               *((u16 *)tramp + 14) = addr & 0x0000ffff;
+               *((u16 *)tramp + 15) = addr >> 16;
+               if (!is_thumb2(insn)) {
+                       addr = vaddr + 2;
+                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((u16 *)tramp + 17) = addr >> 16;
+               } else {
+                       addr = vaddr + 4;
+                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((u16 *)tramp + 17) = addr >> 16;
+               }
+       } else {
+               memcpy(tramp, gen_insn_execbuf_thumb, tramp_len);
+               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
+               if (!is_thumb2(insn)) {
+                       addr = vaddr + 2;
+                       *((u16 *)tramp + 2) = insn;
+                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((u16 *)tramp + 17) = addr >> 16;
+               } else {
+                       addr = vaddr + 4;
+                       tramp[1] = insn;
+                       *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((u16 *)tramp + 17) = addr >> 16;
+               }
+       }
+
+       if (THUMB_INSN_MATCH(B2, insn)) {
+               memcpy(tramp, b_off_insn_execbuf_thumb, tramp_len);
+               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
+               addr = branch_t16_dest(insn, vaddr);
+               *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+               *((u16 *)tramp + 15) = addr >> 16;
+               *((u16 *)tramp + 16) = 0;
+               *((u16 *)tramp + 17) = 0;
+
+       } else if (THUMB_INSN_MATCH(B1, insn)) {
+               memcpy(tramp, b_cond_insn_execbuf_thumb, tramp_len);
+               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
+               *((u16 *)tramp + 0) |= (insn & 0xf00);
+               addr = branch_cond_t16_dest(insn, vaddr);
+               *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+               *((u16 *)tramp + 15) = addr >> 16;
+               addr = vaddr + 2;
+               *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((u16 *)tramp + 17) = addr >> 16;
+
+       } else if (THUMB_INSN_MATCH(BLX2, insn) ||
+                  THUMB_INSN_MATCH(BX, insn)) {
+               memcpy(tramp, b_r_insn_execbuf_thumb, tramp_len);
+               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
+               *((u16 *)tramp + 4) = insn;
+               addr = vaddr + 2;
+               *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((u16 *)tramp + 17) = addr >> 16;
+
+       } else if (THUMB_INSN_MATCH(CBZ, insn)) {
+               memcpy(tramp, cbz_insn_execbuf_thumb, tramp_len);
+               *((u16 *)tramp + 13) = RET_BREAK_THUMB;
+               /* zero out original branch displacement (imm5 = 0; i = 0) */
+               *((u16 *)tramp + 0) = insn & (~0x2f8);
+               /* replace it with 8 bytes offset in execbuf (imm5 = 0b00010) */
+               *((u16 *)tramp + 0) |= 0x20;
+               addr = cbz_t16_dest(insn, vaddr);
+               *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+               *((u16 *)tramp + 15) = addr >> 16;
+               addr = vaddr + 2;
+               *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((u16 *)tramp + 17) = addr >> 16;
+       }
+
+       return 0;
+}
+
+int make_trampoline_thumb(struct arch_insn_arm *ainsn,
+                         u32 vaddr, u32 insn, u32 *tramp, size_t tramp_len)
+{
+       int ret;
+
+       ret = do_make_trampoline_thumb(vaddr, insn, tramp, tramp_len);
+       if (ret) {
+               struct decode_info info = {
+                       .vaddr = vaddr,
+                       .tramp = tramp,
+                       .handeler = NULL,
+               };
+
+               ret = decode_thumb(insn, &info);
+               if (info.handeler) {
+                       u16 *tr = (u16 *)tramp;
+                       tr[13] = RET_BREAK_THUMB; /* bp for uretprobe */
+                       ainsn->handler = info.handeler;
+               }
+       }
+
+       return ret;
+}
+
+int noret_thumb(u32 opcode)
+{
+       return !!(THUMB2_INSN_MATCH(BL, opcode) ||
+                 THUMB2_INSN_MATCH(BLX1, opcode) ||
+                 THUMB_INSN_MATCH(BLX2, opcode));
+}
diff --git a/modules/arch/arm/probes/probes_thumb.h b/modules/arch/arm/probes/probes_thumb.h
new file mode 100644 (file)
index 0000000..1b20094
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_PROBES_THUMB_H
+#define _SWAP_ASM_PROBES_THUMB_H
+
+
+int make_trampoline_thumb(struct arch_insn_arm *ainsn, u32 vaddr, u32 insn,
+                         u32 *tramp, size_t tramp_len);
+int noret_thumb(u32 opcode);
+
+
+#endif /* _SWAP_ASM_PROBES_THUMB_H */
diff --git a/modules/arch/arm/probes/tramps_arm.c b/modules/arch/arm/probes/tramps_arm.c
new file mode 100644 (file)
index 0000000..84d978d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+__asm(
+".text\n"
+".arm\n"
+".global gen_insn_execbuf\n"
+"gen_insn_execbuf:\n"
+"      nop\n"
+"      nop\n"
+"      nop\n"                  /* original instruction */
+"      nop\n"
+"      ldr     pc, [pc, #4]\n" /* ssbreak */
+"      nop\n"                  /* retbreak */
+"      nop\n"
+"      nop\n"                  /* stored PC-4(next insn addr) */
+
+".global pc_dep_insn_execbuf\n"
+"pc_dep_insn_execbuf:\n"
+"      str     r0, [sp, #-4]\n"
+"      ldr     r0, [pc, #12]\n"
+"      nop\n"                  /* instruction with replaced PC */
+"      ldr     r0, [sp, #-4]\n"
+"      ldr     pc, [pc, #4]\n" /* ssbreak */
+"      nop\n"                  /* retbreak */
+"      nop\n"                  /* stored PC */
+"      nop\n"                  /* stored PC-4 (next insn addr) */
+
+".global b_r_insn_execbuf\n"
+"b_r_insn_execbuf:\n"
+"      nop\n"                  /* bx, blx (Rm) */
+"      ldr     pc, np1\n"
+"      nop\n"
+"      nop\n"
+"      nop\n"
+"      nop\n"                  /* retbreak */
+"      nop\n"
+"np1:\n"
+"      nop\n"                  /* stored PC-4 (next insn addr) */
+
+".global b_cond_insn_execbuf\n"
+"b_cond_insn_execbuf:\n"
+"      beq     condway\n"
+"      ldr     pc, np2\n"
+"condway:\n"
+"      ldr     pc, bd2\n"
+"      nop\n"
+"      nop\n"
+"      nop\n"                  /* retbreak */
+"bd2:\n"
+"      nop\n"                  /* branch displacement */
+"np2:\n"
+"      nop\n"                  /* stored PC-4 (next insn addr) */
+
+".global blx_off_insn_execbuf\n"
+"blx_off_insn_execbuf:\n"
+"      ldreq   lr, bd3\n"
+"      blxeq   lr\n"
+"      ldr     pc, np3\n"
+"      nop\n"
+"      nop\n"
+"      nop\n"                  /* retbreak */
+"bd3:\n"
+"      nop\n"                  /* branch displacement */
+"np3:\n"
+"      nop\n"                  /* stored PC-4 (next insn addr) */
+);
diff --git a/modules/arch/arm/probes/tramps_arm.h b/modules/arch/arm/probes/tramps_arm.h
new file mode 100644 (file)
index 0000000..0fc5d72
--- /dev/null
@@ -0,0 +1,103 @@
+/**
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
+ * Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
+ * redesign module for separating core and arch parts
+ * @author Alexander Shirshikov <a.shirshikov@samsung.com>:
+ * initial implementation for Thumb
+ *
+ * @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, 2006-2010
+ *
+ */
+
+#ifndef _SWAP_ASM_TRAMPS_ARM_H
+#define _SWAP_ASM_TRAMPS_ARM_H
+
+
+#include <linux/types.h>
+
+
+/*
+ * These arrays generated from tramps_arm.c
+ * using 32 bit compiler:
+ *   $ gcc tramps_arm.c -c -o tramps_arm.o
+ *   $ objdump -d tramps_arm.o
+ */
+
+static u32 __attribute__((unused)) gen_insn_execbuf[] = {
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe59ff004,     //   ldr        pc, [pc, #4]
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+};
+
+static u32 __attribute__((unused)) pc_dep_insn_execbuf[] = {
+       0xe50d0004,     //   str        r0, [sp, #-4]
+       0xe59f000c,     //   ldr        r0, [pc, #12]
+       0xe320f000,     //   nop
+       0xe51d0004,     //   ldr        r0, [sp, #-4]
+       0xe59ff004,     //   ldr        pc, [pc, #4]
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+};
+
+static u32 __attribute__((unused)) b_r_insn_execbuf[] = {
+       0xe320f000,     //   nop
+       0xe59ff010,     //   ldr        pc, [pc, #16]
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+};
+
+static u32 __attribute__((unused)) b_cond_insn_execbuf[] = {
+       0x0a000000,     //   beq        68 <condway>
+       0xe59ff010,     //   ldr        pc, [pc, #16]
+       0xe59ff008,     //   ldr        pc, [pc, #8]
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+};
+
+static u32 __attribute__((unused)) blx_off_insn_execbuf[] = {
+       0x059fe010,     //   ldreq      lr, [pc, #16]
+       0x012fff3e,     //   blxeq      lr
+       0xe59ff00c,     //   ldr        pc, [pc, #12]
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+       0xe320f000,     //   nop
+};
+
+
+#endif /* _SWAP_ASM_TRAMPS_ARM_H */
diff --git a/modules/arch/arm/probes/tramps_thumb.c b/modules/arch/arm/probes/tramps_thumb.c
new file mode 100644 (file)
index 0000000..c9ce11d
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+__asm(
+".text\n"
+".thumb\n"
+
+".global gen_insn_execbuf_thumb\n"
+"gen_insn_execbuf_thumb:\n"
+       "nop\n"
+       "nop\n"
+       "nop\n"                 /* original instruction */
+       "nop\n"                 /* original instruction */
+       "nop\n"
+       "nop\n"
+       "nop\n"
+       "sub    sp, sp, #8\n"
+       "str    r0, [sp, #0]\n"
+       "ldr    r0, [pc, #12]\n"
+       "str    r0, [sp, #4]\n"
+       "nop\n"
+       "pop    {r0, pc}\n"     /* ssbreak */
+       "nop\n"                 /* retbreak */
+       "nop\n"
+       "nop\n"
+       "nop\n"                 /* stored PC-4(next insn addr) hi */
+       "nop\n"                 /* stored PC-4(next insn addr) lo */
+
+       "nop\n"
+
+".global pc_dep_insn_execbuf_thumb\n"
+".align 4\n"
+"pc_dep_insn_execbuf_thumb:\n"
+       "push   {r6, r7}\n"
+       "ldr    r6, i1\n"
+       "mov    r7, sp\n"
+       "mov    sp, r6\n"
+       "nop\n"                 /* PC -> SP */
+       "nop\n"                 /* PC -> SP */
+       "mov    sp, r7\n"
+       "pop    {r6, r7}\n"
+       "push   {r0, r1}\n"
+       "ldr    r0, i2\n"
+       "nop\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0, pc}\n"     /* ssbreak */
+       "nop\n"                 /* retbreak */
+"i1:\n"
+       "nop\n"                 /* stored PC hi */
+       "nop\n"                 /* stored PC lo */
+"i2:\n"
+       "nop\n"                 /* stored PC-4(next insn addr) hi */
+       "nop\n"                 /* stored PC-4(next insn addr) lo */
+
+".global b_r_insn_execbuf_thumb\n"
+".align 4\n"
+"b_r_insn_execbuf_thumb:\n"
+       "nop\n"
+       "nop\n"
+       "nop\n"
+       "nop\n"
+       "nop\n"                 /* bx,blx (Rm) */
+       "nop\n"
+       "push   {r0,r1}\n"
+       "ldr    r0, np\n"
+       "nop\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0,pc}\n"
+       "nop\n"
+       "nop\n"                 /* ssbreak */
+       "nop\n"                 /* retbreak */
+       "nop\n"
+       "nop\n"
+"np:\n"
+       "nop\n"                 /* stored PC-4(next insn addr) hi */
+       "nop\n"                 /* stored PC-4(next insn addr) lo */
+
+".global b_off_insn_execbuf_thumb\n"
+".align 4\n"
+"b_off_insn_execbuf_thumb:\n"
+       "push   {r0,r1}\n"
+       "ldr    r0, bd\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0, pc}\n"
+       "nop\n"
+       "nop\n"
+       "push   {r0,r1}\n"
+       "ldr    r0, np2\n"
+       "nop\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0,pc}\n"
+       "nop\n"
+       "nop\n"                 /* ssbreak */
+       "nop\n"                 /* retbreak */
+"bd:\n"
+       "nop\n"                 /* branch displacement hi */
+       "nop\n"                 /* branch displacement lo */
+"np2:\n"
+       "nop\n"                 /* stored PC-4(next insn addr) hi */
+       "nop\n"                 /* stored PC-4(next insn addr) lo */
+
+".global b_cond_insn_execbuf_thumb\n"
+".align 4\n"
+"b_cond_insn_execbuf_thumb:\n"
+       "beq    condway\n"
+       "push   {r0,r1}\n"
+       "ldr    r0, np4\n"
+       "nop\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0,pc}\n"
+"condway:\n"
+       "push   {r0,r1}\n"
+       "ldr    r0, bd4\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0,pc}\n"
+       "nop\n"
+       "nop\n"
+       "nop\n"                 /* ssbreak */
+       "nop\n"                 /* retbreak */
+"bd4:\n"
+       "nop\n"                 /* branch displacement hi */
+       "nop\n"                 /* branch displacement lo */
+"np4:\n"
+       "nop\n"                 /* stored PC-4(next insn addr) hi */
+       "nop\n"                 /* stored PC-4(next insn addr) lo */
+
+".global cbz_insn_execbuf_thumb\n"
+".align 4\n"
+"cbz_insn_execbuf_thumb:\n"
+       "nop\n"                 /* cbz */
+       "push   {r0,r1}\n"
+       "ldr    r0, np5\n"
+       "nop\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0,pc}\n"
+       "push   {r0,r1}\n"
+       "ldr    r0, bd5\n"
+       "str    r0, [sp, #4]\n"
+       "pop    {r0,pc}\n"
+       "nop\n"
+       "nop\n"
+       "nop\n"                 /* ssbreak */
+       "nop\n"                 /* retbreak */
+"bd5:\n"
+       "nop\n"                 /* branch displacement hi */
+       "nop\n"                 /* branch displacement lo */
+"np5:\n"
+       "nop\n"                 /* stored PC-4(next insn addr) hi */
+       "nop\n"                 /* stored PC-4(next insn addr) lo */
+);
diff --git a/modules/arch/arm/probes/tramps_thumb.h b/modules/arch/arm/probes/tramps_thumb.h
new file mode 100644 (file)
index 0000000..eb34275
--- /dev/null
@@ -0,0 +1,172 @@
+/**
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ */
+
+
+#ifndef _SWAP_ASM_TRAMPS_THUMB_H
+#define _SWAP_ASM_TRAMPS_THUMB_H
+
+
+#include <linux/types.h>
+
+
+/*
+ * These arrays generated from tramps_thumb.c
+ * using 32 bit compiler:
+ *   $ gcc tramps_thumb.c -c -o tramps_thumb.o
+ *   $ objdump -d tramps_thumb.o
+ */
+
+static u16 __attribute__((unused)) gen_insn_execbuf_thumb[] = {
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xb082,         //   sub        sp, #8
+       0x9000,         //   str        r0, [sp, #0]
+       0x4803,         //   ldr        r0, [pc, #12]
+       0x9001,         //   str        r0, [sp, #4]
+       0xbf00,         //   nop
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+};
+
+static u16 __attribute__((unused)) pc_dep_insn_execbuf_thumb[] = {
+       0xb4c0,         //   push       {r6, r7}
+       0x4e06,         //   ldr        r6, [pc, #24]
+       0x466f,         //   mov        r7, sp
+       0x46b5,         //   mov        sp, r6
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0x46bd,         //   mov        sp, r7
+       0xbcc0,         //   pop        {r6, r7}
+       0xb403,         //   push       {r0, r1}
+       0x4803,         //   ldr        r0, [pc, #12]
+       0xbf00,         //   nop
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+};
+
+static u16 __attribute__((unused)) b_r_insn_execbuf_thumb[] = {
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xb403,         //   push       {r0, r1}
+       0x4804,         //   ldr        r0, [pc, #16]
+       0xbf00,         //   nop
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+};
+
+static u16 __attribute__((unused)) b_off_insn_execbuf_thumb[] = {
+       0xb403,         //   push       {r0, r1}
+       0x4806,         //   ldr        r0, [pc, #24]
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xb403,         //   push       {r0, r1}
+       0x4804,         //   ldr        r0, [pc, #16]
+       0xbf00,         //   nop
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+};
+
+static u16 __attribute__((unused)) b_cond_insn_execbuf_thumb[] = {
+       0xf000, 0x8005, //   beq.w      ce <condway>
+       0xb403,         //   push       {r0, r1}
+       0x4807,         //   ldr        r0, [pc, #28]
+       0xbf00,         //   nop
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xb403,         //   push       {r0, r1}
+       0xf8df, 0x000c, //   ldr.w      r0, [pc, #12]
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+};
+
+static u16 __attribute__((unused)) cbz_insn_execbuf_thumb[] = {
+       0xbf00,         //   nop
+       0xb403,         //   push       {r0, r1}
+       0x4806,         //   ldr        r0, [pc, #24]
+       0xbf00,         //   nop
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xb403,         //   push       {r0, r1}
+       0x4803,         //   ldr        r0, [pc, #12]
+       0x9001,         //   str        r0, [sp, #4]
+       0xbd01,         //   pop        {r0, pc}
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+       0xbf00,         //   nop
+};
+
+
+#endif /* _SWAP_ASM_TRAMPS_THUMB_H */
diff --git a/modules/arch/arm/uprobe/swap_uprobe.c b/modules/arch/arm/uprobe/swap_uprobe.c
new file mode 100644 (file)
index 0000000..c7b2d0f
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+
+#include <arch/arm/probes/probes.h>
+#include <arch/arm/probes/probes_arm.h>
+#include <arch/arm/probes/probes_thumb.h>
+#include <uprobe/swap_uprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <kprobe/swap_slots.h>
+#include "../probes/compat_arm64.h"
+
+
+#define PTR_TO_U32(x)  ((u32)(unsigned long)(x))
+#define U32_TO_PTR(x)  ((void *)(unsigned long)(x))
+
+#define flush_insns(addr, size) \
+               flush_icache_range((unsigned long)(addr), \
+                                  (unsigned long)(addr) + (size))
+
+
+/**
+ * @brief Prepares uprobe for ARM.
+ *
+ * @param up Pointer to the uprobe.
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int arch_prepare_uprobe_arm(struct uprobe *p)
+{
+       int ret;
+       struct task_struct *task = p->task;
+       unsigned long vaddr = (unsigned long)p->addr;
+       u32 insn;
+       u32 tramp[UPROBES_TRAMP_LEN];
+       u32 __user *utramp;
+       enum { tramp_len = sizeof(tramp) };
+
+       if (!read_proc_vm_atomic(task, vaddr & ~1, &insn, sizeof(insn))) {
+               printk(KERN_ERR "failed to read memory %lx!\n", vaddr);
+               return -EINVAL;
+       }
+
+       ret = make_tramp(&p->ainsn.insn, vaddr, insn, tramp, tramp_len);
+       if (ret) {
+               pr_err("failed to make tramp, addr=%p\n", p->addr);
+               return ret;
+       }
+
+       utramp = swap_slot_alloc(p->sm);
+       if (utramp == NULL) {
+               printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
+                      vaddr);
+               return -ENOMEM;
+       }
+
+       if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
+                                 tramp_len)) {
+               pr_err("failed to write memory tramp=%p!\n", utramp);
+               swap_slot_free(p->sm, utramp);
+               return -EINVAL;
+       }
+
+       flush_insns(utramp, tramp_len);
+       p->insn = utramp;
+       p->opcode = insn;
+
+       return 0;
+}
+
+int arch_arm_uprobe_arm(struct uprobe *p)
+{
+       int ret;
+       unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
+       int thumb_mode = (unsigned long)p->addr & 1;
+       int len = 4 >> thumb_mode;      /* if thumb_mode then len = 2 */
+       unsigned long insn = thumb_mode ? BREAK_THUMB : BREAK_ARM;
+
+       ret = write_proc_vm_atomic(p->task, vaddr, &insn, len);
+       if (!ret) {
+               pr_err("failed to write memory tgid=%u addr=%08lx len=%d\n",
+                      p->task->tgid, vaddr, len);
+
+               return -EACCES;
+       } else {
+               flush_insns(vaddr, len);
+       }
+
+       return 0;
+}
+
+void arch_disarm_uprobe_arm(struct uprobe *p, struct task_struct *task)
+{
+       int ret;
+
+       unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
+       int thumb_mode = (unsigned long)p->addr & 1;
+       int len = 4 >> thumb_mode;      /* if thumb_mode then len = 2 */
+
+       ret = write_proc_vm_atomic(task, vaddr, &p->opcode, len);
+       if (!ret) {
+               pr_err("Failed to write memory tgid=%u addr=%08lx len=%d\n",
+                      task->tgid, vaddr, len);
+       } else {
+               flush_insns(vaddr, len);
+       }
+}
+
+/**
+ * @brief Prepates uretprobe for ARM.
+ *
+ * @param ri Pointer to the uretprobe instance.
+ * @param regs Pointer to CPU register data.
+ * @return Error code.
+ */
+int prepare_uretprobe_arm(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       unsigned long thumb, bp_offset;
+
+       thumb = ri->preload.use ? ri->preload.thumb : thumb_mode(regs);
+       bp_offset = thumb ? 0x1b : 4 * PROBES_TRAMP_RET_BREAK_IDX;
+
+       /* save original return address */
+       ri->ret_addr = (uprobe_opcode_t *)regs->ARM_lr;
+
+       /* replace return address with break point adddress */
+       regs->ARM_lr = (unsigned long)(ri->rp->up.insn) + bp_offset;
+
+       /* save stack pointer address */
+       ri->sp = (uprobe_opcode_t *)regs->ARM_sp;
+
+       /* Set flag of current mode */
+       ri->sp = (uprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
+
+       return 0;
+}
+
+/**
+ * @brief Restores return address.
+ *
+ * @param orig_ret_addr Original return address.
+ * @param regs Pointer to CPU register data.
+ * @return Void.
+ */
+void set_orig_ret_addr_arm(unsigned long orig_ret_addr, struct pt_regs *regs)
+{
+       regs->ARM_lr = orig_ret_addr;
+       regs->ARM_pc = orig_ret_addr & ~0x1;
+
+       if (regs->ARM_lr & 0x1)
+               regs->ARM_cpsr |= PSR_T_BIT;
+       else
+               regs->ARM_cpsr &= ~PSR_T_BIT;
+}
+
+void arch_opcode_analysis_uretprobe_arm(struct uretprobe *rp)
+{
+       /* Remove retprobe if first insn overwrites lr */
+       rp->thumb_noret = noret_thumb(rp->up.opcode);
+       rp->arm_noret = noret_arm(rp->up.opcode);
+}
+
+unsigned long arch_get_trampoline_addr_arm(struct uprobe *p,
+                                          struct pt_regs *regs)
+{
+       return thumb_mode(regs) ?
+                       PTR_TO_U32(p->insn) + 0x1b :
+                       PTR_TO_U32(p->insn +
+                                  PROBES_TRAMP_RET_BREAK_IDX);
+}
+
+unsigned long arch_tramp_by_ri_arm(struct uretprobe_instance *ri)
+{
+       /* Understand function mode */
+       return (PTR_TO_U32(ri->sp) & 1) ?
+                       PTR_TO_U32(ri->rp->up.insn) + 0x1b :
+                       PTR_TO_U32(ri->rp->up.insn +
+                                  PROBES_TRAMP_RET_BREAK_IDX);
+}
+
+int arch_disarm_urp_inst_arm(struct uretprobe_instance *ri,
+                            struct task_struct *task)
+{
+       struct pt_regs *uregs = task_pt_regs(ri->task);
+       u32 ra = uregs->ARM_lr;
+       u32 vaddr, tramp, found = 0;
+       u32 sp = PTR_TO_U32(ri->sp) & ~1;
+       u32 ret_addr = PTR_TO_U32(ri->ret_addr);
+       u32 stack = sp - 4 * (URETPROBE_STACK_DEPTH + 1);
+       u32 buf[URETPROBE_STACK_DEPTH];
+       int i, ret;
+
+       vaddr = PTR_TO_U32(ri->rp->up.addr);
+       tramp = arch_tramp_by_ri_arm(ri);
+
+       /* check stack */
+       ret = read_proc_vm_atomic(task, stack, buf, sizeof(buf));
+       if (ret != sizeof(buf)) {
+               pr_info("---> %s (%d/%d): failed to read stack from %08x\n",
+                       task->comm, task->tgid, task->pid, stack);
+               ret = -EFAULT;
+               goto check_lr;
+       }
+
+       /* search the stack from the bottom */
+       for (i = URETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
+               if (buf[i] == tramp) {
+                       found = stack + 4 * i;
+                       break;
+               }
+       }
+
+       if (!found) {
+               ret = -ESRCH;
+               goto check_lr;
+       }
+
+       pr_info("---> %s (%d/%d): trampoline found at "
+               "%08x (%08x /%+d) - %x, set ret_addr=%08x\n",
+               task->comm, task->tgid, task->pid,
+               found, sp,
+               found - sp, vaddr, ret_addr);
+       ret = write_proc_vm_atomic(task, found, &ret_addr, 4);
+       if (ret != 4) {
+               pr_info("---> %s (%d/%d): failed to write value to %08x",
+                       task->comm, task->tgid, task->pid, found);
+               ret = -EFAULT;
+       } else {
+               ret = 0;
+       }
+
+check_lr: /* check lr anyway */
+       if (ra == tramp) {
+               pr_info("---> %s (%d/%d): trampoline found at "
+                       "lr = %08x - %x, set ret_addr=%08x\n",
+                       task->comm, task->tgid, task->pid, ra, vaddr,
+                       ret_addr);
+
+               /* set ret_addr */
+               uregs->ARM_lr = ret_addr;
+               ret = 0;
+       } else if (ret) {
+               pr_info("---> %s (%d/%d): trampoline NOT found at "
+                       "sp=%08x, lr=%08x - %x, ret_addr=%08x\n",
+                       task->comm, task->tgid, task->pid,
+                       sp, ra, vaddr, ret_addr);
+       }
+
+       return ret;
+}
diff --git a/modules/arch/arm/uprobe/swap_uprobe.h b/modules/arch/arm/uprobe/swap_uprobe.h
new file mode 100644 (file)
index 0000000..19c84f1
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_ARM_UPROBE_H
+#define _SWAP_ASM_ARM_UPROBE_H
+
+
+#include <linux/printk.h>
+#include <linux/uaccess.h>
+#include "../probes/compat_arm64.h"
+
+
+struct pt_regs;
+struct uprobe;
+struct uretprobe;
+struct uretprobe_instance;
+
+
+static inline unsigned long swap_get_upc_arm(struct pt_regs *regs)
+{
+       return regs->ARM_pc | !!thumb_mode(regs);
+}
+
+static inline void swap_set_upc_arm(struct pt_regs *regs, unsigned long val)
+{
+       if (val & 1) {
+               regs->ARM_pc = val & ~1UL;
+               regs->ARM_cpsr |= PSR_T_BIT;
+       } else {
+               regs->ARM_pc = val;
+               regs->ARM_cpsr &= ~PSR_T_BIT;
+       }
+}
+
+static inline unsigned long swap_get_uarg_arm(struct pt_regs *regs,
+                                             unsigned long n)
+{
+       u32 *ptr, val = 0;
+
+       switch (n) {
+       case 0:
+               return regs->ARM_r0;
+       case 1:
+               return regs->ARM_r1;
+       case 2:
+               return regs->ARM_r2;
+       case 3:
+               return regs->ARM_r3;
+       default:
+               ptr = (u32 *)regs->ARM_sp + n - 4;
+               if (get_user(val, ptr))
+                       pr_err("Failed to dereference a pointer[%p]\n", ptr);
+               break;
+       }
+
+       return val;
+}
+
+static inline void swap_put_uarg_arm(struct pt_regs *regs, unsigned long n,
+                                    unsigned long val)
+{
+       u32 *ptr;
+
+       switch (n) {
+       case 0:
+               regs->ARM_r0 = val;
+               break;
+       case 1:
+               regs->ARM_r1 = val;
+               break;
+       case 2:
+               regs->ARM_r2 = val;
+               break;
+       case 3:
+               regs->ARM_r3 = val;
+               break;
+       default:
+               ptr = (u32 *)regs->ARM_sp + n - 4;
+               if (put_user(val, ptr))
+                       pr_err("Failed to dereference a pointer[%p]\n", ptr);
+       }
+}
+
+static inline unsigned long swap_get_uret_addr_arm(struct pt_regs *regs)
+{
+       return regs->ARM_lr;
+}
+
+static inline void swap_set_uret_addr_arm(struct pt_regs *regs, unsigned long v)
+{
+       regs->ARM_lr = v;
+}
+
+int arch_prepare_uprobe_arm(struct uprobe *p);
+int arch_arm_uprobe_arm(struct uprobe *p);
+void arch_disarm_uprobe_arm(struct uprobe *p, struct task_struct *task);
+
+int prepare_uretprobe_arm(struct uretprobe_instance *ri, struct pt_regs *regs);
+void set_orig_ret_addr_arm(unsigned long orig_ret_addr, struct pt_regs *regs);
+void arch_opcode_analysis_uretprobe_arm(struct uretprobe *rp);
+unsigned long arch_get_trampoline_addr_arm(struct uprobe *p,
+                                          struct pt_regs *regs);
+unsigned long arch_tramp_by_ri_arm(struct uretprobe_instance *ri);
+int arch_disarm_urp_inst_arm(struct uretprobe_instance *ri,
+                            struct task_struct *task);
+
+
+#endif /* _SWAP_ASM_ARM_UPROBE_H */
+
diff --git a/modules/buffer/Kbuild b/modules/buffer/Kbuild
new file mode 100644 (file)
index 0000000..98872bf
--- /dev/null
@@ -0,0 +1,6 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_buffer.o
+swap_buffer-y := swap_buffer_module.o \
+                 buffer_queue.o
+
diff --git a/modules/buffer/buffer_description.h b/modules/buffer/buffer_description.h
new file mode 100644 (file)
index 0000000..353e33a
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * @file buffer/buffer_description.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * swap_subbuffer structure represents one buffers subbufer
+ */
+
+#ifndef __BUFFER_DESCRIPTION_H__
+#define __BUFFER_DESCRIPTION_H__
+
+#include "data_types.h"
+
+/**
+ * @struct swap_subbuffer
+ * @brief This structures are combined in array which represents the SWAP buffer.
+ * @var swap_subbuffer::next_in_queue
+ * Pointer to the next swap_subbufer in queue
+ * @var swap_subbuffer::full_buffer_part
+ * Currently occupied subbuffers size
+ * @var swap_subbuffer::data_buffer
+ * Pointer to subbuffers data itself of type swap_subbuffer_ptr
+ * @var swap_subbuffer::buffer_sync
+ * Subbuffers sync primitive
+ */
+struct swap_subbuffer {
+       /* Pointer to the next subbuffer in queue */
+       struct swap_subbuffer *next_in_queue;
+       /* Size of the filled part of a subbuffer */
+       size_t full_buffer_part;
+       /* Pointer to data buffer */
+       swap_subbuffer_ptr data_buffer;
+       /* Buffer rw sync */
+       struct sync_t buffer_sync;
+};
+
+#endif /* __BUFFER_DESCRIPTION_H__ */
diff --git a/modules/buffer/buffer_queue.c b/modules/buffer/buffer_queue.c
new file mode 100644 (file)
index 0000000..803e930
--- /dev/null
@@ -0,0 +1,684 @@
+/**
+ * buffer/buffer_queue.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ * @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
+ *
+ * Implements buffers queues interface
+ */
+
+/* For all memory allocation/deallocation operations, except buffer memory
+ * allocation/deallocation should be used
+ *  memory_allocation(size_t memory_size)
+ *  memory_free(void *ptr)
+ * defines.
+ * For subbuffer allocation/deallocation operations should be used
+ *  buffer_allocation(size_t subbuffer_size)
+ *  buffer_free(void *ptr, size_t subbuffer_size)
+ * To get buffer pointer for any usage, EXCEPT ALLOCATION AND DEALLOCATION
+ * use the following define:
+ *  buffer_pointer(void *ptr_to_buffer_element_of_swap_buffer_structure)
+ * DO NOT USE SUBBUFFER PTR IN STRUCT SWAP_BUFFER WITHOUT THIS DEFINE!
+ * It will be ok for user space, but fail in kernel space.
+ *
+ * See space_dep_types_and_def.h for details */
+
+
+
+#include "buffer_queue.h"
+#include "swap_buffer_to_buffer_queue.h"
+#include "swap_buffer_errors.h"
+#include "kernel_operations.h"
+
+/**
+ * @struct queue_t
+ * @brief Queue structure. Consist of pointers to the first and the last
+ * elements of queue.
+ * @var queue_t::start_ptr
+ * Pointer to the first subbuffer in queue
+ * @var queue_t::end_ptr
+ * Pointer to the last subbuffer in queue
+ * @var queue_t::subbuffers_count
+ * Subbuffers count in queue
+ * @var queue_t::queue_sync
+ * Queue access sync primitive
+ */
+struct queue_t {
+       struct swap_subbuffer *start_ptr;
+       struct swap_subbuffer *end_ptr;
+       unsigned int subbuffers_count;
+       struct sync_t queue_sync;
+};
+
+/**
+ * @var write_queue
+ * @brief Represents write queue.
+ */
+struct queue_t write_queue = {
+       .start_ptr = NULL,
+       .end_ptr = NULL,
+       .subbuffers_count = 0,
+       .queue_sync = {
+               .flags = 0x0
+       }
+};
+
+/**
+ * @var read_queue
+ * @brief Represents read queue.
+ */
+struct queue_t read_queue = {
+       .start_ptr = NULL,
+       .end_ptr = NULL,
+       .subbuffers_count = 0,
+       .queue_sync = {
+               .flags = 0x0
+       }
+};
+
+/* Pointers array. Points to busy buffers */
+static struct swap_subbuffer **queue_busy;
+
+/* Store last busy element */
+static unsigned int queue_busy_last_element;
+
+/* Subbuffers count */
+static unsigned int queue_subbuffer_count;
+
+/* One subbuffer size */
+static size_t queue_subbuffer_size;
+
+/* Busy list sync */
+static struct sync_t buffer_busy_sync = {
+       .flags = 0x0
+};
+
+/* Memory pages count in one subbuffer */
+static int pages_order_in_subbuffer;
+
+/**
+ * @brief Allocates memory for swap_subbuffer structures and subbuffers.
+ * Total allocated memory = subbuffer_size * subbuffers_count.
+ *
+ * @param subbuffer_size Size of each subbuffer.
+ * @param subbuffers_count Count of subbuffers.
+ * @return 0 on success, negative error code otherwise.
+ */
+int buffer_queue_allocation(size_t subbuffer_size,
+                           unsigned int subbuffers_count)
+{
+       unsigned int i = 0;
+       unsigned int j = 0;
+       unsigned int allocated_buffers = 0;
+       unsigned int allocated_structs = 0;
+       struct swap_subbuffer *clean_tmp_struct;
+       int result;
+
+       /* Static varibles initialization */
+       queue_subbuffer_size = subbuffer_size;
+       queue_subbuffer_count = subbuffers_count;
+       queue_busy_last_element = 0;
+
+       /* Set variable pages_in_subbuffer. It is used for allocation and
+        * deallocation memory pages and its value is returned from
+        * swap_buffer_get() and contains page count in one subbuffer.
+        * All this useful only in kernel space. In userspace it is dummy.*/
+       set_pages_order_in_subbuffer(queue_subbuffer_size);
+       /* Sync primitives initialization */
+       sync_init(&read_queue.queue_sync);
+       sync_init(&write_queue.queue_sync);
+       sync_init(&buffer_busy_sync);
+
+       /* Memory allocation for queue_busy */
+       queue_busy =
+               memory_allocation(sizeof(*queue_busy) * queue_subbuffer_count);
+
+       if (!queue_busy) {
+               result = -E_SB_NO_MEM_QUEUE_BUSY;
+               goto buffer_allocation_error_ret;
+       }
+
+       /* Memory allocation for swap_subbuffer structures */
+
+       /* Allocation for first structure. */
+       write_queue.start_ptr =
+               memory_allocation(sizeof(*write_queue.start_ptr));
+
+       if (!write_queue.start_ptr) {
+               result = -E_SB_NO_MEM_BUFFER_STRUCT;
+               goto buffer_allocation_queue_busy_free;
+       }
+       allocated_structs++;
+
+
+       write_queue.end_ptr = write_queue.start_ptr;
+
+       write_queue.end_ptr->next_in_queue = NULL;
+       write_queue.end_ptr->full_buffer_part = 0;
+       write_queue.end_ptr->data_buffer =
+               buffer_allocation(queue_subbuffer_size);
+       if (!write_queue.end_ptr->data_buffer) {
+               print_err("Cannot allocate memory for buffer 1\n");
+               result = -E_SB_NO_MEM_DATA_BUFFER;
+               goto buffer_allocation_error_free;
+       }
+       allocated_buffers++;
+
+       sync_init(&write_queue.end_ptr->buffer_sync);
+
+       /* Buffer initialization */
+       memset(buffer_address(write_queue.end_ptr->data_buffer), 0,
+              queue_subbuffer_size);
+
+       /* Allocation for other structures. */
+       for (i = 1; i < queue_subbuffer_count; i++) {
+               write_queue.end_ptr->next_in_queue =
+                   memory_allocation(
+                           sizeof(*write_queue.end_ptr->next_in_queue));
+               if (!write_queue.end_ptr->next_in_queue) {
+                       result = -E_SB_NO_MEM_BUFFER_STRUCT;
+                       goto buffer_allocation_error_free;
+               }
+               allocated_structs++;
+
+               /* Now next write_queue.end_ptr is next */
+               write_queue.end_ptr = write_queue.end_ptr->next_in_queue;
+
+               write_queue.end_ptr->next_in_queue = NULL;
+               write_queue.end_ptr->full_buffer_part = 0;
+               write_queue.end_ptr->data_buffer =
+                       buffer_allocation(queue_subbuffer_size);
+               if (!write_queue.end_ptr->data_buffer) {
+                       result = -E_SB_NO_MEM_DATA_BUFFER;
+                       goto buffer_allocation_error_free;
+               }
+               allocated_buffers++;
+
+               sync_init(&write_queue.end_ptr->buffer_sync);
+
+               /* Buffer initialization */
+               memset(buffer_address(write_queue.end_ptr->data_buffer), 0,
+                      queue_subbuffer_size);
+       }
+
+       /* All subbuffers are in write list */
+       write_queue.subbuffers_count = subbuffers_count;
+
+       return E_SB_SUCCESS;
+
+       /* In case of errors, this code is called */
+       /* Free all previously allocated memory */
+buffer_allocation_error_free:
+       clean_tmp_struct = write_queue.start_ptr;
+
+       for (j = 0; j < allocated_structs; j++) {
+               clean_tmp_struct = write_queue.start_ptr;
+               if (allocated_buffers) {
+                       buffer_free(clean_tmp_struct->data_buffer,
+                                   queue_subbuffer_size);
+                       allocated_buffers--;
+               }
+               if (write_queue.start_ptr != write_queue.end_ptr)
+                       write_queue.start_ptr =
+                               write_queue.start_ptr->next_in_queue;
+               memory_free(clean_tmp_struct);
+       }
+       write_queue.end_ptr = NULL;
+       write_queue.start_ptr = NULL;
+
+buffer_allocation_queue_busy_free:
+       memory_free(queue_busy);
+       queue_busy = NULL;
+
+buffer_allocation_error_ret:
+       return result;
+}
+
+/**
+ * @brief Resets all subbuffers for writing.
+ *
+ * @return 0 on success, negative error code otherwise.
+ */
+int buffer_queue_reset(void)
+{
+       struct swap_subbuffer *buffer = read_queue.start_ptr;
+
+       /* Check if there are some subbuffers in busy list.
+        * If so - return error */
+       if (get_busy_buffers_count())
+               return -E_SB_UNRELEASED_BUFFERS;
+
+       /* Lock read sync primitive */
+       sync_lock(&read_queue.queue_sync);
+
+       /* Set all subbuffers in read list to write list
+        * and reinitialize them */
+       while (read_queue.start_ptr) {
+
+               /* Lock buffer sync primitive to prevent writing to buffer if it
+                * had been selected for writing, but still wasn't wrote. */
+               sync_lock(&buffer->buffer_sync);
+
+               buffer = read_queue.start_ptr;
+
+               /* If we reached end of the list */
+               if (read_queue.start_ptr == read_queue.end_ptr)
+                       read_queue.end_ptr = NULL;
+
+               read_queue.start_ptr = read_queue.start_ptr->next_in_queue;
+
+               /* Reinit full buffer part */
+               buffer->full_buffer_part = 0;
+
+               add_to_write_list(buffer);
+
+               /* Unlock buffer sync primitive */
+               sync_unlock(&buffer->buffer_sync);
+       }
+
+       /* Unlock read primitive */
+       sync_unlock(&read_queue.queue_sync);
+
+       return E_SB_SUCCESS;
+}
+
+/**
+ * @brief Free all allocated subbuffers.
+ *
+ * @return Void.
+ */
+void buffer_queue_free(void)
+{
+       struct swap_subbuffer *tmp = NULL;
+
+       /* Lock all sync primitives to prevet accessing free memory */
+       sync_lock(&write_queue.queue_sync);
+       sync_lock(&read_queue.queue_sync);
+       sync_lock(&buffer_busy_sync);
+
+       /* Free buffers and structures memory that are in read list */
+       while (read_queue.start_ptr) {
+               tmp = read_queue.start_ptr;
+               read_queue.start_ptr = read_queue.start_ptr->next_in_queue;
+               buffer_free(tmp->data_buffer, queue_subbuffer_size);
+               memory_free(tmp);
+       }
+
+       /* Free buffers and structures memory that are in read list */
+       while (write_queue.start_ptr) {
+               tmp = write_queue.start_ptr;
+               write_queue.start_ptr = write_queue.start_ptr->next_in_queue;
+               buffer_free(tmp->data_buffer, queue_subbuffer_size);
+               memory_free(tmp);
+       }
+
+       /* Free busy_list */
+       memory_free(queue_busy);
+       queue_busy = NULL;
+
+       queue_subbuffer_size = 0;
+       queue_subbuffer_count = 0;
+       read_queue.start_ptr = NULL;
+       read_queue.end_ptr = NULL;
+       write_queue.start_ptr = NULL;
+       write_queue.end_ptr = NULL;
+
+       /* Unlock all sync primitives */
+       sync_unlock(&buffer_busy_sync);
+       sync_unlock(&read_queue.queue_sync);
+       sync_unlock(&write_queue.queue_sync);
+}
+
+static unsigned int is_buffer_enough(struct swap_subbuffer *subbuffer,
+                                    size_t size)
+{
+       /* XXX Think about checking full_buffer_part for correctness
+        * (<queue_subbuffer_size). It should be true, but if isn't (due to
+        * sources chaning, etc.) this function should be true! */
+       return ((queue_subbuffer_size-subbuffer->full_buffer_part) >= size) ?
+               1 : 0;
+}
+
+static void next_queue_element(struct queue_t *queue)
+{
+       /* If we reached the last elemenet, end pointer should point to NULL */
+       if (queue->start_ptr == queue->end_ptr)
+               queue->end_ptr = NULL;
+
+       queue->start_ptr = queue->start_ptr->next_in_queue;
+       --queue->subbuffers_count;
+}
+
+/**
+ * @brief Get first subbuffer from read list.
+ *
+ * @return Pointer to swap_subbuffer
+ */
+struct swap_subbuffer *get_from_read_list(void)
+{
+       struct swap_subbuffer *result = NULL;
+
+       /* Lock read sync primitive */
+       sync_lock(&read_queue.queue_sync);
+
+       if (read_queue.start_ptr == NULL) {
+               result = NULL;
+               goto get_from_read_list_unlock;
+       }
+
+       result = read_queue.start_ptr;
+
+       next_queue_element(&read_queue);
+
+get_from_read_list_unlock:
+       /* Unlock read sync primitive */
+       sync_unlock(&read_queue.queue_sync);
+
+       return result;
+}
+
+/**
+ * @brief Add subbuffer to read list.
+ *
+ * @param subbuffer Pointer to the subbuffer to add.
+ * @return Void.
+ */
+void add_to_read_list(struct swap_subbuffer *subbuffer)
+{
+       /* Lock read sync primitive */
+       sync_lock(&read_queue.queue_sync);
+
+       if (!read_queue.start_ptr)
+               read_queue.start_ptr = subbuffer;
+
+       if (read_queue.end_ptr) {
+               read_queue.end_ptr->next_in_queue = subbuffer;
+
+               read_queue.end_ptr = read_queue.end_ptr->next_in_queue;
+       } else {
+               read_queue.end_ptr = subbuffer;
+       }
+       read_queue.end_ptr->next_in_queue = NULL;
+       ++read_queue.subbuffers_count;
+
+       /* Unlock read sync primitive */
+       sync_unlock(&read_queue.queue_sync);
+}
+
+static int add_to_read_list_with_callback(struct swap_subbuffer *subbuffer,
+                                  bool wakeup)
+{
+       int result = 0;
+
+       add_to_read_list(subbuffer);
+       /* TODO Handle ret value */
+       result = swap_buffer_callback(subbuffer, wakeup);
+
+       return result;
+}
+
+/**
+ * @brief Returns subbuffers to read count.
+ *
+ * @return Count of subbuffers in read_queue.
+ */
+unsigned int get_readable_buf_cnt(void)
+{
+       return read_queue.subbuffers_count;
+}
+
+
+/**
+ * @brief Get first writable subbuffer from write list.
+ *
+ * @param size Minimum amount of free space in subbuffer.
+ * @param[out] ptr_to_write Pointer to the variable where pointer to the
+ * beginning of memory for writing should be stored.
+ * @return Found swap_subbuffer.
+ */
+struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write,
+                                          bool wakeup)
+{
+       struct swap_subbuffer *result = NULL;
+
+       /* Callbacks are called at the end of the function
+        * to prevent deadlocks */
+       struct queue_t callback_queue = {
+               .start_ptr = NULL,
+               .end_ptr = NULL,
+               .queue_sync = {
+                       .flags = 0x0
+               }
+       };
+       struct swap_subbuffer *tmp_buffer = NULL;
+
+       /* Init pointer */
+       *ptr_to_write = NULL;
+
+       /* Lock write list sync primitive */
+       sync_lock(&write_queue.queue_sync);
+
+       while (write_queue.start_ptr) {
+
+               /* We're found subbuffer */
+               if (is_buffer_enough(write_queue.start_ptr, size)) {
+
+                       result = write_queue.start_ptr;
+                       *ptr_to_write =
+                               (void *)((unsigned long)
+                                        (buffer_address(result->data_buffer)) +
+                                        result->full_buffer_part);
+
+                       /* Add data size to full_buffer_part.
+                        * Very important to do it in
+                        * write_queue.queue_sync spinlock */
+                       write_queue.start_ptr->full_buffer_part += size;
+
+                       /* Lock rw sync.
+                        * Should be unlocked in swap_buffer_write() */
+                       sync_lock_no_flags(&result->buffer_sync);
+                       break;
+               /* This subbuffer is not enough => it goes to read list */
+               } else {
+                       result = write_queue.start_ptr;
+
+                       next_queue_element(&write_queue);
+
+                       /* Add to callback list */
+                       if (!callback_queue.start_ptr)
+                               callback_queue.start_ptr = result;
+
+                       if (callback_queue.end_ptr)
+                               callback_queue.end_ptr->next_in_queue = result;
+                       callback_queue.end_ptr = result;
+                       callback_queue.end_ptr->next_in_queue = NULL;
+                       result = NULL;
+               }
+       }
+
+       /* Unlock write list sync primitive */
+       sync_unlock(&write_queue.queue_sync);
+
+       /* Adding buffers to read list and calling callbacks */
+       for (tmp_buffer = NULL; callback_queue.start_ptr; ) {
+               if (callback_queue.start_ptr == callback_queue.end_ptr)
+                       callback_queue.end_ptr = NULL;
+
+               tmp_buffer = callback_queue.start_ptr;
+               callback_queue.start_ptr =
+                       callback_queue.start_ptr->next_in_queue;
+
+               add_to_read_list_with_callback(tmp_buffer, wakeup);
+       }
+
+       return result;
+}
+
+/**
+ * @brief Add subbuffer to write list.
+ *
+ * @param subbuffer Pointer to the swap_subbuffer that should be stored.
+ * @return Void.
+ */
+void add_to_write_list(struct swap_subbuffer *subbuffer)
+{
+       sync_lock(&write_queue.queue_sync);
+
+       /* Reinitialize */
+       subbuffer->full_buffer_part = 0;
+
+       if (!write_queue.start_ptr)
+               write_queue.start_ptr = subbuffer;
+
+       if (write_queue.end_ptr) {
+               write_queue.end_ptr->next_in_queue = subbuffer;
+               write_queue.end_ptr = write_queue.end_ptr->next_in_queue;
+       } else {
+               write_queue.end_ptr = subbuffer;
+       }
+       write_queue.end_ptr->next_in_queue = NULL;
+       ++write_queue.subbuffers_count;
+
+       sync_unlock(&write_queue.queue_sync);
+}
+
+/**
+ * @brief Returns subbuffers to write count.
+ *
+ * @return Count of subbuffers in write queue.
+ */
+unsigned int get_writable_buf_cnt(void)
+{
+       return write_queue.subbuffers_count;
+}
+
+
+/**
+ * @brief Add subbuffer to busy list when it is read from out of the buffer.
+ *
+ * @param subbuffer Pointer to the swap_subbuffer that should be added.
+ * @return Void.
+ */
+void add_to_busy_list(struct swap_subbuffer *subbuffer)
+{
+       /* Lock busy sync primitive */
+       sync_lock(&buffer_busy_sync);
+
+       subbuffer->next_in_queue = NULL;
+       queue_busy[queue_busy_last_element] = subbuffer;
+       queue_busy_last_element += 1;
+
+       /* Unlock busy sync primitive */
+       sync_unlock(&buffer_busy_sync);
+}
+
+/**
+ * @brief Remove subbuffer from busy list when it is released.
+ *
+ * @param subbuffer Pointer to the swap_subbuffer that should be removed.
+ * @return 0 on success, negative error code otherwise.
+ */
+int remove_from_busy_list(struct swap_subbuffer *subbuffer)
+{
+       int result = -E_SB_NO_SUBBUFFER_IN_BUSY;  /* For sanitization */
+       int i;
+
+       /* Lock busy list sync primitive */
+       sync_lock(&buffer_busy_sync);
+
+       /* Sanitization and removing */
+       for (i = 0; i < queue_busy_last_element; i++) {
+               if (queue_busy[i] == subbuffer) {
+                       /* Last element goes here and length is down 1 */
+                       queue_busy[i] = queue_busy[queue_busy_last_element - 1];
+                       queue_busy_last_element -= 1;
+                       result = E_SB_SUCCESS;
+                       break;
+               }
+       }
+
+       /* Unlock busy list sync primitive */
+       sync_unlock(&buffer_busy_sync);
+
+       return result;
+}
+
+/**
+ * @brief Set all subbuffers in write list to read list.
+ *
+ * @return Void.
+ */
+void buffer_queue_flush(void)
+{
+       struct swap_subbuffer *buffer = write_queue.start_ptr;
+
+       /* Locking write sync primitive */
+       sync_lock(&write_queue.queue_sync);
+
+       while (write_queue.start_ptr &&
+              write_queue.start_ptr->full_buffer_part) {
+
+               /* Lock buffer sync primitive to prevent writing to buffer if it
+                * had been selected for writing, but still wasn't wrote. */
+               sync_lock(&buffer->buffer_sync);
+
+               buffer = write_queue.start_ptr;
+               next_queue_element(&write_queue);
+               add_to_read_list(buffer);
+
+               /* Unlock buffer sync primitive */
+               sync_unlock(&buffer->buffer_sync);
+       }
+
+       /* Unlock write primitive */
+       sync_unlock(&write_queue.queue_sync);
+}
+
+/**
+ * @brief Get subbuffers count in busy list.
+ *
+ * @return Count of swap_subbuffers in busy  list.
+ */
+int get_busy_buffers_count(void)
+{
+       int result;
+
+       sync_lock(&buffer_busy_sync);
+       result = queue_busy_last_element;
+       sync_unlock(&buffer_busy_sync);
+
+       return result;
+}
+
+/**
+ * @brief Get memory pages count in subbuffer.
+ *
+ * @return Pages count in subbuffer.
+ */
+int get_pages_count_in_subbuffer(void)
+{
+/* Return 1 if pages order 0,
+ * or 2 of power pages_order_in_subbuffer otherwise */
+       return (pages_order_in_subbuffer) ?
+               2 << (pages_order_in_subbuffer - 1) : 1;
+}
diff --git a/modules/buffer/buffer_queue.h b/modules/buffer/buffer_queue.h
new file mode 100644 (file)
index 0000000..9b3291e
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * @file buffer/buffer_queue.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Represents buffers queues interface
+ */
+
+/* SWAP Buffer queues interface */
+
+#ifndef __BUFFER_QUEUE_H__
+#define __BUFFER_QUEUE_H__
+
+#include <linux/types.h>
+#include "buffer_description.h"
+
+int buffer_queue_allocation(size_t subbuffer_size,
+                           unsigned int subbuffers_count);
+void buffer_queue_free(void);
+int buffer_queue_reset(void);
+void buffer_queue_flush(void);
+struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write,
+                                          bool wakeup);
+struct swap_subbuffer *get_from_read_list(void);
+void add_to_write_list(struct swap_subbuffer *subbuffer);
+void add_to_read_list(struct swap_subbuffer *subbuffer);
+void add_to_busy_list(struct swap_subbuffer *subbuffer);
+int remove_from_busy_list(struct swap_subbuffer *subbuffer);
+
+unsigned int get_readable_buf_cnt(void);
+unsigned int get_writable_buf_cnt(void);
+int get_busy_buffers_count(void);
+int get_pages_count_in_subbuffer(void);
+
+#endif /* __BUFFER_QUEUE_H__ */
diff --git a/modules/buffer/data_types.h b/modules/buffer/data_types.h
new file mode 100644 (file)
index 0000000..47ef1d8
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file buffer/data_types.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Declares data types for SWAP buffer.
+ */
+
+#ifndef __DATA_TYPES_H__
+#define __DATA_TYPES_H__
+
+
+#include <linux/spinlock.h>
+
+
+struct page;
+
+/**
+ * @struct sync_t
+ * @brief Using spinlocks as sync primitives.
+ * @var sync_t::spinlock
+ * Spinlock.
+ * @var sync_t::flags
+ * Flags for spinlock.
+ */
+struct sync_t {
+       spinlock_t spinlock;
+       unsigned long flags;
+};
+
+/**
+ * @brief swap_subbuffer_ptr points to the first memory page of the subbuffer.
+ */
+typedef struct page *swap_subbuffer_ptr;
+
+#endif /* __DATA_TYPES_H__ */
diff --git a/modules/buffer/kernel_operations.h b/modules/buffer/kernel_operations.h
new file mode 100644 (file)
index 0000000..62aefb2
--- /dev/null
@@ -0,0 +1,212 @@
+/**
+ * @file buffer/kernel_operations.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Kernel functions wrap.
+ */
+
+#ifndef __KERNEL_OPERATIONS_H__
+#define __KERNEL_OPERATIONS_H__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
+#include "data_types.h"
+
+
+/* MESSAGES */
+/** Prints debug message.*/
+#define print_debug(msg, args...) \
+       printk(KERN_DEBUG "SWAP_BUFFER DEBUG : " msg, ##args)
+/** Prints info message.*/
+#define print_msg(msg, args...)   \
+       printk(KERN_INFO "SWAP_BUFFER : " msg, ##args)
+/** Prints warning message.*/
+#define print_warn(msg, args...)  \
+       printk(KERN_WARNING "SWAP_BUFFER WARNING : " msg, ##args)
+/** Prints error message.*/
+#define print_err(msg, args...)   \
+       printk(KERN_ERR "SWAP_BUFFER ERROR : " msg, ##args)
+/** Prints critical error message.*/
+#define print_crit(msg, args...)  \
+       printk(KERN_CRIT "SWAP_BUFFER CRITICAL : " msg, ##args)
+
+
+/**
+ * @brief struct sync_t initialization.
+ *
+ * @param buffer_sync Target sync primitive.
+ * @return Void.
+ */
+static inline void sync_init(struct sync_t *buffer_sync)
+{
+       spin_lock_init(&buffer_sync->spinlock);
+}
+
+/**
+ * @brief Lock sync_t with saving flags.
+ *
+ * @param buffer_sync Target sync primitive.
+ * @return Void.
+ */
+static inline void sync_lock(struct sync_t *buffer_sync)
+{
+       spin_lock_irqsave(&buffer_sync->spinlock, buffer_sync->flags);
+}
+
+/**
+ * @brief Unlock sync_t with restoring flags.
+ *
+ * @param buffer_sync Target sync primitive.
+ * @return Void.
+ */
+static inline void sync_unlock(struct sync_t *buffer_sync)
+{
+       spin_unlock_irqrestore(&buffer_sync->spinlock, buffer_sync->flags);
+}
+
+/**
+ * @brief Lock sync_t without saving flags.
+ *
+ * @param buffer_sync Target sync primitive.
+ * @return Void.
+ */
+static inline void sync_lock_no_flags(struct sync_t *buffer_sync)
+{
+       spin_lock(&buffer_sync->spinlock);
+}
+
+/**
+ * @brief Unlock sync_t without restoring flags.
+ *
+ * @param buffer_sync Target sync primitive.
+ * @return Void.
+ */
+static inline void sync_unlock_no_flags(struct sync_t *buffer_sync)
+{
+       spin_unlock(&buffer_sync->spinlock);
+}
+
+/**
+ * @brief Disable preemption and irqs.
+ *
+ * @param flags Variable to save flags to.
+ * @return Void.
+ */
+static inline void swap_irq_disable(unsigned long *flags)
+{
+       preempt_disable();
+       local_irq_save(*flags);
+}
+
+/**
+ * @brief Enable preemption and irqs.
+ *
+ * @param flags Variable to restore flags from.
+ * @return Void.
+ */
+static inline void swap_irq_enable(unsigned long *flags)
+{
+       local_irq_restore(*flags);
+       preempt_enable();
+}
+
+/* SWAP SUBBUFER */
+
+
+/* We alloc memory for swap_subbuffer structures with common kmalloc */
+/** Allocates memory for subbuffer structures.*/
+#define memory_allocation(memory_size)  kmalloc(memory_size, GFP_KERNEL)
+/** Free subbuffer structures memory.*/
+#define memory_free(ptr)                kfree(ptr)
+
+/** For subbuffers themselves, we allocate memory with alloc_pages, so, we have
+ * to evaluate required pages order */
+#define buffer_allocation(memory_size)                        \
+       alloc_pages(GFP_KERNEL, (pages_order_in_subbuffer >= 0) ? \
+               pages_order_in_subbuffer :                            \
+               get_order_for_alloc_pages(memory_size))
+
+/** Free buffer's memory.*/
+#define buffer_free(ptr, subbuf_size)                         \
+       __free_pages(ptr, (pages_order_in_subbuffer >= 0) ?       \
+                pages_order_in_subbuffer :                           \
+                get_order_for_alloc_pages(subbuf_size))
+
+/** Returns buffer address.*/
+#define buffer_address(buffer_ptr)  page_address(buffer_ptr)
+/** Sets page order in subbuffer.*/
+#define set_pages_order_in_subbuffer(memory_size) \
+       pages_order_in_subbuffer = get_order_for_alloc_pages(memory_size)
+
+/**
+ * @brief Functions for pages allocation.
+ *
+ * @param number Target number.
+ * @return Power of two.
+ */
+static inline unsigned int nearest_power_of_two(unsigned int number)
+{
+       unsigned int result = 0;
+       unsigned int two_to_the_power = 1;
+
+       /* If aligned_size == PAGE_SIZE we need only one page, so return 0 */
+       if (number == 1)
+               return result;
+
+       while (two_to_the_power < number) {
+               two_to_the_power <<= 1;
+               result++;
+       }
+
+       return result;
+}
+
+/**
+ * @brief Order for alloc pages.
+ *
+ * @param memory_size Wishful memory size.
+ * @return Pages order.
+ */
+static inline unsigned int get_order_for_alloc_pages(size_t memory_size)
+{
+       /* First evaluate remainder of the division memory_size by PAGE_SIZE.
+        * If memory_size is divisible by PAGE_SIZE, then remainder equals 0. */
+       size_t remainder = (memory_size % PAGE_SIZE) ?
+                      (memory_size % PAGE_SIZE) : PAGE_SIZE;
+
+       /* Align memory_size to the PAGE_SIZE. aligned_size >= memory_size */
+       size_t aligned_size = memory_size + (PAGE_SIZE - remainder);
+
+       return nearest_power_of_two(aligned_size / PAGE_SIZE);
+}
+
+#endif /* __KERNEL_OPERATIONS_H__ */
diff --git a/modules/buffer/swap_buffer_errors.h b/modules/buffer/swap_buffer_errors.h
new file mode 100644 (file)
index 0000000..f153214
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * @file buffer/swap_buffer_errors.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * SWAP Buffer error codes enumeration.
+ */
+
+#ifndef __SWAP_BUFFER_ERRORS_H__
+#define __SWAP_BUFFER_ERRORS_H__
+
+/**
+ * @enum _swap_buffer_errors
+ * @brief SWAP buffer errors enumeration.
+ */
+enum _swap_buffer_errors {
+       /**
+        * @brief Success.
+        */
+       E_SB_SUCCESS = 0,
+       /**
+        * @brief There are some unreleased buffers.
+        * Mainly returned by swap_buffer_uninit.
+        */
+       E_SB_UNRELEASED_BUFFERS = 1,
+       /**
+        * @brief No buffers for writing.
+        */
+       E_SB_NO_WRITABLE_BUFFERS = 2,
+       /**
+        * @brief Wrong data size: size == 0 or size > subbuffer size.
+        */
+       E_SB_WRONG_DATA_SIZE = 3,
+       /**
+        * @brief Trying to write data after SWAP buffer has been stopped.
+        */
+       E_SB_IS_STOPPED = 4,
+       /**
+        * @brief Memory areas of data to be written and subbuffer itself
+        * are overlap.
+        */
+       E_SB_OVERLAP = 5,
+       /**
+        * @brief No buffers for reading.
+        */
+       E_SB_NO_READABLE_BUFFERS = 6,
+       /**
+        * @brief Callback function ptr == NULL.
+        */
+       E_SB_NO_CALLBACK = 7,
+       /**
+        * @brief Memory for queue_busy wasn't allocated.
+        */
+       E_SB_NO_MEM_QUEUE_BUSY = 8,
+       /**
+        * @brief Memory for one of struct swap_buffer wasn't allocated.
+        */
+       E_SB_NO_MEM_BUFFER_STRUCT = 9,
+       /**
+        * @brief Memort for data buffer itself wasn't allocated.
+        */
+       E_SB_NO_MEM_DATA_BUFFER = 10,
+       /**
+        * @brief No such subbuffer in busy_list.
+        */
+       E_SB_NO_SUBBUFFER_IN_BUSY = 11,
+       /**
+        * @brief Subbuffers aren't allocated.
+        */
+       E_SB_NOT_ALLOC = 12,
+       /**
+        * @brief Thresholds > 100, top < lower.
+        */
+       E_SB_WRONG_THRESHOLD = 13
+};
+
+#endif /* __SWAP_BUFFER_ERRORS_H__ */
diff --git a/modules/buffer/swap_buffer_module.c b/modules/buffer/swap_buffer_module.c
new file mode 100644 (file)
index 0000000..551f940
--- /dev/null
@@ -0,0 +1,364 @@
+/**
+ * buffer/swap_buffer_module.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * SWAP Buffer interface implementation.
+ */
+
+#include "swap_buffer_module.h"
+#include "buffer_queue.h"
+#include "buffer_description.h"
+#include "swap_buffer_errors.h"
+#include "kernel_operations.h"
+
+/**
+ * @enum _swap_buffer_status_mask
+ * @brief Bitwise mask for buffer status.
+ */
+enum _swap_buffer_status_mask {
+       BUFFER_FREE = 0,                /**< 000 - memory free. */
+       BUFFER_ALLOC = 1,               /**< 001 - memory allocated. */
+       BUFFER_PAUSE = 2,               /**< 010 - buffer overflow. */
+       BUFFER_WORK = 4                 /**< @brief 100 - buffer work. */
+};
+
+static unsigned char swap_buffer_status = BUFFER_FREE;
+
+/**
+ * @brief Subbuffer callback type.
+ */
+typedef int(*subbuffer_callback_type)(bool wakeup);
+
+/* Callback that is called when full subbuffer appears */
+static subbuffer_callback_type subbuffer_callback;
+
+/* One subbuffer size */
+static size_t subbuffers_size;
+
+/* Subbuffers count */
+static unsigned int subbuffers_num;
+
+static unsigned int enough_writable_bufs;
+static unsigned int min_writable_bufs;
+static int (*low_mem_cb)(void);
+static int (*enough_mem_cb)(void);
+
+
+static inline int areas_overlap(const void *area1,
+                               const void *area2,
+                               size_t size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               if ((area1 + i == area2) || (area2 + i == area1))
+                       return 1;
+
+       return 0;
+}
+
+static inline unsigned int percent_to_count(unsigned char percent,
+                                            unsigned int cnt)
+{
+       return (percent * cnt) / 100;
+}
+
+/**
+ * @brief Initializes SWAP buffer and allocates memory.
+ *
+ * @param buf_init Pointer to the buffer_init_t structure which contains
+ * information about subbuffers count, subbuffers size and subbuffer-full-
+ * callback.
+ * @return 0 on success, negative error code otherwise.
+ */
+int swap_buffer_init(struct buffer_init_t *buf_init)
+{
+       int result = -1;
+
+       swap_buffer_status &= ~BUFFER_WORK;
+       print_debug("status buffer stop = %d\n", swap_buffer_status);
+
+       if ((buf_init->top_threshold > 100) ||
+           (buf_init->lower_threshold > 100) ||
+           (buf_init->top_threshold < buf_init->lower_threshold))
+               return -E_SB_WRONG_THRESHOLD;
+
+       min_writable_bufs = percent_to_count(buf_init->lower_threshold,
+                                            buf_init->nr_subbuffers);
+
+       enough_writable_bufs = percent_to_count(buf_init->top_threshold,
+                                               buf_init->nr_subbuffers);
+
+       low_mem_cb = buf_init->low_mem_cb;
+       enough_mem_cb = buf_init->enough_mem_cb;
+
+       if ((swap_buffer_status & BUFFER_ALLOC) &&
+               (subbuffers_size == buf_init->subbuffer_size) &&
+               (subbuffers_num == buf_init->nr_subbuffers) &&
+               ((subbuffer_callback_type)subbuffer_callback ==
+                                 buf_init->subbuffer_full_cb)) {
+               result = buffer_queue_reset();
+               goto swap_buffer_init_work;
+       }
+
+       subbuffer_callback = buf_init->subbuffer_full_cb;
+       subbuffers_size = buf_init->subbuffer_size;
+       subbuffers_num = buf_init->nr_subbuffers;
+
+       result = buffer_queue_allocation(subbuffers_size, subbuffers_num);
+       if (result < 0)
+               return result;
+
+       result = get_pages_count_in_subbuffer();
+
+       swap_buffer_status |= BUFFER_ALLOC;
+       print_debug("status buffer alloc = %d\n", swap_buffer_status);
+
+swap_buffer_init_work:
+       swap_buffer_status |= BUFFER_WORK;
+       print_debug("status buffer work = %d\n", swap_buffer_status);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(swap_buffer_init);
+
+/**
+ * @brief Uninitializes SWAP buffer, releases allocated memory.
+ *
+ * @return 0 on success, negative error code otherwise.
+ */
+int swap_buffer_uninit(void)
+{
+       /* Check whether buffer is allocated */
+       if (!(swap_buffer_status & BUFFER_ALLOC))
+               return -E_SB_NOT_ALLOC;
+
+       /* Stop buffer */
+       swap_buffer_status &= ~BUFFER_WORK;
+       print_debug("status buffer stop = %d\n", swap_buffer_status);
+
+       /* Check whether all buffers are released */
+       if (get_busy_buffers_count())
+               return -E_SB_UNRELEASED_BUFFERS;
+
+       /* Free */
+       buffer_queue_free();
+
+       subbuffer_callback = NULL;
+       subbuffers_size = 0;
+       subbuffers_num = 0;
+       min_writable_bufs = 0;
+       enough_writable_bufs = 0;
+       low_mem_cb = NULL;
+       enough_mem_cb = NULL;
+
+       swap_buffer_status &= ~BUFFER_ALLOC;
+       print_debug("status buffer dealloc = %d\n", swap_buffer_status);
+
+       return E_SB_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(swap_buffer_uninit);
+
+/**
+ * @brief Writes data to SWAP buffer.
+ *
+ * @param data Pointer to a data for writing.
+ * @param size Size of a data for writing.
+ * @return Size of written data on success, negative error code otherwise.
+ */
+ssize_t swap_buffer_write(void *data, size_t size, bool wakeup)
+{
+       int result = E_SB_SUCCESS;
+       struct swap_subbuffer *buffer_to_write = NULL;
+       void *ptr_to_write = NULL;
+       unsigned long flags = 0;
+
+       /* Size sanitization */
+       if ((size > subbuffers_size) || (size == 0))
+               return -E_SB_WRONG_DATA_SIZE;
+
+       /* Check buffer status */
+       if (!(swap_buffer_status & BUFFER_WORK))
+               return -E_SB_IS_STOPPED;
+
+       /* We're going to look for writable buffer, so disable irqs */
+       swap_irq_disable(&flags);
+
+       /* Get next write buffer and occupying semaphore */
+       buffer_to_write = get_from_write_list(size, &ptr_to_write, wakeup);
+       if (!buffer_to_write) {
+               swap_irq_enable(&flags);
+               return -E_SB_NO_WRITABLE_BUFFERS;
+       }
+
+       /* Check for overlapping */
+       if (areas_overlap(ptr_to_write, data, size)) {
+               result = -E_SB_OVERLAP;
+               goto buf_write_sem_post;
+       }
+
+       /* Copy data to buffer */
+       /* XXX Think of using memmove instead - useless, anyway overlapping
+        * means that something went wrong. */
+       memcpy(ptr_to_write, data, size);
+
+       result = size;
+
+       if ((get_writable_buf_cnt() < min_writable_bufs) &&
+           !(swap_buffer_status & BUFFER_PAUSE)) {
+               swap_buffer_status |= BUFFER_PAUSE;
+               if (low_mem_cb != NULL)
+                       low_mem_cb();
+       }
+
+       /* Unlock sync (Locked in get_from_write_list()) and enable irqs */
+buf_write_sem_post:
+       sync_unlock_no_flags(&buffer_to_write->buffer_sync);
+       swap_irq_enable(&flags);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(swap_buffer_write);
+
+/**
+ * @brief Gets pointer to subbuffer for reading.
+ *
+ * @param[out] subbuffer Pointer to a variable which points on target subbuffer.
+ * @return 0 on success, negative error code otherwise.
+ */
+int swap_buffer_get(struct swap_subbuffer **subbuffer)
+{
+       int result = 0;
+       struct swap_subbuffer *buffer_to_read = NULL;
+
+       /* Check buffer status */
+       if (!(swap_buffer_status & BUFFER_WORK))
+               return -E_SB_IS_STOPPED;
+
+       /* Get next read buffer */
+       buffer_to_read = get_from_read_list();
+       if (!buffer_to_read)
+               return -E_SB_NO_READABLE_BUFFERS;
+
+       /* Add to busy list */
+       buffer_to_read->next_in_queue = NULL;
+       add_to_busy_list(buffer_to_read);
+
+       *subbuffer = buffer_to_read;
+
+       result = get_pages_count_in_subbuffer();
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(swap_buffer_get);
+
+/**
+ * @brief Releases subbuffer after reading.
+ *
+ * @param subbuffer Subbuffer that should be released.
+ * @return 0 on success, negative error code otherwise.
+ */
+int swap_buffer_release(struct swap_subbuffer **subbuffer)
+{
+       int result;
+
+       /* Remove from busy list (includes sanitization) */
+       result = remove_from_busy_list(*subbuffer);
+       if (result < 0)
+               return result;
+
+       /* Add to write list */
+       add_to_write_list(*subbuffer);
+
+       if ((swap_buffer_status & BUFFER_PAUSE) &&
+           (get_writable_buf_cnt() >= enough_writable_bufs)) {
+               swap_buffer_status &= ~BUFFER_PAUSE;
+               if (enough_mem_cb != NULL)
+                       enough_mem_cb();
+       }
+
+       return E_SB_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(swap_buffer_release);
+
+/**
+ * @brief Sets all subbuffers for reading.
+ *
+ * @return Count of subbeffers for reading.
+ */
+unsigned int swap_buffer_flush(void)
+{
+       unsigned int result;
+
+       /* Set all non-empty write buffers to read list */
+       buffer_queue_flush();
+
+       /* Get count of all full buffers */
+       result = get_readable_buf_cnt();
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(swap_buffer_flush);
+
+/**
+ * @brief Executes subbuffer-full-callback.
+ *
+ * @param buffer Pointer to the full subbuffer.
+ * @return -E_SB_NO_CALLBACK if no callback is registered or callbacks ret
+ * value otherwise.
+ */
+int swap_buffer_callback(void *buffer, bool wakeup)
+{
+       int result;
+
+       if (!subbuffer_callback)
+               return -E_SB_NO_CALLBACK;
+
+       result = subbuffer_callback(wakeup);
+       if (result < 0)
+               print_err("Callback error! Error code: %d\n", result);
+
+       return result;
+}
+
+static int __init swap_buffer_module_init(void)
+{
+       printk(KERN_NOTICE "SWAP_BUFFER : Buffer module initialized\n");
+       return E_SB_SUCCESS;
+}
+
+static void __exit swap_buffer_module_exit(void)
+{
+       if (swap_buffer_status & BUFFER_ALLOC)
+               swap_buffer_uninit();
+       printk(KERN_NOTICE "SWAP_BUFFER : Buffer module unintialized\n");
+}
+
+module_init(swap_buffer_module_init);
+module_exit(swap_buffer_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP buffer module");
+MODULE_AUTHOR("Aksenov A.S.");
diff --git a/modules/buffer/swap_buffer_module.h b/modules/buffer/swap_buffer_module.h
new file mode 100644 (file)
index 0000000..95b31fa
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * @file buffer/swap_buffer_module.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * SWAP Buffer interface declaration.
+ */
+
+#ifndef __SWAP_BUFFER_MODULE_H__
+#define __SWAP_BUFFER_MODULE_H__
+
+#include <linux/types.h>
+
+struct swap_subbuffer;
+
+/**
+ * @struct buffer_init_t
+ * @brief Buffer init structure. Contains information necessary for SWAP buffer
+ * initialization.
+ * @var buffer_init_t::subbuffer_size
+ * Subbuffer size.
+ * @var buffer_init_t::nr_subbuffers
+ * Subbuffers count.
+ * @var buffer_init_t::subbuffer_full_cb
+ * Callback. Called when one of subbuffers is full.
+ * @var buffer_init_t::lower_threshold
+ * Lower threshold in percent. When buffers fall below this limit
+ * low_mem_cb is called and swap_buffer is suspended.
+ * @var buffer_init_t::low_mem_cb
+ * Callback that is called when count of free subbuffers falls below
+ * lower_threshold.
+ * @var buffer_init_t::top_threshold
+ * Top threshold in percent. When buffers exceed this limit
+ * enough_mem_cb is called.
+ * @var buffer_init_t::enough_mem_cb
+ * Callback that is called when count of free subbuffers exceeds top_threshold.
+ */
+
+struct buffer_init_t {
+       size_t subbuffer_size;
+       unsigned int nr_subbuffers;
+       int (*subbuffer_full_cb)(bool wakeup);
+
+       unsigned char lower_threshold;
+       int (*low_mem_cb)(void);
+
+       unsigned char top_threshold;
+       int (*enough_mem_cb)(void);
+};
+
+/* SWAP Buffer initialization function. Call it before using buffer.
+ * Returns memory pages count (>0) in one subbuffer on success, or error code
+ * (<0) otherwise. */
+int swap_buffer_init(struct buffer_init_t *buf_init);
+
+/* SWAP Buffer uninitialization function. Call it every time before removing
+ * this module.
+ * Returns E_SB_SUCCESS (0) on success, otherwise error code. */
+int swap_buffer_uninit(void);
+
+/* SWAP Buffer write function. Pass it size of the data and pointer to the data.
+ * On success returns number of bytes written (>=0) or error code (<0)
+ * otherwise */
+ssize_t swap_buffer_write(void *data, size_t size, bool wakeup);
+
+/* SWAP Buffer get. Put subbuffer pointer to the variable *subbuffer.
+ * Return pages count in subbuffer. */
+int swap_buffer_get(struct swap_subbuffer **subbuffer);
+
+/* SWAP Buffer release. All 'get' buffers must be released with this function.
+ * Just pass &subbuffer_ptr to it */
+int swap_buffer_release(struct swap_subbuffer **subbuffer);
+
+/* SWAP Buffer flush. Puts all buffers to read queue and returns their count. */
+unsigned int swap_buffer_flush(void);
+
+#endif /* __SWAP_BUFFER_MODULE_H__ */
diff --git a/modules/buffer/swap_buffer_to_buffer_queue.h b/modules/buffer/swap_buffer_to_buffer_queue.h
new file mode 100644 (file)
index 0000000..076549d
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * @file buffer/swap_buffer_to_buffer_queue.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ * SWAP Buffer interface for buffer queue.
+ */
+
+#ifndef __SWAP_BUFFER_TO_BUFFER_QUEUE_H__
+#define __SWAP_BUFFER_TO_BUFFER_QUEUE_H__
+
+#include <linux/types.h>
+
+int swap_buffer_callback(void *buffer, bool wakeup);
+
+#endif /* __SWAP_BUFFER_TO_BUFFER_QUEUE_H__ */
diff --git a/modules/build.config.example b/modules/build.config.example
new file mode 100644 (file)
index 0000000..557b452
--- /dev/null
@@ -0,0 +1,5 @@
+# Config for build.sh
+
+kernel=<path-to-kernel-sourse>
+toolchain=<path-to-toolchain>
+arch=<architecture>
diff --git a/modules/build.sh b/modules/build.sh
new file mode 100755 (executable)
index 0000000..5b1e3a5
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+# NOTE: This requires GNU getopt.  On Mac OS X and FreeBSD, you have to install
+# this separately; see below.
+
+IDENT=${0}
+
+show_usage_and_exit () {
+       echo -e "Usage: ${IDENT} <options> <compile|check|clean>"
+       echo -e "\tOptions:"
+       echo -e "\t--verbose"
+       echo -e "\t--file <config file>"
+#      echo -e "\t--debug"
+       echo -e "\t--kernel <kernel path>"
+       echo -e "\t--arch <arm|arm64|i386>"
+       echo -e "\t[--toolchain <cross compile path>]"
+       exit 1
+}
+
+TEMP=`getopt -o vk:t:a:f: --long verbose,kernel:,toolchain:,arch:,file: \
+       -n '${IDENT}' -- "$@"`
+
+if [ $? != 0 ] ; then
+       show_usage_and_exit
+fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+MDIR=`pwd`
+VERBOSE=false
+CONFIG_FILE="build.config"
+KERNELDIR=""
+TOOLCHAIN=""
+ARCH=""
+
+while true; do
+       case "$1" in
+               -v | --verbose ) VERBOSE=true; shift ;;
+               -k | --kernel ) KERNELDIR="$2"; shift 2 ;;
+               -t | --toolchain ) TOOLCHAIN="$2"; shift 2;;
+               -a | --arch ) ARCH="$2"; shift 2;;
+               -f | --file ) CONFIG_FILE="$2"; shift 2;;
+               -- ) shift; break ;;
+               * ) break ;;
+       esac
+done
+
+if  [ "${1}" != "compile" -a "${1}" != "clean" -a "${1}" != "check"  ] ; then
+       ACTION="compile"
+        ARCH=${2}
+       KERNELDIR=${1}
+       if [ "${3}" != "" ] ; then
+               TOOLCHAIN=${3}
+       fi
+else
+       if [ -r ${CONFIG_FILE} ]; then
+               . ${CONFIG_FILE}
+               KERNELDIR=${kernel}
+               TOOLCHAIN=${toolchain}
+               ARCH=$arch
+       fi
+       ACTION="${1}"
+fi
+
+if [ "${KERNELDIR}" = "" ] ; then
+       show_usage_and_exit
+fi
+
+if [ "${ARCH}" = "arm" ] ; then
+       LINKNAME="arm"
+elif [ "${ARCH}" = "arm64" ] ; then
+       LINKNAME="arm64"
+elif [ "${ARCH}" = "i386" ] ; then
+       LINKNAME="x86"
+else
+       show_usage_and_exit
+fi
+
+MCFLAGS="-Werror"
+
+CMDLINE_ARGS=""
+CMDLINE_ARGS="CROSS_COMPILE=${TOOLCHAIN} ARCH=${ARCH} -C ${KERNELDIR}"
+CMDLINE_ARGS="${CMDLINE_ARGS} M=${MDIR} MCFLAGS=${MCFLAGS} LINKNAME=${LINKNAME}"
+
+if [ "${ACTION}" = "check" ] ; then
+       CMDLINE="make C=2 CF=\"-Wsparse-all\" ${CMDLINE_ARGS} modules"
+elif [ "${ACTION}" = "clean" ] ; then
+       CMDLINE="make ${CMDLINE_ARGS} clean"
+else
+       CMDLINE="make ${CMDLINE_ARGS} modules"
+fi
+
+if [ ${VERBOSE} = "true" ] ; then
+       CMDLINE="${CMDLINE} V=1"
+fi
+
+#echo -n "CMDLINE ${CMDLINE}\n"
+
+${CMDLINE} || exit 1
+
+# On arm64 gbs compiler fails on stripping arm64. This workaround is made to 
+# make it buildable until the bug is fixed.
+if [ "${ARCH}" = "arm64" ] ; then
+       for i in */*.ko; do
+               echo "Stripping $i..."
+               strip -x -g $i
+       done
+fi
+
+exit 0
+
diff --git a/modules/deploy.sh b/modules/deploy.sh
new file mode 100755 (executable)
index 0000000..5309f27
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+model=$(sed -n  "s|.*tizen.org/system/model_name[^>]*>\([^<]*\)<.*|\1|p" /etc/config/model-config.xml)
+modpath=/opt/swap/sdk
+
+case $model in
+# armv7l
+       "TM1")
+               mv $modpath/tm1_swap_modules/* $modpath
+               rm -r $modpath/tm1_swap_modules
+               rm -rf $modpath/odroid_swap_modules
+               rm -rf $modpath/tw1_swap_modules
+               ;;
+       "xu3")
+               mv $modpath/odroid_swap_modules/* $modpath
+               rm -r $modpath/odroid_swap_modules
+               rm -rf $modpath/tm1_swap_modules
+               rm -rf $modpath/tw1_swap_modules
+               ;;
+       "TW1")
+               mv $modpath/tw1_swap_modules/* $modpath
+               rm -r $modpath/tw1_swap_modules
+               rm -rf $modpath/odroid_swap_modules
+               rm -rf $modpath/tm1_swap_modules
+               ;;
+# x86
+       "Emulator")
+               mv $modpath/emul_swap_modules/* $modpath
+               rm -r $modpath/emul_swap_modules
+               ;;
+# aarch64
+       "TM2")
+               mv $modpath/tm2_swap_modules/* $modpath
+               rm -r $modpath/tm2_swap_modules
+               rm -rf $modpath/rpi3_swap_modules
+               rm -rf $modpath/tw2_swap_modules
+               ;;
+       "TW2")
+               mv $modpath/tw2_swap_modules/* $modpath
+               rm -r $modpath/tw2_swap_modules
+               rm -rf $modpath/rpi3_swap_modules
+               rm -rf $modpath/tm2_swap_modules
+               ;;
+       "rpi3")
+               mv $modpath/rpi3_swap_modules/* $modpath
+               rm -r $modpath/rpi3_swap_modules
+               rm -rf $modpath/tw2_swap_modules
+               rm -rf $modpath/tm2_swap_modules
+               ;;
+       *)
+               echo "Device isn't supported" > /tmp/swap-modules_install.log
+               ;;
+esac
diff --git a/modules/driver/Kbuild b/modules/driver/Kbuild
new file mode 100644 (file)
index 0000000..51f30cc
--- /dev/null
@@ -0,0 +1,12 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../buffer/Module.symvers
+
+obj-m := swap_driver.o
+swap_driver-y := swap_driver_module.o \
+                     device_driver.o \
+                     driver_to_buffer.o \
+                     driver_debugfs.o
+
+ifeq ($(CONFIG_CONNECTOR),y)
+       swap_driver-y += us_interaction.o
+endif
diff --git a/modules/driver/app_manage.h b/modules/driver/app_manage.h
new file mode 100644 (file)
index 0000000..6c31de6
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file driver/app_manage.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * Driver user <-> kernel connect implement.
+ */
+
+#ifndef __APP_MANAGE_H__
+#define __APP_MANAGE_H__
+
+#include "us_interaction.h"
+#include "us_interaction_msg.h"
+
+/**
+ * @brief Sends pause message to kernel.
+ *
+ * @return us_interaction_send_msg result.
+ */
+static inline int app_manage_pause_apps(void)
+{
+       enum us_interaction_k2u_msg_t us_int_msg = US_INT_PAUSE_APPS;
+
+       return us_interaction_send_msg(&us_int_msg, sizeof(us_int_msg));
+}
+
+/**
+ * @brief Sends continue message to kernel.
+ *
+ * @return us_interaction_send_msg result.
+ */
+static inline int app_manage_cont_apps(void)
+{
+       enum us_interaction_k2u_msg_t us_int_msg = US_INT_CONT_APPS;
+
+       return us_interaction_send_msg(&us_int_msg, sizeof(us_int_msg));
+}
+
+#endif /* __APP_MANAGE_H__ */
diff --git a/modules/driver/device_driver.c b/modules/driver/device_driver.c
new file mode 100644 (file)
index 0000000..e473cb8
--- /dev/null
@@ -0,0 +1,564 @@
+/**
+ * driver/device_driver.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Provides SWAP device.
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/splice.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#include <ksyms/ksyms.h>
+#include <master/swap_initializer.h>
+
+#include "device_driver.h"
+#include "swap_driver_errors.h"
+#include "driver_to_buffer.h"
+#include "swap_ioctl.h"
+#include "driver_defs.h"
+#include "device_driver_to_driver_to_buffer.h"
+#include "driver_to_buffer.h"
+#include "driver_to_msg.h"
+
+/** SWAP device name as it is in /dev/. */
+#define SWAP_DEVICE_NAME "swap_device"
+
+/* swap_device driver routines */
+static ssize_t swap_device_read(struct file *filp, char __user *buf,
+                               size_t count, loff_t *f_pos);
+static long swap_device_ioctl(struct file *filp, unsigned int cmd,
+                             unsigned long arg);
+static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
+                                      struct pipe_inode_info *pipe, size_t len,
+                                      unsigned int flags);
+
+#ifdef CONFIG_COMPAT
+static long swap_compat_device_ioctl(struct file *filp, unsigned int cmd,
+                                    unsigned long arg)
+{
+       switch (cmd & ~IOCSIZE_MASK) {
+       case SWAP_DRIVER_BUFFER_INITIALIZE & ~IOCSIZE_MASK:
+       case SWAP_DRIVER_MSG & ~IOCSIZE_MASK:
+               /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case) */
+               if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
+                       cmd &= ~IOCSIZE_MASK;
+                       cmd |= sizeof(void *) << IOCSIZE_SHIFT;
+               }
+               break;
+       }
+
+       return swap_device_ioctl(filp, cmd, arg);
+}
+#else /* CONFIG_COMPAT */
+#define swap_compat_device_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
+
+/**
+ * @var swap_device_fops
+ * @brief SWAP device file operations.
+ */
+const struct file_operations swap_device_fops = {
+       .owner = THIS_MODULE,
+       .read = swap_device_read,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .unlocked_ioctl = swap_device_ioctl,
+       .compat_ioctl = swap_compat_device_ioctl,
+       .splice_read = swap_device_splice_read,
+};
+
+/* Typedefs for splice_* funcs. Prototypes are for linux-3.8.6 */
+/** Splice to pipe pointer type. */
+typedef ssize_t(*splice_to_pipe_p_t)(struct pipe_inode_info *pipe,
+                                        struct splice_pipe_desc *spd);
+/** Splice grow spd pointer type. */
+typedef int(*splice_grow_spd_p_t)(const struct pipe_inode_info *pipe,
+                                       struct splice_pipe_desc *spd);
+
+static splice_to_pipe_p_t splice_to_pipe_p;
+static splice_grow_spd_p_t splice_grow_spd_p;
+
+/* Device numbers */
+static dev_t swap_device_no;
+
+/* Device cdev struct */
+static struct cdev swap_device_cdev;
+
+/* Device class struct */
+static struct class *swap_device_class;
+
+/* Device device struct */
+static struct device *swap_device_device;
+
+/* Reading tasks queue */
+static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait);
+
+
+static atomic_t flag_wake_up = ATOMIC_INIT(0);
+
+static void __bottom_wake_up(void)
+{
+       if (waitqueue_active(&swap_device_wait))
+               wake_up_interruptible(&swap_device_wait);
+}
+
+static void bottom_wake_up(struct work_struct *work)
+{
+       if (atomic_read(&flag_wake_up)) {
+               atomic_set(&flag_wake_up, 0);
+               __bottom_wake_up();
+       }
+}
+
+static DECLARE_WORK(w_wake_up, bottom_wake_up);
+
+static void exit_w_wake_up(void)
+{
+       flush_scheduled_work();
+       __bottom_wake_up();
+}
+
+
+/*
+ * Driver message handler
+ */
+static DECLARE_RWSEM(dmsg_handler_sem);
+static struct driver_msg_handler *dmsg_handler;
+
+static int driver_msg_handler_call(void __user *data)
+{
+       int ret;
+
+       down_read(&dmsg_handler_sem);
+       if (dmsg_handler) {
+               ret = dmsg_handler->handler(data);
+       } else {
+               print_warn("dmsg_handler() is not register\n");
+               ret = -EINVAL;
+       }
+       up_read(&dmsg_handler_sem);
+
+       return ret;
+}
+
+/**
+ * @brief Register message handler.
+ *
+ * @param msg_handler Pointer to message handler.
+ * @return Void.
+ */
+void driver_msg_handler_set(struct driver_msg_handler *msg_handler)
+{
+       down_write(&dmsg_handler_sem);
+       /* unregister dmsg_handler */
+       if (dmsg_handler) {
+               module_put(dmsg_handler->mod);
+               dmsg_handler = NULL;
+       }
+
+       /* register dmsg_handler */
+       if (msg_handler) {
+               BUG_ON(!try_module_get(msg_handler->mod));
+               dmsg_handler = msg_handler;
+       }
+       up_write(&dmsg_handler_sem);
+}
+EXPORT_SYMBOL_GPL(driver_msg_handler_set);
+
+
+/**
+ * @brief We need this realization of splice_shrink_spd() because its desing
+ * frequently changes in custom kernels.
+ *
+ * @param pipe Pointer to the pipe whereto splice data.
+ * @param spd Pointer to the splice_pipe_desc structure.
+ * @return Void.
+ */
+void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe,
+                                  struct splice_pipe_desc *spd)
+{
+       if (pipe->buffers <= PIPE_DEF_BUFFERS)
+               return;
+
+       kfree(spd->pages);
+       kfree(spd->partial);
+}
+
+
+/* TODO Think of permanent major */
+
+/**
+ * @brief Register device.
+ *
+ * @return 0 on success, negative error code otherwise.
+ */
+int swap_device_init(void)
+{
+       int result;
+
+       /* Allocating device major and minor nums for swap_device */
+       result = alloc_chrdev_region(&swap_device_no, 0, 1, SWAP_DEVICE_NAME);
+       if (result < 0) {
+               print_crit("Major number allocation has failed\n");
+               result = -E_SD_ALLOC_CHRDEV_FAIL;
+               goto init_fail;
+       }
+
+       /* Creating device class. Using IS_ERR, because class_create
+        * returns ERR_PTR on error. */
+       swap_device_class = class_create(THIS_MODULE, SWAP_DEVICE_NAME);
+       if (IS_ERR(swap_device_class)) {
+               print_crit("Class creation has failed\n");
+               result = -E_SD_CLASS_CREATE_FAIL;
+               goto init_fail;
+       }
+
+       /* Cdev intialization and setting file operations */
+       cdev_init(&swap_device_cdev, &swap_device_fops);
+
+       /* Adding cdev to system */
+       result = cdev_add(&swap_device_cdev, swap_device_no, 1);
+       if (result < 0) {
+               print_crit("Device adding has failed\n");
+               result = -E_SD_CDEV_ADD_FAIL;
+               goto init_fail;
+       }
+
+       /* Create device struct */
+       swap_device_device = device_create(swap_device_class, NULL,
+                                          swap_device_no,
+                                          "%s", SWAP_DEVICE_NAME);
+       if (IS_ERR(swap_device_device)) {
+               print_crit("Device struct creating has failed\n");
+               result = -E_SD_DEVICE_CREATE_FAIL;
+               goto init_fail;
+       }
+
+       /* Find splice_* funcs addresses */
+       splice_to_pipe_p = (splice_to_pipe_p_t)swap_ksyms("splice_to_pipe");
+       if (!splice_to_pipe_p) {
+               print_err("splice_to_pipe() not found!\n");
+               result = -E_SD_NO_SPLICE_FUNCS;
+               goto init_fail;
+       }
+
+       splice_grow_spd_p = (splice_grow_spd_p_t)swap_ksyms("splice_grow_spd");
+       if (!splice_grow_spd_p) {
+               print_err("splice_grow_spd() not found!\n");
+               result = -E_SD_NO_SPLICE_FUNCS;
+               goto init_fail;
+       }
+
+       return 0;
+
+init_fail:
+       cdev_del(&swap_device_cdev);
+       if (swap_device_class)
+               class_destroy(swap_device_class);
+       if (swap_device_no)
+               unregister_chrdev_region(swap_device_no, 1);
+       return result;
+}
+
+/* TODO Check wether driver is registered */
+
+/**
+ * @brief Unregister device.
+ *
+ * @return Void.
+ */
+void swap_device_exit(void)
+{
+       exit_w_wake_up();
+
+       splice_to_pipe_p = NULL;
+       splice_grow_spd_p = NULL;
+
+       device_destroy(swap_device_class, swap_device_no);
+       cdev_del(&swap_device_cdev);
+       class_destroy(swap_device_class);
+       unregister_chrdev_region(swap_device_no, 1);
+}
+
+static ssize_t swap_device_read(struct file *filp, char __user *buf,
+                               size_t count, loff_t *f_pos)
+{
+       /* Wait queue item that consists current task. It is used to be added in
+        * swap_device_wait queue if there is no data to be read. */
+       DEFINE_WAIT(wait);
+       int result;
+
+       /* TODO : Think about spin_locks to prevent reading race condition. */
+       while ((result =
+               driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
+
+               /* Add process to the swap_device_wait queue and set the current
+                * task state TASK_INTERRUPTIBLE. If there is any data to be
+                * read, then the current task is removed from the
+                * swap_device_wait queue and its state is changed to this. */
+               prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
+
+               if (result < 0) {
+                       result = 0;
+                       goto swap_device_read_error;
+               } else if (result == E_SD_NO_DATA_TO_READ) {
+                       /* Yes, E_SD_NO_DATA_TO_READ should be positive,
+                        * cause it's not really an error */
+                       if (filp->f_flags & O_NONBLOCK) {
+                               result = -EAGAIN;
+                               goto swap_device_read_error;
+                       }
+                       if (signal_pending(current)) {
+                               result = -ERESTARTSYS;
+                               goto swap_device_read_error;
+                       }
+                       schedule();
+                       finish_wait(&swap_device_wait, &wait);
+               }
+       }
+
+       result = driver_to_buffer_read(buf, count);
+       /* If there is an error - return 0 */
+       if (result < 0)
+               result = 0;
+
+
+       return result;
+
+swap_device_read_error:
+       finish_wait(&swap_device_wait, &wait);
+
+       return result;
+}
+
+static long swap_device_ioctl(struct file *filp, unsigned int cmd,
+                                                        unsigned long arg)
+{
+       int result;
+
+       switch (cmd) {
+       case SWAP_DRIVER_BUFFER_INITIALIZE:
+       {
+               struct buffer_initialize initialize_struct;
+
+               result = copy_from_user(&initialize_struct, (void *)arg,
+                                       sizeof(struct buffer_initialize));
+               if (result)
+                       break;
+
+               result = driver_to_buffer_set_size(initialize_struct.size);
+               if (result < 0) {
+                       print_err("Wrong subbuffer size=%u\n",
+                                 initialize_struct.size);
+                       break;
+               }
+
+               result = driver_to_buffer_set_count(initialize_struct.count);
+               if (result < 0) {
+                       print_err("Wrong subbuffer count=%u\n",
+                                 initialize_struct.count);
+                       break;
+               }
+
+               result = driver_to_buffer_initialize();
+               if (result < 0) {
+                       print_err("Buffer initialization failed %d\n", result);
+                       break;
+               }
+               result = E_SD_SUCCESS;
+
+               break;
+       }
+       case SWAP_DRIVER_BUFFER_UNINITIALIZE:
+       {
+               result = driver_to_buffer_uninitialize();
+               if (result < 0)
+                       print_err("Buffer uninitialization failed %d\n",
+                                 result);
+               break;
+       }
+       case SWAP_DRIVER_NEXT_BUFFER_TO_READ:
+       {
+               /* Use this carefully */
+               result = driver_to_buffer_next_buffer_to_read();
+               if (result == E_SD_NO_DATA_TO_READ) {
+                       /* TODO Do what we usually do when there are no
+                        * subbuffers to read (make daemon sleep ?) */
+               }
+               break;
+       }
+       case SWAP_DRIVER_FLUSH_BUFFER:
+       {
+               result = driver_to_buffer_flush();
+               break;
+       }
+       case SWAP_DRIVER_MSG:
+       {
+               result = driver_msg_handler_call((void __user *)arg);
+               break;
+       }
+       case SWAP_DRIVER_WAKE_UP:
+       {
+               swap_device_wake_up_process();
+               result = E_SD_SUCCESS;
+               break;
+       }
+       default:
+               print_warn("Unknown command %d\n", cmd);
+               result = -EINVAL;
+               break;
+
+       }
+       return result;
+}
+
+static void swap_device_pipe_buf_release(struct pipe_inode_info *inode,
+                                        struct pipe_buffer *pipe)
+{
+       __free_page(pipe->page);
+}
+
+static void swap_device_page_release(struct splice_pipe_desc *spd,
+                                    unsigned int i)
+{
+       __free_page(spd->pages[i]);
+}
+
+static const struct pipe_buf_operations swap_device_pipe_buf_ops = {
+       .can_merge = 0,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0)
+       .map = generic_pipe_buf_map,
+       .unmap = generic_pipe_buf_unmap,
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0) */
+       .confirm = generic_pipe_buf_confirm,
+       .release = swap_device_pipe_buf_release,
+       .steal = generic_pipe_buf_steal,
+       .get = generic_pipe_buf_get
+};
+
+static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
+                                      struct pipe_inode_info *pipe,
+                                      size_t len, unsigned int flags)
+{
+       /* Wait queue item that consists current task. It is used to be added in
+        * swap_device_wait queue if there is no data to be read. */
+       DEFINE_WAIT(wait);
+
+       int result;
+       struct page *pages[PIPE_DEF_BUFFERS];
+       struct partial_page partial[PIPE_DEF_BUFFERS];
+       struct splice_pipe_desc spd = {
+               .pages = pages,
+               .partial = partial,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 5))
+               .nr_pages_max = PIPE_DEF_BUFFERS,
+#endif
+               .nr_pages = 0,
+               .flags = flags,
+               .ops = &swap_device_pipe_buf_ops,
+               .spd_release = swap_device_page_release,
+       };
+
+       /* Get next buffer to read */
+       /* TODO : Think about spin_locks to prevent reading race condition.*/
+       while ((result =
+               driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
+
+               /* Add process to the swap_device_wait queue and set the current
+                * task state TASK_INTERRUPTIBLE. If there is any data to be
+                * read, then the current task is removed from the
+                * swap_device_wait queue and its state is changed. */
+               prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
+               if (result < 0) {
+                       print_err("driver_to_buffer_next_buffer_to_read error "
+                                 "%d\n", result);
+                       /* TODO Error return to OS */
+                       result = 0;
+                       goto swap_device_splice_read_error;
+               } else if (result == E_SD_NO_DATA_TO_READ) {
+                       if (filp->f_flags & O_NONBLOCK) {
+                               result = -EAGAIN;
+                               goto swap_device_splice_read_error;
+                       }
+                       if (signal_pending(current)) {
+                               result = -ERESTARTSYS;
+                               goto swap_device_splice_read_error;
+                       }
+                       schedule();
+                       finish_wait(&swap_device_wait, &wait);
+               }
+       }
+
+       if (splice_grow_spd_p(pipe, &spd)) {
+               result = -ENOMEM;
+               goto swap_device_splice_read_out;
+       }
+
+       result = driver_to_buffer_fill_spd(&spd);
+       if (result != 0) {
+               print_err("Cannot fill spd for splice\n");
+               goto swap_device_shrink_spd;
+       }
+
+       result = splice_to_pipe_p(pipe, &spd);
+
+swap_device_shrink_spd:
+       swap_device_splice_shrink_spd(pipe, &spd);
+
+swap_device_splice_read_out:
+       return result;
+
+swap_device_splice_read_error:
+       finish_wait(&swap_device_wait, &wait);
+
+       return result;
+}
+
+/**
+ * @brief Wakes up daemon that splicing data from driver.
+ *
+ * @return Void.
+ */
+void swap_device_wake_up_process(void)
+{
+       if (atomic_read(&flag_wake_up) == 0) {
+               atomic_set(&flag_wake_up, 1);
+               schedule_work(&w_wake_up);
+       }
+}
diff --git a/modules/driver/device_driver.h b/modules/driver/device_driver.h
new file mode 100644 (file)
index 0000000..b8f821b
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * @file driver/device_driver.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * SWAP device driver interface declaration.
+ */
+
+#ifndef __SWAP_DRIVER_DEVICE_DRIVER_H__
+#define __SWAP_DRIVER_DEVICE_DRIVER_H__
+
+/* Create and register device */
+int swap_device_init(void);
+
+/* Delete device */
+void swap_device_exit(void);
+
+#endif /* __SWAP_DRIVER_DEVICE_DRIVER_H__ */
diff --git a/modules/driver/device_driver_to_driver_to_buffer.h b/modules/driver/device_driver_to_driver_to_buffer.h
new file mode 100644 (file)
index 0000000..1e062e2
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * @file device_driver_to_driver_to_buffer.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ * SWAP device interface for driver_to_buffer.
+ */
+
+
+#ifndef __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__
+#define __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__
+
+void swap_device_wake_up_process(void);
+
+#endif /* __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__ */
diff --git a/modules/driver/driver_debugfs.c b/modules/driver/driver_debugfs.c
new file mode 100644 (file)
index 0000000..fb801da
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, 2016
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP debugfs interface definition.
+ */
+
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/debugfs.h>
+#include <master/swap_debugfs.h>
+#include "driver_to_buffer.h"
+#include "swap_driver_errors.h"
+
+
+#define WRITER_DBG_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
+
+
+static int buf_enabled_set(u64 val)
+{
+       int ret = -EINVAL;
+
+       switch (val) {
+       case 0:
+               ret = driver_to_buffer_uninitialize();
+               break;
+       case 1:
+               ret = driver_to_buffer_initialize();
+               break;
+       }
+
+       return ret;
+}
+
+static u64 buf_enabled_get(void)
+{
+       return driver_to_buffer_enabled();
+}
+
+static struct dfs_setget_64 dfs_enabled = {
+       .set = buf_enabled_set,
+       .get = buf_enabled_get,
+};
+
+static int subbuf_size_set(u64 val)
+{
+
+       if (driver_to_buffer_set_size(val) != E_SD_SUCCESS)
+               return -EINVAL;
+
+       return 0;
+}
+
+static u64 subbuf_size_get(void)
+{
+       return driver_to_buffer_get_size();
+}
+
+static struct dfs_setget_64 dfs_subbuf_size = {
+       .set = subbuf_size_set,
+       .get = subbuf_size_get,
+};
+
+static int subbuf_count_set(u64 val)
+{
+       if (driver_to_buffer_set_count(val) != E_SD_SUCCESS)
+               return -EINVAL;
+
+       return 0;
+}
+
+static u64 subbuf_count_get(void)
+{
+       return driver_to_buffer_get_count();
+}
+
+static struct dfs_setget_64 dfs_subbuf_count = {
+       .set = subbuf_count_set,
+       .get = subbuf_count_get,
+};
+
+
+struct dbgfs_data {
+       const char *name;
+       struct dfs_setget_64 *setget;
+};
+
+static struct dbgfs_data dbgfs[] = {
+       {
+               .name = "buffer_enabled",
+               .setget = &dfs_enabled,
+       }, {
+               .name = "subbuf_size",
+               .setget = &dfs_subbuf_size,
+       }, {
+               .name = "subbuf_conunt",
+               .setget = &dfs_subbuf_count,
+       }
+};
+
+
+static struct dentry *driver_dir;
+
+void driver_debugfs_uninit(void)
+{
+       debugfs_remove_recursive(driver_dir);
+       driver_dir = NULL;
+}
+
+int driver_debugfs_init(void)
+{
+       int i;
+       struct dentry *swap_dir, *dentry;
+
+       swap_dir = swap_debugfs_getdir();
+       if (swap_dir == NULL)
+               return -ENOENT;
+
+       driver_dir = swap_debugfs_create_dir("driver", swap_dir);
+       if (driver_dir == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(dbgfs); ++i) {
+               struct dbgfs_data *data = &dbgfs[i];
+               dentry = swap_debugfs_create_setget_u64(data->name,
+                                                       WRITER_DBG_PERMS,
+                                                       driver_dir,
+                                                       data->setget);
+               if (!dentry)
+                       goto fail;
+       }
+
+       return 0;
+fail:
+       driver_debugfs_uninit();
+       return -ENOMEM;
+}
diff --git a/modules/driver/driver_debugfs.h b/modules/driver/driver_debugfs.h
new file mode 100644 (file)
index 0000000..5624d05
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, 2016
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP debugfs interface definition.
+ */
+
+#ifndef DRIVER_DEBUGFS_H
+#define DRIVER_DEBUGFS_H
+
+
+int driver_debugfs_init(void);
+void driver_debugfs_uninit(void);
+
+#endif // DRIVER_DEBUGFS_H
diff --git a/modules/driver/driver_defs.h b/modules/driver/driver_defs.h
new file mode 100644 (file)
index 0000000..3318ae8
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * @file driver/driver_defs.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ * Device driver defs.
+ */
+
+#ifndef __SWAP_DRIVER_DEVICE_DEFS_H__
+#define __SWAP_DRIVER_DEVICE_DEFS_H__
+
+#include <linux/kernel.h>
+
+/** Prints debug message.*/
+#define print_debug(msg, args...) \
+       printk(KERN_DEBUG "SWAP_DRIVER DEBUG : " msg, ##args)
+/** Prints info message.*/
+#define print_msg(msg, args...)   \
+       printk(KERN_INFO "SWAP_DRIVER : " msg, ##args)
+/** Prints warning message.*/
+#define print_warn(msg, args...)  \
+       printk(KERN_WARNING "SWAP_DRIVER WARNING : " msg, ##args)
+/** Prints error message.*/
+#define print_err(msg, args...)   \
+       printk(KERN_ERR "SWAP_DRIVER ERROR : " msg, ##args)
+/** Prints critical error message.*/
+#define print_crit(msg, args...)  \
+       printk(KERN_CRIT "SWAP_DRIVER CRITICAL : " msg, ##args)
+
+#endif /* __SWAP_DRIVER_DEVICE_DEFS_H__ */
diff --git a/modules/driver/driver_to_buffer.c b/modules/driver/driver_to_buffer.c
new file mode 100644 (file)
index 0000000..80683a4
--- /dev/null
@@ -0,0 +1,461 @@
+/**
+ * driver/driver_to_buffer.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Driver and buffer interaction interface implementation.
+ */
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/splice.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#include <buffer/swap_buffer_module.h>
+#include <buffer/swap_buffer_errors.h>
+#include <buffer/buffer_description.h>
+
+#include "driver_defs.h"
+#include "swap_driver_errors.h"
+#include "device_driver_to_driver_to_buffer.h"
+#include "app_manage.h"
+
+/** Maximum subbuffer size. Used for sanitization checks. */
+#define MAXIMUM_SUBBUFFER_SIZE (64 * 1024)
+
+/* Current busy buffer */
+static struct swap_subbuffer *busy_buffer;
+
+/* Buffers count ready to be read */
+static int buffers_to_read;
+
+/* Pages count in one subbuffer */
+static int pages_per_buffer;
+
+/* Used to sync changes of the buffers_to_read var */
+static spinlock_t buf_to_read;
+
+
+static inline void init_buffers_to_read(void)
+{
+       spin_lock_init(&buf_to_read);
+       buffers_to_read = 0;
+}
+
+static inline void inc_buffers_to_read(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&buf_to_read, flags);
+       buffers_to_read++;
+       spin_unlock_irqrestore(&buf_to_read, flags);
+}
+
+static inline void dec_buffers_to_read(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&buf_to_read, flags);
+       buffers_to_read--;
+       spin_unlock_irqrestore(&buf_to_read, flags);
+}
+
+static inline void set_buffers_to_read(int count)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&buf_to_read, flags);
+       buffers_to_read = count;
+       spin_unlock_irqrestore(&buf_to_read, flags);
+}
+
+static inline int something_to_read(void)
+{
+       unsigned long flags;
+       int result;
+
+       spin_lock_irqsave(&buf_to_read, flags);
+       result = buffers_to_read;
+       spin_unlock_irqrestore(&buf_to_read, flags);
+
+       return result;
+}
+
+/* TODO Get subbuffer for reading */
+static size_t driver_to_buffer_get(void)
+{
+       int result;
+
+       /* If there is no readable buffers, return error */
+       result = swap_buffer_get(&busy_buffer);
+       if (result == -E_SB_NO_READABLE_BUFFERS) {
+               busy_buffer = NULL;
+               return -E_SD_NO_DATA_TO_READ;
+       } else if (result < 0) {
+               print_err("swap_buffer_get unhandle error %d\n", result);
+               return -E_SD_BUFFER_ERROR;
+       }
+
+       return busy_buffer->full_buffer_part;
+}
+
+/* TODO Release subbuffer */
+static int driver_to_buffer_release(void)
+{
+       int result;
+
+       if (!busy_buffer)
+               return -E_SD_NO_BUSY_SUBBUFFER;
+
+       result = swap_buffer_release(&busy_buffer);
+       if (result == -E_SB_NO_SUBBUFFER_IN_BUSY) {
+               return -E_SD_WRONG_SUBBUFFER_PTR;
+       } else if (result < 0) {
+               print_err("swap_buffer_release unhandle error %d\n", result);
+               return -E_SD_BUFFER_ERROR;
+       }
+
+       busy_buffer = NULL;
+
+       return E_SD_SUCCESS;
+}
+
+static int driver_to_buffer_callback(bool wakeup)
+{
+       /* Increment buffers_to_read counter */
+       inc_buffers_to_read();
+       if (wakeup)
+               swap_device_wake_up_process();
+
+       return E_SD_SUCCESS;
+}
+
+/**
+ * @brief Copies data from subbuffer to userspace.
+ *
+ * @param[out] buf Pointer to userspace memory area whereto copy data from
+ * subbuffer.
+ * @param count Size of data to be read.
+ * @return Read data size on success, negative error code on error.
+ */
+ssize_t driver_to_buffer_read(char __user *buf, size_t count)
+{
+       size_t bytes_to_copy;
+       size_t bytes_to_read = 0;
+       int page_counter = 0;
+
+       /* Reading from swap_device means reading only current busy_buffer.
+        * So, if there is no busy_buffer, we don't get next to read, we just
+        * read nothing. In this case, or if there is nothing to read from
+        * busy_buffer - return -E_SD_NO_DATA_TO_READ. It should be correctly
+        * handled in device_driver */
+       if (!busy_buffer || !busy_buffer->full_buffer_part)
+               return -E_SD_NO_DATA_TO_READ;
+
+       /* Bytes count that we're going to copy to user buffer is equal to user
+        * buffer size or to subbuffer readable size whichever is less */
+       bytes_to_copy = (count > busy_buffer->full_buffer_part) ?
+                   busy_buffer->full_buffer_part : count;
+
+       /* Copy data from each page to buffer */
+       while (bytes_to_copy > 0) {
+               /* Get size that should be copied from current page */
+               size_t read_from_this_page =
+                       (bytes_to_copy > PAGE_SIZE) ? PAGE_SIZE
+                       : bytes_to_copy;
+
+               /* Copy and add size to copied bytes count */
+
+               /* TODO Check with more than one page */
+               bytes_to_read += read_from_this_page -
+                        copy_to_user(
+                                buf, page_address(busy_buffer->data_buffer) +
+                                (sizeof(struct page *) *
+                                 page_counter),
+                                read_from_this_page);
+               bytes_to_copy -= read_from_this_page;
+               page_counter++;
+       }
+
+       return bytes_to_read;
+}
+
+/**
+ * @brief Flushes SWAP buffer.
+ *
+ * @return 0.
+ */
+int driver_to_buffer_flush(void)
+{
+       unsigned int flushed;
+
+       flushed = swap_buffer_flush();
+       set_buffers_to_read(flushed);
+       swap_device_wake_up_process();
+
+       return E_SD_SUCCESS;
+}
+
+/**
+ * @brief Fills spd structure.
+ *
+ * @param[out] spd Pointer to the splice_pipe_desc struct that should be filled.
+ * @return 0 on success, negative error code on error.
+ */
+int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd)
+{
+       size_t data_to_splice = busy_buffer->full_buffer_part;
+       struct page **pages = spd->pages;
+       struct partial_page *partial = spd->partial;
+
+       while (data_to_splice) {
+               size_t read_from_current_page = min(data_to_splice,
+                                                   (size_t)PAGE_SIZE);
+
+               pages[spd->nr_pages] = alloc_page(GFP_KERNEL);
+               if (!pages[spd->nr_pages]) {
+                       print_err("Cannot alloc page for splice\n");
+                       return -ENOMEM;
+               }
+
+               /* FIXME: maybe there is more efficient way */
+               memcpy(page_address(pages[spd->nr_pages]),
+              page_address(&busy_buffer->data_buffer[spd->nr_pages]),
+              read_from_current_page);
+
+               /* Always beginning of the page */
+               partial[spd->nr_pages].offset = 0;
+               partial[spd->nr_pages].len = read_from_current_page;
+
+               /* Private is not used */
+               partial[spd->nr_pages].private = 0;
+
+               spd->nr_pages++;
+               data_to_splice -= read_from_current_page;
+
+               /* TODO: add check for pipe->buffers exceeding */
+               /* if (spd->nr_pages == pipe->buffers) { */
+               /*      break; */
+               /* } */
+       }
+       return 0;
+}
+
+/**
+ * @brief Check for subbuffer ready to be read.
+ *
+ * @return 1 if there is subbuffer to be read, 0 - if there isn't.
+ */
+int driver_to_buffer_buffer_to_read(void)
+{
+       return busy_buffer ? 1 : 0;
+}
+
+static size_t subbuf_size;
+static unsigned int subbuf_count;
+static bool buffer_enabled;
+static DEFINE_MUTEX(buffer_mtx);
+
+bool driver_to_buffer_enabled(void)
+{
+       return buffer_enabled;
+}
+
+enum _swap_driver_errors driver_to_buffer_set_size(size_t size)
+{
+       enum _swap_driver_errors ret = E_SD_SUCCESS;
+
+       if (!size || size > MAXIMUM_SUBBUFFER_SIZE)
+               return -E_SD_WRONG_ARGS;
+
+       mutex_lock(&buffer_mtx);
+       if (buffer_enabled) {
+               ret = -E_SD_BUFFER_ENABLED;
+               goto unlock;
+       }
+
+       subbuf_size = size;
+unlock:
+       mutex_unlock(&buffer_mtx);
+       return ret;
+}
+
+size_t driver_to_buffer_get_size(void)
+{
+       return subbuf_size;
+}
+
+enum _swap_driver_errors driver_to_buffer_set_count(unsigned int count)
+{
+       enum _swap_driver_errors ret = E_SD_SUCCESS;
+
+       if (!count)
+               return -E_SD_WRONG_ARGS;
+
+       mutex_lock(&buffer_mtx);
+       if (buffer_enabled) {
+               ret = -E_SD_BUFFER_ENABLED;
+               goto unlock;
+       }
+       subbuf_count = count;
+
+unlock:
+       mutex_unlock(&buffer_mtx);
+       return ret;
+}
+
+unsigned int driver_to_buffer_get_count(void)
+{
+       return subbuf_count;
+}
+
+/**
+ * @brief Initializes SWAP buffer.
+ *
+ * @param size Size of one subbuffer.
+ * @param count Count of subbuffers.
+ * @return 0 on success, negative error code on error.
+ */
+int driver_to_buffer_initialize(void)
+{
+       enum _swap_driver_errors result;
+       struct buffer_init_t buf_init = {
+               .subbuffer_size = subbuf_size,
+               .nr_subbuffers = subbuf_count,
+               .subbuffer_full_cb = driver_to_buffer_callback,
+               .lower_threshold = 20,
+               .low_mem_cb = app_manage_pause_apps,
+               .top_threshold = 80,
+               .enough_mem_cb = app_manage_cont_apps,
+       };
+
+       mutex_lock(&buffer_mtx);
+       if (buffer_enabled) {
+               result = -E_SD_BUFFER_ENABLED;
+               goto unlock;
+       }
+
+       result = swap_buffer_init(&buf_init);
+       if (result == -E_SB_NO_MEM_QUEUE_BUSY
+               || result == -E_SB_NO_MEM_BUFFER_STRUCT) {
+               result = -E_SD_NO_MEMORY;
+               goto unlock;
+       }
+
+       /* TODO Race condition: buffer can be used in other thread till */
+       /* we're in this func */
+       /* Initialize driver_to_buffer variables */
+       pages_per_buffer = result;
+       busy_buffer = NULL;
+       init_buffers_to_read();
+       result = E_SD_SUCCESS;
+       buffer_enabled = true;
+
+unlock:
+       mutex_unlock(&buffer_mtx);
+       return result;
+}
+
+/**
+ * @brief Uninitializes buffer.
+ *
+ * @return 0 on success, negative error code on error.
+ */
+int driver_to_buffer_uninitialize(void)
+{
+       int result;
+
+       mutex_lock(&buffer_mtx);
+       if (!buffer_enabled) {
+               result = -E_SD_BUFFER_DISABLED;
+               goto unlock;
+       }
+
+       /* Release occupied buffer */
+       if (busy_buffer) {
+               result = driver_to_buffer_release();
+               /* TODO Maybe release anyway */
+               if (result < 0)
+                       goto unlock;
+               busy_buffer = NULL;
+       }
+
+       result = swap_buffer_uninit();
+       if (result == -E_SB_UNRELEASED_BUFFERS) {
+               print_err("Can't uninit buffer! There are busy subbuffers!\n");
+               result = -E_SD_BUFFER_ERROR;
+       } else if (result < 0) {
+               print_err("swap_buffer_uninit error %d\n", result);
+               result = -E_SD_BUFFER_ERROR;
+       } else {
+               result = E_SD_SUCCESS;
+               buffer_enabled = false;
+       }
+
+       /* Reinit driver_to_buffer vars */
+       init_buffers_to_read();
+       pages_per_buffer = 0;
+
+unlock:
+       mutex_unlock(&buffer_mtx);
+       return result;
+}
+
+/**
+ * @brief Get next buffer to read.
+ *
+ * @return 0 on success, negative error code on error, E_SD_NO_DATA_TO_READ if
+ * there is nothing to be read.
+ */
+int driver_to_buffer_next_buffer_to_read(void)
+{
+       int result;
+
+       /* If there is busy_buffer first release it */
+       if (busy_buffer) {
+               result = driver_to_buffer_release();
+               if (result)
+                       return result;
+       }
+
+       /* If there is no buffers to read, return E_SD_NO_DATA_TO_READ.
+        * SHOULD BE POSITIVE, cause there is no real error. */
+       if (!something_to_read())
+               return E_SD_NO_DATA_TO_READ;
+
+       /* Get next buffer to read */
+       result = driver_to_buffer_get();
+       if (result < 0) {
+               print_err("buffer_to_reads > 0, but there are no buffers to read\n");
+               return result;
+       }
+
+       /* Decrement buffers_to_read counter */
+       dec_buffers_to_read();
+
+       return E_SD_SUCCESS;
+}
diff --git a/modules/driver/driver_to_buffer.h b/modules/driver/driver_to_buffer.h
new file mode 100644 (file)
index 0000000..465968f
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * @file driver/driver_to_buffer.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Driver and buffer interaction interface declaration.
+ */
+
+#ifndef __SWAP_DRIVER_DRIVER_TO_BUFFER__
+#define __SWAP_DRIVER_DRIVER_TO_BUFFER__
+
+
+#include <linux/types.h>
+
+struct splice_pipe_desc;
+
+
+bool driver_to_buffer_enabled(void);
+
+enum _swap_driver_errors driver_to_buffer_set_size(size_t size);
+size_t driver_to_buffer_get_size(void);
+
+enum _swap_driver_errors driver_to_buffer_set_count(unsigned int count);
+unsigned int driver_to_buffer_get_count(void);
+
+int driver_to_buffer_initialize(void);
+int driver_to_buffer_uninitialize(void);
+ssize_t driver_to_buffer_read(char __user *buf, size_t count);
+int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd);
+int driver_to_buffer_buffer_to_read(void);
+int driver_to_buffer_next_buffer_to_read(void);
+int driver_to_buffer_flush(void);
+
+
+#endif /* __SWAP_DRIVER_DRIVER_TO_BUFFER__ */
diff --git a/modules/driver/driver_to_msg.h b/modules/driver/driver_to_msg.h
new file mode 100644 (file)
index 0000000..f252155
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * @file driver/driver_to_msg.h
+ * @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
+ *
+ * Driver and parser interaction interface declaration.
+ */
+
+#ifndef __SWAP_DRIVER_DRIVER_TO_MSG__
+#define __SWAP_DRIVER_DRIVER_TO_MSG__
+
+#include <linux/compiler.h>
+
+struct module;
+
+struct driver_msg_handler {
+       struct module *mod;
+       int (*handler)(void __user *data);
+};
+
+/* Set the message handler */
+void driver_msg_handler_set(struct driver_msg_handler *msg_handler);
+
+#endif /* __SWAP_DRIVER_DRIVER_TO_MSG__ */
diff --git a/modules/driver/swap_driver_errors.h b/modules/driver/swap_driver_errors.h
new file mode 100644 (file)
index 0000000..7c6fce2
--- /dev/null
@@ -0,0 +1,121 @@
+/**
+ * @file driver/swap_driver_errors.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * SWAP driver error codes.
+ */
+
+#ifndef __SWAP_DRIVER_ERRORS_H__
+#define __SWAP_DRIVER_ERRORS_H__
+
+
+/**
+ * @enum _swap_driver_errors
+ * @brief SWAP driver errors enumeration.
+ */
+enum _swap_driver_errors {
+       /**
+        * @brief Success.
+        */
+       E_SD_SUCCESS = 0,
+       /**
+        * @brief Alloc_chrdev_region failed.
+        */
+       E_SD_ALLOC_CHRDEV_FAIL = 1,
+       /**
+        * @brief cdev_alloc failed.
+        */
+       E_SD_CDEV_ALLOC_FAIL = 2,
+       /**
+        * @brief cdev_add failed.
+        */
+       E_SD_CDEV_ADD_FAIL = 3,
+       /**
+        * @brief class_create failed.
+        */
+       E_SD_CLASS_CREATE_FAIL = 4,
+       /**
+        * @brief device_create failed.
+        */
+       E_SD_DEVICE_CREATE_FAIL = 5,
+       /**
+        * @brief splice_* funcs not found.
+        */
+       E_SD_NO_SPLICE_FUNCS = 6,
+       /**
+        * @brief swap_buffer_get tells us that there is no readable subbuffers.
+        */
+       E_SD_NO_DATA_TO_READ = 7,
+       /**
+        * @brief No busy subbuffer.
+        */
+       E_SD_NO_BUSY_SUBBUFFER = 8,
+       /**
+        * @brief Wrong subbuffer pointer passed to swap_buffer module.
+        */
+       E_SD_WRONG_SUBBUFFER_PTR = 9,
+       /**
+        * @brief Unhandled swap_buffer error.
+        */
+       E_SD_BUFFER_ERROR = 10,
+       /**
+        * @brief Write to subbuffer error.
+        */
+       E_SD_WRITE_ERROR = 11,
+       /**
+        * @brief Arguments, been passed to the func, doesn't pass sanity check.
+        */
+       E_SD_WRONG_ARGS = 12,
+       /**
+        * @brief No memory to allocate.
+        */
+       E_SD_NO_MEMORY = 13,
+       /**
+        * @brief swap_buffer uninitialization error.
+        */
+       E_SD_UNINIT_ERROR = 14,
+       /**
+        * @brief Netlink init error.
+        */
+       E_SD_NL_INIT_ERR = 15,
+       /**
+        * @brief Netlink message send error.
+        */
+       E_SD_NL_MSG_ERR = 16,
+       /**
+        * @brief No daemon pid in us_interaction.
+        */
+       E_SD_NO_DAEMON_PID = 17,
+       /**
+        * @brief Buffer already enabled
+        */
+       E_SD_BUFFER_ENABLED = 18,
+       /**
+        * @brief Buffer already disabled
+        */
+       E_SD_BUFFER_DISABLED = 19,
+};
+
+#endif /* __SWAP_DRIVER_ERRORS_H__ */
diff --git a/modules/driver/swap_driver_module.c b/modules/driver/swap_driver_module.c
new file mode 100644 (file)
index 0000000..dcb69bb
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * driver/swap_driver_module.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * SWAP drive module interface implementation.
+ */
+
+#include <linux/module.h>
+#include <master/swap_initializer.h>
+#include "driver_defs.h"
+#include "device_driver.h"
+#include "us_interaction.h"
+#include "driver_debugfs.h"
+
+static int fs_init(void)
+{
+       int ret;
+
+       ret = swap_device_init();
+       if (ret)
+               goto dev_init_fail;
+
+       ret = us_interaction_create();
+       if (ret)
+               print_err("Cannot initialize netlink socket\n");
+
+       ret = driver_debugfs_init();
+       if (ret)
+               goto us_int_destroy;
+
+       print_msg("Driver module initialized\n");
+
+       return ret;
+
+us_int_destroy:
+       us_interaction_destroy();
+dev_init_fail:
+       swap_device_exit();
+
+       return ret;
+}
+
+static void fs_uninit(void)
+{
+       driver_debugfs_uninit();
+       us_interaction_destroy();
+       swap_device_exit();
+       print_msg("Driver module uninitialized\n");
+}
+
+SWAP_LIGHT_INIT_MODULE(NULL, NULL, NULL, fs_init, fs_uninit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP device driver");
+MODULE_AUTHOR("Aksenov A.S.");
diff --git a/modules/driver/swap_ioctl.h b/modules/driver/swap_ioctl.h
new file mode 100644 (file)
index 0000000..9fd541c
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * @file driver/swap_ioctl.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Provides ioctl commands and recources for SWAP driver.
+ */
+
+#ifndef __SWAP_IOCTL_H__
+#define __SWAP_IOCTL_H__
+
+#include <linux/ioctl.h>
+
+/** SWAP device magic number. */
+#define SWAP_DRIVER_IOC_MAGIC 0xAF
+
+/**
+ * @struct buffer_initialize
+ * @brief SWAP buffer initialization struct.
+ * @var buffer_initialize::size
+ * Size of one subbuffer.
+ * @var buffer_initialize::count
+ * Count of subbuffers in the buffer.
+ */
+struct buffer_initialize {
+       u32 size;
+       u32 count;
+} __packed;
+
+/* SWAP Device ioctl commands */
+
+/** Initialize buffer message. */
+#define SWAP_DRIVER_BUFFER_INITIALIZE          _IOW(SWAP_DRIVER_IOC_MAGIC, 1, \
+                                                    struct buffer_initialize *)
+/** Uninitialize buffer message. */
+#define SWAP_DRIVER_BUFFER_UNINITIALIZE                _IO(SWAP_DRIVER_IOC_MAGIC, 2)
+/** Set next buffer to read. */
+#define SWAP_DRIVER_NEXT_BUFFER_TO_READ                _IO(SWAP_DRIVER_IOC_MAGIC, 3)
+/** Flush buffers. */
+#define SWAP_DRIVER_FLUSH_BUFFER               _IO(SWAP_DRIVER_IOC_MAGIC, 4)
+/** Custom message. */
+#define SWAP_DRIVER_MSG                                _IOW(SWAP_DRIVER_IOC_MAGIC, 5, \
+                                                    void *)
+/** Force wake up daemon. */
+#define SWAP_DRIVER_WAKE_UP                    _IO(SWAP_DRIVER_IOC_MAGIC, 6)
+
+#endif /* __SWAP_IOCTL_H__ */
diff --git a/modules/driver/us_interaction.c b/modules/driver/us_interaction.c
new file mode 100644 (file)
index 0000000..9bac1be
--- /dev/null
@@ -0,0 +1,123 @@
+/**
+ * driver/us_interaction.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * Kernel-to-user interface implementation.
+ */
+
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/connector.h>
+#include <linux/slab.h>
+
+#include "us_interaction.h"
+#include "us_interaction_msg.h"
+#include "swap_driver_errors.h"
+#include "driver_defs.h"
+
+
+/* Connector id struct */
+static struct cb_id cn_swap_id = {CN_SWAP_IDX, CN_SWAP_VAL};
+
+/* Swap connector name */
+static const char cn_swap_name[] = "cn_swap";
+
+/* Send messages counter */
+static u32 msg_counter;
+
+/**
+ * @brief Sends message to userspace via netlink.
+ *
+ * @param data Pointer to the data to be send.
+ * @param size Size of the data to be send.
+ * @return 0 on success, error code on error.
+ */
+int us_interaction_send_msg(const void *data, size_t size)
+{
+       struct cn_msg *msg;
+       int ret;
+
+       msg = kzalloc(sizeof(*msg) + size, GFP_ATOMIC);
+       if (msg == NULL)
+               return -E_SD_NO_MEMORY;
+
+       memcpy(&msg->id, &cn_swap_id, sizeof(msg->id));
+       msg->seq = msg_counter;
+       msg->len = size;
+       memcpy(msg->data, data, msg->len);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 25)
+       ret = cn_netlink_send(msg, CN_DAEMON_GROUP, GFP_ATOMIC);
+#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0) */
+       ret = cn_netlink_send(msg, 0, CN_DAEMON_GROUP, GFP_ATOMIC);
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 14, 0) */
+       if (ret < 0)
+               goto fail_send;
+       kfree(msg);
+
+       msg_counter++;
+
+       return E_SD_SUCCESS;
+
+fail_send:
+       kfree(msg);
+
+       return ret;
+}
+
+static void us_interaction_recv_msg(struct cn_msg *msg,
+                                   struct netlink_skb_parms *nsp)
+{
+}
+
+/**
+ * @brief Creates netlink connection.
+ *
+ * @return 0 on success, error code on error.
+ */
+int us_interaction_create(void)
+{
+       int res;
+
+       res = cn_add_callback(&cn_swap_id,
+                             cn_swap_name,
+                             us_interaction_recv_msg);
+       if (res)
+               return -E_SD_NL_INIT_ERR;
+
+       return E_SD_SUCCESS;
+}
+
+/**
+ * @brief Destroy netlink connection.
+ *
+ * @return Void.
+ */
+void us_interaction_destroy(void)
+{
+       cn_del_callback(&cn_swap_id);
+}
diff --git a/modules/driver/us_interaction.h b/modules/driver/us_interaction.h
new file mode 100644 (file)
index 0000000..66f6343
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * @file driver/us_interaction.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * Kernel-to-user interface definition.
+ */
+
+#ifndef __US_INTERACTION_H__
+#define __US_INTERACTION_H__
+
+#include <linux/version.h>
+
+#ifdef CONFIG_CONNECTOR
+
+int us_interaction_create(void);
+void us_interaction_destroy(void);
+int us_interaction_send_msg(const void *data, size_t size);
+
+#else /* CONFIG_CONNECTOR */
+
+static inline int us_interaction_create(void)
+{
+       return -EPERM;
+}
+
+static inline void us_interaction_destroy(void)
+{
+}
+
+static inline int us_interaction_send_msg(const void *data, size_t size)
+{
+       return -EPERM;
+}
+
+#endif /* CONFIG_CONNECTOR */
+
+#endif /* __US_INTERACTION_H__ */
diff --git a/modules/driver/us_interaction_msg.h b/modules/driver/us_interaction_msg.h
new file mode 100644 (file)
index 0000000..d6bb4c9
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * @file driver/us_interaction_msg.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * Netlink messages declaration.
+ */
+
+#ifndef __US_INTERACTION_MSG_H__
+#define __US_INTERACTION_MSG_H__
+
+#define CN_SWAP_IDX     0x22    /**< Should be unique throughout the system */
+#define CN_SWAP_VAL     0x1     /**< Just the same in kernel and user */
+#define CN_DAEMON_GROUP 0x1     /**< Listener group. Connector works a bit
+                                * faster when using one */
+
+/**
+ * @enum us_interaction_k2u_msg_t
+ * @brief Kernel-to-user netlink messages headers.
+ */
+enum us_interaction_k2u_msg_t {
+       /**
+        * @brief Make daemon pause apps.
+        */
+       US_INT_PAUSE_APPS = 1,
+       /**
+        * @brief Make daemon continue apps.
+        */
+       US_INT_CONT_APPS = 2
+};
+
+#endif /* __US_INTERACTION_MSG_H__ */
diff --git a/modules/energy/Kbuild b/modules/energy/Kbuild
new file mode 100644 (file)
index 0000000..80d23c9
--- /dev/null
@@ -0,0 +1,96 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers \
+                       $(src)/../us_manager/Module.symvers \
+                       $(src)/../driver/Module.symvers
+
+
+
+
+
+###############################################################################
+###                      swap energy module description                     ###
+###############################################################################
+obj-m := swap_energy.o
+swap_energy-y := energy_module.o \
+                 energy.o \
+                 rational_debugfs.o \
+                 debugfs_energy.o \
+                 lcd/lcd_base.o \
+                 lcd/lcd_debugfs.o
+
+
+
+
+
+###############################################################################
+###                               math support                              ###
+###############################################################################
+# S6E8AA0:
+ifeq ($(CONFIG_LCD_S6E8AA0), y)
+    swap_energy-y += lcd/s6e8aa0.o
+    LCD_FUNC_LIST += s6e8aa0
+endif
+
+
+# PANEL_S6E8AA0:
+ifeq ($(CONFIG_DISPLAY_PANEL_S6E8AA0), y)
+    swap_energy-y += lcd/s6e8aa0_panel.o
+    LCD_FUNC_LIST += s6e8aa0_panel
+endif
+
+
+# MARU:
+ifeq ($(CONFIG_MARU_BACKLIGHT), y)
+    swap_energy-y += lcd/maru.o
+    LCD_FUNC_LIST += maru
+endif
+
+
+
+
+
+###############################################################################
+###                          description functions                          ###
+###############################################################################
+LCD_FUNC_ARGS := void
+LCD_FUNC_RET := struct lcd_ops *
+
+
+
+
+
+###############################################################################
+###                            generate defines                             ###
+###############################################################################
+LCD_PREFIX := lcd_energy_
+
+# add prefix
+TMP := $(foreach it, $(LCD_FUNC_LIST), $(LCD_PREFIX)$(it))
+LCD_FUNC_LIST := $(TMP)
+
+# generate DEFINITION_LCD_FUNC
+TMP := ($(LCD_FUNC_ARGS));
+DEFINITION_LCD_FUNC := DEFINITION_LCD_FUNC=\
+$(foreach it, $(LCD_FUNC_LIST), "extern" $(LCD_FUNC_RET) $(it)$(TMP))
+
+
+# generate DEFINITION_LCD_ARRAY
+COMMA := ,
+AND := &
+DEFINITION_LCD_ARRAY := DEFINITION_LCD_ARRAY=\
+"{" $(foreach it, $(LCD_FUNC_LIST), &$(it),) "}"
+
+
+# generate LCD_MAKE_FNAME
+LCD_MAKE_FNAME := LCD_MAKE_FNAME(name)=$(LCD_PREFIX)\#\#name
+
+
+
+
+
+###############################################################################
+###                  add generate defines to EXTRA_CFLAGS                   ###
+###############################################################################
+EXTRA_CFLAGS += -D"$(DEFINITION_LCD_FUNC)" \
+                -D"$(DEFINITION_LCD_ARRAY)" \
+                -D"$(LCD_MAKE_FNAME)"
diff --git a/modules/energy/debugfs_energy.c b/modules/energy/debugfs_energy.c
new file mode 100644 (file)
index 0000000..b6ce420
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  energy/debugfs_energy.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/math64.h>
+#include <master/swap_debugfs.h>
+#include "energy.h"
+#include "debugfs_energy.h"
+#include "rational_debugfs.h"
+#include "lcd/lcd_debugfs.h"
+#include "lcd/lcd_base.h"
+
+
+/* CPU running */
+static DEFINE_RATIONAL(cpu0_running_coef); /* boot core uses distinct coeff */
+static DEFINE_RATIONAL(cpuN_running_coef);
+
+static u64 __energy_cpu0(enum parameter_energy pe)
+{
+       u64 times[NR_CPUS] = { 0 };
+       u64 val = 0;
+
+       /* TODO: make for only cpu0 */
+       if (get_parameter_energy(pe, times, sizeof(times)) == 0) {
+               val = div_u64(times[0] * cpu0_running_coef.num,
+                             cpu0_running_coef.denom);
+       }
+
+       return val;
+}
+
+static u64 __energy_cpuN(enum parameter_energy pe)
+{
+       u64 times[NR_CPUS] = { 0 };
+       u64 val = 0;
+
+       if (get_parameter_energy(pe, times, sizeof(times)) == 0) {
+               int i;
+
+               for (i = 1; i < NR_CPUS; i++)
+                       val += div_u64(times[i] * cpuN_running_coef.num,
+                                      cpuN_running_coef.denom);
+       }
+
+       return val;
+}
+
+static u64 cpu0_system(void)
+{
+       return __energy_cpu0(PE_TIME_SYSTEM);
+}
+
+static u64 cpuN_system(void)
+{
+       return __energy_cpuN(PE_TIME_SYSTEM);
+}
+
+static u64 cpu0_apps(void)
+{
+       return __energy_cpu0(PE_TIME_APPS);
+}
+
+static u64 cpuN_apps(void)
+{
+       return __energy_cpuN(PE_TIME_APPS);
+}
+
+
+/* CPU idle */
+static DEFINE_RATIONAL(cpu_idle_coef);
+
+static u64 cpu_idle_system(void)
+{
+       u64 time = 0;
+
+       get_parameter_energy(PE_TIME_IDLE, &time, sizeof(time));
+       return div_u64(time * cpu_idle_coef.num, cpu_idle_coef.denom);
+}
+
+
+/* flash read */
+static DEFINE_RATIONAL(fr_coef);
+
+static u64 fr_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_READ_SYSTEM, &byte, sizeof(byte));
+       return div_u64(byte * fr_coef.num, fr_coef.denom);
+}
+
+static u64 fr_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_READ_APPS, &byte, sizeof(byte));
+       return div_u64(byte * fr_coef.num, fr_coef.denom);
+}
+
+
+/* flash write */
+static DEFINE_RATIONAL(fw_coef);
+
+static u64 fw_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_WRITE_SYSTEM, &byte, sizeof(byte));
+       return div_u64(byte * fw_coef.num, fw_coef.denom);
+}
+
+static u64 fw_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_WRITE_APPS, &byte, sizeof(byte));
+       return div_u64(byte * fw_coef.num, fw_coef.denom);
+}
+
+
+/* wifi recv */
+static DEFINE_RATIONAL(wf_recv_coef);
+
+static u64 wf_recv_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_WF_RECV_SYSTEM, &byte, sizeof(byte));
+
+       return div_u64(byte * wf_recv_coef.num, wf_recv_coef.denom);
+}
+
+static u64 wf_recv_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_WF_RECV_APPS, &byte, sizeof(byte));
+
+       return div_u64(byte * wf_recv_coef.num, wf_recv_coef.denom);
+}
+
+/* wifi send */
+static DEFINE_RATIONAL(wf_send_coef);
+
+static u64 wf_send_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_WF_SEND_SYSTEM, &byte, sizeof(byte));
+
+       return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
+}
+
+static u64 wf_send_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_WF_SEND_APPS, &byte, sizeof(byte));
+
+       return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
+}
+
+/* l2cap_recv_acldata */
+static DEFINE_RATIONAL(l2cap_recv_acldata_coef);
+
+static u64 l2cap_recv_acldata_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_L2CAP_RECV_SYSTEM, &byte, sizeof(byte));
+
+       return div_u64(byte * l2cap_recv_acldata_coef.num,
+                      l2cap_recv_acldata_coef.denom);
+}
+
+static u64 l2cap_recv_acldata_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_L2CAP_RECV_APPS, &byte, sizeof(byte));
+
+       return div_u64(byte * l2cap_recv_acldata_coef.num,
+                      l2cap_recv_acldata_coef.denom);
+}
+
+/* sco_recv_scodata */
+static DEFINE_RATIONAL(sco_recv_scodata_coef);
+
+static u64 sco_recv_scodata_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_SCO_RECV_SYSTEM, &byte, sizeof(byte));
+
+       return div_u64(byte * sco_recv_scodata_coef.num,
+                      sco_recv_scodata_coef.denom);
+}
+
+static u64 sco_recv_scodata_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PE_SCO_RECV_APPS, &byte, sizeof(byte));
+
+       return div_u64(byte * sco_recv_scodata_coef.num,
+                      sco_recv_scodata_coef.denom);
+}
+
+/* hci_send_acl */
+static DEFINE_RATIONAL(hci_send_acl_coef);
+
+static u64 hci_send_acl_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PT_SEND_ACL_SYSTEM, &byte, sizeof(byte));
+
+       return div_u64(byte * hci_send_acl_coef.num, hci_send_acl_coef.denom);
+}
+
+static u64 hci_send_acl_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PT_SEND_ACL_APPS, &byte, sizeof(byte));
+
+       return div_u64(byte * hci_send_acl_coef.num, hci_send_acl_coef.denom);
+}
+
+/* hci_send_sco */
+static DEFINE_RATIONAL(hci_send_sco_coef);
+
+static u64 hci_send_sco_system(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PT_SEND_SCO_SYSTEM, &byte, sizeof(byte));
+
+       return div_u64(byte * hci_send_sco_coef.num, hci_send_sco_coef.denom);
+}
+
+static u64 hci_send_sco_apps(void)
+{
+       u64 byte = 0;
+
+       get_parameter_energy(PT_SEND_SCO_APPS, &byte, sizeof(byte));
+
+       return div_u64(byte * hci_send_sco_coef.num, hci_send_sco_coef.denom);
+}
+
+
+
+
+
+/* ============================================================================
+ * ===                             PARAMETERS                               ===
+ * ============================================================================
+ */
+static int get_func_u64(void *data, u64 *val)
+{
+       u64 (*func)(void) = data;
+       *val = func();
+       return 0;
+}
+
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_u64, get_func_u64, NULL, "%llu\n");
+
+
+struct param_data {
+       char *name;
+       struct rational *coef;
+       u64 (*system)(void);
+       u64 (*apps)(void);
+};
+
+static struct dentry *create_parameter(struct dentry *parent,
+                                      struct param_data *param)
+{
+       struct dentry *name, *system, *apps = NULL;
+
+       name = swap_debugfs_create_dir(param->name, parent);
+       if (name == NULL)
+               return NULL;
+
+       system = swap_debugfs_create_file("system", 0600, name, param->system,
+                                         &fops_get_u64);
+       if (system == NULL)
+               goto rm_name;
+
+       if (param->apps) {
+               apps = swap_debugfs_create_file("apps", 0600, name, param->apps,
+                                               &fops_get_u64);
+               if (apps == NULL)
+                       goto rm_system;
+       }
+
+       if (create_rational_files(name, param->coef,
+                                 "numerator", "denominator"))
+               goto rm_apps;
+
+       return name;
+
+rm_apps:
+       if (param->apps)
+               debugfs_remove(apps);
+rm_system:
+       debugfs_remove(system);
+rm_name:
+       debugfs_remove(name);
+
+       return NULL;
+}
+
+struct param_data parameters[] = {
+       {
+               .name = "cpu_running",
+               .coef = &cpu0_running_coef,
+               .system = cpu0_system,
+               .apps = cpu0_apps
+       },
+       {
+               .name = "cpuN_running",
+               .coef = &cpuN_running_coef,
+               .system = cpuN_system,
+               .apps = cpuN_apps
+       },
+       {
+               .name = "cpu_idle",
+               .coef = &cpu_idle_coef,
+               .system = cpu_idle_system,
+               .apps = NULL
+       },
+       {
+               .name = "flash_read",
+               .coef = &fr_coef,
+               .system = fr_system,
+               .apps = fr_apps
+       },
+       {
+               .name = "flash_write",
+               .coef = &fw_coef,
+               .system = fw_system,
+               .apps = fw_apps
+       },
+       {
+               .name = "wf_recv",
+               .coef = &wf_recv_coef,
+               .system = wf_recv_system,
+               .apps = wf_recv_apps
+       },
+       {
+               .name = "wf_send",
+               .coef = &wf_send_coef,
+               .system = wf_send_system,
+               .apps = wf_send_apps
+       },
+       {
+               .name = "sco_recv_scodata",
+               .coef = &sco_recv_scodata_coef,
+               .system = sco_recv_scodata_system,
+               .apps = sco_recv_scodata_apps
+       },
+       {
+               .name = "l2cap_recv_acldata",
+               .coef = &l2cap_recv_acldata_coef,
+               .system = l2cap_recv_acldata_system,
+               .apps = l2cap_recv_acldata_apps
+       },
+       {
+               .name = "hci_send_acl",
+               .coef = &hci_send_acl_coef,
+               .system = hci_send_acl_system,
+               .apps = hci_send_acl_apps
+       },
+       {
+               .name = "hci_send_sco",
+               .coef = &hci_send_sco_coef,
+               .system = hci_send_sco_system,
+               .apps = hci_send_sco_apps
+       }
+};
+
+enum {
+       parameters_cnt = sizeof(parameters) / sizeof(struct param_data)
+};
+
+
+
+
+
+/* ============================================================================
+ * ===                              INIT/EXIT                               ===
+ * ============================================================================
+ */
+static struct dentry *energy_dir;
+
+/**
+ * @brief Destroy debugfs for LCD
+ *
+ * @return Dentry of energy debugfs
+ */
+struct dentry *get_energy_dir(void)
+{
+       return energy_dir;
+}
+
+/**
+ * @brief Destroy debugfs for energy
+ *
+ * @return Void
+ */
+void exit_debugfs_energy(void)
+{
+       lcd_exit();
+       exit_lcd_debugfs();
+
+       if (energy_dir)
+               debugfs_remove_recursive(energy_dir);
+
+       energy_dir = NULL;
+}
+
+/**
+ * @brief Create debugfs for energy
+ *
+ * @return Error code
+ */
+int init_debugfs_energy(void)
+{
+       int i;
+       struct dentry *swap_dir, *dentry;
+
+       swap_dir = swap_debugfs_getdir();
+       if (swap_dir == NULL)
+               return -ENOENT;
+
+       energy_dir = swap_debugfs_create_dir("energy", swap_dir);
+       if (energy_dir == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < parameters_cnt; ++i) {
+               dentry = create_parameter(energy_dir, &parameters[i]);
+               if (dentry == NULL)
+                       goto fail;
+       }
+
+       if (init_lcd_debugfs(energy_dir))
+               goto fail;
+
+       /* Actually, the only goal of lcd_init() is to register lcd screen's
+          debugfs, so it is called here. */
+       if (lcd_init()) {
+               exit_lcd_debugfs();
+       }
+
+       return 0;
+
+fail:
+       exit_debugfs_energy();
+       return -ENOMEM;
+}
diff --git a/modules/energy/debugfs_energy.h b/modules/energy/debugfs_energy.h
new file mode 100644 (file)
index 0000000..e4b5e32
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _DEBUGFS_ENERGY_H
+#define _DEBUGFS_ENERGY_H
+
+/**
+ * @file energy/debugfs_energy.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ * Debugfs for energy
+ */
+
+
+#include <linux/fs.h>
+#include <master/swap_initializer.h>
+
+
+struct dentry;
+
+
+/* based on define DEFINE_SIMPLE_ATTRIBUTE */
+#define SWAP_DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)      \
+static int __fops ## _open(struct inode *inode, struct file *file)     \
+{                                                                      \
+       int ret;                                                        \
+                                                                       \
+       ret = swap_init_simple_open(inode, file);                       \
+       if (ret)                                                        \
+               return ret;                                             \
+                                                                       \
+       __simple_attr_check_format(__fmt, 0ull);                        \
+       ret = simple_attr_open(inode, file, __get, __set, __fmt);       \
+       if (ret)                                                        \
+               swap_init_simple_release(inode, file);                  \
+                                                                       \
+       return ret;                                                     \
+}                                                                      \
+static int __fops ## _release(struct inode *inode, struct file *file)  \
+{                                                                      \
+       simple_attr_release(inode, file);                               \
+       swap_init_simple_release(inode, file);                          \
+                                                                       \
+       return 0;                                                       \
+}                                                                      \
+static const struct file_operations __fops = {                         \
+       .owner   = THIS_MODULE,                                         \
+       .open    = __fops ## _open,                                     \
+       .release = __fops ## _release,                                  \
+       .read    = simple_attr_read,                                    \
+       .write   = simple_attr_write,                                   \
+       .llseek  = generic_file_llseek,                                 \
+}
+
+
+int init_debugfs_energy(void);
+void exit_debugfs_energy(void);
+
+struct dentry *get_energy_dir(void);
+
+
+#endif /* _DEBUGFS_ENERGY_H */
diff --git a/modules/energy/energy.c b/modules/energy/energy.c
new file mode 100644 (file)
index 0000000..49ac721
--- /dev/null
@@ -0,0 +1,1353 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/energy/swap_energy.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vasiliy Ulyanov <v.ulyanov@samsung.com>
+ *              Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/spinlock.h>
+#include <linux/magic.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/fdtable.h>
+#include <net/sock.h>
+#include <ksyms/ksyms.h>
+#include <master/swap_deps.h>
+#include <swap-asm/swap_kprobes.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/sspt/sspt_feature.h>
+#include <linux/atomic.h>
+
+#ifdef CONFIG_SWAP_HOOK_SWITCH_TO
+# include <swap/hook_switch_to.h>
+#else /* CONFIG_SWAP_HOOK_SWITCH_TO */
+# include <kprobe/swap_kprobes.h>
+#endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
+
+#ifdef CONFIG_SWAP_HOOK_ENERGY
+# include <swap/hook_syscall.h>
+# include <swap/hook_energy.h>
+# include <kprobe/swap_td_raw.h>
+#else /* CONFIG_SWAP_HOOK_ENERGY */
+# include <kprobe/swap_kprobes.h>
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
+#include "energy.h"
+#include "lcd/lcd_base.h"
+#include "tm_stat.h"
+
+
+#ifndef CONFIG_SWAP_HOOK_ENERGY
+/* ============================================================================
+ * =                              ENERGY_XXX                                  =
+ * ============================================================================
+ */
+struct kern_probe {
+       const char *name;
+       struct kretprobe *rp;
+};
+
+static int energy_xxx_once(struct kern_probe p[], int size)
+{
+       int i;
+       const char *sym;
+
+       for (i = 0; i < size; ++i) {
+               struct kretprobe *rp = p[i].rp;
+
+               sym = p[i].name;
+               rp->kp.addr = swap_ksyms(sym);
+               if (rp->kp.addr == 0)
+                       goto not_found;
+       }
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+static int energy_xxx_set(struct kern_probe p[], int size, int *flag)
+{
+       int i, ret;
+
+       for (i = 0; i < size; ++i) {
+               ret = swap_register_kretprobe(p[i].rp);
+               if (ret)
+                       goto fail;
+       }
+
+       *flag = 1;
+       return 0;
+
+fail:
+       pr_err("swap_register_kretprobe(%s) ret=%d\n", p[i].name, ret);
+
+       for (--i; i != -1; --i)
+               swap_unregister_kretprobe(p[i].rp);
+
+       return ret;
+}
+
+static void energy_xxx_unset(struct kern_probe p[], int size, int *flag)
+{
+       int i;
+
+       if (*flag == 0)
+               return;
+
+       for (i = size - 1; i != -1; --i)
+               swap_unregister_kretprobe(p[i].rp);
+
+       *flag = 0;
+}
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
+
+
+
+
+/* ============================================================================
+ * =                              CPUS_TIME                                   =
+ * ============================================================================
+ */
+struct cpus_time {
+       spinlock_t lock; /* for concurrent access */
+       struct tm_stat tm[NR_CPUS];
+};
+
+#define cpus_time_lock(ct, flags) spin_lock_irqsave(&(ct)->lock, flags)
+#define cpus_time_unlock(ct, flags) spin_unlock_irqrestore(&(ct)->lock, flags)
+
+static void cpus_time_init(struct cpus_time *ct, u64 time)
+{
+       int cpu;
+
+       spin_lock_init(&ct->lock);
+
+       for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+               tm_stat_init(&ct->tm[cpu]);
+               tm_stat_set_timestamp(&ct->tm[cpu], time);
+       }
+}
+
+static inline u64 cpu_time_get_running(struct cpus_time *ct, int cpu, u64 now)
+{
+       return tm_stat_current_running(&ct->tm[cpu], now);
+}
+
+static void *cpus_time_get_running_all(struct cpus_time *ct, u64 *buf, u64 now)
+{
+       int cpu;
+
+       for (cpu = 0; cpu < NR_CPUS; ++cpu)
+               buf[cpu] = tm_stat_current_running(&ct->tm[cpu], now);
+
+       return buf;
+}
+
+static void *cpus_time_sum_running_all(struct cpus_time *ct, u64 *buf, u64 now)
+{
+       int cpu;
+
+       for (cpu = 0; cpu < NR_CPUS; ++cpu)
+               buf[cpu] += tm_stat_current_running(&ct->tm[cpu], now);
+
+       return buf;
+}
+
+static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
+{
+       struct tm_stat *tm = &ct->tm[cpu];
+
+       if (unlikely(tm_stat_timestamp(tm))) /* should never happen */
+               printk(KERN_INFO "XXX %s[%d/%d]: WARNING tmstamp(%p) set on cpu(%d)\n",
+                      current->comm, current->tgid, current->pid, tm, cpu);
+       tm_stat_set_timestamp(&ct->tm[cpu], time);
+}
+
+static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 now,
+                                    u64 start_time)
+{
+       struct tm_stat *tm = &ct->tm[cpu];
+
+       if (unlikely(tm_stat_timestamp(tm) == 0)) {
+               /* not initialized. should happen only once per cpu/task */
+               printk(KERN_INFO "XXX %s[%d/%d]: nnitializing tmstamp(%p) "
+                      "on cpu(%d)\n",
+                      current->comm, current->tgid, current->pid, tm, cpu);
+               tm_stat_set_timestamp(tm, start_time);
+       }
+
+       tm_stat_update(tm, now);
+       tm_stat_set_timestamp(tm, 0); /* set timestamp to 0 */
+}
+
+
+
+
+
+struct energy_data {
+       /* for __switch_to */
+       struct cpus_time ct;
+
+       /* for sys_read */
+       atomic64_t bytes_read;
+
+       /*for sys_write */
+       atomic64_t bytes_written;
+
+       /*for recvmsg*/
+       atomic64_t bytes_recv;
+
+       /* for sock_send */
+       atomic64_t bytes_send;
+
+       /* for l2cap_recv */
+       atomic64_t bytes_l2cap_recv_acldata;
+
+       /* for sco_recv_scodata */
+       atomic64_t bytes_sco_recv_scodata;
+
+       /* for hci_send_acl */
+       atomic64_t bytes_hci_send_acl;
+
+       /* for hci_send_sco */
+       atomic64_t bytes_hci_send_sco;
+};
+
+static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
+
+static void init_ed(struct energy_data *ed)
+{
+       /* instead of get_ntime(), CPU time is initialized to 0 here. Timestamp
+        * value will be properly set when the corresponding __switch_to event
+        * occurs */
+       cpus_time_init(&ed->ct, 0);
+       atomic64_set(&ed->bytes_read, 0);
+       atomic64_set(&ed->bytes_written, 0);
+       atomic64_set(&ed->bytes_recv, 0);
+       atomic64_set(&ed->bytes_send, 0);
+       atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
+       atomic64_set(&ed->bytes_sco_recv_scodata, 0);
+       atomic64_set(&ed->bytes_hci_send_acl, 0);
+       atomic64_set(&ed->bytes_hci_send_sco, 0);
+}
+
+static void uninit_ed(struct energy_data *ed)
+{
+       cpus_time_init(&ed->ct, 0);
+       atomic64_set(&ed->bytes_read, 0);
+       atomic64_set(&ed->bytes_written, 0);
+       atomic64_set(&ed->bytes_recv, 0);
+       atomic64_set(&ed->bytes_send, 0);
+       atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
+       atomic64_set(&ed->bytes_sco_recv_scodata, 0);
+       atomic64_set(&ed->bytes_hci_send_acl, 0);
+       atomic64_set(&ed->bytes_hci_send_sco, 0);
+}
+
+static void *create_ed(void)
+{
+       struct energy_data *ed;
+
+       ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
+       if (ed)
+               init_ed(ed);
+
+       return (void *)ed;
+}
+
+static void destroy_ed(void *data)
+{
+       struct energy_data *ed = (struct energy_data *)data;
+       kfree(ed);
+}
+
+
+static int init_feature(void)
+{
+       feature_id = sspt_register_feature(create_ed, destroy_ed);
+
+       if (feature_id == SSPT_FEATURE_ID_BAD)
+               return -EPERM;
+
+       return 0;
+}
+
+static void uninit_feature(void)
+{
+       sspt_unregister_feature(feature_id);
+       feature_id = SSPT_FEATURE_ID_BAD;
+}
+
+static struct energy_data *get_energy_data(struct task_struct *task)
+{
+       void *data = NULL;
+       struct sspt_proc *proc;
+
+       proc = sspt_proc_by_task(task);
+       if (proc)
+               data = sspt_get_feature_data(proc->feature, feature_id);
+
+       return (struct energy_data *)data;
+}
+
+static int check_fs(unsigned long magic)
+{
+       switch (magic) {
+       case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
+       case MSDOS_SUPER_MAGIC:
+               return 1;
+       }
+
+       return 0;
+}
+
+static int check_ftype(int fd)
+{
+       int err, ret = 0;
+       struct kstat kstat;
+
+       err = vfs_fstat(fd, &kstat);
+       if (err == 0 && S_ISREG(kstat.mode))
+               ret = 1;
+
+       return ret;
+}
+
+static int check_file(int fd)
+{
+       struct file *file;
+
+       file = fget(fd);
+       if (file) {
+               int magic = 0;
+               if (file->f_path.dentry && file->f_path.dentry->d_sb)
+                       magic = file->f_path.dentry->d_sb->s_magic;
+
+               fput(file);
+
+               if (check_fs(magic) && check_ftype(fd))
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+
+
+
+static struct cpus_time ct_idle;
+static struct energy_data ed_system;
+static u64 start_time;
+
+static void init_data_energy(void)
+{
+       start_time = get_ntime();
+       init_ed(&ed_system);
+       cpus_time_init(&ct_idle, 0);
+}
+
+static void uninit_data_energy(void)
+{
+       start_time = 0;
+       uninit_ed(&ed_system);
+       cpus_time_init(&ct_idle, 0);
+}
+
+
+
+
+
+/* ============================================================================
+ * =                             __switch_to                                  =
+ * ============================================================================
+ */
+static void do_entry_handler_switch(struct task_struct *task)
+{
+       int cpu;
+       struct cpus_time *ct;
+       struct energy_data *ed;
+       unsigned long flags;
+
+       cpu = smp_processor_id();
+
+       ct = task->tgid ? &ed_system.ct : &ct_idle;
+       cpus_time_lock(ct, flags);
+       cpus_time_update_running(ct, cpu, get_ntime(), start_time);
+       cpus_time_unlock(ct, flags);
+
+       ed = get_energy_data(task);
+       if (ed) {
+               ct = &ed->ct;
+               cpus_time_lock(ct, flags);
+               cpus_time_update_running(ct, cpu, get_ntime(), start_time);
+               cpus_time_unlock(ct, flags);
+       }
+}
+
+static void do_ret_handler_switch(struct task_struct *task)
+{
+       int cpu;
+       struct cpus_time *ct;
+       struct energy_data *ed;
+       unsigned long flags;
+
+       cpu = smp_processor_id();
+
+       ct = task->tgid ? &ed_system.ct : &ct_idle;
+       cpus_time_lock(ct, flags);
+       cpus_time_save_entry(ct, cpu, get_ntime());
+       cpus_time_unlock(ct, flags);
+
+       ed = get_energy_data(task);
+       if (ed) {
+               ct = &ed->ct;
+               cpus_time_lock(ct, flags);
+               cpus_time_save_entry(ct, cpu, get_ntime());
+               cpus_time_unlock(ct, flags);
+       }
+}
+
+#ifndef CONFIG_SWAP_HOOK_SWITCH_TO
+static int ret_handler_switch(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       do_ret_handler_switch(current);
+       return 0;
+}
+
+static int entry_handler_switch(struct kretprobe_instance *ri,
+                               struct pt_regs *regs)
+{
+       do_entry_handler_switch(current);
+       return 0;
+}
+
+static struct kretprobe switch_to_krp = {
+       .entry_handler = entry_handler_switch,
+       .handler = ret_handler_switch,
+};
+#endif /* !CONFIG_SWAP_HOOK_SWITCH_TO */
+
+
+
+
+
+/* ============================================================================
+ * =                                sys_read                                  =
+ * ============================================================================
+ */
+struct sys_read_data {
+       int fd;
+};
+
+#ifndef CONFIG_SWAP_HOOK_ENERGY
+static int entry_handler_sys_read(struct kretprobe_instance *ri,
+                                 struct pt_regs *regs)
+{
+       struct sys_read_data *srd = (struct sys_read_data *)ri->data;
+
+       srd->fd = (int)swap_get_sarg(regs, 0);
+
+       return 0;
+}
+
+static int ret_handler_sys_read(struct kretprobe_instance *ri,
+                               struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+
+       if (ret > 0) {
+               struct sys_read_data *srd;
+
+               srd = (struct sys_read_data *)ri->data;
+               if (check_file(srd->fd)) {
+                       struct energy_data *ed;
+
+                       ed = get_energy_data(current);
+                       if (ed)
+                               atomic64_add(ret, &ed->bytes_read);
+
+                       atomic64_add(ret, &ed_system.bytes_read);
+               }
+       }
+
+       return 0;
+}
+
+static struct kretprobe sys_read_krp = {
+       .entry_handler = entry_handler_sys_read,
+       .handler = ret_handler_sys_read,
+       .data_size = sizeof(struct sys_read_data)
+};
+
+
+
+
+
+/* ============================================================================
+ * =                               sys_write                                  =
+ * ============================================================================
+ */
+static int entry_handler_sys_write(struct kretprobe_instance *ri,
+                                  struct pt_regs *regs)
+{
+       struct sys_read_data *srd = (struct sys_read_data *)ri->data;
+
+       srd->fd = (int)swap_get_sarg(regs, 0);
+
+       return 0;
+}
+
+static int ret_handler_sys_write(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+
+       if (ret > 0) {
+               struct sys_read_data *srd;
+
+               srd = (struct sys_read_data *)ri->data;
+               if (check_file(srd->fd)) {
+                       struct energy_data *ed;
+
+                       ed = get_energy_data(current);
+                       if (ed)
+                               atomic64_add(ret, &ed->bytes_written);
+
+                       atomic64_add(ret, &ed_system.bytes_written);
+               }
+       }
+
+       return 0;
+}
+
+static struct kretprobe sys_write_krp = {
+       .entry_handler = entry_handler_sys_write,
+       .handler = ret_handler_sys_write,
+       .data_size = sizeof(struct sys_read_data)
+};
+#endif /* !CONFIG_SWAP_HOOK_ENERGY */
+
+
+
+
+
+/* ============================================================================
+ * =                                wifi                                      =
+ * ============================================================================
+ */
+static bool check_wlan0(struct socket *sock)
+{
+       /* FIXME: hardcode interface */
+       const char *name_intrf = "wlan0";
+
+       if (sock->sk->sk_dst_cache &&
+           sock->sk->sk_dst_cache->dev &&
+           !strcmp(sock->sk->sk_dst_cache->dev->name, name_intrf))
+               return true;
+
+       return false;
+}
+
+static bool check_socket(struct task_struct *task, struct socket *socket)
+{
+       bool ret = false;
+       unsigned int fd;
+       struct files_struct *files;
+
+       files = swap_get_files_struct(task);
+       if (files == NULL)
+               return false;
+
+       rcu_read_lock();
+       for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
+               if (fcheck_files(files, fd) == socket->file) {
+                       ret = true;
+                       goto unlock;
+               }
+       }
+
+unlock:
+       rcu_read_unlock();
+       swap_put_files_struct(files);
+       return ret;
+}
+
+static struct energy_data *get_energy_data_by_socket(struct task_struct *task,
+                                                    struct socket *socket)
+{
+       struct energy_data *ed;
+
+       ed = get_energy_data(task);
+       if (ed)
+               ed = check_socket(task, socket) ? ed : NULL;
+
+       return ed;
+}
+
+#ifndef CONFIG_SWAP_HOOK_ENERGY
+static int wf_sock_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct socket *socket = (struct socket *)swap_get_karg(regs, 0);
+
+       *(struct socket **)ri->data = socket;
+
+       return 0;
+}
+
+static int wf_sock_aio_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct kiocb *iocb = (struct kiocb *)swap_get_karg(regs, 0);
+       struct socket *socket = iocb->ki_filp->private_data;
+
+       *(struct socket **)ri->data = socket;
+
+       return 0;
+}
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
+static void calc_wifi_recv_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
+
+       if (len <= 0 || !check_wlan0(sock))
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_recv);
+       atomic64_add(len, &ed_system.bytes_recv);
+}
+
+static void calc_wifi_send_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
+
+       if (len <= 0 || !check_wlan0(sock))
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_send);
+       atomic64_add(len, &ed_system.bytes_send);
+}
+
+#ifndef CONFIG_SWAP_HOOK_ENERGY
+static int wf_sock_recv_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+
+       calc_wifi_recv_energy(*(struct socket **)ri->data, ret);
+
+       return 0;
+}
+
+static int wf_sock_send_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+
+       calc_wifi_send_energy(*(struct socket **)ri->data, ret);
+
+       return 0;
+}
+
+static struct kretprobe sock_recv_krp = {
+       .entry_handler = wf_sock_eh,
+       .handler = wf_sock_recv_rh,
+       .data_size = sizeof(struct socket *)
+};
+
+static struct kretprobe sock_send_krp = {
+       .entry_handler = wf_sock_eh,
+       .handler = wf_sock_send_rh,
+       .data_size = sizeof(struct socket *)
+};
+
+static struct kretprobe sock_aio_read_krp = {
+       .entry_handler = wf_sock_aio_eh,
+       .handler = wf_sock_recv_rh,
+       .data_size = sizeof(struct socket *)
+};
+
+static struct kretprobe sock_aio_write_krp = {
+       .entry_handler = wf_sock_aio_eh,
+       .handler = wf_sock_send_rh,
+       .data_size = sizeof(struct socket *)
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+static const char sock_aio_read[] = "sock_read_iter";
+static const char sock_aio_write[] = "sock_write_iter";
+#else  /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
+static const char sock_aio_read[] = "sock_aio_read";
+static const char sock_aio_write[] = "sock_aio_write";
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
+
+static struct kern_probe wifi_probes[] = {
+       {
+               .name = "sock_recvmsg",
+               .rp = &sock_recv_krp,
+       },
+       {
+               .name = "sock_sendmsg",
+               .rp = &sock_send_krp,
+       },
+       {
+               .name = sock_aio_read,
+               .rp = &sock_aio_read_krp,
+       },
+       {
+               .name = sock_aio_write,
+               .rp = &sock_aio_write_krp,
+       }
+};
+
+enum { wifi_probes_cnt = ARRAY_SIZE(wifi_probes) };
+static int wifi_flag = 0;
+#endif /* !CONFIG_SWAP_HOOK_ENERGY */
+
+
+
+
+
+/* ============================================================================
+ * =                                bluetooth                                 =
+ * ============================================================================
+ */
+
+struct swap_bt_data {
+       struct socket *socket;
+};
+
+static void calc_bt_recv_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
+
+       if (len <= 0 || !sock)
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_l2cap_recv_acldata);
+       atomic64_add(len, &ed_system.bytes_l2cap_recv_acldata);
+}
+
+static void calc_bt_send_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
+
+       if (len <= 0 || !sock)
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_hci_send_sco);
+       atomic64_add(len, &ed_system.bytes_hci_send_sco);
+}
+
+#ifndef CONFIG_SWAP_HOOK_ENERGY
+static int bt_entry_handler(struct kretprobe_instance *ri,
+                           struct pt_regs *regs)
+{
+       struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
+       struct socket *sock = (struct socket *)swap_get_sarg(regs, 1);
+
+       data->socket = sock ? sock : NULL;
+
+       return 0;
+}
+
+static int bt_recvmsg_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
+
+       calc_bt_recv_energy(data->socket, ret);
+
+       return 0;
+}
+
+static int bt_sendmsg_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
+
+       calc_bt_send_energy(data->socket, ret);
+
+       return 0;
+}
+
+static struct kretprobe rfcomm_sock_recvmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_recvmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kretprobe l2cap_sock_recvmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_recvmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kretprobe hci_sock_recvmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_recvmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kretprobe sco_sock_recvmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_recvmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+static struct kretprobe rfcomm_sock_sendmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_sendmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kretprobe l2cap_sock_sendmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_sendmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kretprobe hci_sock_sendmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_sendmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kretprobe sco_sock_sendmsg_krp = {
+       .entry_handler = bt_entry_handler,
+       .handler = bt_sendmsg_handler,
+       .data_size = sizeof(struct swap_bt_data)
+};
+
+static struct kern_probe bt_probes[] = {
+       {
+               .name = "rfcomm_sock_recvmsg",
+               .rp = &rfcomm_sock_recvmsg_krp,
+       },
+       {
+               .name = "l2cap_sock_recvmsg",
+               .rp = &l2cap_sock_recvmsg_krp,
+       },
+       {
+               .name = "hci_sock_recvmsg",
+               .rp = &hci_sock_recvmsg_krp,
+       },
+       {
+               .name = "sco_sock_recvmsg",
+               .rp = &sco_sock_recvmsg_krp,
+       },
+       {
+               .name = "rfcomm_sock_sendmsg",
+               .rp = &rfcomm_sock_sendmsg_krp,
+       },
+       {
+               .name = "l2cap_sock_sendmsg",
+               .rp = &l2cap_sock_sendmsg_krp,
+       },
+       {
+               .name = "hci_sock_sendmsg",
+               .rp = &hci_sock_sendmsg_krp,
+       },
+       {
+               .name = "sco_sock_sendmsg",
+               .rp = &sco_sock_sendmsg_krp,
+       }
+};
+
+enum { bt_probes_cnt = ARRAY_SIZE(bt_probes) };
+static int energy_bt_flag = 0;
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
+enum parameter_type {
+       PT_CPU,
+       PT_READ,
+       PT_WRITE,
+       PT_WF_RECV,
+       PT_WF_SEND,
+       PT_L2CAP_RECV,
+       PT_SCO_RECV,
+       PT_SEND_ACL,
+       PT_SEND_SCO
+};
+
+struct cmd_pt {
+       enum parameter_type pt;
+       void *buf;
+       int sz;
+};
+
+static void callback_for_proc(struct sspt_proc *proc, void *data)
+{
+       void *f_data = sspt_get_feature_data(proc->feature, feature_id);
+       struct energy_data *ed = (struct energy_data *)f_data;
+
+       if (ed) {
+               unsigned long flags;
+               struct cmd_pt *cmdp = (struct cmd_pt *)data;
+               u64 *val = cmdp->buf;
+
+               switch (cmdp->pt) {
+               case PT_CPU:
+                       cpus_time_lock(&ed->ct, flags);
+                       cpus_time_sum_running_all(&ed->ct, val, get_ntime());
+                       cpus_time_unlock(&ed->ct, flags);
+                       break;
+               case PT_READ:
+                       *val += atomic64_read(&ed->bytes_read);
+                       break;
+               case PT_WRITE:
+                       *val += atomic64_read(&ed->bytes_written);
+                       break;
+               case PT_WF_RECV:
+                       *val += atomic64_read(&ed->bytes_recv);
+                       break;
+               case PT_WF_SEND:
+                       *val += atomic64_read(&ed->bytes_send);
+                       break;
+               case PT_L2CAP_RECV:
+                       *val += atomic64_read(&ed->bytes_l2cap_recv_acldata);
+                       break;
+               case PT_SCO_RECV:
+                       *val += atomic64_read(&ed->bytes_sco_recv_scodata);
+                       break;
+               case PT_SEND_ACL:
+                       *val += atomic64_read(&ed->bytes_hci_send_acl);
+                       break;
+               case PT_SEND_SCO:
+                       *val += atomic64_read(&ed->bytes_hci_send_sco);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int current_parameter_apps(enum parameter_type pt, void *buf, int sz)
+{
+       struct cmd_pt cmdp;
+
+       cmdp.pt = pt;
+       cmdp.buf = buf;
+       cmdp.sz = sz;
+
+       on_each_proc(callback_for_proc, (void *)&cmdp);
+
+       return 0;
+}
+
+/**
+ * @brief Get energy parameter
+ *
+ * @param pe Type of energy parameter
+ * @param buf Buffer
+ * @param sz Buffer size
+ * @return Error code
+ */
+int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz)
+{
+       unsigned long flags;
+       u64 *val = buf; /* currently all parameters are u64 vals */
+       int ret = 0;
+
+       switch (pe) {
+       case PE_TIME_IDLE:
+               cpus_time_lock(&ct_idle, flags);
+               /* for the moment we consider only CPU[0] idle time */
+               *val = cpu_time_get_running(&ct_idle, 0, get_ntime());
+               cpus_time_unlock(&ct_idle, flags);
+               break;
+       case PE_TIME_SYSTEM:
+               cpus_time_lock(&ed_system.ct, flags);
+               cpus_time_get_running_all(&ed_system.ct, val, get_ntime());
+               cpus_time_unlock(&ed_system.ct, flags);
+               break;
+       case PE_TIME_APPS:
+               current_parameter_apps(PT_CPU, buf, sz);
+               break;
+       case PE_READ_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_read);
+               break;
+       case PE_WRITE_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_written);
+               break;
+       case PE_WF_RECV_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_recv);
+               break;
+       case PE_WF_SEND_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_send);
+               break;
+       case PE_L2CAP_RECV_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_l2cap_recv_acldata);
+               break;
+       case PE_SCO_RECV_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_sco_recv_scodata);
+               break;
+       case PT_SEND_ACL_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_hci_send_acl);
+               break;
+       case PT_SEND_SCO_SYSTEM:
+               *val = atomic64_read(&ed_system.bytes_hci_send_sco);
+               break;
+       case PE_READ_APPS:
+               current_parameter_apps(PT_READ, buf, sz);
+               break;
+       case PE_WRITE_APPS:
+               current_parameter_apps(PT_WRITE, buf, sz);
+               break;
+       case PE_WF_RECV_APPS:
+               current_parameter_apps(PT_WF_RECV, buf, sz);
+               break;
+       case PE_WF_SEND_APPS:
+               current_parameter_apps(PT_WF_SEND, buf, sz);
+               break;
+       case PE_L2CAP_RECV_APPS:
+               current_parameter_apps(PT_L2CAP_RECV, buf, sz);
+               break;
+       case PE_SCO_RECV_APPS:
+               current_parameter_apps(PT_SCO_RECV, buf, sz);
+               break;
+       case PT_SEND_ACL_APPS:
+               current_parameter_apps(PT_SEND_ACL, buf, sz);
+               break;
+       case PT_SEND_SCO_APPS:
+               current_parameter_apps(PT_SEND_SCO, buf, sz);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_SWAP_HOOK_ENERGY
+static struct swap_hook_energy hook_energy = {
+       .bt_recvmsg = calc_bt_recv_energy,
+       .bt_sendmsg = calc_bt_send_energy,
+       .wifi_recvmsg = calc_wifi_recv_energy ,
+       .wifi_sendmsg = calc_wifi_send_energy
+};
+
+
+static struct td_raw sys_call_tdraw;
+
+static void entry_hook_sys_rw(struct hook_syscall *self, struct pt_regs *regs)
+{
+       struct sys_read_data *srd =
+               (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
+       srd->fd = (int)swap_get_sarg(regs, 0);
+}
+
+static void return_hook_sys_read(struct hook_syscall *self,
+                                struct pt_regs *regs)
+{
+       struct sys_read_data *srd;
+       struct energy_data *ed;
+       int ret = regs_return_value(regs);
+
+       if (ret <= 0)
+               return;
+
+       srd = (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
+       if (!check_file(srd->fd))
+               return;
+
+       ed = get_energy_data(current);
+       if (ed)
+               atomic64_add(ret, &ed->bytes_read);
+       atomic64_add(ret, &ed_system.bytes_read);
+}
+
+static void return_hook_sys_write(struct hook_syscall *self,
+                                 struct pt_regs *regs)
+{
+       struct sys_read_data *srd;
+       struct energy_data *ed;
+       int ret = regs_return_value(regs);
+
+       if (ret > 0)
+               return;
+
+       srd = (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
+       if (!check_file(srd->fd))
+               return;
+
+       ed = get_energy_data(current);
+       if (ed)
+               atomic64_add(ret, &ed->bytes_written);
+       atomic64_add(ret, &ed_system.bytes_written);
+}
+
+static struct hook_syscall sys_read_hook = {
+       .entry = entry_hook_sys_rw,
+       .exit = return_hook_sys_read
+};
+
+static struct hook_syscall sys_write_hook = {
+       .entry = entry_hook_sys_rw,
+       .exit = return_hook_sys_write
+};
+
+
+# ifdef CONFIG_SWAP_HOOK_SWITCH_TO
+static void handler_switch(struct task_struct *prev,
+                          struct task_struct *next)
+{
+       do_entry_handler_switch(prev);
+       do_ret_handler_switch(next);
+}
+
+static struct swap_hook_ctx switch_to_hook = {
+       .hook = handler_switch
+};
+# endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
+
+int do_set_energy(void)
+{
+       int ret = 0;
+
+       init_data_energy();
+
+       swap_hook_ctx_reg(&switch_to_hook);
+       ret = swap_td_raw_reg(&sys_call_tdraw, sizeof(struct sys_read_data));
+       if (ret)
+               return ret;
+
+       hook_syscall_reg(&sys_read_hook, __NR_read);
+       hook_syscall_reg(&sys_write_hook, __NR_write);
+
+       /* TODO: add compat mode support */
+
+       swap_hook_energy_set(&hook_energy);
+       /* TODO: init lcd */
+
+       return ret;
+}
+
+void do_unset_energy(void)
+{
+       /* TODO: uinit lcd */
+       swap_hook_energy_unset();
+       swap_hook_ctx_unreg(&switch_to_hook);
+       hook_syscall_unreg(&sys_write_hook);
+       hook_syscall_unreg(&sys_read_hook);
+
+       swap_td_raw_unreg(&sys_call_tdraw);
+       uninit_data_energy();
+}
+
+int energy_once(void)
+{
+       return 0;
+}
+#else /* CONFIG_SWAP_HOOK_ENERGY */
+
+int do_set_energy(void)
+{
+       int ret = 0;
+
+       init_data_energy();
+
+       ret = swap_register_kretprobe(&sys_read_krp);
+       if (ret) {
+               printk(KERN_INFO "swap_register_kretprobe(sys_read) "
+                      "result=%d!\n", ret);
+               return ret;
+       }
+
+       ret = swap_register_kretprobe(&sys_write_krp);
+       if (ret != 0) {
+               printk(KERN_INFO "swap_register_kretprobe(sys_write) "
+                      "result=%d!\n", ret);
+               goto unregister_sys_read;
+       }
+
+       ret = swap_register_kretprobe(&switch_to_krp);
+       if (ret) {
+               printk(KERN_INFO "swap_register_kretprobe(__switch_to) "
+                      "result=%d!\n",
+                      ret);
+               goto unregister_sys_write;
+       }
+
+       energy_xxx_set(bt_probes, bt_probes_cnt, &energy_bt_flag);
+       energy_xxx_set(wifi_probes, wifi_probes_cnt, &wifi_flag);
+
+       /* TODO: check return value */
+       lcd_set_energy();
+
+       return ret;
+
+unregister_sys_read:
+       swap_unregister_kretprobe(&sys_read_krp);
+
+unregister_sys_write:
+       swap_unregister_kretprobe(&sys_write_krp);
+
+       return ret;
+}
+
+void do_unset_energy(void)
+{
+       lcd_unset_energy();
+       energy_xxx_unset(wifi_probes, wifi_probes_cnt, &wifi_flag);
+       energy_xxx_unset(bt_probes, bt_probes_cnt, &energy_bt_flag);
+
+       swap_unregister_kretprobe(&switch_to_krp);
+       swap_unregister_kretprobe(&sys_write_krp);
+       swap_unregister_kretprobe(&sys_read_krp);
+
+       uninit_data_energy();
+}
+
+int energy_once(void)
+{
+       const char *sym;
+
+       sym = "__switch_to";
+       switch_to_krp.kp.addr = swap_ksyms(sym);
+       if (switch_to_krp.kp.addr == 0)
+               goto not_found;
+
+       sym = "sys_read";
+       sys_read_krp.kp.addr = swap_ksyms(sym);
+       if (sys_read_krp.kp.addr == 0)
+               goto not_found;
+
+       sym = "sys_write";
+       sys_write_krp.kp.addr = swap_ksyms(sym);
+       if (sys_write_krp.kp.addr == 0)
+               goto not_found;
+
+       energy_xxx_once(bt_probes, bt_probes_cnt);
+       energy_xxx_once(wifi_probes, wifi_probes_cnt);
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
+static DEFINE_MUTEX(mutex_enable);
+static int energy_enable;
+
+/**
+ * @brief Start measuring the energy consumption
+ *
+ * @return Error code
+ */
+int set_energy(void)
+{
+       int ret = -EINVAL;
+
+       mutex_lock(&mutex_enable);
+       if (energy_enable) {
+               printk(KERN_INFO "energy profiling is already run!\n");
+               goto unlock;
+       }
+
+       ret = do_set_energy();
+       if (ret == 0)
+               energy_enable = 1;
+
+unlock:
+       mutex_unlock(&mutex_enable);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(set_energy);
+
+/**
+ * @brief Stop measuring the energy consumption
+ *
+ * @return Error code
+ */
+int unset_energy(void)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_enable);
+       if (energy_enable == 0) {
+               printk(KERN_INFO "energy profiling is not running!\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       do_unset_energy();
+
+       energy_enable = 0;
+unlock:
+       mutex_unlock(&mutex_enable);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(unset_energy);
+
+/**
+ * @brief Initialization energy
+ *
+ * @return Error code
+ */
+int energy_init(void)
+{
+       int ret;
+
+       ret = init_feature();
+       if (ret)
+               printk(KERN_INFO "Cannot init feature\n");
+
+       return ret;
+}
+
+/**
+ * @brief Deinitialization energy
+ *
+ * @return Void
+ */
+void energy_uninit(void)
+{
+       uninit_feature();
+
+       if (energy_enable)
+               do_unset_energy();
+}
diff --git a/modules/energy/energy.h b/modules/energy/energy.h
new file mode 100644 (file)
index 0000000..7466570
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _ENERGY_H
+#define _ENERGY_H
+
+/**
+ * @file energy/energy.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @section LICENCE
+ * 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
+ *
+ */
+
+
+#include <linux/types.h>
+
+
+/** Description of parameters */
+enum parameter_energy {
+       PE_TIME_IDLE,           /**< IDLE working time */
+       PE_TIME_SYSTEM,         /**< system working time */
+       PE_TIME_APPS,           /**< apps working time */
+       PE_READ_SYSTEM,         /**< number of bytes are read by system */
+       PE_WRITE_SYSTEM,        /**< number of bytes are write by system */
+       PE_READ_APPS,           /**< number of bytes are read by apps */
+       PE_WRITE_APPS,          /**< number of bytes are write by apps */
+       PE_WF_RECV_SYSTEM,      /**< number of bytes are receive by system through wifi */
+       PE_WF_SEND_SYSTEM,      /**< number of bytes are send by system through wifi */
+       PE_WF_RECV_APPS,        /**< number of bytes are receive by apps through wifi */
+       PE_WF_SEND_APPS,        /**< number of bytes are send by apps through wifi */
+       PE_L2CAP_RECV_SYSTEM,   /**< number of bytes(ACL packets) are recv by system through bluetooth */
+       PE_L2CAP_RECV_APPS,     /**< number of bytes(ACL packets) are recv by apps through bluetooth */
+       PE_SCO_RECV_SYSTEM,     /**< number of bytes(SCO packets) are recv by system through bluetooth */
+       PE_SCO_RECV_APPS,       /**< number of bytes(SCO packets) are recv by apps through bluetooth */
+       PT_SEND_ACL_SYSTEM,     /**< number of bytes(ACL packets) are send by system through bluetooth */
+       PT_SEND_ACL_APPS,       /**< number of bytes(ACL packets) are send by apps through bluetooth */
+       PT_SEND_SCO_SYSTEM,     /**< number of bytes(SCO packets) are send by system through bluetooth */
+       PT_SEND_SCO_APPS,       /**< number of bytes(SCO packets) are send by apps through bluetooth */
+};
+
+
+int energy_once(void);
+int energy_init(void);
+void energy_uninit(void);
+
+int set_energy(void);
+int unset_energy(void);
+
+int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz);
+
+#endif /* _ENERGY_H */
diff --git a/modules/energy/energy_module.c b/modules/energy/energy_module.c
new file mode 100644 (file)
index 0000000..b4ac328
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  energy/energy_mod.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <master/swap_initializer.h>
+#include "energy.h"
+#include "debugfs_energy.h"
+
+
+SWAP_LIGHT_INIT_MODULE(energy_once, energy_init, energy_uninit,
+                      init_debugfs_energy, exit_debugfs_energy);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/energy/lcd/lcd_base.c b/modules/energy/lcd/lcd_base.c
new file mode 100644 (file)
index 0000000..12ee466
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  energy/lcd/lcd_base.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <energy/tm_stat.h>
+#include <energy/debugfs_energy.h>
+#include "lcd_base.h"
+#include "lcd_debugfs.h"
+
+
+/**
+ * @brief Read the number of file
+ *
+ * @param path of the file
+ * @return Value or error(when negative)
+ */
+int read_val(const char *path)
+{
+       int ret;
+       struct file *f;
+       unsigned long val;
+       enum { buf_len = 32 };
+       char buf[buf_len];
+
+       f = filp_open(path, O_RDONLY, 0);
+       if (IS_ERR(f)) {
+               printk(KERN_INFO "cannot open file \'%s\'", path);
+               return PTR_ERR(f);
+       }
+
+       ret = kernel_read(f, 0, buf, sizeof(buf));
+       filp_close(f, NULL);
+       if (ret < 0)
+               return ret;
+
+       buf[ret >= buf_len ? buf_len - 1 : ret] = '\0';
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       return (int)val;
+}
+
+enum {
+       brt_no_init = -1,
+       brt_cnt = 10
+};
+
+enum power_t {
+       PW_ON,
+       PW_OFF
+};
+
+struct lcd_priv_data {
+       int min_brt;
+       int max_brt;
+
+       size_t tms_brt_cnt;
+       struct tm_stat *tms_brt;
+       spinlock_t lock_tms;
+       int brt_old;
+       enum power_t power;
+
+       u64 min_denom;
+       u64 min_num;
+       u64 max_denom;
+       u64 max_num;
+};
+
+static void *create_lcd_priv(struct lcd_ops *ops, size_t tms_brt_cnt)
+{
+       int i;
+       struct lcd_priv_data *lcd;
+
+       if (tms_brt_cnt <= 0) {
+               printk(KERN_INFO "error variable tms_brt_cnt=%zu\n",
+                      tms_brt_cnt);
+               return NULL;
+       }
+
+       lcd = kmalloc(sizeof(*lcd) + sizeof(*lcd->tms_brt) * tms_brt_cnt,
+                     GFP_KERNEL);
+       if (lcd == NULL) {
+               printk(KERN_INFO "error: %s - out of memory\n", __func__);
+               return NULL;
+       }
+
+       lcd->tms_brt = (void *)lcd + sizeof(*lcd);
+       lcd->tms_brt_cnt = tms_brt_cnt;
+
+       lcd->min_brt = ops->get(ops, LPD_MIN_BRIGHTNESS);
+       lcd->max_brt = ops->get(ops, LPD_MAX_BRIGHTNESS);
+
+       for (i = 0; i < tms_brt_cnt; ++i)
+               tm_stat_init(&lcd->tms_brt[i]);
+
+       spin_lock_init(&lcd->lock_tms);
+
+       lcd->brt_old = brt_no_init;
+       lcd->power = PW_OFF;
+
+       lcd->min_denom = 1;
+       lcd->min_num = 1;
+       lcd->max_denom = 1;
+       lcd->max_num = 1;
+
+       return (void *)lcd;
+}
+
+static void destroy_lcd_priv(void *data)
+{
+       kfree(data);
+}
+
+static struct lcd_priv_data *get_lcd_priv(struct lcd_ops *ops)
+{
+       return (struct lcd_priv_data *)ops->priv;
+}
+
+static void clean_brightness(struct lcd_ops *ops)
+{
+       struct lcd_priv_data *lcd = get_lcd_priv(ops);
+       int i;
+
+       spin_lock(&lcd->lock_tms);
+       for (i = 0; i < lcd->tms_brt_cnt; ++i)
+               tm_stat_init(&lcd->tms_brt[i]);
+
+       lcd->brt_old = brt_no_init;
+       spin_unlock(&lcd->lock_tms);
+}
+
+static int get_brt_num_of_array(struct lcd_priv_data *lcd, int brt)
+{
+       if (brt > lcd->max_brt || brt < lcd->min_brt) {
+               printk(KERN_INFO "LCD energy error: set brightness=%d, "
+                      "when brightness[%d..%d]\n",
+                      brt, lcd->min_brt, lcd->max_brt);
+               brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt;
+       }
+
+       return lcd->tms_brt_cnt * (brt - lcd->min_brt) /
+              (lcd->max_brt - lcd->min_brt + 1);
+}
+
+static void set_brightness(struct lcd_ops *ops, int brt)
+{
+       struct lcd_priv_data *lcd = get_lcd_priv(ops);
+       int n = get_brt_num_of_array(lcd, brt);
+
+       spin_lock(&lcd->lock_tms);
+
+       if (lcd->power == PW_ON && lcd->brt_old != n) {
+               u64 time = get_ntime();
+               if (lcd->brt_old != brt_no_init)
+                       tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
+
+               tm_stat_set_timestamp(&lcd->tms_brt[n], time);
+       }
+       lcd->brt_old = n;
+
+       spin_unlock(&lcd->lock_tms);
+}
+
+static void set_power_on_set_brt(struct lcd_priv_data *lcd)
+{
+       if (lcd->brt_old != brt_no_init) {
+               u64 time = get_ntime();
+               tm_stat_set_timestamp(&lcd->tms_brt[lcd->brt_old], time);
+       }
+}
+
+static void set_power_on(struct lcd_priv_data *lcd)
+{
+       if (lcd->power == PW_OFF)
+               set_power_on_set_brt(lcd);
+
+       lcd->power = PW_ON;
+}
+
+static void set_power_off_update_brt(struct lcd_priv_data *lcd)
+{
+       if (lcd->brt_old != brt_no_init) {
+               u64 time = get_ntime();
+               tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
+               lcd->brt_old = brt_no_init;
+       }
+}
+
+static void set_power_off(struct lcd_priv_data *lcd)
+{
+       if (lcd->power == PW_ON)
+               set_power_off_update_brt(lcd);
+
+       lcd->power = PW_OFF;
+}
+
+static void set_power(struct lcd_ops *ops, int val)
+{
+       struct lcd_priv_data *lcd = get_lcd_priv(ops);
+
+       spin_lock(&lcd->lock_tms);
+
+       switch (val) {
+       case FB_BLANK_UNBLANK:
+               set_power_on(lcd);
+               break;
+       case FB_BLANK_POWERDOWN:
+               set_power_off(lcd);
+               break;
+       default:
+               printk(KERN_INFO "LCD energy error: set power=%d\n", val);
+               break;
+       }
+
+       spin_unlock(&lcd->lock_tms);
+}
+
+static int func_notifier_lcd(struct lcd_ops *ops, enum lcd_action_type action,
+                            void *data)
+{
+       switch (action) {
+       case LAT_BRIGHTNESS:
+               set_brightness(ops, VOIDP2INT(data));
+               break;
+       case LAT_POWER:
+               set_power(ops, VOIDP2INT(data));
+               break;
+       default:
+               printk(KERN_INFO "LCD energy error: action=%d\n", action);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Get the array size of LCD
+ *
+ * @param ops LCD operations
+ * @return Array size
+ */
+size_t get_lcd_size_array(struct lcd_ops *ops)
+{
+       struct lcd_priv_data *lcd = get_lcd_priv(ops);
+
+       return lcd->tms_brt_cnt;
+}
+
+/**
+ * @brief Get an array of times
+ *
+ * @param ops LCD operations
+ * @param array_time[out] Array of times
+ * @return Void
+ */
+void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time)
+{
+       struct lcd_priv_data *lcd = get_lcd_priv(ops);
+       int i;
+
+       spin_lock(&lcd->lock_tms);
+       for (i = 0; i < lcd->tms_brt_cnt; ++i)
+               array_time[i] = tm_stat_running(&lcd->tms_brt[i]);
+
+       if (lcd->power == PW_ON && lcd->brt_old != brt_no_init) {
+               int old = lcd->brt_old;
+               struct tm_stat *tm = &lcd->tms_brt[old];
+
+               array_time[old] += get_ntime() - tm_stat_timestamp(tm);
+       }
+       spin_unlock(&lcd->lock_tms);
+}
+
+static int register_lcd(struct lcd_ops *ops)
+{
+       int ret = 0;
+
+       ops->priv = create_lcd_priv(ops, brt_cnt);
+
+       /* TODO: create init_func() for 'struct rational' */
+       ops->min_coef.num = 1;
+       ops->min_coef.denom = 1;
+       ops->max_coef.num = 1;
+       ops->max_coef.denom = 1;
+
+       ops->notifier = func_notifier_lcd;
+
+       ret = register_lcd_debugfs(ops);
+       if (ret)
+               destroy_lcd_priv(ops->priv);
+
+       return ret;
+}
+
+static void unregister_lcd(struct lcd_ops *ops)
+{
+       unregister_lcd_debugfs(ops);
+       destroy_lcd_priv(ops->priv);
+}
+
+
+
+
+/* ============================================================================
+ * ===                          LCD_INIT/LCD_EXIT                           ===
+ * ============================================================================
+ */
+typedef struct lcd_ops *(*get_ops_t)(void);
+
+DEFINITION_LCD_FUNC;
+
+get_ops_t lcd_ops[] = DEFINITION_LCD_ARRAY;
+enum { lcd_ops_cnt = sizeof(lcd_ops) / sizeof(get_ops_t) };
+
+enum ST_LCD_OPS {
+       SLO_REGISTER    = 1 << 0,
+       SLO_SET         = 1 << 1
+};
+
+static DEFINE_MUTEX(lcd_lock);
+static enum ST_LCD_OPS stat_lcd_ops[lcd_ops_cnt];
+
+static void do_lcd_exit(void)
+{
+       int i;
+       struct lcd_ops *ops;
+
+       mutex_lock(&lcd_lock);
+       for (i = 0; i < lcd_ops_cnt; ++i) {
+               ops = lcd_ops[i]();
+
+               if (stat_lcd_ops[i] & SLO_SET) {
+                       ops->unset(ops);
+                       stat_lcd_ops[i] &= ~SLO_SET;
+               }
+
+               if (stat_lcd_ops[i] & SLO_REGISTER) {
+                       unregister_lcd(ops);
+                       stat_lcd_ops[i] &= ~SLO_REGISTER;
+               }
+       }
+       mutex_unlock(&lcd_lock);
+}
+
+/**
+ * @brief LCD deinitialization
+ *
+ * @return Void
+ */
+void lcd_exit(void)
+{
+       do_lcd_exit();
+}
+
+static int do_lcd_init(void)
+{
+       int i, ret, count = 0;
+       struct lcd_ops *ops;
+
+       mutex_lock(&lcd_lock);
+       for (i = 0; i < lcd_ops_cnt; ++i) {
+               ops = lcd_ops[i]();
+               if (ops == NULL) {
+                       printk(KERN_INFO "error %s [ops == NULL]\n", __func__);
+                       continue;
+               }
+
+               if (0 == ops->check(ops)) {
+                       printk(KERN_INFO "error checking %s\n", ops->name);
+                       continue;
+               }
+
+               ret = register_lcd(ops);
+               if (ret) {
+                       printk(KERN_INFO "error register_lcd %s\n", ops->name);
+                       continue;
+               }
+
+               stat_lcd_ops[i] |= SLO_REGISTER;
+               ++count;
+       }
+       mutex_unlock(&lcd_lock);
+
+       return count ? 0 : -EPERM;
+}
+
+/**
+ * @brief LCD initialization
+ *
+ * @return Error code
+ */
+int lcd_init(void)
+{
+       int ret;
+
+       ret = do_lcd_init();
+       if (ret)
+               printk(KERN_INFO "LCD is not supported\n");
+
+       return ret;
+}
+
+
+
+/* ============================================================================
+ * ===                     LCD_SET_ENERGY/LCD_UNSET_ENERGY                  ===
+ * ============================================================================
+ */
+
+/**
+ * @brief Start measuring the energy consumption of LСD
+ *
+ * @return Error code
+ */
+int lcd_set_energy(void)
+{
+       int i, ret, count = 0;
+       struct lcd_ops *ops;
+
+       mutex_lock(&lcd_lock);
+       for (i = 0; i < lcd_ops_cnt; ++i) {
+               ops = lcd_ops[i]();
+               if (stat_lcd_ops[i] & SLO_REGISTER) {
+                       ret = ops->set(ops);
+                       if (ret) {
+                               printk(KERN_INFO "error %s set LCD energy",
+                                      ops->name);
+                               continue;
+                       }
+
+                       set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS));
+                       set_power(ops, ops->get(ops, LPD_POWER));
+
+                       stat_lcd_ops[i] |= SLO_SET;
+                       ++count;
+               }
+       }
+       mutex_unlock(&lcd_lock);
+
+       return count ? 0 : -EPERM;
+}
+
+/**
+ * @brief Stop measuring the energy consumption of LСD
+ *
+ * @return Void
+ */
+void lcd_unset_energy(void)
+{
+       int i, ret;
+       struct lcd_ops *ops;
+
+       mutex_lock(&lcd_lock);
+       for (i = 0; i < lcd_ops_cnt; ++i) {
+               ops = lcd_ops[i]();
+               if (stat_lcd_ops[i] & SLO_SET) {
+                       ret = ops->unset(ops);
+                       if (ret)
+                               printk(KERN_INFO "error %s unset LCD energy",
+                                      ops->name);
+
+                       clean_brightness(ops);
+                       stat_lcd_ops[i] &= ~SLO_SET;
+               }
+       }
+       mutex_unlock(&lcd_lock);
+}
diff --git a/modules/energy/lcd/lcd_base.h b/modules/energy/lcd/lcd_base.h
new file mode 100644 (file)
index 0000000..85d59c6
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef _LCD_BASE_H
+#define _LCD_BASE_H
+
+/**
+ * @file energy/lcd/lcd_base.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ * Description of the interface for interacting with LСD
+ */
+
+
+#include <linux/errno.h>
+#include <energy/rational_debugfs.h>
+
+
+#define VOIDP2INT(x)   ((int)(unsigned long)(x))
+#define INT2VOIDP(x)   ((void *)(unsigned long)(x))
+
+
+/** Description of actions */
+enum lcd_action_type {
+       LAT_BRIGHTNESS,         /**< LCD brightness */
+       LAT_POWER               /**< LCD power */
+};
+
+
+/** Description of parameters */
+enum lcd_parameter_type {
+       LPD_MIN_BRIGHTNESS,     /**< minimum brightness value */
+       LPD_MAX_BRIGHTNESS,     /**< maximum brightness value */
+       LPD_BRIGHTNESS,         /**< current brightness value */
+
+       LPD_POWER               /**< current power value */
+};
+
+struct lcd_ops;
+
+/**
+ * @brief LCD callback type
+ *
+ * @param ops LCD operations
+ * @return Error code
+ */
+typedef int (*call_lcd)(struct lcd_ops *ops);
+
+/**
+ * @brief LCD notifier type
+ *
+ * @param ops LCD operations
+ * @param action Event type
+ * @param data Date
+ * @return Error code
+ */
+typedef int (*notifier_lcd)(struct lcd_ops *ops, enum lcd_action_type action,
+                           void *data);
+
+/**
+ * @brief LCD parameter type
+ *
+ * @param ops LCD operations
+ * @param type Requested parameter type
+ * @return Requested parameter value
+ *
+ */
+typedef unsigned long (*get_parameter_lcd)(struct lcd_ops *ops,
+                                          enum lcd_parameter_type type);
+
+
+/**
+ * @struct lcd_ops
+ * @breaf set of operations available for LСD
+ */
+struct lcd_ops {
+       char *name;                     /**< LCD driver name */
+       notifier_lcd notifier;          /**< Notifier */
+       get_parameter_lcd get;          /**< Method to obtain the parameters */
+
+       call_lcd check;                 /**< LCD check on device */
+       call_lcd set;                   /**< LCD initialization */
+       call_lcd unset;                 /**< LCD deinitialization */
+
+       /* for debugfs */
+       struct dentry *dentry;          /**< Dentry of debugfs for this LCD */
+       struct rational min_coef;       /**< Minimum coefficient */
+       struct rational max_coef;       /**< Maximum coefficient */
+
+       void *priv;                     /**< Private data */
+};
+
+size_t get_lcd_size_array(struct lcd_ops *ops);
+void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time);
+
+int read_val(const char *path);
+
+int lcd_set_energy(void);
+void lcd_unset_energy(void);
+
+int lcd_init(void);
+void lcd_exit(void);
+
+#endif /* _LCD_BASE_H */
diff --git a/modules/energy/lcd/lcd_debugfs.c b/modules/energy/lcd/lcd_debugfs.c
new file mode 100644 (file)
index 0000000..a3cac95
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  energy/lcd/lcd_debugfs.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <master/swap_debugfs.h>
+#include <energy/lcd/lcd_base.h>
+#include <energy/debugfs_energy.h>
+#include <energy/rational_debugfs.h>
+
+
+static int get_system(void *data, u64 *val)
+{
+       struct lcd_ops *ops = (struct lcd_ops *)data;
+       const size_t size = get_lcd_size_array(ops);
+       const size_t size_1 = size - 1;
+       u64 i_max, j_min, t, e = 0;
+       u64 *array_time;
+       int i, j;
+
+       array_time = kmalloc(sizeof(*array_time) * size, GFP_KERNEL);
+       if (array_time == NULL)
+               return -ENOMEM;
+
+       get_lcd_array_time(ops, array_time);
+
+       for (i = 0; i < size; ++i) {
+               t = array_time[i];
+
+               /* e = (i * max + (k - i) * min) * t / k */
+               j = size_1 - i;
+               i_max = div_u64(i * ops->max_coef.num * t,
+                               ops->max_coef.denom);
+               j_min = div_u64(j * ops->min_coef.num * t,
+                               ops->min_coef.denom);
+               e += div_u64(i_max + j_min, size_1);
+       }
+
+       kfree(array_time);
+
+       *val = e;
+
+       return 0;
+}
+
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_system, get_system, NULL, "%llu\n");
+
+
+static struct dentry *lcd_dir;
+
+/**
+ * @brief Register LCD in debugfs
+ *
+ * @param ops LCD operations
+ * @return Error code
+ */
+int register_lcd_debugfs(struct lcd_ops *ops)
+{
+       int ret;
+       struct dentry *dentry, *system;
+
+       if (lcd_dir == NULL)
+               return -EINVAL;
+
+       dentry = swap_debugfs_create_dir(ops->name, lcd_dir);
+       if (dentry == NULL)
+               return -ENOMEM;
+
+       ret = create_rational_files(dentry, &ops->min_coef,
+                                   "min_num", "min_denom");
+       if (ret)
+               goto fail;
+
+       ret = create_rational_files(dentry, &ops->max_coef,
+                                   "max_num", "max_denom");
+       if (ret)
+               goto fail;
+
+       system = swap_debugfs_create_file("system", 0600, dentry, (void *)ops,
+                                         &fops_get_system);
+       if (system == NULL)
+               goto fail;
+
+       ops->dentry = dentry;
+
+       return 0;
+fail:
+       debugfs_remove_recursive(dentry);
+       return -ENOMEM;
+}
+
+/**
+ * @brief Unregister LCD in debugfs
+ *
+ * @param ops LCD operations
+ * @return Void
+ */
+void unregister_lcd_debugfs(struct lcd_ops *ops)
+{
+       debugfs_remove_recursive(ops->dentry);
+}
+
+/**
+ * @brief Destroy debugfs for LCD
+ *
+ * @return Void
+ */
+void exit_lcd_debugfs(void)
+{
+       if (lcd_dir)
+               debugfs_remove_recursive(lcd_dir);
+
+       lcd_dir = NULL;
+}
+
+/**
+ * @brief Create debugfs for LCD
+ *
+ * @param dentry Dentry
+ * @return Error code
+ */
+int init_lcd_debugfs(struct dentry *energy_dir)
+{
+       lcd_dir = swap_debugfs_create_dir("lcd", energy_dir);
+       if (lcd_dir == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
diff --git a/modules/energy/lcd/lcd_debugfs.h b/modules/energy/lcd/lcd_debugfs.h
new file mode 100644 (file)
index 0000000..369748c
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _LCD_DEBUGFS_H
+#define _LCD_DEBUGFS_H
+
+/**
+ * @file energy/lcd/lcd_debugfs.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ * Debugfs for LСD
+ *
+ */
+
+
+struct dentry;
+struct lcd_ops;
+
+int register_lcd_debugfs(struct lcd_ops *ops);
+void unregister_lcd_debugfs(struct lcd_ops *ops);
+
+int init_lcd_debugfs(struct dentry *energy_dir);
+void exit_lcd_debugfs(void);
+
+#endif /* _LCD_DEBUGFS_H */
diff --git a/modules/energy/lcd/maru.c b/modules/energy/lcd/maru.c
new file mode 100644 (file)
index 0000000..e6a9c2c
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  energy/lcd/maru.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <kprobe/swap_kprobes.h>
+#include <linux/backlight.h>
+#include "lcd_base.h"
+
+
+
+static const char path_backlight[]     =
+       "/sys/class/backlight/emulator/brightness";
+static const char path_backlight_min[] =
+       "/sys/class/backlight/emulator/min_brightness";
+static const char path_backlight_max[] =
+       "/sys/class/backlight/emulator/max_brightness";
+static const char path_power[]         =
+       "/sys/class/lcd/emulator/lcd_power";
+
+static const char * const all_path[] = {
+       path_backlight,
+       path_backlight_min,
+       path_backlight_max,
+       path_power
+};
+
+enum {
+       all_path_cnt = sizeof(all_path) / sizeof(char *)
+};
+
+
+static int maru_check(struct lcd_ops *ops)
+{
+       int i;
+
+       for (i = 0; i < all_path_cnt; ++i) {
+               int ret = read_val(all_path[i]);
+
+               if (IS_ERR_VALUE(ret))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static unsigned long maru_get_parameter(struct lcd_ops *ops,
+                                       enum lcd_parameter_type type)
+{
+       switch (type) {
+       case LPD_MIN_BRIGHTNESS:
+               return read_val(path_backlight_min);
+       case LPD_MAX_BRIGHTNESS:
+               return read_val(path_backlight_max);
+       case LPD_BRIGHTNESS:
+               return read_val(path_backlight);
+       case LPD_POWER:
+               return read_val(path_power);
+       default:
+               return -EINVAL;
+       }
+}
+
+
+
+
+
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+                                      struct pt_regs *regs);
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+                                    struct pt_regs *regs);
+
+static struct kretprobe set_backlight_krp = {
+       .kp.symbol_name = "marubl_send_intensity",
+       .entry_handler = entry_handler_set_backlight,
+       .handler = ret_handler_set_backlight,
+       .data_size = sizeof(int)
+};
+
+
+
+
+
+static int maru_set(struct lcd_ops *ops)
+{
+       return swap_register_kretprobe(&set_backlight_krp);
+}
+
+static int maru_unset(struct lcd_ops *ops)
+{
+       swap_unregister_kretprobe(&set_backlight_krp);
+       return 0;
+}
+
+static struct lcd_ops maru_ops = {
+       .name = "maru",
+       .check = maru_check,
+       .set = maru_set,
+       .unset = maru_unset,
+       .get = maru_get_parameter
+};
+
+struct lcd_ops *LCD_MAKE_FNAME(maru)(void)
+{
+       return &maru_ops;
+}
+
+
+
+
+
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+                                      struct pt_regs *regs)
+{
+       int *brightness = (int *)ri->data;
+       struct backlight_device *bd;
+
+       bd = (struct backlight_device *)swap_get_karg(regs, 0);
+       *brightness = bd->props.brightness;
+
+       return 0;
+}
+
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+                                    struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       int *brightness = (int *)ri->data;
+
+       if (!ret && maru_ops.notifier)
+               maru_ops.notifier(&maru_ops, LAT_BRIGHTNESS,
+                                 INT2VOIDP(*brightness));
+
+       return 0;
+}
diff --git a/modules/energy/lcd/s6e8aa0.c b/modules/energy/lcd/s6e8aa0.c
new file mode 100644 (file)
index 0000000..241003b
--- /dev/null
@@ -0,0 +1,179 @@
+#include <kprobe/swap_kprobes.h>
+#include "lcd_base.h"
+
+
+static const char path_backlight[] =
+       "/sys/class/backlight/s6e8aa0-bl/brightness";
+static const char path_backlight_min[] =
+       "/sys/class/backlight/s6e8aa0-bl/min_brightness";
+static const char path_backlight_max[] =
+       "/sys/class/backlight/s6e8aa0-bl/max_brightness";
+static const char path_power[] =
+       "/sys/class/lcd/s6e8aa0/lcd_power";
+
+static const char * const all_path[] = {
+       path_backlight,
+       path_backlight_min,
+       path_backlight_max,
+       path_power
+};
+
+enum {
+       all_path_cnt = sizeof(all_path) / sizeof(char *)
+};
+
+
+
+static int s6e8aa0_check(struct lcd_ops *ops)
+{
+       int i;
+
+       for (i = 0; i < all_path_cnt; ++i) {
+               int ret = read_val(all_path[i]);
+
+               if (IS_ERR_VALUE(ret))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
+                                          enum lcd_parameter_type type)
+{
+       switch (type) {
+       case LPD_MIN_BRIGHTNESS:
+               return read_val(path_backlight_min);
+       case LPD_MAX_BRIGHTNESS:
+               return read_val(path_backlight_max);
+       case LPD_BRIGHTNESS:
+               return read_val(path_backlight);
+       case LPD_POWER:
+               return read_val(path_power);
+       default:
+               return -EINVAL;
+       }
+}
+
+
+
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+                                  struct pt_regs *regs);
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+                                struct pt_regs *regs);
+
+static struct kretprobe set_power_krp = {
+       .kp.symbol_name = "s6e8aa0_set_power",
+       .entry_handler = entry_handler_set_power,
+       .handler = ret_handler_set_power,
+       .data_size = sizeof(int)
+};
+
+
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+                                      struct pt_regs *regs);
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+                                    struct pt_regs *regs);
+
+static struct kretprobe set_backlight_krp = {
+       .kp.symbol_name = "s6e8aa0_gamma_ctrl",
+       .entry_handler = entry_handler_set_backlight,
+       .handler = ret_handler_set_backlight,
+       .data_size = sizeof(int)
+};
+
+int s6e8aa0_set(struct lcd_ops *ops)
+{
+       int ret;
+
+       ret = swap_register_kretprobe(&set_power_krp);
+       if (ret)
+               return ret;
+
+       ret = swap_register_kretprobe(&set_backlight_krp);
+       if (ret)
+               swap_unregister_kretprobe(&set_power_krp);
+
+       return ret;
+}
+
+int s6e8aa0_unset(struct lcd_ops *ops)
+{
+       swap_unregister_kretprobe(&set_backlight_krp);
+       swap_unregister_kretprobe(&set_power_krp);
+
+       return 0;
+}
+
+static struct lcd_ops s6e8aa0_ops = {
+       .name = "s6e8aa0",
+       .check = s6e8aa0_check,
+       .set = s6e8aa0_set,
+       .unset = s6e8aa0_unset,
+       .get = s6e8aa0_get_parameter
+};
+
+struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0)(void)
+{
+       return &s6e8aa0_ops;
+}
+
+
+
+
+
+/* ============================================================================
+ * ===                               POWER                                  ===
+ * ============================================================================
+ */
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+                                  struct pt_regs *regs)
+{
+       int *power = (int *)ri->data;
+
+       *power = (int)swap_get_karg(regs, 1);
+
+       return 0;
+}
+
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       int *power = (int *)ri->data;
+
+       if (!ret && s6e8aa0_ops.notifier)
+               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER, INT2VOIDP(*power));
+
+       return 0;
+}
+
+
+
+
+
+/* ============================================================================
+ * ===                              BACKLIGHT                               ===
+ * ============================================================================
+ */
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+                                      struct pt_regs *regs)
+{
+       int *brightness = (int *)ri->data;
+       *brightness = (int)swap_get_karg(regs, 1);
+
+       return 0;
+}
+
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+                                    struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       int *brightness = (int *)ri->data;
+
+       if (!ret && s6e8aa0_ops.notifier)
+               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
+                                    INT2VOIDP(*brightness));
+
+       return 0;
+}
diff --git a/modules/energy/lcd/s6e8aa0_panel.c b/modules/energy/lcd/s6e8aa0_panel.c
new file mode 100644 (file)
index 0000000..e2cd8fa
--- /dev/null
@@ -0,0 +1,181 @@
+#include <kprobe/swap_kprobes.h>
+#include <linux/backlight.h>
+#include "lcd_base.h"
+
+
+static const char path_backlight[] =
+       "/sys/class/backlight/s6e8aa0-bl/brightness";
+static const char path_backlight_max[] =
+       "/sys/class/backlight/s6e8aa0-bl/max_brightness";
+static const char path_power[] =
+       "/sys/class/lcd/s6e8aa0/lcd_power";
+
+static const char * const all_path[] = {
+       path_backlight,
+       path_backlight_max,
+       path_power
+};
+
+enum {
+       all_path_cnt = sizeof(all_path) / sizeof(char *)
+};
+
+
+
+static int s6e8aa0_check(struct lcd_ops *ops)
+{
+       int i;
+
+       for (i = 0; i < all_path_cnt; ++i) {
+               int ret = read_val(all_path[i]);
+
+               if (IS_ERR_VALUE(ret))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
+                                          enum lcd_parameter_type type)
+{
+       switch (type) {
+       case LPD_MIN_BRIGHTNESS:
+               return 0;
+       case LPD_MAX_BRIGHTNESS:
+               return read_val(path_backlight_max);
+       case LPD_BRIGHTNESS:
+               return read_val(path_backlight);
+       case LPD_POWER:
+               return read_val(path_power);
+       }
+
+       return -EINVAL;
+}
+
+
+
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+                                  struct pt_regs *regs);
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+                                struct pt_regs *regs);
+
+static struct kretprobe set_power_krp = {
+       .kp.symbol_name = "s6e8aa0_set_power",
+       .entry_handler = entry_handler_set_power,
+       .handler = ret_handler_set_power,
+       .data_size = sizeof(int)
+};
+
+
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+                                      struct pt_regs *regs);
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+                                    struct pt_regs *regs);
+
+static struct kretprobe set_backlight_krp = {
+       .kp.symbol_name = "s6e8aa0_update_status",
+       .entry_handler = entry_handler_set_backlight,
+       .handler = ret_handler_set_backlight,
+       .data_size = sizeof(int)
+};
+
+int s6e8aa0_set(struct lcd_ops *ops)
+{
+       int ret;
+
+       ret = swap_register_kretprobe(&set_power_krp);
+       if (ret)
+               return ret;
+
+       ret = swap_register_kretprobe(&set_backlight_krp);
+       if (ret)
+               swap_unregister_kretprobe(&set_power_krp);
+
+       return ret;
+}
+
+int s6e8aa0_unset(struct lcd_ops *ops)
+{
+       swap_unregister_kretprobe(&set_backlight_krp);
+       swap_unregister_kretprobe(&set_power_krp);
+
+       return 0;
+}
+
+static struct lcd_ops s6e8aa0_ops = {
+       .name = "s6e8aa0_panel",
+       .check = s6e8aa0_check,
+       .set = s6e8aa0_set,
+       .unset = s6e8aa0_unset,
+       .get = s6e8aa0_get_parameter
+};
+
+struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0_panel)(void)
+{
+       return &s6e8aa0_ops;
+}
+
+
+
+
+
+/* ============================================================================
+ * ===                               POWER                                  ===
+ * ============================================================================
+ */
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+                                  struct pt_regs *regs)
+{
+       int *power = (int *)ri->data;
+
+       *power = (int)swap_get_karg(regs, 1);
+
+       return 0;
+}
+
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       int *power = (int *)ri->data;
+
+       if (!ret && s6e8aa0_ops.notifier)
+               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER,
+                                    INT2VOIDP(*power));
+
+       return 0;
+}
+
+
+
+
+
+/* ============================================================================
+ * ===                              BACKLIGHT                               ===
+ * ============================================================================
+ */
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+                                      struct pt_regs *regs)
+{
+       int *brightness = (int *)ri->data;
+       struct backlight_device *bd;
+
+       bd = (struct backlight_device *)swap_get_karg(regs, 0);
+       *brightness = bd->props.brightness;
+
+       return 0;
+}
+
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+                                    struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+       int *brightness = (int *)ri->data;
+
+       if (!ret && s6e8aa0_ops.notifier)
+               s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
+                                    INT2VOIDP(*brightness));
+
+       return 0;
+}
diff --git a/modules/energy/rational_debugfs.c b/modules/energy/rational_debugfs.c
new file mode 100644 (file)
index 0000000..16c73d5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  energy/rational_debugfs.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <master/swap_debugfs.h>
+#include "debugfs_energy.h"
+#include "rational_debugfs.h"
+
+
+static int denom_set(void *data, u64 val)
+{
+       if (val == 0)
+               return -EINVAL;
+
+       *(u64 *)data = val;
+       return 0;
+}
+
+static int denom_get(void *data, u64 *val)
+{
+       *val = *(u64 *)data;
+       return 0;
+}
+
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_denom, denom_get, denom_set, "%llu\n");
+
+/**
+ * @brief Create file in debugfs for rational struct
+ *
+ * @param parent Dentry parent
+ * @param r Pointer to the rational struct
+ * @param num_name File name of numerator
+ * @param denom_name File name of denominator
+ * @return Error code
+ */
+int create_rational_files(struct dentry *parent, struct rational *r,
+                         const char *num_name, const char *denom_name)
+{
+       struct dentry *d_num, *d_denom;
+
+       d_num = swap_debugfs_create_u64(num_name, 0600, parent, &r->num);
+       if (d_num == NULL)
+               return -ENOMEM;
+
+       d_denom = swap_debugfs_create_file(denom_name, 0600, parent, &r->denom,
+                                          &fops_denom);
+       if (d_denom == NULL) {
+               debugfs_remove(d_num);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
diff --git a/modules/energy/rational_debugfs.h b/modules/energy/rational_debugfs.h
new file mode 100644 (file)
index 0000000..6a30155
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _RATIONAL_DEBUGFS_H
+#define _RATIONAL_DEBUGFS_H
+
+/**
+ * @file energy/rational_debugfs.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+
+#include <linux/types.h>
+
+
+/**
+ * @struct rational
+ * @brief Description of rational number
+ */
+struct rational {
+       u64 num;                /**< Numerator */
+       u64 denom;              /**< Denominator */
+};
+
+
+/**
+ * @def DEFINE_RATIONAL
+ * Initialize of rational struct @hideinitializer
+ */
+#define DEFINE_RATIONAL(rational_name)         \
+       struct rational rational_name = {       \
+               .num = 1,                       \
+               .denom = 1                      \
+       }
+
+
+struct dentry;
+
+int create_rational_files(struct dentry *parent, struct rational *r,
+                         const char *num_name, const char *denom_name);
+
+
+#endif /* _RATIONAL_DEBUGFS_H */
diff --git a/modules/energy/tm_stat.h b/modules/energy/tm_stat.h
new file mode 100644 (file)
index 0000000..67278b1
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef _TM_STAT_H
+#define _TM_STAT_H
+
+/**
+ * @file energy/tm_stat.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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 COPYFIGHT
+ * Copyright (C) Samsung Electronics, 2013
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+
+/**
+ * @struct tm_stat
+ * @brief Description of statistic time
+ */
+struct tm_stat {
+       u64 timestamp;          /**< Time stamp */
+       u64 running;            /**< Running time */
+};
+
+/**
+ * @def DEFINE_TM_STAT
+ * Initialize of tm_stat struct @hideinitializer
+ */
+#define DEFINE_TM_STAT(tm_name)                \
+       struct tm_stat tm_name = {      \
+               .timestamp = 0,         \
+               .running = 0            \
+       }
+
+
+static inline u64 get_ntime(void)
+{
+       struct timespec ts;
+       getnstimeofday(&ts);
+       return timespec_to_ns(&ts);
+}
+
+static inline void tm_stat_init(struct tm_stat *tm)
+{
+       tm->timestamp = 0;
+       tm->running = 0;
+}
+
+static inline void tm_stat_set_timestamp(struct tm_stat *tm, u64 time)
+{
+       tm->timestamp = time;
+}
+
+static inline u64 tm_stat_timestamp(struct tm_stat *tm)
+{
+       return tm->timestamp;
+}
+
+static inline void tm_stat_update(struct tm_stat *tm, u64 time)
+{
+       tm->running += time - tm->timestamp;
+}
+
+static inline u64 tm_stat_running(struct tm_stat *tm)
+{
+       return tm->running;
+}
+
+static inline u64 tm_stat_current_running(struct tm_stat *tm, u64 now)
+{
+       if (unlikely(now < tm->timestamp))
+               printk(KERN_INFO "XXX %p WARNING now(%llu) < tmstmp(%llu)\n",
+                      tm, now, tm->timestamp);
+       return tm->timestamp ? tm->running + now - tm->timestamp : tm->running;
+}
+
+#endif /* _TM_STAT_H */
diff --git a/modules/fbiprobe/Kbuild b/modules/fbiprobe/Kbuild
new file mode 100644 (file)
index 0000000..3d90976
--- /dev/null
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_fbiprobe.o
+swap_fbiprobe-y := fbiprobe.o \
+                   fbi_msg.o
diff --git a/modules/fbiprobe/fbi_msg.c b/modules/fbiprobe/fbi_msg.c
new file mode 100644 (file)
index 0000000..d2bd34a
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * fbiprobe/fbi_msg.c
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @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, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Packing and writing data.
+ */
+
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <writer/swap_msg.h>
+
+struct msg_fbi {
+       u32 var_id;
+       u32 size;
+       char var_data[0];
+} __packed;
+
+
+static char *pack_fbi_info(char *payload, unsigned long var_id, size_t size,
+                          char *msg_buf)
+{
+       struct msg_fbi *fbi_m = (struct msg_fbi *)payload;
+
+       fbi_m->var_id = var_id;
+       fbi_m->size = size;
+       if (size != 0) {
+               /* FIXME Possible out of buffer! */
+               memcpy(&fbi_m->var_data, msg_buf, size);
+       }
+
+       /*
+        * If size is 0 that mean we cannot get data for this probe.
+        * But we pack it like error code
+        */
+
+       return payload + sizeof(struct msg_fbi) + size;
+}
+
+void fbi_msg(unsigned long var_id, size_t size, char *msg_buf)
+{
+       struct swap_msg *m;
+       void *p;
+       void *buf_end;
+
+       m = swap_msg_get(MSG_FBI);
+       p = swap_msg_payload(m);
+
+       buf_end = pack_fbi_info(p, var_id, size, msg_buf);
+
+       swap_msg_flush(m, buf_end - p);
+
+       swap_msg_put(m);
+}
diff --git a/modules/fbiprobe/fbi_msg.h b/modules/fbiprobe/fbi_msg.h
new file mode 100644 (file)
index 0000000..69fd209
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * @file fbiprobe/fbi_msg.h
+ *
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * Function body instrumetation
+ *
+ */
+
+#ifndef __FBI_MSG_H__
+#define __FBI_MSG_H__
+
+#include <linux/types.h>
+
+void fbi_msg(unsigned long var_id, size_t size, char *msg_buf);
+
+#endif /* __FBI_MSG_H__ */
diff --git a/modules/fbiprobe/fbi_probe_module.h b/modules/fbiprobe/fbi_probe_module.h
new file mode 100644 (file)
index 0000000..cac6f4a
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * @file fbiprobe/fbi_probe.h
+ *
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * 2014 Alexander Aksenov : FBI implement
+ * 2014 Vitaliy Cherepanov: FBI implement, portage
+ *
+ * @section DESCRIPTION
+ *
+ * Function body instrumentation.
+ *
+ */
+
+#ifndef __FBI_PROBE_MODULE_H__
+#define __FBI_PROBE_MODULE_H__
+
+#include <linux/kernel.h>
+
+/* MESSAGES */
+
+#define MODULE_NAME "SWAP_FBI_PROBE"
+
+/* FBI_DEBUG_ON:
+ * val | DEBUG | MSG | WARN | ERR | CRITICAL|
+ * ----+-------+-----+------+-----+---------|
+ * 0   | OFF   | OFF | OFF  | OFF | OFF     |
+ * 1   | OFF   | OFF | OFF  | OFF | ON      |
+ * 2   | OFF   | OFF | OFF  | ON  | ON      |
+ * 3   | OFF   | OFF | ON   | ON  | ON      |
+ * 4   | OFF   | ON  | ON   | ON  | ON      |
+ * 5   | ON    | ON  | ON   | ON  | ON      |
+ */
+
+#define FBI_DEBUG_LEVEL 3
+
+/** Prints debug message.*/
+#if (FBI_DEBUG_LEVEL >= 5)
+#define print_debug(msg, args...) \
+       printk(KERN_DEBUG MODULE_NAME " DEBUG : " msg, ##args)
+#else
+#define print_debug(msg, args...)
+#endif
+
+/** Prints info message.*/
+#if (FBI_DEBUG_LEVEL >= 4)
+#define print_msg(msg, args...)   \
+       printk(KERN_INFO MODULE_NAME " : " msg, ##args)
+#else
+#define print_msg(msg, args...)
+#endif
+
+/** Prints warning message.*/
+#if (FBI_DEBUG_LEVEL >= 3)
+#define print_warn(msg, args...)  \
+       printk(KERN_WARNING MODULE_NAME " WARNING : " msg, ##args)
+#else
+#define print_warn(msg, args...)
+#endif
+
+/** Prints error message.*/
+#if (FBI_DEBUG_LEVEL >= 2)
+#define print_err(msg, args...)   \
+       printk(KERN_ERR MODULE_NAME " ERROR : " msg, ##args)
+#else
+#define print_err(msg, args...)
+#endif
+
+/** Prints critical error message.*/
+#if (FBI_DEBUG_LEVEL >= 1)
+#define print_crit(msg, args...)  \
+       printk(KERN_CRIT MODULE_NAME " CRITICAL : " msg, ##args)
+#else
+#define print_crit(msg, args...)
+#endif
+
+#endif /* __FBI_PROBE_MODULE_H__ */
diff --git a/modules/fbiprobe/fbiprobe.c b/modules/fbiprobe/fbiprobe.c
new file mode 100644 (file)
index 0000000..39e6477
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * @file fbiprobe/fbi_probe.c
+ *
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * 2014 Alexander Aksenov : FBI implement
+ * 2014 Vitaliy Cherepanov: FBI implement, portage
+ *
+ * @section DESCRIPTION
+ *
+ * Function body instrumetation
+ *
+ */
+
+#include "fbiprobe.h"
+#include "fbi_probe_module.h"
+#include "fbi_msg.h"
+#include "regs.h"
+
+#include <us_manager/us_manager.h>
+#include <us_manager/probes/probes.h>
+#include <us_manager/probes/register_probes.h>
+
+#include <uprobe/swap_uprobes.h>
+#include <us_manager/sspt/sspt_ip.h>
+
+#include <kprobe/swap_kprobes_deps.h>
+#include <linux/module.h>
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/dcache.h>
+#include <linux/mm_types.h>
+
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+
+#define DIRECT_ADDR (0xFF)
+#define MAX_STRING_LEN (512)
+
+/* on fails. return NULL, set size to 0 */
+/* you shoud free allocated data buffer */
+static char *fbi_probe_alloc_and_read_from_addr(const struct fbi_var_data *fbid,
+                                               unsigned long addr,
+                                               uint32_t *size)
+{
+       uint8_t i, j;
+       char *buf = NULL;
+       struct fbi_step *step;
+
+       *size = 0;
+
+       /* get final variable address */
+       step = fbid->steps;
+       for (i = 0; i != fbid->steps_count; i++) {
+               /* dereference */
+               for (j = 0; j != step->ptr_order; j++) {
+                       unsigned long new_addr;
+                       /* equel to: addr = *addr */
+                       if (!read_proc_vm_atomic(current, addr, &new_addr,
+                                                sizeof(new_addr))) {
+                               print_warn("p = 0x%lx step #%d ptr_order #%d\n",
+                                          addr, i + 1, j + 1);
+                               goto exit_fail;
+                       }
+                       addr = new_addr;
+                       print_debug("dereference addr = 0x%lx;\n", addr);
+               }
+
+               /* offset */
+               addr += step->data_offset;
+               print_debug("addr + offset = 0x%lx;\n", addr);
+               step++;
+       }
+
+       /* calculate data size */
+       if (fbid->data_size == 0) {
+               /*
+                * that mean variable is string and
+                * we need to calculate string length
+                */
+
+               *size = strnlen_user((const char __user *)addr, MAX_STRING_LEN);
+               if (*size == 0) {
+                       print_warn("Cannot get string from 0x%lx\n", addr);
+                       goto exit_fail;
+               }
+       } else {
+               /* else use size from fbi struct */
+               *size = fbid->data_size;
+       }
+
+       buf = kmalloc(*size, GFP_KERNEL);
+       if (buf == NULL) {
+               print_warn("Not enough memory\n");
+               goto exit_fail_size_0;
+       }
+
+       if (!read_proc_vm_atomic(current, addr, buf, *size)) {
+               print_warn("Error reading data at 0x%lx, task %d\n",
+                          addr, current->pid);
+               goto exit_fail_free_buf;
+       }
+
+       if (fbid->data_size == 0) {
+               /*
+                * that mean variable is string and
+                * we need to add terminate '\0'
+                */
+               buf[*size - 1] = '\0';
+       }
+
+       return buf;
+
+exit_fail_free_buf:
+       kfree(buf);
+       buf = NULL;
+exit_fail_size_0:
+       *size = 0;
+exit_fail:
+       return NULL;
+
+}
+
+static int fbi_probe_get_data_from_reg(const struct fbi_var_data *fbi_i,
+                                      struct pt_regs *regs)
+{
+       unsigned long *reg_ptr;
+
+       reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
+       if (reg_ptr == NULL) {
+               print_err("fbi_probe_get_data_from_reg: Wrong register number!\n");
+               return 0;
+       }
+
+       fbi_msg(fbi_i->var_id, fbi_i->data_size, (char *)reg_ptr);
+
+       return 0;
+}
+
+static int fbi_probe_get_data_from_ptrs(const struct fbi_var_data *fbi_i,
+                                       struct pt_regs *regs)
+{
+       unsigned long *reg_ptr;
+       unsigned long addr;
+       uint32_t size = 0;
+       void *buf = NULL;
+
+       reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
+       if (reg_ptr == NULL) {
+               print_err("fbi_probe_get_data_from_ptrs: Wrong register number!\n");
+               goto send_msg;
+       }
+
+       addr = *reg_ptr + fbi_i->reg_offset;
+       print_warn("reg = %p; off = 0x%llx; addr = 0x%lx!\n", reg_ptr,
+                  fbi_i->reg_offset, addr);
+
+       buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
+
+send_msg:
+       /* If buf is NULL size will be 0.
+        * That mean we cannot get data for this probe.
+        * But we should send probe message with packed data size 0
+        * as error message.
+        */
+       fbi_msg(fbi_i->var_id, size, buf);
+
+       if (buf != NULL)
+               kfree(buf);
+       else
+               print_err("cannot get data from ptrs\n");
+
+       return 0;
+}
+
+static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm,
+                                                    struct dentry *dentry)
+{
+       struct vm_area_struct *vma;
+
+       /* FIXME: down_write(&mm->mmap_sem); up_write(&mm->mmap_sem); */
+       /* TODO FILTER vma */
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (vma->vm_file &&
+                  (vma->vm_file->f_path.dentry == dentry))
+                       /* found */
+                       goto exit;
+       }
+
+       /* not found */
+       vma = NULL;
+exit:
+       return vma;
+}
+
+static int fbi_probe_get_data_from_direct_addr(const struct fbi_var_data *fbi_i,
+                                              struct sspt_ip *ip,
+                                              struct pt_regs *regs)
+{
+       struct vm_area_struct *vma;
+       unsigned long addr;
+       uint32_t size = 0;
+       char *buf;
+
+       /* register offset is global address */
+       vma = find_vma_exe_by_dentry(current->mm, ip->page->file->dentry);
+       if (vma == NULL) {
+               print_warn("cannot locate dentry\n");
+               goto exit;
+       }
+
+       addr = vma->vm_start + fbi_i->reg_offset;
+
+       print_debug("DIRECT_ADDR reg_offset = %llx\n", fbi_i->reg_offset);
+       print_debug("DIRECT_ADDR vm_start   = %lx\n", vma->vm_start);
+       print_debug("DIRECT_ADDR res_addr   = %lx\n", addr);
+
+       buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
+       /* If buf is NULL size will be 0.
+        * That mean we cannot get data for this probe.
+        * But we should send probe message with packed data size 0
+        * as error message.
+        */
+       fbi_msg(fbi_i->var_id, size, buf);
+
+       if (buf != NULL) {
+               kfree(buf);
+       } else {
+               print_warn("get data by direct addr failed (0x%lx :0x%llx)\n",
+                          addr, fbi_i->reg_offset);
+       }
+exit:
+       return 0;
+}
+
+static int fbi_probe_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct sspt_ip *ip = container_of(p, struct sspt_ip, uprobe);
+       struct fbi_info *fbi_i = &ip->desc->info.fbi_i;
+       struct fbi_var_data *fbi_d = NULL;
+       uint8_t i;
+
+       if (ip->desc->type != SWAP_FBIPROBE) {
+               /* How this can occure? Doesn't matter, just print and go */
+               print_err("Not FBI probe in FBI handler!\n");
+               return 0;
+       }
+
+       for (i = 0; i != fbi_i->var_count; i++) {
+               fbi_d = &fbi_i->vars[i];
+               if (fbi_d->reg_n == DIRECT_ADDR) {
+                       if (0 != fbi_probe_get_data_from_direct_addr(fbi_d, ip,
+                                                                    regs))
+                               print_err("fbi_probe_get_data_from_direct_addr error\n");
+               } else if (fbi_d->steps_count == 0) {
+                       if (0 != fbi_probe_get_data_from_reg(fbi_d, regs))
+                               print_err("fbi_probe_get_data_from_reg error\n");
+               } else {
+                       if (0 != fbi_probe_get_data_from_ptrs(fbi_d, regs))
+                               print_err("fbi_probe_get_data_from_ptrs error\n");
+               }
+       }
+
+       return 0;
+}
+
+/* FBI probe interfaces */
+void fbi_probe_cleanup(struct probe_info *probe_i)
+{
+       uint8_t i;
+       struct fbi_info *fbi_i = &(probe_i->fbi_i);
+
+       for (i = 0; i != fbi_i->var_count; i++) {
+               if (fbi_i->vars[i].steps != NULL) {
+                       if (fbi_i->vars[i].steps != NULL)
+                               kfree(fbi_i->vars[i].steps);
+                       fbi_i->vars[i].steps = NULL;
+                       fbi_i->vars[i].steps_count = 0;
+               }
+       }
+
+       kfree(fbi_i->vars);
+       fbi_i->vars = NULL;
+}
+
+void fbi_probe_init(struct sspt_ip *ip)
+{
+       ip->uprobe.pre_handler = (uprobe_pre_handler_t)fbi_probe_handler;
+}
+
+void fbi_probe_uninit(struct sspt_ip *ip)
+{
+       if (ip != NULL)
+               fbi_probe_cleanup(&ip->desc->info);
+}
+
+static int fbi_probe_register_probe(struct sspt_ip *ip)
+{
+       return swap_register_uprobe(&ip->uprobe);
+}
+
+static void fbi_probe_unregister_probe(struct sspt_ip *ip, int disarm)
+{
+       __swap_unregister_uprobe(&ip->uprobe, disarm);
+}
+
+static struct uprobe *fbi_probe_get_uprobe(struct sspt_ip *ip)
+{
+       return &ip->uprobe;
+}
+
+int fbi_probe_copy(struct probe_info *dest, const struct probe_info *source)
+{
+       uint8_t steps_count;
+       size_t steps_size;
+       size_t vars_size;
+       struct fbi_var_data *vars;
+       struct fbi_step *steps_source;
+       struct fbi_step *steps_dest = NULL;
+       uint8_t i, n;
+       int ret = 0;
+
+       memcpy(dest, source, sizeof(*source));
+
+       vars_size = source->fbi_i.var_count * sizeof(*source->fbi_i.vars);
+       vars = kmalloc(vars_size, GFP_KERNEL);
+       if (vars == NULL)
+               return -ENOMEM;
+
+       memcpy(vars, source->fbi_i.vars, vars_size);
+
+       for (i = 0; i != source->fbi_i.var_count; i++) {
+               steps_dest = NULL;
+               steps_count = vars[i].steps_count;
+               steps_size = sizeof(*steps_source) * steps_count;
+               steps_source = vars[i].steps;
+
+               if (steps_size != 0 && steps_source != NULL) {
+                       steps_dest = kmalloc(steps_size, GFP_KERNEL);
+                       if (steps_dest == NULL) {
+                               print_err("can not alloc data\n");
+                               n = i;
+                               ret = -ENOMEM;
+                               goto err;
+                       }
+
+                       memcpy(steps_dest, steps_source, steps_size);
+               }
+               vars[i].steps = steps_dest;
+       }
+
+       dest->fbi_i.vars = vars;
+
+       return ret;
+err:
+       for (i = 0; i < n; i++)
+               kfree(vars[i].steps);
+       kfree(vars);
+       return ret;
+}
+
+/* Register */
+static struct probe_iface fbi_probe_iface = {
+       .init = fbi_probe_init,
+       .uninit = fbi_probe_uninit,
+       .reg = fbi_probe_register_probe,
+       .unreg = fbi_probe_unregister_probe,
+       .get_uprobe = fbi_probe_get_uprobe,
+       .copy = fbi_probe_copy,
+       .cleanup = fbi_probe_cleanup
+};
+
+static int __init fbiprobe_module_init(void)
+{
+       int ret = 0;
+       ret = swap_register_probe_type(SWAP_FBIPROBE, &fbi_probe_iface);
+       print_debug("Init done. Result=%d\n", ret);
+       return ret;
+}
+
+static void __exit fbiprobe_module_exit(void)
+{
+       swap_unregister_probe_type(SWAP_FBIPROBE);
+}
+
+module_init(fbiprobe_module_init);
+module_exit(fbiprobe_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP fbiprobe");
+MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>; Vitaliy Cherepanov <v.cherepanov@samsung.com>");
+
diff --git a/modules/fbiprobe/fbiprobe.h b/modules/fbiprobe/fbiprobe.h
new file mode 100644 (file)
index 0000000..2e158c2
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * @file fbi_probe/fbi_probe.h
+ *
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * 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, 2014
+ *
+ * 2014 Alexander Aksenov : FBI implement
+ * 2014 Vitaliy Cherepanov: FBI implement, portage
+ *
+ * @section DESCRIPTION
+ *
+ * Function body instrumentation.
+ *
+ */
+
+#ifndef __FBI_PROBE_H__
+#define __FBI_PROBE_H__
+
+#include <linux/types.h>
+
+/* FBI step */
+struct fbi_step {
+       uint8_t ptr_order;         /* Specifies what is located on the address:
+                                   * ptr_order = 0  -  variable
+                                   * ptr_order = 1  -  pointer to variable
+                                   * ptr_order = 2  -  pointer to pointer
+                                   * etc. */
+
+       uint64_t data_offset;
+} __packed;
+
+/* FBI var data */
+struct fbi_var_data {
+       /* Variable position is evaluated by the following rule:
+        * var_position = *(pointer_to_register) - reg_offset
+        * It is expected that the offset is not null only when we're taking
+        * var value from stack.
+        */
+       uint64_t var_id;           /* Variable identifier
+                                   * Used to specify var */
+       uint64_t reg_offset;       /* Offset relative to the registers value
+                                   * address, specified with reg_n */
+       uint8_t reg_n;             /* Register number. Hope times of cpu
+                                   * with more than 2 million ones are very
+                                   * far from us */
+       uint32_t data_size;        /* Data size to be read */
+
+       uint8_t steps_count;       /* Count of steps to extract variable
+                                   * value */
+       struct fbi_step *steps;    /* extract steps */
+};
+
+/* FBI info */
+struct fbi_info {
+       uint8_t var_count;
+       struct fbi_var_data *vars;
+};
+
+#endif /* __FBI_PROBE_H__ */
diff --git a/modules/fbiprobe/regs.h b/modules/fbiprobe/regs.h
new file mode 100644 (file)
index 0000000..6ad231a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * @file fbiprobe/fbi_probe.h
+ *
+ * @author Aleksandr Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * 2014 Alexander Aksenov : FBI implement
+ * 2014 Vitaliy Cherepanov: FBI portage
+ *
+ * @section DESCRIPTION
+ *
+ * Function body instrumetation
+ *
+ */
+
+#ifndef __REGS_H__
+#define __REGS_H__
+
+#include <linux/ptrace.h>
+
+#include "fbi_probe_module.h"
+/* This function is used to compare register number and its name on x86 arch.
+ * For ARM it is dumb.
+ * List of registers and their nums on x86:
+ * ax       0
+ * bx       1
+ * cx       2
+ * dx       3
+ * si       4
+ * di       5
+ * bp       6
+ * sp       7
+ */
+
+static inline unsigned long *get_ptr_by_num(struct pt_regs *regs,
+                                           unsigned char reg_num)
+{
+       unsigned long *reg = NULL;
+       /* FIXME: bad way to use "sizeof(long) " */
+       if (reg_num < sizeof(struct pt_regs) / sizeof(long)) {
+               reg = (unsigned long *)regs;
+               reg =  &reg[reg_num];
+       }
+
+       return reg;
+}
+
+#endif /* __REGS_H__ */
diff --git a/modules/got_patcher/Kbuild b/modules/got_patcher/Kbuild
new file mode 100644 (file)
index 0000000..bd078f4
--- /dev/null
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_gtp.o
+swap_gtp-y := gt_module.o \
+              gt_debugfs.o
diff --git a/modules/got_patcher/gt.h b/modules/got_patcher/gt.h
new file mode 100644 (file)
index 0000000..ba5924e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __GT_H__
+#define __GT_H__
+
+#define GT_PREFIX "SWAP GOT PATCHER: "
+
+#endif /* __GT_H__ */
diff --git a/modules/got_patcher/gt_debugfs.c b/modules/got_patcher/gt_debugfs.c
new file mode 100644 (file)
index 0000000..362c5d1
--- /dev/null
@@ -0,0 +1,618 @@
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <master/swap_debugfs.h>
+#include "gt.h"
+#include "gt_debugfs.h"
+#include "gt_module.h"
+
+#define GT_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
+
+static const char GT_FOLDER[] = "got_patcher";
+static const char GT_LINKER[] = "linker";
+static const char GT_PATH[] = "path";
+static const char GT_FIXUP_ADDR[] = "dl_fixup_addr";
+static const char GT_RELOC_ADDR[] = "dl_reloc_addr";
+static const char GT_ENABLE[] = "enable";
+static const char GT_BY_PATH[] = "by_path";
+static const char GT_BY_PID[] = "by_pid";
+static const char GT_BY_ID[] = "by_id";
+static const char GT_ADD[] = "add";
+static const char GT_DEL[] = "del";
+static const char GT_DEL_ALL[] = "del_all";
+static const char GT_LIST_TARGETS[] = "list_targets";
+static const char GT_HANDLER[] = "handler";
+static const char GT_HANDLER_FIXUP_OFF[] = "fixup_handler_off";
+static const char GT_HANDLER_RELOC_OFF[] = "reloc_handler_off";
+static const char GT_PROC_FEATURES_OFF[] = "proc_features_off";
+static const char GT_PTHREAD[] = "pthread";
+static const char GT_MINIMAL_INIT[] = "minimal_init_off";
+
+static struct dentry *gt_root;
+
+
+/* Type for function that handles string grabbed from userspace */
+typedef int (*sh_t)(char *);
+
+/* Type for function that handles unsigned long grabbed from userspace */
+typedef int (*ulh_t)(unsigned long);
+
+/* Type for function that handles pid grabbed from userspace */
+typedef int (*ph_t)(pid_t);
+
+
+static ssize_t get_string_and_call(const char __user *buf, size_t len,
+                                  sh_t cb)
+{
+       char *string;
+       ssize_t ret;
+
+       string = kmalloc(len, GFP_KERNEL);
+       if (string == NULL) {
+               ret = -ENOMEM;
+               goto get_string_write_out;
+       }
+
+       if (copy_from_user(string, buf, len)) {
+               ret = -EINVAL;
+               goto get_string_write_out;
+       }
+
+       string[len - 1] = '\0';
+
+       ret = cb(string);
+
+get_string_write_out:
+       kfree(string);
+
+       return ret == 0 ? len : ret;
+}
+
+static ssize_t get_ul_and_call(const char __user *buf, size_t len, ulh_t cb)
+{
+       ssize_t ret;
+       char *ulstring;
+       unsigned long ul;
+
+       ulstring = kmalloc(len, GFP_KERNEL);
+       if (ulstring == NULL) {
+               ret = -ENOMEM;
+               goto get_ul_write_out;
+       }
+
+       if (copy_from_user(ulstring, buf, len)) {
+               ret = -EINVAL;
+               goto get_ul_write_out;
+       }
+
+       ulstring[len - 1] = '\0';
+
+       ret = kstrtoul(ulstring, 16, &ul);
+       if (ret != 0)
+               goto get_ul_write_out;
+
+       ret = cb(ul);
+
+get_ul_write_out:
+       kfree(ulstring);
+
+       return ret == 0 ? len : ret;
+}
+
+static ssize_t get_pid_and_call(const char __user *buf, size_t len, ph_t cb)
+{
+       ssize_t ret;
+       char *pidstring;
+       pid_t pid;
+
+       pidstring = kmalloc(len, GFP_KERNEL);
+       if (pidstring == NULL) {
+               ret = -ENOMEM;
+               goto get_pid_write_out;
+       }
+
+       if (copy_from_user(pidstring, buf, len)) {
+               ret = -EINVAL;
+               goto get_pid_write_out;
+       }
+
+       pidstring[len - 1] = '\0';
+
+       ret = kstrtoul(pidstring, 10, (unsigned long *)&pid);
+       if (ret != 0)
+               goto get_pid_write_out;
+
+       ret = cb(pid);
+
+get_pid_write_out:
+       kfree(pidstring);
+
+       return ret == 0 ? len : ret;
+}
+
+/* ===========================================================================
+ * =                              TARGETS                                    =
+ * ===========================================================================
+ */
+
+static ssize_t handler_path_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_set_handler_path);
+}
+
+static ssize_t handler_fixup_off_write(struct file *file,
+                                      const char __user *buf, size_t len,
+                                      loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_handler_fixup_off);
+}
+
+static ssize_t handler_reloc_off_write(struct file *file,
+                                      const char __user *buf, size_t len,
+                                      loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_handler_reloc_off);
+}
+
+static ssize_t proc_features_off_write(struct file *file,
+                                      const char __user *buf, size_t len,
+                                      loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_proc_features_off);
+}
+
+static const struct file_operations handler_path_fops = {
+       .owner = THIS_MODULE,
+       .write = handler_path_write,
+};
+
+static const struct file_operations handler_fixup_off_fops = {
+       .owner = THIS_MODULE,
+       .write = handler_fixup_off_write,
+};
+
+static const struct file_operations handler_reloc_off_fops = {
+       .owner = THIS_MODULE,
+       .write = handler_reloc_off_write,
+};
+
+static const struct file_operations proc_features_off_fops = {
+       .owner = THIS_MODULE,
+       .write = proc_features_off_write,
+};
+
+/* ===========================================================================
+ * =                              TARGETS                                    =
+ * ===========================================================================
+ */
+
+static ssize_t by_path_add_write(struct file *file, const char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_add_by_path);
+}
+
+static ssize_t by_path_del_write(struct file *file, const char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_del_by_path);
+}
+
+static ssize_t by_pid_add_write(struct file *file, const char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       return get_pid_and_call(buf, len, gtm_add_by_pid);
+}
+
+static ssize_t by_pid_del_write(struct file *file, const char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       return get_pid_and_call(buf, len, gtm_del_by_pid);
+}
+
+static ssize_t by_id_add_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_add_by_id);
+}
+
+static ssize_t by_id_del_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_del_by_id);
+}
+
+static ssize_t del_all_write(struct file *file, const char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+
+       ret = gtm_del_all();
+
+       return ret == 0 ? len : ret;
+}
+
+static ssize_t target_read(struct file *file, char __user *buf,
+                          size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *targets;
+
+       ret = gtm_get_targets(&targets);
+       if (ret < 0)
+               return ret;
+
+       ret = simple_read_from_buffer(buf, len, ppos, targets, ret);
+       kfree(targets);
+
+       return ret;
+}
+
+static const struct file_operations by_path_add_fops = {
+       .owner = THIS_MODULE,
+       .write = by_path_add_write,
+};
+
+static const struct file_operations by_path_del_fops = {
+       .owner = THIS_MODULE,
+       .write = by_path_del_write,
+};
+
+static const struct file_operations by_pid_add_fops = {
+       .owner = THIS_MODULE,
+       .write = by_pid_add_write,
+};
+
+static const struct file_operations by_pid_del_fops = {
+       .owner = THIS_MODULE,
+       .write = by_pid_del_write,
+};
+
+static const struct file_operations by_id_add_fops = {
+       .owner = THIS_MODULE,
+       .write = by_id_add_write,
+};
+
+static const struct file_operations by_id_del_fops = {
+       .owner = THIS_MODULE,
+       .write = by_id_del_write,
+};
+
+static const struct file_operations del_all_fops = {
+       .owner = THIS_MODULE,
+       .write = del_all_write,
+};
+
+static const struct file_operations target_fops = {
+       .owner = THIS_MODULE,
+       .read = target_read,
+};
+
+/* ===========================================================================
+ * =                              ENABLE                                     =
+ * ===========================================================================
+ */
+
+static ssize_t enable_read(struct file *file, char __user *buf,
+                          size_t len, loff_t *ppos)
+{
+       char val[2];
+
+       val[0] = (gtm_status() == GT_ON ? '1' : '0');
+       val[1] = '\0';
+
+       return simple_read_from_buffer(buf, len, ppos, val, 2);
+}
+
+static ssize_t enable_write(struct file *file, const char __user *buf,
+                           size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char val[2];
+       size_t val_size;
+
+       val_size = min(len, (sizeof(val) - 1));
+       if (copy_from_user(val, buf, val_size))
+               return -EFAULT;
+
+       val[1] = '\0';
+       switch(val[0]) {
+       case '0':
+               ret = gtm_switch(GT_OFF);
+               break;
+       case '1':
+               ret = gtm_switch(GT_ON);
+               break;
+       default:
+               printk(GT_PREFIX "Invalid state!\n");
+               return -EINVAL;
+       }
+
+       return ret == 0 ? len : ret;
+}
+
+static const struct file_operations enable_fops = {
+       .owner = THIS_MODULE,
+       .write = enable_write,
+       .read = enable_read,
+};
+
+
+/* ===========================================================================
+ * =                              LINKER                                     =
+ * ===========================================================================
+ */
+
+static ssize_t linker_path_write(struct file *file, const char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_set_linker_path);
+}
+
+static ssize_t fixup_off_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_fixup_off);
+}
+
+static ssize_t reloc_off_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_reloc_off);
+}
+
+static const struct file_operations linker_path_fops = {
+       .owner = THIS_MODULE,
+       .write = linker_path_write,
+};
+
+static const struct file_operations fixup_off_fops = {
+       .owner = THIS_MODULE,
+       .write = fixup_off_write,
+};
+
+static const struct file_operations reloc_off_fops = {
+       .owner = THIS_MODULE,
+       .write = reloc_off_write,
+};
+
+
+
+/* ===========================================================================
+ * =                             PTHREAD                                     =
+ * ===========================================================================
+ */
+
+static ssize_t pthread_path_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_set_pthread_path);
+}
+
+static ssize_t init_off_write(struct file *file, const char __user *buf,
+                             size_t len, loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_init_off);
+}
+
+static const struct file_operations pthread_path_fops = {
+       .owner = THIS_MODULE,
+       .write = pthread_path_write,
+};
+
+static const struct file_operations pthread_init_off_fops = {
+       .owner = THIS_MODULE,
+       .write = init_off_write,
+};
+
+
+
+
+int gtd_init(void)
+{
+       struct dentry *swap_dentry, *root, *linker, *by_path, *by_pid,
+                     *by_id, *handler, *pthread, *dentry;
+       int ret;
+
+       ret = -ENODEV;
+       if (!debugfs_initialized())
+               goto fail;
+
+       ret = -ENOENT;
+       swap_dentry = swap_debugfs_getdir();
+       if (!swap_dentry)
+               goto fail;
+
+       ret = -ENOMEM;
+       root = swap_debugfs_create_dir(GT_FOLDER, swap_dentry);
+       if (IS_ERR_OR_NULL(root))
+               goto fail;
+
+       gt_root = root;
+
+       linker = swap_debugfs_create_dir(GT_LINKER, root);
+       if (IS_ERR_OR_NULL(linker)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_PATH, GT_DEFAULT_PERMS, linker,
+                                         NULL, &linker_path_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_FIXUP_ADDR, GT_DEFAULT_PERMS,
+                                         linker, NULL, &fixup_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_RELOC_ADDR, GT_DEFAULT_PERMS,
+                                         linker, NULL, &reloc_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       by_path = swap_debugfs_create_dir(GT_BY_PATH, root);
+       if (IS_ERR_OR_NULL(by_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_ADD, GT_DEFAULT_PERMS, by_path,
+                                         NULL, &by_path_add_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_DEL, GT_DEFAULT_PERMS, by_path,
+                                         NULL, &by_path_del_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       by_pid = swap_debugfs_create_dir(GT_BY_PID, root);
+       if (IS_ERR_OR_NULL(by_pid)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_ADD, GT_DEFAULT_PERMS, by_pid,
+                                         NULL, &by_pid_add_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_DEL, GT_DEFAULT_PERMS, by_pid,
+                                         NULL, &by_pid_del_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       by_id = swap_debugfs_create_dir(GT_BY_ID, root);
+       if (IS_ERR_OR_NULL(by_id)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_ADD, GT_DEFAULT_PERMS, by_id,
+                                         NULL, &by_id_add_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_DEL, GT_DEFAULT_PERMS, by_id,
+                                         NULL, &by_id_del_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_DEL_ALL, GT_DEFAULT_PERMS, root,
+                                         NULL, &del_all_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_LIST_TARGETS, GT_DEFAULT_PERMS, root,
+                                         NULL, &target_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_ENABLE, GT_DEFAULT_PERMS, root,
+                                         NULL, &enable_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       handler = swap_debugfs_create_dir(GT_HANDLER, root);
+       if (IS_ERR_OR_NULL(handler)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_PATH, GT_DEFAULT_PERMS, handler,
+                                         NULL, &handler_path_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_HANDLER_FIXUP_OFF,
+                                         GT_DEFAULT_PERMS, handler,
+                                         NULL, &handler_fixup_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_HANDLER_RELOC_OFF,
+                                         GT_DEFAULT_PERMS, handler, NULL,
+                                         &handler_reloc_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_PROC_FEATURES_OFF,
+                                         GT_DEFAULT_PERMS, handler, NULL,
+                                         &proc_features_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       pthread = swap_debugfs_create_dir(GT_PTHREAD, root);
+       if (IS_ERR_OR_NULL(pthread)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_PATH, GT_DEFAULT_PERMS, pthread,
+                                         NULL, &pthread_path_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(GT_MINIMAL_INIT, GT_DEFAULT_PERMS,
+                                         pthread, NULL,
+                                         &pthread_init_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       return 0;
+
+remove:
+       debugfs_remove_recursive(root);
+
+fail:
+       printk(GT_PREFIX "Debugfs initialization failure: %d\n", ret);
+
+       return ret;
+}
+
+void gtd_exit(void)
+{
+       if (gt_root)
+               debugfs_remove_recursive(gt_root);
+       gt_root = NULL;
+}
diff --git a/modules/got_patcher/gt_debugfs.h b/modules/got_patcher/gt_debugfs.h
new file mode 100644 (file)
index 0000000..e6d5329
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __GT_DEBUGFS_H__
+#define __GT_DEBUGFS_H__
+
+int gtd_init(void);
+void gtd_exit(void);
+
+#endif /* __GT_DEBUGFS_H__ */
diff --git a/modules/got_patcher/gt_module.c b/modules/got_patcher/gt_module.c
new file mode 100644 (file)
index 0000000..0779177
--- /dev/null
@@ -0,0 +1,1069 @@
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/limits.h>
+#include <kprobe/swap_ktd.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/probes/probe_info_new.h>
+#include <us_manager/us_common_file.h>
+#include <loader/loader.h>
+#include <master/swap_initializer.h>
+#include "gt.h"
+#include "gt_module.h"
+#include "gt_debugfs.h"
+
+
+enum task_id_t {
+       GT_SET_BY_DENTRY,
+       GT_SET_BY_PID,
+       GT_SET_BY_ID,
+};
+
+struct l_probe_el {
+       struct list_head list;
+
+       struct pf_group *pfg;
+       enum task_id_t task_id;
+       union {
+               pid_t tgid;
+               struct dentry *dentry;
+               char *id;
+       };
+
+       struct probe_new p_fixup;
+       struct probe_new p_reloc;
+       struct probe_new p_init;
+};
+
+struct bin_data_t {
+       struct dentry *dentry;
+       unsigned long off;
+};
+
+typedef unsigned long (*rh_t)(struct uretprobe_instance *, struct pt_regs *,
+                             struct hd_t *);
+
+/* Typedef for compare function that removes data from list */
+typedef bool (*cf_t)(struct l_probe_el*, void *);
+
+static LIST_HEAD(_reg_probes);
+static LIST_HEAD(_unreg_probes);
+static DEFINE_MUTEX(_linker_probes_lock);
+
+static enum gt_status _status = GT_OFF;
+static struct bin_data_t _linker_fixup;
+static struct bin_data_t _linker_reloc;
+static struct bin_data_t _handler_fixup;
+static struct bin_data_t _handler_reloc;
+static struct bin_data_t _proc_features;
+static struct bin_data_t _pthread_init;
+
+
+static inline void _lock_probes_list(void)
+{
+       mutex_lock(&_linker_probes_lock);
+}
+
+static inline void _unlock_probes_list(void)
+{
+       mutex_unlock(&_linker_probes_lock);
+}
+
+static inline bool _is_enable(void)
+{
+       return _status == GT_ON;
+}
+
+static inline bool _is_bin_data_available(struct bin_data_t *bin_data)
+{
+       return (bin_data->dentry && bin_data->off);
+}
+
+static inline bool _is_linker_data_available(void)
+{
+       return _is_bin_data_available(&_linker_fixup) &&
+              _is_bin_data_available(&_linker_reloc);
+}
+
+static inline bool _is_handler_data_available(void)
+{
+       return _is_bin_data_available(&_handler_fixup) &&
+              _is_bin_data_available(&_handler_reloc) &&
+              _is_bin_data_available(&_proc_features);
+}
+
+static inline bool _is_pthread_data_available(void)
+{
+       return _is_bin_data_available(&_pthread_init);
+}
+
+
+
+
+/* ===========================================================================
+ * =                           TASK DATA MANIPULATION                        =
+ * ===========================================================================
+ */
+
+static void gt_ktd_init(struct task_struct *task, void *data)
+{
+       bool *in_handler = (bool *)data;
+
+       *in_handler = false;
+}
+
+static void gt_ktd_exit(struct task_struct *task, void *data)
+{
+}
+
+static struct ktask_data gt_ktd = {
+       .init = gt_ktd_init,
+       .exit = gt_ktd_exit,
+       .size = sizeof(bool),
+};
+
+static inline bool _is_in_handler(void)
+{
+       return *(bool *)swap_ktd(&gt_ktd, current);
+}
+
+static inline void _set_in_handler(bool is_in_handler)
+{
+       *(bool *)swap_ktd(&gt_ktd, current) = is_in_handler;
+}
+
+static inline bool _check_by_dentry(struct l_probe_el *l_probe, void *data)
+{
+       struct dentry *dentry = (struct dentry *)data;
+
+       if (l_probe->task_id == GT_SET_BY_DENTRY &&
+           l_probe->dentry == dentry)
+               return true;
+
+       return false;
+}
+
+static inline bool _check_by_pid(struct l_probe_el *l_probe, void *data)
+{
+       pid_t tgid = *(pid_t *)data;
+
+       if (l_probe->task_id == GT_SET_BY_PID &&
+           l_probe->tgid == tgid)
+               return true;
+
+       return false;
+}
+
+static inline bool _check_by_id(struct l_probe_el *l_probe, void *data)
+{
+       char *id = (char *)data;
+
+       if (l_probe->task_id == GT_SET_BY_ID &&
+           strncmp(l_probe->id, id, PATH_MAX))
+               return true;
+
+       return false;
+}
+
+static inline bool _del_all(struct l_probe_el *l_probe, void *data)
+{
+       return true;
+}
+
+/* ===========================================================================
+ * =                            LINKER HANDLERS                              =
+ * ===========================================================================
+ */
+
+static unsigned long _redirect_to_handler(struct uretprobe_instance *ri,
+                                         struct pt_regs *regs,
+                                         struct hd_t *hd, unsigned long off)
+{
+       unsigned long base;
+       unsigned long vaddr;
+
+       base = lpd_get_handlers_base(hd);
+       if (base == 0)
+               return 0;
+
+       vaddr = base + off;
+       loader_module_prepare_ujump(ri, regs, vaddr);
+
+       return vaddr;
+}
+
+static unsigned long _redirect_to_fixup_handler(struct uretprobe_instance *ri,
+                                               struct pt_regs *regs,
+                                               struct hd_t *hd)
+{
+       return _redirect_to_handler(ri, regs, hd, _handler_fixup.off);
+}
+
+static unsigned long _redirect_to_reloc_handler(struct uretprobe_instance *ri,
+                                               struct pt_regs *regs,
+                                               struct hd_t *hd)
+{
+       return _redirect_to_handler(ri, regs, hd, _handler_reloc.off);
+}
+
+static unsigned long _redirect_to_proc_features(struct uretprobe_instance *ri,
+                                               struct pt_regs *regs,
+                                               struct hd_t *hd)
+{
+       return _redirect_to_handler(ri, regs, hd, _proc_features.off);
+}
+
+
+
+static int _process_eh(struct uretprobe_instance *ri, struct pt_regs *regs,
+                      rh_t rh, struct dentry *dentry)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+       struct hd_t *hd;
+       unsigned long vaddr = 0;
+       unsigned long old_pc = swap_get_upc(regs);
+
+       if ((dentry == NULL) || _is_in_handler())
+               goto out_set_orig;
+
+       hd = lpd_get_hd(pd, dentry);
+       if (hd == NULL)
+               goto out_set_orig;
+
+       if ((lpd_get_state(hd) == NOT_LOADED || lpd_get_state(hd) == FAILED) &&
+           lpd_get_init_state(pd)) {
+               vaddr = loader_not_loaded_entry(ri, regs, pd, hd);
+       } else if (lpd_get_state(hd) == LOADED) {
+               _set_in_handler(true);
+               vaddr = rh(ri, regs, hd);
+       }
+
+out_set_orig:
+       loader_set_priv_origin(ri, vaddr);
+
+       /* PC change check */
+       return old_pc != swap_get_upc(regs);
+}
+
+static int dl_fixup_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       return _process_eh(ri, regs, &_redirect_to_fixup_handler,
+                          _handler_fixup.dentry);
+}
+
+
+
+static void _restore_exec(struct uretprobe_instance *ri, struct hd_t *hd)
+{
+       if (_is_in_handler())
+               _set_in_handler(false);
+}
+
+static int _process_rh(struct uretprobe_instance *ri, struct pt_regs *regs,
+                      rh_t rh, struct dentry *dentry)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+       struct hd_t *hd;
+
+       if (dentry == NULL)
+               return 0;
+
+       hd = lpd_get_hd(pd, dentry);
+       if (hd == NULL)
+               return 0;
+
+       switch (lpd_get_state(hd)) {
+       case NOT_LOADED:
+               break;
+       case LOADING:
+               loader_loading_ret(ri, regs, pd, hd);
+               /* Patch all binaries */
+               if (lpd_get_state(hd))
+                       rh(ri, regs, hd);
+               break;
+       case LOADED:
+               /* TODO Check does we need this if library is loaded
+                * with RTLD_NOW ? */
+               _restore_exec(ri, hd);
+               break;
+       case FAILED:
+               loader_failed_ret(ri, regs, pd, hd);
+               break;
+       case ERROR:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int common_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       return _process_rh(ri, regs, &_redirect_to_proc_features,
+                          _proc_features.dentry);
+}
+
+/* TODO Make ordinary interface. Now real data_size is set in init, because
+ * it is unknown in this module during compile time. */
+static struct probe_desc pin_fixup = MAKE_URPROBE(dl_fixup_eh, common_rh, 0);
+
+
+static int dl_reloc_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       return _process_eh(ri, regs, &_redirect_to_reloc_handler,
+                          _handler_reloc.dentry);
+}
+
+/* TODO Make ordinary interface. Now real data_size is set in init, because
+ * it is unknown in this module during compile time. */
+static struct probe_desc pin_reloc = MAKE_URPROBE(dl_reloc_eh, common_rh, 0);
+
+
+static int pthread_init_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+
+       /* Wait until pthread is inited, if it is going to be inited before
+        * loading our library */
+       lpd_set_init_state(pd, false);
+
+       return 0;
+}
+
+static int pthread_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+
+       lpd_set_init_state(pd, true);
+
+       return 0;
+}
+
+/* TODO Make ordinary interface. Now real data_size is set in init, because
+ * it is unknown in this module during compile time. */
+static struct probe_desc pin_pinit = MAKE_URPROBE(pthread_init_eh,
+                                                pthread_init_rh, 0);
+
+
+static int _register_probe_el_no_lock(struct l_probe_el *l_probe)
+{
+       int ret;
+
+       /* register 'fix_up' */
+       l_probe->p_fixup.desc = &pin_fixup;
+       l_probe->p_fixup.offset = _linker_fixup.off;
+       ret = pin_register(&l_probe->p_fixup, l_probe->pfg,
+                          _linker_fixup.dentry);
+       if (ret != 0) {
+               printk(GT_PREFIX "Error register linker fixup probe. "
+                                "Linker dentry %s, "
+                                "dl_fixup() offset = 0x%lx\n",
+                                _linker_fixup.dentry->d_name.name,
+                                _linker_fixup.off);
+               return ret;
+       }
+
+       /* register 'reloc' */
+       l_probe->p_reloc.desc = &pin_reloc;
+       l_probe->p_reloc.offset = _linker_reloc.off;
+       ret = pin_register(&l_probe->p_reloc, l_probe->pfg,
+                          _linker_reloc.dentry);
+       if (ret != 0) {
+               printk(GT_PREFIX "Error register linker reloc probe. "
+                                 "Linker dentry %s, "
+                                "dl_reloc() offset = 0x%lx\n",
+                                _linker_reloc.dentry->d_name.name,
+                                _linker_reloc.off);
+
+               goto reg_probe_el_fail;
+       }
+
+       /* register 'init' */
+       l_probe->p_init.desc = &pin_pinit;
+       l_probe->p_init.offset = _pthread_init.off;
+       ret = pin_register(&l_probe->p_init, l_probe->pfg,
+                          _pthread_init.dentry);
+       if (ret != 0) {
+               printk(GT_PREFIX "Error register pthread minimal init. "
+                                "Pthread dentry %s, "
+                                "__pthread_minimal_init() offset = 0x%lx\n",
+                                _pthread_init.dentry->d_name.name,
+                                _pthread_init.off);
+
+               goto reg_probe_pthread_fail;
+       }
+
+       return 0;
+
+reg_probe_pthread_fail:
+       pin_unregister(&l_probe->p_reloc, l_probe->pfg);
+
+reg_probe_el_fail:
+       pin_unregister(&l_probe->p_fixup, l_probe->pfg);
+
+       return ret;
+}
+
+static int _unregister_probe_el_no_lock(struct l_probe_el *l_probe)
+{
+       pin_unregister(&l_probe->p_init, l_probe->pfg);
+       pin_unregister(&l_probe->p_reloc, l_probe->pfg);
+       pin_unregister(&l_probe->p_fixup, l_probe->pfg);
+
+       return 0;
+}
+
+static int _disable_got_patcher(void)
+{
+       struct l_probe_el *l_probe;
+       int ret = 0;
+
+       if (!_is_linker_data_available())
+               return -EINVAL;
+
+       _lock_probes_list();
+
+       list_for_each_entry(l_probe, &_reg_probes, list) {
+               ret = _unregister_probe_el_no_lock(l_probe);
+               if (ret == 0)
+                       list_move_tail(&l_probe->list, &_unreg_probes);
+       }
+
+       _unlock_probes_list();
+
+       _status = GT_OFF;
+
+       return ret;
+}
+
+static int _enable_got_patcher(void)
+{
+       struct l_probe_el *l_probe;
+       int ret;
+
+       if (!_is_linker_data_available() || !_is_handler_data_available() ||
+           !_is_pthread_data_available())
+               return -EINVAL;
+
+       _lock_probes_list();
+
+       list_for_each_entry(l_probe, &_unreg_probes, list) {
+               ret = _register_probe_el_no_lock(l_probe);
+               if (ret == 0)
+                       list_move_tail(&l_probe->list, &_reg_probes);
+               else
+                       goto enable_patcher_fail_unlock;
+       }
+
+       _unlock_probes_list();
+
+       _status = GT_ON;
+
+       return 0;
+enable_patcher_fail_unlock:
+       _unlock_probes_list();
+
+       printk(GT_PREFIX "Error registering linker probes, disabling...");
+       _disable_got_patcher();
+
+       return ret;
+}
+
+
+/* ===========================================================================
+ * =                           LIST MANIPULATIONS                           =
+ * ===========================================================================
+ */
+static struct l_probe_el *_create_linker_probe_el(void)
+{
+       struct l_probe_el *l_probe;
+
+       l_probe = kzalloc(sizeof(*l_probe), GFP_KERNEL);
+       if (l_probe == NULL)
+               return NULL;
+
+       INIT_LIST_HEAD(&l_probe->list);
+
+       return l_probe;
+}
+
+static void _destroy_linker_probe_el_no_lock(struct l_probe_el *l_probe)
+{
+       if (l_probe->pfg)
+               put_pf_group(l_probe->pfg);
+
+       if (l_probe->task_id == GT_SET_BY_DENTRY && l_probe->dentry != NULL)
+               swap_put_dentry(l_probe->dentry);
+
+       if (l_probe->task_id == GT_SET_BY_ID && l_probe->id != NULL)
+               kfree(l_probe->id);
+
+       kfree(l_probe);
+}
+
+static void _clean_linker_probes(void)
+{
+       struct l_probe_el *l_probe, *n;
+       int ret;
+
+       _lock_probes_list();
+
+       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
+               ret = _unregister_probe_el_no_lock(l_probe);
+               if (ret != 0)
+                       printk(GT_PREFIX "Cannot remove linker probe!\n");
+               list_del(&l_probe->list);
+               _destroy_linker_probe_el_no_lock(l_probe);
+       }
+
+       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
+               list_del(&l_probe->list);
+               _destroy_linker_probe_el_no_lock(l_probe);
+       }
+
+       _unlock_probes_list();
+}
+
+
+/* ===========================================================================
+ * =                          STRING MANIPULATIONS                           =
+ * ===========================================================================
+ */
+
+static size_t _get_dentry_len(struct dentry *dentry)
+{
+       return strnlen(dentry->d_name.name, PATH_MAX);
+}
+
+static size_t _get_pid_len(pid_t pid)
+{
+       /* FIXME Return constant - maximum digits for 10-based unsigned long on
+        * 64 bit architecture to avoid complicated evaluations. */
+        return 20;
+}
+
+static size_t _get_id_len(char *id)
+{
+       return strnlen(id, PATH_MAX);
+}
+
+static size_t _get_item_len(struct l_probe_el *l_probe)
+{
+       if (l_probe->task_id == GT_SET_BY_DENTRY)
+               return _get_dentry_len(l_probe->dentry);
+       else if (l_probe->task_id == GT_SET_BY_PID)
+               return _get_pid_len(l_probe->tgid);
+       else if (l_probe->task_id == GT_SET_BY_ID)
+               return _get_id_len(l_probe->id);
+
+       printk(GT_PREFIX "Error! Unknown process identificator!\n");
+       return 0;
+}
+
+static char *_copy_dentry_item(char *dest, struct dentry *dentry)
+{
+       size_t len;
+
+       len = strnlen(dentry->d_name.name, PATH_MAX);
+       memcpy(dest, dentry->d_name.name, len);
+
+       return (dest + len);
+}
+
+static char *_copy_pid_item(char *dest, pid_t pid)
+{
+       int ret;
+       size_t len;
+
+       len = _get_pid_len(pid);
+
+       ret = snprintf(dest, len, "%lu", (unsigned long)pid);
+       if (ret >= len)
+               printk(GT_PREFIX "PID string is truncated!\n");
+
+       return (dest + ret);
+}
+
+static char *_copy_id_item(char *dest, char *id)
+{
+       size_t len;
+
+       len = strnlen(id, PATH_MAX);
+       memcpy(dest, id, len);
+
+       return (dest + len);
+}
+
+static char *_copy_item(char *dest, struct l_probe_el *l_probe)
+{
+       if (l_probe->task_id == GT_SET_BY_DENTRY)
+               return _copy_dentry_item(dest, l_probe->dentry);
+       else if (l_probe->task_id == GT_SET_BY_PID)
+               return _copy_pid_item(dest, l_probe->tgid);
+       else if (l_probe->task_id == GT_SET_BY_ID)
+               return _copy_id_item(dest, l_probe->id);
+
+       printk(GT_PREFIX "Error! Unknown process identificator!\n");
+       return dest;
+}
+
+static char *_add_separator(char *dest)
+{
+       const char sep = ':';
+
+       *dest = sep;
+
+       return (dest + 1);
+}
+
+static int _add_to_list(struct l_probe_el *l_probe)
+{
+       int ret = 0;
+
+       _lock_probes_list();
+       if (_is_enable()) {
+               ret = _register_probe_el_no_lock(l_probe);
+               if (ret == 0)
+                       list_add_tail(&l_probe->list, &_reg_probes);
+       } else {
+               list_add_tail(&l_probe->list, &_unreg_probes);
+       }
+
+       _unlock_probes_list();
+
+       return ret;
+}
+
+static int _remove_from_list(cf_t cb, void *data)
+{
+       struct l_probe_el *l_probe, *n;
+       int ret = 0;
+
+       _lock_probes_list();
+
+       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
+               if (cb(l_probe, data)) {
+                       ret = _unregister_probe_el_no_lock(l_probe);
+                       if (ret == 0) {
+                               list_del(&l_probe->list);
+                               _destroy_linker_probe_el_no_lock(l_probe);
+                       }
+                       goto remove_from_list_unlock;
+               }
+       }
+
+       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
+               if (cb(l_probe, data)) {
+                       list_del(&l_probe->list);
+                       _destroy_linker_probe_el_no_lock(l_probe);
+                       goto remove_from_list_unlock;
+               }
+       }
+
+remove_from_list_unlock:
+       _unlock_probes_list();
+
+       return ret;
+}
+
+
+
+
+int gtm_set_linker_path(char *path)
+{
+       struct dentry *dentry;
+
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL)
+               return -EINVAL;
+
+       /* We use get_dentry only once, so use put dentry also only once */
+       if (_linker_fixup.dentry != NULL ||
+           _linker_reloc.dentry != NULL) {
+               if (_linker_fixup.dentry != NULL)
+                       swap_put_dentry(_linker_fixup.dentry);
+               else
+                       swap_put_dentry(_linker_reloc.dentry);
+       }
+
+       _linker_fixup.dentry = dentry;
+       _linker_reloc.dentry = dentry;
+
+       return 0;
+}
+
+int gtm_set_fixup_off(unsigned long offset)
+{
+       _linker_fixup.off = offset;
+
+       return 0;
+}
+
+int gtm_set_reloc_off(unsigned long offset)
+{
+       _linker_reloc.off = offset;
+
+       return 0;
+}
+
+int gtm_switch(enum gt_status stat)
+{
+       int ret;
+
+       switch (stat) {
+       case GT_ON:
+               ret = _enable_got_patcher();
+               break;
+       case GT_OFF:
+               ret = _disable_got_patcher();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+enum gt_status gtm_status(void)
+{
+       return _status;
+}
+
+int gtm_add_by_path(char *path)
+{
+       struct dentry *dentry;
+       struct pf_group *pfg;
+       struct l_probe_el *l_probe;
+       int ret;
+
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL)
+               return -EINVAL;
+
+       pfg = get_pf_group_by_dentry(dentry, dentry);
+       if (pfg == NULL) {
+               ret = -ENOMEM;
+               goto add_by_path_put_dentry;
+       }
+
+       l_probe = _create_linker_probe_el();
+       if (l_probe == NULL) {
+               ret = -ENOMEM;
+               goto add_by_path_put_pfg;
+       }
+
+       l_probe->pfg = pfg;
+       l_probe->task_id = GT_SET_BY_DENTRY;
+       l_probe->dentry = dentry;
+
+       ret = _add_to_list(l_probe);
+       if (ret != 0)
+               goto add_by_path_free;
+
+       return 0;
+
+add_by_path_free:
+       kfree(l_probe);
+
+add_by_path_put_pfg:
+       put_pf_group(pfg);
+
+add_by_path_put_dentry:
+       swap_put_dentry(dentry);
+
+       return ret;
+}
+
+int gtm_add_by_pid(pid_t pid)
+{
+       struct pf_group *pfg;
+       struct l_probe_el *l_probe;
+       int ret;
+
+       /* TODO Add dentry as private data */
+       pfg = get_pf_group_by_tgid(pid, NULL);
+       if (pfg == NULL)
+               return -ENOMEM;
+
+       l_probe = _create_linker_probe_el();
+       if (l_probe == NULL) {
+               ret = -ENOMEM;
+               goto add_by_pid_put_pfg;
+       }
+
+       l_probe->pfg = pfg;
+       l_probe->task_id = GT_SET_BY_PID;
+       l_probe->tgid = pid;
+
+       ret = _add_to_list(l_probe);
+       if (ret != 0)
+               goto add_by_pid_free;
+
+       return 0;
+
+add_by_pid_free:
+       kfree(l_probe);
+
+add_by_pid_put_pfg:
+       put_pf_group(pfg);
+
+       return ret;
+}
+
+int gtm_add_by_id(char *id)
+{
+       char *new_id;
+       struct pf_group *pfg;
+       struct l_probe_el *l_probe;
+       size_t len;
+       int ret;
+
+       len = strnlen(id, PATH_MAX);
+       new_id = kmalloc(len, GFP_KERNEL);
+       if (new_id == NULL)
+               return -ENOMEM;
+
+       /* TODO Add dentry as private data */
+       pfg = get_pf_group_by_comm(id, NULL);
+       if (pfg == NULL) {
+               ret = -ENOMEM;
+               goto add_by_id_free_id;
+       }
+
+       l_probe = _create_linker_probe_el();
+       if (l_probe == NULL) {
+               ret = -ENOMEM;
+               goto add_by_id_put_pfg;
+       }
+
+       l_probe->pfg = pfg;
+       l_probe->task_id = GT_SET_BY_ID;
+       l_probe->id = new_id;
+
+       ret = _add_to_list(l_probe);
+       if (ret != 0)
+               goto add_by_id_free;
+
+       return 0;
+
+add_by_id_free:
+       kfree(l_probe);
+
+add_by_id_put_pfg:
+       put_pf_group(pfg);
+
+add_by_id_free_id:
+       kfree(new_id);
+
+       return ret;
+}
+
+int gtm_del_by_path(char *path)
+{
+       struct dentry *dentry;
+       int ret = 0;
+
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL)
+               return -EINVAL;
+
+       ret = _remove_from_list(_check_by_dentry, dentry);
+
+       return ret;
+}
+
+int gtm_del_by_pid(pid_t pid)
+{
+       int ret = 0;
+
+       ret = _remove_from_list(_check_by_pid, &pid);
+
+       return ret;
+}
+
+int gtm_del_by_id(char *id)
+{
+       int ret = 0;
+
+       ret = _remove_from_list(_check_by_id, id);
+
+       return ret;
+}
+
+int gtm_del_all(void)
+{
+       int ret = 0;
+
+       ret = _remove_from_list(_del_all, NULL);
+
+       return ret;
+}
+
+ssize_t gtm_get_targets(char **targets)
+{
+       struct l_probe_el *l_probe;
+       char *ptr;
+       size_t len = 0;
+
+       _lock_probes_list();
+       list_for_each_entry(l_probe, &_reg_probes, list) {
+               /* Add separator */
+               len += _get_item_len(l_probe) + 1;
+       }
+
+       list_for_each_entry(l_probe, &_unreg_probes, list) {
+               /* Add separator */
+               len += _get_item_len(l_probe) + 1;
+       }
+       _unlock_probes_list();
+
+       *targets = kmalloc(len, GFP_KERNEL);
+       if (*targets == NULL)
+               return -ENOMEM;
+
+       ptr = *targets;
+
+       _lock_probes_list();
+
+       list_for_each_entry(l_probe, &_reg_probes, list) {
+               ptr = _copy_item(ptr, l_probe);
+               ptr = _add_separator(ptr);
+       }
+
+       list_for_each_entry(l_probe, &_unreg_probes, list) {
+               ptr = _copy_item(ptr, l_probe);
+               ptr = _add_separator(ptr);
+       }
+
+       _unlock_probes_list();
+
+       *targets[len - 1] = '\0';
+
+       return len;
+}
+
+int gtm_set_handler_path(char *path)
+{
+       struct dentry *dentry;
+       int ret;
+
+       /* We use get_dentry only once, so use put dentry also only once */
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL)
+               return -EINVAL;
+
+       if (_handler_fixup.dentry)
+               swap_put_dentry(_handler_fixup.dentry);
+
+       if (_handler_reloc.dentry)
+               swap_put_dentry(_handler_reloc.dentry);
+
+       if (_proc_features.dentry)
+               swap_put_dentry(_proc_features.dentry);
+
+       _handler_fixup.dentry = dentry;
+       _handler_reloc.dentry = dentry;
+       _proc_features.dentry = dentry;
+
+       /* TODO Do smth with this:
+        * make interface for loader to remove handlers
+        * and add/delete when gtm_set_handler() is called
+        * Check container_of() may be useful */
+       ret = loader_add_handler(path);
+
+       return ret;
+}
+
+int gtm_set_handler_fixup_off(unsigned long offset)
+{
+       _handler_fixup.off = offset;
+
+       return 0;
+}
+
+int gtm_set_handler_reloc_off(unsigned long offset)
+{
+       _handler_reloc.off = offset;
+
+       return 0;
+}
+
+int gtm_set_proc_features_off(unsigned long offset)
+{
+       _proc_features.off = offset;
+
+       return 0;
+}
+
+int gtm_set_pthread_path(char *path)
+{
+       struct dentry *dentry;
+
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL)
+               return -EINVAL;
+
+       if (_pthread_init.dentry != NULL)
+               swap_put_dentry(_pthread_init.dentry);
+
+       _pthread_init.dentry = dentry;
+
+       return 0;
+}
+
+int gtm_set_init_off(unsigned long offset)
+{
+       _pthread_init.off = offset;
+
+       return 0;
+}
+
+static int gtm_init(void)
+{
+       int ret;
+
+       ret = gtd_init();
+       if (ret)
+               goto gtd_init_err;
+
+       ret = swap_ktd_reg(&gt_ktd);
+       if (ret)
+               goto gtd_ktd_reg_err;
+
+       return 0;
+
+gtd_ktd_reg_err:
+       gtd_exit();
+
+gtd_init_err:
+       return ret;
+}
+
+static void gtm_exit(void)
+{
+       swap_ktd_unreg(&gt_ktd);
+       gtd_exit();
+
+       _clean_linker_probes();
+
+       /* We use get_dentry only once, so use put dentry also only once */
+       if (_handler_fixup.dentry != NULL ||
+           _handler_reloc.dentry != NULL) {
+               if (_handler_fixup.dentry != NULL)
+                       swap_put_dentry(_handler_fixup.dentry);
+               else
+                       swap_put_dentry(_handler_reloc.dentry);
+               _handler_reloc.dentry = NULL;
+               _handler_fixup.dentry = NULL;
+       }
+}
+
+SWAP_LIGHT_INIT_MODULE(NULL, gtm_init, gtm_exit, NULL, NULL);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP GOT Patcher Module");
+MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/modules/got_patcher/gt_module.h b/modules/got_patcher/gt_module.h
new file mode 100644 (file)
index 0000000..7e1b151
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __GT_MODULE_H__
+#define __GT_MODULE_H__
+
+#include <linux/types.h>
+
+enum gt_status {
+       GT_ON,
+       GT_OFF
+};
+
+/* Linker data */
+int gtm_set_linker_path(char *path);
+int gtm_set_fixup_off(unsigned long offset);
+int gtm_set_reloc_off(unsigned long offset);
+int gtm_switch(enum gt_status stat);
+enum gt_status gtm_status(void);
+
+/* Target processes data */
+int gtm_add_by_path(char *path);
+int gtm_add_by_pid(pid_t pid);
+int gtm_add_by_id(char *id);
+int gtm_del_by_path(char *path);
+int gtm_del_by_pid(pid_t pid);
+int gtm_del_by_id(char *id);
+int gtm_del_all(void);
+/* Returns len on success, error code on fail.
+ * Allocates memory with malloc(), caller should free it */
+ssize_t gtm_get_targets(char **targets);
+
+/* Handlers data */
+int gtm_set_handler_path(char *path);
+int gtm_set_handler_fixup_off(unsigned long offset);
+int gtm_set_handler_reloc_off(unsigned long offset);
+int gtm_set_proc_features_off(unsigned long offset);
+
+/* Pthread data */
+int gtm_set_pthread_path(char *path);
+int gtm_set_init_off(unsigned long offset);
+
+#endif /* __GT_MODULE_H__ */
diff --git a/modules/kprobe/Kbuild b/modules/kprobe/Kbuild
new file mode 100644 (file)
index 0000000..e6d12ca
--- /dev/null
@@ -0,0 +1,44 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_kprobe.o
+swap_kprobe-y := \
+       swap_kprobes_deps.o \
+       swap_slots.o \
+       swap_td_raw.o \
+       swap_ktd.o
+
+
+### ARM64
+swap_kprobe-$(CONFIG_ARM64) += \
+       arch/arm64/swap-asm/simulate-insn.o \
+       arch/arm64/swap-asm/condn-helpers.o
+
+
+ifeq ($(CONFIG_SWAP_KERNEL_IMMUTABLE), y)
+
+swap_kprobe-y += swap_no_kprobes.o
+
+else # CONFIG_SWAP_KERNEL_IMMUTABLE
+
+swap_kprobe-y += swap_kprobes.o
+
+### ARM
+swap_kprobe-$(CONFIG_ARM) += \
+       arch/arm/swap-asm/swap_kprobes.o \
+       ../arch/arm/probes/probes_arm.o
+
+ifeq ($(CONFIG_STRICT_MEMORY_RWX), y)
+swap_kprobe-$(CONFIG_ARM) += arch/arm/swap-asm/memory_rwx.o
+endif #ifeq ($(CONFIG_STRICT_MEMORY_RWX), y)
+
+
+### ARM64
+swap_kprobe-$(CONFIG_ARM64) += arch/arm64/swap-asm/swap_kprobes.o \
+                               arch/arm64/swap-asm/dbg_interface.o \
+                               arch/arm64/swap-asm/kprobes-arm64.o
+
+
+### X86
+swap_kprobe-$(CONFIG_X86) += arch/x86/swap-asm/swap_kprobes.o
+
+endif # CONFIG_SWAP_KERNEL_IMMUTABLE
diff --git a/modules/kprobe/arch/arm/swap-asm/memory_rwx.c b/modules/kprobe/arch/arm/swap-asm/memory_rwx.c
new file mode 100644 (file)
index 0000000..c7a9510
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
+ *
+ * @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, 2014
+ */
+
+
+#include <asm/page.h>
+#include <asm/cacheflush.h>
+#include <asm/mmu_writeable.h>
+
+
+#include <ksyms/ksyms.h>
+
+
+static struct mm_struct *swap_init_mm;
+static int (*swap_set_memory_ro)(unsigned long addr, int numpages);
+static int (*swap_set_memory_rw)(unsigned long addr, int numpages);
+
+
+static int get_pte_cb(pte_t *ptep, pgtable_t token,
+                     unsigned long addr, void *data)
+{
+       *(pte_t *)data = *ptep;
+
+       return 1;
+}
+
+static pte_t get_pte(unsigned long page_addr)
+{
+       pte_t pte = 0;
+
+       apply_to_page_range(swap_init_mm, page_addr,
+                           PAGE_SIZE, get_pte_cb, &pte);
+
+       return pte;
+}
+
+static void write_to_module(unsigned long addr, unsigned long val)
+{
+       unsigned long *maddr = (unsigned long *)addr;
+       unsigned long page_addr = addr & PAGE_MASK;
+       pte_t pte;
+
+       pte = get_pte(page_addr);
+       if (pte_write(pte) == 0) {
+               unsigned long flags;
+               DEFINE_SPINLOCK(mem_lock);
+
+               spin_lock_irqsave(&mem_lock, flags);
+               if (swap_set_memory_rw(page_addr, 1) == 0) {
+                       *maddr = val;
+                       swap_set_memory_ro(page_addr, 1);
+               } else {
+                       printk(KERN_INFO "RWX: failed to write memory %08lx (%08lx)\n",
+                              addr, val);
+               }
+               spin_unlock_irqrestore(&mem_lock, flags);
+       } else {
+               *maddr = val;
+       }
+
+       flush_icache_range(addr, addr + sizeof(long));
+}
+
+void mem_rwx_write_u32(unsigned long addr, unsigned long val)
+{
+       if (addr < MODULES_VADDR || addr >= MODULES_END) {
+               /*
+                * if addr doesn't belongs kernel space,
+                * segmentation fault will occur
+                */
+               mem_text_write_kernel_word((long *)addr, val);
+       } else {
+               write_to_module(addr, val);
+       }
+}
+
+int mem_rwx_once(void)
+{
+       const char *sym;
+
+       sym = "set_memory_ro";
+       swap_set_memory_ro = (void *)swap_ksyms(sym);
+       if (swap_set_memory_ro == NULL)
+               goto not_found;
+
+       sym = "set_memory_rw";
+       swap_set_memory_rw = (void *)swap_ksyms(sym);
+       if (swap_set_memory_rw == NULL)
+               goto not_found;
+
+       sym = "init_mm";
+       swap_init_mm = (void *)swap_ksyms(sym);
+       if (swap_init_mm == NULL)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
diff --git a/modules/kprobe/arch/arm/swap-asm/memory_rwx.h b/modules/kprobe/arch/arm/swap-asm/memory_rwx.h
new file mode 100644 (file)
index 0000000..f533965
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * @file kprobe/arch/asm-arm/memory_rwx.h
+ *
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
+ *
+ * @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, 2014
+ */
+
+
+#ifndef _MEMORY_RWX_H
+#define _MEMORY_RWX_H
+
+
+int mem_rwx_once(void);
+void mem_rwx_write_u32(unsigned long addr, unsigned long val);
+
+
+#endif /* _MEMORY_RWX_H */
diff --git a/modules/kprobe/arch/arm/swap-asm/swap_kprobes.c b/modules/kprobe/arch/arm/swap-asm/swap_kprobes.c
new file mode 100644 (file)
index 0000000..5b510cf
--- /dev/null
@@ -0,0 +1,552 @@
+/**
+ * kprobe/arch/asm-arm/swap_kprobes.c
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation; Support x86.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ * @author Alexander Shirshikov <a.shirshikov@samsung.com>: initial implementation for Thumb
+ * @author Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
+ * @author Stanislav Andreev <s.andreev@samsung.com>: redesign of kprobe functionality -
+ * kprobe_handler() now called via undefined instruction hooks
+ * @author Stanislav Andreev <s.andreev@samsung.com>: hash tables search implemented for uprobes
+ *
+ * @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, 2006-2014
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP kprobe implementation for ARM architecture.
+ */
+
+
+#include <linux/kconfig.h>
+
+#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
+# error "Kernel is immutable"
+#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
+
+
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <asm/traps.h>
+#include <linux/ptrace.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <ksyms/ksyms.h>
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_kdebug.h>
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <arch/arm/probes/probes_arm.h>
+#include "swap_kprobes.h"
+
+
+static void (*__swap_register_undef_hook)(struct undef_hook *hook);
+static void (*__swap_unregister_undef_hook)(struct undef_hook *hook);
+
+
+/**
+ * @brief Creates trampoline for kprobe.
+ *
+ * @param p Pointer to kp_core.
+ * @param sm Pointer to slot manager
+ * @return 0 on success, error code on error.
+ */
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
+{
+       u32 *tramp;
+       int ret;
+
+       tramp = swap_slot_alloc(sm);
+       if (tramp == NULL)
+               return -ENOMEM;
+
+       p->opcode = *(unsigned long *)p->addr;
+       ret = make_trampoline_arm(p->addr, p->opcode, tramp);
+       if (ret) {
+               swap_slot_free(sm, tramp);
+               return ret;
+       }
+
+       flush_icache_range((unsigned long)tramp,
+                          (unsigned long)tramp + KPROBES_TRAMP_LEN);
+
+       p->ainsn.insn = (unsigned long *)tramp;
+
+       return 0;
+}
+
+/**
+ * @brief Prepares singlestep for current CPU.
+ *
+ * @param p Pointer to kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+static void prepare_singlestep(struct kp_core *p, struct pt_regs *regs)
+{
+       regs->ARM_pc = (unsigned long)p->ainsn.insn;
+}
+
+static void save_previous_kp_core(struct kp_core_ctlblk *kcb)
+{
+       kcb->prev_kp_core.p = kp_core_running();
+       kcb->prev_kp_core.status = kcb->kp_core_status;
+}
+
+/**
+ * @brief Restores previous kp_core.
+ *
+ * @param kcb Pointer to kp_core_ctlblk which contains previous kp_core.
+ * @return Void.
+ */
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
+{
+       kp_core_running_set(kcb->prev_kp_core.p);
+       kcb->kp_core_status = kcb->prev_kp_core.status;
+}
+
+static int kprobe_handler(struct pt_regs *regs)
+{
+       struct kp_core *p, *cur;
+       struct kp_core_ctlblk *kcb;
+       struct kctx *ctx = current_kctx;
+
+       if (regs->ARM_pc == sched_addr)
+               switch_to_bits_set(ctx, SWITCH_TO_KP);
+
+       kcb = kp_core_ctlblk();
+       cur = kp_core_running();
+
+       rcu_read_lock();
+       p = kp_core_by_addr(regs->ARM_pc);
+       if (p)
+               kp_core_get(p);
+       rcu_read_unlock();
+
+       if (p) {
+               if (cur) {
+                       /* Kprobe is pending, so we're recursing. */
+                       switch (kcb->kp_core_status) {
+                       case KPROBE_HIT_ACTIVE:
+                       case KPROBE_HIT_SSDONE:
+                               /* A pre- or post-handler probe got us here. */
+                               save_previous_kp_core(kcb);
+                               kp_core_running_set(p);
+                               kcb->kp_core_status = KPROBE_REENTER;
+                               prepare_singlestep(p, regs);
+                               restore_previous_kp_core(kcb);
+                               break;
+                       default:
+                               /* impossible cases */
+                               BUG();
+                       }
+               } else {
+                       kp_core_running_set(p);
+                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
+
+                       if (!(regs->ARM_cpsr & PSR_I_BIT))
+                               local_irq_enable();
+
+                       if (!p->handlers.pre(p, regs)) {
+                               kcb->kp_core_status = KPROBE_HIT_SS;
+                               prepare_singlestep(p, regs);
+                               kp_core_running_set(NULL);
+                       }
+               }
+               kp_core_put(p);
+       } else {
+               goto no_kprobe;
+       }
+
+       switch_to_bits_reset(ctx, SWITCH_TO_KP);
+
+       return 0;
+
+no_kprobe:
+       printk(KERN_INFO "no_kprobe: Not one of ours: let kernel handle it %p\n",
+                       (unsigned long *)regs->ARM_pc);
+       return 1;
+}
+
+/**
+ * @brief Trap handler.
+ *
+ * @param regs Pointer to CPU register data.
+ * @param instr Instruction.
+ * @return kprobe_handler result.
+ */
+int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+{
+       int ret;
+
+       if (likely(instr == BREAK_ARM)) {
+               ret = kprobe_handler(regs);
+       } else {
+               struct kp_core *p;
+
+               rcu_read_lock();
+               p = kp_core_by_addr(regs->ARM_pc);
+
+               /* skip false exeption */
+               ret = p && (p->opcode == instr) ? 0 : 1;
+               rcu_read_unlock();
+       }
+
+       return ret;
+}
+
+/**
+ * @brief Probe pre handler.
+ *
+ * @param p Pointer to fired kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return 0.
+ */
+int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       entry_point_t entry = (entry_point_t)jp->entry;
+
+       if (entry) {
+               entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
+                     regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
+       } else {
+               swap_jprobe_return();
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Jprobe return stub.
+ *
+ * @return Void.
+ */
+void swap_jprobe_return(void)
+{
+}
+EXPORT_SYMBOL_GPL(swap_jprobe_return);
+
+/**
+ * @brief Break handler stub.
+ *
+ * @param p Pointer to fired kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return 0.
+ */
+int swap_longjmp_break_handler (struct kprobe *p, struct pt_regs *regs)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_longjmp_break_handler);
+
+#ifdef CONFIG_STRICT_MEMORY_RWX
+#include "memory_rwx.h"
+
+static void write_u32(unsigned long addr, unsigned long val)
+{
+       mem_rwx_write_u32(addr, val);
+}
+#else /* CONFIG_STRICT_MEMORY_RWX */
+static void write_u32(unsigned long addr, unsigned long val)
+{
+       *(long *)addr = val;
+       flush_icache_range(addr, addr + sizeof(long));
+}
+#endif /* CONFIG_STRICT_MEMORY_RWX */
+
+/**
+ * @brief Arms kprobe.
+ *
+ * @param p Pointer to target kprobe.
+ * @return Void.
+ */
+void arch_kp_core_arm(struct kp_core *core)
+{
+       write_u32(core->addr, BREAK_ARM);
+}
+
+/**
+ * @brief Disarms kprobe.
+ *
+ * @param p Pointer to target kprobe.
+ * @return Void.
+ */
+void arch_kp_core_disarm(struct kp_core *core)
+{
+       write_u32(core->addr, core->opcode);
+}
+
+/**
+ * @brief Kretprobe trampoline. Provides jumping to probe handler.
+ *
+ * @return Void.
+ */
+void __naked swap_kretprobe_trampoline(void)
+{
+       __asm__ __volatile__ (
+               "stmdb  sp!, {r0 - r11}\n"
+               "mov    r0, sp\n"               /* struct pt_regs -> r0 */
+               "bl     swap_trampoline_handler\n"
+               "mov    lr, r0\n"
+               "ldmia  sp!, {r0 - r11}\n"
+               "bx     lr\n"
+               : : : "memory");
+}
+
+/**
+ * @brief Prepares kretprobes, saves ret address, makes function return to
+ * trampoline.
+ *
+ * @param ri Pointer to kretprobe_instance.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       unsigned long *ptr_ret_addr;
+
+       /* for __switch_to probe */
+       if ((unsigned long)ri->rp->kp.addr == sched_addr) {
+               struct thread_info *tinfo = (struct thread_info *)regs->ARM_r2;
+
+               ptr_ret_addr = (unsigned long *)&tinfo->cpu_context.pc;
+               ri->sp = NULL;
+               ri->task = tinfo->task;
+               switch_to_bits_set(kctx_by_task(tinfo->task), SWITCH_TO_RP);
+       } else {
+               ptr_ret_addr = (unsigned long *)&regs->ARM_lr;
+               ri->sp = (unsigned long *)regs->ARM_sp;
+       }
+
+       /* Save the return address */
+       ri->ret_addr = (unsigned long *)*ptr_ret_addr;
+
+       /* Replace the return addr with trampoline addr */
+       *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline;
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                                   jumper                                   *
+ ******************************************************************************
+ */
+struct cb_data {
+       unsigned long ret_addr;
+       unsigned long r0;
+
+       jumper_cb_t cb;
+       char data[0];
+};
+
+static unsigned long __used get_r0(struct cb_data *data)
+{
+       return data->r0;
+}
+
+static unsigned long __used jump_handler(struct cb_data *data)
+{
+       unsigned long ret_addr = data->ret_addr;
+
+       /* call callback */
+       data->cb(data->data);
+
+       /* FIXME: potential memory leak, when process kill */
+       kfree(data);
+
+       return ret_addr;
+}
+
+/* FIXME: restore condition flags */
+
+/**
+ * @brief Jumper trampoline.
+ *
+ * @return Void.
+ */
+void jump_trampoline(void);
+__asm(
+       "jump_trampoline:\n"
+
+       "push   {r0 - r12}\n"
+       "mov    r1, r0\n"       /* data --> r1 */
+       "bl     get_r0\n"
+       "str    r0, [sp]\n"     /* restore r0 */
+       "mov    r0, r1\n"       /* data --> r0 */
+       "bl     jump_handler\n"
+       "mov    lr, r0\n"
+       "pop    {r0 - r12}\n"
+       "bx     lr\n"
+);
+
+/**
+ * @brief Get jumper address.
+ *
+ * @return Jumper address.
+ */
+unsigned long get_jump_addr(void)
+{
+       return (unsigned long)&jump_trampoline;
+}
+EXPORT_SYMBOL_GPL(get_jump_addr);
+
+/**
+ * @brief Set jumper probe callback.
+ *
+ * @param ret_addr Jumper probe return address.
+ * @param regs Pointer to CPU registers data.
+ * @param cb Jumper callback of jumper_cb_t type.
+ * @param data Data that should be stored in cb_data.
+ * @param size Size of the data.
+ * @return 0.
+ */
+int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
+               jumper_cb_t cb, void *data, size_t size)
+{
+       struct cb_data *cb_data;
+
+       cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
+       if (cb_data == NULL)
+               return -ENOMEM;
+
+       /* save data */
+       if (size)
+               memcpy(cb_data->data, data, size);
+
+       /* save info for restore */
+       cb_data->ret_addr = ret_addr;
+       cb_data->cb = cb;
+       cb_data->r0 = regs->ARM_r0;
+
+       /* save cb_data to r0 */
+       regs->ARM_r0 = (long)cb_data;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(set_jump_cb);
+
+
+
+
+/**
+ * @brief Registers hook on specified instruction.
+ *
+ * @param hook Pointer to struct undef_hook.
+ * @return Void.
+ */
+void swap_register_undef_hook(struct undef_hook *hook)
+{
+       __swap_register_undef_hook(hook);
+}
+EXPORT_SYMBOL_GPL(swap_register_undef_hook);
+
+/**
+ * @brief Unregisters hook.
+ *
+ * @param hook Pointer to struct undef_hook.
+ * @return Void.
+ */
+void swap_unregister_undef_hook(struct undef_hook *hook)
+{
+       __swap_unregister_undef_hook(hook);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_undef_hook);
+
+/* kernel probes hook */
+static struct undef_hook undef_ho_k = {
+       .instr_mask     = 0,
+       .instr_val      = 0,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = SVC_MODE,
+       .fn             = kprobe_trap_handler
+};
+
+/**
+ * @brief Arch-dependend module deps initialization stub.
+ *
+ * @return 0.
+ */
+int arch_init_module_deps(void)
+{
+       const char *sym;
+#ifdef CONFIG_STRICT_MEMORY_RWX
+       int ret;
+
+       ret = mem_rwx_once();
+       if (ret)
+               return ret;
+#endif /* CONFIG_STRICT_MEMORY_RWX */
+
+       sym = "register_undef_hook";
+       __swap_register_undef_hook = (void *)swap_ksyms(sym);
+       if (__swap_register_undef_hook == NULL)
+               goto not_found;
+
+       sym = "unregister_undef_hook";
+       __swap_unregister_undef_hook = (void *)swap_ksyms(sym);
+       if (__swap_unregister_undef_hook == NULL)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+/**
+ * @brief Initializes kprobes module for ARM arch.
+ *
+ * @return 0 on success, error code on error.
+ */
+int swap_arch_init_kprobes(void)
+{
+       swap_register_undef_hook(&undef_ho_k);
+
+       return 0;
+}
+
+/**
+ * @brief Uninitializes kprobe module.
+ *
+ * @return Void.
+ */
+void swap_arch_exit_kprobes(void)
+{
+       swap_unregister_undef_hook(&undef_ho_k);
+}
+
+
+/* export symbol for probes_arm.h */
+EXPORT_SYMBOL_GPL(noret_arm);
+EXPORT_SYMBOL_GPL(make_trampoline_arm);
+
+#include <arch/arm/probes/tramps_arm.h>
+/* export symbol for tramps_arm.h */
+EXPORT_SYMBOL_GPL(gen_insn_execbuf);
+EXPORT_SYMBOL_GPL(pc_dep_insn_execbuf);
+EXPORT_SYMBOL_GPL(b_r_insn_execbuf);
+EXPORT_SYMBOL_GPL(b_cond_insn_execbuf);
+EXPORT_SYMBOL_GPL(blx_off_insn_execbuf);
diff --git a/modules/kprobe/arch/arm/swap-asm/swap_kprobes.h b/modules/kprobe/arch/arm/swap-asm/swap_kprobes.h
new file mode 100644 (file)
index 0000000..0ef86f2
--- /dev/null
@@ -0,0 +1,284 @@
+/**
+ * @file kprobe/arch/asm-arm/swap_kprobes.h
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
+ *             initial implementation for ARM/MIPS
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com>:
+ *             User-Space Probes initial implementation;
+ *             Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
+ *             redesign module for separating core and arch parts
+ * @author Alexander Shirshikov <a.shirshikov@samsung.com>:
+ *              initial implementation for Thumb
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * ARM arch-dependent kprobes interface declaration.
+ */
+
+
+#ifndef _SWAP_ASM_ARM_KPROBES_H
+#define _SWAP_ASM_ARM_KPROBES_H
+
+#include <linux/sched.h>
+#include <linux/compiler.h>
+#include <arch/arm/probes/probes.h>
+
+typedef unsigned long kprobe_opcode_t;
+
+
+/** Kprobes trampoline length */
+#define KPROBES_TRAMP_LEN              PROBES_TRAMP_LEN
+
+/** User register offset */
+#define UREGS_OFFSET 8
+
+/**
+ * @struct prev_kp_core
+ * @brief Stores previous kp_core.
+ * @var prev_kp_core::p
+ * Pointer to kp_core struct.
+ * @var prev_kp_core::status
+ * Kprobe status.
+ */
+struct prev_kp_core {
+       struct kp_core *p;
+       unsigned long status;
+};
+
+/**
+ * @brief Gets task pc.
+ *
+ * @param p Pointer to task_struct
+ * @return Value in pc.
+ */
+static inline unsigned long arch_get_task_pc(struct task_struct *p)
+{
+       return task_thread_info(p)->cpu_context.pc;
+}
+
+/**
+ * @brief Sets task pc.
+ *
+ * @param p Pointer to task_struct.
+ * @param val Value that should be set.
+ * @return Void.
+ */
+static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
+{
+       task_thread_info(p)->cpu_context.pc = val;
+}
+
+/**
+ * @brief Gets syscall registers.
+ *
+ * @param sp Pointer to stack.
+ * @return Pointer to CPU regs data.
+ */
+static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
+{
+       return (struct pt_regs *)(sp + UREGS_OFFSET);
+}
+
+/**
+ * @brief Gets stack pointer.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @return Stack address.
+ */
+static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
+{
+       return regs->ARM_sp;
+}
+
+/**
+ * @brief Sets stack pointer.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @param sp New stack pointer value.
+ * @return Void
+ */
+static inline void swap_set_stack_ptr(struct pt_regs *regs, unsigned long sp)
+{
+       regs->ARM_sp = sp;
+}
+
+/**
+ * @brief Gets instruction pointer.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @return Pointer to pc.
+ */
+static inline unsigned long swap_get_kpc(struct pt_regs *regs)
+{
+       return regs->ARM_pc | !!thumb_mode(regs);
+}
+
+/**
+ * @brief Sets instruction pointer.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @param val Address that should be stored in pc.
+ * @return Void.
+ */
+static inline void swap_set_kpc(struct pt_regs *regs, unsigned long val)
+{
+       if (val & 1) {
+               regs->ARM_pc = val & ~1;
+               regs->ARM_cpsr |= PSR_T_BIT;
+       } else {
+               regs->ARM_pc = val;
+               regs->ARM_cpsr &= ~PSR_T_BIT;
+       }
+}
+
+/**
+ * @brief Gets specified argument.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @param num Number of the argument.
+ * @return Argument value.
+ */
+static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
+{
+       return regs->uregs[num];
+}
+
+/**
+ * @brief Sets specified argument.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @param num Number of the argument.
+ * @param val New argument value.
+ * @return Void.
+ */
+static inline void swap_set_arg(struct pt_regs *regs, int num,
+                               unsigned long val)
+{
+       regs->uregs[num] = val;
+}
+
+/**
+ * @struct kp_core_ctlblk
+ * @brief Per-cpu kp_core control block.
+ * @var kp_core_ctlblk::kp_core_status
+ * Kprobe status.
+ * @var kp_core_ctlblk::prev_kp_core
+ * Previous kp_core.
+ */
+struct kp_core_ctlblk {
+       unsigned long kp_core_status;
+       struct prev_kp_core prev_kp_core;
+};
+
+/**
+ * @struct swap_arch_specific_insn
+ * @brief Architecture specific copy of original instruction.
+ * @var swap_arch_specific_insn::insn
+ * Copy of the original instruction.
+ */
+struct swap_arch_specific_insn {
+       kprobe_opcode_t *insn;
+};
+
+typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
+                                         unsigned long, unsigned long,
+                                         unsigned long, unsigned long);
+
+struct undef_hook;
+
+void swap_register_undef_hook(struct undef_hook *hook);
+void swap_unregister_undef_hook(struct undef_hook *hook);
+
+int arch_init_module_deps(void);
+
+struct slot_manager;
+struct kretprobe;
+struct kretprobe_instance;
+struct kp_core;
+struct kprobe;
+
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
+void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                struct pt_regs *regs);
+
+void arch_kp_core_arm(struct kp_core *p);
+void arch_kp_core_disarm(struct kp_core *p);
+
+int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
+int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs);
+
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
+
+void __naked swap_kretprobe_trampoline(void);
+
+/**
+ * @brief Gets arguments of kernel functions.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @param n Number of the argument.
+ * @return Argument value.
+ */
+static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
+{
+       switch (n) {
+       case 0:
+               return regs->ARM_r0;
+       case 1:
+               return regs->ARM_r1;
+       case 2:
+               return regs->ARM_r2;
+       case 3:
+               return regs->ARM_r3;
+       }
+
+       return *((unsigned long *)regs->ARM_sp + n - 4);
+}
+
+/**
+ * @brief swap_get_karg wrapper.
+ *
+ * @param regs Pointer to CPU registers data.
+ * @param n Number of the argument.
+ * @return Argument value.
+ */
+static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
+{
+       return swap_get_karg(regs, n);
+}
+
+/* jumper */
+typedef unsigned long (*jumper_cb_t)(void *);
+
+unsigned long get_jump_addr(void);
+int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
+               jumper_cb_t cb, void *data, size_t size);
+
+int swap_arch_init_kprobes(void);
+void swap_arch_exit_kprobes(void);
+
+/* void gen_insn_execbuf (void); */
+/* void pc_dep_insn_execbuf (void); */
+/* void gen_insn_execbuf_holder (void); */
+/* void pc_dep_insn_execbuf_holder (void); */
+
+#endif /* _SWAP_ASM_ARM_KPROBES_H */
diff --git a/modules/kprobe/arch/arm/swap-asm/swap_probes.h b/modules/kprobe/arch/arm/swap-asm/swap_probes.h
new file mode 100644 (file)
index 0000000..3cbd18a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_ARM_PROBES_H
+#define _SWAP_ASM_ARM_PROBES_H
+
+
+#define BREAK_ARM                      0xffffdeff
+#define BREAK_THUMB                    (BREAK_ARM & 0xffff)
+#define RET_BREAK_ARM                  BREAK_ARM
+#define RET_BREAK_THUMB                        BREAK_THUMB
+
+#define PROBES_TRAMP_LEN               (9 * 4)
+#define PROBES_TRAMP_INSN_IDX          2
+#define PROBES_TRAMP_RET_BREAK_IDX     5
+
+
+#endif /* _SWAP_ASM_ARM_PROBES_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/condn-helpers.c b/modules/kprobe/arch/arm64/swap-asm/condn-helpers.c
new file mode 100644 (file)
index 0000000..708fb7f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/condn-helpers.c
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * Copied from: arch/arm/kernel/kprobes-common.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Description:
+ *
+ *  AArch64 and AArch32 shares same conditional(CNZV) flags encoding.
+ *  This file implements conditional check helpers compatible with
+ *  both AArch64 and AArch32 modes. Uprobes on v8 can handle both 32-bit
+ *  & 64-bit user-space instructions, so we abstract the common functions
+ *  in this file. While AArch64 and AArch32 specific instruction handling
+ *  are implemented in separate files, this file contains common bits.
+ */
+
+
+#include <linux/module.h>
+#include "condn-helpers.h"
+
+
+static unsigned long __check_eq(unsigned long pstate)
+{
+       return pstate & PSR_Z_BIT;
+}
+
+static unsigned long __check_ne(unsigned long pstate)
+{
+       return (~pstate) & PSR_Z_BIT;
+}
+
+static unsigned long __check_cs(unsigned long pstate)
+{
+       return pstate & PSR_C_BIT;
+}
+
+static unsigned long __check_cc(unsigned long pstate)
+{
+       return (~pstate) & PSR_C_BIT;
+}
+
+static unsigned long __check_mi(unsigned long pstate)
+{
+       return pstate & PSR_N_BIT;
+}
+
+static unsigned long __check_pl(unsigned long pstate)
+{
+       return (~pstate) & PSR_N_BIT;
+}
+
+static unsigned long __check_vs(unsigned long pstate)
+{
+       return pstate & PSR_V_BIT;
+}
+
+static unsigned long __check_vc(unsigned long pstate)
+{
+       return (~pstate) & PSR_V_BIT;
+}
+
+static unsigned long __check_hi(unsigned long pstate)
+{
+       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return pstate & PSR_C_BIT;
+}
+
+static unsigned long __check_ls(unsigned long pstate)
+{
+       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (~pstate) & PSR_C_BIT;
+}
+
+static unsigned long __check_ge(unsigned long pstate)
+{
+       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
+       return (~pstate) & PSR_N_BIT;
+}
+
+static unsigned long __check_lt(unsigned long pstate)
+{
+       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
+       return pstate & PSR_N_BIT;
+}
+
+static unsigned long __check_gt(unsigned long pstate)
+{
+       /*PSR_N_BIT ^= PSR_V_BIT */
+       unsigned long temp = pstate ^ (pstate << 3);
+
+       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
+       return (~temp) & PSR_N_BIT;
+}
+
+static unsigned long __check_le(unsigned long pstate)
+{
+       /*PSR_N_BIT ^= PSR_V_BIT */
+       unsigned long temp = pstate ^ (pstate << 3);
+
+       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
+       return temp & PSR_N_BIT;
+}
+
+static unsigned long __check_al(unsigned long pstate)
+{
+       return true;
+}
+
+probes_pstate_check_t * const probe_condition_checks[16] = {
+       &__check_eq, &__check_ne, &__check_cs, &__check_cc,
+       &__check_mi, &__check_pl, &__check_vs, &__check_vc,
+       &__check_hi, &__check_ls, &__check_ge, &__check_lt,
+       &__check_gt, &__check_le, &__check_al, &__check_al
+};
+EXPORT_SYMBOL_GPL(probe_condition_checks);
diff --git a/modules/kprobe/arch/arm64/swap-asm/condn-helpers.h b/modules/kprobe/arch/arm64/swap-asm/condn-helpers.h
new file mode 100644 (file)
index 0000000..088974d
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _ASM_CONDN_HELPER_H
+#define _ASM_CONDN_HELPER_H
+
+/*
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+typedef unsigned long (probes_pstate_check_t)(unsigned long);
+
+
+extern probes_pstate_check_t * const probe_condition_checks[16];
+
+
+#endif /* _ASM_CONDN_HELPER_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/dbg_interface.c b/modules/kprobe/arch/arm64/swap-asm/dbg_interface.c
new file mode 100644 (file)
index 0000000..56543b7
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/kconfig.h>
+
+#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
+# error "Kernel is immutable"
+#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
+
+
+#include <linux/module.h>
+#include <linux/rwlock.h>
+#include <asm/debug-monitors.h>
+#include <ksyms/ksyms.h>
+#include "dbg_interface.h"
+
+
+
+
+/* ============================================================================
+ * =                               BRK IMPLEMENT                              =
+ * ============================================================================
+ */
+static LIST_HEAD(brk_list);
+static DEFINE_RWLOCK(brk_list_lock);
+
+void dbg_brk_hook_reg(struct brk_hook *hook)
+{
+       write_lock(&brk_list_lock);
+       list_add(&hook->list, &brk_list);
+       write_unlock(&brk_list_lock);
+}
+EXPORT_SYMBOL_GPL(dbg_brk_hook_reg);
+
+void dbg_brk_hook_unreg(struct brk_hook *hook)
+{
+       write_lock(&brk_list_lock);
+       list_del(&hook->list);
+       write_unlock(&brk_list_lock);
+}
+EXPORT_SYMBOL_GPL(dbg_brk_hook_unreg);
+
+static enum dbg_code call_brk_hook(struct pt_regs *regs, unsigned int esr)
+{
+       struct brk_hook *hook;
+       enum dbg_code (*fn)(struct pt_regs *regs, unsigned int esr) = NULL;
+
+       read_lock(&brk_list_lock);
+       list_for_each_entry(hook, &brk_list, list)
+               if (((esr & hook->esr_mask) == hook->esr_val) &&
+                   ((regs->pstate & hook->spsr_mask) == hook->spsr_val))
+                       fn = hook->fn;
+       read_unlock(&brk_list_lock);
+
+       return fn ? fn(regs, esr) : DBG_ERROR;
+}
+
+
+typedef int (*dbg_fn_t)(unsigned long addr, unsigned int esr,
+                       struct pt_regs *regs);
+
+static dbg_fn_t *brk_handler_ptr;
+static dbg_fn_t orig_brk_handler;
+
+static int brk_handler(unsigned long addr, unsigned int esr,
+                      struct pt_regs *regs)
+{
+       /* call the registered breakpoint handler */
+       if (call_brk_hook(regs, esr) == DBG_HANDLED)
+               return 0;
+
+       return orig_brk_handler(addr, esr, regs);
+}
+
+static void init_brk(dbg_fn_t *fn)
+{
+       brk_handler_ptr = fn;
+       orig_brk_handler = *brk_handler_ptr;
+       *brk_handler_ptr = brk_handler;
+}
+
+static void uninit_brk(void)
+{
+       *brk_handler_ptr = orig_brk_handler;
+}
+
+
+
+
+
+
+/* ============================================================================
+ * =                                INIT / EXIT                               =
+ * ============================================================================
+ */
+int dbg_iface_init(void)
+{
+       struct fault_info {
+               int (*fn)(unsigned long addr, unsigned int esr,
+                         struct pt_regs *regs);
+               int sig;
+               int code;
+               const char *name;
+       };
+
+       struct fault_info *debug_finfo;
+       struct fault_info *finfo_brk;
+
+       debug_finfo = (struct fault_info *)swap_ksyms("debug_fault_info");
+       if (debug_finfo == NULL) {
+               pr_err("cannot found 'debug_fault_info'\n");
+               return -EINVAL;
+       }
+
+       finfo_brk = &debug_finfo[DBG_ESR_EVT_BRK];
+
+       init_brk(&finfo_brk->fn);
+
+       return 0;
+}
+
+void dbg_iface_uninit(void)
+{
+       uninit_brk();
+}
diff --git a/modules/kprobe/arch/arm64/swap-asm/dbg_interface.h b/modules/kprobe/arch/arm64/swap-asm/dbg_interface.h
new file mode 100644 (file)
index 0000000..3a65f69
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _ASM_DBG_INTERFACE_H
+#define _ASM_DBG_INTERFACE_H
+
+/*
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/list.h>
+#include <linux/types.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+# include <asm/esr.h>
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
+# define ESR_ELx_IL       (1 << 25)
+# define ESR_ELx_EC_MASK  0xfc000000
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
+
+#define ESR_ELx_EC_BRK   0xf0000000
+#define BRK_COMM_MASK    0x0000ffff
+
+#define DBG_BRK_ESR_MASK (ESR_ELx_EC_MASK | ESR_ELx_IL | BRK_COMM_MASK)
+#define DBG_BRK_ESR(x)   (ESR_ELx_EC_BRK | ESR_ELx_IL | (BRK_COMM_MASK & (x)))
+
+#define MAKE_BRK(v)      ((((v) & 0xffff) << 5) | 0xd4200000)
+
+
+enum dbg_code {
+       DBG_HANDLED,
+       DBG_ERROR,
+};
+
+
+struct brk_hook {
+       struct list_head list;
+       u32 spsr_mask;
+       u32 spsr_val;
+       u32 esr_mask;
+       u32 esr_val;
+       enum dbg_code (*fn)(struct pt_regs *regs, unsigned int esr);
+};
+
+
+void dbg_brk_hook_reg(struct brk_hook *hook);
+void dbg_brk_hook_unreg(struct brk_hook *hook);
+
+int dbg_iface_init(void);
+void dbg_iface_uninit(void);
+
+
+#endif /* _ASM_DBG_INTERFACE_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/kprobes-arm64.c b/modules/kprobe/arch/arm64/swap-asm/kprobes-arm64.c
new file mode 100644 (file)
index 0000000..14aff81
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/kprobes-arm64.c
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <kprobe/swap_kprobes.h>
+
+#include "probes-decode.h"
+#include "kprobes-arm64.h"
+#include "simulate-insn.h"
+#include "condn-helpers.h"
+
+
+/*
+ * condition check functions for kp_cores simulation
+ */
+static unsigned long __check_pstate(struct kp_core *p, struct pt_regs *regs)
+{
+       struct swap_arch_specific_insn *asi = &p->ainsn;
+       unsigned long pstate = regs->pstate & 0xffffffff;
+
+       return asi->pstate_cc(pstate);
+}
+
+static unsigned long __check_cbz(struct kp_core *p, struct pt_regs *regs)
+{
+       return check_cbz((u32)p->opcode, regs);
+}
+
+static unsigned long __check_cbnz(struct kp_core *p, struct pt_regs *regs)
+{
+       return check_cbnz((u32)p->opcode, regs);
+}
+
+static unsigned long __check_tbz(struct kp_core *p, struct pt_regs *regs)
+{
+       return check_tbz((u32)p->opcode, regs);
+}
+
+static unsigned long __check_tbnz(struct kp_core *p, struct pt_regs *regs)
+{
+       return check_tbnz((u32)p->opcode, regs);
+}
+
+/*
+ * prepare functions for instruction simulation
+ */
+static void prepare_none(struct kp_core *p, struct swap_arch_specific_insn *asi)
+{
+}
+
+static void prepare_bcond(struct kp_core *p,
+                         struct swap_arch_specific_insn *asi)
+{
+       kprobe_opcode_t insn = p->opcode;
+
+       asi->check_condn = __check_pstate;
+       asi->pstate_cc = probe_condition_checks[insn & 0xf];
+}
+
+static void prepare_cbz_cbnz(struct kp_core *p,
+                            struct swap_arch_specific_insn *asi)
+{
+       kprobe_opcode_t insn = p->opcode;
+
+       asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz;
+}
+
+static void prepare_tbz_tbnz(struct kp_core *p,
+                            struct swap_arch_specific_insn *asi)
+{
+       kprobe_opcode_t insn = p->opcode;
+
+       asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz;
+}
+
+
+/* Load literal (PC-relative) instructions
+ * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
+ *
+ * opcode[26]: V=0, Load GP registers, simulate them.
+ * Encoding: xx01 1000 xxxx xxxx xxxx xxxx xxxx xxxx
+ *     opcode[31:30]: op = 00, 01 - LDR literal
+ *     opcode[31:30]: op = 10,    - LDRSW literal
+ *
+ * 1.   V=1 -Load FP/AdvSIMD registers
+ *     Encoding: xx01 1100 xxxx xxxx xxxx xxxx xxxx xxxx
+ * 2.   V=0,opc=11 -PRFM(Prefetch literal)
+ *     Encoding: 1101 1000 xxxx xxxx xxxx xxxx xxxx xxxx
+ *     Reject FP/AdvSIMD literal load & PRFM literal.
+ */
+static const struct aarch64_decode_item load_literal_subtable[] = {
+       DECODE_REJECT(0x1C000000, 0x3F000000),
+       DECODE_REJECT(0xD8000000, 0xFF000000),
+       DECODE_LITERAL(0x18000000, 0xBF000000, prepare_none,
+                      simulate_ldr_literal),
+       DECODE_LITERAL(0x98000000, 0xFF000000, prepare_none,
+                      simulate_ldrsw_literal),
+       DECODE_END,
+};
+
+/* AArch64 instruction decode table for kp_cores:
+ * The instruction will fall into one of the 3 groups:
+ *  1. Single stepped out-of-the-line slot.
+ *     -Most instructions fall in this group, those does not
+ *      depend on PC address.
+ *
+ *  2. Should be simulated because of PC-relative/literal access.
+ *     -All branching and PC-relative insrtcutions are simulated
+ *      in C code, making use of saved pt_regs
+ *      Catch: SIMD/NEON register context are not saved while
+ *      entering debug exception, so are rejected for now.
+ *
+ *  3. Cannot be probed(not safe) so are rejected.
+ *     - Exception generation and exception return instructions
+ *     - Exclusive monitor(LDREX/STREX family)
+ *
+ */
+static const struct aarch64_decode_item aarch64_decode_table[] = {
+       /*
+        * Data processing - PC relative(literal) addressing:
+        * Encoding: xxx1 0000 xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_LITERAL(0x10000000, 0x1F000000, prepare_none,
+                       simulate_adr_adrp),
+
+       /*
+        * Data processing - Add/Substract Immediate:
+        * Encoding: xxx1 0001 xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x11000000, 0x1F000000),
+
+       /*
+        * Data processing
+        * Encoding:
+        *      xxx1 0010 0xxx xxxx xxxx xxxx xxxx xxxx (Logical)
+        *      xxx1 0010 1xxx xxxx xxxx xxxx xxxx xxxx (Move wide)
+        *      xxx1 0011 0xxx xxxx xxxx xxxx xxxx xxxx (Bitfield)
+        *      xxx1 0011 1xxx xxxx xxxx xxxx xxxx xxxx (Extract)
+        */
+       DECODE_SINGLESTEP(0x12000000, 0x1E000000),
+
+       /*
+        * Data processing - SIMD/FP/AdvSIMD/Crypto-AES/SHA
+        * Encoding: xxx0 111x xxxx xxxx xxxx xxxx xxxx xxxx
+        * Encoding: xxx1 111x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x0E000000, 0x0E000000),
+
+       /*
+        * Data processing - Register
+        * Encoding: xxxx 101x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x0A000000, 0x0E000000),
+
+       /* Branching Instructions
+        *
+        * Encoding:
+        *  x001 01xx xxxx xxxx xxxx xxxx xxxx xxxx (uncondtional Branch)
+        *  x011 010x xxxx xxxx xxxx xxxx xxxx xxxx (compare & branch)
+        *  x011 011x xxxx xxxx xxxx xxxx xxxx xxxx (Test & Branch)
+        *  0101 010x xxxx xxxx xxxx xxxx xxxx xxxx (Conditional, immediate)
+        *  1101 011x xxxx xxxx xxxx xxxx xxxx xxxx (Unconditional,register)
+        */
+       DECODE_BRANCH(0x14000000, 0x7C000000, prepare_none,
+                       simulate_b_bl),
+       DECODE_BRANCH(0x34000000, 0x7E000000, prepare_cbz_cbnz,
+                     simulate_cbz_cbnz),
+       DECODE_BRANCH(0x36000000, 0x7E000000, prepare_tbz_tbnz,
+                     simulate_tbz_tbnz),
+       DECODE_BRANCH(0x54000000, 0xFE000000, prepare_bcond,
+                       simulate_b_cond),
+       DECODE_BRANCH(0xD6000000, 0xFE000000, prepare_none,
+                     simulate_br_blr_ret),
+
+       /* System insn:
+        * Encoding: 1101 0101 00xx xxxx xxxx xxxx xxxx xxxx
+        *
+        * Note: MSR immediate (update PSTATE daif) is not safe handling
+        * within kp_cores, rejected.
+        *
+        * Don't re-arrange these decode table entries.
+        */
+       DECODE_REJECT(0xD500401F, 0xFFF8F01F),
+       DECODE_SINGLESTEP(0xD5000000, 0xFFC00000),
+
+       /* Exception Generation:
+        * Encoding:  1101 0100 xxxx xxxx xxxx xxxx xxxx xxxx
+        * Instructions: SVC, HVC, SMC, BRK, HLT, DCPS1, DCPS2, DCPS3
+        */
+       DECODE_REJECT(0xD4000000, 0xFF000000),
+
+       /*
+        * Load/Store - Exclusive monitor
+        * Encoding: xx00 1000 xxxx xxxx xxxx xxxx xxxx xxxx
+        *
+        * Reject exlusive monitor'ed instructions
+        */
+       DECODE_REJECT(0x08000000, 0x3F000000),
+
+       /*
+        * Load/Store - PC relative(literal):
+        * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE(0x18000000, 0x3B000000, load_literal_subtable),
+
+       /*
+        * Load/Store - Register Pair
+        * Encoding:
+        *      xx10 1x00 0xxx xxxx xxxx xxxx xxxx xxxx
+        *      xx10 1x00 1xxx xxxx xxxx xxxx xxxx xxxx
+        *      xx10 1x01 0xxx xxxx xxxx xxxx xxxx xxxx
+        *      xx10 1x01 1xxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x28000000, 0x3A000000),
+
+       /*
+        * Load/Store - Register
+        * Encoding:
+        *      xx11 1x00 xx0x xxxx xxxx 00xx xxxx xxxx (unscaled imm)
+        *      xx11 1x00 xx0x xxxx xxxx 01xx xxxx xxxx (imm post-indexed)
+        *      xx11 1x00 xx0x xxxx xxxx 10xx xxxx xxxx (unpriviledged)
+        *      xx11 1x00 xx0x xxxx xxxx 11xx xxxx xxxx (imm pre-indexed)
+        *
+        *      xx11 1x00 xx10 xxxx xxxx xx10 xxxx xxxx (register offset)
+        *
+        *      xx11 1x01 xxxx xxxx xxxx xxxx xxxx xxxx (unsigned imm)
+        */
+       DECODE_SINGLESTEP(0x38000000, 0x3B200000),
+       DECODE_SINGLESTEP(0x38200200, 0x38300300),
+       DECODE_SINGLESTEP(0x39000000, 0x3B000000),
+
+       /*
+        * Load/Store - AdvSIMD
+        * Encoding:
+        *  0x00 1100 0x00 0000 xxxx xxxx xxxx xxxx (Multiple-structure)
+        *  0x00 1100 1x0x xxxx xxxx xxxx xxxx xxxx (Multi-struct post-indexed)
+        *  0x00 1101 0xx0 0000 xxxx xxxx xxxx xxxx (Single-structure))
+        *  0x00 1101 1xxx xxxx xxxx xxxx xxxx xxxx (Single-struct post-index)
+        */
+       DECODE_SINGLESTEP(0x0C000000, 0xBFBF0000),
+       DECODE_SINGLESTEP(0x0C800000, 0xBFA00000),
+       DECODE_SINGLESTEP(0x0D000000, 0xBF9F0000),
+       DECODE_SINGLESTEP(0x0D800000, 0xBF800000),
+
+       /* Unallocated:         xxx0 0xxx xxxx xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT(0x00000000, 0x18000000),
+       DECODE_END,
+};
+
+static int kp_core_decode_insn(kprobe_opcode_t insn,
+                              struct swap_arch_specific_insn *asi,
+                              const struct aarch64_decode_item *tbl)
+{
+       unsigned int entry, ret = INSN_REJECTED;
+
+       for (entry = 0; !decode_table_end(tbl[entry]); entry++) {
+               if (decode_table_hit(tbl[entry], insn))
+                       break;
+       }
+
+       switch (decode_get_type(tbl[entry])) {
+       case DECODE_TYPE_END:
+       case DECODE_TYPE_REJECT:
+       default:
+               ret = INSN_REJECTED;
+               break;
+
+       case DECODE_TYPE_SINGLESTEP:
+               ret = INSN_GOOD;
+               break;
+
+       case DECODE_TYPE_SIMULATE:
+               asi->prepare = decode_prepare_fn(tbl[entry]);
+               asi->handler = decode_handler_fn(tbl[entry]);
+               ret = INSN_GOOD_NO_SLOT;
+               break;
+
+       case DECODE_TYPE_TABLE:
+               /* recurse with next level decode table */
+               ret = kp_core_decode_insn(insn, asi,
+                                         decode_sub_table(tbl[entry]));
+       };
+
+       return ret;
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ */
+enum kp_core_insn arm_kp_core_decode_insn(kprobe_opcode_t insn,
+                                         struct swap_arch_specific_insn *asi)
+{
+       return kp_core_decode_insn(insn, asi, aarch64_decode_table);
+}
diff --git a/modules/kprobe/arch/arm64/swap-asm/kprobes-arm64.h b/modules/kprobe/arch/arm64/swap-asm/kprobes-arm64.h
new file mode 100644 (file)
index 0000000..db7480a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/kprobes-arm64.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_KERNEL_KPROBES_ARM64_H
+#define _ARM_KERNEL_KPROBES_ARM64_H
+
+enum kp_core_insn {
+       INSN_REJECTED,
+       INSN_GOOD_NO_SLOT,
+       INSN_GOOD,
+};
+
+extern kp_core_pstate_check_t * const kp_core_condition_checks[16];
+
+enum kp_core_insn arm_kp_core_decode_insn(kprobe_opcode_t insn,
+                                         struct swap_arch_specific_insn *asi);
+
+#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/probes-decode.h b/modules/kprobe/arch/arm64/swap-asm/probes-decode.h
new file mode 100644 (file)
index 0000000..0a210ef
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/probes-decode.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_KERNEL_PROBES_DECODE_H
+#define _ARM_KERNEL_PROBES_DECODE_H
+
+/*
+ * The following definitions and macros are used to build instruction
+ * decoding tables.
+ */
+enum decode_type {
+       DECODE_TYPE_END,
+       DECODE_TYPE_SINGLESTEP,
+       DECODE_TYPE_SIMULATE,
+       DECODE_TYPE_TABLE,
+       DECODE_TYPE_REJECT,
+};
+
+struct aarch64_decode_item;
+
+struct aarch64_decode_header {
+       enum decode_type type;
+       u32 mask;
+       u32 val;
+};
+
+struct aarch64_decode_actions {
+       kp_core_prepare_t *prepare;
+       kp_core_handler_t *handler;
+};
+
+struct aarch64_decode_table {
+       const struct aarch64_decode_item *tbl;
+};
+
+union aarch64_decode_handler {
+       struct aarch64_decode_actions actions;
+       struct aarch64_decode_table table;
+};
+
+struct aarch64_decode_item {
+       struct aarch64_decode_header header;
+       union aarch64_decode_handler decode;
+};
+
+#define decode_get_type(_entry)         ((_entry).header.type)
+
+#define decode_table_end(_entry)               \
+       ((_entry).header.type == DECODE_TYPE_END)
+
+#define decode_table_hit(_entry, insn)         \
+       ((insn & (_entry).header.mask) == (_entry).header.val)
+
+#define decode_prepare_fn(_entry)      ((_entry).decode.actions.prepare)
+#define decode_handler_fn(_entry)      ((_entry).decode.actions.handler)
+#define decode_sub_table(_entry)       ((_entry).decode.table.tbl)
+
+#define DECODE_ADD_HEADER(_type, _val, _mask)  \
+       .header = {                             \
+               .type = _type,                  \
+               .mask = _mask,                  \
+               .val = _val,                    \
+       }
+
+#define DECODE_ADD_ACTION(_prepare, _handler)  \
+       .decode = {                             \
+               .actions = {                    \
+                       .prepare = _prepare,    \
+                       .handler = _handler,    \
+               }                               \
+       }
+
+#define DECODE_ADD_TABLE(_table)               \
+       .decode = {                             \
+               .table = {.tbl = _table}        \
+       }
+
+#define DECODE_REJECT(_v, _m)                                  \
+       { DECODE_ADD_HEADER(DECODE_TYPE_REJECT, _v, _m) }
+
+#define DECODE_SINGLESTEP(_v, _m)                              \
+       { DECODE_ADD_HEADER(DECODE_TYPE_SINGLESTEP, _v, _m) }
+
+#define DECODE_SIMULATE(_v, _m, _p, _h)                                \
+       { DECODE_ADD_HEADER(DECODE_TYPE_SIMULATE, _v, _m),      \
+         DECODE_ADD_ACTION(_p, _h) }
+
+#define DECODE_TABLE(_v, _m, _table)                           \
+       { DECODE_ADD_HEADER(DECODE_TYPE_TABLE, _v, _m),         \
+         DECODE_ADD_TABLE(_table) }
+
+#define DECODE_LITERAL(_v, _m, _p, _h) DECODE_SIMULATE(_v, _m, _p, _h)
+#define DECODE_BRANCH(_v, _m, _p, _h)  DECODE_SIMULATE(_v, _m, _p, _h)
+
+/* should be the last element in decode structure */
+#define DECODE_END     { .header = {.type = DECODE_TYPE_END, } }
+
+#endif /* _ARM_KERNEL_PROBES_DECODE_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/simulate-insn.c b/modules/kprobe/arch/arm64/swap-asm/simulate-insn.c
new file mode 100644 (file)
index 0000000..c959a1d
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/simulate-insn.c
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/ptrace.h>
+
+#include "simulate-insn.h"
+
+#define sign_extend(x, signbit)                \
+       ((x) | (0 - ((x) & ((long)1 << (signbit)))))
+
+#define bbl_displacement(insn)         \
+       sign_extend(((insn) & 0x3ffffff) << 2, 27)
+
+#define bcond_displacement(insn)       \
+       sign_extend(((insn >> 5) & 0xfffff) << 2, 21)
+
+#define cbz_displacement(insn) \
+       sign_extend(((insn >> 5) & 0xfffff) << 2, 21)
+
+#define tbz_displacement(insn) \
+       sign_extend(((insn >> 5) & 0x3fff) << 2, 15)
+
+#define ldr_displacement(insn) \
+       sign_extend(((insn >> 5) & 0xfffff) << 2, 21)
+
+
+unsigned long check_cbz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+
+       return (opcode & (1 << 31)) ?
+           !(regs->regs[xn]) : !(regs->regs[xn] & 0xffffffff);
+}
+EXPORT_SYMBOL_GPL(check_cbz);
+
+unsigned long check_cbnz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+
+       return (opcode & (1 << 31)) ?
+           (regs->regs[xn]) : (regs->regs[xn] & 0xffffffff);
+}
+EXPORT_SYMBOL_GPL(check_cbnz);
+
+unsigned long check_tbz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+       int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+       return ~((regs->regs[xn] >> bit_pos) & 0x1);
+}
+EXPORT_SYMBOL_GPL(check_tbz);
+
+unsigned long check_tbnz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+       int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+       return (regs->regs[xn] >> bit_pos) & 0x1;
+}
+EXPORT_SYMBOL_GPL(check_tbnz);
+
+/*
+ * instruction simulate functions
+ */
+void simulate_none(u32 opcode, long addr, struct pt_regs *regs)
+{
+}
+
+void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs)
+{
+       long res, imm, xn, shift;
+
+       xn = opcode & 0x1f;
+       shift = (opcode >> 31) ? 12 : 0;        /* check insn ADRP/ADR */
+       imm = ((opcode >> 3) & 0xffffc) | ((opcode >> 29) & 0x3);
+       res = addr + 8 + (sign_extend(imm, 20) << shift);
+
+       regs->regs[xn] = opcode & 0x80000000 ? res & 0xfffffffffffff000 : res;
+       regs->pc += 4;
+}
+EXPORT_SYMBOL_GPL(simulate_adr_adrp);
+
+void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = bbl_displacement(opcode);
+
+       /* Link register is x30 */
+       if (opcode & (1 << 31))
+               regs->regs[30] = addr + 4;
+
+       regs->pc = addr + disp;
+}
+EXPORT_SYMBOL_GPL(simulate_b_bl);
+
+void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = bcond_displacement(opcode);
+
+       regs->pc = addr + disp;
+}
+EXPORT_SYMBOL_GPL(simulate_b_cond);
+
+void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int xn = (opcode >> 5) & 0x1f;
+
+       /* Link register is x30 */
+       if (((opcode >> 21) & 0x3) == 1)
+               regs->regs[30] = addr + 4;
+
+       regs->pc = regs->regs[xn];
+}
+EXPORT_SYMBOL_GPL(simulate_br_blr_ret);
+
+void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = cbz_displacement(opcode);
+
+       regs->pc = addr + disp;
+}
+EXPORT_SYMBOL_GPL(simulate_cbz_cbnz);
+
+void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = tbz_displacement(opcode);
+
+       regs->pc = addr + disp;
+}
+EXPORT_SYMBOL_GPL(simulate_tbz_tbnz);
+
+void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs)
+{
+       u64 *load_addr;
+       int xn = opcode & 0x1f;
+       int disp = ldr_displacement(opcode);
+
+       load_addr = (u64 *) (addr + disp);
+
+       if (opcode & (1 << 30)) /* x0-x31 */
+               regs->regs[xn] = *load_addr;
+       else                    /* w0-w31 */
+               *(u32 *) (&regs->regs[xn]) = (*(u32 *) (load_addr));
+}
+EXPORT_SYMBOL_GPL(simulate_ldr_literal);
+
+void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs)
+{
+       u64 *load_addr;
+       long data;
+       int xn = opcode & 0x1f;
+       int disp = ldr_displacement(opcode);
+
+       load_addr = (u64 *) (addr + disp);
+       data = *load_addr;
+
+       regs->regs[xn] = sign_extend(data, 63);
+}
+EXPORT_SYMBOL_GPL(simulate_ldrsw_literal);
diff --git a/modules/kprobe/arch/arm64/swap-asm/simulate-insn.h b/modules/kprobe/arch/arm64/swap-asm/simulate-insn.h
new file mode 100644 (file)
index 0000000..07a4939
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/simulate-insn.h
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_KERNEL_SIMULATE_INSN_H
+#define _ARM_KERNEL_SIMULATE_INSN_H
+
+unsigned long check_cbz(u32 opcode, struct pt_regs *regs);
+unsigned long check_cbnz(u32 opcode, struct pt_regs *regs);
+unsigned long check_tbz(u32 opcode, struct pt_regs *regs);
+unsigned long check_tbnz(u32 opcode, struct pt_regs *regs);
+void simulate_none(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs);
+
+#endif /* _ARM_KERNEL_SIMULATE_INSN_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/swap_kprobes.c b/modules/kprobe/arch/arm64/swap-asm/swap_kprobes.c
new file mode 100644 (file)
index 0000000..77970ef
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * Copied from: arch/arm64/kernel/kprobes.c
+ *
+ * Kprobes support for ARM64
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ * Author: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
+ *
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/kconfig.h>
+
+#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
+# error "Kernel is immutable"
+#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
+
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/cacheflush.h>
+#include <asm/debug-monitors.h>
+#include <ksyms/ksyms.h>
+#include <kprobe/swap_ktd.h>
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include "swap_kprobes.h"
+#include "kprobes-arm64.h"
+#include "dbg_interface.h"
+
+
+#define BRK_BP                 0x63
+#define BRK_PSEUDO_SS          0x64
+#define BRK64_OPCODE_BP                MAKE_BRK(BRK_BP)
+#define BRK64_OPCODE_PSEUDO_SS MAKE_BRK(BRK_PSEUDO_SS)
+
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+static u32 conv_inst(u32 inst)
+{
+       return swab32(inst);
+}
+#else /* CONFIG_CPU_BIG_ENDIAN */
+static u32 conv_inst(u32 inst)
+{
+       return inst;
+}
+#endif /* CONFIG_CPU_BIG_ENDIAN */
+
+
+static void flush_icache(unsigned long addr, size_t size)
+{
+       flush_icache_range(addr, addr + size);
+}
+
+static void write_u32(u32 *addr, u32 val)
+{
+       *addr = val;
+       flush_icache((unsigned long)addr, sizeof(val));
+}
+
+void arch_kp_core_arm(struct kp_core *p)
+{
+       write_u32((u32 *)p->addr, conv_inst(BRK64_OPCODE_BP));
+}
+
+void arch_kp_core_disarm(struct kp_core *p)
+{
+       write_u32((u32 *)p->addr, p->opcode);
+}
+
+
+struct restore_data {
+       unsigned long restore_addr;
+};
+
+static void ktd_restore_init(struct task_struct *task, void *data)
+{
+       struct restore_data *rdata = (struct restore_data *)data;
+
+       rdata->restore_addr = 0;
+}
+
+static void ktd_restore_exit(struct task_struct *task, void *data)
+{
+       struct restore_data *rdata = (struct restore_data *)data;
+
+       WARN(rdata->restore_addr, "restore_addr=%lx", rdata->restore_addr);
+}
+
+struct ktask_data ktd_restore = {
+       .init = ktd_restore_init,
+       .exit = ktd_restore_exit,
+       .size = sizeof(struct restore_data),
+};
+
+static DEFINE_PER_CPU(struct restore_data, per_cpu_restore_i);
+static DEFINE_PER_CPU(struct restore_data, per_cpu_restore_st);
+
+static struct restore_data *current_restore_td(void)
+{
+       if (swap_in_interrupt())
+               return &__get_cpu_var(per_cpu_restore_i);
+       else if (switch_to_bits_get(current_kctx, SWITCH_TO_ALL))
+               return &__get_cpu_var(per_cpu_restore_st);
+
+       return (struct restore_data *)swap_ktd(&ktd_restore, current);
+}
+
+
+static void arch_prepare_ss_slot(struct kp_core *p)
+{
+       /* prepare insn slot */
+       p->ainsn.insn[0] = p->opcode;
+       p->ainsn.insn[1] = conv_inst(BRK64_OPCODE_PSEUDO_SS);
+
+       flush_icache((unsigned long)p->ainsn.insn, KPROBES_TRAMP_LEN);
+}
+
+static void arch_prepare_simulate(struct kp_core *p)
+{
+       if (p->ainsn.prepare)
+               p->ainsn.prepare(p, &p->ainsn);
+}
+
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
+{
+       kprobe_opcode_t insn;
+
+       /* copy instruction */
+       insn = *(kprobe_opcode_t *)p->addr;
+       p->opcode = insn;
+
+       /* decode instruction */
+       switch (arm_kp_core_decode_insn(insn, &p->ainsn)) {
+       case INSN_REJECTED:     /* insn not supported */
+               return -EINVAL;
+
+       case INSN_GOOD_NO_SLOT: /* insn need simulation */
+               p->ainsn.insn = NULL;
+               arch_prepare_simulate(p);
+               break;
+
+       case INSN_GOOD:         /* instruction uses slot */
+               p->ainsn.insn = swap_slot_alloc(sm);
+               if (!p->ainsn.insn)
+                       return -ENOMEM;
+
+               arch_prepare_ss_slot(p);
+               break;
+       };
+
+       return 0;
+}
+
+static void save_previous_kp_core(struct kp_core_ctlblk *kcb,
+                                 unsigned long restore_addr)
+{
+       kcb->prev_kp_core.p = kp_core_running();
+       kcb->prev_kp_core.status = kcb->kp_core_status;
+       kcb->prev_kp_core.restore_addr = restore_addr;
+}
+
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
+{
+       kp_core_running_set(kcb->prev_kp_core.p);
+       kcb->kp_core_status = kcb->prev_kp_core.status;
+       current_restore_td()->restore_addr = kcb->prev_kp_core.restore_addr;
+}
+
+static void set_ss_context(struct kp_core_ctlblk *kcb, unsigned long addr)
+{
+       kcb->ss_ctx.ss_status = KP_CORE_STEP_PENDING;
+       kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
+}
+
+static void clear_ss_context(struct kp_core_ctlblk *kcb)
+{
+       kcb->ss_ctx.ss_status = KP_CORE_STEP_NONE;
+       kcb->ss_ctx.match_addr = 0;
+}
+
+static void nop_singlestep_skip(struct pt_regs *regs)
+{
+       /* set return addr to next pc to continue */
+       regs->pc += sizeof(kprobe_opcode_t);
+}
+
+static int post_kp_core_handler(struct kp_core_ctlblk *kcb,
+                               struct pt_regs *regs);
+
+static void arch_simulate_insn(struct kp_core *p, struct pt_regs *regs)
+{
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       if (p->ainsn.handler)
+               p->ainsn.handler(p->opcode, (long)p->addr, regs);
+
+       /* single step simulated, now go for post processing */
+       post_kp_core_handler(kcb, regs);
+}
+
+static bool is_ss_setup(struct restore_data *restore)
+{
+       return !!restore->restore_addr;
+}
+
+static void setup_singlestep(struct kp_core *p, struct pt_regs *regs,
+                            struct kp_core_ctlblk *kcb, int reenter)
+{
+       struct restore_data *restore = current_restore_td();
+
+       if (reenter) {
+               save_previous_kp_core(kcb, restore->restore_addr);
+               kp_core_running_set(p);
+               kcb->kp_core_status = KPROBE_REENTER;
+       } else {
+               kcb->kp_core_status = KPROBE_HIT_SS;
+       }
+
+       if (p->ainsn.insn) {
+               unsigned long slot = (unsigned long)p->ainsn.insn;
+
+               /* prepare for single stepping */
+               restore->restore_addr = regs->pc + 4;
+               regs->pc = slot;
+
+               set_ss_context(kcb, slot);      /* mark pending ss */
+       } else  {
+               restore->restore_addr = 0;      /* reset */
+
+               /* insn simulation */
+               arch_simulate_insn(p, regs);
+       }
+}
+
+static int reenter_kp_core(struct kp_core *p, struct pt_regs *regs,
+                          struct kp_core_ctlblk *kcb)
+{
+       switch (kcb->kp_core_status) {
+       case KPROBE_HIT_SSDONE:
+       case KPROBE_HIT_ACTIVE:
+               if (!p->ainsn.check_condn || p->ainsn.check_condn(p, regs)) {
+                       setup_singlestep(p, regs, kcb, 1);
+               } else  {
+                       /* condition failed, it's NOP so skip stepping */
+                       nop_singlestep_skip(regs);
+               }
+               break;
+       case KPROBE_HIT_SS:
+               pr_warn("Unrecoverable kp_core detected at %lx\n", p->addr);
+               BUG();
+       default:
+               WARN_ON(1);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int post_kp_core_handler(struct kp_core_ctlblk *kcb,
+                               struct pt_regs *regs)
+{
+       struct kp_core *cur = kp_core_running();
+       struct restore_data *restore = current_restore_td();
+
+       if (cur == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       /* return addr restore if non-branching insn */
+       if (is_ss_setup(restore)) {
+               regs->pc = restore->restore_addr;
+               restore->restore_addr = 0;
+               kp_core_put(cur);
+       } else {
+               WARN_ON(1);
+       }
+
+       /* restore back original saved kp_core variables and continue */
+       if (kcb->kp_core_status == KPROBE_REENTER) {
+               restore_previous_kp_core(kcb);
+       } else  { /* call post handler */
+               kcb->kp_core_status = KPROBE_HIT_SSDONE;
+               kp_core_running_set(NULL);
+       }
+
+       return 1;
+}
+
+static enum dbg_code kprobe_handler(struct pt_regs *regs, unsigned int esr)
+{
+       struct kp_core *p, *cur;
+       struct kp_core_ctlblk *kcb;
+       unsigned long addr = regs->pc;
+       struct restore_data *restore = current_restore_td();
+
+       kcb = kp_core_ctlblk();
+       cur = kp_core_running();
+
+       rcu_read_lock();
+       p = kp_core_by_addr(addr);
+       if (p)
+               kp_core_get(p);
+       rcu_read_unlock();
+
+       if (p) {
+               if (cur && reenter_kp_core(p, regs, kcb)) {
+                       if (!is_ss_setup(restore))
+                               kp_core_put(p);
+
+                       return DBG_HANDLED;
+               } else if (!p->ainsn.check_condn ||
+                       p->ainsn.check_condn(p, regs)) {
+                       /* Probe hit and conditional execution check ok. */
+                       kp_core_running_set(p);
+                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
+
+                       if (!(regs->pstate & PSR_I_BIT))
+                               local_irq_enable();
+
+                       if (!p->handlers.pre(p, regs)) {
+                               kcb->kp_core_status = KPROBE_HIT_SS;
+                               setup_singlestep(p, regs, kcb, 0);
+                       }
+
+                       local_irq_disable();
+               } else {
+                       /*
+                        * Breakpoint hit but conditional check failed,
+                        * so just skip handling since it is NOP.
+                        */
+                       nop_singlestep_skip(regs);
+               }
+
+               if (!is_ss_setup(restore))
+                       kp_core_put(p);
+       } else if (*(kprobe_opcode_t *)addr != BRK64_OPCODE_BP) {
+               /*
+                * The breakpoint instruction was removed right
+                * after we hit it.  Another cpu has removed
+                * either a probepoint or a debugger breakpoint
+                * at this address.  In either case, no further
+                * handling of this interrupt is appropriate.
+                * Return back to original instruction, and continue.
+                */
+       } else {
+               pr_info("no_kprobe: pc=%llx\n", regs->pc);
+       }
+
+       return DBG_HANDLED;
+}
+
+static enum dbg_code kp_core_ss_hit(struct kp_core_ctlblk *kcb,
+                                   unsigned long addr)
+{
+       if ((kcb->ss_ctx.ss_status == KP_CORE_STEP_PENDING)
+           && (kcb->ss_ctx.match_addr == addr)) {
+               /* clear pending ss */
+               clear_ss_context(kcb);
+               return DBG_HANDLED;
+       }
+
+       /* not ours, kp_cores should ignore it */
+       return DBG_ERROR;
+}
+
+static enum dbg_code kprobe_ss_handler(struct pt_regs *regs, unsigned int esr)
+{
+       enum dbg_code ret;
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       /* check, and return error if this is not our step */
+       ret = kp_core_ss_hit(kcb, regs->pc);
+       if (ret == DBG_HANDLED) {
+               /* single step complete, call post handlers */
+               post_kp_core_handler(kcb, regs);
+       }
+
+       return ret;
+}
+
+static struct brk_hook dbg_bp = {
+       .spsr_mask = PSR_MODE_MASK,
+       .spsr_val = PSR_MODE_EL1h,
+       .esr_mask = DBG_BRK_ESR_MASK,
+       .esr_val = DBG_BRK_ESR(BRK_BP),
+       .fn = kprobe_handler,
+};
+
+static struct brk_hook dbg_ss = {
+       .spsr_mask = PSR_MODE_MASK,
+       .spsr_val = PSR_MODE_EL1h,
+       .esr_mask = DBG_BRK_ESR_MASK,
+       .esr_val = DBG_BRK_ESR(BRK_PSEUDO_SS),
+       .fn = kprobe_ss_handler,
+};
+
+
+
+
+
+/* ============================================================================
+ * =                               KRETPROBE                                  =
+ * ============================================================================
+ */
+void swap_kretprobe_trampoline(void);
+__asm(
+       ".text\n"
+       ".global swap_kretprobe_trampoline\n"
+       "swap_kretprobe_trampoline:\n"
+       "stp    x6, x7, [sp,#-16]!\n"
+       "stp    x4, x5, [sp,#-16]!\n"
+       "stp    x2, x3, [sp,#-16]!\n"
+       "stp    x0, x1, [sp,#-16]!\n"
+       "mov    x0, sp\n"                       /* struct pt_regs (x0..x7) */
+       "bl     swap_trampoline_handler\n"
+       "mov    x30, x0\n"                      /* set real lr */
+       "ldp    x0, x1, [sp],#16\n"
+       "ldp    x2, x3, [sp],#16\n"
+       "ldp    x4, x5, [sp],#16\n"
+       "ldp    x6, x7, [sp],#16\n"
+       "ret\n"
+);
+
+void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       ri->ret_addr = (unsigned long *)regs->regs[30]; /* lr */
+       regs->regs[30] = (unsigned long)&swap_kretprobe_trampoline;
+       ri->sp = (unsigned long *)regs->sp;
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                 JUMPER                                   =
+ * ============================================================================
+ */
+struct cb_data {
+       unsigned long ret_addr;
+       unsigned long x0;
+
+       jumper_cb_t cb;
+       char data[0];
+};
+
+static unsigned long __used get_x0(struct cb_data *data)
+{
+       return data->x0;
+}
+
+static unsigned long __used jump_handler(struct cb_data *data)
+{
+       unsigned long ret_addr = data->ret_addr;
+
+       /* call callback */
+       data->cb(data->data);
+
+       /* FIXME: potential memory leak, when process kill */
+       kfree(data);
+
+       return ret_addr;
+}
+
+void jump_trampoline(void);
+__asm(
+       ".text\n"
+       "jump_trampoline:\n"
+
+       "stp    x6, x7, [sp,#-16]!\n"
+       "stp    x4, x5, [sp,#-16]!\n"
+       "stp    x2, x3, [sp,#-16]!\n"
+       "stp    x0, x1, [sp,#-16]!\n"
+       "mov    x1, x0\n"               /* data --> x1 */
+       "bl     get_x0\n"
+       "str    x0, [sp]\n"             /* restore x0 */
+       "mov    x0, x1\n"               /* data --> x0 */
+       "bl     jump_handler\n"
+       "mov    x30, x0\n"              /* set lr */
+       "ldp    x0, x1, [sp],#16\n"
+       "ldp    x2, x3, [sp],#16\n"
+       "ldp    x4, x5, [sp],#16\n"
+       "ldp    x6, x7, [sp],#16\n"
+       "ret\n"
+);
+
+unsigned long get_jump_addr(void)
+{
+       return (unsigned long)&jump_trampoline;
+}
+EXPORT_SYMBOL_GPL(get_jump_addr);
+
+int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
+               jumper_cb_t cb, void *data, size_t size)
+{
+       struct cb_data *cb_data;
+
+       cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
+       if (cb_data == NULL)
+               return -ENOMEM;
+
+       /* save data */
+       if (size)
+               memcpy(cb_data->data, data, size);
+
+       /* save info for restore */
+       cb_data->ret_addr = ret_addr;
+       cb_data->cb = cb;
+       cb_data->x0 = regs->regs[0];
+
+       /* save cb_data to x0 */
+       regs->regs[0] = (long)cb_data;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(set_jump_cb);
+
+
+
+
+
+/* ============================================================================
+ * =                          ARCH INIT/EXIT KPROBES                          =
+ * ============================================================================
+ */
+int arch_init_module_deps(void)
+{
+       return 0;
+}
+
+int swap_arch_init_kprobes(void)
+{
+       int ret;
+
+       ret = swap_ktd_reg(&ktd_restore);
+       if (ret)
+               return ret;
+
+       ret = dbg_iface_init();
+       if (ret)
+               swap_ktd_unreg(&ktd_restore);
+
+       dbg_brk_hook_reg(&dbg_ss);
+       dbg_brk_hook_reg(&dbg_bp);
+
+       return 0;
+}
+
+void swap_arch_exit_kprobes(void)
+{
+       dbg_brk_hook_unreg(&dbg_ss);
+       dbg_brk_hook_unreg(&dbg_bp);
+       dbg_iface_uninit();
+       swap_ktd_unreg(&ktd_restore);
+}
diff --git a/modules/kprobe/arch/arm64/swap-asm/swap_kprobes.h b/modules/kprobe/arch/arm64/swap-asm/swap_kprobes.h
new file mode 100644 (file)
index 0000000..7975938
--- /dev/null
@@ -0,0 +1,153 @@
+#ifndef _ASM_ARM64_KPROBES_H
+#define _ASM_ARM64_KPROBES_H
+
+/*
+ * Copied from: arch/arm64/kernel/kprobes.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+
+
+#define MAX_INSN_SIZE          2
+#define KPROBES_TRAMP_LEN      (MAX_INSN_SIZE * 4)  /* 4 - instruction size */
+
+
+struct kprobe;
+struct kp_core;
+struct slot_manager;
+struct swap_arch_specific_insn;
+struct kretprobe_instance;
+
+
+typedef u32 kprobe_opcode_t;
+typedef unsigned long (kp_core_pstate_check_t)(unsigned long);
+typedef unsigned long (kp_core_condition_check_t)(struct kp_core *,
+                                                 struct pt_regs *);
+typedef void (kp_core_prepare_t)(struct kp_core *,
+                                struct swap_arch_specific_insn *);
+typedef void (kp_core_handler_t)(u32 opcode, long addr, struct pt_regs *);
+
+
+/* architecture specific copy of original instruction */
+struct swap_arch_specific_insn {
+       kprobe_opcode_t *insn;
+       kp_core_pstate_check_t *pstate_cc;
+       kp_core_condition_check_t *check_condn;
+       kp_core_prepare_t *prepare;
+       kp_core_handler_t *handler;
+};
+
+struct prev_kp_core {
+       struct kp_core *p;
+       unsigned int status;
+       unsigned long restore_addr;     /* restore address after single step */
+};
+
+enum ss_status {
+       KP_CORE_STEP_NONE,
+       KP_CORE_STEP_PENDING,
+};
+
+/* Single step context for kp_core */
+struct kp_core_step_ctx {
+       enum ss_status ss_status;
+       unsigned long match_addr;
+};
+
+/* kp_core control block */
+struct kp_core_ctlblk {
+       unsigned int kp_core_status;
+       struct prev_kp_core prev_kp_core;
+       struct kp_core_step_ctx ss_ctx;
+};
+
+
+static inline unsigned long swap_get_karg(struct pt_regs *regs,
+                                         unsigned long n)
+{
+       return n < 8 ?  regs->regs[n] : *(((long *)regs->sp) + (n - 8));
+}
+
+static inline unsigned long swap_get_sarg(struct pt_regs *regs,
+                                         unsigned long n)
+{
+       return swap_get_karg(regs, n);
+}
+
+static inline unsigned long swap_get_kpc(struct pt_regs *regs)
+{
+       return regs->pc;
+}
+
+static inline void swap_set_kpc(struct pt_regs *regs, unsigned long val)
+{
+       regs->pc = val;
+}
+
+
+void arch_kp_core_arm(struct kp_core *p);
+void arch_kp_core_disarm(struct kp_core *p);
+
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
+
+void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                struct pt_regs *regs);
+void swap_kretprobe_trampoline(void);
+
+
+static inline unsigned long arch_get_task_pc(struct task_struct *p)
+{
+       WARN(1, "not implemented"); /* FIXME: to implement */
+       return 0xdeadc0de;
+}
+
+static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
+{
+       WARN(1, "not implemented"); /* FIXME: to implement */
+}
+
+static inline int swap_setjmp_pre_handler(struct kprobe *p,
+                                         struct pt_regs *regs)
+{
+       WARN(1, "not implemented"); /* FIXME: to implement */
+       return 0;
+}
+
+/* jumper */
+typedef unsigned long (*jumper_cb_t)(void *);
+
+unsigned long get_jump_addr(void);
+int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
+               jumper_cb_t cb, void *data, size_t size);
+
+
+int arch_init_module_deps(void);
+
+int swap_arch_init_kprobes(void);
+void swap_arch_exit_kprobes(void);
+
+
+#endif /* _ASM_ARM64_KPROBES_H */
diff --git a/modules/kprobe/arch/arm64/swap-asm/swap_probes.h b/modules/kprobe/arch/arm64/swap-asm/swap_probes.h
new file mode 100644 (file)
index 0000000..3cbd18a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_ARM_PROBES_H
+#define _SWAP_ASM_ARM_PROBES_H
+
+
+#define BREAK_ARM                      0xffffdeff
+#define BREAK_THUMB                    (BREAK_ARM & 0xffff)
+#define RET_BREAK_ARM                  BREAK_ARM
+#define RET_BREAK_THUMB                        BREAK_THUMB
+
+#define PROBES_TRAMP_LEN               (9 * 4)
+#define PROBES_TRAMP_INSN_IDX          2
+#define PROBES_TRAMP_RET_BREAK_IDX     5
+
+
+#endif /* _SWAP_ASM_ARM_PROBES_H */
diff --git a/modules/kprobe/arch/asm-mips/dbi_kprobes.c b/modules/kprobe/arch/asm-mips/dbi_kprobes.c
new file mode 100644 (file)
index 0000000..bc4abb4
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/kprobe/arch/asm-mips/dbi_kprobes.c
+ *
+ * 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, 2006-2010
+ *
+ * 2006-2007    Ekaterina Gorelkina <e.gorelkina@samsung.com>:
+ *             initial implementation for ARM/MIPS
+ * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
+ *              Probes initial implementation; Support x86/ARM/MIPS for both
+ *             user-space and kernel space.
+ * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module
+ *             for separating core and arch parts
+ * 2012                Stanislav Andreev <s.andreev@samsung.com>: added time debug
+ *              profiling support; BUG() message fix
+ */
+
+#include "dbi_kprobes.h"
+#include <kprobe/dbi_kprobes.h>
+
+#include <kprobe/dbi_kdebug.h>
+#include <kprobe/dbi_insn_slots.h>
+#include <kprobe/dbi_kprobes_deps.h>
+#include <kprobe/dbi_uprobes.h>
+#include <ksyms/ksyms.h>
+
+unsigned int *arr_traps_original;
+
+
+unsigned int arr_traps_template[] = {  0x3c010000,   /* lui  a1       [0] */
+                                      0x24210000,   /* addiu a1, a1  [1] */
+                                      0x00200008,   /* jr a1         [2] */
+                                      0x00000000,   /* nop */
+                                      0xffffffff    /* end */
+};
+
+struct kprobe trampoline_p = {
+       .addr = (kprobe_opcode_t *)&kretprobe_trampoline,
+       .pre_handler = trampoline_probe_handler
+};
+
+void gen_insn_execbuf(void);
+
+void gen_insn_execbuf_holder(void)
+{
+       asm volatile(".global gen_insn_execbuf\n"
+                    "gen_insn_execbuf:\n"
+                    "nop\n"                  /* original instruction */
+                    "nop\n"                 /* ssbreak */
+                    "nop\n");               /* retbreak */
+}
+
+
+int arch_check_insn(struct arch_specific_insn *ainsn)
+{
+       int ret = 0;
+
+       switch (MIPS_INSN_OPCODE(ainsn->insn[0])) {
+       case MIPS_BEQ_OPCODE:   /* B, BEQ */
+       case MIPS_BEQL_OPCODE:  /* BEQL */
+       case MIPS_BNE_OPCODE:   /* BNE */
+       case MIPS_BNEL_OPCODE:  /* BNEL */
+       case MIPS_BGTZ_OPCODE:  /* BGTZ */
+       case MIPS_BGTZL_OPCODE: /* BGTZL */
+       case MIPS_BLEZ_OPCODE:  /* BLEZ */
+       case MIPS_BLEZL_OPCODE: /* BLEZL */
+       case MIPS_J_OPCODE:     /* J */
+       case MIPS_JAL_OPCODE:   /* JAL */
+               DBPRINTF("arch_check_insn: opcode");
+               ret = -EFAULT;
+               break;
+       case MIPS_REGIMM_OPCODE:
+               /* BAL, BGEZ, BGEZAL, BGEZALL, BGEZL,
+                * BLTZ, BLTZAL, BLTZALL, BLTZL */
+               switch (MIPS_INSN_RT(ainsn->insn[0])) {
+               case MIPS_BLTZ_RT:
+               case MIPS_BGEZ_RT:
+               case MIPS_BLTZL_RT:
+               case MIPS_BGEZL_RT:
+               case MIPS_BLTZAL_RT:
+               case MIPS_BGEZAL_RT:
+               case MIPS_BLTZALL_RT:
+               case MIPS_BGEZALL_RT:
+                       DBPRINTF("arch_check_insn: REGIMM opcode\n");
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+               /* BC1F, BC1FL, BC1T, BC1TL */
+       case MIPS_COP1_OPCODE:
+               /* BC2F, BC2FL, BC2T, BC2TL */
+       case MIPS_COP2_OPCODE:
+               if (MIPS_INSN_RS(ainsn->insn[0]) == MIPS_BC_RS) {
+                       DBPRINTF("arch_check_insn: COP1 opcode\n");
+                       ret = -EFAULT;
+               }
+               break;
+       case MIPS_SPECIAL_OPCODE:
+               /* BREAK, JALR, JALR.HB, JR, JR.HB */
+               switch (MIPS_INSN_FUNC(ainsn->insn[0])) {
+               case MIPS_JR_FUNC:
+               case MIPS_JALR_FUNC:
+               case MIPS_BREAK_FUNC:
+               case MIPS_SYSCALL_FUNC:
+                       DBPRINTF("arch_check_insn: SPECIAL opcode\n");
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+       }
+       return ret;
+}
+
+int arch_prepare_kprobe(struct kprobe *p)
+{
+       kprobe_opcode_t insns[KPROBES_TRAMP_LEN];
+
+       int ret = 0;
+       if (!ret) {
+               kprobe_opcode_t insn[MAX_INSN_SIZE];
+               struct arch_specific_insn ainsn;
+               /* insn: must be on special executable page on i386. */
+               p->ainsn.insn = get_insn_slot(NULL, 0);
+               if (!p->ainsn.insn)
+                       return -ENOMEM;
+               memcpy(insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+               ainsn.insn = insn;
+               ret = arch_check_insn(&ainsn);
+               if (!ret) {
+                       p->opcode = *p->addr;
+                       p->ainsn.boostable = 0;
+                       memcpy(insns, gen_insn_execbuf, sizeof(insns));
+                       insns[KPROBES_TRAMP_INSN_IDX] = insn[0];
+                       insns[KPROBES_TRAMP_SS_BREAK_IDX] =
+                               BREAKPOINT_INSTRUCTION;
+                       insns[KPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION;
+                       DBPRINTF("arch_prepare_kprobe: insn %lx", insn[0]);
+                       DBPRINTF("arch_prepare_kprobe: to %p - %lx %lx %lx",
+                                       p->ainsn.insn, insns[0],
+                                insns[1], insns[2]);
+                       memcpy(p->ainsn.insn, insns, sizeof(insns));
+               } else {
+                       free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
+               }
+       }
+
+       return ret;
+}
+
+int arch_prepare_uprobe(struct kprobe *p, struct task_struct *task, int atomic)
+{
+       int ret = 0;
+       kprobe_opcode_t insns[UPROBES_TRAMP_LEN];
+
+       if ((unsigned long) p->addr & 0x01) {
+               DBPRINTF("Attempt to register kprobe at an unaligned address");
+               ret = -EINVAL;
+       }
+
+       if (!ret) {
+               kprobe_opcode_t insn[MAX_INSN_SIZE];
+               struct arch_specific_insn ainsn;
+
+               if (!read_proc_vm_atomic(task, (unsigned long) p->addr,
+                                        &insn,
+                                        MAX_INSN_SIZE *
+                                        sizeof(kprobe_opcode_t)))
+                       panic("failed to read memory %p!\n", p->addr);
+               ainsn.insn = insn;
+               ret = arch_check_insn(&ainsn);
+               if (!ret) {
+                       p->opcode = insn[0];
+                       p->ainsn.insn = get_insn_slot(task, atomic);
+                       if (!p->ainsn.insn)
+                               return -ENOMEM;
+                       p->ainsn.boostable = 0;
+                       memcpy(insns, gen_insn_execbuf, sizeof(insns));
+                       insns[UPROBES_TRAMP_INSN_IDX] = insn[0];
+                       insns[UPROBES_TRAMP_SS_BREAK_IDX] =
+                               BREAKPOINT_INSTRUCTION;
+                       insns[UPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION;
+                       DBPRINTF("arch_prepare_uprobe: insn %lx", insn[0]);
+                       DBPRINTF("arch_prepare_uprobe: to %p - %lx %lx %lx",
+                                p->ainsn.insn, insns[0], insns[1], insns[2]);
+
+                       if (!write_proc_vm_atomic(task,
+                                                 (unsigned long) p->ainsn.insn,
+                                                 insns, sizeof(insns))) {
+                               panic("failed to write memory %p!\n",
+                                     p->ainsn.insn);
+                               DBPRINTF("failed to write insn slot to "
+                                        "process memory: insn %p, addr %p, "
+                                        "probe %p!",
+                                        insn, p->ainsn.insn, p->addr);
+                               /* printk("failed to write insn slot to process
+                                * memory: %p/%d insn %lx, addr %p,
+                                * probe %p!\n",task, task->pid, insn,
+                                * p->ainsn.insn, p->addr);*/
+                               free_insn_slot(&uprobe_insn_pages, task,
+                                              p->ainsn.insn);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+       if (p->ss_addr) {
+               regs->cp0_epc = (unsigned long)p->ss_addr;
+               p->ss_addr = NULL;
+       } else
+               regs->cp0_epc = (unsigned long)p->ainsn.insn;
+}
+
+
+void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *cur_p)
+{
+       if (kcb->prev_kprobe.kp != NULL) {
+               panic("no space to save new probe[]: task = %d/%s, prev %d/%p,"
+                     " current %d/%p, new %d/%p,",
+                     current->pid, current->comm, kcb->prev_kprobe.kp->tgid,
+                     kcb->prev_kprobe.kp->addr, kprobe_running()->tgid,
+                     kprobe_running()->addr, cur_p->tgid, cur_p->addr);
+       }
+
+       kcb->prev_kprobe.kp = kprobe_running();
+       kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+       __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+       kcb->kprobe_status = kcb->prev_kprobe.status;
+       kcb->prev_kprobe.kp = NULL;
+       kcb->prev_kprobe.status = 0;
+}
+
+void set_current_kprobe(struct kprobe *p,
+                       struct pt_regs *regs,
+                       struct kprobe_ctlblk *kcb)
+{
+       __get_cpu_var(current_kprobe) = p;
+       DBPRINTF("set_current_kprobe[]: p=%p addr=%p\n", p, p->addr);
+}
+
+int kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p = 0;
+       int ret = 0, pid = 0, retprobe = 0, reenter = 0;
+       kprobe_opcode_t *addr = NULL, *ssaddr = 0;
+       struct kprobe_ctlblk *kcb;
+
+       /* We're in an interrupt, but this is clear and BUG()-safe. */
+
+       addr = (kprobe_opcode_t *) regs->cp0_epc;
+       DBPRINTF("regs->regs[ 31 ] = 0x%lx\n", regs->regs[31]);
+
+       preempt_disable();
+
+       kcb = get_kprobe_ctlblk();
+
+       if (user_mode(regs)) {
+               /* DBPRINTF("exception[%lu] from user mode %s/%u addr %p(%lx).",
+                * nCount, current->comm,
+                * current->pid, addr, regs->uregs[14]); */
+               pid = current->tgid;
+       }
+
+       /* Check we're not actually recursing */
+       if (kprobe_running()) {
+               DBPRINTF("lock???");
+               p = get_kprobe(addr, pid);
+               if (p) {
+                       if (!pid && (addr ==
+                                    (kprobe_opcode_t *)kretprobe_trampoline)) {
+                               save_previous_kprobe(kcb, p);
+                               kcb->kprobe_status = KPROBE_REENTER;
+                               reenter = 1;
+                       } else {
+                               /* We have reentered the kprobe_handler(), since
+                                * another probe was hit while within the
+                                * handler. We here save the original kprobes
+                                * variables and just single step on the
+                                * instruction of the new probe without calling
+                                * any user handlers.
+                                */
+                               if (!p->ainsn.boostable) {
+                                       save_previous_kprobe(kcb, p);
+                                       set_current_kprobe(p, regs, kcb);
+                               }
+                               kprobes_inc_nmissed_count(p);
+                               prepare_singlestep(p, regs);
+                               if (!p->ainsn.boostable)
+                                       kcb->kprobe_status = KPROBE_REENTER;
+                               preempt_enable_no_resched();
+                               return 1;
+                       }
+               } else {
+                       if (pid) {
+                               /* we can reenter probe upon
+                                * uretprobe exception */
+                               DBPRINTF("check for UNDEF_INSTRUCTION %p\n",
+                                        addr);
+                               /* UNDEF_INSTRUCTION from user space */
+                               p = get_kprobe_by_insn_slot(
+                                       addr-UPROBES_TRAMP_RET_BREAK_IDX,
+                                       pid, current);
+                               if (p) {
+                                       save_previous_kprobe(kcb, p);
+                                       kcb->kprobe_status = KPROBE_REENTER;
+                                       reenter = 1;
+                                       retprobe = 1;
+                                       DBPRINTF("uretprobe %p\n", addr);
+                               }
+                       }
+                       if (!p) {
+                               p = __get_cpu_var(current_kprobe);
+                               DBPRINTF("kprobe_running !!! p = 0x%p "
+                                        "p->break_handler = 0x%p", p,
+                                        p->break_handler);
+                               /* if (p->break_handler &&
+                                * p->break_handler(p, regs)) {
+                                * DBPRINTF("kprobe_running !!! goto ss");
+                                * goto ss_probe;
+                                * } */
+                               DBPRINTF("unknown uprobe at %p cur at %p/%p\n",
+                                        addr, p->addr, p->ainsn.insn);
+                               if (pid)
+                                       ssaddr = p->ainsn.insn +
+                                               UPROBES_TRAMP_SS_BREAK_IDX;
+                               else
+                                       ssaddr = p->ainsn.insn +
+                                               KPROBES_TRAMP_SS_BREAK_IDX;
+                               if (addr == ssaddr) {
+                                       regs->cp0_epc =
+                                               (unsigned long)(p->addr + 1);
+                                       DBPRINTF("finish step at %p cur at "
+                                                "%p/%p, redirect to %lx\n",
+                                                addr, p->addr,
+                                                p->ainsn.insn, regs->cp0_epc);
+
+                                       if (kcb->kprobe_status ==
+                                           KPROBE_REENTER) {
+                                               restore_previous_kprobe(kcb);
+                                       } else {
+                                               reset_current_kprobe();
+                                       }
+                               }
+                               DBPRINTF("kprobe_running !!! goto no");
+                               ret = 1;
+                               /* If it's not ours, can't be delete race,
+                                * (we hold lock). */
+                               DBPRINTF("no_kprobe");
+                               goto no_kprobe;
+                       }
+               }
+       }
+
+       /* if(einsn != UNDEF_INSTRUCTION) { */
+       DBPRINTF("get_kprobe %p-%d", addr, pid);
+       if (!p)
+               p = get_kprobe(addr, pid);
+       if (!p) {
+               if (pid) {
+                       DBPRINTF("search UNDEF_INSTRUCTION %p\n", addr);
+                       /*  UNDEF_INSTRUCTION from user space */
+                       p = get_kprobe_by_insn_slot(
+                               addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
+                       if (!p) {
+                               /* Not one of ours: let kernel handle it */
+                               DBPRINTF("no_kprobe");
+                               /* printk("no_kprobe2 ret = %d\n", ret); */
+                               goto no_kprobe;
+                       }
+                       retprobe = 1;
+                       DBPRINTF("uretprobe %p\n", addr);
+               } else {
+                       /* Not one of ours: let kernel handle it */
+                       DBPRINTF("no_kprobe");
+                       /* printk(KERN_INFO "no_kprobe2 ret = %d\n", ret); */
+                       goto no_kprobe;
+               }
+       }
+
+       set_current_kprobe(p, regs, kcb);
+       if (!reenter)
+               kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+       if (retprobe)           /* (einsn == UNDEF_INSTRUCTION) */
+               ret = trampoline_probe_handler(p, regs);
+       else if (p->pre_handler) {
+               ret = p->pre_handler(p, regs);
+               if (!p->ainsn.boostable)
+                       kcb->kprobe_status = KPROBE_HIT_SS;
+               else if (p->pre_handler != trampoline_probe_handler) {
+                       reset_current_kprobe();
+               }
+       }
+
+       if (ret) {
+               DBPRINTF("p->pre_handler[] 1");
+               /* handler has already set things up, so skip ss setup */
+               return 1;
+       }
+       DBPRINTF("p->pre_handler 0");
+
+no_kprobe:
+       preempt_enable_no_resched();
+       return ret;
+}
+
+void patch_suspended_task_ret_addr(struct task_struct *p, struct kretprobe *rp)
+{
+       DBPRINTF("patch_suspended_task_ret_addr is not implemented");
+}
+
+int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       kprobe_pre_entry_handler_t pre_entry;
+       entry_point_t entry;
+
+       DBPRINTF("pjp = 0x%p jp->entry = 0x%p", jp, jp->entry);
+       entry = (entry_point_t) jp->entry;
+       pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
+       /* if(!entry) */
+       /*       DIE("entry NULL", regs) */
+       DBPRINTF("entry = 0x%p jp->entry = 0x%p", entry, jp->entry);
+
+       /* call handler for all kernel probes and user space
+        * ones which belong to current tgid */
+       if (!p->tgid || (p->tgid == current->tgid)) {
+               if (!p->tgid && (p->addr == sched_addr) && sched_rp) {
+                       struct task_struct *p, *g;
+                       rcu_read_lock();
+                       /* swapper task */
+                       if (current != &init_task)
+                               patch_suspended_task_ret_addr(&init_task,
+                                                             sched_rp);
+                       /*  other tasks */
+                       do_each_thread(g, p) {
+                               if (p == current)
+                                       continue;
+                               patch_suspended_task_ret_addr(p, sched_rp);
+                       } while_each_thread(g, p);
+                       rcu_read_unlock();
+               }
+               if (pre_entry)
+                       p->ss_addr = (void *)pre_entry(jp->priv_arg, regs);
+               if (entry) {
+                       entry(regs->regs[4], regs->regs[5], regs->regs[6],
+                             regs->regs[7], regs->regs[8], regs->regs[9]);
+               } else {
+                       if (p->tgid)
+                               arch_ujprobe_return();
+                       else
+                               dbi_jprobe_return();
+               }
+       } else if (p->tgid)
+               arch_ujprobe_return();
+
+       prepare_singlestep(p, regs);
+
+       return 1;
+}
+
+
+void dbi_jprobe_return(void)
+{
+       preempt_enable_no_resched();
+}
+
+void arch_ujprobe_return(void)
+{
+       preempt_enable_no_resched();
+}
+
+int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       return 0;
+}
+
+void arch_arm_kprobe(struct kprobe *p)
+{
+       *p->addr = BREAKPOINT_INSTRUCTION;
+       flush_icache_range((unsigned long) p->addr,
+                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+}
+
+void arch_disarm_kprobe(struct kprobe *p)
+{
+       *p->addr = p->opcode;
+       flush_icache_range((unsigned long) p->addr,
+                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+}
+
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_head *head, empty_rp;
+       struct hlist_node *node, *tmp;
+       unsigned long flags, orig_ret_address = 0;
+       unsigned long trampoline_address =
+               (unsigned long) &kretprobe_trampoline;
+       struct kretprobe *crp = NULL;
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       DBPRINTF("start");
+
+       if (p && p->tgid) {
+               /*  in case of user space retprobe trampoline
+                * is at the Nth instruction of US tramp */
+               trampoline_address =
+                       (unsigned long)(p->ainsn.insn +
+                                       UPROBES_TRAMP_RET_BREAK_IDX);
+       }
+
+       INIT_HLIST_HEAD(&empty_rp);
+       spin_lock_irqsave(&kretprobe_lock, flags);
+       head = kretprobe_inst_table_head(current);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist)
+       {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+               if (ri->rp && ri->rp->handler)
+                       ri->rp->handler(ri, regs, ri->rp->priv_arg);
+
+               orig_ret_address = (unsigned long) ri->ret_addr;
+               recycle_rp_inst(ri);
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+       /* BUG_ON(!orig_ret_address ||
+        * (orig_ret_address == trampoline_address)); */
+       if (trampoline_address != (unsigned long) &kretprobe_trampoline)
+               if (ri->rp)
+                       BUG_ON(ri->rp->kp.tgid == 0);
+
+       if (ri->rp && ri->rp->kp.tgid)
+               BUG_ON(trampoline_address ==
+                      (unsigned long) &kretprobe_trampoline);
+
+       regs->regs[31] = orig_ret_address;
+       DBPRINTF("regs->cp0_epc = 0x%lx", regs->cp0_epc);
+       if (trampoline_address != (unsigned long) &kretprobe_trampoline)
+               regs->cp0_epc = orig_ret_address;
+       else
+               regs->cp0_epc = regs->cp0_epc + 4;
+       DBPRINTF("regs->cp0_epc = 0x%lx", regs->cp0_epc);
+       DBPRINTF("regs->cp0_status = 0x%lx", regs->cp0_status);
+
+       if (p) { /*  ARM, MIPS, X86 user space */
+               if (kcb->kprobe_status == KPROBE_REENTER)
+                       restore_previous_kprobe(kcb);
+               else
+                       reset_current_kprobe();
+       }
+
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+       hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist)
+       {
+               hlist_del(&ri->hlist);
+               kfree(ri);
+       }
+       preempt_enable_no_resched();
+       /*
+        * By returning a non-zero value, we are telling
+        * kprobe_handler() that we don't want the post_handler
+        * to run (and have re-enabled preemption)
+        */
+       return 1;
+}
+
+void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+{
+
+       struct kretprobe_instance *ri;
+
+       DBPRINTF("start\n");
+       /* TODO: test - remove retprobe after func entry but before its exit */
+       ri = get_free_rp_inst(rp);
+       if (ri != NULL) {
+               ri->rp = rp;
+               ri->task = current;
+               ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
+               if (rp->kp.tgid)
+                       regs->regs[31] =
+                               (unsigned long)(rp->kp.ainsn.insn +
+                                               UPROBES_TRAMP_RET_BREAK_IDX);
+               else    /* Replace the return addr with trampoline addr */
+                       regs->regs[31] = (unsigned long) &kretprobe_trampoline;
+               add_rp_inst(ri);
+       } else {
+               DBPRINTF("WARNING: missed retprobe %p\n", rp->kp.addr);
+               rp->nmissed++;
+       }
+}
+
+DECLARE_MOD_CB_DEP(flush_icache_range, \
+               void, unsigned long __user start, unsigned long __user end);
+DECLARE_MOD_CB_DEP(flush_icache_page, \
+               void, struct vm_area_struct *vma, struct page *page);
+DECLARE_MOD_CB_DEP(flush_cache_page, \
+               void, struct vm_area_struct *vma, unsigned long page);
+
+int arch_init_module_deps()
+{
+       INIT_MOD_DEP_CB(flush_icache_range, r4k_flush_icache_range);
+       INIT_MOD_DEP_CB(flush_icache_page, r4k_flush_icache_page);
+       INIT_MOD_DEP_CB(flush_cache_page, r4k_flush_cache_page);
+
+       return 0;
+}
+
+
+int __init arch_init_kprobes(void)
+{
+       unsigned int do_bp_handler;
+       unsigned int kprobe_handler_addr;
+
+       unsigned int insns_num = 0;
+       unsigned int code_size = 0;
+
+       unsigned int reg_hi;
+       unsigned int reg_lo;
+
+       int ret;
+
+       if (arch_init_module_dependencies()) {
+               DBPRINTF("Unable to init module dependencies\n");
+               return -1;
+       }
+
+       do_bp_handler = (unsigned int)swap_ksyms("do_bp");
+
+       kprobe_handler_addr = (unsigned int) &kprobe_handler;
+       insns_num = sizeof(arr_traps_template) / sizeof(arr_traps_template[0]);
+       code_size = insns_num * sizeof(unsigned int);
+       DBPRINTF("insns_num = %d\n", insns_num);
+       /*  Save original code */
+       arr_traps_original = kmalloc(code_size, GFP_KERNEL);
+       if (!arr_traps_original) {
+               DBPRINTF("Unable to allocate space for "
+                        "original code of <do_bp>!\n");
+               return -1;
+       }
+       memcpy(arr_traps_original, (void *) do_bp_handler, code_size);
+
+       reg_hi = HIWORD(kprobe_handler_addr);
+       reg_lo = LOWORD(kprobe_handler_addr);
+       if (reg_lo >= 0x8000)
+               reg_hi += 0x0001;
+       arr_traps_template[REG_HI_INDEX] |= reg_hi;
+       arr_traps_template[REG_LO_INDEX] |= reg_lo;
+
+       /*  Insert new code */
+       memcpy((void *) do_bp_handler, arr_traps_template, code_size);
+       flush_icache_range(do_bp_handler, do_bp_handler + code_size);
+       ret = dbi_register_kprobe(&trampoline_p);
+       if (ret != 0) {
+               /* dbi_unregister_jprobe(&do_exit_p, 0); */
+               return ret;
+       }
+}
+
+void __exit dbi_arch_exit_kprobes(void)
+{
+       unsigned int do_bp_handler;
+
+       unsigned int insns_num = 0;
+       unsigned int code_size = 0;
+
+       /*  Get instruction address */
+       do_bp_handler = (unsigned int)swap_ksyms("do_undefinstr");
+
+       /* dbi_unregister_jprobe(&do_exit_p, 0); */
+
+       /*  Replace back the original code */
+
+       insns_num = sizeof(arr_traps_template) / sizeof(arr_traps_template[0]);
+       code_size = insns_num * sizeof(unsigned int);
+       memcpy((void *) do_bp_handler, arr_traps_original, code_size);
+       flush_icache_range(do_bp_handler, do_bp_handler + code_size);
+       kfree(arr_traps_original);
+       arr_traps_original = NULL;
+}
+
+
diff --git a/modules/kprobe/arch/asm-mips/dbi_kprobes.h b/modules/kprobe/arch/asm-mips/dbi_kprobes.h
new file mode 100644 (file)
index 0000000..23b36f5
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef _SRC_ASM_MIPS_KPROBES_H
+#define _SRC_ASM_MIPS_KPROBES_H
+
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/kprobe/arch/asm-mips/dbi_kprobes.h
+ *
+ * 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, 2006-2010
+ *
+ * 2006-2007    Ekaterina Gorelkina <e.gorelkina@samsung.com>:
+ *             initial implementation for ARM/MIPS
+ * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
+ *              Probes initial implementation; Support x86/ARM/MIPS for both
+ *             user-space and kernel space.
+ * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>:
+ *             redesign module for separating core and arch parts
+ *
+ */
+
+#include <kprobe/dbi_kprobes_deps.h>
+#include <kprobe/dbi_kprobes.h>
+
+typedef unsigned long kprobe_opcode_t;
+
+#define BREAKPOINT_INSTRUCTION         0x0000000d
+
+#ifndef KPROBES_RET_PROBE_TRAMP
+#define UNDEF_INSTRUCTION              0x0000004d
+#endif
+
+#define MAX_INSN_SIZE                  1
+
+# define UPROBES_TRAMP_LEN             3
+# define UPROBES_TRAMP_INSN_IDX        0
+# define UPROBES_TRAMP_SS_BREAK_IDX    1
+# define UPROBES_TRAMP_RET_BREAK_IDX   2
+# define KPROBES_TRAMP_LEN             UPROBES_TRAMP_LEN
+# define KPROBES_TRAMP_INSN_IDX        UPROBES_TRAMP_INSN_IDX
+# define KPROBES_TRAMP_SS_BREAK_IDX    UPROBES_TRAMP_SS_BREAK_IDX
+# define KPROBES_TRAMP_RET_BREAK_IDX   UPROBES_TRAMP_RET_BREAK_IDX
+
+#define REG_HI_INDEX                   0
+#define REG_LO_INDEX                   1
+#define NOTIFIER_CALL_CHAIN_INDEX      0
+
+
+#define MIPS_INSN_OPCODE_MASK  0xFC000000
+#define MIPS_INSN_RS_MASK      0x03E00000
+#define MIPS_INSN_RT_MASK      0x001F0000
+/* #define MIPS_INSN_UN_MASK     0x0000FFC0 */
+#define MIPS_INSN_FUNC_MASK     0x0000003F
+#define MIPS_INSN_OPCODE(insn) (insn & MIPS_INSN_OPCODE_MASK)
+#define MIPS_INSN_RS(insn)      (insn & MIPS_INSN_RS_MASK)
+#define MIPS_INSN_RT(insn)      (insn & MIPS_INSN_RT_MASK)
+#define MIPS_INSN_FUNC(insn)   (insn & MIPS_INSN_FUNC_MASK)
+/* opcodes 31..26 */
+#define MIPS_BEQ_OPCODE                0x10000000
+#define MIPS_BNE_OPCODE                0x14000000
+#define MIPS_BLEZ_OPCODE       0x18000000
+#define MIPS_BGTZ_OPCODE       0x1C000000
+#define MIPS_BEQL_OPCODE       0x50000000
+#define MIPS_BNEL_OPCODE       0x54000000
+#define MIPS_BLEZL_OPCODE      0x58000000
+#define MIPS_BGTZL_OPCODE      0x5C000000
+#define MIPS_REGIMM_OPCODE     0x04000000
+#define MIPS_SPECIAL_OPCODE    0x00000000
+#define MIPS_COP1_OPCODE       0x44000000
+#define MIPS_COP2_OPCODE       0x48000000
+#define MIPS_J_OPCODE          0x08000000
+#define MIPS_JAL_OPCODE                0x0C000000
+#define MIPS_JALX_OPCODE       0x74000000
+/*  rs 25..21 */
+#define MIPS_BC_RS             0x01000000
+/*  rt 20..16 */
+#define MIPS_BLTZ_RT           0x00000000
+#define MIPS_BGEZ_RT           0x00010000
+#define MIPS_BLTZL_RT          0x00020000
+#define MIPS_BGEZL_RT          0x00030000
+#define MIPS_BLTZAL_RT         0x00100000
+#define MIPS_BGEZAL_RT         0x00110000
+#define MIPS_BLTZALL_RT                0x00120000
+#define MIPS_BGEZALL_RT                0x00130000
+/*  unnamed 15..6 */
+/*  function 5..0 */
+#define MIPS_JR_FUNC           0x00000008
+#define MIPS_JALR_FUNC         0x00000009
+#define MIPS_BREAK_FUNC                0x0000000D
+#define MIPS_SYSCALL_FUNC      0x0000000C
+
+
+/* per-cpu kprobe control block */
+struct kprobe_ctlblk {
+       unsigned long kprobe_status;
+       struct prev_kprobe prev_kprobe;
+};
+
+/* Architecture specific copy of original instruction */
+struct arch_specific_insn {
+       /* copy of the original instruction */
+       kprobe_opcode_t *insn;
+       /*
+        * If this flag is not 0, this kprobe can be boost when its
+        * post_handler and break_handler is not set.
+        */
+       int boostable;
+};
+
+typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
+                                         unsigned long, unsigned long,
+                                         unsigned long, unsigned long);
+
+
+void gen_insn_execbuf_holder(void);
+
+void patch_suspended_task_ret_addr(struct task_struct *p, struct kretprobe *rp);
+int arch_init_module_deps(void);
+
+#endif /*  _SRC_ASM_MIPS_KPROBES_H */
diff --git a/modules/kprobe/arch/x86/swap-asm/swap_kprobes.c b/modules/kprobe/arch/x86/swap-asm/swap_kprobes.c
new file mode 100644 (file)
index 0000000..72b47e1
--- /dev/null
@@ -0,0 +1,1059 @@
+/**
+ * arch/asm-x86/swap_kprobes.c
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ * @author Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
+ *
+ * @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) IBM Corporation, 2002, 2004
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP krpobes arch-dependend part for x86.
+ */
+
+
+#include <linux/kconfig.h>
+
+#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
+# error "Kernel is immutable"
+#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
+
+
+#include<linux/module.h>
+#include <linux/kdebug.h>
+
+#include "swap_kprobes.h"
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_td_raw.h>
+#include <kprobe/swap_kdebug.h>
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_kprobes_deps.h>
+
+
+static int (*swap_fixup_exception)(struct pt_regs *regs);
+static void *(*swap_text_poke)(void *addr, const void *opcode, size_t len);
+static void (*swap_show_registers)(struct pt_regs *regs);
+
+
+#define SWAP_SAVE_REGS_STRING                  \
+       /* Skip cs, ip, orig_ax and gs. */      \
+       "subl $16, %esp\n"                      \
+       "pushl %fs\n"                           \
+       "pushl %es\n"                           \
+       "pushl %ds\n"                           \
+       "pushl %eax\n"                          \
+       "pushl %ebp\n"                          \
+       "pushl %edi\n"                          \
+       "pushl %esi\n"                          \
+       "pushl %edx\n"                          \
+       "pushl %ecx\n"                          \
+       "pushl %ebx\n"
+#define SWAP_RESTORE_REGS_STRING               \
+       "popl %ebx\n"                           \
+       "popl %ecx\n"                           \
+       "popl %edx\n"                           \
+       "popl %esi\n"                           \
+       "popl %edi\n"                           \
+       "popl %ebp\n"                           \
+       "popl %eax\n"                           \
+       /* Skip ds, es, fs, gs, orig_ax, and ip. Note: don't pop cs here*/\
+       "addl $24, %esp\n"
+
+
+/*
+ * Function return probe trampoline:
+ *      - init_kprobes() establishes a probepoint here
+ *      - When the probed function returns, this probe
+ *        causes the handlers to fire
+ */
+__asm(
+       ".global swap_kretprobe_trampoline\n"
+       "swap_kretprobe_trampoline:\n"
+       "pushf\n"
+       SWAP_SAVE_REGS_STRING
+       "movl %esp, %eax\n"
+       "call swap_trampoline_handler\n"
+       /* move eflags to cs */
+       "movl 56(%esp), %edx\n"
+       "movl %edx, 52(%esp)\n"
+       /* replace saved flags with true return address. */
+       "movl %eax, 56(%esp)\n"
+       SWAP_RESTORE_REGS_STRING
+       "popf\n"
+       "ret\n"
+);
+
+/* insert a jmp code */
+static __always_inline void set_jmp_op(void *from, void *to)
+{
+       struct __arch_jmp_op {
+               char op;
+               long raddr;
+       } __packed * jop;
+       jop = (struct __arch_jmp_op *) from;
+       jop->raddr = (long) (to) - ((long) (from) + 5);
+       jop->op = RELATIVEJUMP_INSTRUCTION;
+}
+
+/**
+ * @brief Check if opcode can be boosted.
+ *
+ * @param opcodes Opcode to check.
+ * @return Non-zero if opcode can be boosted.
+ */
+int swap_can_boost(kprobe_opcode_t *opcodes)
+{
+#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf) \
+       (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) |   \
+         (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) |   \
+         (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) |   \
+         (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf))    \
+        << (row % 32))
+       /*
+        * Undefined/reserved opcodes, conditional jump, Opcode Extension
+        * Groups, and some special opcodes can not be boost.
+        */
+       static const unsigned long twobyte_is_boostable[256 / 32] = {
+               /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+               W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) |
+               W(0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+               W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
+               W(0x30, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+               W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
+               W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+               W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1) |
+               W(0x70, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1),
+               W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
+               W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+               W(0xa0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1) |
+               W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1),
+               W(0xc0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) |
+               W(0xd0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1),
+               W(0xe0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1) |
+               W(0xf0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0)
+               /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+
+       };
+#undef W
+       kprobe_opcode_t opcode;
+       kprobe_opcode_t *orig_opcodes = opcodes;
+retry:
+       if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
+               return 0;
+       opcode = *(opcodes++);
+
+       /* 2nd-byte opcode */
+       if (opcode == 0x0f) {
+               if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
+                       return 0;
+               return test_bit(*opcodes, twobyte_is_boostable);
+       }
+
+       switch (opcode & 0xf0) {
+       case 0x60:
+               if (0x63 < opcode && opcode < 0x67)
+                       goto retry;     /* prefixes */
+               /* can't boost Address-size override and bound */
+               return (opcode != 0x62 && opcode != 0x67);
+       case 0x70:
+               return 0;       /* can't boost conditional jump */
+       case 0xc0:
+               /* can't boost software-interruptions */
+               return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf;
+       case 0xd0:
+               /* can boost AA* and XLAT */
+               return (opcode == 0xd4 || opcode == 0xd5 || opcode == 0xd7);
+       case 0xe0:
+               /* can boost in/out and absolute jmps */
+               return ((opcode & 0x04) || opcode == 0xea);
+       case 0xf0:
+               if ((opcode & 0x0c) == 0 && opcode != 0xf1)
+                       goto retry;     /* lock/rep(ne) prefix */
+               /* clear and set flags can be boost */
+               return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe));
+       default:
+               if (opcode == 0x26 || opcode == 0x36 || opcode == 0x3e)
+                       goto retry;     /* prefixes */
+               /* can't boost CS override and call */
+               return (opcode != 0x2e && opcode != 0x9a);
+       }
+}
+EXPORT_SYMBOL_GPL(swap_can_boost);
+
+/*
+ * returns non-zero if opcode modifies the interrupt flag.
+ */
+static int is_IF_modifier(kprobe_opcode_t opcode)
+{
+       switch (opcode) {
+       case 0xfa:              /* cli */
+       case 0xfb:              /* sti */
+       case 0xcf:              /* iret/iretd */
+       case 0x9d:              /* popf/popfd */
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * @brief Creates trampoline for kprobe.
+ *
+ * @param p Pointer to kprobe.
+ * @param sm Pointer to slot manager
+ * @return 0 on success, error code on error.
+ */
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
+{
+       /* insn: must be on special executable page on i386. */
+       p->ainsn.insn = swap_slot_alloc(sm);
+       if (p->ainsn.insn == NULL)
+               return -ENOMEM;
+
+       memcpy(p->ainsn.insn, (void *)p->addr, MAX_INSN_SIZE);
+
+       p->opcode = *(char *)p->addr;
+       p->ainsn.boostable = swap_can_boost((void *)p->addr) ? 0 : -1;
+
+       return 0;
+}
+
+/**
+ * @brief Prepares singlestep for current CPU.
+ *
+ * @param p Pointer to kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+static void prepare_singlestep(struct kp_core *p, struct pt_regs *regs)
+{
+       regs->flags |= TF_MASK;
+       regs->flags &= ~IF_MASK;
+
+       /* single step inline if the instruction is an int3 */
+       if (p->opcode == BREAKPOINT_INSTRUCTION)
+               regs->ip = (unsigned long)p->addr;
+       else
+               regs->ip = (unsigned long)p->ainsn.insn;
+}
+
+/**
+ * @brief Saves previous kprobe.
+ *
+ * @param kcb Pointer to kp_core_ctlblk struct whereto save current kprobe.
+ * @param p_run Pointer to kprobe.
+ * @return Void.
+ */
+static void save_previous_kp_core(struct kp_core_ctlblk *kcb, struct kp_core *cur)
+{
+       if (kcb->prev_kp_core.p != NULL) {
+               panic("no space to save new probe[]: "
+                     "task = %d/%s, prev %08lx, current %08lx, new %08lx,",
+                     current->pid, current->comm, kcb->prev_kp_core.p->addr,
+                     kp_core_running()->addr, cur->addr);
+       }
+
+
+       kcb->prev_kp_core.p = kp_core_running();
+       kcb->prev_kp_core.status = kcb->kp_core_status;
+}
+
+/**
+ * @brief Restores previous kp_core.
+ *
+ * @param kcb Pointer to kp_core_ctlblk which contains previous kp_core.
+ * @return Void.
+ */
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
+{
+       kp_core_running_set(kcb->prev_kp_core.p);
+       kcb->kp_core_status = kcb->prev_kp_core.status;
+       kcb->prev_kp_core.p = NULL;
+       kcb->prev_kp_core.status = 0;
+}
+
+static void set_current_kp_core(struct kp_core *p, struct pt_regs *regs,
+                               struct kp_core_ctlblk *kcb)
+{
+       kp_core_running_set(p);
+       kcb->kp_core_saved_eflags = kcb->kp_core_old_eflags =
+               (regs->EREG(flags) & (TF_MASK | IF_MASK));
+       if (is_IF_modifier(p->opcode))
+               kcb->kp_core_saved_eflags &= ~IF_MASK;
+}
+
+static int setup_singlestep(struct kp_core *p, struct pt_regs *regs,
+                           struct kp_core_ctlblk *kcb)
+{
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
+       if (p->ainsn.boostable == 1) {
+               /* Boost up -- we can execute copied instructions directly */
+               kp_core_running_set(NULL);
+               regs->ip = (unsigned long)p->ainsn.insn;
+
+               return 1;
+       }
+#endif /* !CONFIG_PREEMPT */
+
+       prepare_singlestep(p, regs);
+       kcb->kp_core_status = KPROBE_HIT_SS;
+
+       return 1;
+}
+
+
+struct regs_td {
+       struct pt_regs *sp_regs;
+       struct pt_regs regs;
+};
+
+static struct td_raw kp_tdraw;
+static DEFINE_PER_CPU(struct regs_td, per_cpu_regs_td_i);
+static DEFINE_PER_CPU(struct regs_td, per_cpu_regs_td_st);
+
+static struct regs_td *current_regs_td(void)
+{
+       if (swap_in_interrupt())
+               return &__get_cpu_var(per_cpu_regs_td_i);
+       else if (switch_to_bits_get(current_kctx, SWITCH_TO_ALL))
+               return &__get_cpu_var(per_cpu_regs_td_st);
+
+       return (struct regs_td *)swap_td_raw(&kp_tdraw, current);
+}
+
+/** Stack address. */
+unsigned long swap_kernel_sp(struct pt_regs *regs)
+{
+       struct pt_regs *sp_regs = current_regs_td()->sp_regs;
+
+       if (sp_regs == NULL)
+               sp_regs = regs;
+
+       return kernel_stack_pointer(sp_regs);
+}
+EXPORT_SYMBOL_GPL(swap_kernel_sp);
+
+void exec_trampoline(void);
+void exec_trampoline_int3(void);
+__asm(
+       ".text\n"
+       "exec_trampoline:\n"
+       "call   exec_handler\n"
+       "exec_trampoline_int3:\n"
+       "int3\n"
+);
+
+static int __used exec_handler(void)
+{
+       struct kp_core *p = kp_core_running();
+       struct pt_regs *regs = &current_regs_td()->regs;
+
+       return p->handlers.pre(p, regs);
+}
+
+static int after_exec_trampoline(struct pt_regs *regs)
+{
+       int ret = (int)regs->ax;
+       struct kp_core *p = kp_core_running();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       /*
+        * Restore regs from stack.
+        * Don't restore SP and SS registers because they are invalid (- 8)
+        */
+       memcpy(regs, &current_regs_td()->regs, sizeof(*regs) - 8);
+
+       if (ret) {
+               kp_core_put(p);
+               return 1;
+       }
+
+       setup_singlestep(p, regs, kcb);
+       if (!(regs->flags & TF_MASK))
+               kp_core_put(p);
+
+       return 1;
+}
+
+#define KSTAT_NOT_FOUND                0x00
+#define KSTAT_FOUND            0x01
+#define KSTAT_PREPARE_KCB      0x02
+
+static unsigned long kprobe_pre_handler(struct kp_core *p,
+                                       struct pt_regs *regs,
+                                       struct kp_core_ctlblk *kcb)
+{
+       int ret = KSTAT_NOT_FOUND;
+       unsigned long addr = regs->ip - 1;
+
+       /* Check we're not actually recursing */
+       if (kp_core_running()) {
+               if (p) {
+                       if (kcb->kp_core_status == KPROBE_HIT_SS &&
+                           *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
+                               regs->flags &= ~TF_MASK;
+                               regs->flags |= kcb->kp_core_saved_eflags;
+                               goto out;
+                       }
+
+                       /* We have reentered the kprobe_handler(), since
+                        * another probe was hit while within the handler.
+                        * We here save the original kprobes variables and
+                        * just single step on the instruction of the new probe
+                        * without calling any user handlers.
+                        */
+                       save_previous_kp_core(kcb, p);
+                       set_current_kp_core(p, regs, kcb);
+                       prepare_singlestep(p, regs);
+                       kcb->kp_core_status = KPROBE_REENTER;
+
+                       ret = KSTAT_FOUND;
+                       goto out;
+               } else {
+                       if (*(char *)addr != BREAKPOINT_INSTRUCTION) {
+                               /* The breakpoint instruction was removed by
+                                * another cpu right after we hit, no further
+                                * handling of this interrupt is appropriate
+                                */
+                               regs->EREG(ip) -= sizeof(kprobe_opcode_t);
+
+                               ret = KSTAT_FOUND;
+                               goto out;
+                       }
+
+                       goto out;
+               }
+       }
+
+       if (!p) {
+               if (*(char *)addr != BREAKPOINT_INSTRUCTION) {
+                       /*
+                        * The breakpoint instruction was removed right
+                        * after we hit it.  Another cpu has removed
+                        * either a probepoint or a debugger breakpoint
+                        * at this address.  In either case, no further
+                        * handling of this interrupt is appropriate.
+                        * Back up over the (now missing) int3 and run
+                        * the original instruction.
+                        */
+                       regs->EREG(ip) -= sizeof(kprobe_opcode_t);
+
+                       ret = KSTAT_FOUND;
+               }
+
+               goto out;
+       }
+
+       set_current_kp_core(p, regs, kcb);
+       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
+
+       ret = KSTAT_PREPARE_KCB;
+out:
+       return ret;
+}
+
+static int __kprobe_handler(struct pt_regs *regs)
+{
+       int ret;
+       struct kp_core *p;
+       struct kp_core_ctlblk *kcb;
+       unsigned long addr = regs->ip - 1;
+       struct kctx *ctx = current_kctx;
+
+       if (addr == sched_addr)
+               switch_to_bits_set(ctx, SWITCH_TO_KP);
+
+       kcb = kp_core_ctlblk();
+
+       rcu_read_lock();
+       p = kp_core_by_addr(addr);
+       kp_core_get(p);
+       rcu_read_unlock();
+
+       if (able2resched(ctx)) {
+               ret = kprobe_pre_handler(p, regs, kcb);
+               if (ret == KSTAT_PREPARE_KCB) {
+                       struct regs_td *rtd = current_regs_td();
+
+                       /* save regs to stack */
+                       rtd->regs = *regs;
+                       rtd->sp_regs = regs;
+
+                       regs->ip = (unsigned long)exec_trampoline;
+                       return 1;
+               }
+
+               if (!(regs->flags & TF_MASK))
+                       kp_core_put(p);
+       } else {
+               ret = kprobe_pre_handler(p, regs, kcb);
+               if (ret == KSTAT_PREPARE_KCB) {
+                       int rr;
+
+                       current_regs_td()->sp_regs = NULL;
+                       rr = p->handlers.pre(p, regs);
+                       if (rr) {
+                               switch_to_bits_reset(ctx, SWITCH_TO_KP);
+                               kp_core_put(p);
+                               return 1;
+                       }
+
+                       setup_singlestep(p, regs, kcb);
+               }
+
+               /*
+                * If TF is enabled then processing instruction
+                * takes place in two stages.
+                */
+               if (regs->flags & TF_MASK) {
+                       preempt_disable();
+               } else {
+                       switch_to_bits_reset(ctx, SWITCH_TO_KP);
+                       kp_core_put(p);
+               }
+       }
+
+       return !!ret;
+}
+
+static int kprobe_handler(struct pt_regs *regs)
+{
+       int ret;
+
+       if (regs->ip == (unsigned long)exec_trampoline_int3 + 1)
+               ret = after_exec_trampoline(regs);
+       else
+               ret = __kprobe_handler(regs);
+
+       return ret;
+}
+
+/**
+ * @brief Probe pre handler.
+ *
+ * @param p Pointer to fired kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return 0.
+ */
+int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       kprobe_pre_entry_handler_t pre_entry;
+
+       unsigned long addr;
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
+
+       kcb->jprobe_saved_regs = *regs;
+       kcb->jprobe_saved_esp = (unsigned long *)swap_kernel_sp(regs);
+       addr = (unsigned long)(kcb->jprobe_saved_esp);
+
+       /* TBD: As Linus pointed out, gcc assumes that the callee
+        * owns the argument space and could overwrite it, e.g.
+        * tailcall optimization. So, to be absolutely safe
+        * we also save and restore enough stack bytes to cover
+        * the argument area. */
+       memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
+              MIN_STACK_SIZE(addr));
+       regs->EREG(flags) &= ~IF_MASK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+       trace_hardirqs_off();
+#endif
+
+       regs->EREG(ip) = (unsigned long)(jp->entry);
+
+       return 1;
+}
+
+/**
+ * @brief Jprobe return end.
+ *
+ * @return Void.
+ */
+void swap_jprobe_return_end(void);
+
+/**
+ * @brief Jprobe return code.
+ *
+ * @return Void.
+ */
+void swap_jprobe_return(void)
+{
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       asm volatile("       xchgl   %%ebx,%%esp\n"
+                    "       int3\n"
+                    "       .globl swap_jprobe_return_end\n"
+                    "       swap_jprobe_return_end:\n"
+                    "       nop\n"
+                    : : "b" (kcb->jprobe_saved_esp) : "memory");
+}
+EXPORT_SYMBOL_GPL(swap_jprobe_return);
+
+void arch_ujprobe_return(void)
+{
+}
+
+/*
+ * Called after single-stepping.  p->addr is the address of the
+ * instruction whose first byte has been replaced by the "int 3"
+ * instruction.  To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction.  The address of this
+ * copy is p->ainsn.insn.
+ *
+ * This function prepares to return from the post-single-step
+ * interrupt.  We have to fix up the stack as follows:
+ *
+ * 0) Except in the case of absolute or indirect jump or call instructions,
+ * the new eip is relative to the copied instruction.  We need to make
+ * it relative to the original instruction.
+ *
+ * 1) If the single-stepped instruction was pushfl, then the TF and IF
+ * flags are set in the just-pushed eflags, and may need to be cleared.
+ *
+ * 2) If the single-stepped instruction was a call, the return address
+ * that is atop the stack is the address following the copied instruction.
+ * We need to make it the address following the original instruction.
+ *
+ * This function also checks instruction size for preparing direct execution.
+ */
+static void resume_execution(struct kp_core *p,
+                            struct pt_regs *regs,
+                            struct kp_core_ctlblk *kcb)
+{
+       unsigned long *tos;
+       unsigned long copy_eip = (unsigned long) p->ainsn.insn;
+       unsigned long orig_eip = (unsigned long) p->addr;
+       kprobe_opcode_t insns[2];
+
+       regs->EREG(flags) &= ~TF_MASK;
+
+       tos = (unsigned long *)swap_kernel_sp(regs);
+       insns[0] = p->ainsn.insn[0];
+       insns[1] = p->ainsn.insn[1];
+
+       switch (insns[0]) {
+       case 0x9c: /* pushfl */
+               *tos &= ~(TF_MASK | IF_MASK);
+               *tos |= kcb->kp_core_old_eflags;
+               break;
+       case 0xc2: /* iret/ret/lret */
+       case 0xc3:
+       case 0xca:
+       case 0xcb:
+       case 0xcf:
+       case 0xea: /* jmp absolute -- eip is correct */
+               /* eip is already adjusted, no more changes required */
+               p->ainsn.boostable = 1;
+               goto no_change;
+       case 0xe8: /* call relative - Fix return addr */
+               *tos = orig_eip + (*tos - copy_eip);
+               break;
+       case 0x9a: /* call absolute -- same as call absolute, indirect */
+               *tos = orig_eip + (*tos - copy_eip);
+               goto no_change;
+       case 0xff:
+               if ((insns[1] & 0x30) == 0x10) {
+                       /*
+                        * call absolute, indirect
+                        * Fix return addr; eip is correct.
+                        * But this is not boostable
+                        */
+                       *tos = orig_eip + (*tos - copy_eip);
+                       goto no_change;
+               } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
+                                                          * indirect */
+                        ((insns[1] & 0x31) == 0x21)) {
+                       /* jmp far, absolute indirect */
+                       /* eip is correct. And this is boostable */
+                       p->ainsn.boostable = 1;
+                       goto no_change;
+               }
+       default:
+               break;
+       }
+
+       if (p->ainsn.boostable == 0) {
+               if ((regs->EREG(ip) > copy_eip) &&
+                   (regs->EREG(ip) - copy_eip) + 5 < MAX_INSN_SIZE) {
+                       /*
+                        * These instructions can be executed directly if it
+                        * jumps back to correct address.
+                        */
+                       set_jmp_op((void *)regs->EREG(ip),
+                                  (void *)orig_eip +
+                                  (regs->EREG(ip) - copy_eip));
+                       p->ainsn.boostable = 1;
+               } else {
+                       p->ainsn.boostable = -1;
+               }
+       }
+
+       regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
+
+no_change:
+       return;
+}
+
+/*
+ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
+ * remain disabled thoroughout this function.
+ */
+static int post_kprobe_handler(struct pt_regs *regs)
+{
+       struct kctx *ctx = current_kctx;
+       struct kp_core *cur = kp_core_running();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       if (!cur)
+               return 0;
+
+       resume_execution(cur, regs, kcb);
+       regs->flags |= kcb->kp_core_saved_eflags;
+#ifndef CONFIG_X86
+       trace_hardirqs_fixup_flags(regs->EREG(flags));
+#endif /* CONFIG_X86 */
+       /* Restore back the original saved kprobes variables and continue. */
+       if (kcb->kp_core_status == KPROBE_REENTER) {
+               restore_previous_kp_core(kcb);
+               goto out;
+       }
+       kp_core_running_set(NULL);
+
+out:
+       if (!able2resched(ctx))
+               swap_preempt_enable_no_resched();
+
+       switch_to_bits_reset(ctx, SWITCH_TO_KP);
+       kp_core_put(cur);
+
+       /*
+        * if somebody else is singlestepping across a probe point, eflags
+        * will have TF set, in which case, continue the remaining processing
+        * of do_debug, as if this is not a probe hit.
+        */
+       if (regs->EREG(flags) & TF_MASK)
+               return 0;
+
+       return 1;
+}
+
+static int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       struct kp_core *cur = kp_core_running();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       switch (kcb->kp_core_status) {
+       case KPROBE_HIT_SS:
+       case KPROBE_REENTER:
+               /*
+                * We are here because the instruction being single
+                * stepped caused a page fault. We reset the current
+                * kprobe and the eip points back to the probe address
+                * and allow the page fault handler to continue as a
+                * normal page fault.
+                */
+               regs->ip = cur->addr;
+               regs->flags |= kcb->kp_core_old_eflags;
+               if (kcb->kp_core_status == KPROBE_REENTER)
+                       restore_previous_kp_core(kcb);
+               else
+                       kp_core_running_set(NULL);
+               break;
+       case KPROBE_HIT_ACTIVE:
+       case KPROBE_HIT_SSDONE:
+               /*
+                * In case the user-specified fault handler returned
+                * zero, try to fix up.
+                */
+               if (swap_fixup_exception(regs))
+                       return 1;
+
+               /*
+                * fixup_exception() could not handle it,
+                * Let do_page_fault() fix it.
+                */
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int kprobe_exceptions_notify(struct notifier_block *self,
+                                   unsigned long val, void *data)
+{
+       struct die_args *args = (struct die_args *) data;
+       int ret = NOTIFY_DONE;
+
+       DBPRINTF("val = %ld, data = 0x%X", val, (unsigned int) data);
+
+       if (args->regs == NULL || swap_user_mode(args->regs))
+               return ret;
+
+       DBPRINTF("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP);
+       switch (val) {
+#ifdef CONFIG_KPROBES
+       case DIE_INT3:
+#else
+       case DIE_TRAP:
+#endif
+               DBPRINTF("before kprobe_handler ret=%d %p",
+                        ret, args->regs);
+               if (kprobe_handler (args->regs))
+                       ret = NOTIFY_STOP;
+               DBPRINTF("after kprobe_handler ret=%d %p",
+                        ret, args->regs);
+               break;
+       case DIE_DEBUG:
+               if (post_kprobe_handler(args->regs))
+                       ret = NOTIFY_STOP;
+               break;
+       case DIE_GPF:
+               if (kp_core_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       ret = NOTIFY_STOP;
+               break;
+       default:
+               break;
+       }
+       DBPRINTF("ret=%d", ret);
+       /* if(ret == NOTIFY_STOP) */
+       /*      handled_exceptions++; */
+
+       return ret;
+}
+
+static struct notifier_block kprobe_exceptions_nb = {
+       .notifier_call = kprobe_exceptions_notify,
+       .priority = INT_MAX
+};
+
+/**
+ * @brief Arms kp_core.
+ *
+ * @param core Pointer to target kp_core.
+ * @return Void.
+ */
+void arch_kp_core_arm(struct kp_core *p)
+{
+       swap_text_poke((void *)p->addr,
+                      ((unsigned char[]){BREAKPOINT_INSTRUCTION}), 1);
+}
+
+/**
+ * @brief Disarms kp_core.
+ *
+ * @param core Pointer to target kp_core.
+ * @return Void.
+ */
+void arch_kp_core_disarm(struct kp_core *p)
+{
+       swap_text_poke((void *)p->addr, &p->opcode, 1);
+}
+
+/**
+ * @brief Prepares kretprobes, saves ret address, makes function return to
+ * trampoline.
+ *
+ * @param ri Pointer to kretprobe_instance.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       unsigned long *ptr_ret_addr = (unsigned long *)swap_kernel_sp(regs);
+
+       /* for __switch_to probe */
+       if ((unsigned long)ri->rp->kp.addr == sched_addr) {
+               struct task_struct *next = (struct task_struct *)swap_get_karg(regs, 1);
+               ri->sp = NULL;
+               ri->task = next;
+               switch_to_bits_set(kctx_by_task(next), SWITCH_TO_RP);
+       } else {
+               ri->sp = ptr_ret_addr;
+       }
+
+       /* Save the return address */
+       ri->ret_addr = (unsigned long *)*ptr_ret_addr;
+
+       /* Replace the return addr with trampoline addr */
+       *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline;
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                                   jumper                                   *
+ ******************************************************************************
+ */
+struct cb_data {
+       unsigned long ret_addr;
+       unsigned long bx;
+
+       jumper_cb_t cb;
+       char data[0];
+};
+
+static unsigned long __used get_bx(struct cb_data *data)
+{
+       return data->bx;
+}
+
+static unsigned long __used jump_handler(struct cb_data *data)
+{
+       unsigned long ret_addr = data->ret_addr;
+
+       /* call callback */
+       data->cb(data->data);
+
+       /* FIXME: potential memory leak, when process kill */
+       kfree(data);
+
+       return ret_addr;
+}
+
+void jump_trampoline(void);
+__asm(
+       "jump_trampoline:\n"
+       "pushf\n"
+       SWAP_SAVE_REGS_STRING
+       "movl   %ebx, %eax\n"   /* data --> ax */
+       "call   get_bx\n"
+       "movl   %eax, (%esp)\n" /* restore bx */
+       "movl   %ebx, %eax\n"   /* data --> ax */
+       "call   jump_handler\n"
+       /* move flags to cs */
+       "movl 56(%esp), %edx\n"
+       "movl %edx, 52(%esp)\n"
+       /* replace saved flags with true return address. */
+       "movl %eax, 56(%esp)\n"
+       SWAP_RESTORE_REGS_STRING
+       "popf\n"
+       "ret\n"
+);
+
+unsigned long get_jump_addr(void)
+{
+       return (unsigned long)&jump_trampoline;
+}
+EXPORT_SYMBOL_GPL(get_jump_addr);
+
+int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
+               jumper_cb_t cb, void *data, size_t size)
+{
+       struct cb_data *cb_data;
+
+       cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
+       if (cb_data == NULL)
+               return -ENOMEM;
+
+       /* save data */
+       if (size)
+               memcpy(cb_data->data, data, size);
+
+       /* save info for restore */
+       cb_data->ret_addr = ret_addr;
+       cb_data->cb = cb;
+       cb_data->bx = regs->bx;
+
+       /* save cb_data to bx */
+       regs->bx = (long)cb_data;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(set_jump_cb);
+
+
+
+
+
+/**
+ * @brief Initializes x86 module deps.
+ *
+ * @return 0 on success, negative error code on error.
+ */
+int arch_init_module_deps()
+{
+       const char *sym;
+
+       sym = "fixup_exception";
+       swap_fixup_exception = (void *)swap_ksyms(sym);
+       if (swap_fixup_exception == NULL)
+               goto not_found;
+
+       sym = "text_poke";
+       swap_text_poke = (void *)swap_ksyms(sym);
+       if (swap_text_poke == NULL)
+               goto not_found;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+       sym = "show_registers";
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */
+       sym = "show_regs";
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */
+       swap_show_registers = (void *)swap_ksyms(sym);
+       if (swap_show_registers == NULL)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol %s(...) not found\n", sym);
+       return -ESRCH;
+}
+
+/**
+ * @brief Initializes kprobes module for ARM arch.
+ *
+ * @return 0 on success, error code on error.
+ */
+int swap_arch_init_kprobes(void)
+{
+       int ret;
+
+       ret = swap_td_raw_reg(&kp_tdraw, sizeof(struct regs_td));
+       if (ret)
+               return ret;
+
+       ret = register_die_notifier(&kprobe_exceptions_nb);
+       if (ret)
+               swap_td_raw_unreg(&kp_tdraw);
+
+       return ret;
+}
+
+/**
+ * @brief Uninitializes kprobe module.
+ *
+ * @return Void.
+ */
+void swap_arch_exit_kprobes(void)
+{
+       unregister_die_notifier(&kprobe_exceptions_nb);
+       swap_td_raw_unreg(&kp_tdraw);
+}
diff --git a/modules/kprobe/arch/x86/swap-asm/swap_kprobes.h b/modules/kprobe/arch/x86/swap-asm/swap_kprobes.h
new file mode 100644 (file)
index 0000000..7aed0bb
--- /dev/null
@@ -0,0 +1,259 @@
+/**
+ * @file kprobe/arch/asm-x86/swap_kprobes.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ *
+ * @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) IBM Corporation, 2002, 2004
+ * Copyright (C) Samsung Electronics, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Arch-dependent kprobes interface for x86 arch.
+ */
+
+#ifndef _SWAP_ASM_X86_KPROBES_H
+#define _SWAP_ASM_X86_KPROBES_H
+
+
+#include <linux/version.h>
+#include <kprobe/swap_kprobes_deps.h>
+
+/**
+ * @brief Opcode type.
+ */
+typedef u8 kprobe_opcode_t;
+
+#define BREAKPOINT_INSTRUCTION          0xcc
+#define RELATIVEJUMP_INSTRUCTION        0xe9
+
+#define BP_INSN_SIZE                    1
+#define MAX_INSN_SIZE                   16
+#define MAX_STACK_SIZE                  64
+
+#define MIN_STACK_SIZE(ADDR)   (((MAX_STACK_SIZE) <                      \
+                       (((unsigned long)current_thread_info())  \
+                        + THREAD_SIZE - (ADDR)))                 \
+               ? (MAX_STACK_SIZE)                        \
+               : (((unsigned long)current_thread_info()) \
+                       + THREAD_SIZE - (ADDR)))
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+
+#define EREG(rg)                e##rg
+#define XREG(rg)                x##rg
+#define ORIG_EAX_REG            orig_eax
+
+#else
+
+#define EREG(rg)                rg
+#define XREG(rg)                rg
+#define ORIG_EAX_REG            orig_ax
+
+#endif /*  LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+#define TF_MASK                         X86_EFLAGS_TF
+#define IF_MASK                                X86_EFLAGS_IF
+#endif
+#define UPROBES_TRAMP_LEN               (MAX_INSN_SIZE+sizeof(kprobe_opcode_t))
+#define UPROBES_TRAMP_INSN_IDX         0
+#define UPROBES_TRAMP_RET_BREAK_IDX     MAX_INSN_SIZE
+#define KPROBES_TRAMP_LEN              MAX_INSN_SIZE
+#define KPROBES_TRAMP_INSN_IDX          0
+
+static inline int swap_user_mode(struct pt_regs *regs)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+       return user_mode(regs);
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
+       return user_mode_vm(regs);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+#define swap_in_interrupt()    (in_interrupt() & ~HARDIRQ_OFFSET)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
+
+static inline unsigned long arch_get_task_pc(struct task_struct *p)
+{
+       /* FIXME: Not implemented yet */
+       return 0;
+}
+
+static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
+{
+       /* FIXME: Not implemented yet */
+}
+
+static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
+{
+       return NULL; /* FIXME currently not implemented for x86 */
+}
+
+static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
+{
+       return regs->EREG(sp);
+}
+
+static inline void swap_set_stack_ptr(struct pt_regs *regs, unsigned long sp)
+{
+       regs->EREG(sp) = sp;
+}
+
+static inline unsigned long swap_get_kpc(struct pt_regs *regs)
+{
+       return regs->ip;
+}
+
+static inline void swap_set_kpc(struct pt_regs *regs, unsigned long val)
+{
+       regs->ip = val;
+}
+
+static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
+{
+       unsigned long arg = 0;
+       read_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
+                       &arg, sizeof(arg));
+       return arg;
+}
+
+static inline void swap_set_arg(struct pt_regs *regs, int num,
+                               unsigned long val)
+{
+       write_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
+                       &val, sizeof(val));
+}
+
+/**
+ * @struct prev_kp_core
+ * @brief Stores previous kp_core.
+ * @var prev_kp_core::kp
+ * Pointer to kp_core struct.
+ * @var prev_kp_core::status
+ * kp_core status.
+ */
+struct prev_kp_core {
+       struct kp_core *p;
+       unsigned long status;
+};
+
+/**
+ * @struct kp_core_ctlblk
+ * @brief Per-cpu kp_core control block.
+ * @var kp_core_ctlblk::kp_core_status
+ * kp_core status.
+ * @var kp_core_ctlblk::prev_kp_core
+ * Previous kp_core.
+ */
+struct kp_core_ctlblk {
+       unsigned long kp_core_status;
+       struct prev_kp_core prev_kp_core;
+       struct pt_regs jprobe_saved_regs;
+       unsigned long kp_core_old_eflags;
+       unsigned long kp_core_saved_eflags;
+       unsigned long *jprobe_saved_esp;
+       kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
+};
+
+
+/**
+ * @struct swap_arch_specific_insn
+ * @brief Architecture specific copy of original instruction.
+ * @var swap_arch_specific_insn::insn
+ * Copy of the original instruction.
+ * @var swap_arch_specific_insn::boostable
+ * If this flag is not 0, this kp_core can be boost when its
+ * post_handler and break_handler is not set.
+ */
+struct swap_arch_specific_insn {
+       kprobe_opcode_t *insn;
+       int boostable;
+};
+
+/**
+ * @brief Entry point.
+ */
+typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
+                                         unsigned long, unsigned long,
+                                         unsigned long, unsigned long);
+
+int arch_init_module_deps(void);
+
+struct kprobe;
+struct kp_core;
+struct slot_manager;
+struct kretprobe_instance;
+
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
+void arch_kp_core_arm(struct kp_core *core);
+void arch_kp_core_disarm(struct kp_core *core);
+int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
+void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                struct pt_regs *regs);
+void swap_kretprobe_trampoline(void);
+
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
+int swap_can_boost(kprobe_opcode_t *opcodes);
+static inline int arch_check_insn(struct swap_arch_specific_insn *ainsn)
+{
+       return 0;
+}
+
+unsigned long swap_kernel_sp(struct pt_regs *regs);
+
+static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
+{
+       switch (n) {
+       case 0:
+               return regs->ax;
+       case 1:
+               return regs->dx;
+       case 2:
+               return regs->cx;
+       }
+
+       /*
+        * 2 = 3 - 1
+        * 3 - arguments from registers
+        * 1 - return address saved on top of the stack
+        */
+       return *((unsigned long *)swap_kernel_sp(regs) + n - 2);
+}
+
+static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
+{
+       /* 1 - return address saved on top of the stack */
+       return *((unsigned long *)kernel_stack_pointer(regs) + n + 1);
+}
+
+/* jumper */
+typedef unsigned long (*jumper_cb_t)(void *);
+
+unsigned long get_jump_addr(void);
+int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
+               jumper_cb_t cb, void *data, size_t size);
+
+int swap_arch_init_kprobes(void);
+void swap_arch_exit_kprobes(void);
+
+#endif /* _SWAP_ASM_X86_KPROBES_H */
diff --git a/modules/kprobe/swap_kdebug.h b/modules/kprobe/swap_kdebug.h
new file mode 100644 (file)
index 0000000..4c3be6e
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * @file kprobe/swap_kdebug.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Header for debug purposes.
+ */
+
+
+#ifndef _SWAP_KPROBE_DEBUG_H
+#define _SWAP_KPROBE_DEBUG_H
+
+/* #define _DEBUG */
+
+#ifdef _DEBUG
+#define DBPRINTF(format, args...) do { \
+               if (1) { \
+                       char *f = __FILE__; \
+                       char *n = strrchr(f, '/'); \
+                       printk(KERN_INFO "%s : %u : %s : " format "\n" , \
+                              (n) ? n+1 : f, __LINE__, __func__, ##args); \
+               } \
+       } while (0)
+#else
+#define DBPRINTF(format, args...)
+#endif
+
+
+#endif /* _SWAP_KPROBE_DEBUG_H */
diff --git a/modules/kprobe/swap_kprobes.c b/modules/kprobe/swap_kprobes.c
new file mode 100644 (file)
index 0000000..3981ffe
--- /dev/null
@@ -0,0 +1,1300 @@
+/**
+ * kprobe/swap_kprobes.c
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM and MIPS
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ *
+ * @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) IBM Corporation, 2002, 2004
+ * Copyright (C) Samsung Electronics, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP kprobe implementation. Dynamic kernel functions instrumentation.
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+#include <linux/config.h>
+#endif
+
+#include <linux/hash.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/stop_machine.h>
+#include <linux/delay.h>
+#include <ksyms/ksyms.h>
+#include <master/swap_initializer.h>
+#include <swap-asm/swap_kprobes.h>
+#include "swap_ktd.h"
+#include "swap_slots.h"
+#include "swap_ktd.h"
+#include "swap_td_raw.h"
+#include "swap_kdebug.h"
+#include "swap_kprobes.h"
+#include "swap_kprobes_deps.h"
+
+
+#define KRETPROBE_STACK_DEPTH 64
+
+
+/**
+ * @var sched_addr
+ * @brief Scheduler address.
+ */
+unsigned long sched_addr;
+static unsigned long exit_addr;
+static unsigned long do_group_exit_addr;
+static unsigned long sys_exit_group_addr;
+static unsigned long sys_exit_addr;
+
+/**
+ * @var sm
+ * @brief Current slot manager. Slots are the places where trampolines are
+ * located.
+ */
+struct slot_manager sm;
+
+static DEFINE_SPINLOCK(kretprobe_lock);        /* Protects kretprobe_inst_table */
+
+static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
+static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
+
+/**
+ * @var kprobe_count
+ * @brief Count of kprobes.
+ */
+atomic_t kprobe_count;
+EXPORT_SYMBOL_GPL(kprobe_count);
+
+
+static void *(*__module_alloc)(unsigned long size);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+static void (*__module_free)(void *module_region);
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+static void (*__module_free)(struct module *mod, void *module_region);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+
+static void *wrapper_module_alloc(unsigned long size)
+{
+       return __module_alloc(size);
+}
+
+static void wrapper_module_free(void *module_region)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+       __module_free(module_region);
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+       __module_free(NULL, module_region);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+}
+
+static void *sm_alloc(struct slot_manager *sm)
+{
+       return wrapper_module_alloc(PAGE_SIZE);
+}
+
+static void sm_free(struct slot_manager *sm, void *ptr)
+{
+       wrapper_module_free(ptr);
+}
+
+static void init_sm(void)
+{
+       sm.slot_size = KPROBES_TRAMP_LEN;
+       sm.alloc = sm_alloc;
+       sm.free = sm_free;
+       INIT_HLIST_HEAD(&sm.page_list);
+}
+
+static void exit_sm(void)
+{
+       /* FIXME: free */
+}
+
+static struct hlist_head *kpt_head_by_addr(unsigned long addr)
+{
+       return &kprobe_table[hash_ptr((void *)addr, KPROBE_HASH_BITS)];
+}
+
+static void kretprobe_assert(struct kretprobe_instance *ri,
+                            unsigned long orig_ret_address,
+                            unsigned long trampoline_address)
+{
+       if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
+               struct task_struct *task;
+               if (ri == NULL)
+                       panic("kretprobe BUG!: ri = NULL\n");
+
+               task = ri->task;
+
+               if (task == NULL)
+                       panic("kretprobe BUG!: task = NULL\n");
+
+               if (ri->rp == NULL)
+                       panic("kretprobe BUG!: ri->rp = NULL\n");
+
+               panic("kretprobe BUG!: "
+                     "Processing kretprobe %p @ %08lx (%d/%d - %s)\n",
+                     ri->rp, ri->rp->kp.addr, ri->task->tgid,
+                     ri->task->pid, ri->task->comm);
+       }
+}
+
+struct kpc_data {
+       struct kp_core *running;
+       struct kp_core_ctlblk ctlblk;
+};
+
+struct kctx {
+       struct kpc_data kpc;
+       unsigned long st_flags;
+};
+
+static void ktd_cur_init(struct task_struct *task, void *data)
+{
+       struct kctx *ctx = (struct kctx *)data;
+
+       memset(ctx, 0, sizeof(*ctx));
+}
+
+static void ktd_cur_exit(struct task_struct *task, void *data)
+{
+       struct kctx *ctx = (struct kctx *)data;
+
+       WARN(ctx->kpc.running, "running=%p\n", ctx->kpc.running);
+}
+
+struct ktask_data ktd_cur = {
+       .init = ktd_cur_init,
+       .exit = ktd_cur_exit,
+       .size = sizeof(struct kctx),
+};
+
+struct kctx *kctx_by_task(struct task_struct *task)
+{
+       return (struct kctx *)swap_ktd(&ktd_cur, task);
+}
+
+void switch_to_bits_set(struct kctx *ctx, unsigned long mask)
+{
+       ctx->st_flags |= mask;
+}
+
+void switch_to_bits_reset(struct kctx *ctx, unsigned long mask)
+{
+       ctx->st_flags &= ~mask;
+}
+
+unsigned long switch_to_bits_get(struct kctx *ctx, unsigned long mask)
+{
+       return ctx->st_flags & mask;
+}
+
+static DEFINE_PER_CPU(struct kpc_data, per_cpu_kpc_data_i);
+static DEFINE_PER_CPU(struct kpc_data, per_cpu_kpc_data_st);
+
+static struct kpc_data *kp_core_data(void)
+{
+       struct kctx *ctx = current_kctx;
+
+       if (swap_in_interrupt())
+               return &__get_cpu_var(per_cpu_kpc_data_i);
+       else if (switch_to_bits_get(ctx, SWITCH_TO_ALL))
+               return &__get_cpu_var(per_cpu_kpc_data_st);
+
+       return &ctx->kpc;
+}
+
+static int kprobe_cur_reg(void)
+{
+       return swap_ktd_reg(&ktd_cur);
+}
+
+static void kprobe_cur_unreg(void)
+{
+       swap_ktd_unreg(&ktd_cur);
+}
+
+struct kp_core *kp_core_running(void)
+{
+       return kp_core_data()->running;
+}
+
+void kp_core_running_set(struct kp_core *p)
+{
+       kp_core_data()->running = p;
+}
+
+/**
+ * @brief Gets kp_core_ctlblk for the current CPU.
+ *
+ * @return Current CPU struct kp_core_ctlblk.
+ */
+struct kp_core_ctlblk *kp_core_ctlblk(void)
+{
+       return &kp_core_data()->ctlblk;
+}
+
+/*
+ * This routine is called either:
+ *     - under the kprobe_mutex - during kprobe_[un]register()
+ *                             OR
+ *     - with preemption disabled - from arch/xxx/kernel/kprobes.c
+ */
+
+/**
+ * @brief Gets kp_core.
+ *
+ * @param addr Probe address.
+ * @return kprobe_core for addr.
+ */
+struct kp_core *kp_core_by_addr(unsigned long addr)
+{
+       struct hlist_head *head;
+       struct kp_core *core;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       head = kpt_head_by_addr(addr);
+       swap_hlist_for_each_entry_rcu(core, node, head, hlist) {
+               if (core->addr == addr)
+                       return core;
+       }
+
+       return NULL;
+}
+
+
+static int alloc_nodes_kretprobe(struct kretprobe *rp);
+
+/* Called with kretprobe_lock held */
+static struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
+               return ri;
+       }
+
+       if (!alloc_nodes_kretprobe(rp)) {
+               swap_hlist_for_each_entry(ri, node, &rp->free_instances,
+                                         uflist) {
+                       return ri;
+               }
+       }
+
+       return NULL;
+}
+
+/* Called with kretprobe_lock held */
+static struct kretprobe_instance *
+get_free_rp_inst_no_alloc(struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
+               return ri;
+       }
+
+       return NULL;
+}
+
+/* Called with kretprobe_lock held */
+static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
+               return ri;
+       }
+
+       return NULL;
+}
+
+/* Called with kretprobe_lock held */
+static void add_rp_inst(struct kretprobe_instance *ri)
+{
+       /*
+        * Remove rp inst off the free list -
+        * Add it back when probed function returns
+        */
+       hlist_del(&ri->uflist);
+
+       /* Add rp inst onto table */
+       INIT_HLIST_NODE(&ri->hlist);
+
+       hlist_add_head(&ri->hlist,
+                      &kretprobe_inst_table[hash_ptr(ri->task,
+                                                     KPROBE_HASH_BITS)]);
+
+       /* Also add this rp inst to the used list. */
+       INIT_HLIST_NODE(&ri->uflist);
+       hlist_add_head(&ri->uflist, &ri->rp->used_instances);
+}
+
+/* Called with kretprobe_lock held */
+static void recycle_rp_inst(struct kretprobe_instance *ri)
+{
+       if (ri->rp) {
+               hlist_del(&ri->hlist);
+               /* remove rp inst off the used list */
+               hlist_del(&ri->uflist);
+               /* put rp inst back onto the free list */
+               INIT_HLIST_NODE(&ri->uflist);
+               hlist_add_head(&ri->uflist, &ri->rp->free_instances);
+       }
+}
+
+static struct hlist_head *kretprobe_inst_table_head(void *hash_key)
+{
+       return &kretprobe_inst_table[hash_ptr(hash_key, KPROBE_HASH_BITS)];
+}
+
+static void free_rp_inst(struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri;
+       while ((ri = get_free_rp_inst_no_alloc(rp)) != NULL) {
+               hlist_del(&ri->uflist);
+               kfree(ri);
+       }
+}
+
+static void kp_core_remove(struct kp_core *core)
+{
+       /* TODO: check boostable for x86 and MIPS */
+       swap_slot_free(&sm, core->ainsn.insn);
+}
+
+static void kp_core_wait(struct kp_core *p)
+{
+       int ms = 1;
+
+       while (atomic_read(&p->usage)) {
+               msleep(ms);
+               ms += ms < 7 ? 1 : 0;
+       }
+}
+
+static struct kp_core *kp_core_create(unsigned long addr)
+{
+       struct kp_core *core;
+
+       core = kzalloc(sizeof(*core), GFP_KERNEL);
+       if (core) {
+               INIT_HLIST_NODE(&core->hlist);
+               core->addr = addr;
+               atomic_set(&core->usage, 0);
+               rwlock_init(&core->handlers.lock);
+       }
+
+       return core;
+}
+
+static void kp_core_free(struct kp_core *core)
+{
+       WARN_ON(atomic_read(&core->usage));
+       kfree(core);
+}
+
+static int pre_handler_one(struct kp_core *core, struct pt_regs *regs)
+{
+       int ret = 0;
+       struct kprobe *p = core->handlers.kps[0];
+
+       if (p && p->pre_handler)
+               ret = p->pre_handler(p, regs);
+
+       return ret;
+}
+
+static int pre_handler_multi(struct kp_core *core, struct pt_regs *regs)
+{
+       int i, ret = 0;
+
+       /* TODO: add sync use kprobe */
+       for (i = 0; i < ARRAY_SIZE(core->handlers.kps); ++i) {
+               struct kprobe *p = core->handlers.kps[i];
+
+               if (p && p->pre_handler) {
+                       ret = p->pre_handler(p, regs);
+                       if (ret)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+static int kp_core_add_kprobe(struct kp_core *core, struct kprobe *p)
+{
+       int i, ret = 0;
+       unsigned long flags;
+       struct kp_handlers *h = &core->handlers;
+
+       write_lock_irqsave(&h->lock, flags);
+       if (h->pre == NULL) {
+               h->pre = pre_handler_one;
+       } else if (h->pre == pre_handler_one) {
+               h->pre = pre_handler_multi;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(core->handlers.kps); ++i) {
+               if (core->handlers.kps[i])
+                       continue;
+
+               core->handlers.kps[i] = p;
+               goto unlock;
+       }
+
+       pr_err("all kps slots is busy\n");
+       ret = -EBUSY;
+unlock:
+       write_unlock_irqrestore(&h->lock, flags);
+       return ret;
+}
+
+static void kp_core_del_kprobe(struct kp_core *core, struct kprobe *p)
+{
+       int i, cnt = 0;
+       unsigned long flags;
+       struct kp_handlers *h = &core->handlers;
+
+       write_lock_irqsave(&h->lock, flags);
+       for (i = 0; i < ARRAY_SIZE(h->kps); ++i) {
+               if (h->kps[i] == p)
+                       h->kps[i] = NULL;
+
+               if (h->kps[i] == NULL)
+                       ++cnt;
+       }
+       write_unlock_irqrestore(&h->lock, flags);
+
+       if (cnt == ARRAY_SIZE(h->kps)) {
+               arch_kp_core_disarm(core);
+               synchronize_sched();
+
+               hlist_del_rcu(&core->hlist);
+               synchronize_rcu();
+
+               kp_core_wait(core);
+               kp_core_remove(core);
+               kp_core_free(core);
+       }
+}
+
+static DEFINE_MUTEX(kp_mtx);
+/**
+ * @brief Registers kprobe.
+ *
+ * @param p Pointer to the target kprobe.
+ * @return 0 on success, error code on error.
+ */
+int swap_register_kprobe(struct kprobe *p)
+{
+       struct kp_core *core;
+       unsigned long addr;
+       int ret = 0;
+       /*
+        * If we have a symbol_name argument look it up,
+        * and add it to the address.  That way the addr
+        * field can either be global or relative to a symbol.
+        */
+       if (p->symbol_name) {
+               if (p->addr)
+                       return -EINVAL;
+               p->addr = swap_ksyms(p->symbol_name);
+       }
+
+       if (!p->addr)
+               return -EINVAL;
+
+       addr = p->addr + p->offset;
+
+       mutex_lock(&kp_mtx);
+       core = kp_core_by_addr(addr);
+       if (core == NULL) {
+               core = kp_core_create(addr);
+               if (core == NULL) {
+                       pr_err("Out of memory\n");
+                       ret = -ENOMEM;
+                       goto unlock;
+               }
+
+               ret = arch_kp_core_prepare(core, &sm);
+               if (ret) {
+                       kp_core_free(core);
+                       goto unlock;
+               }
+
+               ret = kp_core_add_kprobe(core, p);
+               if (ret) {
+                       kp_core_free(core);
+                       goto unlock;
+               }
+
+               hlist_add_head_rcu(&core->hlist, kpt_head_by_addr(core->addr));
+               arch_kp_core_arm(core);
+       } else {
+               ret = kp_core_add_kprobe(core, p);
+       }
+
+unlock:
+       mutex_unlock(&kp_mtx);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_register_kprobe);
+
+/**
+ * @brief Unregistes kprobe.
+ *
+ * @param kp Pointer to the target kprobe.
+ * @return Void.
+ */
+void swap_unregister_kprobe(struct kprobe *p)
+{
+       unsigned long addr = p->addr + p->offset;
+       struct kp_core *core;
+
+       mutex_lock(&kp_mtx);
+       core = kp_core_by_addr(addr);
+       BUG_ON(core == NULL);
+
+       kp_core_del_kprobe(core, p);
+       mutex_unlock(&kp_mtx);
+
+       /* Set 0 addr for reusability if symbol_name is used */
+       if (p->symbol_name)
+               p->addr = 0;
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kprobe);
+
+/**
+ * @brief Registers jprobe.
+ *
+ * @param jp Pointer to the target jprobe.
+ * @return swap_register_kprobe result.
+ */
+int swap_register_jprobe(struct jprobe *jp)
+{
+       /* Todo: Verify probepoint is a function entry point */
+       jp->kp.pre_handler = swap_setjmp_pre_handler;
+
+       return swap_register_kprobe(&jp->kp);
+}
+EXPORT_SYMBOL_GPL(swap_register_jprobe);
+
+/**
+ * @brief Unregisters jprobe.
+ *
+ * @param jp Pointer to the target jprobe.
+ * @return Void.
+ */
+void swap_unregister_jprobe(struct jprobe *jp)
+{
+       swap_unregister_kprobe(&jp->kp);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_jprobe);
+
+/*
+ * This kprobe pre_handler is registered with every kretprobe. When probe
+ * hits it will set up the return probe.
+ */
+static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
+{
+       struct kretprobe *rp = container_of(p, struct kretprobe, kp);
+       struct kretprobe_instance *ri;
+       unsigned long flags = 0;
+
+       /* TODO: consider to only swap the RA
+        * after the last pre_handler fired */
+       spin_lock_irqsave(&kretprobe_lock, flags);
+
+       /* TODO: test - remove retprobe after func entry but before its exit */
+       ri = get_free_rp_inst(rp);
+       if (ri != NULL) {
+               int skip = 0;
+
+               ri->rp = rp;
+               ri->task = current;
+
+               if (rp->entry_handler)
+                       skip = rp->entry_handler(ri, regs);
+
+               if (skip) {
+                       add_rp_inst(ri);
+                       recycle_rp_inst(ri);
+               } else {
+                       swap_arch_prepare_kretprobe(ri, regs);
+                       add_rp_inst(ri);
+               }
+       } else {
+               ++rp->nmissed;
+       }
+
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+       return 0;
+}
+
+/**
+ * @brief Trampoline probe handler.
+ *
+ * @param p Pointer to the fired kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return orig_ret_address
+ */
+unsigned long swap_trampoline_handler(struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_head *head;
+       unsigned long flags, orig_ret_address = 0;
+       unsigned long trampoline_address;
+
+       struct kp_core_ctlblk *kcb;
+
+       struct hlist_node *tmp;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       trampoline_address = (unsigned long)&swap_kretprobe_trampoline;
+
+       kcb = kp_core_ctlblk();
+
+       spin_lock_irqsave(&kretprobe_lock, flags);
+
+       /*
+        * We are using different hash keys (current and mm) for finding kernel
+        * space and user space probes.  Kernel space probes can change mm field
+        * in task_struct.  User space probes can be shared between threads of
+        * one process so they have different current but same mm.
+        */
+       head = kretprobe_inst_table_head(current);
+
+#ifdef CONFIG_X86
+       regs->XREG(cs) = __KERNEL_CS | get_kernel_rpl();
+       regs->EREG(ip) = trampoline_address;
+       regs->ORIG_EAX_REG = 0xffffffff;
+#endif
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+               if (ri->rp && ri->rp->handler) {
+                       /*
+                        * Set fake current probe, we don't
+                        * want to go into recursion
+                        */
+                       kp_core_running_set((struct kp_core *)0xfffff);
+                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
+                       ri->rp->handler(ri, regs);
+                       kp_core_running_set(NULL);
+               }
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               recycle_rp_inst(ri);
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+       if (kcb->kp_core_status == KPROBE_REENTER)
+               restore_previous_kp_core(kcb);
+       else
+               kp_core_running_set(NULL);
+
+       switch_to_bits_reset(current_kctx, SWITCH_TO_RP);
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+       /*
+        * By returning a non-zero value, we are telling
+        * kprobe_handler() that we don't want the post_handler
+        * to run (and have re-enabled preemption)
+        */
+
+       return orig_ret_address;
+}
+
+#define SCHED_RP_NR 200
+#define COMMON_RP_NR 10
+
+static int alloc_nodes_kretprobe(struct kretprobe *rp)
+{
+       int alloc_nodes;
+       struct kretprobe_instance *inst;
+       int i;
+
+       DBPRINTF("Alloc aditional mem for retprobes");
+
+       if (rp->kp.addr == sched_addr) {
+               rp->maxactive += SCHED_RP_NR; /* max (100, 2 * NR_CPUS); */
+               alloc_nodes = SCHED_RP_NR;
+       } else {
+#if 1/* def CONFIG_PREEMPT */
+               rp->maxactive += max(COMMON_RP_NR, 2 * NR_CPUS);
+#else
+               rp->maxacpptive += NR_CPUS;
+#endif
+               alloc_nodes = COMMON_RP_NR;
+       }
+
+       for (i = 0; i < alloc_nodes; i++) {
+               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_ATOMIC);
+               if (inst == NULL) {
+                       free_rp_inst(rp);
+                       return -ENOMEM;
+               }
+               INIT_HLIST_NODE(&inst->uflist);
+               hlist_add_head(&inst->uflist, &rp->free_instances);
+       }
+
+       DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
+                 (unsigned long) (*(rp->kp.addr)),
+                 (unsigned long) (*(rp->kp.addr + 1)),
+                 (unsigned long) (*(rp->kp.addr + 2)));
+       return 0;
+}
+
+/**
+ * @brief Registers kretprobes.
+ *
+ * @param rp Pointer to the target kretprobe.
+ * @return 0 on success, error code on error.
+ */
+int swap_register_kretprobe(struct kretprobe *rp)
+{
+       int ret = 0;
+       struct kretprobe_instance *inst;
+       int i;
+       DBPRINTF("START");
+
+       rp->kp.pre_handler = pre_handler_kretprobe;
+
+       /* Pre-allocate memory for max kretprobe instances */
+       if (rp->kp.addr == exit_addr) {
+               rp->kp.pre_handler = NULL; /* not needed for do_exit */
+               rp->maxactive = 0;
+       } else if (rp->kp.addr == do_group_exit_addr) {
+               rp->kp.pre_handler = NULL;
+               rp->maxactive = 0;
+       } else if (rp->kp.addr == sys_exit_group_addr) {
+               rp->kp.pre_handler = NULL;
+               rp->maxactive = 0;
+       } else if (rp->kp.addr == sys_exit_addr) {
+               rp->kp.pre_handler = NULL;
+               rp->maxactive = 0;
+       } else if (rp->maxactive <= 0) {
+#if 1/* def CONFIG_PREEMPT */
+               rp->maxactive = max(COMMON_RP_NR, 2 * NR_CPUS);
+#else
+               rp->maxactive = NR_CPUS;
+#endif
+       }
+       INIT_HLIST_HEAD(&rp->used_instances);
+       INIT_HLIST_HEAD(&rp->free_instances);
+       for (i = 0; i < rp->maxactive; i++) {
+               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_KERNEL);
+               if (inst == NULL) {
+                       free_rp_inst(rp);
+                       return -ENOMEM;
+               }
+               INIT_HLIST_NODE(&inst->uflist);
+               hlist_add_head(&inst->uflist, &rp->free_instances);
+       }
+
+       DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
+                 (unsigned long) (*(rp->kp.addr)),
+                 (unsigned long) (*(rp->kp.addr + 1)),
+                 (unsigned long) (*(rp->kp.addr + 2)));
+       rp->nmissed = 0;
+       /* Establish function entry probe point */
+       ret = swap_register_kprobe(&rp->kp);
+       if (ret != 0)
+               free_rp_inst(rp);
+
+       DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
+                 (unsigned long) (*(rp->kp.addr)),
+                 (unsigned long) (*(rp->kp.addr + 1)),
+                 (unsigned long) (*(rp->kp.addr + 2)));
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_register_kretprobe);
+
+static int swap_disarm_krp_inst(struct kretprobe_instance *ri);
+
+static void swap_disarm_krp(struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
+               if (swap_disarm_krp_inst(ri) != 0) {
+                       printk(KERN_INFO "%s (%d/%d): cannot disarm "
+                              "krp instance (%08lx)\n",
+                              ri->task->comm, ri->task->tgid, ri->task->pid,
+                              rp->kp.addr);
+               }
+       }
+}
+
+
+struct unreg_krp_args {
+       struct kretprobe **rps;
+       size_t size;
+       int rp_disarm;
+};
+
+static int __swap_unregister_kretprobes_top(void *data)
+{
+       struct unreg_krp_args *args = data;
+       struct kretprobe **rps = args->rps;
+       size_t size = args->size;
+       int rp_disarm = args->rp_disarm;
+       unsigned long flags;
+       const size_t end = ((size_t) 0) - 1;
+
+       for (--size; size != end; --size) {
+               if (rp_disarm) {
+                       spin_lock_irqsave(&kretprobe_lock, flags);
+                       swap_disarm_krp(rps[size]);
+                       spin_unlock_irqrestore(&kretprobe_lock, flags);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Kretprobes unregister top. Unregisters kprobes.
+ *
+ * @param rps Pointer to the array of pointers to the target kretprobes.
+ * @param size Size of rps array.
+ * @param rp_disarm Disarm flag. If set kretprobe is disarmed.
+ * @return Void.
+ */
+void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size,
+                                  int rp_disarm)
+{
+       struct unreg_krp_args args = {
+               .rps = rps,
+               .size = size,
+               .rp_disarm = rp_disarm,
+       };
+       const size_t end = ((size_t)0) - 1;
+
+       for (--size; size != end; --size)
+               swap_unregister_kprobe(&rps[size]->kp);
+
+       if (rp_disarm) {
+               int ret;
+
+               ret = stop_machine(__swap_unregister_kretprobes_top,
+                                  &args, NULL);
+               if (ret)
+                       pr_err("%s failed (%d)\n", __func__, ret);
+       } else {
+               __swap_unregister_kretprobes_top(&args);
+       }
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_top);
+
+/**
+ * @brief swap_unregister_kretprobes_top wrapper for a single kretprobe.
+ *
+ * @param rp Pointer to the target kretprobe.
+ * @param rp_disarm Disarm flag.
+ * @return Void.
+ */
+void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm)
+{
+       swap_unregister_kretprobes_top(&rp, 1, rp_disarm);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_top);
+
+/**
+ * @brief Kretprobe unregister bottom. Here is kretprobe memory is released.
+ *
+ * @param rp Pointer to the target kretprobe.
+ * @return Void.
+ */
+void swap_unregister_kretprobe_bottom(struct kretprobe *rp)
+{
+       unsigned long flags;
+       struct kretprobe_instance *ri;
+
+       spin_lock_irqsave(&kretprobe_lock, flags);
+
+       while ((ri = get_used_rp_inst(rp)) != NULL)
+               recycle_rp_inst(ri);
+       free_rp_inst(rp);
+
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_bottom);
+
+/**
+ * @brief swap_unregister_kretprobe_bottom wrapper for several kretprobes.
+ *
+ * @param rps Pointer to the array of the target kretprobes pointers.
+ * @param size Size of rps array.
+ * @return Void.
+ */
+void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size)
+{
+       const size_t end = ((size_t) 0) - 1;
+
+       for (--size; size != end; --size)
+               swap_unregister_kretprobe_bottom(rps[size]);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_bottom);
+
+/**
+ * @brief Unregisters kretprobes.
+ *
+ * @param rpp Pointer to the array of the target kretprobes pointers.
+ * @param size Size of rpp array.
+ * @return Void.
+ */
+void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size)
+{
+       swap_unregister_kretprobes_top(rpp, size, 1);
+
+       if (!in_atomic())
+               synchronize_sched();
+
+       swap_unregister_kretprobes_bottom(rpp, size);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kretprobes);
+
+/**
+ * @brief swap_unregister_kretprobes wrapper for a single kretprobe.
+ *
+ * @param rp Pointer to the target kretprobe.
+ * @return Void.
+ */
+void swap_unregister_kretprobe(struct kretprobe *rp)
+{
+       swap_unregister_kretprobes(&rp, 1);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_kretprobe);
+
+static inline void rm_task_trampoline(struct task_struct *p,
+                                     struct kretprobe_instance *ri)
+{
+       arch_set_task_pc(p, (unsigned long)ri->ret_addr);
+}
+
+static int swap_disarm_krp_inst(struct kretprobe_instance *ri)
+{
+       unsigned long *tramp = (unsigned long *)&swap_kretprobe_trampoline;
+       unsigned long *sp = ri->sp;
+       unsigned long *found = NULL;
+       int retval = -ENOENT;
+
+       if (!sp) {
+               unsigned long pc = arch_get_task_pc(ri->task);
+
+               printk(KERN_INFO "---> [%d] %s (%d/%d): pc = %08lx, ra = %08lx, tramp= %08lx (%08lx)\n",
+                      task_cpu(ri->task),
+                      ri->task->comm, ri->task->tgid, ri->task->pid,
+                      pc, (long unsigned int)ri->ret_addr,
+                      (long unsigned int)tramp,
+                      (ri->rp ? ri->rp->kp.addr : 0));
+
+               /* __switch_to retprobe handling */
+               if (pc == (unsigned long)tramp) {
+                       rm_task_trampoline(ri->task, ri);
+                       return 0;
+               }
+
+               return -EINVAL;
+       }
+
+       while (sp > ri->sp - KRETPROBE_STACK_DEPTH) {
+               if (*sp == (unsigned long)tramp) {
+                       found = sp;
+                       break;
+               }
+               sp--;
+       }
+
+       if (found) {
+               printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
+                      "found at %08lx (%08lx /%+ld) - %08lx\n",
+                      task_cpu(ri->task),
+                      ri->task->comm, ri->task->tgid, ri->task->pid,
+                      (long unsigned int)tramp,
+                      (long unsigned int)found, (long unsigned int)ri->sp,
+                      (unsigned long)(found - ri->sp), ri->rp ? ri->rp->kp.addr : 0);
+               *found = (unsigned long)ri->ret_addr;
+               retval = 0;
+       } else {
+               printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
+                      "NOT found at sp = %08lx - %08lx\n",
+                      task_cpu(ri->task),
+                      ri->task->comm, ri->task->tgid, ri->task->pid,
+                      (long unsigned int)tramp,
+                      (long unsigned int)ri->sp,
+                      ri->rp ? ri->rp->kp.addr : 0);
+       }
+
+       return retval;
+}
+
+static void krp_inst_flush(struct task_struct *task)
+{
+       unsigned long flags;
+       struct kretprobe_instance *ri;
+       struct hlist_node *tmp;
+       struct hlist_head *head;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       spin_lock_irqsave(&kretprobe_lock, flags);
+       head = kretprobe_inst_table_head(task);
+       swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+               if (ri->task == task) {
+                       printk("task[%u %u %s]: flush krp_inst, ret_addr=%p\n",
+                               task->tgid, task->pid, task->comm,
+                               ri->ret_addr);
+                       recycle_rp_inst(ri);
+               }
+       }
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+}
+
+static void do_put_task_handler(struct task_struct *task)
+{
+       /* task has died */
+       krp_inst_flush(task);
+       swap_ktd_put_task(task);
+}
+
+#ifdef CONFIG_SWAP_HOOK_TASKDATA
+
+#include <swap/hook_taskdata.h>
+
+static struct hook_taskdata put_hook = {
+       .owner = THIS_MODULE,
+       .put_task = do_put_task_handler,
+};
+
+static int put_task_once(void)
+{
+       return 0;
+}
+
+static int put_task_init(void)
+{
+       return hook_taskdata_reg(&put_hook);
+}
+
+static void put_task_uninit(void)
+{
+       hook_taskdata_unreg(&put_hook);
+}
+
+#else /* CONFIG_SWAP_HOOK_TASKDATA */
+
+/* Handler is called the last because it is registered the first */
+static int put_task_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct task_struct *t = (struct task_struct *)swap_get_karg(regs, 0);
+
+       do_put_task_handler(t);
+
+       return 0;
+}
+
+static struct kprobe put_task_kp = {
+       .pre_handler = put_task_handler,
+};
+
+static int put_task_once(void)
+{
+       const char *sym = "__put_task_struct";
+
+       put_task_kp.addr = swap_ksyms(sym);
+       if (put_task_kp.addr == 0) {
+               pr_err("ERROR: symbol '%s' not found\n", sym);
+               return -ESRCH;
+       }
+
+       return 0;
+}
+
+static int put_task_init(void)
+{
+       return swap_register_kprobe(&put_task_kp);
+}
+
+static void put_task_uninit(void)
+{
+       swap_unregister_kprobe(&put_task_kp);
+}
+
+#endif /* CONFIG_SWAP_HOOK_TASKDATA */
+
+
+static int init_module_deps(void)
+{
+       int ret;
+
+       sched_addr = swap_ksyms("__switch_to");
+       exit_addr = swap_ksyms("do_exit");
+       sys_exit_group_addr = swap_ksyms("sys_exit_group");
+       do_group_exit_addr = swap_ksyms("do_group_exit");
+       sys_exit_addr = swap_ksyms("sys_exit");
+
+       if (sched_addr == 0 ||
+           exit_addr == 0 ||
+           sys_exit_group_addr == 0 ||
+           do_group_exit_addr == 0 ||
+           sys_exit_addr == 0) {
+               return -ESRCH;
+       }
+
+       ret = init_module_dependencies();
+       if (ret)
+               return ret;
+
+       return arch_init_module_deps();
+}
+
+static int once(void)
+{
+       int i, ret;
+       const char *sym;
+
+       ret = put_task_once();
+       if (ret)
+               return ret;
+
+       sym = "module_alloc";
+       __module_alloc = (void *)swap_ksyms(sym);
+       if (__module_alloc == NULL)
+               goto not_found;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+       sym = "module_memfree";
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+       sym = "module_free";
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+       __module_free = (void *)swap_ksyms(sym);
+       if (__module_free == NULL)
+               goto not_found;
+
+       ret = init_module_deps();
+       if (ret)
+               return ret;
+
+       /*
+        * FIXME allocate the probe table, currently defined statically
+        * initialize all list heads
+        */
+       for (i = 0; i < KPROBE_TABLE_SIZE; ++i) {
+               INIT_HLIST_HEAD(&kprobe_table[i]);
+               INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
+       }
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+static int init_kprobes(void)
+{
+       int ret;
+
+       init_sm();
+       atomic_set(&kprobe_count, 0);
+
+       ret = swap_td_raw_init();
+       if (ret)
+               return ret;
+
+       ret = swap_arch_init_kprobes();
+       if (ret)
+               goto td_raw_uninit;
+
+       ret = swap_ktd_init();
+       if (ret)
+               goto arch_kp_exit;
+
+       ret = kprobe_cur_reg();
+       if (ret)
+               goto ktd_uninit;
+
+       ret = put_task_init();
+       if (ret)
+               goto cur_uninit;
+
+       return 0;
+
+cur_uninit:
+       kprobe_cur_unreg();
+ktd_uninit:
+       swap_ktd_uninit_top();
+       swap_ktd_uninit_bottom();
+arch_kp_exit:
+       swap_arch_exit_kprobes();
+td_raw_uninit:
+       swap_td_raw_uninit();
+       return ret;
+}
+
+static void exit_kprobes(void)
+{
+       swap_ktd_uninit_top();
+       put_task_uninit();
+       kprobe_cur_unreg();
+       swap_ktd_uninit_bottom();
+       swap_arch_exit_kprobes();
+       swap_td_raw_uninit();
+       exit_sm();
+}
+
+SWAP_LIGHT_INIT_MODULE(once, init_kprobes, exit_kprobes, NULL, NULL);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/kprobe/swap_kprobes.h b/modules/kprobe/swap_kprobes.h
new file mode 100644 (file)
index 0000000..646a368
--- /dev/null
@@ -0,0 +1,328 @@
+/**
+ * @file kprobe/swap_kprobes.h
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM and MIPS
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ *
+ * @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) IBM Corporation, 2002, 2004
+ * Copyright (C) Samsung Electronics, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP kprobe interface definition.
+ */
+
+
+#ifndef _SWAP_KPROBES_H
+#define _SWAP_KPROBES_H
+
+
+#include <linux/kconfig.h>
+
+#ifdef CONFIG_SWAP_KERNEL_IMMUTABLE
+# error "Kernel is immutable"
+#endif /* CONFIG_SWAP_KERNEL_IMMUTABLE */
+
+
+#include <linux/version.h>     /*  LINUX_VERSION_CODE, KERNEL_VERSION() */
+#include <linux/notifier.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/pagemap.h>
+
+#include <swap-asm/swap_kprobes.h>
+
+
+/* kp_core_status settings */
+/** Kprobe hit active */
+#define KPROBE_HIT_ACTIVE      0x00000001
+/** Kprobe hit ss */
+#define KPROBE_HIT_SS          0x00000002
+/** Kprobe reenter */
+#define KPROBE_REENTER         0x00000004
+/** Kprobe hit ss done */
+#define KPROBE_HIT_SSDONE      0x00000008
+
+/** High word */
+#define HIWORD(x)               (((x) & 0xFFFF0000) >> 16)
+/** Low word */
+#define LOWORD(x)               ((x) & 0x0000FFFF)
+
+/** Invalid value */
+#define INVALID_VALUE           0xFFFFFFFF
+/** Invalid pointer */
+#define INVALID_POINTER         (void *)INVALID_VALUE
+
+/** Jprobe entry */
+#define JPROBE_ENTRY(pentry)    (kprobe_opcode_t *)pentry
+
+
+struct kprobe;
+struct pt_regs;
+struct kretprobe;
+struct kretprobe_instance;
+
+/**
+ * @brief Kprobe pre-handler pointer.
+ */
+typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
+
+/**
+ * @brief Kprobe break handler pointer.
+ */
+typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *);
+
+/**
+ * @brief Kprobe post handler pointer.
+ */
+typedef void (*kprobe_post_handler_t) (struct kprobe *,
+                                      struct pt_regs *,
+                                      unsigned long flags);
+
+/**
+ * @brief Kprobe fault handler pointer.
+ */
+typedef int (*kprobe_fault_handler_t) (struct kprobe *,
+                                      struct pt_regs *,
+                                      int trapnr);
+
+/**
+ * @brief Kretprobe handler pointer.
+ */
+typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
+                                   struct pt_regs *);
+
+struct kprobe;
+struct kp_core;
+
+struct kp_handlers {
+       int (*pre)(struct kp_core *, struct pt_regs *);
+
+       rwlock_t lock;
+       struct kprobe *kps[4];
+};
+
+struct kp_core {
+       struct hlist_node hlist;
+       atomic_t usage;
+
+       struct kp_handlers handlers;
+
+       unsigned long addr;
+       kprobe_opcode_t opcode;
+
+       struct swap_arch_specific_insn ainsn;
+};
+
+/**
+ * @struct kprobe
+ * @brief Main kprobe struct.
+ */
+struct kprobe {
+       unsigned long addr;     /**< Location of the probe point. */
+       char *symbol_name;      /**< Symbol name of the probe point. */
+       unsigned long offset;   /**< Offset into the symbol.*/
+       /**< Called before addr is executed. */
+       kprobe_pre_handler_t pre_handler;
+};
+
+/**
+ * @brief Kprobe pre-entry handler pointer.
+ */
+typedef unsigned long (*kprobe_pre_entry_handler_t) (void *priv_arg,
+                                                    struct pt_regs *regs);
+
+
+/**
+ * @struct jprobe
+ * @brief Special probe type that uses setjmp-longjmp type tricks to resume
+ * execution at a specified entry with a matching prototype corresponding
+ * to the probed function - a trick to enable arguments to become
+ * accessible seamlessly by probe handling logic.
+ * Note:
+ * Because of the way compilers allocate stack space for local variables
+ * etc upfront, regardless of sub-scopes within a function, this mirroring
+ * principle currently works only for probes placed on function entry points.
+ */
+struct jprobe {
+       struct kprobe kp;                   /**< This probes kprobe.*/
+       kprobe_opcode_t *entry;             /**< Probe handling code to jump to.*/
+       /** Handler which will be called before 'entry'. */
+       kprobe_pre_entry_handler_t pre_entry;
+       void *priv_arg;                     /**< Private args.*/
+};
+
+
+/**
+ * @struct jprobe_instance
+ * @brief Jprobe instance struct.
+ */
+struct jprobe_instance {
+       /*  either on free list or used list */
+       struct hlist_node uflist;            /**< Jprobes hash list. */
+       struct hlist_node hlist;             /**< Jprobes hash list. */
+       struct jprobe *jp;                   /**< Pointer to the target jprobe. */
+       /** Pointer to the target task_struct. */
+       struct task_struct *task;
+};
+
+
+
+
+
+/**
+ * @struct kretprobe
+ * @brief Function-return probe
+ * Note: User needs to provide a handler function, and initialize maxactive.
+ */
+struct kretprobe {
+       struct kprobe kp;                    /**< Kprobe of this kretprobe.*/
+       kretprobe_handler_t handler;         /**< Handler of this kretprobe.*/
+       kretprobe_handler_t entry_handler;   /**< Entry handler of this kretprobe.*/
+       /** The maximum number of instances of the probed function that can be
+        * active concurrently. */
+       int maxactive;
+       /** Tracks the number of times the probed function's return was ignored,
+        * due to maxactive being too low. */
+       int nmissed;
+       size_t data_size;                    /**< Size of the data. */
+       /** List of this probe's free_instances. */
+       struct hlist_head free_instances;
+       /** List of this probe's used_instances. */
+       struct hlist_head used_instances;
+
+#ifdef CONFIG_ARM
+       unsigned arm_noret:1;    /**< No-return flag for ARM.*/
+       unsigned thumb_noret:1;  /**< No-return flag for Thumb.*/
+#endif
+
+};
+
+/**
+ * @struct kretprobe_instance
+ * @brief Instance of kretprobe.
+ */
+struct kretprobe_instance {
+       /*  either on free list or used list */
+       struct hlist_node uflist;       /**< Kretprobe hash list.*/
+       struct hlist_node hlist;        /**< Kretprobe hash list.*/
+       struct kretprobe *rp;           /**< Pointer to this instance's kretprobe.*/
+       unsigned long *ret_addr;        /**< Return address.*/
+       unsigned long *sp;              /**< Stack pointer.*/
+       struct task_struct *task;       /**< Pointer to the target task_struct.*/
+       char data[0];                   /**< Pointer to data.*/
+};
+
+
+/*
+ * Large value for fast but memory consuming implementation
+ * it is good when a lot of probes are instrumented
+ */
+/* #define KPROBE_HASH_BITS 6 */
+#define KPROBE_HASH_BITS 16
+#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
+
+
+static void inline kp_core_get(struct kp_core *p)
+{
+       atomic_inc(&p->usage);
+}
+
+static void inline kp_core_put(struct kp_core *p)
+{
+       atomic_dec(&p->usage);
+}
+
+
+/* Get the kp_core at this addr (if any) - called with rcu_read_lock() */
+struct kp_core *kp_core_by_addr(unsigned long addr);
+
+int swap_register_kprobe(struct kprobe *p);
+void swap_unregister_kprobe(struct kprobe *p);
+
+int swap_register_jprobe(struct jprobe *p);
+void swap_unregister_jprobe(struct jprobe *p);
+void swap_jprobe_return(void);
+
+
+int swap_register_kretprobe(struct kretprobe *rp);
+void swap_unregister_kretprobe(struct kretprobe *rp);
+void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size);
+
+/*
+ * use:
+ *     swap_unregister_kretprobe[s]_top();
+ *     synchronize_sched();
+ *     swap_unregister_kretprobe[s]_bottom();
+ *
+ * rp_disarm - indicates the need for restoration of the return address
+ */
+void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm);
+void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size,
+                                  int rp_disarm);
+void swap_unregister_kretprobe_bottom(struct kretprobe *rp);
+void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size);
+
+
+unsigned long swap_trampoline_handler(struct pt_regs *regs);
+
+
+extern atomic_t kprobe_count;
+extern unsigned long sched_addr;
+
+struct kp_core *kp_core_running(void);
+void kp_core_running_set(struct kp_core *p);
+struct kp_core_ctlblk *kp_core_ctlblk(void);
+
+
+struct kctx;
+
+/* for __switch_to support */
+#define SWITCH_TO_KP   0b0001
+#define SWITCH_TO_RP   0b0010
+#define SWITCH_TO_ALL  (SWITCH_TO_KP | SWITCH_TO_RP)
+
+#define current_kctx   kctx_by_task(current)
+struct kctx *kctx_by_task(struct task_struct *task);
+
+void switch_to_bits_set(struct kctx *ctx, unsigned long mask);
+void switch_to_bits_reset(struct kctx *ctx, unsigned long mask);
+unsigned long switch_to_bits_get(struct kctx *ctx, unsigned long mask);
+
+
+#ifndef swap_in_interrupt
+#define swap_in_interrupt()    in_interrupt()
+#endif /* swap_in_interrupt */
+
+static inline int able2resched(struct kctx *ctx)
+{
+       if (swap_in_interrupt() || switch_to_bits_get(ctx, SWITCH_TO_ALL))
+               return 0;
+
+       return 1;
+}
+
+
+#endif /* _SWAP_KPROBES_H */
+
diff --git a/modules/kprobe/swap_kprobes_deps.c b/modules/kprobe/swap_kprobes_deps.c
new file mode 100644 (file)
index 0000000..9a54bb8
--- /dev/null
@@ -0,0 +1,1471 @@
+/**
+ * kprobe/swap_kprobes_deps.c
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP kprobe kernel-dependent dependencies.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+
+#include "swap_kprobes_deps.h"
+#include "swap_kdebug.h"
+
+
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+/* kernel define 'pgd_offset_k' redefinition */
+#undef pgd_offset_k
+#define pgd_offset_k(addr)     pgd_offset(init_task.active_mm, addr)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
+#ifndef is_zero_pfn
+
+static unsigned long swap_zero_pfn ;
+
+#endif /* is_zero_pfn */
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
+static inline void *swap_kmap_atomic(struct page *page)
+{
+       return kmap_atomic(page);
+}
+static inline void swap_kunmap_atomic(void *kvaddr)
+{
+       kunmap_atomic(kvaddr);
+}
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36) */
+static inline void *swap_kmap_atomic(struct page *page)
+{
+       return kmap_atomic(page, KM_USER0);
+}
+
+static inline void swap_kunmap_atomic(void *kvaddr)
+{
+       kunmap_atomic(kvaddr, KM_USER0);
+}
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+DECLARE_MOD_FUNC_DEP(do_mmap, unsigned long, struct file *file,
+                    unsigned long addr, unsigned long len, unsigned long prot,
+                    unsigned long flags, vm_flags_t vm_flags,
+                    unsigned long pgoff, unsigned long *populate);
+DECLARE_MOD_DEP_WRAPPER(swap_do_mmap,
+                       unsigned long,
+                       struct file *file, unsigned long addr,
+                       unsigned long len, unsigned long prot,
+                       unsigned long flags, vm_flags_t vm_flags,
+                       unsigned long pgoff, unsigned long *populate)
+IMP_MOD_DEP_WRAPPER(do_mmap, file, addr, len,
+                   prot, flags, vm_flags, pgoff, populate)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+DECLARE_MOD_FUNC_DEP(do_mmap_pgoff, unsigned long, struct file *file,
+                    unsigned long addr, unsigned long len, unsigned long prot,
+                    unsigned long flags, unsigned long pgoff,
+                    unsigned long *populate);
+DECLARE_MOD_DEP_WRAPPER(swap_do_mmap_pgoff,
+                       unsigned long,
+                       struct file *file, unsigned long addr,
+                       unsigned long len, unsigned long prot,
+                       unsigned long flags, unsigned long pgoff,
+                       unsigned long *populate)
+IMP_MOD_DEP_WRAPPER(do_mmap_pgoff, file, addr, len,
+                   prot, flags, pgoff, populate)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+DECLARE_MOD_FUNC_DEP(do_mmap_pgoff, unsigned long, struct file *file,
+                    unsigned long addr, unsigned long len, unsigned long prot,
+                    unsigned long flags, unsigned long pgoff);
+DECLARE_MOD_DEP_WRAPPER(swap_do_mmap_pgoff,
+                       unsigned long,
+                       struct file *file, unsigned long addr,
+                       unsigned long len, unsigned long prot,
+                       unsigned long flags, unsigned long pgoff)
+IMP_MOD_DEP_WRAPPER(do_mmap_pgoff, file, addr, len, prot, flags, pgoff)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+EXPORT_SYMBOL_GPL(swap_do_mmap);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+EXPORT_SYMBOL_GPL(swap_do_mmap_pgoff);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
+
+/* copy_to_user_page */
+#ifndef copy_to_user_page
+static DECLARE_MOD_FUNC_DEP(copy_to_user_page, void, struct vm_area_struct *vma,
+                           struct page *page, unsigned long uaddr, void *dst,
+                           const void *src, unsigned long len);
+DECLARE_MOD_DEP_WRAPPER(swap_copy_to_user_page,
+                       void,
+                       struct vm_area_struct *vma, struct page *page,
+                       unsigned long uaddr, void *dst, const void *src,
+                       unsigned long len)
+IMP_MOD_DEP_WRAPPER(copy_to_user_page, vma, page, uaddr, dst, src, len)
+#else /* copy_to_user_page */
+#define swap_copy_to_user_page copy_to_user_page
+#endif /* copy_to_user_page */
+
+
+static DECLARE_MOD_FUNC_DEP(find_extend_vma, struct vm_area_struct *,
+                           struct mm_struct *mm, unsigned long addr);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+static DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm,
+                           struct vm_area_struct *vma, unsigned long address,
+                           int write_access);
+#endif
+#else
+static DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm,
+                           struct vm_area_struct *vma, unsigned long address,
+                           unsigned int flags);
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
+
+#ifdef __HAVE_ARCH_GATE_AREA
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+static DECLARE_MOD_FUNC_DEP(get_gate_vma, struct vm_area_struct *,
+                           struct mm_struct *mm);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+static DECLARE_MOD_FUNC_DEP(get_gate_vma, struct vm_area_struct *,
+                           struct task_struct *tsk);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+DECLARE_MOD_FUNC_DEP(in_gate_area, int, struct mm_struct *mm,
+                    unsigned long addr);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+DECLARE_MOD_FUNC_DEP(in_gate_area, int, struct task_struct *task,
+                    unsigned long addr);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+static DECLARE_MOD_FUNC_DEP(in_gate_area_no_mm, int, unsigned long addr);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+static DECLARE_MOD_FUNC_DEP(in_gate_area_no_task, int, unsigned long addr);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#endif /* __HAVE_ARCH_GATE_AREA */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+static DECLARE_MOD_FUNC_DEP(follow_page_mask, \
+               struct page *, struct vm_area_struct *vma, \
+               unsigned long address, unsigned int foll_flags, \
+               unsigned int *page_mask);
+DECLARE_MOD_DEP_WRAPPER(swap_follow_page_mask,
+                       struct page *,
+                       struct vm_area_struct *vma, unsigned long address,
+                       unsigned int foll_flags, unsigned int *page_mask)
+IMP_MOD_DEP_WRAPPER(follow_page_mask, vma, address, foll_flags, page_mask)
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+static DECLARE_MOD_FUNC_DEP(follow_page, \
+               struct page *, struct vm_area_struct *vma, \
+               unsigned long address, unsigned int foll_flags);
+DECLARE_MOD_DEP_WRAPPER(swap_follow_page,
+                       struct page *,
+                       struct vm_area_struct *vma, unsigned long address,
+                       unsigned int foll_flags)
+IMP_MOD_DEP_WRAPPER(follow_page, vma, address, foll_flags)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+static DECLARE_MOD_FUNC_DEP(__flush_anon_page, \
+               void, struct vm_area_struct *vma, struct page *page, \
+               unsigned long vmaddr);
+static DECLARE_MOD_FUNC_DEP(vm_normal_page, \
+               struct page *, struct vm_area_struct *vma, \
+               unsigned long addr, pte_t pte);
+
+
+#if (LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 16))
+static DECLARE_MOD_FUNC_DEP(put_task_struct, \
+               void, struct task_struct *tsk);
+#else
+static DECLARE_MOD_FUNC_DEP(put_task_struct, \
+               void, struct rcu_head *rhp);
+#endif
+
+DECLARE_MOD_DEP_WRAPPER(swap_find_extend_vma,
+                       struct vm_area_struct *,
+                       struct mm_struct *mm, unsigned long addr)
+IMP_MOD_DEP_WRAPPER(find_extend_vma, mm, addr)
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+DECLARE_MOD_DEP_WRAPPER(swap_handle_mm_fault,
+                       int,
+                       struct mm_struct *mm, struct vm_area_struct *vma,
+                       unsigned long address, int write_access)
+{
+       if (in_atomic())
+               return VM_FAULT_ERROR | VM_FAULT_OOM;
+
+       IMP_MOD_DEP_WRAPPER(handle_mm_fault, mm, vma, address, write_access)
+}
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) */
+#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
+DECLARE_MOD_DEP_WRAPPER(swap_handle_mm_fault,
+                       int,
+                       struct mm_struct *mm, struct vm_area_struct *vma,
+                       unsigned long address, unsigned int flags)
+{
+       if (in_atomic())
+               return VM_FAULT_ERROR | VM_FAULT_OOM;
+
+       IMP_MOD_DEP_WRAPPER(handle_mm_fault, mm, vma, address, flags)
+}
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
+
+struct vm_area_struct *swap_get_gate_vma(struct mm_struct *mm)
+{
+#ifdef __HAVE_ARCH_GATE_AREA
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+IMP_MOD_DEP_WRAPPER(get_gate_vma, mm)
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+IMP_MOD_DEP_WRAPPER(get_gate_vma, tsk)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#else /* __HAVE_ARCH_GATE_AREA */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+       return get_gate_vma(mm);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+       return get_gate_vma(tsk);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#endif /* __HAVE_ARCH_GATE_AREA */
+}
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
+DECLARE_MOD_FUNC_DEP(follow_hugetlb_page,                              \
+                    int,                                               \
+                    struct mm_struct *mm, struct vm_area_struct *vma,  \
+                    struct page **pages, struct vm_area_struct **vmas, \
+                    unsigned long *position, int *length, int i,       \
+                    unsigned int flags);
+DECLARE_MOD_DEP_WRAPPER(swap_follow_hugetlb_page,
+                       int,
+                       struct mm_struct *mm, struct vm_area_struct *vma,
+                       struct page **pages, struct vm_area_struct **vmas,
+                       unsigned long *position, int *length, int i,
+                       unsigned int flags)
+IMP_MOD_DEP_WRAPPER(follow_hugetlb_page,                               \
+                   mm, vma, pages, vmas, position, length, i, flags)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) */
+DECLARE_MOD_FUNC_DEP(follow_hugetlb_page,                              \
+                    long,                                              \
+                    struct mm_struct *mm, struct vm_area_struct *vma,  \
+                    struct page **pages, struct vm_area_struct **vmas, \
+                    unsigned long *position, unsigned long *nr_pages,  \
+                    long i, unsigned int flags);
+DECLARE_MOD_DEP_WRAPPER(swap_follow_hugetlb_page,
+                       long,
+                       struct mm_struct *mm, struct vm_area_struct *vma,
+                       struct page **pages, struct vm_area_struct **vmas,
+                       unsigned long *position, unsigned long *nr_pages,
+                       long i, unsigned int flags)
+IMP_MOD_DEP_WRAPPER(follow_hugetlb_page,                               \
+                   mm, vma, pages, vmas, position, nr_pages, i, flags)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) */
+
+#else /* CONFIG_HUGETLB_PAGE */
+#define swap_follow_hugetlb_page follow_hugetlb_page
+#endif /* CONFIG_HUGETLB_PAGE */
+
+static inline int swap_in_gate_area(struct task_struct *task,
+                                   unsigned long addr)
+{
+#ifdef __HAVE_ARCH_GATE_AREA
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+       struct mm_struct *mm;
+
+       if (task == NULL)
+               return 0;
+
+       mm = task->mm;
+       IMP_MOD_DEP_WRAPPER(in_gate_area, mm, addr)
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+       IMP_MOD_DEP_WRAPPER(in_gate_area, task, addr)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#else /*__HAVE_ARCH_GATE_AREA */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+       struct mm_struct *mm;
+
+       if (task == NULL)
+               return 0;
+
+       mm = task->mm;
+       return in_gate_area(mm, addr);
+#else
+       return in_gate_area(task, addr);
+#endif
+#endif/*__HAVE_ARCH_GATE_AREA */
+}
+
+
+#ifdef __HAVE_ARCH_GATE_AREA
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+DECLARE_MOD_DEP_WRAPPER(swap_in_gate_area_no_mm, int, unsigned long addr)
+IMP_MOD_DEP_WRAPPER(in_gate_area_no_mm, addr)
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+DECLARE_MOD_DEP_WRAPPER(swap_in_gate_area_no_task, int, unsigned long addr)
+IMP_MOD_DEP_WRAPPER(in_gate_area_no_task, addr)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#endif /* __HAVE_ARCH_GATE_AREA */
+
+static inline int swap_in_gate_area_no_xxx(unsigned long addr)
+{
+#ifdef __HAVE_ARCH_GATE_AREA
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+       return swap_in_gate_area_no_mm(addr);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+       return swap_in_gate_area_no_task(addr);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#else /* __HAVE_ARCH_GATE_AREA */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+       return in_gate_area_no_mm(addr);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+       return in_gate_area_no_task(addr);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#endif /* __HAVE_ARCH_GATE_AREA */
+}
+
+DECLARE_MOD_DEP_WRAPPER(swap__flush_anon_page,
+                       void,
+                       struct vm_area_struct *vma, struct page *page,
+                       unsigned long vmaddr)
+IMP_MOD_DEP_WRAPPER(__flush_anon_page, vma, page, vmaddr)
+
+static inline void swap_flush_anon_page(struct vm_area_struct *vma,
+                                       struct page *page,
+                                       unsigned long vmaddr)
+{
+#if defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM)
+       if (PageAnon(page))
+               swap__flush_anon_page(vma, page, vmaddr);
+#else /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
+       flush_anon_page(vma, page, vmaddr);
+#endif /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
+}
+
+DECLARE_MOD_DEP_WRAPPER(swap_vm_normal_page,
+                       struct page *,
+                       struct vm_area_struct *vma, unsigned long addr,
+                       pte_t pte)
+IMP_MOD_DEP_WRAPPER(vm_normal_page, vma, addr, pte)
+
+
+
+/**
+ * @brief Initializes module dependencies.
+ *
+ * @return 0.
+ */
+int init_module_dependencies(void)
+{
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+       INIT_MOD_DEP_VAR(handle_mm_fault, handle_mm_fault);
+#endif
+
+#ifndef copy_to_user_page
+       INIT_MOD_DEP_VAR(copy_to_user_page, copy_to_user_page);
+#endif /* copy_to_user_page */
+
+       INIT_MOD_DEP_VAR(find_extend_vma, find_extend_vma);
+
+#ifdef CONFIG_HUGETLB_PAGE
+       INIT_MOD_DEP_VAR(follow_hugetlb_page, follow_hugetlb_page);
+#endif
+
+#ifdef __HAVE_ARCH_GATE_AREA
+       INIT_MOD_DEP_VAR(in_gate_area, in_gate_area);
+       INIT_MOD_DEP_VAR(get_gate_vma, get_gate_vma);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+       INIT_MOD_DEP_VAR(in_gate_area_no_mm, in_gate_area_no_mm);
+#else /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))  */
+       INIT_MOD_DEP_VAR(in_gate_area_no_task, in_gate_area_no_task);
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))  */
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+       INIT_MOD_DEP_VAR(follow_page_mask, follow_page_mask);
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+       INIT_MOD_DEP_VAR(follow_page, follow_page);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+
+#ifndef is_zero_pfn
+       swap_zero_pfn = page_to_pfn(ZERO_PAGE(0));
+#endif /* is_zero_pfn */
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))  */
+
+#if defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM)
+       INIT_MOD_DEP_VAR(__flush_anon_page, __flush_anon_page);
+#endif /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
+
+       INIT_MOD_DEP_VAR(vm_normal_page, vm_normal_page);
+
+#if (LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 16))
+# if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11))
+       INIT_MOD_DEP_VAR(put_task_struct, put_task_struct);
+# else
+       INIT_MOD_DEP_VAR(put_task_struct, __put_task_struct);
+# endif
+#else /*2.6.16 */
+       INIT_MOD_DEP_VAR(put_task_struct, __put_task_struct_cb);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+       INIT_MOD_DEP_VAR(do_mmap, do_mmap);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+       INIT_MOD_DEP_VAR(do_mmap_pgoff, do_mmap_pgoff);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
+
+       return 0;
+}
+
+
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+
+static int do_access_process_vm(struct task_struct *tsk, struct mm_struct *mm,
+                               unsigned long addr, void *buf, int len,
+                               int write)
+{
+       struct vm_area_struct *vma;
+       void *old_buf = buf;
+
+       while (len) {
+               int bytes, ret, offset;
+               void *maddr;
+               struct page *page = NULL;
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
+               ret = get_user_pages(tsk, mm, addr, 1, write, 1, &page, &vma);
+# else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */
+               ret = get_user_pages_remote(tsk, mm, addr, 1,
+                                           FOLL_WRITE | FOLL_FORCE,
+                                           &page, &vma);
+# endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */
+
+               if (ret <= 0) {
+#ifndef CONFIG_HAVE_IOREMAP_PROT
+                       break;
+#else
+                       /*
+                        * Check if this is a VM_IO | VM_PFNMAP VMA, which
+                        * we can access using slightly different code.
+                        */
+                       vma = find_vma(mm, addr);
+                       if (!vma || vma->vm_start > addr)
+                               break;
+                       if (vma->vm_ops && vma->vm_ops->access)
+                               ret = vma->vm_ops->access(vma, addr, buf, len,
+                                                         write);
+                       if (ret <= 0)
+                               break;
+                       bytes = ret;
+#endif
+               } else {
+                       bytes = len;
+                       offset = addr & (PAGE_SIZE-1);
+                       if (bytes > PAGE_SIZE-offset)
+                               bytes = PAGE_SIZE-offset;
+
+                       maddr = kmap(page);
+                       if (write) {
+                               swap_copy_to_user_page(vma, page, addr,
+                                                      maddr + offset,
+                                                      buf, bytes);
+                               set_page_dirty_lock(page);
+                       } else {
+                               copy_from_user_page(vma, page, addr,
+                                                   buf, maddr + offset, bytes);
+                       }
+                       kunmap(page);
+                       put_page(page);
+               }
+               len -= bytes;
+               buf += bytes;
+               addr += bytes;
+       }
+
+       return buf - old_buf;
+}
+
+int swap_access_process_vm(struct task_struct *tsk, unsigned long addr,
+                          void *buf, int len, int write)
+{
+       int ret;
+       struct mm_struct *mm;
+
+       mm = get_task_mm(tsk);
+       if (!mm)
+               return 0;
+
+       ret = do_access_process_vm(tsk, mm, addr, buf, len, write);
+       mmput(mm);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_access_process_vm);
+
+#else /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38) /* FIXME: must be < 32 */
+#define GUP_FLAGS_WRITE                  0x1
+#define GUP_FLAGS_FORCE                  0x2
+#define GUP_FLAGS_IGNORE_VMA_PERMISSIONS 0x4
+#define GUP_FLAGS_IGNORE_SIGKILL         0x8
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+static inline int use_zero_page(struct vm_area_struct *vma)
+{
+       /*
+        * We don't want to optimize FOLL_ANON for make_pages_present()
+        * when it tries to page in a VM_LOCKED region. As to VM_SHARED,
+        * we want to get the page from the page tables to make sure
+        * that we serialize and update with any other user of that
+        * mapping.
+        */
+       if (vma->vm_flags & (VM_LOCKED | VM_SHARED))
+               return 0;
+       /*
+        * And if we have a fault routine, it's not an anonymous region.
+        */
+       return !vma->vm_ops || !vma->vm_ops->fault;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+
+#ifdef __HAVE_COLOR_ZERO_PAGE
+
+static inline int swap_is_zero_pfn(unsigned long pfn)
+{
+       unsigned long offset_from_zero_pfn = pfn - swap_zero_pfn;
+       return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
+}
+
+#else /* __HAVE_COLOR_ZERO_PAGE */
+
+static inline int swap_is_zero_pfn(unsigned long pfn)
+{
+       return pfn == swap_zero_pfn;
+}
+#endif /* __HAVE_COLOR_ZERO_PAGE */
+
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */
+
+static inline int swap_is_zero_pfn(unsigned long pfn)
+{
+#ifndef is_zero_pfn
+       return pfn == swap_zero_pfn;
+#else /* is_zero_pfn */
+       return is_zero_pfn(pfn);
+#endif /* is_zero_pfn */
+}
+
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */
+
+static inline int stack_guard_page(struct vm_area_struct *vma,
+                                  unsigned long addr)
+{
+       return stack_guard_page_start(vma, addr) ||
+                       stack_guard_page_end(vma, addr+PAGE_SIZE);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+
+/**
+ * @brief Gets user pages uprobe.
+ *
+ * @param tsk Pointer to the task_struct.
+ * @param mm Pointer to the mm_struct.
+ * @param start Starting address.
+ * @param nr_pages Pages number.
+ * @param gup_flags Flags.
+ * @param pages Pointer to the array of pointers to the target page structs.
+ * @param vmas Pointer to the array of pointers to the target vm_area_struct.
+ * @param nonblocking Pointer to int.
+ * @return negative error code on error, positive result otherwise.
+ */
+long __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
+               unsigned long start, unsigned long nr_pages,
+               unsigned int gup_flags, struct page **pages,
+               struct vm_area_struct **vmas, int *nonblocking)
+{
+       long i;
+       unsigned long vm_flags;
+       unsigned int page_mask;
+
+       if (!nr_pages)
+               return 0;
+
+       VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
+
+       /*
+        * Require read or write permissions.
+        * If FOLL_FORCE is set, we only require the "MAY" flags.
+        */
+       vm_flags  = (gup_flags & FOLL_WRITE) ?
+                       (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+       vm_flags &= (gup_flags & FOLL_FORCE) ?
+                       (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
+
+       /*
+        * If FOLL_FORCE and FOLL_NUMA are both set, handle_mm_fault
+        * would be called on PROT_NONE ranges. We must never invoke
+        * handle_mm_fault on PROT_NONE ranges or the NUMA hinting
+        * page faults would unprotect the PROT_NONE ranges if
+        * _PAGE_NUMA and _PAGE_PROTNONE are sharing the same pte/pmd
+        * bitflag. So to avoid that, don't set FOLL_NUMA if
+        * FOLL_FORCE is set.
+        */
+       if (!(gup_flags & FOLL_FORCE))
+               gup_flags |= FOLL_NUMA;
+
+       i = 0;
+
+       do {
+               struct vm_area_struct *vma;
+
+               vma = swap_find_extend_vma(mm, start);
+               if (!vma && swap_in_gate_area(tsk, start)) {
+                       unsigned long pg = start & PAGE_MASK;
+                       pgd_t *pgd;
+                       pud_t *pud;
+                       pmd_t *pmd;
+                       pte_t *pte;
+
+                       /* user gate pages are read-only */
+                       if (gup_flags & FOLL_WRITE)
+                               return i ? : -EFAULT;
+                       if (pg > TASK_SIZE)
+                               pgd = pgd_offset_k(pg);
+                       else
+                               pgd = pgd_offset_gate(mm, pg);
+                       BUG_ON(pgd_none(*pgd));
+                       pud = pud_offset(pgd, pg);
+                       BUG_ON(pud_none(*pud));
+                       pmd = pmd_offset(pud, pg);
+                       if (pmd_none(*pmd))
+                               return i ? : -EFAULT;
+                       VM_BUG_ON(pmd_trans_huge(*pmd));
+                       pte = pte_offset_map(pmd, pg);
+                       if (pte_none(*pte)) {
+                               pte_unmap(pte);
+                               return i ? : -EFAULT;
+                       }
+                       vma = swap_get_gate_vma(mm);
+                       if (pages) {
+                               struct page *page;
+
+                               page = swap_vm_normal_page(vma, start, *pte);
+                               if (!page) {
+                                       if (!(gup_flags & FOLL_DUMP) &&
+                                            swap_is_zero_pfn(pte_pfn(*pte)))
+                                               page = pte_page(*pte);
+                                       else {
+                                               pte_unmap(pte);
+                                               return i ? : -EFAULT;
+                                       }
+                               }
+                               pages[i] = page;
+                               get_page(page);
+                       }
+                       pte_unmap(pte);
+                       page_mask = 0;
+                       goto next_page;
+               }
+
+               if (!vma ||
+                   (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
+                   !(vm_flags & vma->vm_flags))
+                       return i ? : -EFAULT;
+
+               if (is_vm_hugetlb_page(vma)) {
+                       i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
+                                       &start, &nr_pages, i, gup_flags);
+                       continue;
+               }
+
+               do {
+                       struct page *page;
+                       unsigned int foll_flags = gup_flags;
+                       unsigned int page_increm;
+
+                       /*
+                        * If we have a pending SIGKILL, don't keep faulting
+                        * pages and potentially allocating memory.
+                        */
+                       if (unlikely(fatal_signal_pending(current)))
+                               return i ? i : -ERESTARTSYS;
+
+                       /* cond_resched(); */
+                       while (!(page = swap_follow_page_mask(vma, start,
+                                               foll_flags, &page_mask))) {
+                               int ret;
+                               unsigned int fault_flags = 0;
+
+                               /* For mlock, just skip the stack guard page. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+                               if (foll_flags & FOLL_POPULATE) {
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
+                               if (foll_flags & FOLL_MLOCK) {
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
+                                       if (stack_guard_page(vma, start))
+                                               goto next_page;
+                               }
+                               if (foll_flags & FOLL_WRITE)
+                                       fault_flags |= FAULT_FLAG_WRITE;
+                               if (nonblocking)
+                                       fault_flags |= FAULT_FLAG_ALLOW_RETRY;
+                               if (foll_flags & FOLL_NOWAIT)
+                                       fault_flags |=
+                                               (FAULT_FLAG_ALLOW_RETRY |
+                                                FAULT_FLAG_RETRY_NOWAIT);
+
+                               ret = swap_handle_mm_fault(mm, vma, start,
+                                                       fault_flags);
+
+                               if (ret & VM_FAULT_ERROR) {
+                                       if (ret & VM_FAULT_OOM)
+                                               return i ? i : -ENOMEM;
+                                       if (ret & (VM_FAULT_HWPOISON |
+                                                  VM_FAULT_HWPOISON_LARGE)) {
+                                               if (i)
+                                                       return i;
+                                               else if (gup_flags &
+                                                        FOLL_HWPOISON)
+                                                       return -EHWPOISON;
+                                               else
+                                                       return -EFAULT;
+                                       }
+                                       if (ret & VM_FAULT_SIGBUS)
+                                               return i ? i : -EFAULT;
+                                       BUG();
+                               }
+
+                               if (tsk) {
+                                       if (ret & VM_FAULT_MAJOR)
+                                               tsk->maj_flt++;
+                                       else
+                                               tsk->min_flt++;
+                               }
+
+                               if (ret & VM_FAULT_RETRY) {
+                                       if (nonblocking)
+                                               *nonblocking = 0;
+                                       return i;
+                               }
+
+                               /*
+                                * The VM_FAULT_WRITE bit tells us that
+                                * do_wp_page has broken COW when necessary,
+                                * even if maybe_mkwrite decided not to set
+                                * pte_write. We can thus safely do subsequent
+                                * page lookups as if they were reads. But only
+                                * do so when looping for pte_write is futile:
+                                * in some cases userspace may also be wanting
+                                * to write to the gotten user page, which a
+                                * read fault here might prevent (a readonly
+                                * page might get reCOWed by userspace write).
+                                */
+                               if ((ret & VM_FAULT_WRITE) &&
+                                   !(vma->vm_flags & VM_WRITE))
+                                       foll_flags &= ~FOLL_WRITE;
+
+                               /* cond_resched(); */
+                       }
+                       if (IS_ERR(page))
+                               return i ? i : PTR_ERR(page);
+                       if (pages) {
+                               pages[i] = page;
+
+                               swap_flush_anon_page(vma, page, start);
+                               flush_dcache_page(page);
+                               page_mask = 0;
+                       }
+next_page:
+                       if (vmas) {
+                               vmas[i] = vma;
+                               page_mask = 0;
+                       }
+                       page_increm = 1 + (~(start >> PAGE_SHIFT) & page_mask);
+                       if (page_increm > nr_pages)
+                               page_increm = nr_pages;
+                       i += page_increm;
+                       start += page_increm * PAGE_SIZE;
+                       nr_pages -= page_increm;
+               } while (nr_pages && start < vma->vm_end);
+       } while (nr_pages);
+       return i;
+}
+
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+static int __get_user_pages_uprobe(struct task_struct *tsk,
+                                  struct mm_struct *mm, unsigned long start,
+                                  int nr_pages, unsigned int gup_flags,
+                                  struct page **pages,
+                                  struct vm_area_struct **vmas,
+                                  int *nonblocking)
+{
+       int i;
+       unsigned long vm_flags;
+
+       if (nr_pages <= 0)
+               return 0;
+
+       VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
+
+       /*
+        * Require read or write permissions.
+        * If FOLL_FORCE is set, we only require the "MAY" flags.
+        */
+       vm_flags  = (gup_flags & FOLL_WRITE) ?
+                       (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+       vm_flags &= (gup_flags & FOLL_FORCE) ?
+                       (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
+       i = 0;
+
+       do {
+               struct vm_area_struct *vma;
+
+               vma = swap_find_extend_vma(mm, start);
+               if (!vma && swap_in_gate_area_no_xxx(start)) {
+                       unsigned long pg = start & PAGE_MASK;
+                       pgd_t *pgd;
+                       pud_t *pud;
+                       pmd_t *pmd;
+                       pte_t *pte;
+
+                       /* user gate pages are read-only */
+                       if (gup_flags & FOLL_WRITE)
+                               return i ? : -EFAULT;
+                       if (pg > TASK_SIZE)
+                               pgd = pgd_offset_k(pg);
+                       else
+                               pgd = pgd_offset_gate(mm, pg);
+                       BUG_ON(pgd_none(*pgd));
+                       pud = pud_offset(pgd, pg);
+                       BUG_ON(pud_none(*pud));
+                       pmd = pmd_offset(pud, pg);
+                       if (pmd_none(*pmd))
+                               return i ? : -EFAULT;
+                       VM_BUG_ON(pmd_trans_huge(*pmd));
+                       pte = pte_offset_map(pmd, pg);
+                       if (pte_none(*pte)) {
+                               pte_unmap(pte);
+                               return i ? : -EFAULT;
+                       }
+                       vma = swap_get_gate_vma(mm);
+                       if (pages) {
+                               struct page *page;
+
+                               page = swap_vm_normal_page(vma, start, *pte);
+                               if (!page) {
+                                       if (!(gup_flags & FOLL_DUMP) &&
+                                               swap_is_zero_pfn(pte_pfn(*pte)))
+                                               page = pte_page(*pte);
+                                       else {
+                                               pte_unmap(pte);
+                                               return i ? : -EFAULT;
+                                       }
+                               }
+                               pages[i] = page;
+                               get_page(page);
+                       }
+                       pte_unmap(pte);
+                       goto next_page;
+               }
+
+               if (!vma ||
+                       (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
+                       !(vm_flags & vma->vm_flags)) {
+                       return i ? : -EFAULT;
+               }
+
+               if (is_vm_hugetlb_page(vma)) {
+                       i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
+                                       &start, &nr_pages, i, gup_flags);
+                       continue;
+               }
+
+               do {
+                       struct page *page;
+                       unsigned int foll_flags = gup_flags;
+
+                       /*
+                        * If we have a pending SIGKILL, don't keep faulting
+                        * pages and potentially allocating memory.
+                        */
+                       if (unlikely(fatal_signal_pending(current)))
+                               return i ? i : -ERESTARTSYS;
+
+                       /* cond_resched(); */
+                       while (!(page = swap_follow_page(vma, start,
+                                                        foll_flags))) {
+                               int ret;
+                               unsigned int fault_flags = 0;
+
+                               /* For mlock, just skip the stack guard page. */
+                               if (foll_flags & FOLL_MLOCK) {
+                                       if (stack_guard_page(vma, start))
+                                               goto next_page;
+                               }
+                               if (foll_flags & FOLL_WRITE)
+                                       fault_flags |= FAULT_FLAG_WRITE;
+                               if (nonblocking)
+                                       fault_flags |= FAULT_FLAG_ALLOW_RETRY;
+                               if (foll_flags & FOLL_NOWAIT)
+                                       fault_flags |=
+                                               (FAULT_FLAG_ALLOW_RETRY |
+                                               FAULT_FLAG_RETRY_NOWAIT);
+
+                               ret = swap_handle_mm_fault(mm, vma, start,
+                                                       fault_flags);
+
+                               if (ret & VM_FAULT_ERROR) {
+                                       if (ret & VM_FAULT_OOM)
+                                               return i ? i : -ENOMEM;
+                                       if (ret & (VM_FAULT_HWPOISON |
+                                                  VM_FAULT_HWPOISON_LARGE)) {
+                                               if (i)
+                                                       return i;
+                                               else if (gup_flags &
+                                                        FOLL_HWPOISON)
+                                                       return -EHWPOISON;
+                                               else
+                                                       return -EFAULT;
+                                       }
+                                       if (ret & VM_FAULT_SIGBUS)
+                                               return i ? i : -EFAULT;
+                                       BUG();
+                               }
+
+                               if (tsk) {
+                                       if (ret & VM_FAULT_MAJOR)
+                                               tsk->maj_flt++;
+                                       else
+                                               tsk->min_flt++;
+                               }
+
+                               if (ret & VM_FAULT_RETRY) {
+                                       if (nonblocking)
+                                               *nonblocking = 0;
+                                       return i;
+                               }
+
+                               /*
+                                * The VM_FAULT_WRITE bit tells us that
+                                * do_wp_page has broken COW when necessary,
+                                * even if maybe_mkwrite decided not to set
+                                * pte_write. We can thus safely do subsequent
+                                * page lookups as if they were reads. But only
+                                * do so when looping for pte_write is futile:
+                                * in some cases userspace may also be wanting
+                                * to write to the gotten user page, which a
+                                * read fault here might prevent (a readonly
+                                * page might get reCOWed by userspace write).
+                                */
+                               if ((ret & VM_FAULT_WRITE) &&
+                                       !(vma->vm_flags & VM_WRITE))
+                                       foll_flags &= ~FOLL_WRITE;
+
+                               /* cond_resched(); */
+                       }
+                       if (IS_ERR(page))
+                               return i ? i : PTR_ERR(page);
+                       if (pages) {
+                               pages[i] = page;
+
+                               swap_flush_anon_page(vma, page, start);
+                               flush_dcache_page(page);
+                       }
+next_page:
+                       if (vmas)
+                               vmas[i] = vma;
+                       i++;
+                       start += PAGE_SIZE;
+                       nr_pages--;
+               } while (nr_pages && start < vma->vm_end);
+       } while (nr_pages);
+
+       return i;
+}
+
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+
+static int __get_user_pages_uprobe(struct task_struct *tsk,
+                                  struct mm_struct *mm,
+                                  unsigned long start, int len, int flags,
+                                  struct page **pages,
+                                  struct vm_area_struct **vmas)
+{
+       int i;
+       unsigned int vm_flags = 0;
+       int write = !!(flags & GUP_FLAGS_WRITE);
+       int force = !!(flags & GUP_FLAGS_FORCE);
+       int ignore = !!(flags & GUP_FLAGS_IGNORE_VMA_PERMISSIONS);
+
+       if (len <= 0)
+               return 0;
+       /*
+        * Require read or write permissions.
+        * If 'force' is set, we only require the "MAY" flags.
+        */
+       vm_flags  = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+       vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
+       i = 0;
+
+       do {
+               struct vm_area_struct *vma;
+               unsigned int foll_flags;
+
+               vma = find_vma(mm, start);
+               if (!vma && swap_in_gate_area(tsk, start)) {
+                       unsigned long pg = start & PAGE_MASK;
+                       struct vm_area_struct *gate_vma =
+                               swap_get_gate_vma(tsk);
+                       pgd_t *pgd;
+                       pud_t *pud;
+                       pmd_t *pmd;
+                       pte_t *pte;
+
+                       /* user gate pages are read-only */
+                       if (!ignore && write)
+                               return i ? : -EFAULT;
+                       if (pg > TASK_SIZE)
+                               pgd = pgd_offset_k(pg);
+                       else
+                               pgd = pgd_offset_gate(mm, pg);
+                       BUG_ON(pgd_none(*pgd));
+                       pud = pud_offset(pgd, pg);
+                       BUG_ON(pud_none(*pud));
+                       pmd = pmd_offset(pud, pg);
+                       if (pmd_none(*pmd))
+                               return i ? : -EFAULT;
+                       pte = pte_offset_map(pmd, pg);
+                       if (pte_none(*pte)) {
+                               pte_unmap(pte);
+                               return i ? : -EFAULT;
+                       }
+                       if (pages) {
+                               struct page *page =
+                                       swap_vm_normal_page(gate_vma, start,
+                                                           *pte);
+                               pages[i] = page;
+                               if (page)
+                                       get_page(page);
+                       }
+                       pte_unmap(pte);
+                       if (vmas)
+                               vmas[i] = gate_vma;
+                       i++;
+                       start += PAGE_SIZE;
+                       len--;
+                       continue;
+               }
+
+               if (!vma ||
+                       (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
+                       (!ignore && !(vm_flags & vma->vm_flags)))
+                       return i ? : -EFAULT;
+
+               if (is_vm_hugetlb_page(vma)) {
+                       i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
+                                               &start, &len, i, write);
+                       continue;
+               }
+
+               foll_flags = FOLL_TOUCH;
+               if (pages)
+                       foll_flags |= FOLL_GET;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
+               if (!write && use_zero_page(vma))
+                       foll_flags |= FOLL_ANON;
+#endif
+#endif
+
+               do {
+                       struct page *page;
+
+                       if (write)
+                               foll_flags |= FOLL_WRITE;
+
+
+                       /* cond_resched(); */
+
+                       DBPRINTF("pages = %p vma = %p\n", pages, vma);
+                       while (!(page = swap_follow_page(vma, start,
+                                                        foll_flags))) {
+                               int ret;
+                               ret = swap_handle_mm_fault(mm, vma, start,
+                                               foll_flags & FOLL_WRITE);
+
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
+                               if (ret & VM_FAULT_WRITE)
+                                       foll_flags &= ~FOLL_WRITE;
+
+                               switch (ret & ~VM_FAULT_WRITE) {
+                               case VM_FAULT_MINOR:
+                                       tsk->min_flt++;
+                                       break;
+                               case VM_FAULT_MAJOR:
+                                       tsk->maj_flt++;
+                                       break;
+                               case VM_FAULT_SIGBUS:
+                                       return i ? i : -EFAULT;
+                               case VM_FAULT_OOM:
+                                       return i ? i : -ENOMEM;
+                               default:
+                                       BUG();
+                               }
+
+#else
+                               if (ret & VM_FAULT_ERROR) {
+                                       if (ret & VM_FAULT_OOM)
+                                               return i ? i : -ENOMEM;
+                                       else if (ret & VM_FAULT_SIGBUS)
+                                               return i ? i : -EFAULT;
+                                       BUG();
+                               }
+                               if (ret & VM_FAULT_MAJOR)
+                                       tsk->maj_flt++;
+                               else
+                                       tsk->min_flt++;
+
+                               /*
+                                * The VM_FAULT_WRITE bit tells us that
+                                * do_wp_page has broken COW when necessary,
+                                * even if maybe_mkwrite decided not to set
+                                * pte_write. We can thus safely do subsequent
+                                * page lookups as if they were reads. But only
+                                * do so when looping for pte_write is futile:
+                                * in some cases userspace may also be wanting
+                                * to write to the gotten user page, which a
+                                * read fault here might prevent (a readonly
+                                * page might get reCOWed by userspace write).
+                                */
+                               if ((ret & VM_FAULT_WRITE) &&
+                                               !(vma->vm_flags & VM_WRITE))
+                                       foll_flags &= ~FOLL_WRITE;
+
+                               /* cond_resched(); */
+#endif
+
+                       }
+
+                       if (IS_ERR(page))
+                               return i ? i : PTR_ERR(page);
+                       if (pages) {
+                               pages[i] = page;
+
+                               swap_flush_anon_page(vma, page, start);
+                               flush_dcache_page(page);
+                       }
+                       if (vmas)
+                               vmas[i] = vma;
+                       i++;
+                       start += PAGE_SIZE;
+                       len--;
+               } while (len && start < vma->vm_end);
+       } while (len);
+       return i;
+}
+#endif
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+
+/**
+ * @brief Gets user pages uprobe.
+ *
+ * @param tsk Pointer to the task_struct.
+ * @param mm Pointer to the mm_struct.
+ * @param start Starting address.
+ * @param len Length.
+ * @param write Write flag.
+ * @param force Force flag.
+ * @param pages Pointer to the array of pointers to the target page structs.
+ * @param vmas Pointer to the array of pointers to the target vm_area_struct.
+ * @return negative error code on error, positive result otherwise.
+ */
+int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
+               unsigned long start, int len, int write, int force,
+               struct page **pages, struct vm_area_struct **vmas)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) /* FIXME: must be >= 32! */
+       int flags = FOLL_TOUCH;
+
+       if (pages)
+               flags |= FOLL_GET;
+       if (write)
+               flags |= FOLL_WRITE;
+       if (force)
+               flags |= FOLL_FORCE;
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+       int flags = 0;
+
+       if (write)
+               flags |= GUP_FLAGS_WRITE;
+       if (force)
+               flags |= GUP_FLAGS_FORCE;
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+
+       return __get_user_pages_uprobe(tsk, mm,
+                               start, len, flags,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
+                                               pages, vmas, NULL);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+                                               pages, vmas);
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
+#else
+       return get_user_pages(tsk, mm, start, len, write, force, pages, vmas);
+#endif
+}
+
+#define ACCESS_PROCESS_OPTIMIZATION 0
+
+#if ACCESS_PROCESS_OPTIMIZATION
+
+#define GET_STEP_X(LEN, STEP) (((LEN) >= (STEP)) ? (STEP) : (LEN) % (STEP))
+#define GET_STEP_4(LEN) GET_STEP_X((LEN), 4)
+
+static void read_data_current(unsigned long addr, void *buf, int len)
+{
+       int step;
+       int pos = 0;
+
+       for (step = GET_STEP_4(len); len; len -= step) {
+               switch (GET_STEP_4(len)) {
+               case 1:
+                       get_user(*(u8 *)(buf + pos),
+                                (unsigned long *)(addr + pos));
+                       step = 1;
+                       break;
+
+               case 2:
+               case 3:
+                       get_user(*(u16 *)(buf + pos),
+                                (unsigned long *)(addr + pos));
+                       step = 2;
+                       break;
+
+               case 4:
+                       get_user(*(u32 *)(buf + pos),
+                                (unsigned long *)(addr + pos));
+                       step = 4;
+                       break;
+               }
+
+               pos += step;
+       }
+}
+
+/* not working */
+static void write_data_current(unsigned long addr, void *buf, int len)
+{
+       int step;
+       int pos = 0;
+
+       for (step = GET_STEP_4(len); len; len -= step) {
+               switch (GET_STEP_4(len)) {
+               case 1:
+                       put_user(*(u8 *)(buf + pos),
+                                (unsigned long *)(addr + pos));
+                       step = 1;
+                       break;
+
+               case 2:
+               case 3:
+                       put_user(*(u16 *)(buf + pos),
+                                (unsigned long *)(addr + pos));
+                       step = 2;
+                       break;
+
+               case 4:
+                       put_user(*(u32 *)(buf + pos),
+                                (unsigned long *)(addr + pos));
+                       step = 4;
+                       break;
+               }
+
+               pos += step;
+       }
+}
+#endif
+
+/**
+ * @brief Read-write task memory.
+ *
+ * @param tsk Pointer to the target task task_struct.
+ * @param addr Address to read-write.
+ * @param buf Pointer to buffer where to put-get data.
+ * @param len Buffer length.
+ * @param write Write flag. If 0 - reading, if 1 - writing.
+ * @return Read-write size, error code on error.
+ */
+int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr,
+                            void *buf, int len, int write)
+{
+       struct mm_struct *mm;
+       struct vm_area_struct *vma;
+       void *old_buf = buf;
+       int atomic;
+
+       if (len <= 0)
+               return -1;
+
+#if ACCESS_PROCESS_OPTIMIZATION
+       if (write == 0 && tsk == current) {
+               read_data_current(addr, buf, len);
+               return len;
+       }
+#endif
+
+       mm = tsk->mm; /* function 'get_task_mm' is to be called */
+       if (!mm)
+               return 0;
+
+       /* FIXME: danger: write memory in atomic context */
+       atomic = in_atomic();
+       WARN_ON(atomic);
+
+       /* ignore errors, just check how much was successfully transferred */
+       while (len) {
+               int bytes, ret, offset;
+               void *maddr;
+               struct page *page = NULL;
+
+               ret = get_user_pages_uprobe(tsk, mm, addr, 1,
+                                               write, 1, &page, &vma);
+
+               if (ret <= 0) {
+                       /*
+                        * Check if this is a VM_IO | VM_PFNMAP VMA, which
+                        * we can access using slightly different code.
+                        */
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+                       vma = find_vma(mm, addr);
+                       if (!vma)
+                               break;
+                       if (vma->vm_ops && vma->vm_ops->access)
+                               ret = vma->vm_ops->access(vma, addr, buf,
+                                                       len, write);
+                       if (ret <= 0)
+#endif
+                               break;
+                       bytes = ret;
+               } else {
+                       bytes = len;
+                       offset = addr & (PAGE_SIZE-1);
+                       if (bytes > PAGE_SIZE-offset)
+                               bytes = PAGE_SIZE-offset;
+
+                       maddr = atomic ? swap_kmap_atomic(page) : kmap(page);
+
+                       if (write) {
+                               swap_copy_to_user_page(vma, page, addr,
+                                                       maddr + offset,
+                                                      buf, bytes);
+                               set_page_dirty_lock(page);
+                       } else {
+                               copy_from_user_page(vma, page, addr,
+                                                   buf, maddr + offset,
+                                                   bytes);
+                       }
+
+                       atomic ? swap_kunmap_atomic(maddr) : kunmap(page);
+                       page_cache_release(page);
+               }
+               len -= bytes;
+               buf += bytes;
+               addr += bytes;
+       }
+
+       return buf - old_buf;
+}
+EXPORT_SYMBOL_GPL(access_process_vm_atomic);
+
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+
+/**
+ * @brief Page present.
+ *
+ * @param mm Pointer to the target mm_struct.
+ * @param address Address.
+ */
+int page_present(struct mm_struct *mm, unsigned long address)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+       unsigned long pfn;
+
+       pgd = pgd_offset(mm, address);
+       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+               goto out;
+
+       pud = pud_offset(pgd, address);
+       if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+               goto out;
+
+       pmd = pmd_offset(pud, address);
+       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+               goto out;
+
+       ptep = pte_offset_map(pmd, address);
+       if (pte_none(*ptep)) {
+               pte_unmap(ptep);
+               goto out;
+       }
+
+       pte = *ptep;
+       pte_unmap(ptep);
+       if (pte_present(pte)) {
+               pfn = pte_pfn(pte);
+               if (pfn_valid(pfn))
+                       return 1;
+       }
+
+out:
+       return 0;
+}
+EXPORT_SYMBOL_GPL(page_present);
+
diff --git a/modules/kprobe/swap_kprobes_deps.h b/modules/kprobe/swap_kprobes_deps.h
new file mode 100644 (file)
index 0000000..8d4f345
--- /dev/null
@@ -0,0 +1,188 @@
+/**
+ * @file kprobe/swap_kprobes_deps.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP kprobe kernel-dependent dependencies.
+ */
+
+#ifndef _SWAP_KPROBES_DEPS_H
+#define _SWAP_KPROBES_DEPS_H
+
+#include <linux/version.h>     /* LINUX_VERSION_CODE, KERNEL_VERSION() */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/mempolicy.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <ksyms/ksyms.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+#define DECLARE_NODE_PTR_FOR_HLIST(var_name)
+#define swap_hlist_for_each_entry_rcu(tpos, pos, head, member) \
+       hlist_for_each_entry_rcu(tpos, head, member)
+#define swap_hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+       hlist_for_each_entry_safe(tpos, n, head, member)
+#define swap_hlist_for_each_entry(tpos, pos, head, member) \
+       hlist_for_each_entry(tpos, head, member)
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+#define DECLARE_NODE_PTR_FOR_HLIST(var_name) struct hlist_node *var_name
+#define swap_hlist_for_each_entry_rcu(tpos, pos, head, member) \
+       hlist_for_each_entry_rcu(tpos, pos, head, member)
+#define swap_hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+       hlist_for_each_entry_safe(tpos, pos, n, head, member)
+#define swap_hlist_for_each_entry(tpos, pos, head, member) \
+       hlist_for_each_entry(tpos, pos, head, member)
+
+#define list_first_entry_or_null(ptr, type, member) \
+       (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12))
+#define synchronize_sched      synchronize_kernel
+#endif
+
+
+/*
+ * swap_preempt_enable_no_resched()
+ */
+#if (defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)))
+
+#ifdef CONFIG_PREEMPT_COUNT
+#define swap_preempt_enable_no_resched() \
+do { \
+       barrier(); \
+       preempt_count_dec(); \
+} while (0)
+#else /* !CONFIG_PREEMPT_COUNT */
+#define swap_preempt_enable_no_resched() barrier()
+#endif /* CONFIG_PREEMPT_COUNT */
+
+#else /* !(defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) */
+#define swap_preempt_enable_no_resched() preempt_enable_no_resched()
+#endif /* !(defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) */
+
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0)
+    #define task_job(task) (task->jobctl)
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0) */
+    #define task_job(task) (task->group_stop)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0) */
+
+
+
+/* --------------------- Declaration of module dependencies ----------------- */
+
+#define DECLARE_MOD_FUNC_DEP(name, ret, ...) ret(*__ref_##name)(__VA_ARGS__)
+#define DECLARE_MOD_CB_DEP(name, ret, ...) ret(*name)(__VA_ARGS__)
+
+
+/* ---------------- Implementation of module dependencies wrappers ---------- */
+
+#define DECLARE_MOD_DEP_WRAPPER(name, ret, ...) ret name(__VA_ARGS__)
+#define IMP_MOD_DEP_WRAPPER(name, ...) \
+{ \
+       return __ref_##name(__VA_ARGS__); \
+}
+
+
+/* --------------------- Module dependencies initialization ----------------- */
+
+#define INIT_MOD_DEP_VAR(dep, name) \
+{ \
+       __ref_##dep = (void *) swap_ksyms(#name); \
+       if (!__ref_##dep) { \
+               DBPRINTF(#name " is not found! Oops. Where is it?"); \
+               return -ESRCH; \
+       } \
+}
+
+#define INIT_MOD_DEP_CB(dep, name) \
+{ \
+       dep = (void *) swap_ksyms(#name); \
+       if (!dep) { \
+               DBPRINTF(#name " is not found! Oops. Where is it?"); \
+               return -ESRCH; \
+       } \
+}
+
+
+int init_module_dependencies(void);
+
+
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+
+int swap_access_process_vm(struct task_struct *tsk, unsigned long addr,
+                          void *buf, int len, int write);
+
+# define read_proc_vm_atomic(tsk, addr, buf, len) \
+       swap_access_process_vm(tsk, addr, buf, len, 0)
+# define write_proc_vm_atomic(tsk, addr, buf, len) \
+       swap_access_process_vm(tsk, addr, buf, len, 1)
+
+#else /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+
+int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr,
+                            void *buf, int len, int write);
+
+# define read_proc_vm_atomic(tsk, addr, buf, len) \
+       access_process_vm_atomic(tsk, addr, buf, len, 0)
+# define write_proc_vm_atomic(tsk, addr, buf, len) \
+       access_process_vm_atomic(tsk, addr, buf, len, 1)
+
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+
+int page_present(struct mm_struct *mm, unsigned long addr);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+unsigned long swap_do_mmap(struct file *file, unsigned long addr,
+                          unsigned long len, unsigned long prot,
+                          unsigned long flags, vm_flags_t vm_flags,
+                          unsigned long pgoff, unsigned long *populate);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+unsigned long swap_do_mmap_pgoff(struct file *file, unsigned long addr,
+                                unsigned long len, unsigned long prot,
+                                unsigned long flags, unsigned long pgoff,
+                                unsigned long *populate);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+unsigned long swap_do_mmap_pgoff(struct file *file, unsigned long addr,
+                                unsigned long len, unsigned long prot,
+                                unsigned long flags, unsigned long pgoff);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0)
+#define swap_hlist_add_after(node, prev) hlist_add_behind(node, prev)
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
+#define swap_hlist_add_after(node, prev) hlist_add_after(node, prev)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 18, 0)
+#define __get_cpu_var(var) (*this_cpu_ptr(&(var)))
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 18, 0) */
+
+#endif /* _SWAP_KPROBES_DEPS_H */
diff --git a/modules/kprobe/swap_ktd.c b/modules/kprobe/swap_ktd.c
new file mode 100644 (file)
index 0000000..4947d37
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <ksyms/ksyms.h>
+#include "swap_ktd.h"
+#include "swap_td_raw.h"
+
+
+#define KTD_PREFIX             "[SWAP_KTD] "
+#define kTD_JOBCTL_PREPARE     (1 << 31)
+#define KTD_BIT_MAX            (sizeof(unsigned long) * 8)
+
+
+struct td {
+       struct list_head list;
+       struct task_struct *task;
+
+       spinlock_t flags_lock;
+       unsigned long init_flags;
+};
+
+
+static struct td_raw td_raw;
+static LIST_HEAD(prepare_list);
+static DEFINE_RWLOCK(prepare_lock);
+static int preparing_cnt = 0;
+
+
+static DEFINE_MUTEX(mutex_ktd_nr);
+static struct ktask_data *ktd_array[KTD_BIT_MAX];
+
+
+static bool ktd_init_is(struct ktask_data *ktd, struct td *td)
+{
+       return !!(td->init_flags & (1 << ktd->nr_bit));
+}
+
+static void ktd_init(struct ktask_data *ktd, struct td *td,
+                    struct task_struct *task)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&td->flags_lock, flags);
+       if (ktd_init_is(ktd, td))
+               goto unlock;
+
+       if (ktd->init)
+               ktd->init(task, swap_td_raw(&ktd->td_raw, task));
+
+       td->init_flags |= 1 << ktd->nr_bit;
+
+unlock:
+       spin_unlock_irqrestore(&td->flags_lock, flags);
+}
+
+static void ktd_exit_no_lock(struct ktask_data *ktd, struct td *td,
+                            struct task_struct *task)
+{
+       if (ktd_init_is(ktd, td)) {
+               if (ktd->exit)
+                       ktd->exit(task, swap_td_raw(&ktd->td_raw, task));
+
+               td->init_flags &= ~(1 << ktd->nr_bit);
+       }
+}
+
+static void ktd_exit_all(struct td *td, struct task_struct *task)
+{
+       unsigned long flags;
+       unsigned long init_flags;
+       int nr_bit = 0;
+
+       spin_lock_irqsave(&td->flags_lock, flags);
+       init_flags = td->init_flags;
+       do {
+               if (init_flags & 1)
+                       ktd_exit_no_lock(ktd_array[nr_bit], td, task);
+
+               ++nr_bit;
+               init_flags >>= 1;
+       } while (init_flags);
+       td->init_flags = 0;
+       spin_unlock_irqrestore(&td->flags_lock, flags);
+}
+
+
+static bool task_prepare_is(struct task_struct *task)
+{
+       return !!(task_job(task) & kTD_JOBCTL_PREPARE);
+}
+
+static void task_prepare_set(struct task_struct *task)
+{
+       if (!(task_job(task) & kTD_JOBCTL_PREPARE))
+               task_job(task) |= kTD_JOBCTL_PREPARE;
+       else
+               WARN(1, KTD_PREFIX "already prepare");
+
+       ++preparing_cnt;
+}
+
+static void task_prepare_clear(struct task_struct *task)
+{
+       if (task_job(task) & kTD_JOBCTL_PREPARE)
+               task_job(task) &= ~kTD_JOBCTL_PREPARE;
+       else
+               WARN(1, KTD_PREFIX "is not prepare");
+
+       --preparing_cnt;
+}
+
+static struct task_struct *task_by_td(struct td *td)
+{
+       return td->task;
+}
+
+static struct td *td_by_task(struct task_struct *task)
+{
+       return (struct td *)swap_td_raw(&td_raw, task);
+}
+
+
+static void task_prepare(struct task_struct *task, struct td *td,
+                        struct ktask_data *ktd)
+{
+       unsigned long flags;
+
+       write_lock_irqsave(&prepare_lock, flags);
+
+       /* skip multi-preparing task */
+       if (task_prepare_is(task))
+               goto unlock;
+
+       task_prepare_set(task);
+
+       INIT_LIST_HEAD(&td->list);
+       td->task = task;
+       spin_lock_init(&td->flags_lock);
+       td->init_flags = 0;
+
+       /* add to prepare_list */
+       list_add(&td->list, &prepare_list);
+
+unlock:
+       write_unlock_irqrestore(&prepare_lock, flags);
+}
+
+static void ktd_exit_all(struct td *td, struct task_struct *task);
+
+static void td_prepare_clear_no_lock(struct td *td, struct task_struct *task)
+{
+       if (task_prepare_is(task)) {
+               task_prepare_clear(task);
+
+               ktd_exit_all(td, task);
+
+               /* delete from prepare_list */
+               list_del(&td->list);
+       }
+}
+
+static void td_prepare_clear(struct td *td, struct task_struct *task)
+{
+       unsigned long flags;
+
+       write_lock_irqsave(&prepare_lock, flags);
+       td_prepare_clear_no_lock(td, task);
+       write_unlock_irqrestore(&prepare_lock, flags);
+}
+
+void *swap_ktd(struct ktask_data *ktd, struct task_struct *task)
+{
+       struct td *td = td_by_task(task);
+
+       if (!likely(task_prepare_is(task)))
+               task_prepare(task, td, ktd);
+
+       if (!likely(ktd_init_is(ktd, td)))
+               ktd_init(ktd, td, task);
+
+       return swap_td_raw(&ktd->td_raw, task);
+}
+EXPORT_SYMBOL_GPL(swap_ktd);
+
+
+static int ktd_nr_get_free_bit(void)
+{
+       int bit;
+
+       for (bit = 0; bit < KTD_BIT_MAX; ++bit) {
+               if (ktd_array[bit] == NULL)
+                       return bit;
+       }
+
+       return -ENOMEM;
+}
+
+int swap_ktd_reg(struct ktask_data *ktd)
+{
+       int ret;
+       int free_bit;
+
+       mutex_lock(&mutex_ktd_nr);
+       free_bit = ktd_nr_get_free_bit();
+
+       if (free_bit < 0) {
+               ret = free_bit;
+               goto unlock;
+       }
+
+       ret = swap_td_raw_reg(&ktd->td_raw, ktd->size);
+       if (ret)
+               goto unlock;
+
+       ktd->nr_bit = free_bit;
+       ktd_array[free_bit] = ktd;
+unlock:
+       mutex_unlock(&mutex_ktd_nr);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_ktd_reg);
+
+void swap_ktd_unreg(struct ktask_data *ktd)
+{
+       struct td *td;
+       unsigned long flags;
+
+       /* exit all task */
+       read_lock_irqsave(&prepare_lock, flags);
+       list_for_each_entry(td, &prepare_list, list) {
+               spin_lock(&td->flags_lock);
+               ktd_exit_no_lock(ktd, td, task_by_td(td));
+               spin_unlock(&td->flags_lock);
+       }
+       read_unlock_irqrestore(&prepare_lock, flags);
+
+       mutex_lock(&mutex_ktd_nr);
+
+       ktd_array[ktd->nr_bit] = NULL;
+       swap_td_raw_unreg(&ktd->td_raw);
+
+       mutex_unlock(&mutex_ktd_nr);
+}
+EXPORT_SYMBOL_GPL(swap_ktd_unreg);
+
+
+static void do_put_task(struct task_struct *task)
+{
+       if (task_prepare_is(task))
+               td_prepare_clear(td_by_task(task), task);
+}
+
+#ifdef CONFIG_SWAP_HOOK_TASKDATA
+
+#include <swap/hook_taskdata.h>
+
+static struct hook_taskdata hook_taskdata = {
+       .owner = THIS_MODULE,
+       .put_task = do_put_task,
+};
+
+static int taskdata_init(void)
+{
+       return hook_taskdata_reg(&hook_taskdata);
+}
+
+static void taskdata_uninit(void)
+{
+       hook_taskdata_unreg(&hook_taskdata);
+}
+
+void swap_ktd_put_task(struct task_struct *task)
+{
+}
+
+#else /* CONFIG_SWAP_HOOK_TASKDATA */
+
+static int taskdata_init(void)
+{
+       return 0;
+}
+
+static void taskdata_uninit(void)
+{
+}
+
+void swap_ktd_put_task(struct task_struct *task)
+{
+       do_put_task(task);
+}
+
+#endif /* CONFIG_SWAP_HOOK_TASKDATA */
+
+int swap_ktd_init(void)
+{
+       int ret;
+
+       WARN(preparing_cnt, KTD_PREFIX "preparing_cnt=%d", preparing_cnt);
+
+       preparing_cnt = 0;
+
+       ret = swap_td_raw_reg(&td_raw, sizeof(struct td));
+       if (ret) {
+               pr_err(KTD_PREFIX "registration failed, ret=%d", ret);
+               return ret;
+       }
+
+       ret = taskdata_init();
+       if (ret) {
+               swap_td_raw_unreg(&td_raw);
+               pr_err(KTD_PREFIX "failed to initialize, ret=%d\n", ret);
+       }
+
+       return ret;
+}
+
+void swap_ktd_uninit_top(void)
+{
+       struct td *td;
+       unsigned long flags;
+
+       /* get injected tasks */
+       write_lock_irqsave(&prepare_lock, flags);
+       list_for_each_entry(td, &prepare_list, list) {
+               get_task_struct(task_by_td(td));
+       }
+       write_unlock_irqrestore(&prepare_lock, flags);
+}
+
+void swap_ktd_uninit_bottom(void)
+{
+       struct td *td, *n;
+       unsigned long flags;
+
+       /* remove td injection from tasks and put tasks */
+       write_lock_irqsave(&prepare_lock, flags);
+       list_for_each_entry_safe(td, n, &prepare_list, list) {
+               struct task_struct *task = task_by_td(td);
+
+               td_prepare_clear_no_lock(td, task);
+               put_task_struct(task);
+       }
+       write_unlock_irqrestore(&prepare_lock, flags);
+
+       taskdata_uninit();
+       swap_td_raw_unreg(&td_raw);
+
+       WARN(preparing_cnt, KTD_PREFIX "preparing_cnt=%d", preparing_cnt);
+}
diff --git a/modules/kprobe/swap_ktd.h b/modules/kprobe/swap_ktd.h
new file mode 100644 (file)
index 0000000..664f539
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_TD_H
+#define _SWAP_TD_H
+
+
+#include <linux/list.h>
+#include "swap_td_raw.h"
+
+struct task_struct;
+
+struct ktask_data {
+       int nr_bit;
+       struct td_raw td_raw;
+
+       /* init() and exit() may be called in atomic context */
+       void (*init)(struct task_struct *, void *);
+       void (*exit)(struct task_struct *, void *);
+       unsigned long size;
+};
+
+
+int swap_ktd_reg(struct ktask_data *ktd);
+void swap_ktd_unreg(struct ktask_data *ktd);
+
+void *swap_ktd(struct ktask_data *ktd, struct task_struct *task);
+
+int swap_ktd_init(void);
+void swap_ktd_uninit_top(void);
+void swap_ktd_uninit_bottom(void);
+void swap_ktd_put_task(struct task_struct *task);
+
+
+#endif /* _SWAP_TD_H */
diff --git a/modules/kprobe/swap_no_kprobes.c b/modules/kprobe/swap_no_kprobes.c
new file mode 100644 (file)
index 0000000..ecec419
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <kprobe/swap_ktd.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <master/swap_initializer.h>
+
+
+static void ktd_uninit(void)
+{
+       swap_ktd_uninit_top();
+       swap_ktd_uninit_bottom();
+}
+
+SWAP_LIGHT_INIT_MODULE(init_module_dependencies, swap_ktd_init, ktd_uninit, NULL, NULL);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/kprobe/swap_slots.c b/modules/kprobe/swap_slots.c
new file mode 100644 (file)
index 0000000..58869e4
--- /dev/null
@@ -0,0 +1,252 @@
+/**
+ * kprobe/swap_slots.c
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
+ *
+ * @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) IBM Corporation, 2002, 2004
+ * Copyright (C) Samsung Electronics, 2006-2012
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP slots implementation.
+ */
+
+
+#include <linux/module.h>
+#include <linux/rculist.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "swap_slots.h"
+#include "swap_kprobes_deps.h"
+
+
+/**
+ * @struct chunk
+ * @brief Chunk of memory for trampolines.
+ * @var chunk::data
+ * Chunk data.
+ * @var chunk::first_available
+ * Index of the first available block.
+ * @var chunk::count_available
+ * Count of the blocks.
+ * @var chunk::lock
+ * Chunk's lock.
+ * @var chunk::size
+ * Count of the blocks in chunk.
+ * @var chunk::index
+ * Pointer to allocated memory.
+ */
+struct chunk {
+       unsigned long *data;
+       unsigned long first_available;
+       unsigned long count_available;
+
+       spinlock_t    lock;
+       unsigned long size;
+       unsigned long *index;
+};
+
+/**
+ * @struct fixed_alloc
+ * @brief Item of fixed allocs list.
+ * @var fixed_alloc::hlist
+ * Fixed alloc hash list node.
+ * @var fixed_alloc::chunk
+ * Chunk.
+ */
+struct fixed_alloc {
+       struct hlist_node hlist;
+       struct chunk chunk;
+};
+
+static int chunk_init(struct chunk *chunk, void *data,
+                     size_t size, size_t size_block)
+{
+       unsigned long i;
+       unsigned long *p;
+
+       spin_lock_init(&chunk->lock);
+       chunk->data = (unsigned long *)data;
+       chunk->first_available = 0;
+       chunk->count_available = size / size_block;
+       chunk->size = chunk->count_available;
+
+       chunk->index = kmalloc(sizeof(*chunk->index)*chunk->count_available,
+                              GFP_ATOMIC);
+
+       if (chunk->index == NULL) {
+               pr_err("%s: failed to allocate memory\n", __func__);
+               return -ENOMEM;
+       }
+
+       p = chunk->index;
+       for (i = 0; i != chunk->count_available; ++p)
+               *p = ++i;
+
+       return 0;
+}
+
+static void chunk_uninit(struct chunk *chunk)
+{
+       kfree(chunk->index);
+}
+
+static void *chunk_allocate(struct chunk *chunk, size_t size_block)
+{
+       unsigned long *ret;
+
+       if (!chunk->count_available)
+               return NULL;
+
+       spin_lock(&chunk->lock);
+       ret = chunk->data + chunk->first_available*size_block;
+       chunk->first_available = chunk->index[chunk->first_available];
+       --chunk->count_available;
+       spin_unlock(&chunk->lock);
+
+       return ret;
+}
+
+static void chunk_deallocate(struct chunk *chunk, void *p, size_t size_block)
+{
+       unsigned long idx = ((unsigned long *)p - chunk->data)/size_block;
+
+       spin_lock(&chunk->lock);
+       chunk->index[idx] = chunk->first_available;
+       chunk->first_available = idx;
+       ++chunk->count_available;
+       spin_unlock(&chunk->lock);
+}
+
+static inline int chunk_check_ptr(struct chunk *chunk, void *p, size_t size)
+{
+       if ((chunk->data                             <= (unsigned long *)p) &&
+           ((chunk->data + size/sizeof(chunk->data))  > (unsigned long *)p))
+               return 1;
+
+       return 0;
+}
+
+static inline int chunk_free(struct chunk *chunk)
+{
+       return (chunk->count_available == chunk->size);
+}
+
+static struct fixed_alloc *create_fixed_alloc(struct slot_manager *sm)
+{
+       int ret;
+       void *data;
+       struct fixed_alloc *fa;
+
+       fa = kmalloc(sizeof(*fa), GFP_ATOMIC);
+       if (fa == NULL)
+               return NULL;
+
+       data = sm->alloc(sm);
+       if (data == NULL)
+               goto free_fa;
+
+       ret = chunk_init(&fa->chunk, data,
+                        PAGE_SIZE / sizeof(unsigned long), sm->slot_size);
+       if (ret)
+               goto free_sm;
+
+       return fa;
+
+free_sm:
+       sm->free(sm, data);
+free_fa:
+       kfree(fa);
+       return NULL;
+}
+
+static void free_fixed_alloc(struct slot_manager *sm, struct fixed_alloc *fa)
+{
+       chunk_uninit(&fa->chunk);
+       sm->free(sm, fa->chunk.data);
+       kfree(fa);
+}
+
+
+/**
+ * @brief Allocates slot for slot manager.
+ *
+ * @param[in,out] sm Slot manager that should be filled.
+ * @return Pointer to allocated slot.
+ */
+void *swap_slot_alloc(struct slot_manager *sm)
+{
+       void *free_slot;
+       struct fixed_alloc *fa;
+       DECLARE_NODE_PTR_FOR_HLIST(pos);
+
+       swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
+               free_slot = chunk_allocate(&fa->chunk, sm->slot_size);
+               if (free_slot)
+                       return free_slot;
+       }
+
+       fa = create_fixed_alloc(sm);
+       if (fa == NULL)
+               return NULL;
+
+       INIT_HLIST_NODE(&fa->hlist);
+       hlist_add_head_rcu(&fa->hlist, &sm->page_list);
+
+       return chunk_allocate(&fa->chunk, sm->slot_size);
+}
+EXPORT_SYMBOL_GPL(swap_slot_alloc);
+
+/**
+ * @brief Releases allocated slot.
+ *
+ * @param sm Pointer to the target slot manager.
+ * @param slot Pointer to the target slot.
+ * @return Void.
+ */
+void swap_slot_free(struct slot_manager *sm, void *slot)
+{
+       struct fixed_alloc *fa;
+       DECLARE_NODE_PTR_FOR_HLIST(pos);
+
+       if (slot == NULL)
+               return;
+
+       swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
+               if (!chunk_check_ptr(&fa->chunk, slot, PAGE_SIZE))
+                       continue;
+
+               chunk_deallocate(&fa->chunk, slot, sm->slot_size);
+
+               if (chunk_free(&fa->chunk)) {
+                       hlist_del_rcu(&fa->hlist);
+                       free_fixed_alloc(sm, fa);
+               }
+
+               return;
+       }
+
+       panic("%s: slot=%p is not data base\n", __func__, slot);
+}
+EXPORT_SYMBOL_GPL(swap_slot_free);
diff --git a/modules/kprobe/swap_slots.h b/modules/kprobe/swap_slots.h
new file mode 100644 (file)
index 0000000..129a439
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * @file kprobe/swap_slots.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
+ * Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
+ *
+ * @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) IBM Corporation, 2002, 2004
+ * Copyright (C) Samsung Electronics, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP slots interface declaration.
+ */
+
+#ifndef _SWAP_SLOTS_H
+#define _SWAP_SLOTS_H
+
+#include <linux/types.h>
+
+/**
+ * @struct slot_manager
+ * @brief Manage slots.
+ * @var slot_manager::slot_size
+ * Size of the slot.
+ * @var slot_manager::alloc
+ * Memory allocation callback.
+ * @var slot_manager::free
+ * Memory release callback.
+ * @var slot_manager::page_list
+ * List of pages.
+ * @var slot_manager::data
+ * Slot manager data. task_struct pointer usually stored here.
+ */
+struct slot_manager {
+       unsigned long slot_size;        /* FIXME: allocated in long (4 byte) */
+       void *(*alloc)(struct slot_manager *sm);
+       void (*free)(struct slot_manager *sm, void *ptr);
+       struct hlist_head page_list;
+       void *data;
+};
+
+void *swap_slot_alloc(struct slot_manager *sm);
+void swap_slot_free(struct slot_manager *sm, void *slot);
+
+#endif /* _SWAP_SLOTS_H */
diff --git a/modules/kprobe/swap_td_raw.c b/modules/kprobe/swap_td_raw.c
new file mode 100644 (file)
index 0000000..9985d06
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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
+ *
+ * 2014         Vasiliy Ulyanov <v.ulyanov@samsung.com>
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include "swap_td_raw.h"
+
+
+#define TD_OFFSET              1  /* skip STACK_END_MAGIC */
+#define TD_PREFIX              "[SWAP_TD_RAW] "
+#define TD_STACK_USAGE_MAX     0x200
+#define TD_CHUNK_MIN           sizeof(long)
+
+
+static DEFINE_MUTEX(mutex_stack_usage);
+static unsigned long stack_usage = 0;
+static LIST_HEAD(td_raw_list);
+
+
+/*
+ * take small area from stack
+ *
+ * 0x00 +--------------------------+
+ *      |      STACK_END_MAGIC     |
+ *      +--------------------------+  <-- bottom of stack;
+ *      |                          |
+ *      |           stack          |
+ *      |                          |
+ * 0xff
+ *
+ */
+
+static void *bottom_of_stack(struct task_struct *task)
+{
+       return (void *)(end_of_stack(task) + TD_OFFSET);
+}
+
+int swap_td_raw_reg(struct td_raw *raw, unsigned long size)
+{
+       int ret = 0;
+
+       size = (size / TD_CHUNK_MIN + !!(size % TD_CHUNK_MIN)) * TD_CHUNK_MIN;
+
+       mutex_lock(&mutex_stack_usage);
+       if (stack_usage + size > TD_STACK_USAGE_MAX) {
+               pr_warn(TD_PREFIX "free stack ended: usage=%ld size=%ld\n",
+                       stack_usage, size);
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+       raw->offset = stack_usage;
+
+       INIT_LIST_HEAD(&raw->list);
+       list_add(&raw->list, &td_raw_list);
+
+       stack_usage += size;
+
+unlock:
+       mutex_unlock(&mutex_stack_usage);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_td_raw_reg);
+
+void swap_td_raw_unreg(struct td_raw *raw)
+{
+       mutex_lock(&mutex_stack_usage);
+
+       list_del(&raw->list);
+       if (list_empty(&td_raw_list))
+               stack_usage = 0;
+
+       mutex_unlock(&mutex_stack_usage);
+}
+EXPORT_SYMBOL_GPL(swap_td_raw_unreg);
+
+void *swap_td_raw(struct td_raw *raw, struct task_struct *task)
+{
+       return bottom_of_stack(task) + raw->offset;
+}
+EXPORT_SYMBOL_GPL(swap_td_raw);
+
+int swap_td_raw_init(void)
+{
+       WARN_ON(stack_usage);
+
+       stack_usage = 0;
+
+       return 0;
+}
+
+void swap_td_raw_uninit(void)
+{
+       WARN_ON(!list_empty(&td_raw_list));
+       WARN_ON(stack_usage);
+}
diff --git a/modules/kprobe/swap_td_raw.h b/modules/kprobe/swap_td_raw.h
new file mode 100644 (file)
index 0000000..079b153
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ * 2014         Vasiliy Ulyanov <v.ulyanov@samsung.com>
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_TD_RAW_H
+#define _SWAP_TD_RAW_H
+
+
+#include <linux/list.h>
+
+
+struct td_raw {
+       struct list_head list;
+       unsigned long offset;
+};
+
+
+int swap_td_raw_reg(struct td_raw *raw, unsigned long size);
+void swap_td_raw_unreg(struct td_raw *raw);
+
+void *swap_td_raw(struct td_raw *raw, struct task_struct *task);
+
+int swap_td_raw_init(void);
+void swap_td_raw_uninit(void);
+
+
+#endif /* _SWAP_TD_RAW_H */
diff --git a/modules/ks_features/Kbuild b/modules/ks_features/Kbuild
new file mode 100644 (file)
index 0000000..94a041a
--- /dev/null
@@ -0,0 +1,10 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers \
+                       $(src)/../writer/Module.symvers
+
+obj-m := swap_ks_features.o
+swap_ks_features-y := ks_features.o \
+                      ks_features_data.o \
+                      ks_map.o \
+                      file_ops.o \
+                      ksf_msg.o
diff --git a/modules/ks_features/features_data.c b/modules/ks_features/features_data.c
new file mode 100644 (file)
index 0000000..5b847e4
--- /dev/null
@@ -0,0 +1,330 @@
+/**
+ * ks_features/features_data.c
+ * @author Vyacheslav Cherkashin: SWAP ks_features implement
+ *
+ * @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
+ *
+ * SWAP kernel features
+ */
+
+
+#include "ksf_msg.h"
+#include "syscall_list.h"
+
+
+/**
+ * @struct feature
+ * Feature description.
+ * @var feature::cnt
+ * Syscalls count.
+ * @var feature::feature_list
+ * Pointer to feature's syscall list.
+ * @var feature::type
+ * Featue subtype.
+ * @var feature::enable
+ * Is feature enable.
+ */
+struct feature {
+       size_t cnt;
+       enum syscall_id *feature_list;
+       enum probe_t type;
+
+       unsigned enable:1;
+};
+
+/**
+ * @def X
+ * X-macros for syscall list.
+ */
+#define X(name, args) id_sys_##name,
+/**
+ * @enum syscall_id
+ * Syscall list
+ */
+enum syscall_id {
+       SYSCALL_LIST
+};
+#undef X
+
+static enum syscall_id id_none[] = {};
+
+static enum syscall_id id_file[] = {
+       id_sys_acct,
+       id_sys_mount,
+/* TODO:
+ *     id_sys_umount,
+ */
+       id_sys_truncate,
+/* TODO:
+ *     id_sys_stat,
+ */
+       id_sys_statfs,
+       id_sys_statfs64,
+/* TODO:
+ *     id_sys_lstat,
+ */
+       id_sys_stat64,
+       id_sys_fstat64,
+       id_sys_lstat64,
+       id_sys_truncate64,
+       id_sys_ftruncate64,
+       id_sys_setxattr,
+       id_sys_getxattr,
+       id_sys_listxattr,
+       id_sys_removexattr,
+       id_sys_chroot,
+       id_sys_mknod,
+       id_sys_link,
+       id_sys_symlink,
+       id_sys_unlink,
+       id_sys_rename,
+       id_sys_chmod,
+       id_sys_readlink,
+       id_sys_creat,
+       id_sys_open,
+       id_sys_access,
+       id_sys_chown,
+/* TODO:
+ *     id_sys_chown16,
+ *     id_sys_utime,
+ */
+       id_sys_utimes,
+       id_sys_pread64,
+       id_sys_pwrite64,
+       id_sys_preadv,
+       id_sys_pwritev,
+       id_sys_getcwd,
+       id_sys_mkdir,
+       id_sys_chdir,
+       id_sys_rmdir,
+       id_sys_swapon,
+       id_sys_swapoff,
+       id_sys_uselib,
+       id_sys_mknodat,
+       id_sys_mkdirat,
+       id_sys_unlinkat,
+       id_sys_symlinkat,
+       id_sys_linkat,
+       id_sys_renameat,
+       id_sys_futimesat,
+       id_sys_faccessat,
+       id_sys_fchmodat,
+       id_sys_fchownat,
+       id_sys_openat,
+/* TODO:
+ *     id_sys_newfstatat,
+ */
+       id_sys_readlinkat,
+       id_sys_utimensat,
+       id_sys_fanotify_mark,
+       id_sys_execve,
+       id_sys_name_to_handle_at,
+       id_sys_open_by_handle_at
+};
+
+static enum syscall_id id_ipc[] = {
+       id_sys_msgget,
+       id_sys_msgsnd,
+       id_sys_msgrcv,
+       id_sys_msgctl,
+       id_sys_semget,
+       id_sys_semop,
+       id_sys_semctl,
+       id_sys_semtimedop,
+       id_sys_shmat,
+       id_sys_shmget,
+       id_sys_shmdt,
+       id_sys_shmctl,
+/* TODO:
+ *     id_sys_ipc
+ */
+};
+
+static enum syscall_id id_net[] = {
+       id_sys_shutdown,
+       id_sys_sendfile,
+       id_sys_sendfile64,
+       id_sys_setsockopt,
+       id_sys_getsockopt,
+       id_sys_bind,
+       id_sys_connect,
+       id_sys_accept,
+       id_sys_accept4,
+       id_sys_getsockname,
+       id_sys_getpeername,
+       id_sys_send,
+       id_sys_sendto,
+       id_sys_sendmsg,
+       id_sys_sendmmsg,
+       id_sys_recv,
+       id_sys_recvfrom,
+       id_sys_recvmsg,
+       id_sys_recvmmsg,
+       id_sys_socket,
+       id_sys_socketpair,
+/* TODO:
+ *     id_sys_socketcall,
+ */
+       id_sys_listen
+};
+
+static enum syscall_id id_process[] = {
+       id_sys_exit,
+       id_sys_exit_group,
+       id_sys_wait4,
+       id_sys_waitid,
+/* TODO:
+ *     id_sys_waitpid,
+ */
+       id_sys_rt_tgsigqueueinfo,
+       id_sys_unshare,
+       id_sys_fork,
+       id_sys_vfork,
+/* TODO: add support CONFIG_CLONE_BACKWARDS
+ *     id_sys_clone,
+ *     id_sys_clone,
+ */
+       id_sys_execve
+};
+
+static enum syscall_id id_signal[] = {
+       id_sys_sigpending,
+       id_sys_sigprocmask,
+/* TODO:
+ *     id_sys_sigaltstack,
+ */
+/* TODO: add support CONFIG_OLD_SIGSUSPEND and CONFIG_OLD_SIGSUSPEND3
+ *     id_sys_sigsuspend,
+ *     id_sys_sigsuspend,
+ */
+       id_sys_rt_sigsuspend,
+       id_sys_sigaction,
+       id_sys_rt_sigaction,
+       id_sys_rt_sigprocmask,
+       id_sys_rt_sigtimedwait,
+       id_sys_rt_tgsigqueueinfo,
+       id_sys_kill,
+       id_sys_tgkill,
+/* TODO:
+ *     id_sys_signal,
+ */
+       id_sys_pause,
+       id_sys_signalfd,
+       id_sys_signalfd4
+};
+
+static enum syscall_id id_desc[] = {
+       id_sys_fgetxattr,
+       id_sys_flistxattr,
+       id_sys_fremovexattr,
+/* TODO:
+ *     id_sys_fadvise64_64,
+ */
+       id_sys_pipe2,
+       id_sys_dup3,
+       id_sys_sendfile,
+       id_sys_sendfile64,
+       id_sys_preadv,
+       id_sys_pwritev,
+       id_sys_epoll_create1,
+       id_sys_epoll_ctl,
+       id_sys_epoll_wait,
+       id_sys_epoll_pwait,
+       id_sys_inotify_init,
+       id_sys_inotify_init1,
+       id_sys_inotify_add_watch,
+       id_sys_inotify_rm_watch,
+       id_sys_mknodat,
+       id_sys_mkdirat,
+       id_sys_unlinkat,
+       id_sys_symlinkat,
+       id_sys_linkat,
+       id_sys_renameat,
+       id_sys_futimesat,
+       id_sys_faccessat,
+       id_sys_fchmodat,
+       id_sys_fchownat,
+       id_sys_openat,
+/* TODO:
+ *     id_sys_newfstatat,
+ */
+       id_sys_readlinkat,
+       id_sys_utimensat,
+       id_sys_splice,
+       id_sys_vmsplice,
+       id_sys_tee,
+       id_sys_signalfd,
+       id_sys_signalfd4,
+       id_sys_timerfd_create,
+       id_sys_timerfd_settime,
+       id_sys_timerfd_gettime,
+       id_sys_eventfd,
+       id_sys_eventfd2,
+       id_sys_fallocate,
+       id_sys_pselect6,
+       id_sys_ppoll,
+       id_sys_fanotify_init,
+       id_sys_fanotify_mark,
+       id_sys_syncfs,
+/* TODO:
+ *     id_sys_mmap_pgoff,
+ *     id_sys_old_mmap,
+ */
+       id_sys_name_to_handle_at,
+       id_sys_setns
+};
+
+/**
+ * @def CREATE_FEATURE
+ * Feature initialization.
+ */
+#define CREATE_FEATURE(x, _type)                               \
+{                                                              \
+       .cnt = sizeof(x) / sizeof(enum syscall_id),             \
+       .feature_list = x,                                      \
+       .type = _type,                                          \
+       .enable = 0                                             \
+}
+
+static struct feature features[] = {
+       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)
+};
+
+/**
+ * @enum
+ * Defines feature_cnt.
+ */
+enum {
+       feature_cnt = sizeof(features) / sizeof(struct feature)
+};
+
+static int feature_index(struct feature *f)
+{
+       return f - features;
+}
diff --git a/modules/ks_features/file_ops.c b/modules/ks_features/file_ops.c
new file mode 100644 (file)
index 0000000..7954528
--- /dev/null
@@ -0,0 +1,751 @@
+#include <linux/kconfig.h>
+
+#ifndef CONFIG_SWAP_HOOK_SYSCALL
+
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/percpu.h>
+#include <linux/namei.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <writer/event_filter.h>
+#include "ks_map.h"
+#include "ksf_msg.h"
+#include "file_ops.h"
+
+#define FOPS_PREFIX "[FILE_OPS] "
+
+#define PT_FILE 0x4 /* probe type FILE(04) */
+
+/* path buffer size */
+enum { PATH_LEN = 512 };
+
+struct file_probe {
+       int id;
+       const char *args;
+       int subtype;
+       struct kretprobe rp;
+};
+
+#define to_file_probe(_rp) container_of(_rp, struct file_probe, rp)
+
+/* common private data */
+struct file_private {
+       struct dentry *dentry;
+};
+
+/* open/creat private data */
+struct open_private {
+       int dfd;
+       const char __user *name;
+       int ret;
+};
+
+/* locks private data */
+struct flock_private {
+       struct dentry *dentry;
+       int subtype;
+};
+
+#define DECLARE_HANDLER(_name) \
+       int _name(struct kretprobe_instance *, struct pt_regs *)
+
+/* generic handlers forward declaration */
+static DECLARE_HANDLER(generic_entry_handler);
+static DECLARE_HANDLER(generic_ret_handler);
+/* open/creat handlers */
+static DECLARE_HANDLER(open_entry_handler);
+static DECLARE_HANDLER(open_ret_handler);
+/* lock handlers */
+static DECLARE_HANDLER(lock_entry_handler);
+static DECLARE_HANDLER(lock_ret_handler);
+/* filp_close helper handlers */
+static DECLARE_HANDLER(filp_close_entry_handler);
+static DECLARE_HANDLER(filp_close_ret_handler);
+
+#define FILE_OPS_OPEN_LIST \
+       X(sys_open, sdd), \
+       X(sys_openat, dsdd), \
+       X(sys_creat, sd)
+
+#define FILE_OPS_CLOSE_LIST \
+       X(sys_close, d)
+
+#define FILE_OPS_READ_LIST \
+       X(sys_read, dpd), \
+       X(sys_readv, dpd), \
+       X(sys_pread64, dpxx), \
+       X(sys_preadv, dpxxx)
+
+#define FILE_OPS_WRITE_LIST \
+       X(sys_write, dpd), \
+       X(sys_writev, dpd), \
+       X(sys_pwrite64, dpxx), \
+       X(sys_pwritev, dpxxx)
+
+#define FILE_OPS_LOCK_LIST \
+       X(sys_fcntl, ddd), \
+       X(sys_fcntl64, ddd), \
+       X(sys_flock, dd)
+
+#define FILE_OPS_LIST \
+       FILE_OPS_OPEN_LIST, \
+       FILE_OPS_CLOSE_LIST, \
+       FILE_OPS_READ_LIST, \
+       FILE_OPS_WRITE_LIST, \
+       FILE_OPS_LOCK_LIST
+
+#define X(_name, _args) \
+       id_##_name
+enum {
+       FILE_OPS_LIST
+};
+#undef X
+
+#define __FILE_PROBE_INITIALIZER(_name, _args, _subtype, _dtype, _entry, _ret) \
+       { \
+               .id = id_##_name, \
+               .args = #_args, \
+               .subtype = _subtype, \
+               .rp = { \
+                       .kp.symbol_name = #_name, \
+                       .data_size = sizeof(_dtype), \
+                       .entry_handler = _entry, \
+                       .handler = _ret, \
+               } \
+       }
+
+static struct file_probe fprobes[] = {
+#define X(_name, _args) \
+       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_OPEN, \
+                                               struct open_private, \
+                                               open_entry_handler, \
+                                               open_ret_handler)
+       FILE_OPS_OPEN_LIST,
+#undef X
+
+#define X(_name, _args) \
+       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_CLOSE, \
+                                               struct file_private, \
+                                               generic_entry_handler, \
+                                               generic_ret_handler)
+       FILE_OPS_CLOSE_LIST,
+#undef X
+
+#define X(_name, _args) \
+       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_READ, \
+                                               struct file_private, \
+                                               generic_entry_handler, \
+                                               generic_ret_handler)
+       FILE_OPS_READ_LIST,
+#undef X
+
+#define X(_name, _args) \
+       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_WRITE, \
+                                               struct file_private, \
+                                               generic_entry_handler, \
+                                               generic_ret_handler)
+       FILE_OPS_WRITE_LIST,
+#undef X
+
+#define X(_name, _args) \
+       [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_OTHER, \
+                                               struct flock_private, \
+                                               lock_entry_handler, \
+                                               lock_ret_handler)
+       FILE_OPS_LOCK_LIST
+#undef X
+};
+
+static void *fops_key_func(void *);
+static int fops_cmp_func(void *, void *);
+
+/* percpu buffer to hold the filepath inside handlers */
+static DEFINE_PER_CPU(char[PATH_LEN], __path_buf);
+
+/* map to hold 'interesting' files */
+static DEFINE_MAP(__map, fops_key_func, fops_cmp_func);
+static DEFINE_RWLOCK(__map_lock);
+
+/* enabled/disabled flag */
+static int fops_enabled;
+static DEFINE_MUTEX(fops_lock);
+
+/* GET/PUT debug stuff */
+static int file_get_put_balance;
+static int dentry_get_put_balance;
+
+/* helper probe */
+static struct kretprobe filp_close_krp = {
+       .kp.symbol_name = "filp_close",
+       .data_size = 0,
+       .entry_handler = filp_close_entry_handler,
+       .handler = filp_close_ret_handler
+};
+
+/* should be called only from handlers (with preemption disabled) */
+static inline char *fops_path_buf(void)
+{
+       return __get_cpu_var(__path_buf);
+}
+
+static inline unsigned fops_dcount(const struct dentry *dentry)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
+       return dentry->d_count;
+#else
+       return d_count(dentry);
+#endif
+}
+
+/* kernel function args */
+#define fops_karg(_type, _regs, _idx) ((_type)swap_get_karg(_regs, _idx))
+/* syscall args */
+#define fops_sarg(_type, _regs, _idx) ((_type)swap_get_sarg(_regs, _idx))
+/* retval */
+#define fops_ret(_type, _regs) ((_type)regs_return_value(_regs))
+
+#define F_ADDR(_rp) ((unsigned long)(_rp)->kp.addr) /* function address */
+#define R_ADDR(_ri) ((unsigned long)(_ri)->ret_addr) /* return adress */
+
+static void *fops_key_func(void *data)
+{
+       /* use ((struct dentry *)data)->d_inode pointer as map key to handle
+        * symlinks/hardlinks the same way as the original file */
+       return data;
+}
+
+static int fops_cmp_func(void *key_a, void *key_b)
+{
+       return key_a - key_b;
+}
+
+static inline struct map *__get_map(void)
+{
+       return &__map;
+}
+
+static inline struct map *get_map_read(void)
+{
+       read_lock(&__map_lock);
+
+       return __get_map();
+}
+
+static inline void put_map_read(struct map *map)
+{
+       read_unlock(&__map_lock);
+}
+
+static inline struct map *get_map_write(void)
+{
+       write_lock(&__map_lock);
+
+       return __get_map();
+}
+
+static inline void put_map_write(struct map *map)
+{
+       write_unlock(&__map_lock);
+}
+
+static struct file *__fops_fget(int fd)
+{
+       struct file *file;
+
+       file = fget(fd);
+       if (IS_ERR_OR_NULL(file))
+               file = NULL;
+       else
+               file_get_put_balance++;
+
+       return file;
+}
+
+static void __fops_fput(struct file *file)
+{
+       file_get_put_balance--;
+       fput(file);
+}
+
+static struct dentry *__fops_dget(struct dentry *dentry)
+{
+       dentry_get_put_balance++;
+
+       return dget(dentry);
+}
+
+static void __fops_dput(struct dentry *dentry)
+{
+       dentry_get_put_balance--;
+       dput(dentry);
+}
+
+static int fops_dinsert(struct dentry *dentry)
+{
+       struct map *map;
+       int ret;
+
+       map = get_map_write();
+       ret = insert(map, __fops_dget(dentry));
+       put_map_write(map);
+
+       if (ret)
+               __fops_dput(dentry);
+
+       /* it's ok if dentry is already inserted */
+       return ret == -EEXIST ? 0 : ret;
+}
+
+static struct dentry *fops_dsearch(struct dentry *dentry)
+{
+       struct dentry *found;
+       struct map *map;
+
+       map = get_map_read();
+       found = search(map, map->key_f(dentry));
+       put_map_read(map);
+
+       return found;
+}
+
+static struct dentry *fops_dremove(struct dentry *dentry)
+{
+       struct dentry *removed;
+       struct map *map;
+
+       map = get_map_write();
+       removed = remove(map, map->key_f(dentry));
+       put_map_write(map);
+
+       if (removed)
+               __fops_dput(removed);
+
+       return removed;
+}
+
+static int fops_fcheck(struct task_struct *task, struct file *file)
+{
+       struct dentry *dentry;
+
+       if (!task || !file)
+               return -EINVAL;
+
+       dentry = file->f_path.dentry;
+
+       /* check if it is a regular file */
+       if (!S_ISREG(dentry->d_inode->i_mode))
+               return -EBADF;
+
+       if (check_event(task))
+               /* it is 'our' task: just add the dentry to the map */
+               return fops_dinsert(dentry) ? : -EAGAIN;
+       else
+               /* not 'our' task: check if the file is 'interesting' */
+               return fops_dsearch(dentry) ? 0 : -ESRCH;
+}
+
+static char *fops_fpath(struct file *file, char *buf, int buflen)
+{
+       char *filename;
+
+       path_get(&file->f_path);
+       filename = d_path(&file->f_path, buf, buflen);
+       path_put(&file->f_path);
+
+       if (IS_ERR_OR_NULL(filename)) {
+               printk(FOPS_PREFIX "d_path FAILED: %ld\n", PTR_ERR(filename));
+               buf[0] = '\0';
+               filename = buf;
+       }
+
+       return filename;
+}
+
+static int generic_entry_handler(struct kretprobe_instance *ri,
+                                struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+
+       if (rp) {
+               struct file_probe *fprobe = to_file_probe(rp);
+               struct file_private *priv = (struct file_private *)ri->data;
+               int fd = fops_sarg(int, regs, 0);
+               struct file *file = __fops_fget(fd);
+
+               if (fops_fcheck(current, file) == 0) {
+                       char *buf = fops_path_buf();
+
+                       ksf_msg_file_entry(fd, fprobe->subtype,
+                                          fops_fpath(file, buf, PATH_LEN));
+
+                       priv->dentry = file->f_path.dentry;
+               } else {
+                       priv->dentry = NULL;
+               }
+
+               if (file)
+                       __fops_fput(file);
+       }
+
+       return 0;
+}
+
+static int generic_ret_handler(struct kretprobe_instance *ri,
+                              struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+       struct file_private *priv = (struct file_private *)ri->data;
+
+       if (rp && priv->dentry)
+               ksf_msg_file_exit(regs, 'x');
+
+       return 0;
+}
+
+static int open_private_init(const char *args, struct pt_regs *regs,
+                            struct open_private *priv)
+{
+       int ret = 0;
+
+       switch (args[0]) {
+       case 'd': /* file name: relative to fd */
+               if (args[1] != 's') {
+                       ret = -EINVAL;
+                       break;
+               }
+               priv->dfd = fops_sarg(int, regs, 0);
+               priv->name = fops_sarg(const char __user *, regs, 1);
+               break;
+       case 's': /* file name: absolute or relative to CWD */
+               priv->dfd = AT_FDCWD;
+               priv->name = fops_sarg(const char __user *, regs, 0);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       priv->ret = ret;
+
+       return ret;
+}
+
+static int open_entry_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+
+       if (rp) {
+               struct file_probe *fprobe = to_file_probe(rp);
+               struct open_private *priv = (struct open_private *)ri->data;
+
+               open_private_init(fprobe->args, regs, priv);
+               /* FIXME entry event will be sent in open_ret_handler: cannot
+                * perform a file lookup in atomic context */
+       }
+
+       return 0;
+}
+
+static int open_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+       struct open_private *priv = (struct open_private *)ri->data;
+
+       if (rp && priv->ret == 0) {
+               struct file_probe *fprobe = to_file_probe(rp);
+               int fd = fops_ret(int, regs);
+               struct file *file = __fops_fget(fd);
+
+               if (fops_fcheck(current, file) == 0) {
+                       char *buf = fops_path_buf();
+                       const char *path = fops_fpath(file, buf, PATH_LEN);
+
+                       ksf_msg_file_entry_open(fd, fprobe->subtype,
+                                               path, priv->name);
+                       ksf_msg_file_exit(regs, 'x');
+               }
+
+               if (file)
+                       __fops_fput(file);
+       }
+
+       return 0;
+}
+
+/* wrapper for 'struct flock*' data */
+struct lock_arg {
+       int type;
+       int whence;
+       s64 start;
+       s64 len;
+};
+
+/* TODO copy_from_user */
+#define __lock_arg_init(_type, _regs, _arg) \
+       do { \
+               _type __user *flock = fops_sarg(_type __user *, _regs, 2); \
+               _arg->type = flock->l_type; \
+               _arg->whence = flock->l_whence; \
+               _arg->start = flock->l_start; \
+               _arg->len = flock->l_len; \
+       } while (0)
+
+static int lock_arg_init(int id, struct pt_regs *regs, struct lock_arg *arg)
+{
+       unsigned int cmd = fops_sarg(unsigned int, regs, 1);
+       int ret = 0;
+
+       switch (id) {
+       case id_sys_fcntl:
+               if (cmd == F_SETLK || cmd == F_SETLKW)
+                       __lock_arg_init(struct flock, regs, arg);
+               else
+                       ret = -EINVAL;
+               break;
+       case id_sys_fcntl64:
+               if (cmd == F_SETLK64 || cmd == F_SETLKW64)
+                       __lock_arg_init(struct flock64, regs, arg);
+               else if (cmd == F_SETLK || cmd == F_SETLKW)
+                       __lock_arg_init(struct flock, regs, arg);
+               else
+                       ret = -EINVAL;
+               break;
+       case id_sys_flock: /* TODO is it really needed? */
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int lock_entry_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+
+       if (rp) {
+               struct file_probe *fprobe = to_file_probe(rp);
+               struct flock_private *priv = (struct flock_private *)ri->data;
+               int fd = fops_sarg(int, regs, 0);
+               struct file *file = __fops_fget(fd);
+
+               if (fops_fcheck(current, file) == 0) {
+                       int subtype = fprobe->subtype;
+                       struct lock_arg arg;
+                       char *buf, *filepath;
+
+                       buf = fops_path_buf();
+                       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;
+                               ksf_msg_file_entry_lock(fd, subtype, filepath,
+                                                       arg.type, arg.whence,
+                                                       arg.start, arg.len);
+                       } else {
+                               ksf_msg_file_entry(fd, subtype, filepath);
+                       }
+
+                       priv->dentry = file->f_path.dentry;
+                       priv->subtype = subtype;
+               } else {
+                       priv->dentry = NULL;
+               }
+
+               if (file)
+                       __fops_fput(file);
+       }
+
+       return 0;
+}
+
+static int lock_ret_handler(struct kretprobe_instance *ri,
+                           struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+       struct flock_private *priv = (struct flock_private *)ri->data;
+
+       if (rp && priv->dentry)
+               ksf_msg_file_exit(regs, 'x');
+
+       return 0;
+}
+
+static int filp_close_entry_handler(struct kretprobe_instance *ri,
+                                   struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+       struct file *file = fops_karg(struct file *, regs, 0);
+
+       if (rp && file && file_count(file)) {
+               struct dentry *dentry = file->f_path.dentry;
+
+               /* release the file if it is going to be removed soon */
+               if (dentry && fops_dcount(dentry) == 2)
+                       fops_dremove(dentry);
+       }
+
+       return 0;
+}
+
+static int filp_close_ret_handler(struct kretprobe_instance *ri,
+                                 struct pt_regs *regs)
+{
+       return 0;
+}
+
+static void fops_unregister_probes(struct file_probe *fprobes, int cnt)
+{
+       int i = cnt;
+
+       /* probes are unregistered in reverse order */
+       while (--i >= 0) {
+               struct kretprobe *rp = &fprobes[i].rp;
+
+               swap_unregister_kretprobe(rp);
+               printk(FOPS_PREFIX "'%s/%08lx' kretprobe unregistered  (%d)\n",
+                      rp->kp.symbol_name, F_ADDR(rp), i);
+       }
+
+       /* unregister helper probes */
+       swap_unregister_kretprobe(&filp_close_krp);
+}
+
+static int fops_register_probes(struct file_probe *fprobes, int cnt)
+{
+       struct kretprobe *rp = &filp_close_krp;
+       int ret, i = 0;
+
+       /* register helper probes */
+       ret = swap_register_kretprobe(rp);
+       if (ret)
+               goto fail;
+
+       /* register syscalls */
+       for (i = 0; i < cnt; i++) {
+               rp = &fprobes[i].rp;
+
+               if (!rp->entry_handler)
+                       rp->entry_handler = generic_entry_handler;
+
+               if (!rp->handler)
+                       rp->handler = generic_ret_handler;
+
+               ret = swap_register_kretprobe(rp);
+               if (ret)
+                       goto fail_unreg;
+
+               printk(FOPS_PREFIX "'%s/%08lx' kretprobe registered (%d)\n",
+                      rp->kp.symbol_name, F_ADDR(rp), i);
+       }
+
+       return 0;
+
+fail_unreg:
+       fops_unregister_probes(fprobes, i);
+
+fail:
+       printk(FOPS_PREFIX "Failed to register probe: %s\n",
+              rp->kp.symbol_name);
+
+       return ret;
+}
+
+static char *__fops_dpath(struct dentry *dentry, char *buf, int buflen)
+{
+       static const char *NA = "N/A";
+       char *filename = dentry_path_raw(dentry, buf, buflen);
+
+       if (IS_ERR_OR_NULL(filename)) {
+               printk(FOPS_PREFIX "dentry_path_raw FAILED: %ld\n",
+                      PTR_ERR(filename));
+               strncpy(buf, NA, buflen);
+               filename = buf;
+       }
+
+       return filename;
+}
+
+/* just a simple wrapper for passing to clear function */
+static int __fops_dput_wrapper(void *data, void *arg)
+{
+       static char buf[PATH_LEN]; /* called under write lock => static is ok */
+       struct dentry *dentry = data;
+       struct inode *inode = dentry->d_inode;
+
+       printk(FOPS_PREFIX "Releasing dentry(%p/%p/%d): %s\n",
+              dentry, inode, inode ? inode->i_nlink : 0,
+             __fops_dpath(dentry, buf, PATH_LEN));
+       __fops_dput(dentry);
+
+       return 0;
+}
+
+bool file_ops_is_init(void)
+{
+       return fops_enabled;
+}
+
+int file_ops_init(void)
+{
+       int ret = -EINVAL;
+
+       mutex_lock(&fops_lock);
+
+       if (fops_enabled) {
+               printk(FOPS_PREFIX "Handlers already enabled\n");
+               goto unlock;
+       }
+
+       ret = fops_register_probes(fprobes, ARRAY_SIZE(fprobes));
+       if (ret == 0)
+               fops_enabled = 1;
+
+unlock:
+       mutex_unlock(&fops_lock);
+
+       return ret;
+}
+
+void file_ops_exit(void)
+{
+       struct map *map;
+
+       mutex_lock(&fops_lock);
+
+       if (!fops_enabled) {
+               printk(FOPS_PREFIX "Handlers not enabled\n");
+               goto unlock;
+       }
+
+       /* 1. unregister probes */
+       fops_unregister_probes(fprobes, ARRAY_SIZE(fprobes));
+
+       /* 2. clear the map */
+       map = get_map_write();
+       printk(FOPS_PREFIX "Clearing map: entries(%d)\n", map->size);
+       clear(map, __fops_dput_wrapper, NULL);
+       WARN(file_get_put_balance, "File GET/PUT balance: %d\n",
+            file_get_put_balance);
+       WARN(dentry_get_put_balance, "Dentry GET/PUT balance: %d\n",
+            dentry_get_put_balance);
+       put_map_write(map);
+
+       /* 3. drop the flag */
+       fops_enabled = 0;
+
+unlock:
+       mutex_unlock(&fops_lock);
+}
+
+#endif /* CONFIG_SWAP_HOOK_SYSCALL */
diff --git a/modules/ks_features/file_ops.h b/modules/ks_features/file_ops.h
new file mode 100644 (file)
index 0000000..b8344e7
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __FILE_OPS__
+#define __FILE_OPS__
+
+#include <linux/types.h>
+#include <linux/printk.h>
+
+
+#define FOPS_PREFIX "[FILE_OPS] "
+
+
+/* TODO: add support CONFIG_SWAP_HOOK_SYSCALL */
+#ifdef CONFIG_SWAP_HOOK_SYSCALL
+
+static inline bool file_ops_is_init(void)
+{
+       return 0;
+}
+
+static inline bool file_ops_init(void)
+{
+       pr_info(FOPS_PREFIX "file_ops is not supported\n");
+       return 0;
+}
+
+void file_ops_exit(void)
+{
+}
+
+#else /* CONFIG_SWAP_HOOK_SYSCALL */
+
+bool file_ops_is_init(void);
+int file_ops_init(void);
+void file_ops_exit(void);
+
+#endif /* CONFIG_SWAP_HOOK_SYSCALL */
+
+#endif /* __FILE_OPS__ */
diff --git a/modules/ks_features/ks_feature_hook.c b/modules/ks_features/ks_feature_hook.c
new file mode 100644 (file)
index 0000000..a0e60f7
--- /dev/null
@@ -0,0 +1,156 @@
+/**
+ * @author Vyacheslav Cherkashin: SWAP ks_features implement
+ *
+ * @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, 2016
+ *
+ * @section DESCRIPTION
+ *
+ *  SWAP kernel features
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <ksyms/ksyms.h>
+#include <master/swap_initializer.h>
+#include <writer/event_filter.h>
+#include <swap/hook_syscall.h>
+#include <asm/syscall.h>
+#include "ksf_msg.h"
+#include "ks_features.h"
+#include "syscall_list.h"
+#include "features_data.c"
+#include "writer/kernel_operations.h"
+#include "ks_features_data.h"
+
+
+static void syscall_entry_hendler(struct hook_syscall *self,
+                                 struct pt_regs *regs)
+{
+       if (check_event(current)) {
+               struct ks_probe *ksp = container_of(self, struct ks_probe, hook);
+               const char *fmt = ksp->args;
+               const unsigned long func_addr = ksp->sys_addr;
+               enum probe_t type = ksp->type;
+
+               ksf_msg_entry(regs, func_addr, type, fmt);
+       }
+}
+
+static void syscall_exit_hendler(struct hook_syscall *self,
+                                struct pt_regs *regs)
+{
+       if (check_event(current)) {
+               struct ks_probe *ksp = container_of(self, struct ks_probe, hook);
+               const unsigned long func_addr = ksp->sys_addr;
+               const unsigned long ret_addr = get_regs_ret_func(regs);
+               enum probe_t type = ksp->type;
+
+               ksf_msg_exit(regs, func_addr, ret_addr, type, 'x');
+       }
+}
+
+static int register_syscall(size_t id)
+{
+       int ret = 0;
+
+       if (id >= syscall_cnt)
+               return -EINVAL;
+
+       ksp[id].hook.entry = syscall_entry_hendler;
+       ksp[id].hook.exit = syscall_exit_hendler;
+#ifdef CONFIG_COMPAT
+       /* FIXME: add hook_syscall_reg() */
+       ret = hook_syscall_reg_compat(&ksp[id].hook, ksp[id].id);
+#else
+       ret = hook_syscall_reg(&ksp[id].hook, ksp[id].id);
+#endif
+
+       if (ret) {
+               pr_err("ERROR: cannot register hook '%s' id=%zd sysid=%u\n",
+                      get_sys_name(id), id, ksp[id].id);
+       }
+
+       return ret;
+}
+
+static int unregister_syscall(size_t id)
+{
+       if (id >= syscall_cnt)
+               return -EINVAL;
+
+#ifdef CONFIG_COMPAT
+       /* FIXME: add hook_syscall_unreg() */
+       hook_syscall_unreg_compat(&ksp[id].hook);
+#else
+       hook_syscall_unreg(&ksp[id].hook);
+#endif
+
+       return 0;
+}
+
+static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
+{
+       size_t i;
+       int ret = 0;
+
+       for (i = 0; i < cnt; i++) {
+               ret = unregister_syscall(id_p[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int init_syscalls(void)
+{
+       size_t i, sys_id;
+       unsigned long addr;
+       const char *name;
+       const char *sys_call_table_name;
+       unsigned long *syscall_table;
+
+#ifdef CONFIG_COMPAT
+       sys_call_table_name = "compat_sys_call_table";
+#else
+       sys_call_table_name = "sys_call_table";
+#endif
+
+       syscall_table = (unsigned long *)swap_ksyms(sys_call_table_name);
+       if (syscall_table == NULL) {
+               pr_warn("WARN: '%s' not found\n", sys_call_table_name);
+               return 0;
+       }
+
+       for (i = 0; i < syscall_cnt; ++i) {
+               name = get_sys_name(i);
+               sys_id = ksp[i].id;
+               addr = syscall_table[sys_id];
+               if (addr == 0)
+                       pr_warn("WARN: %s() not found\n", name);
+
+               ksp[i].sys_addr = addr;
+       }
+
+       return 0;
+}
diff --git a/modules/ks_features/ks_feature_kprobe.c b/modules/ks_features/ks_feature_kprobe.c
new file mode 100644 (file)
index 0000000..5a47056
--- /dev/null
@@ -0,0 +1,164 @@
+/**
+ * @author Vyacheslav Cherkashin: SWAP ks_features implement
+ *
+ * @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, 2016
+ *
+ * @section DESCRIPTION
+ *
+ *  SWAP kernel features
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <ksyms/ksyms.h>
+#include <kprobe/swap_kprobes.h>
+#include <master/swap_initializer.h>
+#include <writer/event_filter.h>
+#include "ksf_msg.h"
+#include "ks_features.h"
+#include "features_data.c"
+#include "ks_features_data.h"
+
+
+/* ========================= HANDLERS ========================= */
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+
+       if (rp && check_event(current)) {
+               struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
+               const char *fmt = ksp->args;
+               const unsigned long addr = ksp->rp.kp.addr;
+               enum probe_t type = ksp->type;
+
+               ksf_msg_entry(regs, addr, type, fmt);
+       }
+
+       return 0;
+}
+
+static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct kretprobe *rp = ri->rp;
+
+       if (rp && check_event(current)) {
+               struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
+               const unsigned long func_addr = rp->kp.addr;
+               const unsigned long ret_addr = (unsigned long)ri->ret_addr;
+               enum probe_t type = ksp->type;
+
+               ksf_msg_exit(regs, func_addr, ret_addr, type, 'x');
+       }
+
+       return 0;
+}
+
+/* ========================= HANDLERS ========================= */
+
+
+
+
+
+static int register_syscall(size_t id)
+{
+       int ret;
+
+       if (ksp[id].rp.kp.addr == 0)
+               return 0;
+
+       ksp[id].rp.entry_handler = entry_handler;
+       ksp[id].rp.handler = ret_handler;
+
+       ret = swap_register_kretprobe(&ksp[id].rp);
+
+       return ret;
+}
+
+static int unregister_syscall(size_t id)
+{
+       if (ksp[id].rp.kp.addr == 0)
+               return 0;
+
+       swap_unregister_kretprobe(&ksp[id].rp);
+
+       return 0;
+}
+
+static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
+{
+       struct kretprobe **rpp;
+       const size_t end = ((size_t) 0) - 1;
+       size_t i = 0, id;
+       int ret = 0;
+
+       if (cnt == 1)
+               return unregister_syscall(id_p[0]);
+
+       rpp = kmalloc(sizeof(*rpp) * cnt, GFP_KERNEL);
+       --cnt;
+       if (rpp == NULL) {
+               for (; cnt != end; --cnt) {
+                       ret = unregister_syscall(id_p[cnt]);
+                       if (ret)
+                               return ret;
+               }
+               return ret;
+       }
+
+       for (; cnt != end; --cnt) {
+               id = id_p[cnt];
+               if (ksp[id].rp.kp.addr) {
+                               rpp[i] = &ksp[id].rp;
+                               ++i;
+               }
+       }
+
+       swap_unregister_kretprobes(rpp, i);
+       kfree(rpp);
+
+       return 0;
+}
+
+static int init_syscalls(void)
+{
+       size_t i;
+       unsigned long addr, ni_syscall;
+       const char *name;
+
+       ni_syscall = swap_ksyms("sys_ni_syscall");
+
+       for (i = 0; i < syscall_cnt; ++i) {
+               name = get_sys_name(i);
+               addr = swap_ksyms(name);
+               if (addr == 0) {
+                       pr_err("ERROR: %s() not found\n", name);
+               } else if (ni_syscall == addr) {
+                       pr_err("WARN: %s is not install\n", name);
+                       addr = 0;
+               }
+
+               ksp[i].rp.kp.addr = addr;
+       }
+
+       return 0;
+}
diff --git a/modules/ks_features/ks_features.c b/modules/ks_features/ks_features.c
new file mode 100644 (file)
index 0000000..aa2adab
--- /dev/null
@@ -0,0 +1,469 @@
+/**
+ * ks_features/ks_features.c
+ * @author Vyacheslav Cherkashin: SWAP ks_features implement
+ *
+ * @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
+ *
+ *  SWAP kernel features
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <ksyms/ksyms.h>
+#include <master/swap_initializer.h>
+#include <writer/event_filter.h>
+#include "ksf_msg.h"
+#include "ks_features.h"
+#include "file_ops.h"
+
+#ifdef CONFIG_SWAP_HOOK_SYSCALL
+# include "ks_feature_hook.c"
+#else /* CONFIG_SWAP_HOOK_SYSCALL */
+# include "ks_feature_kprobe.c"
+#endif /* CONFIG_SWAP_HOOK_SYSCALL */
+
+
+
+/* ====================== SWITCH_CONTEXT ======================= */
+static DEFINE_MUTEX(mutex_sc_enable);
+static int sc_enable;
+
+
+#ifdef CONFIG_SWAP_HOOK_SWITCH_TO
+
+#include <swap/hook_switch_to.h>
+
+
+static void ksf_switch(struct task_struct *prev, struct task_struct *next)
+{
+       if (check_event(prev))
+               ksf_switch_entry(prev);
+       if (check_event(next))
+               ksf_switch_exit(next);
+}
+
+static struct swap_hook_ctx hook_ctx = {
+       .hook = ksf_switch,
+};
+
+/**
+ * @brief Get scheduler address.
+ *
+ * @return 0 on success, negative error code on error.
+ */
+int init_switch_context(void)
+{
+       return 0;
+}
+
+static int register_ctx_handler(void)
+{
+       return swap_hook_ctx_reg(&hook_ctx);
+}
+
+static void unregister_ctx_handler(void)
+{
+       swap_hook_ctx_unreg(&hook_ctx);
+}
+
+#else  /* CONFIG_SWAP_HOOK_SWITCH_TO */
+
+static int switch_entry_handler(struct kretprobe_instance *ri,
+                               struct pt_regs *regs)
+{
+       if (check_event(current))
+               ksf_switch_entry(current);
+
+       return 0;
+}
+
+static int switch_ret_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       if (check_event(current))
+               ksf_switch_exit(current);
+
+       return 0;
+}
+
+/**
+ * @var switch_rp
+ * Kretprobe for scheduler.
+ */
+struct kretprobe switch_rp = {
+       .entry_handler = switch_entry_handler,
+       .handler = switch_ret_handler
+};
+
+/**
+ * @brief Get scheduler address.
+ *
+ * @return 0 on success, negative error code on error.
+ */
+int init_switch_context(void)
+{
+       switch_rp.kp.addr = swap_ksyms("__switch_to");
+       if (switch_rp.kp.addr == 0) {
+               printk(KERN_INFO "ERROR: not found '__switch_to'\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int register_ctx_handler(void)
+{
+       return swap_register_kretprobe(&switch_rp);
+}
+
+static void unregister_ctx_handler(void)
+{
+       swap_unregister_kretprobe(&switch_rp);
+}
+#endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
+
+
+/**
+ * @brief Unregisters probe on context switching.
+ *
+ * @return Void.
+ */
+void exit_switch_context(void)
+{
+       if (sc_enable)
+               unregister_ctx_handler();
+}
+
+static int register_switch_context(void)
+{
+       int ret = -EINVAL;
+
+       mutex_lock(&mutex_sc_enable);
+       if (sc_enable) {
+               printk(KERN_INFO "switch context profiling is already run!\n");
+               goto unlock;
+       }
+
+       ret = register_ctx_handler();
+       if (ret == 0)
+               sc_enable = 1;
+
+unlock:
+       mutex_unlock(&mutex_sc_enable);
+
+       return ret;
+}
+
+static int unregister_switch_context(void)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_sc_enable);
+       if (sc_enable == 0) {
+               printk(KERN_INFO "switch context profiling is not running!\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       unregister_ctx_handler();
+
+       sc_enable = 0;
+unlock:
+       mutex_unlock(&mutex_sc_enable);
+
+       return ret;
+}
+/* ====================== SWITCH_CONTEXT ======================= */
+
+
+
+
+static void set_pst(struct feature *f, size_t id)
+{
+       ksp[id].type |= f->type;
+}
+
+static void unset_pst(struct feature *f, size_t id)
+{
+       ksp[id].type &= !f->type;
+}
+
+static void do_uninstall_features(struct feature *f, size_t i)
+{
+       int ret;
+       size_t *id_p;
+       size_t id;
+       size_t cnt = 0;
+       const size_t end = ((size_t) 0) - 1;
+
+       id_p = kmalloc(sizeof(id) * (i + 1), GFP_KERNEL);
+       /* NULL check is below in loop */
+
+       for (; i != end; --i) {
+               id = f->feature_list[i];
+
+               if (get_counter(id) == 0) {
+                       printk(KERN_INFO "syscall %s not installed\n",
+                              get_sys_name(id));
+                       kfree(id_p);
+                       BUG();
+               }
+
+               dec_counter(id);
+
+               if (get_counter(id) == 0) {
+                       if (id_p != NULL) {
+                               id_p[cnt] = id;
+                               ++cnt;
+                       } else {
+                               ret = unregister_syscall(id);
+                               if (ret)
+                                       printk(KERN_INFO "syscall %s uninstall error, ret=%d\n",
+                                                  get_sys_name(id), ret);
+                       }
+               }
+
+               unset_pst(f, id);
+       }
+
+       if (id_p != NULL) {
+               unregister_multiple_syscalls(id_p, cnt);
+               kfree(id_p);
+       }
+}
+
+static int do_install_features(struct feature *f)
+{
+       int ret;
+       size_t i, id;
+
+       for (i = 0; i < f->cnt; ++i) {
+               id = f->feature_list[i];
+               set_pst(f, id);
+
+               if (get_counter(id) == 0) {
+                       ret = register_syscall(id);
+                       if (ret) {
+                               printk(KERN_INFO "syscall %s install error, ret=%d\n",
+                                      get_sys_name(id), ret);
+
+                               do_uninstall_features(f, --i);
+                               return ret;
+                       }
+               }
+
+               inc_counter(id);
+       }
+
+       return 0;
+}
+
+static DEFINE_MUTEX(mutex_features);
+
+static int install_features(struct feature *f)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_features);
+       if (f->enable) {
+               printk(KERN_INFO "energy profiling is already run!\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       ret = do_install_features(f);
+
+       f->enable = 1;
+unlock:
+       mutex_unlock(&mutex_features);
+       return ret;
+}
+
+static int uninstall_features(struct feature *f)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_features);
+       if (f->enable == 0) {
+               printk(KERN_INFO "feature[%d] is not running!\n",
+                      feature_index(f));
+               ret = -EINVAL;
+               goto unlock;
+       }
+       do_uninstall_features(f, f->cnt - 1);
+       f->enable = 0;
+unlock:
+       mutex_unlock(&mutex_features);
+
+       return ret;
+}
+
+static struct feature *get_feature(enum feature_id id)
+{
+       if (id < 0 || id >= (int)feature_cnt)
+               return NULL;
+
+       return &features[id];
+}
+
+/**
+ * @brief Sets probes related to specified feature.
+ *
+ * @param id Feature id.
+ * @return 0 on success, negative error code on error.
+ */
+int set_feature(enum feature_id id)
+{
+       struct feature *f;
+       int ret;
+
+       switch (id) {
+       case FID_SYSFILE_ACTIVITY:
+               ret = file_ops_init();
+               break;
+       case FID_SWITCH:
+               ret = register_switch_context();
+               break;
+       default:
+               f = get_feature(id);
+               ret = f ? install_features(f) : -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(set_feature);
+
+/**
+ * @brief Unsets probes related to specified feature.
+ *
+ * @param id Feature id.
+ * @return 0 on success, negative error code on error.
+ */
+int unset_feature(enum feature_id id)
+{
+       struct feature *f;
+       int ret = 0;
+
+       switch (id) {
+       case FID_SYSFILE_ACTIVITY:
+               file_ops_exit();
+               break;
+       case FID_SWITCH:
+               ret = unregister_switch_context();
+               break;
+       default:
+               f = get_feature(id);
+               ret = f ? uninstall_features(f) : -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(unset_feature);
+
+static int init_syscall_features(void)
+{
+       return init_syscalls();
+}
+
+static void uninit_syscall_features(void)
+{
+       size_t id;
+
+       for (id = 0; id < syscall_cnt; ++id) {
+               if (get_counter(id) > 0)
+                       unregister_syscall(id);
+       }
+}
+
+
+static int once(void)
+{
+       int ret;
+
+       ret = init_switch_context();
+       if (ret)
+               return ret;
+
+       ret = init_syscall_features();
+
+       return ret;
+}
+
+static void core_uninit(void)
+{
+       uninit_syscall_features();
+       exit_switch_context();
+
+       if (file_ops_is_init())
+               file_ops_exit();
+}
+
+SWAP_LIGHT_INIT_MODULE(once, NULL, core_uninit, NULL, NULL);
+
+MODULE_LICENSE("GPL");
+
+/* debug */
+static void print_feature(struct feature *f)
+{
+       size_t i;
+
+       for (i = 0; i < f->cnt; ++i)
+               printk(KERN_INFO "    feature[%3zu]: %s\n", i,
+                      get_sys_name(f->feature_list[i]));
+}
+
+/**
+ * @brief Prints features.
+ *
+ * @return Void.
+ */
+void print_features(void)
+{
+       int i;
+
+       printk(KERN_INFO "print_features:\n");
+       for (i = 0; i < feature_cnt; ++i) {
+               printk(KERN_INFO "feature: %d\n", i);
+               print_feature(&features[i]);
+       }
+}
+
+/**
+ * @brief Prints all syscalls.
+ *
+ * @return Void.
+ */
+void print_all_syscall(void)
+{
+       int i;
+
+       printk(KERN_INFO "SYSCALL:\n");
+       for (i = 0; i < syscall_cnt; ++i)
+               printk(KERN_INFO "    [%2d] %s\n",
+                      get_counter(i), get_sys_name(i));
+}
+/* debug */
diff --git a/modules/ks_features/ks_features.h b/modules/ks_features/ks_features.h
new file mode 100644 (file)
index 0000000..d75da5e
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file ks_features/ks_features.h
+ * @author Vyacheslav Cherkashin: SWAP ks_features implement
+ *
+ * @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
+ *
+ * SWAP kernel features interface declaration.
+ */
+
+
+#ifndef _KS_FEATURES_H
+#define _KS_FEATURES_H
+
+/**
+ * @enum feature_id
+ * Features ids
+ */
+enum feature_id {
+       FID_FILE = 1,                   /**< File probes */
+       FID_IPC = 2,                    /**< Hz probes */
+       FID_PROCESS = 3,                /**< Process probes */
+       FID_SIGNAL = 4,                 /**< Signal probes */
+       FID_NET = 5,                    /**< Network probes */
+       FID_DESC = 6,                   /**< Description probes */
+       FID_SWITCH = 7,                 /**< Switch context probes */
+       FID_SYSFILE_ACTIVITY = 8        /**< System file activity */
+};
+
+int set_feature(enum feature_id id);
+int unset_feature(enum feature_id id);
+
+/* debug */
+void print_features(void);
+void print_all_syscall(void);
+/* debug */
+
+#endif /*  _KS_FEATURES_H */
diff --git a/modules/ks_features/ks_features_data.c b/modules/ks_features/ks_features_data.c
new file mode 100644 (file)
index 0000000..78ef3a0
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+ * @author Vitaliy Cherepanov: SWAP ks_features_data implement
+ *
+ * @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, 2016
+ *
+ * @section DESCRIPTION
+ *
+ *  SWAP kernel features
+ */
+
+#include "syscall_list.h"
+#include "ks_features_data.h"
+#include "ksf_msg.h"
+
+
+/**
+ * @struct ks_probe
+ * @brief Kernel-space probe. Struct used as a container of syscall probes.
+ * @var ks_probe::rp
+ * Pointer to kretprobe.
+ * @var ks_probe::counter
+ * Installed probes counter.
+ * @var ks_probe::args
+ * Pointer to args format string.
+ * @var ks_probe::type
+ * Probe sub type.
+ */
+
+#define CREATE_RP(name)                                                \
+{                                                              \
+       .entry_handler = NULL,                                  \
+       .handler = NULL                                         \
+}
+
+#define CREATE_HOOK_SYSCALL(name)                              \
+{                                                              \
+       .entry = NULL,                                  \
+       .exit = NULL                                    \
+}
+
+#define SYSCALL_NAME_STR(name) #name
+
+#ifdef CONFIG_SWAP_HOOK_SYSCALL
+
+#include <asm/unistd32.h>      /* FIXME: for only arm64 compat mode */
+
+#define X(name__, args__)                                      \
+{                                                              \
+       .hook = CREATE_HOOK_SYSCALL(name__),                    \
+       .sys_addr = 0xdeadbeef,                                 \
+       .counter = 0,                                           \
+       .args = #args__,                                        \
+       .type = PT_KS_NONE,                                     \
+       .name = SYSCALL_NAME_STR(sys_ ## name__),               \
+       .id = __NR_ ## name__,                                  \
+},
+#else /* !CONFIG_SWAP_HOOK_SYSCALL */
+#define X(name__, args__)                                      \
+{                                                              \
+       .rp = CREATE_RP(name__),                                \
+       .counter = 0,                                           \
+       .args = #args__,                                        \
+       .type = PT_KS_NONE,                                     \
+       .name = SYSCALL_NAME_STR(sys_ ## name__),               \
+},
+#endif /* CONFIG_SWAP_HOOK_SYSCALL */
+
+struct ks_probe ksp[syscall_cnt] = {
+       SYSCALL_LIST
+};
+
+#undef X
+
+const char *get_sys_name(size_t id)
+{
+       return ksp[id].name;
+}
+
+int get_counter(size_t id)
+{
+       return ksp[id].counter;
+}
+
+void inc_counter(size_t id)
+{
+       ++ksp[id].counter;
+}
+
+void dec_counter(size_t id)
+{
+       --ksp[id].counter;
+}
+
diff --git a/modules/ks_features/ks_features_data.h b/modules/ks_features/ks_features_data.h
new file mode 100644 (file)
index 0000000..e68a1b1
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * ks_features/ks_features_data.h
+ * @author Vitaliy Cherepanov: SWAP ks_features implement
+ *
+ * @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, 2016
+ *
+ * @section DESCRIPTION
+ *
+ *  SWAP kernel features
+ */
+
+/**
+ * @struct ks_probe
+ * @brief Kernel-space probe. Struct used as a container of syscall probes.
+ * @var ks_probe::rp
+ * Pointer to kretprobe.
+ * @var ks_probe::counter
+ * Installed probes counter.
+ * @var ks_probe::args
+ * Pointer to args format string.
+ * @var ks_probe::type
+ * Probe sub type.
+ */
+#ifndef __KS_FEATURE_DATA_H__
+#define __KS_FEATURE_DATA_H__
+
+#include "syscall_list.h"
+
+#ifdef CONFIG_SWAP_HOOK_SYSCALL
+# include <swap/hook_syscall.h>
+#else
+# include "kprobe/swap_kprobes.h"
+#endif
+
+struct ks_probe {
+#ifdef CONFIG_SWAP_HOOK_SYSCALL
+       struct hook_syscall hook;
+       u64 sys_addr;
+#else /* CONFIG_SWAP_HOOK_SYSCALL */
+       struct kretprobe rp;
+#endif /* CONFIG_SWAP_HOOK_SYSCALL */
+
+       int counter;
+       char *args;
+       int type;
+
+       const char *name;
+       unsigned int id;
+};
+
+/**
+ * @enum
+ * Syscall name count defenition
+ */
+#define X(name__, args__) + 1
+enum {
+       syscall_cnt = 0 SYSCALL_LIST
+};
+#undef X
+
+extern struct ks_probe ksp[syscall_cnt];
+
+const char *get_sys_name(size_t id);
+int get_counter(size_t id);
+void inc_counter(size_t id);
+void dec_counter(size_t id);
+
+#endif /* __KS_FEATURE_DATA_H__ */
diff --git a/modules/ks_features/ks_map.c b/modules/ks_features/ks_map.c
new file mode 100644 (file)
index 0000000..6be2f2e
--- /dev/null
@@ -0,0 +1,203 @@
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "ks_map.h"
+
+struct entry {
+       struct rb_node node;
+       void *data;
+};
+
+static inline void *entry_data(struct entry *entry)
+{
+       return entry->data;
+}
+
+static struct entry *alloc_entry(struct map *map, void *data)
+{
+       struct entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+
+       if (entry) {
+               entry->data = data;
+               RB_CLEAR_NODE(&entry->node);
+       }
+
+       return entry;
+}
+
+static void *free_entry(struct map *map, struct entry *entry)
+{
+       void *data = entry_data(entry);
+
+       kfree(entry);
+
+       return data;
+}
+
+static struct entry *__search(struct map *map, void *key)
+{
+       struct rb_root *root = &map->root;
+       struct rb_node *node = root->rb_node;
+       key_func_t key_f = map->key_f;
+       cmp_func_t cmp_f = map->cmp_f;
+
+       while (node) {
+               struct entry *entry = rb_entry(node, struct entry, node);
+               int result = cmp_f(key_f(entry_data(entry)), key);
+
+               if (result < 0)
+                       node = node->rb_left;
+               else if (result > 0)
+                       node = node->rb_right;
+               else
+                       return entry;
+       }
+
+       return NULL;
+}
+
+void *search(struct map *map, void *key)
+{
+       struct entry *entry = __search(map, key);
+
+       return entry ? entry_data(entry) : NULL;
+}
+
+static void *__remove(struct map *map, struct entry *entry)
+{
+       struct rb_root *root = &map->root;
+
+       rb_erase(&entry->node, root);
+       RB_CLEAR_NODE(&entry->node);
+       map->size--;
+
+       return free_entry(map, entry);
+}
+
+void *remove(struct map *map, void *key)
+{
+       struct entry *entry = __search(map, key);
+
+       /* Removes entry from the tree but does not free the data */
+       return entry ? __remove(map, entry) : NULL;
+}
+
+static void *__replace(struct map *map, struct entry *old, struct entry *new)
+{
+       struct rb_root *root = &map->root;
+
+       rb_replace_node(&old->node, &new->node, root);
+
+       return free_entry(map, old);
+}
+
+void *replace(struct map *map, void *data)
+{
+       struct entry *old, *new;
+
+       old = __search(map, map->key_f(data));
+       if (old) {
+               new = alloc_entry(map, data);
+               if (!new)
+                       return ERR_PTR(-ENOMEM);
+
+               return __replace(map, old, new);
+       }
+
+       return ERR_PTR(-ESRCH);
+}
+
+int insert(struct map *map, void *data)
+{
+       struct rb_root *root = &map->root;
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       key_func_t key_f = map->key_f;
+       cmp_func_t cmp_f = map->cmp_f;
+       void *key = key_f(data);
+       struct entry *entry;
+
+       /* Figure out where to put new node */
+       while (*new) {
+               struct entry *this = rb_entry(*new, struct entry, node);
+               int result = cmp_f(key_f(entry_data(this)), key);
+
+               parent = *new;
+               if (result < 0)
+                       new = &((*new)->rb_left);
+               else if (result > 0)
+                       new = &((*new)->rb_right);
+               else /* entry already inserted */
+                       return -EEXIST;
+       }
+
+       entry = alloc_entry(map, data);
+       if (!entry)
+               return -ENOMEM;
+
+       /* Add new node and rebalance tree. */
+       rb_link_node(&entry->node, parent, new);
+       rb_insert_color(&entry->node, root);
+       map->size++;
+
+       return 0;
+}
+
+int for_each_entry(struct map *map, act_func_t func, void *arg)
+{
+       struct rb_root *root = &map->root;
+       struct rb_node *node = rb_first(root);
+       int ret = 0;
+
+       while (node) {
+               struct entry *entry = rb_entry(node, struct entry, node);
+
+               /* Stop iteration if actor returns non zero */
+               ret = func(entry_data(entry), arg);
+               if (ret)
+                       break;
+
+               node = rb_next(node);
+       }
+
+       return ret;
+}
+
+int for_each_entry_reverse(struct map *map, act_func_t func, void *arg)
+{
+       struct rb_root *root = &map->root;
+       struct rb_node *node = rb_last(root);
+       int ret = 0;
+
+       while (node) {
+               struct entry *entry = rb_entry(node, struct entry, node);
+
+               /* Stop iteration if actor returns non zero */
+               ret = func(entry_data(entry), arg);
+               if (ret)
+                       break;
+
+               node = rb_prev(node);
+       }
+
+       return ret;
+}
+
+void clear(struct map *map, act_func_t destructor, void *arg)
+{
+       struct rb_root *root = &map->root;
+       struct rb_node *node = root->rb_node;
+
+       while (node) {
+               struct entry *entry = rb_entry(node, struct entry, node);
+               void *data = __remove(map, entry);
+
+               /* call the data 'destructor' if supplied */
+               if (destructor)
+                       destructor(data, arg);
+
+               node = root->rb_node;
+       }
+
+       WARN(map->size, "ks_map size: %d\n", map->size);
+       map->root = RB_ROOT;
+}
diff --git a/modules/ks_features/ks_map.h b/modules/ks_features/ks_map.h
new file mode 100644 (file)
index 0000000..8d86a9c
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __KS_MAP__
+#define __KS_MAP__
+
+#include <linux/rbtree.h>
+
+typedef void *(*key_func_t)(void *);
+typedef int (*cmp_func_t)(void *, void *);
+typedef int (*act_func_t)(void *, void *);
+
+struct map {
+       struct rb_root root;
+       int size;
+       key_func_t key_f;
+       cmp_func_t cmp_f;
+};
+
+#define __MAP_INITIALIZER(_key_f, _cmp_f) \
+       { \
+               .root = RB_ROOT, \
+               .size = 0, \
+               .key_f = _key_f, \
+               .cmp_f = _cmp_f \
+       }
+
+#define DEFINE_MAP(_name, _key_f, _cmp_f) \
+       struct map _name = __MAP_INITIALIZER(_key_f, _cmp_f)
+
+void *search(struct map *map, void *key);
+void *remove(struct map *map, void *key);
+void *replace(struct map *map, void *data);
+int insert(struct map *map, void *data);
+int for_each_entry(struct map *map, act_func_t func, void *arg);
+int for_each_entry_reverse(struct map *map, act_func_t act, void *arg);
+void clear(struct map *map, act_func_t destructor, void *arg);
+
+#endif /* __KS_MAP__ */
diff --git a/modules/ks_features/ksf_msg.c b/modules/ks_features/ksf_msg.c
new file mode 100644 (file)
index 0000000..e1d0b65
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <writer/swap_msg.h>
+#include <writer/kernel_operations.h>
+#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 = raw_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");
+               goto put_msg;
+       }
+
+       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 task_struct *task, enum swap_msg_id id)
+{
+       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 = raw_smp_processor_id();
+
+       swap_msg_flush_wakeupoff(m, sizeof(*mcs));
+       swap_msg_put(m);
+}
+
+void ksf_switch_entry(struct task_struct *task)
+{
+       context_switch(task, MSG_CONTEXT_SWITCH_ENTRY);
+}
+
+void ksf_switch_exit(struct task_struct *task)
+{
+       context_switch(task, MSG_CONTEXT_SWITCH_EXIT);
+}
diff --git a/modules/ks_features/ksf_msg.h b/modules/ks_features/ksf_msg.h
new file mode 100644 (file)
index 0000000..102cd46
--- /dev/null
@@ -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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#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 task_struct *task);
+void ksf_switch_exit(struct task_struct *task);
+
+
+#endif /* _KSF_MSG_H */
diff --git a/modules/ks_features/syscall_list.h b/modules/ks_features/syscall_list.h
new file mode 100644 (file)
index 0000000..380e53f
--- /dev/null
@@ -0,0 +1,189 @@
+/**
+ * @file ks_features/syscall_list.h
+ * @author Vyacheslav Cherkashin: SWAP ks_features implement
+ *
+ * @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
+ *
+ * Syscalls list.
+ */
+
+
+#ifndef _SYSCALL_LIST_H
+#define _SYSCALL_LIST_H
+
+#define SYSCALL_LIST \
+       X(accept4, dpdd) \
+       X(accept, dpd) \
+       X(access, sd) \
+       X(acct, s) \
+       X(bind, dpd) \
+       X(chdir, s) \
+       X(chmod, sd) \
+/* TODO: X(chown16, sdd) */ \
+       X(chown, sdd) \
+       X(chroot, s) \
+       X(clone, ddddd) \
+       X(connect, dpd) \
+       X(creat, sd) \
+       X(dup3, ddd) \
+       X(epoll_create1, d) \
+       X(epoll_ctl, dddp) \
+       X(epoll_pwait, dpddpx) \
+       X(epoll_wait, dpdd) \
+       X(eventfd2, dd) \
+       X(eventfd, d) \
+       X(execve, spp) \
+       X(exit, d) \
+       X(exit_group, d) \
+       X(faccessat, dsd) \
+/* TODO: X(fadvise64_64, dxxd) */ \
+       X(fallocate, ddxx) \
+       X(fanotify_init, dd) \
+       X(fanotify_mark, ddxds) \
+       X(fchmodat, dsd) \
+       X(fchownat, dsddd) \
+       X(fgetxattr, dspx) \
+       X(flistxattr, dpx) \
+       X(fork, /* empty */) \
+       X(fremovexattr, ds) \
+       X(fstat64, xp) \
+       X(ftruncate64, dx) \
+       X(futimesat, dsp) \
+       X(getcwd, px) \
+       X(getpeername, dpd) \
+       X(getsockname, dpd) \
+       X(getsockopt, dddpd) \
+       X(getxattr, sspx) \
+       X(inotify_add_watch, dsd) \
+       X(inotify_init, /* empty */) \
+       X(inotify_init1, d) \
+       X(inotify_rm_watch, dd) \
+/* TODO: X(ipc, ddxxpx) */\
+       X(kill, dd) \
+       X(linkat, dsdsd) \
+       X(link, ss) \
+       X(listen, dd) \
+       X(listxattr, spx) \
+       X(lstat64, sp) \
+/* TODO: X(lstat, sp) */ \
+       X(mkdirat, dsd) \
+       X(mkdir, sd) \
+       X(mknodat, dsdd) \
+       X(mknod, sdd) \
+/* TODO: X(mmap_pgoff, xxxxxx) */ \
+       X(mount, pppxp) \
+       X(msgctl, ddp) \
+       X(msgget, dd) \
+       X(msgrcv, dpxxd) \
+       X(msgsnd, dpxd) \
+       X(name_to_handle_at, dspdd) \
+/* TODO: X(newfstatat, dspd) */ \
+/* TODO: X(old_mmap, p) */ \
+       X(openat, dsdd) \
+       X(open_by_handle_at, dpd) \
+       X(open, sdd) \
+       X(pause, /* empty */) \
+       X(pipe2, dd) \
+       X(ppoll, pdpp) \
+       X(pread64, dpxx) \
+       X(preadv, xpxxx) \
+       X(pselect6, dxxxpp) \
+       X(pwrite64, dsxx) \
+       X(pwritev, xpxxx) \
+       X(readlinkat, dspd) \
+       X(readlink, spd) \
+       X(recv, dpxd) \
+       X(recvfrom, dpxdpd) \
+       X(recvmmsg, dpddp) \
+       X(recvmsg, dpd) \
+       X(removexattr, ss) \
+       X(renameat, dsds) \
+       X(rename, ss) \
+       X(rmdir, s) \
+       X(rt_sigaction, dpp) \
+       X(rt_sigprocmask, dppx) \
+       X(rt_sigsuspend, px) \
+       X(rt_sigtimedwait, pppx) \
+       X(rt_tgsigqueueinfo, dddp) \
+       X(semctl, dddx) \
+       X(semget, ddd) \
+       X(semop, dpd) \
+       X(semtimedop, dpdp) \
+       X(send, dpxd) \
+       X(sendfile64, ddlxx) \
+       X(sendfile, ddxx) \
+       X(sendmmsg, dpdd) \
+       X(sendmsg, dpd) \
+       X(sendto, dpxdpd) \
+       X(setns, dd) \
+       X(setsockopt, dddpd) \
+       X(setxattr, sspxd) \
+       X(shmat, dpd) \
+       X(shmctl, ddp) \
+       X(shmdt, p) \
+       X(shmget, dxd) \
+       X(shutdown, dd) \
+       X(sigaction, dpp) \
+/* TODO: X(sigaltstack, pp) */ \
+/* TODO: X(signal, dp) */ \
+       X(signalfd4, dpxd) \
+       X(signalfd, dpx) \
+       X(sigpending, p) \
+       X(sigprocmask, dpp) \
+/* TODO: X(sigsuspend, ddp) */ \
+/* TODO: X(sigsuspend, p) */ \
+/* TODO: X(socketcall, dx) */\
+       X(socket, ddd) \
+       X(socketpair, dddd) \
+       X(splice, dxdxxd) \
+       X(stat64, sp) \
+       X(statfs64, sxp) \
+       X(statfs, sp) \
+/* TODO: X(stat, sp) */ \
+       X(swapoff, s) \
+       X(swapon, sd) \
+       X(symlinkat, sds) \
+       X(symlink, ss) \
+       X(syncfs, d) \
+       X(tee, ddxd) \
+       X(tgkill, ddd) \
+       X(timerfd_create, dd) \
+       X(timerfd_gettime, dp) \
+       X(timerfd_settime, ddpp) \
+       X(truncate64, sx) \
+       X(truncate, sx) \
+/* TODO: X(umount, pd) */\
+       X(unlinkat, dsd) \
+       X(unlink, s) \
+       X(unshare, x) \
+       X(uselib, s) \
+       X(utimensat, dspd) \
+/* TODO: X(utime, pp) */\
+       X(utimes, pp) \
+       X(vfork, /* empty */) \
+       X(vmsplice, dpxd) \
+       X(wait4, dddp) \
+       X(waitid, ddpdp)
+/* TODO: X(waitpid, ddd) */
+
+#endif /* _SYSCALL_LIST_H */
diff --git a/modules/ks_manager/Kbuild b/modules/ks_manager/Kbuild
new file mode 100644 (file)
index 0000000..220e7c2
--- /dev/null
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers
+
+obj-m := swap_ks_manager.o
+swap_ks_manager-y := ks_manager.o
diff --git a/modules/ks_manager/ks_manager.c b/modules/ks_manager/ks_manager.c
new file mode 100644 (file)
index 0000000..2a554e1
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/ks_manager/ks_manager.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include "ks_manager.h"
+
+struct probe {
+       struct hlist_node hlist;
+       struct kern_probe p;
+};
+
+static HLIST_HEAD(list_probes);
+
+static struct probe *create_probe(unsigned long addr, void *pre_handler,
+                                 void *jp_handler, void *rp_handler)
+{
+       struct probe *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+       if (p == NULL)
+               return NULL;
+
+       p->p.jp.kp.addr = p->p.rp.kp.addr = addr;
+       p->p.jp.pre_entry = pre_handler;
+       p->p.jp.entry = jp_handler;
+       p->p.rp.handler = rp_handler;
+       INIT_HLIST_NODE(&p->hlist);
+
+       return p;
+}
+
+static void free_probe(struct probe *p)
+{
+       kfree(p);
+}
+
+static void add_probe_to_list(struct probe *p)
+{
+       hlist_add_head(&p->hlist, &list_probes);
+}
+
+static void remove_probe_to_list(struct probe *p)
+{
+       hlist_del(&p->hlist);
+}
+
+static struct probe *find_probe(unsigned long addr)
+{
+       struct probe *p;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       /* check if such probe does exist */
+       swap_hlist_for_each_entry(p, node, &list_probes, hlist)
+               if ((unsigned long)p->p.jp.kp.addr == addr)
+                       return p;
+
+       return NULL;
+}
+
+int ksm_register_probe(unsigned long addr, void *pre_handler,
+                      void *jp_handler, void *rp_handler)
+{
+       int ret;
+       struct probe *p;
+
+       p = create_probe(addr, pre_handler, jp_handler, rp_handler);
+       if (!p)
+               return -ENOMEM;
+
+       ret = swap_register_jprobe(&p->p.jp);
+       if (ret)
+               goto free;
+
+       ret = swap_register_kretprobe(&p->p.rp);
+       if (ret)
+               goto unregister_jprobe;
+
+       add_probe_to_list(p);
+       return 0;
+
+unregister_jprobe:
+       swap_unregister_jprobe(&p->p.jp);
+free:
+       free_probe(p);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ksm_register_probe);
+
+static void do_ksm_unregister_probe(struct probe *p)
+{
+       remove_probe_to_list(p);
+       swap_unregister_kretprobe(&p->p.rp);
+       swap_unregister_jprobe(&p->p.jp);
+       free_probe(p);
+}
+
+int ksm_unregister_probe(unsigned long addr)
+{
+       struct probe *p;
+
+       p = find_probe(addr);
+       if (p == NULL)
+               return -EINVAL;
+
+       do_ksm_unregister_probe(p);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ksm_unregister_probe);
+
+int ksm_unregister_probe_all(void)
+{
+       struct probe *p;
+       struct hlist_node *n;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry_safe(p, node, n, &list_probes, hlist) {
+               do_ksm_unregister_probe(p);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ksm_unregister_probe_all);
+
+static int __init init_ks_manager(void)
+{
+       return 0;
+}
+
+static void __exit exit_ks_manager(void)
+{
+       ksm_unregister_probe_all();
+}
+
+module_init(init_ks_manager);
+module_exit(exit_ks_manager);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/ks_manager/ks_manager.h b/modules/ks_manager/ks_manager.h
new file mode 100644 (file)
index 0000000..42ca724
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _KS_MANAGER_H
+#define _KS_MANAGER_H
+
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/ks_manager/ks_manager.h
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include <kprobe/swap_kprobes.h>
+
+struct kern_probe {
+       struct jprobe jp;
+       struct kretprobe rp;
+};
+
+int ksm_register_probe(unsigned long addr, void *pre_handler,
+                      void *jp_handler, void *rp_handler);
+int ksm_unregister_probe(unsigned long addr);
+
+int ksm_unregister_probe_all(void);
+
+#endif /* _KS_MANAGER_H */
diff --git a/modules/ksyms/Kbuild b/modules/ksyms/Kbuild
new file mode 100644 (file)
index 0000000..c602e93
--- /dev/null
@@ -0,0 +1,10 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_ksyms.o
+swap_ksyms-y := ksyms_module.o
+
+ifeq ($(CONFIG_KALLSYMS),y)
+       swap_ksyms-y += ksyms.o
+else
+       swap_ksyms-y += no_ksyms.o
+endif
diff --git a/modules/ksyms/ksyms.c b/modules/ksyms/ksyms.c
new file mode 100644 (file)
index 0000000..d44b45a
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * @file ksyms/ksyms.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP ksyms module.
+ */
+
+
+#include "ksyms.h"
+#include "ksyms_init.h"
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+
+/**
+ * @struct symbol_data
+ * @brief Stores symbols data.
+ * @var symbol_data::name
+ * Pointer to symbol name string.
+ * @var symbol_data::len
+ * Symbol name length.
+ * @var symbol_data::addr
+ * Symbol address.
+ */
+struct symbol_data {
+       const char *name;
+       size_t len;
+       unsigned long addr;
+};
+
+static int symbol_cb(void *data, const char *sym, struct module *mod,
+                    unsigned long addr)
+{
+       struct symbol_data *sym_data_p = (struct symbol_data *)data;
+
+       /* We expect that real symbol name should have at least the same
+        * length as symbol name we are looking for. */
+       if (strncmp(sym_data_p->name, sym, sym_data_p->len) == 0) {
+               sym_data_p->addr = addr;
+               /* Return != 0 to stop loop over the symbols */
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Search of symbol address based on substring.
+ *
+ * @param name Pointer to the substring.
+ * @return Symbol address.
+ */
+unsigned long swap_ksyms_substr(const char *name)
+{
+       struct symbol_data sym_data = {
+               .name = name,
+               .len = strlen(name),
+               .addr = 0
+       };
+       kallsyms_on_each_symbol(symbol_cb, (void *)&sym_data);
+
+       return sym_data.addr;
+}
+EXPORT_SYMBOL_GPL(swap_ksyms_substr);
diff --git a/modules/ksyms/ksyms.h b/modules/ksyms/ksyms.h
new file mode 100644 (file)
index 0000000..3348b7f
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * @file ksyms/ksyms.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ * @sectoin DESCRIPTION
+ *
+ * SWAP symbols searching module.
+ */
+
+#ifndef __KSYMS_H__
+#define __KSYMS_H__
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+#include <linux/autoconf.h>
+#else
+#include <generated/autoconf.h>
+#endif
+
+#include <linux/kallsyms.h>
+
+#ifdef CONFIG_KALLSYMS
+
+static inline int swap_get_ksyms(void)
+{
+       return 0;
+}
+
+static inline void swap_put_ksyms(void)
+{
+}
+
+static inline unsigned long swap_ksyms(const char *name)
+{
+       return kallsyms_lookup_name(name);
+}
+
+#else /* !CONFIG_KALLSYMS */
+
+int swap_get_ksyms(void);
+void swap_put_ksyms(void);
+unsigned long swap_ksyms(const char *name);
+
+#endif /*CONFIG_KALLSYMS*/
+
+unsigned long swap_ksyms_substr(const char *name);
+
+#endif /*__KSYMS_H__*/
diff --git a/modules/ksyms/ksyms_init.h b/modules/ksyms/ksyms_init.h
new file mode 100644 (file)
index 0000000..6235a59
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * @file ksyms/ksyms_init.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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 LICENSE
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP symbols searching module initialization interface.
+ */
+
+#ifndef __KSYMS_INIT_H__
+#define __KSYMS_INIT_H__
+
+#ifdef CONFIG_KALLSYMS
+
+static inline int ksyms_init(void)
+{
+       return 0;
+}
+
+static inline void ksyms_exit(void)
+{
+}
+
+#else /* CONFIG_KALLSYMS */
+
+int ksyms_init(void);
+void ksyms_exit(void);
+
+#endif /* CONFIG_KALLSYMS */
+
+#endif /* __KSYMS_INIT_H__ */
diff --git a/modules/ksyms/ksyms_module.c b/modules/ksyms/ksyms_module.c
new file mode 100644 (file)
index 0000000..22eaaf0
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * @file ksyms/ksyms_module.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP symbols searching module initialization implementation.
+ */
+
+#include "ksyms_init.h"
+
+#include <linux/module.h>
+
+/**
+ * @brief Init ksyms module.
+ *
+ * @return 0 on success.
+ */
+int __init swap_ksyms_init(void)
+{
+       int ret = ksyms_init();
+
+       printk(KERN_INFO "SWAP_KSYMS: Module initialized\n");
+
+       return ret;
+}
+
+/**
+ * @brief Exit ksyms module.
+ *
+ * @return Void.
+ */
+void __exit swap_ksyms_exit(void)
+{
+       ksyms_exit();
+
+       printk(KERN_INFO "SWAP_KSYMS: Module uninitialized\n");
+}
+
+module_init(swap_ksyms_init);
+module_exit(swap_ksyms_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP ksyms module");
+MODULE_AUTHOR("Vyacheslav Cherkashin <v.cherkashin@samaung.com>");
diff --git a/modules/ksyms/no_ksyms.c b/modules/ksyms/no_ksyms.c
new file mode 100644 (file)
index 0000000..a5ecb81
--- /dev/null
@@ -0,0 +1,400 @@
+/**
+ * @file ksyms/no_ksyms.c
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ * SWAP symbols searching implementation.
+ */
+
+#include "ksyms.h"
+#include "ksyms_init.h"
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+
+/**
+ * @def KSYMS_ERR
+ * Error message define.
+ */
+#define KSYMS_ERR(format, args...) \
+       do { \
+               char *f = __FILE__; \
+               char *n = strrchr(f, '/'); \
+               printk(KERN_INFO "%s:%u \'%s\' ERROR: " format "\n" ,  \
+                      (n) ? n+1 : f, __LINE__, __func__, ##args); \
+       } while (0)
+
+/**
+ * @struct sys_map_item
+ * @brief System map list item info.
+ * @var sys_map_item::list
+ * List pointer.
+ * @var sys_map_item::addr
+ * Symbol address.
+ * @var sys_map_item::name
+ * Symbol name.
+ */
+struct sys_map_item {
+       struct list_head list;
+
+       unsigned long addr;
+       char *name;
+};
+
+static char *sm_path;
+module_param(sm_path, charp, 0);
+
+/**
+ * @var smi_list
+ * List of sys_map_item.
+ */
+LIST_HEAD(smi_list);
+static struct file *file;
+
+static int cnt_init_sm;
+
+/**
+ * @var cnt_init_sm_lock
+ * System map items list lock.
+ */
+DEFINE_SEMAPHORE(cnt_init_sm_lock);
+
+static int file_open(void)
+{
+       struct file *f = filp_open(sm_path, O_RDONLY, 0);
+
+       if (IS_ERR(f)) {
+               KSYMS_ERR("cannot open file \'%s\'", sm_path);
+               return PTR_ERR(f);
+       }
+
+       file = f;
+
+       return 0;
+}
+
+static void file_close(void)
+{
+       if (file) {
+               int ret = filp_close(file, NULL);
+               file = NULL;
+
+               if (ret) {
+                       KSYMS_ERR("while closing file \'%s\' err=%d",
+                                 sm_path, ret);
+               }
+       }
+}
+
+static int file_check(void)
+{
+       int ret = file_open();
+       if (ret == 0)
+               file_close();
+
+       return ret;
+}
+
+static long file_size(struct file *file)
+{
+       struct kstat st;
+       if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st))
+               return -1;
+
+       if (!S_ISREG(st.mode))
+               return -1;
+
+       if (st.size != (long)st.size)
+               return -1;
+
+       return st.size;
+}
+
+static struct sys_map_item *create_smi(unsigned long addr, const char *name)
+{
+       struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL);
+
+       if (smi == NULL) {
+               KSYMS_ERR("not enough memory");
+               return NULL;
+       }
+
+       smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+       if (smi->name == NULL) {
+               kfree(smi);
+               KSYMS_ERR("not enough memory");
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&smi->list);
+       smi->addr = addr;
+       strcpy(smi->name, name);
+
+       return smi;
+}
+
+static void free_smi(struct sys_map_item *smi)
+{
+       kfree(smi->name);
+       kfree(smi);
+}
+
+static void add_smi(struct sys_map_item *smi)
+{
+       list_add_tail(&smi->list, &smi_list);
+}
+
+static int is_endline(char c)
+{
+       return c == '\n' || c == '\r' || c == '\0';
+}
+
+static int is_symbol_attr(char c)
+{
+       return c == 't' || c == 'T';
+}
+
+static struct sys_map_item *get_sys_map_item(char *begin, char *end)
+{
+       struct sys_map_item *smi = NULL;
+       int n, len = end - begin;
+       unsigned long addr;
+       char attr, name[128], *line;
+
+       line = kmalloc(len + 1, GFP_KERNEL);
+       memcpy(line, begin, len);
+       line[len] = '\0';
+
+       n = sscanf(line, "%lx %c %127s", &addr, &attr, name);
+       name[127] = '\0';
+
+       if (n != 3) {
+               KSYMS_ERR("parsing line: \"%s\"", line);
+               attr = '\0';
+       }
+
+       kfree(line);
+
+       if (is_symbol_attr(attr))
+               smi = create_smi(addr, name);
+
+       return smi;
+}
+
+
+static void parsing(char *buf, int size)
+{
+       struct sys_map_item *smi;
+       char *start, *end, *c;
+
+       start = buf;
+       end = buf + size;
+
+       for (c = start; c < end; ++c) {
+               if (is_endline(*c)) {
+                       smi = get_sys_map_item(start, c);
+                       if (smi)
+                               add_smi(smi);
+
+                       for (start = c; c < end; ++c) {
+                               if (!is_endline(*c)) {
+                                       start = c;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+static int create_sys_map(void)
+{
+       char *data;
+       long size;
+       int ret = file_open();
+
+       if (ret)
+               return ret;
+
+       size = file_size(file);
+       if (size < 0) {
+               KSYMS_ERR("cannot get file size");
+               ret = size;
+               goto close;
+       }
+
+       data = vmalloc(size);
+       if (data == NULL) {
+               KSYMS_ERR("not enough memory");
+               ret = -1;
+               goto close;
+       }
+
+       if (kernel_read(file, 0, data, size) != size) {
+               KSYMS_ERR("reading file %s", sm_path);
+               ret = -1;
+               goto free;
+       }
+
+       parsing(data, size);
+
+free:
+       vfree(data);
+
+close:
+       file_close();
+
+       return 0;
+}
+
+static void free_sys_map(void)
+{
+       struct sys_map_item *smi, *n;
+       list_for_each_entry_safe(smi, n, &smi_list, list) {
+               list_del(&smi->list);
+               free_smi(smi);
+       }
+}
+
+/**
+ * @brief Generates symbols list.
+ *
+ * @return 0 on success.
+ */
+int swap_get_ksyms(void)
+{
+       int ret = 0;
+
+       down(&cnt_init_sm_lock);
+       if (cnt_init_sm == 0)
+               ret = create_sys_map();
+
+       ++cnt_init_sm;
+       up(&cnt_init_sm_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_get_ksyms);
+
+/**
+ * @brief Frees symbols list.
+ *
+ * @return Void.
+ */
+void swap_put_ksyms(void)
+{
+       down(&cnt_init_sm_lock);
+       --cnt_init_sm;
+       if (cnt_init_sm == 0)
+               free_sys_map();
+
+       if (cnt_init_sm < 0) {
+               KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm);
+               cnt_init_sm = 0;
+       }
+
+       up(&cnt_init_sm_lock);
+}
+EXPORT_SYMBOL_GPL(swap_put_ksyms);
+
+/**
+ * @brief Searches for symbol by its exact name.
+ *
+ * @param name Pointer the name string.
+ * @return Symbol's address.
+ */
+unsigned long swap_ksyms(const char *name)
+{
+       struct sys_map_item *smi;
+
+       list_for_each_entry(smi, &smi_list, list) {
+               if (strcmp(name, smi->name) == 0)
+                       return smi->addr;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_ksyms);
+
+/**
+ * @brief Searches for symbol by substring of its name.
+ *
+ * @param name Pointer to the name substring.
+ * @return Symbol's address.
+ */
+unsigned long swap_ksyms_substr(const char *name)
+{
+       struct sys_map_item *smi;
+       size_t len = strlen(name);
+
+       list_for_each_entry(smi, &smi_list, list) {
+               if (strncmp(name, smi->name, len) == 0)
+                       return smi->addr;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_ksyms_substr);
+
+/**
+ * @brief SWAP ksyms module initialization.
+ *
+ * @return 0 on success, negative error code on error.
+ */
+int ksyms_init(void)
+{
+       int ret = 0;
+
+       if (sm_path == NULL) {
+               KSYMS_ERR("sm_path=NULL");
+               return -EINVAL;
+       }
+
+       ret = file_check();
+       if (ret)
+               return -EINVAL;
+
+       /* TODO: calling func 'swap_get_ksyms' in
+        * module used func 'swap_ksyms' */
+       swap_get_ksyms();
+
+       return 0;
+}
+
+/**
+ * @brief SWAP ksyms module deinitialization.
+ *
+ * @return Void.
+ */
+void ksyms_exit(void)
+{
+       down(&cnt_init_sm_lock);
+
+       if (cnt_init_sm > 0)
+               free_sys_map();
+
+       up(&cnt_init_sm_lock);
+}
diff --git a/modules/loader/Kbuild b/modules/loader/Kbuild
new file mode 100644 (file)
index 0000000..92e5e6f
--- /dev/null
@@ -0,0 +1,7 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_loader.o
+swap_loader-y := loader_module.o \
+                 loader_debugfs.o \
+                 loader_storage.o \
+                 loader_pd.o
diff --git a/modules/loader/loader.h b/modules/loader/loader.h
new file mode 100644 (file)
index 0000000..9ba5ced
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __LOADER__
+#define __LOADER__
+
+struct pd_t;
+struct hd_t;
+struct uretprobe_instance;
+struct task_struct;
+
+/* process loader states */
+enum ps_t {
+       NOT_LOADED,
+       LOADING,
+       LOADED,
+       FAILED,
+       ERROR
+};
+
+void loader_module_prepare_ujump(struct uretprobe_instance *ri,
+                                 struct pt_regs *regs, unsigned long addr);
+
+unsigned long loader_not_loaded_entry(struct uretprobe_instance *ri,
+                                      struct pt_regs *regs, struct pd_t *pd,
+                                      struct hd_t *hd);
+void loader_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                        struct pd_t *pd, struct hd_t *hd);
+void loader_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                       struct pd_t *pd, struct hd_t *hd);
+
+void loader_set_rp_data_size(struct uretprobe *rp);
+void loader_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr);
+unsigned long loader_get_priv_origin(struct uretprobe_instance *ri);
+int loader_add_handler(const char *path);
+
+
+struct pd_t *lpd_get(struct sspt_proc *proc);
+struct pd_t *lpd_get_by_task(struct task_struct *task);
+struct hd_t *lpd_get_hd(struct pd_t *pd, struct dentry *dentry);
+
+bool lpd_get_init_state(struct pd_t *pd);
+void lpd_set_init_state(struct pd_t *pd, bool state);
+
+struct dentry *lpd_get_dentry(struct hd_t *hd);
+struct pd_t *lpd_get_parent_pd(struct hd_t *hd);
+enum ps_t lpd_get_state(struct hd_t *hd);
+unsigned long lpd_get_handlers_base(struct hd_t *hd);
+void *lpd_get_handle(struct hd_t *hd);
+long lpd_get_attempts(struct hd_t *hd);
+void lpd_dec_attempts(struct hd_t *hd);
+
+
+#endif /* __LOADER__ */
diff --git a/modules/loader/loader_debugfs.c b/modules/loader/loader_debugfs.c
new file mode 100644 (file)
index 0000000..861bbe3
--- /dev/null
@@ -0,0 +1,290 @@
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/limits.h>
+#include <asm/uaccess.h>
+#include <master/swap_debugfs.h>
+#include <us_manager/us_common_file.h>
+#include "loader_defs.h"
+#include "loader_debugfs.h"
+#include "loader_module.h"
+#include "loader_storage.h"
+
+static const char LOADER_FOLDER[] = "loader";
+static const char LOADER_LOADER[] = "loader";
+static const char LOADER_LOADER_OFFSET[] = "loader_offset";
+static const char LOADER_LOADER_PATH[] = "loader_path";
+static const char LOADER_LINKER_DATA[] = "linker";
+static const char LOADER_LINKER_PATH[] = "linker_path";
+static const char LOADER_LINKER_R_STATE_OFFSET[] = "r_state_offset";
+
+struct loader_info {
+       char *path;
+       unsigned long offset;
+       struct dentry *dentry;
+};
+
+static struct dentry *loader_root;
+static struct loader_info __loader_info;
+
+static unsigned long r_state_offset = 0;
+static DEFINE_SPINLOCK(__dentry_lock);
+
+static inline void dentry_lock(void)
+{
+       spin_lock(&__dentry_lock);
+}
+
+static inline void dentry_unlock(void)
+{
+       spin_unlock(&__dentry_lock);
+}
+
+
+static void set_loader_file(char *path)
+{
+       __loader_info.path = path;
+       dentry_lock();
+       __loader_info.dentry = swap_get_dentry(__loader_info.path);
+       dentry_unlock();
+}
+
+struct dentry *ld_get_loader_dentry(void)
+{
+       struct dentry *dentry;
+
+       dentry_lock();
+       dentry = __loader_info.dentry;
+       dentry_unlock();
+
+       return dentry;
+}
+
+unsigned long ld_get_loader_offset(void)
+{
+       /* TODO Think about sync */
+       return __loader_info.offset;
+}
+
+static void clean_loader_info(void)
+{
+       if (__loader_info.path != NULL)
+               kfree(__loader_info.path);
+       __loader_info.path = NULL;
+
+       dentry_lock();
+       if (__loader_info.dentry != NULL)
+               swap_put_dentry(__loader_info.dentry);
+
+       __loader_info.dentry = NULL;
+       __loader_info.offset = 0;
+
+       dentry_unlock();
+}
+
+struct dentry *swap_debugfs_create_ptr(const char *name, mode_t mode,
+                                      struct dentry *parent,
+                                      unsigned long *value)
+{
+       struct dentry *dentry;
+
+#if BITS_PER_LONG == 32
+       dentry = swap_debugfs_create_x32(name, mode, parent, (u32 *)value);
+#elif BITS_PER_LONG == 64
+       dentry = swap_debugfs_create_x64(name, mode, parent, (u64 *)value);
+#else
+#error Unsupported BITS_PER_LONG value
+#endif
+
+       return dentry;
+}
+
+
+/* ===========================================================================
+ * =                              LOADER PATH                                =
+ * ===========================================================================
+ */
+
+static ssize_t loader_path_write(struct file *file, const char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       if (loader_module_is_running())
+               return -EBUSY;
+
+       clean_loader_info();
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               return -ENOMEM;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       path[len - 1] = '\0';
+       set_loader_file(path);
+
+       ret = len;
+
+       return ret;
+err:
+       kfree(path);
+       return ret;
+}
+
+
+static const struct file_operations loader_path_file_ops = {
+       .owner = THIS_MODULE,
+       .write = loader_path_write,
+};
+
+
+/* ===========================================================================
+ * =                            LINKER PATH                                  =
+ * ===========================================================================
+ */
+
+
+static ssize_t linker_path_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto linker_path_write_out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto linker_path_write_out;
+       }
+
+       path[len - 1] = '\0';
+
+       if (ls_set_linker_info(path) != 0) {
+               printk(LOADER_PREFIX "Cannot set linker path %s\n", path);
+               ret = -EINVAL;
+               goto linker_path_write_out;
+       }
+
+       ret = len;
+
+linker_path_write_out:
+       kfree(path);
+
+       return ret;
+}
+
+static const struct file_operations linker_path_file_ops = {
+       .owner = THIS_MODULE,
+       .write = linker_path_write,
+};
+
+
+
+
+
+unsigned long ld_r_state_offset(void)
+{
+       return r_state_offset;
+}
+
+int ld_init(void)
+{
+       struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
+                 *linker_dir, *linker_path, *r_state_path;
+       int ret;
+
+       ret = -ENODEV;
+       if (!debugfs_initialized())
+               goto fail;
+
+       ret = -ENOENT;
+       swap_dentry = swap_debugfs_getdir();
+       if (!swap_dentry)
+               goto fail;
+
+       ret = -ENOMEM;
+       root = swap_debugfs_create_dir(LOADER_FOLDER, swap_dentry);
+       if (IS_ERR_OR_NULL(root))
+               goto fail;
+
+       loader_root = root;
+
+       loader = swap_debugfs_create_dir(LOADER_LOADER, root);
+       if (IS_ERR_OR_NULL(root)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       open_p = swap_debugfs_create_ptr(LOADER_LOADER_OFFSET,
+                                        LOADER_DEFAULT_PERMS, loader,
+                                        &__loader_info.offset);
+       if (IS_ERR_OR_NULL(open_p)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       lib_path = swap_debugfs_create_file(LOADER_LOADER_PATH,
+                                           LOADER_DEFAULT_PERMS, loader, NULL,
+                                           &loader_path_file_ops);
+       if (IS_ERR_OR_NULL(lib_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       linker_dir = swap_debugfs_create_dir(LOADER_LINKER_DATA, root);
+       if (IS_ERR_OR_NULL(linker_dir)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       linker_path = swap_debugfs_create_file(LOADER_LINKER_PATH,
+                                              LOADER_DEFAULT_PERMS, linker_dir,
+                                              NULL, &linker_path_file_ops);
+       if (IS_ERR_OR_NULL(linker_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       r_state_path = swap_debugfs_create_ptr(LOADER_LINKER_R_STATE_OFFSET,
+                                              LOADER_DEFAULT_PERMS, linker_dir,
+                                              &r_state_offset);
+       if (IS_ERR_OR_NULL(r_state_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       return 0;
+
+remove:
+
+       debugfs_remove_recursive(root);
+
+fail:
+       printk(LOADER_PREFIX "Debugfs initialization failure: %d\n", ret);
+
+       return ret;
+}
+
+void ld_exit(void)
+{
+       if (loader_root)
+               debugfs_remove_recursive(loader_root);
+       loader_root = NULL;
+
+       loader_module_set_not_ready();
+       clean_loader_info();
+}
diff --git a/modules/loader/loader_debugfs.h b/modules/loader/loader_debugfs.h
new file mode 100644 (file)
index 0000000..d961325
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LOADER_DEBUGFS_H__
+#define __LOADER_DEBUGFS_H__
+
+struct dentry;
+
+int ld_init(void);
+void ld_exit(void);
+
+struct dentry *ld_get_loader_dentry(void);
+unsigned long ld_get_loader_offset(void);
+
+unsigned long ld_r_state_offset(void);
+
+#endif /* __LOADER_DEBUGFS_H__ */
diff --git a/modules/loader/loader_defs.h b/modules/loader/loader_defs.h
new file mode 100644 (file)
index 0000000..0025f76
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __LOADER_DEFS_H__
+#define __LOADER_DEFS_H__
+
+#define LOADER_PREFIX "SWAP_LOADER: "
+#define LOADER_MAX_ATTEMPTS 10
+#define LOADER_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
+
+#endif /* __LOADER_DEFS_H__ */
diff --git a/modules/loader/loader_module.c b/modules/loader/loader_module.c
new file mode 100644 (file)
index 0000000..e262c99
--- /dev/null
@@ -0,0 +1,542 @@
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/mman.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/callbacks.h>
+#include <us_manager/usm_hook.h>
+#include <writer/kernel_operations.h>
+#include <master/swap_initializer.h>
+#include "loader_defs.h"
+#include "loader_debugfs.h"
+#include "loader_module.h"
+#include "loader.h"
+#include "loader_storage.h"
+#include "loader_pd.h"
+
+
+struct us_priv {
+       struct pt_regs regs;
+       unsigned long arg0;
+       unsigned long arg1;
+       unsigned long raddr;
+       unsigned long origin;
+};
+
+static atomic_t dentry_balance = ATOMIC_INIT(0);
+
+enum loader_status_t {
+       SWAP_LOADER_NOT_READY = 0,
+       SWAP_LOADER_READY = 1,
+       SWAP_LOADER_RUNNING = 2
+};
+
+static enum loader_status_t __loader_status = SWAP_LOADER_NOT_READY;
+
+static int __loader_cbs_start_h = -1;
+static int __loader_cbs_stop_h = -1;
+
+
+
+bool loader_module_is_running(void)
+{
+       if (__loader_status == SWAP_LOADER_RUNNING)
+               return true;
+
+       return false;
+}
+
+bool loader_module_is_ready(void)
+{
+       if (__loader_status == SWAP_LOADER_READY)
+               return true;
+
+       return false;
+}
+
+bool loader_module_is_not_ready(void)
+{
+       if (__loader_status == SWAP_LOADER_NOT_READY)
+               return true;
+
+       return false;
+}
+
+void loader_module_set_ready(void)
+{
+       __loader_status = SWAP_LOADER_READY;
+}
+
+void loader_module_set_running(void)
+{
+       __loader_status = SWAP_LOADER_RUNNING;
+}
+
+void loader_module_set_not_ready(void)
+{
+       __loader_status = SWAP_LOADER_NOT_READY;
+}
+
+static inline void __prepare_ujump(struct uretprobe_instance *ri,
+                                  struct pt_regs *regs,
+                                  unsigned long vaddr)
+{
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+       ri->preload.use = true;
+       ri->preload.thumb = !!thumb_mode(regs);
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+
+       swap_set_upc(regs, vaddr);
+}
+
+static inline void __save_uregs(struct uretprobe_instance *ri,
+                               struct pt_regs *regs)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+
+       priv->regs = *regs;
+       priv->arg0 = swap_get_uarg(regs, 0);
+       priv->arg1 = swap_get_uarg(regs, 1);
+       priv->raddr = swap_get_uret_addr(regs);
+}
+
+static inline void __restore_uregs(struct uretprobe_instance *ri,
+                                  struct pt_regs *regs)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+
+       *regs = priv->regs;
+       swap_put_uarg(regs, 0, priv->arg0);
+       swap_put_uarg(regs, 1, priv->arg1);
+       swap_set_uret_addr(regs, priv->raddr);
+#ifdef CONFIG_X86_32
+       /* need to do it only on x86 */
+       regs->EREG(ip) -= 1;
+#endif /* CONFIG_X86_32 */
+       /* we have just restored the registers => no need to do it in
+        * trampoline_uprobe_handler */
+       ri->ret_addr = NULL;
+}
+
+static inline void print_regs(const char *prefix, struct pt_regs *regs,
+                             struct uretprobe_instance *ri, struct hd_t *hd)
+{
+       struct dentry *dentry = lpd_get_dentry(hd);
+
+#if defined(CONFIG_ARM)
+       printk(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), "
+              "r0(%08lx), r1(%08lx), r2(%08lx), r3(%08lx), "
+              "r4(%08lx), r5(%08lx), r6(%08lx), r7(%08lx), "
+              "sp(%08lx), lr(%08lx), pc(%08lx)\n",
+              current->comm, current->tgid, current->pid,
+              dentry != NULL ? (char *)(dentry->d_name.name) :
+                               (char *)("NULL"),
+              (int)lpd_get_state(hd),
+              prefix, (unsigned long)ri->rp->up.addr,
+              regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3,
+              regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7,
+              regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
+#elif defined(CONFIG_X86_32)
+       printk(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), "
+              "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n",
+              current->comm, current->tgid, current->pid,
+              dentry != NULL ? (char *)(dentry->d_name.name) :
+                               (char *)("NULL"),
+              (int)lpd_get_state(hd),
+              prefix, (unsigned long)ri->rp->up.addr,
+              regs->EREG(ip), swap_get_uarg(regs, 0), swap_get_uarg(regs, 1),
+              swap_get_uret_addr(regs));
+#elif defined(CONFIG_ARM64)
+       printk(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%016lx), "
+              "x0(%016lx), x1(%016lx), x2(%016lx), x3(%016lx), "
+              "x4(%016lx), x5(%016lx), x6(%016lx), x7(%016lx), "
+              "sp(%016lx), lr(%016lx), pc(%016lx)\n",
+              current->comm, current->tgid, current->pid,
+              dentry != NULL ? (char *)(dentry->d_name.name) :
+                               (char *)("NULL"),
+              (int)lpd_get_state(hd),
+              prefix, (unsigned long)ri->rp->up.addr,
+              (long)regs->regs[0], (long)regs->regs[1],
+              (long)regs->regs[2], (long)regs->regs[3],
+              (long)regs->regs[4], (long)regs->regs[5],
+              (long)regs->regs[6], (long)regs->regs[7],
+              (long)regs->sp, swap_get_uret_addr(regs), (long)regs->pc);
+       (void)dentry;
+#else /* CONFIG_arch */
+# error "this architecture is not supported"
+#endif /* CONFIG_arch */
+}
+
+static inline unsigned long get_r_state_addr(struct vm_area_struct *linker_vma)
+{
+       unsigned long start_addr;
+       unsigned long offset = ld_r_state_offset();
+
+       if (linker_vma == NULL)
+               return 0;
+
+       start_addr = linker_vma->vm_start;
+
+       return (offset ? start_addr + offset : 0);
+}
+
+static struct vm_area_struct *__get_linker_vma(struct task_struct *task)
+{
+       struct vm_area_struct *vma = NULL;
+       struct bin_info *ld_info;
+
+       ld_info = ls_get_linker_info();
+       if (ld_info == NULL) {
+               printk(LOADER_PREFIX "Cannot get linker info [%u %u %s]!\n",
+                      task->tgid, task->pid, task->comm);
+               return NULL;
+       }
+
+       for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
+               if (vma->vm_file && vma->vm_flags & VM_EXEC
+                   && vma->vm_file->f_path.dentry == ld_info->dentry) {
+                               ls_put_linker_info(ld_info);
+                               return vma;
+               }
+       }
+
+       ls_put_linker_info(ld_info);
+       return NULL;
+}
+
+
+
+
+
+
+
+
+
+static bool __is_proc_mmap_mappable(struct task_struct *task)
+{
+       struct vm_area_struct *linker_vma = __get_linker_vma(task);
+       struct sspt_proc *proc;
+       unsigned long r_state_addr;
+       unsigned int state;
+
+       if (linker_vma == NULL)
+               return false;
+
+       r_state_addr = get_r_state_addr(linker_vma);
+       if (r_state_addr == 0)
+               return false;
+
+       proc = sspt_proc_get_by_task(task);
+       if (proc) {
+               proc->r_state_addr = r_state_addr;
+               sspt_proc_put(proc);
+       }
+
+       if (get_user(state, (unsigned long *)r_state_addr))
+               return false;
+
+       return !state;
+}
+
+static bool __should_we_load_handlers(struct task_struct *task,
+                                        struct pt_regs *regs)
+{
+       if (!__is_proc_mmap_mappable(task))
+               return false;
+
+       return true;
+}
+
+
+
+
+
+static void mmap_handler(struct sspt_proc *proc, struct vm_area_struct *vma)
+{
+       struct pd_t *pd;
+       unsigned long vaddr = vma->vm_start;
+       struct dentry *dentry = vma->vm_file->f_path.dentry;
+
+       pd = lpd_get(proc);
+       if (pd == NULL) {
+               printk(LOADER_PREFIX "%d: No process data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
+               return;
+       }
+
+       if (dentry == ld_get_loader_dentry()) {
+               lpd_set_loader_base(pd, vaddr);
+       } else {
+               struct hd_t *hd;
+
+               hd = lpd_get_hd(pd, dentry);
+               if (hd)
+                       lpd_set_handlers_base(hd, vaddr);
+       }
+}
+
+
+static struct usm_hook usm_hook = {
+       .owner = THIS_MODULE,
+       .mmap = mmap_handler,
+};
+
+static bool mmap_rp_inst = false;
+static DEFINE_MUTEX(mmap_rp_mtx);
+
+static void loader_start_cb(void)
+{
+       int res;
+
+       mutex_lock(&mmap_rp_mtx);
+       res = usm_hook_reg(&usm_hook);
+       if (res != 0)
+               pr_err(LOADER_PREFIX "Cannot register usm_hook\n");
+       else
+               mmap_rp_inst = true;
+       mutex_unlock(&mmap_rp_mtx);
+}
+
+static void loader_stop_cb(void)
+{
+       mutex_lock(&mmap_rp_mtx);
+       if (mmap_rp_inst) {
+               usm_hook_unreg(&usm_hook);
+               mmap_rp_inst = false;
+       }
+       mutex_unlock(&mmap_rp_mtx);
+}
+
+static unsigned long __not_loaded_entry(struct uretprobe_instance *ri,
+                                       struct pt_regs *regs,
+                                       struct pd_t *pd, struct hd_t *hd)
+{
+       char __user *path = NULL;
+       unsigned long vaddr = 0;
+       unsigned long base;
+
+       /* if linker is still doing its work, we do nothing */
+       if (!__should_we_load_handlers(current, regs))
+               return 0;
+
+       base = lpd_get_loader_base(pd);
+       if (base == 0)
+               return 0;   /* loader isn't mapped */
+
+       /* jump to loader code if ready */
+       vaddr = base + ld_get_loader_offset();
+       if (vaddr) {
+               /* save original regs state */
+               __save_uregs(ri, regs);
+               print_regs("ORIG", regs, ri, hd);
+
+               path = lpd_get_path(pd, hd);
+
+               /* set dlopen args: filename, flags */
+               swap_put_uarg(regs, 0, (unsigned long)path);
+               swap_put_uarg(regs, 1, 2 /* RTLD_NOW */);
+
+               /* do the jump to dlopen */
+               __prepare_ujump(ri, regs, vaddr);
+               /* set new state */
+               lpd_set_state(hd, LOADING);
+       }
+
+       return vaddr;
+}
+
+static void __loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                         struct pd_t *pd, struct hd_t *hd)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+       unsigned long vaddr = 0;
+
+       /* check if loading has been completed */
+       vaddr = lpd_get_loader_base(pd) +
+               ld_get_loader_offset();
+       if (vaddr && (priv->origin == vaddr)) {
+               lpd_set_handle(hd,
+                                     (void __user *)regs_return_value(regs));
+
+               /* restore original regs state */
+               __restore_uregs(ri, regs);
+               print_regs("REST", regs, ri, hd);
+               /* check if loading done */
+
+               if (lpd_get_handle(hd)) {
+                       lpd_set_state(hd, LOADED);
+               } else {
+                       lpd_dec_attempts(hd);
+                       lpd_set_state(hd, FAILED);
+               }
+       }
+}
+
+static void __failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                        struct pd_t *pd, struct hd_t *hd)
+{
+       if (lpd_get_attempts(hd))
+               lpd_set_state(hd, NOT_LOADED);
+}
+
+
+
+unsigned long loader_not_loaded_entry(struct uretprobe_instance *ri,
+                                      struct pt_regs *regs, struct pd_t *pd,
+                                      struct hd_t *hd)
+{
+       return __not_loaded_entry(ri, regs, pd, hd);
+}
+EXPORT_SYMBOL_GPL(loader_not_loaded_entry);
+
+void loader_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                        struct pd_t *pd, struct hd_t *hd)
+{
+       __loading_ret(ri, regs, pd, hd);
+}
+EXPORT_SYMBOL_GPL(loader_loading_ret);
+
+void loader_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                       struct pd_t *pd, struct hd_t *hd)
+{
+       __failed_ret(ri, regs, pd, hd);
+}
+EXPORT_SYMBOL_GPL(loader_failed_ret);
+
+void loader_module_prepare_ujump(struct uretprobe_instance *ri,
+                                 struct pt_regs *regs, unsigned long addr)
+{
+       __prepare_ujump(ri, regs, addr);
+}
+EXPORT_SYMBOL_GPL(loader_module_prepare_ujump);
+
+void loader_set_rp_data_size(struct uretprobe *rp)
+{
+       rp->data_size = sizeof(struct us_priv);
+}
+EXPORT_SYMBOL_GPL(loader_set_rp_data_size);
+
+void loader_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+
+       priv->origin = addr;
+}
+EXPORT_SYMBOL_GPL(loader_set_priv_origin);
+
+unsigned long loader_get_priv_origin(struct uretprobe_instance *ri)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+
+       return priv->origin;
+}
+EXPORT_SYMBOL_GPL(loader_get_priv_origin);
+
+
+int loader_set(void)
+{
+       if (loader_module_is_running())
+               return -EBUSY;
+
+       return 0;
+}
+
+void loader_unset(void)
+{
+       mutex_lock(&mmap_rp_mtx);
+       if (mmap_rp_inst) {
+               usm_hook_unreg(&usm_hook);
+               mmap_rp_inst = false;
+       }
+       mutex_unlock(&mmap_rp_mtx);
+
+       /*module_put(THIS_MODULE);*/
+       loader_module_set_not_ready();
+}
+
+int loader_add_handler(const char *path)
+{
+       return ls_add_handler(path);
+}
+EXPORT_SYMBOL_GPL(loader_add_handler);
+
+
+static int loader_module_init(void)
+{
+       int ret;
+
+       ret = ld_init();
+       if (ret)
+               goto out_err;
+
+       ret = ls_init();
+       if (ret)
+               goto exit_debugfs;
+
+       ret = lpd_init();
+       if (ret)
+               goto exit_storage;
+
+       /* TODO do not forget to remove set (it is just for debugging) */
+       ret = loader_set();
+       if (ret)
+               goto exit_pd;
+
+       __loader_cbs_start_h = us_manager_reg_cb(START_CB, loader_start_cb);
+       if (__loader_cbs_start_h < 0)
+               goto exit_start_cb;
+
+       __loader_cbs_stop_h = us_manager_reg_cb(STOP_CB, loader_stop_cb);
+       if (__loader_cbs_stop_h < 0)
+               goto exit_stop_cb;
+
+       return 0;
+
+exit_stop_cb:
+       us_manager_unreg_cb(__loader_cbs_start_h);
+
+exit_start_cb:
+       loader_unset();
+
+exit_pd:
+       lpd_uninit();
+
+exit_storage:
+       ls_exit();
+
+exit_debugfs:
+       ld_exit();
+
+out_err:
+       return ret;
+}
+
+static void loader_module_exit(void)
+{
+       int balance;
+
+       us_manager_unreg_cb(__loader_cbs_start_h);
+       us_manager_unreg_cb(__loader_cbs_stop_h);
+       loader_unset();
+       lpd_uninit();
+       ls_exit();
+       ld_exit();
+
+       balance = atomic_read(&dentry_balance);
+       atomic_set(&dentry_balance, 0);
+
+       WARN(balance, "Bad GET/PUT dentry balance: %d\n", balance);
+}
+
+SWAP_LIGHT_INIT_MODULE(NULL, loader_module_init, loader_module_exit,
+                      NULL, NULL);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP Loader Module");
+MODULE_AUTHOR("Vasiliy Ulyanov <v.ulyanov@samsung.com>"
+              "Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/modules/loader/loader_module.h b/modules/loader/loader_module.h
new file mode 100644 (file)
index 0000000..801e5db
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __LOADER_MODULE_H__
+#define __LOADER_MODULE_H__
+
+#include <linux/types.h>
+
+struct dentry;
+
+bool loader_module_is_ready(void);
+bool loader_module_is_running(void);
+bool loader_module_is_not_ready(void);
+void loader_module_set_ready(void);
+void loader_module_set_running(void);
+void loader_module_set_not_ready(void);
+
+struct dentry *get_dentry(const char *filepath);
+void put_dentry(struct dentry *dentry);
+
+
+
+#endif /* __LOADER_MODULE_H__ */
diff --git a/modules/loader/loader_pd.c b/modules/loader/loader_pd.c
new file mode 100644 (file)
index 0000000..a7597e3
--- /dev/null
@@ -0,0 +1,470 @@
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/list.h>
+#include <us_manager/us_manager_common.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include "loader_pd.h"
+#include "loader.h"
+#include "loader_debugfs.h"
+#include "loader_storage.h"
+#include "loader_defs.h"
+
+
+struct pd_t {
+       unsigned long loader_base;
+       unsigned long data_page;
+       struct list_head handlers;
+       bool is_pthread_init;
+};
+
+struct hd_t {
+       struct list_head list;
+       struct dentry *dentry;
+       enum ps_t state;
+       struct pd_t *parent;
+       unsigned long base;
+       unsigned long offset;
+       void __user *handle;
+       long attempts;
+};
+
+
+static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
+{
+       struct file *file = vma->vm_file;
+
+       return (file && (vma->vm_flags & VM_EXEC) &&
+               (file->f_path.dentry == dentry));
+}
+
+static inline unsigned long __get_loader_base(struct pd_t *pd)
+{
+       return pd->loader_base;
+}
+
+static inline void __set_loader_base(struct pd_t *pd,
+                                    unsigned long addr)
+{
+       pd->loader_base = addr;
+}
+
+static inline unsigned long __get_data_page(struct pd_t *pd)
+{
+       return pd->data_page;
+}
+
+static inline void __set_data_page(struct pd_t *pd, unsigned long page)
+{
+       pd->data_page = page;
+}
+
+
+
+static inline enum ps_t __get_state(struct hd_t *hd)
+{
+       return hd->state;
+}
+
+static inline void __set_state(struct hd_t *hd, enum ps_t state)
+{
+       hd->state = state;
+}
+
+static inline unsigned long __get_handlers_base(struct hd_t *hd)
+{
+       return hd->base;
+}
+
+static inline void __set_handlers_base(struct hd_t *hd,
+                                      unsigned long addr)
+{
+       hd->base = addr;
+}
+
+static inline unsigned long __get_offset(struct hd_t *hd)
+{
+       return hd->offset;
+}
+
+static inline void *__get_handle(struct hd_t *hd)
+{
+       return hd->handle;
+}
+
+static inline void __set_handle(struct hd_t *hd, void __user *handle)
+{
+       hd->handle = handle;
+}
+
+static inline long __get_attempts(struct hd_t *hd)
+{
+       return hd->attempts;
+}
+
+static inline void __set_attempts(struct hd_t *hd, long attempts)
+{
+       hd->attempts = attempts;
+}
+
+
+
+static struct vm_area_struct *find_vma_by_dentry(struct mm_struct *mm,
+                                                struct dentry *dentry)
+{
+       struct vm_area_struct *vma;
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next)
+               if (check_vma(vma, dentry))
+                       return vma;
+
+       return NULL;
+}
+
+static struct pd_t *__create_pd(void)
+{
+       struct pd_t *pd;
+       unsigned long page;
+
+       pd = kzalloc(sizeof(*pd), GFP_ATOMIC);
+       if (pd == NULL)
+               return NULL;
+
+       down_write(&current->mm->mmap_sem);
+       page = __swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
+                             MAP_ANONYMOUS | MAP_PRIVATE, 0);
+       up_write(&current->mm->mmap_sem);
+       if (IS_ERR_VALUE(page)) {
+               printk(KERN_ERR LOADER_PREFIX
+                      "Cannot alloc page for %u\n", current->tgid);
+               goto create_pd_fail;
+       }
+
+       __set_data_page(pd, page);
+       pd->is_pthread_init = true;
+       INIT_LIST_HEAD(&pd->handlers);
+
+       return pd;
+
+create_pd_fail:
+       kfree(pd);
+
+       return NULL;
+}
+
+static size_t __copy_path(char *src, unsigned long page, unsigned long offset)
+{
+       unsigned long dest = page + offset;
+       size_t len = strnlen(src, PATH_MAX);
+
+       /* set handler path */
+       if (copy_to_user((void __user *)dest, src, len) != 0) {
+               printk(KERN_ERR LOADER_PREFIX
+                      "Cannot copy string to user!\n");
+               return 0;
+       }
+
+       return len;
+}
+
+static void __set_ld_mapped(struct pd_t *pd, struct mm_struct *mm)
+{
+       struct vm_area_struct *vma;
+       struct dentry *ld = ld_get_loader_dentry();
+
+       down_read(&mm->mmap_sem);
+       if (ld) {
+               vma = find_vma_by_dentry(mm, ld);
+               if (vma)
+                       __set_loader_base(pd, vma->vm_start);
+       }
+       up_read(&mm->mmap_sem);
+}
+
+static void __set_handler_mapped(struct hd_t *hd, struct mm_struct *mm)
+{
+       struct vm_area_struct *vma;
+       struct dentry *handlers = hd->dentry;
+
+       down_read(&mm->mmap_sem);
+       if (handlers) {
+               vma = find_vma_by_dentry(mm, handlers);
+               if (vma) {
+                       __set_handlers_base(hd, vma->vm_start);
+                       __set_state(hd, LOADED);
+                       goto set_handler_mapped_out;
+               }
+       }
+       __set_state(hd, NOT_LOADED);
+
+set_handler_mapped_out:
+       up_read(&mm->mmap_sem);
+}
+
+
+static int __get_handlers(struct pd_t *pd, struct task_struct *task)
+{
+       struct list_head *handlers = NULL;
+       struct bin_info_el *bin;
+       struct hd_t *hd;
+       unsigned long offset = 0;
+       size_t len;
+       int ret = 0;
+
+       handlers = ls_get_handlers();
+       if (handlers == NULL)
+               return -EINVAL;
+
+       list_for_each_entry(bin, handlers, list) {
+               len = __copy_path(bin->path, pd->data_page, offset);
+               if (len == 0) {
+                       ret = -EINVAL;
+                       goto get_handlers_out;
+               }
+
+               hd = kzalloc(sizeof(*hd), GFP_ATOMIC);
+               if (hd == NULL) {
+                       printk(KERN_ERR LOADER_PREFIX "No atomic mem!\n");
+                       ret = -ENOMEM;
+                       goto get_handlers_out;
+               }
+
+
+               INIT_LIST_HEAD(&hd->list);
+               hd->parent = pd;
+               hd->dentry = bin->dentry;
+               hd->offset = offset;
+               __set_handler_mapped(hd, task->mm);
+               __set_attempts(hd, LOADER_MAX_ATTEMPTS);
+               list_add_tail(&hd->list, &pd->handlers);
+
+               /* inc handlers path's on page */
+               offset += len + 1;
+       }
+
+get_handlers_out:
+       /* TODO Cleanup already created */
+       ls_put_handlers();
+
+       return ret;
+}
+
+
+
+enum ps_t lpd_get_state(struct hd_t *hd)
+{
+       if (hd == NULL)
+               return 0;
+
+       return __get_state(hd);
+}
+EXPORT_SYMBOL_GPL(lpd_get_state);
+
+void lpd_set_state(struct hd_t *hd, enum ps_t state)
+{
+       if (hd == NULL) {
+               printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
+               return;
+       }
+
+       __set_state(hd, state);
+}
+
+unsigned long lpd_get_loader_base(struct pd_t *pd)
+{
+       if (pd == NULL)
+               return 0;
+
+       return __get_loader_base(pd);
+}
+
+void lpd_set_loader_base(struct pd_t *pd, unsigned long vaddr)
+{
+       __set_loader_base(pd, vaddr);
+}
+
+unsigned long lpd_get_handlers_base(struct hd_t *hd)
+{
+       if (hd == NULL)
+               return 0;
+
+       return __get_handlers_base(hd);
+}
+EXPORT_SYMBOL_GPL(lpd_get_handlers_base);
+
+void lpd_set_handlers_base(struct hd_t *hd, unsigned long vaddr)
+{
+       __set_handlers_base(hd, vaddr);
+}
+
+char __user *lpd_get_path(struct pd_t *pd, struct hd_t *hd)
+{
+       unsigned long page = __get_data_page(pd);
+       unsigned long offset = __get_offset(hd);
+
+       return (char __user *)(page + offset);
+}
+
+
+
+void *lpd_get_handle(struct hd_t *hd)
+{
+       if (hd == NULL)
+               return NULL;
+
+       return __get_handle(hd);
+}
+
+void lpd_set_handle(struct hd_t *hd, void __user *handle)
+{
+       if (hd == NULL) {
+               printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
+               return;
+       }
+
+       __set_handle(hd, handle);
+}
+
+long lpd_get_attempts(struct hd_t *hd)
+{
+       if (hd == NULL)
+               return -EINVAL;
+
+       return __get_attempts(hd);
+}
+
+void lpd_dec_attempts(struct hd_t *hd)
+{
+       long attempts;
+
+       if (hd == NULL) {
+               printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
+               return;
+       }
+
+       attempts = __get_attempts(hd);
+       attempts--;
+       __set_attempts(hd, attempts);
+}
+
+struct dentry *lpd_get_dentry(struct hd_t *hd)
+{
+       return hd->dentry;
+}
+
+struct pd_t *lpd_get_parent_pd(struct hd_t *hd)
+{
+       return hd->parent;
+}
+EXPORT_SYMBOL_GPL(lpd_get_parent_pd);
+
+struct pd_t *lpd_get(struct sspt_proc *proc)
+{
+       return (struct pd_t *)proc->private_data;
+}
+EXPORT_SYMBOL_GPL(lpd_get);
+
+struct pd_t *lpd_get_by_task(struct task_struct *task)
+{
+       struct sspt_proc *proc = sspt_proc_by_task(task);
+
+       return lpd_get(proc);
+}
+EXPORT_SYMBOL_GPL(lpd_get_by_task);
+
+struct hd_t *lpd_get_hd(struct pd_t *pd, struct dentry *dentry)
+{
+       struct hd_t *hd;
+
+       list_for_each_entry(hd, &pd->handlers, list) {
+               if (hd->dentry == dentry)
+                       return hd;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(lpd_get_hd);
+
+/* TODO Move it to GOT patcher, only it uses this */
+bool lpd_get_init_state(struct pd_t *pd)
+{
+       return pd->is_pthread_init;
+}
+EXPORT_SYMBOL_GPL(lpd_get_init_state);
+
+/* TODO Move it to GOT patcher, only it uses this */
+void lpd_set_init_state(struct pd_t *pd, bool state)
+{
+       pd->is_pthread_init = state;
+}
+EXPORT_SYMBOL_GPL(lpd_set_init_state);
+
+static struct pd_t *do_create_pd(struct task_struct *task)
+{
+       struct pd_t *pd;
+       int ret;
+
+       pd = __create_pd();
+       if (pd == NULL) {
+               ret = -ENOMEM;
+               goto create_pd_exit;
+       }
+
+       ret = __get_handlers(pd, task);
+       if (ret)
+               goto free_pd;
+
+       __set_ld_mapped(pd, task->mm);
+
+       return pd;
+
+free_pd:
+       kfree(pd);
+
+create_pd_exit:
+       printk(KERN_ERR LOADER_PREFIX "do_pd_create_pd: error=%d\n", ret);
+       return NULL;
+}
+
+static void *pd_create(struct sspt_proc *proc)
+{
+       struct pd_t *pd;
+
+       pd = do_create_pd(proc->leader);
+
+       return (void *)pd;
+}
+
+static void pd_destroy(struct sspt_proc *proc, void *data)
+{
+       /* FIXME: to be implemented */
+}
+
+struct sspt_proc_cb pd_cb = {
+       .priv_create = pd_create,
+       .priv_destroy = pd_destroy
+};
+
+int lpd_init(void)
+{
+       int ret;
+
+       ret = sspt_proc_cb_set(&pd_cb);
+
+       return ret;
+}
+
+void lpd_uninit(void)
+{
+       sspt_proc_cb_set(NULL);
+
+       /* TODO Cleanup */
+}
diff --git a/modules/loader/loader_pd.h b/modules/loader/loader_pd.h
new file mode 100644 (file)
index 0000000..aa9da45
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __LOADER_PD_H__
+#define __LOADER_PD_H__
+
+#include <loader/loader.h>
+
+struct pd_t;
+struct hd_t;
+struct sspt_proc;
+struct dentry;
+struct list_head;
+
+
+unsigned long lpd_get_loader_base(struct pd_t *pd);
+void lpd_set_loader_base(struct pd_t *pd, unsigned long vaddr);
+
+void lpd_set_state(struct hd_t *hd, enum ps_t state);
+void lpd_set_handlers_base(struct hd_t *hd, unsigned long vaddr);
+void lpd_set_handle(struct hd_t *hd, void __user *handle);
+
+char __user *lpd_get_path(struct pd_t *pd, struct hd_t *hd);
+
+int lpd_init(void);
+void lpd_uninit(void);
+
+
+#endif /* __LOADER_PD_H__*/
diff --git a/modules/loader/loader_storage.c b/modules/loader/loader_storage.c
new file mode 100644 (file)
index 0000000..2be688e
--- /dev/null
@@ -0,0 +1,205 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <ks_features/ks_map.h>
+#include <us_manager/us_common_file.h>
+#include "loader_defs.h"
+#include "loader_module.h"
+#include "loader_storage.h"
+
+static struct bin_info __linker_info = { NULL, NULL };
+
+static LIST_HEAD(handlers_list);
+
+
+static bool __check_dentry_already_exist(struct dentry *dentry)
+{
+       struct bin_info_el *bin;
+       bool ret = false;
+
+       list_for_each_entry(bin, &handlers_list, list) {
+               if (bin->dentry == dentry) {
+                       ret = true;
+                       goto out;
+               }
+       }
+
+out:
+       return ret;
+}
+
+static inline int __add_handler(const char *path)
+{
+       struct dentry *dentry;
+       size_t len = strnlen(path, PATH_MAX);
+       struct bin_info_el *bin;
+       int ret = 0;
+
+       dentry = swap_get_dentry(path);
+       if (!dentry) {
+               ret = -ENOENT;
+               goto add_handler_out;
+       }
+
+       if (__check_dentry_already_exist(dentry)) {
+               ret = 1;
+               goto add_handler_fail_release_dentry;
+       }
+
+       bin = kmalloc(sizeof(*bin), GFP_KERNEL);
+       if (bin == NULL) {
+               ret = -ENOMEM;
+               goto add_handler_fail_release_dentry;
+       }
+
+       bin->path = kmalloc(len + 1, GFP_KERNEL);
+       if (bin->path == NULL) {
+               ret = -ENOMEM;
+               goto add_handler_fail_free_bin;
+       }
+
+       INIT_LIST_HEAD(&bin->list);
+       strncpy(bin->path, path, len);
+       bin->path[len] = '\0';
+       bin->dentry = dentry;
+       list_add_tail(&bin->list, &handlers_list);
+
+       return ret;
+
+add_handler_fail_free_bin:
+       kfree(bin);
+
+add_handler_fail_release_dentry:
+       swap_put_dentry(dentry);
+
+add_handler_out:
+       return ret;
+}
+
+static inline void __remove_handler(struct bin_info_el *bin)
+{
+       list_del(&bin->list);
+       swap_put_dentry(bin->dentry);
+       kfree(bin->path);
+       kfree(bin);
+}
+
+static inline void __remove_handlers(void)
+{
+       struct bin_info_el *bin, *tmp;
+
+       list_for_each_entry_safe(bin, tmp, &handlers_list, list)
+               __remove_handler(bin);
+}
+
+static inline struct bin_info *__get_linker_info(void)
+{
+       return &__linker_info;
+}
+
+static inline bool __check_linker_info(void)
+{
+       return (__linker_info.dentry != NULL); /* TODO */
+}
+
+static inline int __init_linker_info(char *path)
+{
+       struct dentry *dentry;
+       size_t len = strnlen(path, PATH_MAX);
+       int ret = 0;
+
+
+       __linker_info.path = kmalloc(len + 1, GFP_KERNEL);
+       if (__linker_info.path == NULL) {
+               ret = -ENOMEM;
+               goto init_linker_fail;
+       }
+
+       dentry = swap_get_dentry(path);
+       if (!dentry) {
+               ret = -ENOENT;
+               goto init_linker_fail_free;
+       }
+
+       strncpy(__linker_info.path, path, len);
+       __linker_info.path[len] = '\0';
+       __linker_info.dentry = dentry;
+
+       return ret;
+
+init_linker_fail_free:
+       kfree(__linker_info.path);
+
+init_linker_fail:
+
+       return ret;
+}
+
+static inline void __drop_linker_info(void)
+{
+       kfree(__linker_info.path);
+       __linker_info.path = NULL;
+
+       if (__linker_info.dentry)
+               swap_put_dentry(__linker_info.dentry);
+       __linker_info.dentry = NULL;
+}
+
+
+
+
+int ls_add_handler(const char *path)
+{
+       int ret;
+
+       /* If ret is positive - handler was not added, because it is
+        * already exists */
+       ret = __add_handler(path);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+struct list_head *ls_get_handlers(void)
+{
+       /* TODO counter, syncs */
+       return &handlers_list;
+}
+
+void ls_put_handlers(void)
+{
+       /* TODO dec counter, release sync */
+}
+
+int ls_set_linker_info(char *path)
+{
+       return __init_linker_info(path);
+}
+
+struct bin_info *ls_get_linker_info(void)
+{
+       struct bin_info *info = __get_linker_info();
+
+       if (__check_linker_info())
+               return info;
+
+       return NULL;
+}
+
+void ls_put_linker_info(struct bin_info *info)
+{
+}
+
+int ls_init(void)
+{
+       return 0;
+}
+
+void ls_exit(void)
+{
+       __drop_linker_info();
+       __remove_handlers();
+}
diff --git a/modules/loader/loader_storage.h b/modules/loader/loader_storage.h
new file mode 100644 (file)
index 0000000..69d2121
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __LOADER_STORAGE_H__
+#define __LOADER_STORAGE_H__
+
+struct list_head;
+struct dentry;
+
+struct bin_info {
+       char *path;
+       /* ghot */
+       struct dentry *dentry;
+};
+
+struct bin_info_el {
+       struct list_head list;
+       char *path;
+       /* ghot */
+       struct dentry *dentry;
+};
+
+
+
+int ls_add_handler(const char *path);
+struct list_head *ls_get_handlers(void);
+void ls_put_handlers(void);
+
+int ls_set_linker_info(char *path);
+struct bin_info *ls_get_linker_info(void);
+void ls_put_linker_info(struct bin_info *info);
+
+int ls_init(void);
+void ls_exit(void);
+
+#endif /* __LOADER_HANDLERS_H__ */
diff --git a/modules/master/Kbuild b/modules/master/Kbuild
new file mode 100644 (file)
index 0000000..4265607
--- /dev/null
@@ -0,0 +1,8 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_master.o
+swap_master-y := master_module.o \
+                 swap_debugfs.o \
+                 swap_initializer.o \
+                 swap_deps.o \
+                 wait.o
diff --git a/modules/master/master_module.c b/modules/master/master_module.c
new file mode 100644 (file)
index 0000000..e3b7553
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include "swap_debugfs.h"
+#include "swap_initializer.h"
+
+
+static int __init master_init(void)
+{
+       return swap_debugfs_init();
+}
+
+static void __exit master_exit(void)
+{
+       swap_debugfs_uninit();
+}
+
+module_init(master_init);
+module_exit(master_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/master/swap_debugfs.c b/modules/master/swap_debugfs.c
new file mode 100644 (file)
index 0000000..661305b
--- /dev/null
@@ -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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include "swap_initializer.h"
+#include "swap_debugfs.h"
+
+
+static int change_permission(struct dentry *dentry)
+{
+       const int system_fw = 202;
+
+       /* set UNIX permissions */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+       dentry->d_inode->i_uid = KUIDT_INIT(system_fw);
+       dentry->d_inode->i_gid = KGIDT_INIT(system_fw);
+#else
+       dentry->d_inode->i_uid = system_fw;
+       dentry->d_inode->i_gid = system_fw;
+#endif
+
+       return 0;
+}
+
+struct dentry *swap_debugfs_create_file(const char *name, umode_t mode,
+                                       struct dentry *parent, void *data,
+                                       const struct file_operations *fops)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_create_file(name, mode, parent, data, fops);
+       if (dentry) {
+               if (change_permission(dentry)) {
+                       debugfs_remove(dentry);
+                       return NULL;
+               }
+       }
+
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_file);
+
+struct dentry *swap_debugfs_create_dir(const char *name, struct dentry *parent)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_create_dir(name, parent);
+       if (dentry) {
+               if (change_permission(dentry)) {
+                       debugfs_remove(dentry);
+                       return NULL;
+               }
+       }
+
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_dir);
+
+struct dentry *swap_debugfs_create_x32(const char *name, umode_t mode,
+                                      struct dentry *parent, u32 *value)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_create_x32(name, mode, parent, value);
+       if (dentry) {
+               if (change_permission(dentry)) {
+                       debugfs_remove(dentry);
+                       return NULL;
+               }
+       }
+
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_x32);
+
+struct dentry *swap_debugfs_create_x64(const char *name, umode_t mode,
+                                      struct dentry *parent, u64 *value)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_create_x64(name, mode, parent, value);
+       if (dentry) {
+               if (change_permission(dentry)) {
+                       debugfs_remove(dentry);
+                       return NULL;
+               }
+       }
+
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_x64);
+
+struct dentry *swap_debugfs_create_u64(const char *name, umode_t mode,
+                                      struct dentry *parent, u64 *value)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_create_u64(name, mode, parent, value);
+       if (dentry) {
+               if (change_permission(dentry)) {
+                       debugfs_remove(dentry);
+                       return NULL;
+               }
+       }
+
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_u64);
+
+
+/* based on define DEFINE_SIMPLE_ATTRIBUTE */
+#define SWAP_DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)      \
+static int __fops ## _open(struct inode *inode, struct file *file)     \
+{                                                                      \
+       int ret;                                                        \
+                                                                       \
+       ret = swap_init_simple_open(inode, file);                       \
+       if (ret)                                                        \
+               return ret;                                             \
+                                                                       \
+       __simple_attr_check_format(__fmt, 0ull);                        \
+       ret = simple_attr_open(inode, file, __get, __set, __fmt);       \
+       if (ret)                                                        \
+               swap_init_simple_release(inode, file);                  \
+                                                                       \
+       return ret;                                                     \
+}                                                                      \
+static int __fops ## _release(struct inode *inode, struct file *file)  \
+{                                                                      \
+       simple_attr_release(inode, file);                               \
+       swap_init_simple_release(inode, file);                          \
+                                                                       \
+       return 0;                                                       \
+}                                                                      \
+static const struct file_operations __fops = {                         \
+       .owner   = THIS_MODULE,                                         \
+       .open    = __fops ## _open,                                     \
+       .release = __fops ## _release,                                  \
+       .read    = simple_attr_read,                                    \
+       .write   = simple_attr_write,                                   \
+       .llseek  = generic_file_llseek,                                 \
+}
+
+
+static int fset_u64(void *data, u64 val)
+{
+       struct dfs_setget_64 *setget = data;
+
+       return setget->set(val);
+}
+
+static int fget_u64(void *data, u64 *val)
+{
+       struct dfs_setget_64 *setget = data;
+
+       *val = setget->get();
+       return 0;
+}
+
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_u64, fget_u64, fset_u64, "%llu\n");
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_u64_ro, fget_u64, NULL, "%llu\n");
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_u64_wo, NULL, fset_u64, "%llu\n");
+
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_x64, fget_u64, fset_u64, "0x%08llx\n");
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_x64_ro, fget_u64, NULL, "0x%08llx\n");
+SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_setget_x64_wo, NULL, fset_u64, "0x%08llx\n");
+
+static struct dentry *do_create_dfs_file(const char *name, umode_t mode,
+                                        struct dentry *parent, void *data,
+                                        const struct file_operations *fops,
+                                        const struct file_operations *fops_ro,
+                                        const struct file_operations *fops_wo)
+{
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return swap_debugfs_create_file(name, mode, parent,
+                                               data, fops_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return swap_debugfs_create_file(name, mode, parent,
+                                               data, fops_wo);
+
+       return swap_debugfs_create_file(name, mode, parent, data, fops);
+}
+
+struct dentry *swap_debugfs_create_setget_u64(const char *name, umode_t mode,
+                                             struct dentry *parent,
+                                             struct dfs_setget_64 *setget)
+{
+       return do_create_dfs_file(name, mode, parent, setget,
+                                 &fops_setget_u64,
+                                 &fops_setget_u64_ro,
+                                 &fops_setget_u64_wo);
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_setget_u64);
+
+struct dentry *swap_debugfs_create_setget_x64(const char *name, umode_t mode,
+                                             struct dentry *parent,
+                                             struct dfs_setget_64 *setget)
+{
+       return do_create_dfs_file(name, mode, parent, setget,
+                                 &fops_setget_x64,
+                                 &fops_setget_x64_ro,
+                                 &fops_setget_x64_wo);
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_create_setget_x64);
+
+
+static int set_enable(int enable)
+{
+       int ret = 0, change, enable_current;
+
+       enable_current = swap_init_stat_get();
+
+       change = ((!!enable_current) << 1) | (!!enable);
+       switch (change) {
+       case 0b01: /* init */
+               ret = swap_init_init();
+               break;
+       case 0b10: /* uninit */
+               ret = swap_init_uninit();
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       swap_init_stat_put();
+
+       return ret;
+}
+
+static ssize_t read_enable(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       char buf[3];
+       int enable;
+
+       enable = swap_init_stat_get();
+       swap_init_stat_put();
+
+       if (enable)
+               buf[0] = '1';
+       else
+               buf[0] = '0';
+       buf[1] = '\n';
+       buf[2] = '\0';
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static int do_write_enable(const char *buf, size_t size)
+{
+       if (size < 1)
+               return -EINVAL;
+
+       switch (buf[0]) {
+       case '1':
+               return set_enable(1);
+       case '0':
+               return set_enable(0);
+       }
+
+       return -EINVAL;
+}
+
+static ssize_t write_enable(struct file *file, const char __user *user_buf,
+                           size_t count, loff_t *ppos)
+{
+       int ret;
+       char buf[32];
+       size_t buf_size;
+
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       ret = do_write_enable(buf, buf_size);
+
+       return ret ? ret : count;
+}
+
+static const struct file_operations fops_enable = {
+       .owner = THIS_MODULE,
+       .read = read_enable,
+       .write = write_enable,
+       .llseek = default_llseek,
+};
+
+
+static struct dentry *swap_dir;
+
+/**
+ * @brief Get debugfs dir.
+ *
+ * @return Pointer to dentry stuct.
+ */
+struct dentry *swap_debugfs_getdir(void)
+{
+       return swap_dir;
+}
+EXPORT_SYMBOL_GPL(swap_debugfs_getdir);
+
+static int debugfs_dir_init(void)
+{
+       swap_dir = swap_debugfs_create_dir("swap", NULL);
+       if (swap_dir == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void debugfs_dir_exit(void)
+{
+       struct dentry *dir = swap_dir;
+
+       swap_dir = NULL;
+       debugfs_remove_recursive(dir);
+}
+
+/**
+ * @brief Initializes SWAP debugfs.
+ *
+ * @return 0 on success, negative error code on error.
+ */
+int swap_debugfs_init(void)
+{
+       int ret;
+       struct dentry *dentry;
+
+       ret = debugfs_dir_init();
+       if (ret)
+               return ret;
+
+       dentry = swap_debugfs_create_file("enable", 0600, swap_dir, NULL,
+                                         &fops_enable);
+       if (dentry == NULL) {
+               debugfs_dir_exit();
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Deinitializes SWAP debugfs and recursively removes all its files.
+ *
+ * @return Void.
+ */
+void swap_debugfs_uninit(void)
+{
+       debugfs_dir_exit();
+}
diff --git a/modules/master/swap_debugfs.h b/modules/master/swap_debugfs.h
new file mode 100644 (file)
index 0000000..2717db9
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP debugfs interface definition.
+ */
+
+#ifndef _SWAP_DEBUGFS_H
+#define _SWAP_DEBUGFS_H
+
+
+#include <linux/types.h>
+
+
+struct dfs_setget_64 {
+       int (*set)(u64 val);
+       u64 (*get)(void);
+};
+
+struct dentry;
+struct file_operations;
+
+struct dentry *swap_debugfs_create_setget_u64(const char *name, umode_t mode,
+                                             struct dentry *parent,
+                                             struct dfs_setget_64 *setget);
+
+struct dentry *swap_debugfs_create_setget_x64(const char *name, umode_t mode,
+                                             struct dentry *parent,
+                                             struct dfs_setget_64 *setget);
+
+struct dentry *swap_debugfs_create_file(const char *name, umode_t mode,
+                                       struct dentry *parent, void *data,
+                                       const struct file_operations *fops);
+struct dentry *swap_debugfs_create_dir(const char *name, struct dentry *parent);
+
+struct dentry *swap_debugfs_create_x32(const char *name, umode_t mode,
+                                      struct dentry *parent, u32 *value);
+struct dentry *swap_debugfs_create_x64(const char *name, umode_t mode,
+                                      struct dentry *parent, u64 *value);
+struct dentry *swap_debugfs_create_u64(const char *name, umode_t mode,
+                                      struct dentry *parent, u64 *value);
+
+struct dentry *swap_debugfs_getdir(void);
+
+int swap_debugfs_init(void);
+void swap_debugfs_uninit(void);
+
+
+#endif /* _SWAP_DEBUGFS_H */
diff --git a/modules/master/swap_deps.c b/modules/master/swap_deps.c
new file mode 100644 (file)
index 0000000..0c566c1
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <ksyms/ksyms.h>
+#include "swap_deps.h"
+
+
+static struct files_struct *(*__get_files_struct)(struct task_struct *);
+static void (*__put_files_struct)(struct files_struct *fs);
+
+struct files_struct *swap_get_files_struct(struct task_struct *task)
+{
+       return __get_files_struct(task);
+}
+EXPORT_SYMBOL_GPL(swap_get_files_struct);
+
+void swap_put_files_struct(struct files_struct *fs)
+{
+       __put_files_struct(fs);
+}
+EXPORT_SYMBOL_GPL(swap_put_files_struct);
+
+
+int chef_once(void)
+{
+       const char *sym;
+       static unsigned once_flag = 0;
+
+       if (once_flag)
+               return 0;
+
+       sym = "get_files_struct";
+       __get_files_struct = (void *)swap_ksyms(sym);
+       if (__get_files_struct == NULL)
+               goto not_found;
+
+       sym = "put_files_struct";
+       __put_files_struct = (void *)swap_ksyms(sym);
+       if (__put_files_struct == NULL)
+               goto not_found;
+
+       once_flag = 1;
+       return 0;
+
+not_found:
+       printk("ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
diff --git a/modules/master/swap_deps.h b/modules/master/swap_deps.h
new file mode 100644 (file)
index 0000000..ca4c978
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_DEPS_H
+#define _SWAP_DEPS_H
+
+
+struct task_struct;
+struct files_struct;
+
+
+struct files_struct *swap_get_files_struct(struct task_struct *task);
+void swap_put_files_struct(struct files_struct *fs);
+
+
+int chef_once(void);
+
+
+#endif /* _SWAP_DEPS_H */
diff --git a/modules/master/swap_initializer.c b/modules/master/swap_initializer.c
new file mode 100644 (file)
index 0000000..a7ea8c3
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include "swap_initializer.h"
+#include "swap_deps.h"
+
+
+enum init_level {
+       IL_CORE,
+       IL_FS
+};
+
+static swap_init_t sis_get_fn_init(struct swap_init_struct *init,
+                                  enum init_level level)
+{
+       switch (level) {
+       case IL_CORE:
+               return init->core_init;
+       case IL_FS:
+               return init->fs_init;
+       default:
+               return NULL;
+       }
+}
+
+static swap_uninit_t sis_get_fn_uninit(struct swap_init_struct *init,
+                                      enum init_level level)
+{
+       switch (level) {
+       case IL_CORE:
+               return init->core_uninit;
+       case IL_FS:
+               return init->fs_uninit;
+       }
+
+       return NULL;
+}
+
+static void sis_set_flag(struct swap_init_struct *init,
+                        enum init_level level, bool val)
+{
+       switch (level) {
+       case IL_CORE:
+               init->core_flag = val;
+               break;
+       case IL_FS:
+               init->fs_flag = val;
+               break;
+       }
+}
+
+static bool sis_get_flag(struct swap_init_struct *init, enum init_level level)
+{
+       switch (level) {
+       case IL_CORE:
+               return init->core_flag;
+       case IL_FS:
+               return init->fs_flag;
+       }
+
+       return false;
+}
+
+static int sis_once(struct swap_init_struct *init)
+{
+       swap_init_t once;
+
+       once = init->once;
+       if (!init->once_flag && once) {
+               int ret;
+
+               ret = once();
+               if (ret)
+                       return ret;
+
+               init->once_flag = true;
+       }
+
+       return 0;
+}
+
+static int sis_init_level(struct swap_init_struct *init, enum init_level level)
+{
+       int ret;
+       swap_init_t fn;
+
+       if (sis_get_flag(init, level))
+               return -EPERM;
+
+       fn = sis_get_fn_init(init, level);
+       if (fn) {
+               ret = fn();
+               if (ret)
+                       return ret;
+       }
+
+       sis_set_flag(init, level, true);
+       return 0;
+}
+
+static void sis_uninit_level(struct swap_init_struct *init,
+                            enum init_level level)
+{
+       if (sis_get_flag(init, level)) {
+               swap_uninit_t fn = sis_get_fn_uninit(init, level);
+               if (fn)
+                       fn();
+               sis_set_flag(init, level, false);
+       }
+}
+
+static int sis_init(struct swap_init_struct *init)
+{
+       int ret;
+
+       ret = sis_once(init);
+       if (ret)
+               return ret;
+
+       ret = sis_init_level(init, IL_CORE);
+       if (ret)
+               return ret;
+
+       ret = sis_init_level(init, IL_FS);
+       if (ret)
+               sis_uninit_level(init, IL_CORE);
+
+       return ret;
+}
+
+static void sis_uninit(struct swap_init_struct *init)
+{
+       sis_uninit_level(init, IL_FS);
+       sis_uninit_level(init, IL_CORE);
+}
+
+static LIST_HEAD(init_list);
+static DEFINE_MUTEX(inst_mutex);
+static unsigned init_flag;
+
+static int do_once(void)
+{
+       int ret;
+       struct swap_init_struct *init;
+
+       ret = chef_once();
+       if (ret)
+               return ret;
+
+       list_for_each_entry(init, &init_list, list) {
+               ret = sis_once(init);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void do_uninit_level(enum init_level level)
+{
+       struct swap_init_struct *init;
+
+       list_for_each_entry_reverse(init, &init_list, list)
+               sis_uninit_level(init, level);
+}
+
+static int do_init_level(enum init_level level)
+{
+       int ret;
+       struct swap_init_struct *init;
+
+       list_for_each_entry(init, &init_list, list) {
+               ret = sis_init_level(init, level);
+               if (ret) {
+                       do_uninit_level(level);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int do_init(void)
+{
+       int ret;
+
+       ret = do_once();
+       if (ret)
+               return ret;
+
+       ret = do_init_level(IL_CORE);
+       if (ret)
+               return ret;
+
+       ret = do_init_level(IL_FS);
+       if (ret)
+               do_uninit_level(IL_CORE);
+
+       init_flag = 1;
+
+       return 0;
+}
+
+static void do_uninit(void)
+{
+       do_uninit_level(IL_FS);
+       do_uninit_level(IL_CORE);
+
+       init_flag = 0;
+}
+
+
+static atomic_t init_use = ATOMIC_INIT(0);
+
+enum init_stat_t {
+       IS_OFF,
+       IS_SWITCHING,
+       IS_ON,
+};
+
+static enum init_stat_t init_stat;
+static DEFINE_SPINLOCK(init_stat_lock);
+
+
+static bool swap_init_try_get(void)
+{
+       spin_lock(&init_stat_lock);
+       if (init_stat != IS_ON) {
+               spin_unlock(&init_stat_lock);
+               return false;
+       }
+       spin_unlock(&init_stat_lock);
+
+       atomic_inc(&init_use);
+
+       return true;
+}
+
+static void swap_init_put(void)
+{
+       atomic_dec(&init_use);
+}
+
+int swap_init_simple_open(struct inode *inode, struct file *file)
+{
+       if (swap_init_try_get() == false)
+               return -EBUSY;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_init_simple_open);
+
+int swap_init_simple_release(struct inode *inode, struct file *file)
+{
+       swap_init_put();
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_init_simple_release);
+
+int swap_init_init(void)
+{
+       int ret;
+
+       spin_lock(&init_stat_lock);
+       init_stat = IS_SWITCHING;
+       spin_unlock(&init_stat_lock);
+
+       ret = do_init();
+
+       spin_lock(&init_stat_lock);
+       init_stat = ret ? IS_OFF : IS_ON;
+       spin_unlock(&init_stat_lock);
+
+       return ret;
+}
+
+int swap_init_uninit(void)
+{
+       spin_lock(&init_stat_lock);
+       init_stat = IS_SWITCHING;
+       if (atomic_read(&init_use)) {
+               init_stat = IS_ON;
+               spin_unlock(&init_stat_lock);
+               return -EBUSY;
+       }
+       spin_unlock(&init_stat_lock);
+
+       do_uninit();
+
+       spin_lock(&init_stat_lock);
+       init_stat = IS_OFF;
+       spin_unlock(&init_stat_lock);
+
+       return 0;
+}
+
+
+int swap_init_stat_get(void)
+{
+       mutex_lock(&inst_mutex);
+
+       return init_flag;
+}
+
+void swap_init_stat_put(void)
+{
+       mutex_unlock(&inst_mutex);
+}
+
+int swap_init_register(struct swap_init_struct *init)
+{
+       int ret = 0;
+
+       mutex_lock(&inst_mutex);
+       if (init_flag)
+               ret = sis_init(init);
+
+       if (ret == 0)
+               list_add_tail(&init->list, &init_list);
+       mutex_unlock(&inst_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_init_register);
+
+void swap_init_unregister(struct swap_init_struct *init)
+{
+       mutex_lock(&inst_mutex);
+       list_del(&init->list);
+       sis_uninit(init);
+       mutex_unlock(&inst_mutex);
+}
+EXPORT_SYMBOL_GPL(swap_init_unregister);
diff --git a/modules/master/swap_initializer.h b/modules/master/swap_initializer.h
new file mode 100644 (file)
index 0000000..e0e6314
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * SWAP event notification interface.
+ */
+
+#ifndef _SWAP_INITIALIZER_H
+#define _SWAP_INITIALIZER_H
+
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/module.h>
+
+
+struct file;
+struct inode;
+
+
+typedef int (*swap_init_t)(void);
+typedef void (*swap_uninit_t)(void);
+
+
+struct swap_init_struct {
+       swap_init_t once;       /* to call only on the first initialization */
+
+       swap_init_t core_init;
+       swap_uninit_t core_uninit;
+
+       swap_init_t fs_init;
+       swap_uninit_t fs_uninit;
+
+       /* private fields */
+       struct list_head list;
+       unsigned once_flag:1;
+       unsigned core_flag:1;
+       unsigned fs_flag:1;
+};
+
+
+int swap_init_simple_open(struct inode *inode, struct file *file);
+int swap_init_simple_release(struct inode *inode, struct file *file);
+
+int swap_init_init(void);
+int swap_init_uninit(void);
+
+int swap_init_stat_get(void);
+void swap_init_stat_put(void);
+
+int swap_init_register(struct swap_init_struct *init);
+void swap_init_unregister(struct swap_init_struct *init);
+
+
+#define SWAP_LIGHT_INIT_MODULE(_once, _init, _uninit, _fs_init, _fs_uninit) \
+       static struct swap_init_struct __init_struct = {                \
+               .once = _once,                                          \
+               .core_init = _init,                                     \
+               .core_uninit = _uninit,                                 \
+               .fs_init = _fs_init,                                    \
+               .fs_uninit = _fs_uninit,                                \
+               .list = LIST_HEAD_INIT(__init_struct.list),             \
+               .once_flag = false,                                     \
+               .core_flag = false,                                     \
+               .fs_flag = false                                        \
+       };                                                              \
+       static int __init __init_mod(void)                              \
+       {                                                               \
+               return swap_init_register(&__init_struct);              \
+       }                                                               \
+       static void __exit __exit_mod(void)                             \
+       {                                                               \
+               swap_init_unregister(&__init_struct);                   \
+       }                                                               \
+       module_init(__init_mod);                                        \
+       module_exit(__exit_mod)
+
+
+#endif /* _SWAP_INITIALIZER_H */
diff --git a/modules/master/wait.c b/modules/master/wait.c
new file mode 100644 (file)
index 0000000..c0ee359
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * This code copied from linux kernel 3.11+
+ * commit cb65537ee1134d3cc55c1fa83952bc8eb1212833
+ */
+
+
+#include "wait.h"
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
+
+#include <linux/wait.h>
+#include <linux/module.h>
+
+
+#define WAIT_ATOMIC_T_BIT_NR -1
+#define __WAIT_ATOMIC_T_KEY_INITIALIZER(p)                             \
+       { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, }
+
+
+/*
+ * Manipulate the atomic_t address to produce a better bit waitqueue table hash
+ * index (we're keying off bit -1, but that would produce a horrible hash
+ * value).
+ */
+static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p)
+{
+       if (BITS_PER_LONG == 64) {
+               unsigned long q = (unsigned long)p;
+               return bit_waitqueue((void *)(q & ~1), q & 1);
+       }
+       return bit_waitqueue(p, 0);
+}
+
+static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync,
+                                 void *arg)
+{
+       struct wait_bit_key *key = arg;
+       struct wait_bit_queue *wait_bit
+               = container_of(wait, struct wait_bit_queue, wait);
+       atomic_t *val = key->flags;
+
+       if (wait_bit->key.flags != key->flags ||
+           wait_bit->key.bit_nr != key->bit_nr ||
+           atomic_read(val) != 0)
+               return 0;
+       return autoremove_wake_function(wait, mode, sync, key);
+}
+
+/*
+ * To allow interruptible waiting and asynchronous (i.e. nonblocking) waiting,
+ * the actions of __wait_on_atomic_t() are permitted return codes.  Nonzero
+ * return codes halt waiting and return.
+ */
+static int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
+                             int (*action)(atomic_t *), unsigned mode)
+{
+       atomic_t *val;
+       int ret = 0;
+
+       do {
+               prepare_to_wait(wq, &q->wait, mode);
+               val = q->key.flags;
+               if (atomic_read(val) == 0)
+                       ret = (*action)(val);
+       } while (!ret && atomic_read(val) != 0);
+       finish_wait(wq, &q->wait);
+       return ret;
+}
+
+#define DEFINE_WAIT_ATOMIC_T(name, p)                                  \
+       struct wait_bit_queue name = {                                  \
+               .key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p),              \
+               .wait = {                                               \
+                       .private        = current,                      \
+                       .func           = wake_atomic_t_function,       \
+                       .task_list      =                               \
+                               LIST_HEAD_INIT((name).wait.task_list),  \
+               },                                                      \
+       }
+
+int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *),
+                                        unsigned mode)
+{
+       wait_queue_head_t *wq = atomic_t_waitqueue(p);
+       DEFINE_WAIT_ATOMIC_T(wait, p);
+
+       return __wait_on_atomic_t(wq, &wait, action, mode);
+}
+EXPORT_SYMBOL(out_of_line_wait_on_atomic_t);
+
+/**
+ * wake_up_atomic_t - Wake up a waiter on a atomic_t
+ * @word: The word being waited on, a kernel virtual address
+ * @bit: The bit of the word being waited on
+ *
+ * Wake up anyone waiting for the atomic_t to go to zero.
+ *
+ * Abuse the bit-waker function and its waitqueue hash table set (the atomic_t
+ * check is done by the waiter's wake function, not the by the waker itself).
+ */
+void wake_up_atomic_t(atomic_t *p)
+{
+       __wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR);
+}
+EXPORT_SYMBOL(wake_up_atomic_t);
+
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */
diff --git a/modules/master/wait.h b/modules/master/wait.h
new file mode 100644 (file)
index 0000000..bb1ca4b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * This code copied from linux kernel 3.11+
+ * commit cb65537ee1134d3cc55c1fa83952bc8eb1212833
+ */
+
+
+#ifndef _SWAP_WAIT_H
+#define _SWAP_WAIT_H
+
+
+#include <linux/version.h>
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
+
+
+#include <linux/atomic.h>
+
+
+void wake_up_atomic_t(atomic_t *);
+int out_of_line_wait_on_atomic_t(atomic_t *, int (*)(atomic_t *), unsigned);
+
+static inline
+int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode)
+{
+       if (atomic_read(val) == 0)
+               return 0;
+       return out_of_line_wait_on_atomic_t(val, action, mode);
+}
+
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */
+
+#include <linux/wait.h>
+
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */
+
+#endif /* _SWAP_WAIT_H */
diff --git a/modules/nsp/Kbuild b/modules/nsp/Kbuild
new file mode 100644 (file)
index 0000000..86ea819
--- /dev/null
@@ -0,0 +1,8 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_nsp.o
+swap_nsp-y := \
+       nsp_module.o \
+       nsp.o \
+       nsp_msg.o \
+       nsp_debugfs.o
diff --git a/modules/nsp/nsp.c b/modules/nsp/nsp.c
new file mode 100644 (file)
index 0000000..39d8d29
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <writer/swap_msg.h>
+#include <kprobe/swap_ktd.h>
+#include <uprobe/swap_uaccess.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/probes/probe_info_new.h>
+#include "nsp.h"
+#include "nsp_msg.h"
+#include "nsp_print.h"
+#include "nsp_debugfs.h"
+
+
+/* ============================================================================
+ * =                                 probes                                   =
+ * ============================================================================
+ */
+
+/* dlopen@plt */
+static int dlopen_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static int dlopen_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static struct probe_desc pin_dlopen = MAKE_URPROBE(dlopen_eh, dlopen_rh, 0);
+static struct probe_new p_dlopen = {
+       .desc = &pin_dlopen
+};
+
+/* dlsym@plt */
+static int dlsym_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static int dlsym_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static struct probe_desc pin_dlsym = MAKE_URPROBE(dlsym_eh, dlsym_rh, 0);
+static struct probe_new p_dlsym = {
+       .desc = &pin_dlsym
+};
+
+/* main */
+static int main_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static int main_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static struct probe_desc pin_main = MAKE_URPROBE(main_eh, main_rh, 0);
+
+/* appcore_efl_main */
+static int ac_efl_main_h(struct uprobe *p, struct pt_regs *regs);
+static struct probe_desc pin_ac_efl_main = MAKE_UPROBE(ac_efl_main_h);
+static struct probe_new p_ac_efl_main = {
+       .desc = &pin_ac_efl_main
+};
+
+/* appcore_init@plt */
+static int ac_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static struct probe_desc pin_ac_init = MAKE_URPROBE(NULL, ac_init_rh, 0);
+static struct probe_new p_ac_init = {
+       .desc = &pin_ac_init
+};
+
+/* elm_run@plt */
+static int elm_run_h(struct uprobe *p, struct pt_regs *regs);
+static struct probe_desc pin_elm_run = MAKE_UPROBE(elm_run_h);
+static struct probe_new p_elm_run = {
+       .desc = &pin_elm_run
+};
+
+/* __do_app */
+static int do_app_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static int do_app_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static struct probe_desc pin_do_app = MAKE_URPROBE(do_app_eh, do_app_rh, 0);
+static struct probe_new p_do_app = {
+       .desc = &pin_do_app
+};
+
+
+
+
+
+/* ============================================================================
+ * =                the variables are initialized by the user                 =
+ * ============================================================================
+ */
+static const char *lpad_path;
+static struct dentry *lpad_dentry;
+
+static const char *libappcore_path;
+static struct dentry *libappcore_dentry;
+static const char *libcapi_path;
+static struct dentry *libcapi_dentry;
+
+static void uninit_variables(void)
+{
+       kfree(lpad_path);
+       lpad_path = NULL;
+       lpad_dentry = NULL;
+
+       kfree(libappcore_path);
+       libappcore_path = NULL;
+       libappcore_dentry = NULL;
+
+       kfree(libcapi_path);
+       libcapi_path = NULL;
+       libcapi_dentry = NULL;
+}
+
+static bool is_init(void)
+{
+       return lpad_dentry && libappcore_dentry && libcapi_dentry;
+}
+
+static int do_set_lpad_info(const char *path, unsigned long dlopen,
+                           unsigned long dlsym)
+{
+       struct dentry *dentry;
+       const char *new_path;
+
+       dentry = dentry_by_path(path);
+       if (dentry == NULL) {
+               pr_err("dentry not found (path='%s')\n", path);
+               return -EINVAL;
+       }
+
+       new_path = kstrdup(path, GFP_KERNEL);
+       if (new_path == NULL) {
+               pr_err("out of memory\n");
+               return -ENOMEM;
+       }
+
+       kfree(lpad_path);
+
+       lpad_path = new_path;
+       lpad_dentry = dentry;
+       p_dlopen.offset = dlopen;
+       p_dlsym.offset = dlsym;
+
+       return 0;
+}
+
+static int do_set_appcore_info(struct nsp_info_data *info)
+{
+       struct dentry *dentry;
+       const char *new_path;
+       int ret = 0;
+
+       new_path = kstrdup(info->appcore_path, GFP_KERNEL);
+       if (!new_path)
+               return -ENOMEM;
+       kfree(libappcore_path);
+       libappcore_path = new_path;
+
+       new_path = kstrdup(info->capi_path, GFP_KERNEL);
+       if (!new_path) {
+               ret = -ENOMEM;
+               goto fail_alloc;
+       }
+       kfree(libcapi_path);
+       libcapi_path = new_path;
+
+       dentry = dentry_by_path(info->appcore_path);
+       if (!dentry) {
+               pr_err("dentry not found (path='%s')\n", info->appcore_path);
+               ret = -EINVAL;
+               goto fail;
+       }
+       libappcore_dentry = dentry;
+
+       dentry = dentry_by_path(info->capi_path);
+       if (!dentry) {
+               pr_err("dentry not found (path='%s')\n", info->capi_path);
+               ret = -EINVAL;
+               goto fail;
+       }
+       libcapi_dentry = dentry;
+
+       p_ac_efl_main.offset = info->ac_efl_init;
+       p_do_app.offset = info->do_app;
+       p_ac_init.offset = info->ac_init;
+       p_elm_run.offset = info->elm_run;
+
+       return 0;
+
+fail:
+       kfree(libcapi_path);
+       libcapi_path = NULL;
+fail_alloc:
+       kfree(libappcore_path);
+       libappcore_path = NULL;
+
+       return ret;
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                nsp_data                                  =
+ * ============================================================================
+ */
+struct nsp_data {
+       struct list_head list;
+
+       const char *app_path;
+       struct dentry *app_dentry;
+       struct probe_new p_main;
+
+       struct pf_group *pfg;
+};
+
+static LIST_HEAD(nsp_data_list);
+
+static struct nsp_data *nsp_data_create(const char *app_path,
+                                       unsigned long main_addr)
+{
+       struct dentry *dentry;
+       struct nsp_data *data;
+
+       dentry = dentry_by_path(app_path);
+       if (dentry == NULL)
+               return ERR_PTR(-ENOENT);
+
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       data->app_path = kstrdup(app_path, GFP_KERNEL);
+       if (data->app_path == NULL) {
+               kfree(data);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       data->app_dentry = dentry;
+       data->p_main.desc = &pin_main;
+       data->p_main.offset = main_addr;
+       data->pfg = NULL;
+
+       return data;
+}
+
+static void nsp_data_destroy(struct nsp_data *data)
+{
+       kfree(data->app_path);
+       kfree(data);
+}
+
+static struct nsp_data *nsp_data_find(const struct dentry *dentry)
+{
+       struct nsp_data *data;
+
+       list_for_each_entry(data, &nsp_data_list, list) {
+               if (data->app_dentry == dentry)
+                       return data;
+       }
+
+       return NULL;
+}
+
+static struct nsp_data *nsp_data_find_by_path(const char *path)
+{
+       struct nsp_data *data;
+
+       list_for_each_entry(data, &nsp_data_list, list) {
+               if (strcmp(data->app_path, path) == 0)
+                       return data;
+       }
+
+       return NULL;
+}
+
+static void nsp_data_add(struct nsp_data *data)
+{
+       list_add(&data->list, &nsp_data_list);
+}
+
+static void nsp_data_rm(struct nsp_data *data)
+{
+       list_del(&data->list);
+}
+
+static int nsp_data_inst(struct nsp_data *data)
+{
+       int ret;
+       struct pf_group *pfg;
+
+       pfg = get_pf_group_by_dentry(lpad_dentry, (void *)data->app_dentry);
+       if (pfg == NULL)
+               return -ENOMEM;
+
+       ret = pin_register(&p_dlsym, pfg, lpad_dentry);
+       if (ret)
+               goto put_g;
+
+       ret = pin_register(&p_dlopen, pfg, lpad_dentry);
+       if (ret)
+               goto ur_dlsym;
+
+       ret = pin_register(&data->p_main, pfg, data->app_dentry);
+       if (ret)
+               goto ur_dlopen;
+
+       ret = pin_register(&p_ac_efl_main, pfg, libappcore_dentry);
+       if (ret)
+               goto ur_main;
+
+       ret = pin_register(&p_ac_init, pfg, libcapi_dentry);
+       if (ret)
+               goto ur_ac_efl_main;
+
+       ret = pin_register(&p_elm_run, pfg, libcapi_dentry);
+       if (ret)
+               goto ur_ac_init;
+
+       ret = pin_register(&p_do_app, pfg, libappcore_dentry);
+       if (ret)
+               goto ur_elm_run;
+
+       data->pfg = pfg;
+
+       return 0;
+
+ur_elm_run:
+       pin_unregister(&p_elm_run, pfg);
+ur_ac_init:
+       pin_unregister(&p_ac_init, pfg);
+ur_ac_efl_main:
+       pin_unregister(&p_ac_efl_main, pfg);
+ur_main:
+       pin_unregister(&data->p_main, pfg);
+ur_dlopen:
+       pin_unregister(&p_dlopen, pfg);
+ur_dlsym:
+       pin_unregister(&p_dlsym, pfg);
+put_g:
+       put_pf_group(pfg);
+       return ret;
+}
+
+static void nsp_data_uninst(struct nsp_data *data)
+{
+       struct pf_group *pfg = data->pfg;
+
+       pin_unregister(&p_do_app, pfg);
+       pin_unregister(&p_elm_run, pfg);
+       pin_unregister(&p_ac_init, pfg);
+       pin_unregister(&p_ac_efl_main, pfg);
+       pin_unregister(&data->p_main, pfg);
+       pin_unregister(&p_dlopen, pfg);
+       pin_unregister(&p_dlsym, pfg);
+       put_pf_group(pfg);
+
+       data->pfg = NULL;
+}
+
+static int __nsp_add(const char *app_path, unsigned long main_addr)
+{
+       struct nsp_data *data;
+
+       if (nsp_data_find_by_path(app_path))
+               return -EEXIST;
+
+       data = nsp_data_create(app_path, main_addr);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       nsp_data_add(data);
+
+       return 0;
+}
+
+static int __nsp_rm(const char *path)
+{
+       struct dentry *dentry;
+       struct nsp_data *data;
+
+       dentry = dentry_by_path(path);
+       if (dentry == NULL)
+               return -ENOENT;
+
+       data = nsp_data_find(dentry);
+       if (data == NULL)
+               return -ESRCH;
+
+       nsp_data_rm(data);
+       nsp_data_destroy(data);
+
+       return 0;
+}
+
+static int __nsp_rm_all(void)
+{
+       struct nsp_data *data, *n;
+
+       list_for_each_entry_safe(data, n, &nsp_data_list, list) {
+               nsp_data_rm(data);
+               nsp_data_destroy(data);
+       }
+
+       return 0;
+}
+
+static void __nsp_disabel(void)
+{
+       struct nsp_data *data;
+
+       list_for_each_entry(data, &nsp_data_list, list) {
+               if (data->pfg)
+                       nsp_data_uninst(data);
+       }
+}
+
+static int __nsp_enable(void)
+{
+       int ret;
+       struct nsp_data *data;
+
+       list_for_each_entry(data, &nsp_data_list, list) {
+               ret = nsp_data_inst(data);
+               if (ret)
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       __nsp_disabel();
+       return ret;
+}
+
+
+
+
+
+
+
+/* ============================================================================
+ * =                             set parameters                               =
+ * ============================================================================
+ */
+#define F_ARG1(m, t, a)                m(t, a)
+#define F_ARG2(m, t, a, ...)   m(t, a), F_ARG1(m, __VA_ARGS__)
+#define F_ARG3(m, t, a, ...)   m(t, a), F_ARG2(m, __VA_ARGS__)
+#define F_ARG(n, m, ...)       F_ARG##n(m, __VA_ARGS__)
+
+#define M_TYPE_AND_ARG(t, a)   t a
+#define M_ARG(t, a)            a
+
+#define DECLARE_SAFE_FUNC(n, func_name, do_func, ...)  \
+int func_name(F_ARG(n, M_TYPE_AND_ARG,  __VA_ARGS__))  \
+{                                                      \
+       int ret;                                        \
+       mutex_lock(&stat_mutex);                        \
+       if (stat == NS_ON) {                            \
+               ret = -EBUSY;                           \
+               goto unlock;                            \
+       }                                               \
+       ret = do_func(F_ARG(n, M_ARG,  __VA_ARGS__));   \
+unlock:                                                        \
+       mutex_unlock(&stat_mutex);                      \
+       return ret;                                     \
+}
+
+#define DECLARE_SAFE_FUNC0(name, _do)          DECLARE_SAFE_FUNC(1, name, _do, void, /* */);
+#define DECLARE_SAFE_FUNC1(name, _do, ...)     DECLARE_SAFE_FUNC(1, name, _do, __VA_ARGS__);
+#define DECLARE_SAFE_FUNC2(name, _do, ...)     DECLARE_SAFE_FUNC(2, name, _do, __VA_ARGS__);
+#define DECLARE_SAFE_FUNC3(name, _do, ...)     DECLARE_SAFE_FUNC(3, name, _do, __VA_ARGS__);
+
+
+static DEFINE_MUTEX(stat_mutex);
+static enum nsp_stat stat = NS_OFF;
+
+DECLARE_SAFE_FUNC2(nsp_add, __nsp_add, const char *, app_path,
+                  unsigned long, main_addr);
+DECLARE_SAFE_FUNC1(nsp_rm, __nsp_rm, const char *, app_path);
+DECLARE_SAFE_FUNC0(nsp_rm_all, __nsp_rm_all);
+DECLARE_SAFE_FUNC3(nsp_set_lpad_info, do_set_lpad_info,
+                  const char *, path, unsigned long, dlopen,
+                  unsigned long, dlsym);
+DECLARE_SAFE_FUNC1(nsp_set_appcore_info, do_set_appcore_info,
+                  struct nsp_info_data *, info);
+
+
+
+
+
+/* ============================================================================
+ * =                               set stat                                   =
+ * ============================================================================
+ */
+static int set_stat_off(void)
+{
+       if (stat == NS_OFF)
+               return -EINVAL;
+
+       __nsp_disabel();
+
+       stat = NS_OFF;
+
+       return 0;
+}
+
+static int set_stat_on(void)
+{
+       if (is_init() == false)
+               return -EPERM;
+
+       if (stat == NS_ON)
+               return -EINVAL;
+
+       __nsp_enable();
+
+       stat = NS_ON;
+
+       return 0;
+}
+
+int nsp_set_stat(enum nsp_stat st)
+{
+       int ret = -EINVAL;
+
+       mutex_lock(&stat_mutex);
+       switch (st) {
+       case NS_OFF:
+               ret = set_stat_off();
+               break;
+       case NS_ON:
+               ret = set_stat_on();
+               break;
+       }
+       mutex_unlock(&stat_mutex);
+
+       return ret;
+}
+
+enum nsp_stat nsp_get_stat(void)
+{
+       return stat;
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                 tdata                                    =
+ * ============================================================================
+ */
+enum nsp_proc_stat {
+       NPS_OPEN_E,             /* mapping begin */
+       NPS_OPEN_R,
+       NPS_SYM_E,
+       NPS_SYM_R,              /* mapping end   */
+       NPS_MAIN_E,             /* main begin    */
+       NPS_AC_EFL_MAIN_E,      /* main end      */
+       NPS_AC_INIT_R,          /* create begin  */
+       NPS_ELM_RUN_E,          /* create end    */
+       NPS_DO_APP_E,           /* reset begin   */
+       NPS_DO_APP_R            /* reset end     */
+};
+
+struct tdata {
+       enum nsp_proc_stat stat;
+       struct nsp_data *nsp_data;
+       u64 time;
+       void __user *handle;
+       struct probe_new p_main;
+};
+
+
+static void ktd_init(struct task_struct *task, void *data)
+{
+       struct tdata *tdata = (struct tdata *)data;
+
+       tdata->nsp_data = NULL;
+}
+
+static struct ktask_data ktd = {
+       .init = ktd_init,
+       .size = sizeof(struct tdata),
+};
+
+static struct tdata *tdata_get(struct task_struct *task)
+{
+       return (struct tdata *)swap_ktd(&ktd, task);
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                handlers                                  =
+ * ============================================================================
+ */
+static int dlopen_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       const char __user *user_s = (const char __user *)swap_get_uarg(regs, 0);
+       const char *path;
+       struct nsp_data *nsp_data;
+
+       path = strdup_from_user(user_s, GFP_ATOMIC);
+       if (path == NULL)
+               return 0;
+
+       nsp_data = nsp_data_find_by_path(path);
+       if (nsp_data) {
+               struct tdata *tdata = tdata_get(current);
+
+               /* init tdata */
+               if (tdata->nsp_data == NULL) {
+                       tdata->stat = NPS_OPEN_E;
+                       tdata->time = swap_msg_current_time();
+                       tdata->nsp_data = nsp_data;
+               }
+       }
+
+       kfree(path);
+       return 0;
+}
+
+static int dlopen_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct tdata *tdata = tdata_get(current);
+       void *handle = (void *)regs_return_value(regs);
+
+       if ((tdata->stat == NPS_OPEN_E) && handle) {
+               tdata->stat = NPS_OPEN_R;
+               tdata->handle = handle;
+       } else {
+               tdata->handle = NULL;
+       }
+
+       return 0;
+}
+
+static int dlsym_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct tdata *tdata = tdata_get(current);
+       void __user *handle = (void __user *)swap_get_uarg(regs, 0);
+       const char __user *str = (const char __user *)swap_get_uarg(regs, 1);
+
+       if (handle == tdata->handle && tdata->stat == NPS_OPEN_R) {
+               const char *name;
+
+               name = strdup_from_user(str, GFP_ATOMIC);
+               if (name && (strcmp(name, "main") == 0))
+                       tdata->stat = NPS_SYM_E;
+
+               kfree(name);
+       }
+
+       return 0;
+}
+
+static int dlsym_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct tdata *tdata = tdata_get(current);
+
+       if (tdata->handle && tdata->stat == NPS_SYM_E)
+               tdata->stat = NPS_SYM_R;
+
+       return 0;
+}
+
+static void stage_begin(enum nsp_proc_stat priv, enum nsp_proc_stat cur)
+{
+       struct tdata *tdata = tdata_get(current);
+
+       if (tdata->handle && tdata->stat == priv) {
+               tdata->stat = cur;
+               tdata->time = swap_msg_current_time();
+       }
+}
+
+static void stage_end(enum nsp_proc_stat priv, enum nsp_proc_stat cur,
+                     enum nsp_msg_stage st)
+{
+       struct tdata *tdata = tdata_get(current);
+       u64 time_start;
+       u64 time_end;
+
+       if (tdata->handle && tdata->stat == priv) {
+               tdata->stat = cur;
+               time_start = tdata->time;
+
+               time_end = swap_msg_current_time();
+               nsp_msg(st, time_start, time_end);
+       }
+}
+
+static int main_h(struct uprobe *p, struct pt_regs *regs)
+{
+       struct tdata *tdata = tdata_get(current);
+       u64 time_start;
+       u64 time_end;
+
+       if (tdata->handle && tdata->stat == NPS_SYM_R) {
+               tdata->stat = NPS_MAIN_E;
+               time_start = tdata->time;
+               time_end = swap_msg_current_time();
+               tdata->time = time_end;
+
+               nsp_msg(NMS_MAPPING, time_start, time_end);
+       }
+
+       return 0;
+}
+
+/* FIXME: workaround for simultaneously nsp and main() function profiling */
+#include <retprobe/rp_msg.h>
+#include <us_manager/us_manager.h>
+
+static int main_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct uretprobe *rp = ri->rp;
+
+       if (rp) {
+               main_h(&rp->up, regs);
+
+               if (get_quiet() == QT_OFF) {
+                       struct sspt_ip *ip;
+                       unsigned long func_addr;
+
+                       ip = container_of(rp, struct sspt_ip, retprobe);
+                       func_addr = (unsigned long)ip->orig_addr;
+                       rp_msg_entry(regs, func_addr, "p");
+               }
+       }
+
+       return 0;
+}
+
+static int main_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct uretprobe *rp = ri->rp;
+
+       if (rp && get_quiet() == QT_OFF) {
+               struct sspt_ip *ip;
+               unsigned long func_addr;
+               unsigned long ret_addr;
+
+               ip = container_of(rp, struct sspt_ip, retprobe);
+               func_addr = (unsigned long)ip->orig_addr;
+               ret_addr = (unsigned long)ri->ret_addr;
+               rp_msg_exit(regs, func_addr, 'n', ret_addr);
+       }
+
+       return 0;
+}
+
+static int ac_efl_main_h(struct uprobe *p, struct pt_regs *regs)
+{
+       stage_end(NPS_MAIN_E, NPS_AC_EFL_MAIN_E, NMS_MAIN);
+       return 0;
+}
+
+static int ac_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       stage_begin(NPS_AC_EFL_MAIN_E, NPS_AC_INIT_R);
+       return 0;
+}
+
+static int elm_run_h(struct uprobe *p, struct pt_regs *regs)
+{
+       stage_end(NPS_AC_INIT_R, NPS_ELM_RUN_E, NMS_CREATE);
+       return 0;
+}
+
+static int do_app_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       int event = swap_get_uarg(regs, 0);
+       enum { AE_RESET = 5 };  /* FIXME: hardcode */
+
+       if (event == AE_RESET)
+               stage_begin(NPS_ELM_RUN_E, NPS_DO_APP_E);
+
+       return 0;
+}
+
+static int do_app_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       stage_end(NPS_DO_APP_E, NPS_DO_APP_R, NMS_RESET);
+       return 0;
+}
+
+
+
+
+
+int nsp_init(void)
+{
+       return swap_ktd_reg(&ktd);
+}
+
+void nsp_exit(void)
+{
+       if (stat == NS_ON)
+               set_stat_off();
+
+       uninit_variables();
+       swap_ktd_unreg(&ktd);
+}
diff --git a/modules/nsp/nsp.h b/modules/nsp/nsp.h
new file mode 100644 (file)
index 0000000..35236a4
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _NSP_H
+#define _NSP_H
+
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+enum offset_t {
+       OS_CREATE,
+       OS_RESET
+};
+
+enum nsp_stat {
+       NS_OFF,
+       NS_ON
+};
+
+struct nsp_info_data {
+       const char *appcore_path;
+       unsigned long ac_efl_init;
+       unsigned long do_app;
+
+       const char *capi_path;
+       unsigned long ac_init;
+       unsigned long elm_run;
+};
+
+int nsp_init(void);
+void nsp_exit(void);
+
+int nsp_set_lpad_info(const char *path, unsigned long dlopen,
+                     unsigned long dlsym);
+int nsp_set_appcore_info(struct nsp_info_data *info);
+
+int nsp_set_stat(enum nsp_stat st);
+enum nsp_stat nsp_get_stat(void);
+
+int nsp_add(const char *app_path, unsigned long main_addr);
+int nsp_rm(const char *app_path);
+int nsp_rm_all(void);
+
+
+#endif /* _NSP_H */
diff --git a/modules/nsp/nsp_debugfs.c b/modules/nsp/nsp_debugfs.c
new file mode 100644 (file)
index 0000000..ebf0eb4
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/limits.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <master/swap_debugfs.h>
+#include "nsp.h"
+
+
+/* remove end-line symbols */
+static void rm_endline_symbols(char *buf, size_t len)
+{
+       char *p, *buf_end;
+
+       buf_end = buf + len;
+       for (p = buf; p != buf_end; ++p)
+               if (*p == '\n' || *p == '\r')
+                       *p = '\0';
+}
+
+/*
+ * format:
+ *     main:app_path
+ *
+ * sample:
+ *     0x00000d60:/bin/app_sample
+ */
+static int do_add(const char *buf, size_t len)
+{
+       int n, ret;
+       char *app_path;
+       unsigned long main_addr;
+       const char fmt[] = "%%lx:/%%%ds";
+       char fmt_buf[64];
+
+       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
+       if (n <= 0)
+               return -EINVAL;
+
+       app_path = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (app_path == NULL)
+               return -ENOMEM;
+
+       n = sscanf(buf, fmt_buf, &main_addr, app_path + 1);
+       if (n != 2) {
+               ret = -EINVAL;
+               goto free_app_path;
+       }
+       app_path[0] = '/';
+
+       ret = nsp_add(app_path, main_addr);
+
+free_app_path:
+       kfree(app_path);
+       return ret;
+}
+
+/*
+ * format:
+ *     path
+ *
+ * sample:
+ *     /tmp/sample
+ */
+static int do_rm(const char *buf, size_t len)
+{
+       return nsp_rm(buf);
+}
+
+static int do_rm_all(const char *buf, size_t len)
+{
+       return nsp_rm_all();
+}
+
+/*
+ * format:
+ *     dlopen_addr@plt:dlsym_addr@plt:launchpad_path
+ *
+ * sample:
+ *     0x000234:0x000342:/usr/bin/launchpad-loader
+ */
+static int do_set_lpad_info(const char *data, size_t len)
+{
+       int n, ret;
+       unsigned long dlopen_addr;
+       unsigned long dlsym_addr;
+       char *lpad_path;
+       const char fmt[] = "%%lx:%%lx:/%%%ds";
+       char fmt_buf[64];
+
+       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
+       if (n <= 0)
+               return -EINVAL;
+
+       lpad_path = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (lpad_path == NULL)
+               return -ENOMEM;
+
+       n = sscanf(data, fmt_buf, &dlopen_addr, &dlsym_addr, lpad_path + 1);
+       if (n != 3) {
+               ret = -EINVAL;
+               goto free_lpad_path;
+       }
+       lpad_path[0] = '/';
+
+       ret = nsp_set_lpad_info(lpad_path, dlopen_addr, dlsym_addr);
+
+free_lpad_path:
+       kfree(lpad_path);
+       return ret;
+}
+
+/*
+ * format:
+ *     appcore_efl_init:__do_app:libappcore-efl ui_app_init:elm_run@plt:libcapi-appfw-application
+ *
+ * sample:
+ *     0x2000:0x2ed0:/usr/lib/libappcore-efl.so.1 0x2b20:0x11f0:/usr/lib/libcapi-appfw-application.so.0
+ */
+static int do_set_appcore_info(const char *data, size_t len)
+{
+       int n, ret;
+       struct nsp_info_data info;
+       const char fmt[] = "%%lx:%%lx:/%%%ds %%lx:%%lx:/%%%ds";
+       char fmt_buf[64];
+       char *appcore_path, *capi_path;
+
+       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2, PATH_MAX - 2);
+       if (n <= 0)
+               return -EINVAL;
+
+       appcore_path = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (!appcore_path)
+               return -ENOMEM;
+
+       capi_path = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (!capi_path) {
+               ret = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       n = sscanf(data, fmt_buf,
+                  &info.ac_efl_init, &info.do_app, appcore_path + 1,
+                  &info.ac_init, &info.elm_run, capi_path + 1);
+       if (n != 6) {
+               ret = -EINVAL;
+               goto fail;
+       }
+       appcore_path[0] = '/';
+       capi_path[0] = '/';
+
+       info.appcore_path = appcore_path;
+       info.capi_path = capi_path;
+       ret = nsp_set_appcore_info(&info);
+
+fail:
+       kfree(capi_path);
+fail_alloc:
+       kfree(appcore_path);
+       return ret;
+}
+
+/*
+ * format:
+ *     0 byte - type
+ *     1 byte - ' '
+ *     2.. bytes - data
+ */
+static int do_cmd(const char *data, size_t len)
+{
+       char type;
+       size_t len_data;
+       const char *cmd_data;
+
+       if (len) {
+               if (data[0] == 'c')
+                       return do_rm_all(data + 1, len - 1);
+       }
+       /*
+        * 0 byte - type
+        * 1 byte - ' '
+        */
+       if (len < 2 || data[1] != ' ')
+               return -EINVAL;
+
+       len_data = len - 2;
+       cmd_data = data + 2;
+       type = data[0];
+       switch (type) {
+       case 'a':
+               return do_add(cmd_data, len_data);
+       case 'b':
+               return do_set_lpad_info(cmd_data, len_data);
+       case 'l':
+               return do_set_appcore_info(cmd_data, len_data);
+       case 'r':
+               return do_rm(cmd_data, len_data);
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+
+
+/* ============================================================================
+ * ===                          DEBUGFS FOR CMD                             ===
+ * ============================================================================
+ */
+static ssize_t write_cmd(struct file *file, const char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       char *buf;
+       ssize_t ret = count;
+
+       buf = kmalloc(count + 1, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, user_buf, count)) {
+               ret = -EFAULT;
+               goto free_buf;
+       }
+
+       buf[count] = '\0';
+       rm_endline_symbols(buf, count);
+
+       if (do_cmd(buf, count))
+               ret = -EINVAL;
+
+free_buf:
+       kfree(buf);
+
+       return ret;
+}
+
+static ssize_t read_cmd(struct file *file, char __user *user_buf,
+                       size_t count, loff_t *ppos)
+{
+       const char help[] =
+                       "use:\n"
+                       "\ta $app_path - add\n"
+                       "\tr $app_path - remove\n"
+                       "\tc - remove all\n"
+                       "\tb dlopen_addr@plt:dlsym_addr@plt:launchpad_path\n"
+                       "\tl appcore_efl_init:__do_app:libappcore-efl_path ui_app_init:elm_run@plt:libcapi-appfw-application_path\n";
+       ssize_t ret;
+
+       ret = simple_read_from_buffer(user_buf, count, ppos,
+                                     help, sizeof(help));
+
+       return ret;
+}
+
+static const struct file_operations fops_cmd = {
+       .read =         read_cmd,
+       .write =        write_cmd,
+       .llseek =       default_llseek
+};
+
+
+
+
+/* ============================================================================
+ * ===                         DEBUGFS FOR ENABLE                           ===
+ * ============================================================================
+ */
+static ssize_t read_enabled(struct file *file, char /*__user*/ *user_buf,
+                           size_t count, loff_t *ppos)
+{
+       char buf[2];
+
+       buf[0] = nsp_get_stat() == NS_OFF ? '0' : '1';
+       buf[1] = '\n';
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled(struct file *file, const char /*__user*/ *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       int ret = 0;
+       char buf[32];
+       size_t buf_size;
+
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       switch (buf[0]) {
+       case '1':
+               ret = nsp_set_stat(NS_ON);
+               break;
+       case '0':
+               ret = nsp_set_stat(NS_OFF);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static const struct file_operations fops_enabled = {
+       .read =         read_enabled,
+       .write =        write_enabled,
+       .llseek =       default_llseek,
+};
+
+
+
+
+static struct dentry *nsp_dir = NULL;
+
+void nsp_debugfs_exit(void)
+{
+       if (nsp_dir)
+               debugfs_remove_recursive(nsp_dir);
+
+       nsp_dir = NULL;
+}
+
+int nsp_debugfs_init(void)
+{
+       struct dentry *dentry;
+
+       dentry = swap_debugfs_getdir();
+       if (dentry == NULL)
+               return -ENOENT;
+
+       nsp_dir = swap_debugfs_create_dir("nsp", dentry);
+       if (nsp_dir == NULL)
+               return -ENOMEM;
+
+       dentry = swap_debugfs_create_file("cmd", 0600, nsp_dir, NULL,
+                                         &fops_cmd);
+       if (dentry == NULL)
+               goto fail;
+
+       dentry = swap_debugfs_create_file("enabled", 0600, nsp_dir, NULL,
+                                         &fops_enabled);
+       if (dentry == NULL)
+               goto fail;
+
+       return 0;
+
+fail:
+       nsp_debugfs_exit();
+       return -ENOMEM;
+}
diff --git a/modules/nsp/nsp_debugfs.h b/modules/nsp/nsp_debugfs.h
new file mode 100644 (file)
index 0000000..62565b7
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _NSP_DEBUGFS_H
+#define _NSP_DEBUGFS_H
+
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+int nsp_debugfs_init(void);
+void nsp_debugfs_exit(void);
+
+
+#endif /* _NSP_DEBUGFS_H */
diff --git a/modules/nsp/nsp_module.c b/modules/nsp/nsp_module.c
new file mode 100644 (file)
index 0000000..e40f8ee
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <master/swap_initializer.h>
+#include "nsp.h"
+#include "nsp_debugfs.h"
+
+
+SWAP_LIGHT_INIT_MODULE(NULL, nsp_init, nsp_exit,
+                      nsp_debugfs_init, nsp_debugfs_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/nsp/nsp_msg.c b/modules/nsp/nsp_msg.c
new file mode 100644 (file)
index 0000000..b48c3a1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <writer/swap_msg.h>
+#include "nsp_msg.h"
+
+
+struct nsp_msg_struct {
+       u32 pid;
+       u32 stage;
+       u64 begin_time;
+       u64 end_time;
+} __packed;
+
+
+void nsp_msg(enum nsp_msg_stage stage, u64 begin_time, u64 end_time)
+{
+       struct swap_msg *m;
+       struct nsp_msg_struct *nsp;
+
+       m = swap_msg_get(MSG_NSP);
+
+       nsp = (struct nsp_msg_struct *)swap_msg_payload(m);
+       nsp->pid = (u32)current->tgid;
+       nsp->stage = (u32)stage;
+       nsp->begin_time = begin_time;
+       nsp->end_time = end_time;
+
+       swap_msg_flush(m, sizeof(*nsp));
+       swap_msg_put(m);
+}
diff --git a/modules/nsp/nsp_msg.h b/modules/nsp/nsp_msg.h
new file mode 100644 (file)
index 0000000..17d50ba
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+#ifndef _NSP_MSG_H
+#define _NSP_MSG_H
+
+
+#include <linux/types.h>
+
+
+enum nsp_msg_stage {
+       NMS_MAPPING     = 0x00,
+       NMS_MAIN        = 0x01,
+       NMS_CREATE      = 0x02,
+       NMS_RESET       = 0x03,
+};
+
+
+void nsp_msg(enum nsp_msg_stage stage, u64 begin_time, u64 end_time);
+
+
+#endif /* _NSP_MSG_H */
diff --git a/modules/nsp/nsp_print.h b/modules/nsp/nsp_print.h
new file mode 100644 (file)
index 0000000..d4d68d4
--- /dev/null
@@ -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 <v.cherkashin@samsung.com>
+ *
+ */
+
+#ifndef _NSP_PRINT_H
+#define _NSP_PRINT_H
+
+
+#include <linux/printk.h>
+
+
+#define NSP_PREFIX "[NSP] "
+
+#define nsp_print(...) printk(NSP_PREFIX __VA_ARGS__)
+
+
+#endif /* _NSP_PRINT_H */
diff --git a/modules/pack.sh b/modules/pack.sh
new file mode 100755 (executable)
index 0000000..3186cbc
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash -ex
+
+if [ $# -ne 1 ]; then
+       echo "Usage $0 <dest_dir>"
+       exit 0
+fi
+
+scrdir=$(dirname $(readlink -f $0))
+
+dest=$1
+mkdir -p $dest
+
+mode=0666
+
+modules="master/swap_master.ko
+        buffer/swap_buffer.ko
+        ksyms/swap_ksyms.ko
+        driver/swap_driver.ko
+        writer/swap_writer.ko
+        kprobe/swap_kprobe.ko
+        ks_manager/swap_ks_manager.ko
+        uprobe/swap_uprobe.ko
+        us_manager/swap_us_manager.ko
+        ks_features/swap_ks_features.ko
+        sampler/swap_sampler.ko
+        energy/swap_energy.ko
+        parser/swap_message_parser.ko
+        retprobe/swap_retprobe.ko
+        loader/swap_loader.ko
+        preload/swap_preload.ko
+        uihv/swap_uihv.ko
+        fbiprobe/swap_fbiprobe.ko
+        wsp/swap_wsp.ko
+        nsp/swap_nsp.ko
+        task_ctx/swap_taskctx.ko
+        got_patcher/swap_gtp.ko"
+
+for i in $modules; do
+       mv $scrdir/$i $dest/
+       chmod 0666 $dest/$(basename $i)
+done
diff --git a/modules/parser/Kbuild b/modules/parser/Kbuild
new file mode 100644 (file)
index 0000000..7faf7ba
--- /dev/null
@@ -0,0 +1,17 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../energy/Module.symvers \
+                       $(src)/../ks_features/Module.symvers \
+                       $(src)/../driver/Module.symvers \
+                       $(src)/../writer/Module.symvers \
+                       $(src)/../us_manager/Module.symvers \
+                       $(src)/../sampler/Module.symvers
+
+obj-m := swap_message_parser.o
+swap_message_parser-y := swap_msg_parser.o \
+                         msg_parser.o \
+                         msg_buf.o \
+                         msg_cmd.o \
+                         features.o \
+                         us_inst.o \
+                         cpu_ctrl.o \
+                         usm_msg.o
diff --git a/modules/parser/cpu_ctrl.c b/modules/parser/cpu_ctrl.c
new file mode 100644 (file)
index 0000000..f5498b9
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * parser/cpu_ctrl.c
+ * @author Vasiliy Ulyanov <v.ulyanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * CPU controls implementation.
+ */
+
+#include <linux/cpumask.h>
+#include <linux/cpu.h>
+#include <ksyms/ksyms.h>
+
+#ifdef CONFIG_SMP
+static void (*swap_cpu_maps_update_begin)(void);
+static void (*swap_cpu_maps_update_done)(void);
+static int (*swap_cpu_down)(unsigned int, int);
+static int (*swap_cpu_up)(unsigned int, int);
+
+/**
+ * @brief Disables nonboot CPUs lock.
+ *
+ * @param mask Pointer to CPU mask struct.
+ * @return 0 on success, error code on error.
+ */
+int swap_disable_nonboot_cpus_lock(struct cpumask *mask)
+{
+       int boot_cpu, cpu;
+       int ret = 0;
+
+       swap_cpu_maps_update_begin();
+       cpumask_clear(mask);
+
+       boot_cpu = cpumask_first(cpu_online_mask);
+
+       for_each_online_cpu(cpu) {
+               if (cpu == boot_cpu)
+                       continue;
+               ret = swap_cpu_down(cpu, 0);
+               if (ret == 0)
+                       cpumask_set_cpu(cpu, mask);
+               printk(KERN_INFO "===> SWAP CPU[%d] down(%d)\n", cpu, ret);
+       }
+
+       WARN_ON(num_online_cpus() > 1);
+       return ret;
+}
+
+/**
+ * @brief Enables nonboot CPUs unlock.
+ *
+ * @param mask Pointer to CPU mask struct.
+ * @return 0 on success, error code on error.
+ */
+int swap_enable_nonboot_cpus_unlock(struct cpumask *mask)
+{
+       int cpu, ret = 0;
+
+       if (cpumask_empty(mask))
+               goto out;
+
+       for_each_cpu(cpu, mask) {
+               ret = swap_cpu_up(cpu, 0);
+               printk(KERN_INFO "===> SWAP CPU[%d] up(%d)\n", cpu, ret);
+       }
+
+out:
+       swap_cpu_maps_update_done();
+
+       return ret;
+}
+
+/**
+ * @brief Intializes CPU controls.
+ *
+ * @return 0 on success, error code on error.
+ */
+int init_cpu_deps(void)
+{
+       const char *sym = "cpu_maps_update_begin";
+
+       swap_cpu_maps_update_begin = (void *)swap_ksyms(sym);
+       if (!swap_cpu_maps_update_begin)
+               goto not_found;
+
+       sym = "cpu_maps_update_done";
+       swap_cpu_maps_update_done = (void *)swap_ksyms(sym);
+       if (!swap_cpu_maps_update_done)
+               goto not_found;
+
+       sym = "_cpu_up";
+       swap_cpu_up = (void *)swap_ksyms(sym);
+       if (!swap_cpu_up)
+               goto not_found;
+
+       sym = "_cpu_down";
+       swap_cpu_down = (void *)swap_ksyms(sym);
+       if (!swap_cpu_down)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol %s(...) not found\n", sym);
+       return -ESRCH;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/modules/parser/cpu_ctrl.h b/modules/parser/cpu_ctrl.h
new file mode 100644 (file)
index 0000000..36d3ed1
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file parser/cpu_ctrl.h
+ * @author Vasiliy Ulyanov <v.ulyanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * CPU controls interface.
+ */
+
+#ifndef _CPU_CTRL_H_
+#define _CPU_CTRL_H_
+
+struct cpumask;
+
+#ifdef CONFIG_SMP
+int swap_disable_nonboot_cpus_lock(struct cpumask *mask);
+int swap_enable_nonboot_cpus_unlock(struct cpumask *mask);
+
+int init_cpu_deps(void);
+
+#else /* CONFIG_SMP */
+
+static inline int swap_disable_nonboot_cpus_lock(struct cpumask *mask)
+{
+       return 0;
+}
+
+static inline int swap_enable_nonboot_cpus_unlock(struct cpumask *mask)
+{
+       return 0;
+}
+
+static inline int init_cpu_deps(void)
+{
+       return 0;
+}
+
+#endif /* CONFIG_SMP */
+
+#endif /* _CPU_CTRL_H_ */
diff --git a/modules/parser/features.c b/modules/parser/features.c
new file mode 100644 (file)
index 0000000..da2d61d
--- /dev/null
@@ -0,0 +1,606 @@
+/**
+ * parser/features.c
+ * @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
+ *
+ * Features control implementation.
+ */
+
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <ks_features/ks_features.h>
+#include <us_manager/us_manager.h>
+#include "parser_defs.h"
+#include "features.h"
+#include "msg_parser.h"
+
+#include <writer/swap_msg.h>
+#include <writer/event_filter.h>
+#include <sampler/swap_sampler_module.h>
+#include <energy/energy.h>
+
+/**
+ * @enum features_list
+ * List of supported features.
+ */
+enum features_list {
+       syscall_file    = (1 << 10),    /**< File operation syscalls tracing */
+       syscall_ipc     = (1 << 11),    /**< IPC syscall tracing */
+       syscall_process = (1 << 12),    /**< Process syscalls tracing */
+       syscall_signal  = (1 << 13),    /**< Signal syscalls tracing */
+       syscall_network = (1 << 14),    /**< Network syscalls tracing */
+       syscall_desc    = (1 << 15),    /**< Descriptor syscalls tracing */
+       context_switch  = (1 << 16),    /**< Context switch tracing */
+       func_sampling   = (1 << 19)     /**< Function sampling */
+};
+
+/**
+ * @brief Start user-space instrumentation event handling.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return 0.
+ */
+int set_us_inst(struct conf_data *conf)
+{
+       set_quiet(QT_OFF);
+
+       return 0;
+}
+
+/**
+ * @brief Stop user-space instrumentation event handling.
+ *
+ * @return 0.
+ */
+int unset_us_inst(void)
+{
+       set_quiet(QT_ON);
+
+       return 0;
+}
+
+/**
+ * @brief Set syscall file feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_syscall_file(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_FILE);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall file feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_syscall_file(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_FILE);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall ipc feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_syscall_ipc(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_IPC);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall ipc feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_syscall_ipc(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_IPC);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall process feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_syscall_process(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_PROCESS);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall process feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_syscall_process(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_PROCESS);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall signal feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_syscall_signal(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_SIGNAL);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall signal feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_syscall_signal(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_SIGNAL);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall network feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_syscall_network(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_NET);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall network feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_syscall_network(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_NET);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall desc feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_syscall_desc(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_DESC);
+
+       return ret;
+}
+
+/**
+ * @brief Set syscall desc feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_syscall_desc(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_DESC);
+
+       return ret;
+}
+
+/**
+ * @brief Set context switch feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_context_switch(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_feature(FID_SWITCH);
+
+       return ret;
+}
+/**
+ * @brief Set context switch feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_context_switch(void)
+{
+       int ret;
+
+       ret = unset_feature(FID_SWITCH);
+
+       return ret;
+}
+
+
+
+
+
+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 = raw_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))
+               sample_msg(regs);
+}
+
+/**
+ * @brief Set sampling feature on.
+ *
+ * @param conf Pointer to conf_data config.
+ * @return set_feature results.
+ */
+int set_func_sampling(struct conf_data *conf)
+{
+       int ret;
+
+       ret = swap_sampler_start(conf->data_msg_period, sampler_cb);
+
+       return ret;
+}
+
+/**
+ * @brief Set sampling feature off.
+ *
+ * @return unset_feature results.
+ */
+int unset_func_sampling(void)
+{
+       int ret;
+
+       ret = swap_sampler_stop();
+
+       return ret;
+}
+
+static int set_func_energy(struct conf_data *conf)
+{
+       return set_energy();
+}
+
+static int unset_func_energy(void)
+{
+       return unset_energy();
+}
+
+static int set_sysfile_activity(struct conf_data *conf)
+{
+       return set_feature(FID_SYSFILE_ACTIVITY);
+}
+
+static int unset_sysfile_activity(void)
+{
+       return unset_feature(FID_SYSFILE_ACTIVITY);
+}
+
+/**
+ * @struct feature_item
+ * @brief Struct that describes feature.
+ * @var feature_item::name
+ * Feature name.
+ * @var feature_item::set
+ * Set feature callback.
+ * @var feature_item::unset
+ * Unset feature callback.
+ */
+struct feature_item {
+       char *name;
+       int (*set)(struct conf_data *conf);
+       int (*unset)(void);
+};
+
+static struct feature_item feature_us_inst = {
+       .name = "user space instrumentation",
+       .set = set_us_inst,
+       .unset = unset_us_inst
+};
+
+static struct feature_item feature_syscall_file = {
+       .name = "file operation syscalls",
+       .set = set_syscall_file,
+       .unset = unset_syscall_file
+};
+
+static struct feature_item feature_syscall_ipc = {
+       .name = "IPC syscall",
+       .set = set_syscall_ipc,
+       .unset = unset_syscall_ipc
+};
+
+static struct feature_item feature_syscall_process = {
+       .name = "process syscalls",
+       .set = set_syscall_process,
+       .unset = unset_syscall_process
+};
+
+static struct feature_item feature_syscall_signal = {
+       .name = "signal syscalls",
+       .set = set_syscall_signal,
+       .unset = unset_syscall_signal
+};
+
+static struct feature_item feature_syscall_network = {
+       .name = "network syscalls",
+       .set = set_syscall_network,
+       .unset = unset_syscall_network
+};
+
+static struct feature_item feature_syscall_desc = {
+       .name = "descriptor syscalls",
+       .set = set_syscall_desc,
+       .unset = unset_syscall_desc
+};
+
+static struct feature_item feature_context_switch = {
+       .name = "context switch",
+       .set = set_context_switch,
+       .unset = unset_context_switch
+};
+
+static struct feature_item feature_func_sampling = {
+       .name = "function sampling",
+       .set = set_func_sampling,
+       .unset = unset_func_sampling
+};
+
+static struct feature_item feature_func_energy = {
+       .name = "energy",
+       .set = set_func_energy,
+       .unset = unset_func_energy
+};
+
+static struct feature_item feature_sysfile_activity = {
+       .name = "system file activity",
+       .set = set_sysfile_activity,
+       .unset = unset_sysfile_activity
+};
+
+static struct feature_item *feature_list[] = {
+ /*  0 */      NULL,
+ /*  1 */      NULL,
+ /*  2 */      &feature_us_inst,
+ /*  3 */      NULL,
+ /*  4 */      NULL,
+ /*  5 */      NULL,
+ /*  6 */      NULL,
+ /*  7 */      NULL,
+ /*  8 */      NULL,
+ /*  9 */      NULL,
+ /* 10 */      &feature_syscall_file,
+ /* 11 */      &feature_syscall_ipc,
+ /* 12 */      &feature_syscall_process,
+ /* 13 */      &feature_syscall_signal,
+ /* 14 */      &feature_syscall_network,
+ /* 15 */      &feature_syscall_desc,
+ /* 16 */      &feature_context_switch,
+ /* 17 */      NULL,
+ /* 18 */      NULL,
+ /* 19 */      &feature_func_sampling,
+ /* 20 */      NULL,
+ /* 21 */      NULL,
+ /* 22 */      NULL,
+ /* 23 */      NULL,
+ /* 24 */      NULL,
+ /* 25 */      NULL,
+ /* 26 */      &feature_func_energy,
+ /* 27 */      NULL,
+ /* 28 */      NULL,
+ /* 29 */      NULL,
+ /* 30 */      NULL,
+ /* 31 */      NULL,
+ /* 32 */      NULL,
+ /* 33 */      NULL,
+ /* 34 */      NULL,
+ /* 35 */      NULL,
+ /* 36 */      NULL,
+ /* 37 */      NULL,
+ /* 38 */      NULL,
+ /* 39 */      NULL,
+ /* 40 */      NULL,
+ /* 41 */      NULL,
+ /* 42 */      NULL,
+ /* 43 */      NULL,
+ /* 44 */      NULL,
+ /* 45 */      NULL,
+ /* 46 */      NULL,
+ /* 47 */      NULL,
+ /* 48 */      &feature_sysfile_activity,
+};
+
+/**
+ * @brief SIZE_FEATURE_LIST definition.
+ */
+enum {
+       SIZE_FEATURE_LIST =
+       sizeof(feature_list) / sizeof(struct feature_item *),
+};
+
+static u64 feature_inst;
+static u64 feature_mask;
+
+/**
+ * @brief Inits features list.
+ *
+ * @return 0.
+ */
+int once_features(void)
+{
+       int i;
+       for (i = 0; i < SIZE_FEATURE_LIST; ++i) {
+               printk(KERN_INFO "### f init_feature_mask[%2d]=%p\n", i,
+                      feature_list[i]);
+               if (feature_list[i] != NULL) {
+                       feature_mask |= ((u64)1) << i;
+                       printk(KERN_INFO "### f name=%s\n",
+                              feature_list[i]->name);
+               }
+       }
+
+       return 0;
+}
+
+static int do_set_features(struct conf_data *conf)
+{
+       int i, ret;
+       u64 feature_XOR;
+       u64 features, features_backup;
+
+       /* TODO: field use_features1 is not used*/
+       features_backup = features = conf->use_features0;
+
+       features &= feature_mask;
+       feature_XOR = features ^ feature_inst;
+
+       for (i = 0; feature_XOR && i < SIZE_FEATURE_LIST; ++i) {
+               if ((feature_XOR & 1) && feature_list[i] != NULL) {
+                       u64 f_mask;
+                       if (features & 1)
+                               ret = feature_list[i]->set(conf);
+                       else
+                               ret = feature_list[i]->unset();
+
+                       if (ret) {
+                               char *func = features & 1 ? "set" : "unset";
+                               print_err("%s '%s' ret=%d\n",
+                                         func, feature_list[i]->name, ret);
+
+                               return ret;
+                       }
+                       f_mask = ~((u64)1 << i);
+                       feature_inst = (feature_inst & f_mask) |
+                                      (features_backup & ~f_mask);
+               }
+
+               features >>= 1;
+               feature_XOR >>= 1;
+       }
+
+       return 0;
+}
+
+static DEFINE_MUTEX(mutex_features);
+
+/**
+ * @brief Wrapper for do_set_features with locking.
+ *
+ * @param conf Pointer to the current config.
+ * @return do_set_features result.
+ */
+int set_features(struct conf_data *conf)
+{
+       int ret;
+
+       mutex_lock(&mutex_features);
+       ret = do_set_features(conf);
+       mutex_unlock(&mutex_features);
+
+       return ret;
+}
+
+void disable_all_features(void)
+{
+       struct conf_data conf;
+
+       conf.use_features0 = 0;
+       conf.use_features1 = 0;
+       conf.data_msg_period = 0;
+       conf.sys_trace_period = 0;
+
+       BUG_ON(set_features(&conf));
+       BUG_ON(feature_inst);
+}
diff --git a/modules/parser/features.h b/modules/parser/features.h
new file mode 100644 (file)
index 0000000..09b7b09
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * @file parser/features.h
+ * @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
+ *
+ * Features control interface declaration.
+ */
+
+
+#ifndef _FEATURES_H
+#define _FEATURES_H
+
+struct conf_data;
+
+int once_features(void);
+
+int set_features(struct conf_data *conf);
+void disable_all_features(void);
+
+#endif /* _FEATURES_H */
diff --git a/modules/parser/msg_buf.c b/modules/parser/msg_buf.c
new file mode 100644 (file)
index 0000000..cdaf044
--- /dev/null
@@ -0,0 +1,217 @@
+/**
+ * parser/msg_buf.c
+ * @author Vyacheslav Cherkashin
+ * @author Vitaliy Cherepanov
+ *
+ * @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
+ *
+ * Message buffer controls implementation.
+ */
+
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "msg_buf.h"
+#include "parser_defs.h"
+
+/**
+ * @brief Initializes message buffer.
+ *
+ * @param mb Pointer to message buffer struct.
+ * @param size Size of the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int init_mb(struct msg_buf *mb, size_t size)
+{
+       if (size) {
+               mb->begin = vmalloc(size);
+               if (mb->begin == NULL) {
+                       printk(KERN_INFO "Cannot alloc memory!\n");
+                       return -ENOMEM;
+               }
+
+               mb->ptr = mb->begin;
+               mb->end = mb->begin + size;
+       } else
+               mb->begin = mb->end = mb->ptr = NULL;
+
+       return 0;
+}
+
+/**
+ * @brief Uninitializes message buffer.
+ *
+ * @param mb Pointer to message buffer struct.
+ * @return Void.
+ */
+void uninit_mb(struct msg_buf *mb)
+{
+       vfree(mb->begin);
+}
+
+/**
+ * @brief Checks if current buffer data pointer is at the end.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @param size Size of the message buffer.
+ * @return 1 - buffer ptr is not at the end,
+ * 0 - buffer ptr is at the end,
+ * -1 - buffer ptr is invalid (far away of the end).
+ */
+int cmp_mb(struct msg_buf *mb, size_t size)
+{
+       char *tmp;
+
+       tmp = mb->ptr + size;
+       if (mb->end > tmp)
+               return 1;
+       else if (mb->end < tmp)
+               return -1;
+
+       return 0;
+}
+
+/**
+ * @brief Gets remainder part of message buffer.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @return Remainder part of message buffer.
+ */
+size_t remained_mb(struct msg_buf *mb)
+{
+       return mb->end - mb->ptr;
+}
+
+/**
+ * @brief Checks whether we reached the end of the message buffer or not.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @return 1 - if message buffer end has been reached \n
+ * 0 - otherwise.
+ */
+int is_end_mb(struct msg_buf *mb)
+{
+       return mb->ptr == mb->end;
+}
+
+/**
+ * @brief Reads 8 bits from message buffer and updates buffer's pointer.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @param val Pointer to the target variable where to put read value.
+ * @return 0 on success, negative error code on error.
+ */
+int get_u8(struct msg_buf *mb, u8 *val)
+{
+       if (cmp_mb(mb, sizeof(*val)) < 0)
+               return -EINVAL;
+
+       *val = *((u8 *)mb->ptr);
+       mb->ptr += sizeof(*val);
+
+       print_parse_debug("u8 ->%d;%08X\n", *val, *val);
+
+       return 0;
+}
+
+/**
+ * @brief Reads 32 bits from message buffer and updates buffer's pointer.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @param val Pointer to the target variable where to put read value.
+ * @return 0 on success, negative error code on error.
+ */
+int get_u32(struct msg_buf *mb, u32 *val)
+{
+       if (cmp_mb(mb, sizeof(*val)) < 0)
+               return -EINVAL;
+
+       *val = *((u32 *)mb->ptr);
+       mb->ptr += sizeof(*val);
+
+       print_parse_debug("u32->%d;%08X\n", *val, *val);
+
+       return 0;
+}
+
+/**
+ * @brief Reads 64 bits from message buffer and updates buffer's pointer.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @param val Pointer to the target variable where to put read value.
+ * @return 0 on success, negative error code on error.
+ */
+int get_u64(struct msg_buf *mb, u64 *val)
+{
+       if (cmp_mb(mb, sizeof(*val)) < 0)
+               return -EINVAL;
+
+       *val = *((u64 *)mb->ptr);
+       mb->ptr += sizeof(*val);
+       print_parse_debug("u64->%llu; 0x%016llX\n", *val, *val);
+
+       return 0;
+}
+
+/**
+ * @brief Reads null-terminated string from message buffer and updates
+ * buffer's pointer.
+ *
+ * @param mb Pointer to the message buffer struct.
+ * @param str Pointer to the target variable where to put read string.
+ * @return 0 on success, negative error code on error.
+ */
+int get_string(struct msg_buf *mb, char **str)
+{
+       size_t len, len_max;
+       enum { min_len_str = 1 };
+
+       if (cmp_mb(mb, min_len_str) < 0)
+               return -EINVAL;
+
+       len_max = remained_mb(mb) - 1;
+       len = strnlen(mb->ptr, len_max);
+
+       *str = kmalloc(len + 1, GFP_KERNEL);
+       if (*str == NULL)
+               return -ENOMEM;
+
+       memcpy(*str, mb->ptr, len);
+       (*str)[len] = '\0';
+
+       mb->ptr += len + 1;
+
+       print_parse_debug("str->'%s'\n", *str);
+       return 0;
+}
+
+/**
+ * @brief Releases string memory allocated in get_string.
+ *
+ * @param str Pointer to the target string.
+ * @return Void.
+ */
+void put_string(const char *str)
+{
+       kfree(str);
+}
diff --git a/modules/parser/msg_buf.h b/modules/parser/msg_buf.h
new file mode 100644 (file)
index 0000000..14a5713
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file parser/msg_buf.h
+ * @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
+ *
+ * Message buffer interface declaration.
+ */
+
+
+#ifndef _MSG_BUF_H
+#define _MSG_BUF_H
+
+#include <linux/types.h>
+
+/**
+ * @struct msg_buf
+ * @brief Stores pointers to the message buffer.
+ */
+struct msg_buf {
+       char *begin;    /**< Pointer to the beginning of the buffer. */
+       char *end;      /**< Pointer to the end of the buffer. */
+       char *ptr;      /**< Buffer iterator. */
+};
+
+int init_mb(struct msg_buf *mb, size_t size);
+void uninit_mb(struct msg_buf *mb);
+
+int cmp_mb(struct msg_buf *mb, size_t size);
+size_t remained_mb(struct msg_buf *mb);
+int is_end_mb(struct msg_buf *mb);
+
+int get_u8(struct msg_buf *mb, u8 *val);
+int get_u32(struct msg_buf *mb, u32 *val);
+int get_u64(struct msg_buf *mb, u64 *val);
+
+int get_string(struct msg_buf *mb, char **str);
+void put_string(const char *str);
+
+#endif /* _MSG_BUF_H */
diff --git a/modules/parser/msg_cmd.c b/modules/parser/msg_cmd.c
new file mode 100644 (file)
index 0000000..3572345
--- /dev/null
@@ -0,0 +1,255 @@
+/**
+ * parser/msg_cmd.c
+ * @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
+ *
+ * Module's messages parsing implementation.
+ */
+
+
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include "msg_parser.h"
+#include "msg_buf.h"
+#include "features.h"
+#include "parser_defs.h"
+#include "us_inst.h"
+#include <writer/swap_msg.h>
+#include <us_manager/us_manager.h>
+
+
+static int wrt_launcher_port;
+
+static int set_config(struct conf_data *conf)
+{
+       int ret;
+
+       ret = set_features(conf);
+
+       return ret;
+}
+
+/**
+ * @brief Message "keep alive" handling.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int msg_keep_alive(struct msg_buf *mb)
+{
+       if (!is_end_mb(mb)) {
+               print_err("to long message, remained=%zu", remained_mb(mb));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Message "start" handling.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int msg_start(struct msg_buf *mb)
+{
+       int ret = 0;
+       struct conf_data conf;
+       LIST_HEAD(app_head);
+
+       swap_msg_seq_num_reset();
+       swap_msg_discard_reset();
+
+       if (!create_us_inst_data(mb, &app_head))
+               return -EINVAL;
+
+       if (!is_end_mb(mb)) {
+               pr_info("Too long message, remained=%zu", remained_mb(mb));
+               destroy_us_inst_data(&app_head);
+               return -EINVAL;
+       }
+
+       ret = app_list_reg(&app_head);
+       if (ret) {
+               pr_info("Cannot mod us inst, ret = %d\n", ret);
+               return ret;
+       }
+
+       ret = usm_start();
+       if (ret) {
+               app_list_unreg_all();
+               return ret;
+       }
+
+       restore_config(&conf);
+       set_config(&conf);
+
+       return 0;
+}
+
+/**
+ * @brief Message "stop" handling.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int msg_stop(struct msg_buf *mb)
+{
+       int ret = 0;
+       int discarded;
+
+       if (!is_end_mb(mb)) {
+               print_err("to long message, remained=%zu", remained_mb(mb));
+               return -EINVAL;
+       }
+
+       ret = usm_stop();
+       if (ret)
+               return ret;
+
+       app_list_unreg_all();
+       disable_all_features();
+
+       discarded = swap_msg_discard_get();
+       printk(KERN_INFO "discarded messages: %d\n", discarded);
+       swap_msg_discard_reset();
+
+       return ret;
+}
+
+/**
+ * @brief Message "config" handling.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int msg_config(struct msg_buf *mb)
+{
+       int ret = 0;
+       struct conf_data *conf;
+       enum status_type st;
+
+       conf = create_conf_data(mb);
+       if (conf == NULL)
+               return -EINVAL;
+
+       if (!is_end_mb(mb)) {
+               print_err("to long message, remained=%zu", remained_mb(mb));
+               ret = -EINVAL;
+               goto free_conf_data;
+       }
+
+       st = usm_get_status();
+       if (st == ST_ON)
+               set_config(conf);
+
+       save_config(conf);
+       usm_put_status(st);
+
+free_conf_data:
+       destroy_conf_data(conf);
+
+       return ret;
+}
+
+/**
+ * @brief Message "swap inst add" handling.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int msg_swap_inst_add(struct msg_buf *mb)
+{
+       LIST_HEAD(app_head);
+
+       if (!create_us_inst_data(mb, &app_head))
+               return -EINVAL;
+
+       if (!is_end_mb(mb)) {
+               pr_info("Too long message, remained=%zu", remained_mb(mb));
+               destroy_us_inst_data(&app_head);
+               return -EINVAL;
+       }
+
+       return app_list_reg(&app_head);
+}
+
+/**
+ * @brief Message "swap inst remove" handling.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return 0 on success, negative error code on error.
+ */
+int msg_swap_inst_remove(struct msg_buf *mb)
+{
+       LIST_HEAD(app_head);
+
+       INIT_LIST_HEAD(&app_head);
+       if (!create_us_inst_data(mb, &app_head))
+               return -EINVAL;
+
+       if (!is_end_mb(mb)) {
+               pr_info("Too long message, remained=%zu", remained_mb(mb));
+               destroy_us_inst_data(&app_head);
+               return -EINVAL;
+       }
+
+       return app_list_unreg(&app_head);
+}
+
+void set_wrt_launcher_port(int port)
+{
+       wrt_launcher_port = port;
+}
+EXPORT_SYMBOL_GPL(set_wrt_launcher_port);
+
+#define GET_PORT_DELAY         100     /* msec */
+#define GET_PORT_TIMEOUT       10000   /* msec */
+
+int get_wrt_launcher_port(void)
+{
+       int port;
+       int timeout = GET_PORT_TIMEOUT;
+
+       do {
+               port = wrt_launcher_port;
+               timeout -= GET_PORT_DELAY;
+               mdelay(GET_PORT_DELAY);
+       } while (!port && timeout > 0);
+
+       set_wrt_launcher_port(0);
+
+       return port;
+}
+
+/**
+ * @brief Initializes commands handling.
+ *
+ * @return Initialization results.
+ */
+int once_cmd(void)
+{
+       return once_features();
+}
diff --git a/modules/parser/msg_cmd.h b/modules/parser/msg_cmd.h
new file mode 100644 (file)
index 0000000..e078169
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * @file parser/msg_cmd.h
+ * @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
+ *
+ * Module's message handling interface declaration.
+ */
+
+#ifndef _MSG_CMD_H
+#define _MSG_CMD_H
+
+struct msg_buf;
+
+int once_cmd(void);
+
+int msg_keep_alive(struct msg_buf *mb);
+int msg_start(struct msg_buf *mb);
+int msg_stop(struct msg_buf *mb);
+int msg_config(struct msg_buf *mb);
+int msg_swap_inst_add(struct msg_buf *mb);
+int msg_swap_inst_remove(struct msg_buf *mb);
+int get_wrt_launcher_port(void);
+void set_wrt_launcher_port(int port);
+
+#endif /* _MSG_CMD_H */
diff --git a/modules/parser/msg_parser.c b/modules/parser/msg_parser.c
new file mode 100644 (file)
index 0000000..285da4d
--- /dev/null
@@ -0,0 +1,1100 @@
+/**
+ * parser/msg_parser.c
+ *
+ * @author Vyacheslav Cherkashin
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @sectionLICENSE
+ *
+ * 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
+ *
+ * Message parsing implementation.
+ */
+
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <us_manager/probes/probes.h>
+#include "msg_parser.h"
+#include "msg_buf.h"
+#include "parser_defs.h"
+
+/* ============================================================================
+ * ==                               APP_INFO                                 ==
+ * ============================================================================
+ */
+
+/**
+ * @brief Creates and fills pr_app_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param ai Pointer to the target app_inst_data.
+ * @return 0 on success, error code on error.
+ */
+struct pr_app_info *pr_app_info_create(struct msg_buf *mb)
+{
+       int ret;
+       struct pr_app_info *app_info;
+       u32 app_type;
+       char *str_id, *exec_path;
+
+       app_info = kmalloc(sizeof(*app_info), GFP_KERNEL);
+       if (!app_info)
+               return ERR_PTR(-ENOMEM);
+
+       print_parse_debug("app_info:\n");
+       print_parse_debug("type:");
+       ret = get_u32(mb, &app_type);
+       if (ret) {
+               print_err("failed to read target application type\n");
+               goto free_app_info;
+       }
+
+       print_parse_debug("id:");
+       ret = get_string(mb, &str_id);
+       if (ret) {
+               print_err("failed to read target application ID\n");
+               goto free_app_info;
+       }
+
+       print_parse_debug("exec path:");
+       ret = get_string(mb, &exec_path);
+       if (ret) {
+               print_err("failed to read executable path\n");
+               goto free_id;
+       }
+
+       switch (app_type) {
+       case AT_TIZEN_NATIVE_APP:
+       case AT_TIZEN_WEB_APP:
+       case AT_COMMON_EXEC:
+               app_info->tgid = 0;
+               break;
+       case AT_PID: {
+               u32 tgid = 0;
+
+               if (*str_id != '\0') {
+                       ret = kstrtou32(str_id, 10, &tgid);
+                       if (ret) {
+                               print_err("converting string to PID, "
+                                         "str='%s'\n", str_id);
+                               goto free_exec_path;
+                       }
+               }
+
+               app_info->tgid = tgid;
+               break;
+       }
+       default:
+               print_err("wrong application type(%u)\n", app_type);
+               ret = -EINVAL;
+               goto free_exec_path;
+       }
+
+       app_info->type = (enum APP_TYPE)app_type;
+       app_info->id = str_id;
+       app_info->path = exec_path;
+
+       return app_info;
+
+free_exec_path:
+       put_string(exec_path);
+free_id:
+       put_string(str_id);
+free_app_info:
+       kfree(app_info);
+       return ERR_PTR(ret);
+}
+
+void pr_app_info_free(struct pr_app_info *app_info)
+{
+       put_string(app_info->path);
+       put_string(app_info->id);
+       kfree(app_info);
+}
+
+int pr_app_info_cmp(struct pr_app_info *app0, struct pr_app_info *app1)
+{
+       print_parse_debug("app0: %d, %d, %s, %s\n",
+                         app0->type, app0->tgid, app0->id, app0->path);
+
+       print_parse_debug("app1: %d, %d, %s, %s\n",
+                         app1->type, app1->tgid, app1->id, app1->path);
+
+       if ((app0->type == app1->type) &&
+           (app0->tgid == app1->tgid) &&
+           !strcmp(app0->id, app1->id) &&
+           !strcmp(app0->path, app1->path)) {
+               return 0;
+       }
+
+       return 1;
+}
+
+
+
+/* ============================================================================
+ * ==                                CONFIG                                  ==
+ * ============================================================================
+ */
+
+/**
+ * @brief Creates and fills conf_data struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return Pointer to the filled conf_data struct on success;\n
+ * NULL on error.
+ */
+struct conf_data *create_conf_data(struct msg_buf *mb)
+{
+       struct conf_data *conf;
+       u64 use_features0, use_features1;
+       u32 stp, dmp;
+
+       print_parse_debug("conf_data:\n");
+
+       print_parse_debug("features:");
+       if (get_u64(mb, &use_features0)) {
+               print_err("failed to read use_features\n");
+               return NULL;
+       }
+
+       if (get_u64(mb, &use_features1)) {
+               print_err("failed to read use_features\n");
+               return NULL;
+       }
+
+       print_parse_debug("sys trace period:");
+       if (get_u32(mb, &stp)) {
+               print_err("failed to read sys trace period\n");
+               return NULL;
+       }
+
+       print_parse_debug("data msg period:");
+       if (get_u32(mb, &dmp)) {
+               print_err("failed to read data message period\n");
+               return NULL;
+       }
+
+       conf = kmalloc(sizeof(*conf), GFP_KERNEL);
+       if (conf == NULL) {
+               print_err("out of memory\n");
+               return NULL;
+       }
+
+       conf->use_features0 = use_features0;
+       conf->use_features1 = use_features1;
+       conf->sys_trace_period = stp;
+       conf->data_msg_period = dmp;
+
+       return conf;
+}
+
+/**
+ * @brief conf_data cleanup.
+ *
+ * @param conf Pointer to the target conf_data.
+ * @return Void.
+ */
+void destroy_conf_data(struct conf_data *conf)
+{
+       kfree(conf);
+}
+
+static struct conf_data config;
+
+/**
+ * @brief Saves config to static config variable.
+ *
+ * @param conf Variable to save.
+ * @return Void.
+ */
+void save_config(const struct conf_data *conf)
+{
+       memcpy(&config, conf, sizeof(config));
+}
+
+/**
+ * @brief Restores config from static config variable.
+ *
+ * @param conf Variable to restore.
+ * @return Void.
+ */
+void restore_config(struct conf_data *conf)
+{
+       memcpy(conf, &config, sizeof(*conf));
+}
+
+
+
+/* ============================================================================
+ * ==                             PROBES PARSING                             ==
+ * ============================================================================
+ */
+
+/**
+ * @brief Gets retprobe data and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pd Pointer to the probe_desc struct.
+ * @return 0 on success, error code on error.
+ */
+int get_retprobe(struct msg_buf *mb, struct probe_desc *pd)
+{
+       char *args;
+       char ret_type;
+
+       print_parse_debug("funct args:");
+       if (get_string(mb, &args)) {
+               print_err("failed to read data function arguments\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("funct ret type:");
+       if (get_u8(mb, (u8 *)&ret_type)) {
+               print_err("failed to read data function arguments\n");
+               goto free_args;
+       }
+
+       pd->type = SWAP_RETPROBE;
+       pd->info.rp_i.args = args;
+       pd->info.rp_i.ret_type = ret_type;
+
+       return 0;
+
+free_args:
+       put_string(args);
+       return -EINVAL;
+}
+
+/**
+ * @brief Retprobe data cleanup.
+ *
+ * @param pi Pointer to the probe_info comprising retprobe.
+ * @return Void.
+ */
+void put_retprobe(struct probe_info *pi)
+{
+       put_string(pi->rp_i.args);
+}
+
+static int cmp_retprobe(struct probe_info *p0, struct probe_info *p1)
+{
+       if (p0->rp_i.ret_type == p1->rp_i.ret_type &&
+           !strcmp(p0->rp_i.args, p1->rp_i.args)) {
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * @brief Gets preload data and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pd Pointer to the probe_desc struct.
+ * @return 0 on success, error code on error.
+ */
+int get_preload_probe(struct msg_buf *mb, struct probe_desc *pd)
+{
+       u64 handler;
+       u8 flags;
+       char *path;
+
+       print_parse_debug("funct handler:");
+       if (get_u64(mb, &handler)) {
+               print_err("failed to read function handler\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("collect events flag:");
+       if (get_u8(mb, &flags)) {
+               print_err("failed to read collect events type\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("handler library:");
+       if (get_string(mb, &path)) {
+               print_err("failed to read handler library path\n");
+               return -EINVAL;
+       }
+
+       pd->type = SWAP_PRELOAD_PROBE;
+       pd->info.pl_i.handler = handler;
+       pd->info.pl_i.flags = flags;
+       pd->info.pl_i.path = path;
+
+       return 0;
+}
+
+/**
+ * @brief Preload probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info struct.
+ * @return Void.
+ */
+void put_preload_probe(struct probe_info *pi)
+{
+       put_string((char *)pi->pl_i.path);
+}
+
+static int cmp_preload_probe(struct probe_info *p0, struct probe_info *p1)
+{
+       if (p0->pl_i.handler == p1->pl_i.handler &&
+           p0->pl_i.flags == p1->pl_i.flags) {
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * @brief Gets preload get_caller and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pd Pointer to the probe_desc struct.
+ * @return 0 on success, error code on error.
+ */
+
+int get_get_caller_probe(struct msg_buf *mb, struct probe_desc *pd)
+{
+       pd->type = SWAP_GET_CALLER;
+
+       return 0;
+}
+
+/**
+ * @brief Preload get_caller probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info struct.
+ * @return Void.
+ */
+void put_get_caller_probe(struct probe_info *pi)
+{
+}
+
+static int cmp_get_caller_probe(struct probe_info *p0, struct probe_info *p1)
+{
+       return 0;
+}
+
+/**
+ * @brief Gets preload get_call_type and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pd Pointer to the probe_desc struct.
+ * @return 0 on success, error code on error.
+ */
+int get_get_call_type_probe(struct msg_buf *mb, struct probe_desc *pd)
+{
+       pd->type = SWAP_GET_CALL_TYPE;
+
+       return 0;
+}
+
+/**
+ * @brief Preload get_call type probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info struct.
+ * @return Void.
+ */
+void put_get_call_type_probe(struct probe_info *pi)
+{
+}
+
+static int cmp_get_caller_type_probe(struct probe_info *p0,
+                                    struct probe_info *p1)
+{
+       return 0;
+}
+
+/**
+ * @brief Gets preload write_msg and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pi Pointer to the probe_info struct.
+ * @return 0 on success, error code on error.
+ */
+int get_write_msg_probe(struct msg_buf *mb, struct probe_desc *pd)
+{
+       pd->type = SWAP_WRITE_MSG;
+
+       return 0;
+}
+
+/**
+ * @brief Preload write_msg type probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info comprising retprobe.
+ * @return Void.
+ */
+void put_write_msg_probe(struct probe_info *pi)
+{
+}
+
+static int cmp_write_msg_probe(struct probe_info *p0, struct probe_info *p1)
+{
+       return 0;
+}
+
+/**
+ * @brief Gets FBI probe data and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pi Pointer to the probe_info struct.
+ * @return 0 on success, error code on error.
+ */
+int get_fbi_data(struct msg_buf *mb, struct fbi_var_data *vd)
+{
+       u64 var_id;
+       u64 reg_offset;
+       u8 reg_n;
+       u32 data_size;
+       u8 steps_count, i;
+       struct fbi_step *steps = NULL;
+
+       print_parse_debug("var ID:");
+       if (get_u64(mb, &var_id)) {
+               print_err("failed to read var ID\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("register offset:");
+       if (get_u64(mb, &reg_offset)) {
+               print_err("failed to read register offset\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("register number:");
+       if (get_u8(mb, &reg_n)) {
+               print_err("failed to read number of the register\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("data size:");
+       if (get_u32(mb, &data_size)) {
+               print_err("failed to read data size\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("steps count:");
+       if (get_u8(mb, &steps_count)) {
+               print_err("failed to read steps count\n");
+               return -EINVAL;
+       }
+
+       if (steps_count > 0) {
+               steps = kmalloc(steps_count * sizeof(*vd->steps),
+                               GFP_KERNEL);
+               if (steps == NULL) {
+                       print_err("MALLOC FAIL\n");
+                       return -ENOMEM;
+               }
+
+               for (i = 0; i != steps_count; i++) {
+                       print_parse_debug("steps #%d ptr_order:", i);
+                       if (get_u8(mb, &(steps[i].ptr_order))) {
+                               print_err("failed to read pointer order(step #%d)\n",
+                                         i);
+                               goto free_steps;
+                       }
+                       print_parse_debug("steps #%d data_offset:", i);
+                       if (get_u64(mb, &(steps[i].data_offset))){
+                               print_err("failed to read offset (steps #%d)\n",
+                                         i);
+                               goto free_steps;
+                       }
+               }
+       }
+
+       vd->reg_n = reg_n;
+       vd->reg_offset = reg_offset;
+       vd->data_size = data_size;
+       vd->var_id = var_id;
+       vd->steps_count = steps_count;
+       vd->steps = steps;
+
+       return 0;
+
+free_steps:
+       kfree(steps);
+       return -EINVAL;
+}
+
+int get_fbi_probe(struct msg_buf *mb, struct probe_desc *pd)
+{
+       uint8_t var_count, i;
+       struct fbi_var_data *vars;
+
+       print_parse_debug("var count:");
+       if (get_u8(mb, &var_count)) {
+               print_err("failed to read var ID\n");
+               return -EINVAL;
+       }
+
+       vars = kmalloc(var_count * sizeof(*vars), GFP_KERNEL);
+       if (vars == NULL) {
+               print_err("alloc vars error\n");
+               goto err;
+       }
+
+       for (i = 0; i != var_count; i++) {
+               if (get_fbi_data(mb, &vars[i]) != 0)
+                       goto free_vars;
+       }
+
+       pd->type = SWAP_FBIPROBE;
+       pd->info.fbi_i.var_count = var_count;
+       pd->info.fbi_i.vars = vars;
+       return 0;
+
+free_vars:
+       kfree(vars);
+
+err:
+       return -EINVAL;
+
+}
+
+/**
+ * @brief FBI probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info comprising FBI probe.
+ * @return Void.
+ */
+void put_fbi_probe(struct probe_info *pi)
+{
+       /* FIXME: memory leak (vars) */
+       return;
+}
+
+static int cmp_fbi_probe(struct probe_info *p0, struct probe_info *p1)
+{
+       /* TODO: to implement */
+       return 0;
+}
+
+
+/* ============================================================================
+ * ==                                 PROBE                                  ==
+ * ============================================================================
+ */
+
+/**
+ * @brief Creates and fills func_inst_data struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return Pointer to the filled func_inst_data struct on success;\n
+ * 0 on error.
+ */
+struct pr_probe_desc *pr_probe_desc_create(struct msg_buf *mb)
+{
+       int ret = -EINVAL;
+       struct pr_probe_desc *probe;
+       int (*get_probe)(struct msg_buf *mb, struct probe_desc *pd);
+       u64 addr;
+       u8 type;
+
+       print_parse_debug("func addr:");
+       if (get_u64(mb, &addr)) {
+               print_err("failed to read data function address\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       print_parse_debug("probe type:");
+       if (get_u8(mb, &type)) {
+               print_err("failed to read data probe type\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       probe = kmalloc(sizeof(*probe), GFP_KERNEL);
+       if (!probe) {
+               print_err("out of memory\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_LIST_HEAD(&probe->list);
+
+       switch (type) {
+       case SWAP_RETPROBE:
+               get_probe = get_retprobe;
+               break;
+       case SWAP_PRELOAD_PROBE:
+               get_probe = get_preload_probe;
+               break;
+       case SWAP_GET_CALLER:
+               get_probe = get_get_caller_probe;
+               break;
+       case SWAP_GET_CALL_TYPE:
+               get_probe = get_get_call_type_probe;
+               break;
+       case SWAP_FBIPROBE:
+               get_probe = get_fbi_probe;
+               break;
+       case SWAP_WRITE_MSG:
+               get_probe = get_write_msg_probe;
+               break;
+       default:
+               printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n",
+                      type);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = get_probe(mb, &probe->p_desc);
+       if (ret)
+               goto err;
+
+       probe->addr = addr;
+       return probe;
+
+err:
+       kfree(probe);
+       return ERR_PTR(ret);
+}
+
+
+/**
+ * @brief func_inst_data cleanup.
+ *
+ * @param fi Pointer to the target func_inst_data.
+ * @return Void.
+ */
+void pr_probe_desc_free(struct pr_probe_desc *probe)
+{
+       switch (probe->p_desc.type) {
+       case SWAP_RETPROBE:
+               put_retprobe(&(probe->p_desc.info));
+               break;
+       case SWAP_PRELOAD_PROBE:
+               put_preload_probe(&(probe->p_desc.info));
+               break;
+       case SWAP_GET_CALLER:
+               put_get_caller_probe(&(probe->p_desc.info));
+               break;
+       case SWAP_GET_CALL_TYPE:
+               put_get_call_type_probe(&(probe->p_desc.info));
+               break;
+       case SWAP_FBIPROBE:
+               put_fbi_probe(&(probe->p_desc.info));
+               break;
+       case SWAP_WRITE_MSG:
+               put_write_msg_probe(&(probe->p_desc.info));
+               break;
+       default:
+               pr_err("SWAP PARSER: Wrong probe type %d!\n",
+                      probe->p_desc.type);
+       }
+
+       kfree(probe);
+}
+
+int probe_inst_info_cmp(struct pr_probe_desc *p0, struct pr_probe_desc *p1)
+{
+       enum probe_t type;
+       int (*cmp_probe)(struct probe_info *p0, struct probe_info *p1);
+
+       if (p0->addr != p1->addr &&
+           p0->p_desc.type != p1->p_desc.type)
+               return 1;
+
+       type = p0->p_desc.type;
+       switch (type) {
+       case SWAP_RETPROBE:
+               cmp_probe = cmp_retprobe;
+               break;
+       case SWAP_PRELOAD_PROBE:
+               cmp_probe = cmp_preload_probe;
+               break;
+       case SWAP_GET_CALLER:
+               cmp_probe = cmp_get_caller_probe;
+               break;
+       case SWAP_GET_CALL_TYPE:
+               cmp_probe = cmp_get_caller_type_probe;
+               break;
+       case SWAP_FBIPROBE:
+               cmp_probe = cmp_fbi_probe;
+               break;
+       case SWAP_WRITE_MSG:
+               cmp_probe = cmp_write_msg_probe;
+               break;
+       default:
+               pr_err("SWAP PARSER: Wrong probe type %d!\n", type);
+               return 1;
+       }
+
+       return cmp_probe(&p0->p_desc.info, &p1->p_desc.info);
+}
+
+static struct pr_bin_info *pr_bin_info_create(const char *path)
+{
+       struct pr_bin_info *info;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       info->path = kstrdup(path, GFP_KERNEL);
+       if (!info->path) {
+               kfree(info);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return info;
+}
+
+static void pr_bin_info_free(struct pr_bin_info *info)
+{
+       kfree(info->path);
+       kfree(info);
+}
+
+
+struct pr_bin_desc *pr_bin_desc_create(const char *path,
+                                      struct list_head *probe_list)
+{
+       struct pr_bin_desc *bin;
+
+       bin = kmalloc(sizeof(*bin), GFP_KERNEL);
+       if (!bin)
+               return ERR_PTR(-ENOMEM);
+
+       bin->info = pr_bin_info_create(path);
+       if (IS_ERR(bin->info)) {
+               long err = PTR_ERR(bin->info);
+
+               kfree(bin);
+               return ERR_PTR(err);
+       }
+
+       INIT_LIST_HEAD(&bin->list);
+       INIT_LIST_HEAD(&bin->probe_head);
+       list_splice_init(probe_list, &bin->probe_head);
+
+       return bin;
+}
+
+void pr_bin_desc_free(struct pr_bin_desc *bin)
+{
+       struct pr_probe_desc *p, *n;
+
+       list_for_each_entry_safe(p, n, &bin->probe_head, list) {
+               list_del(&p->list);
+               pr_probe_desc_free(p);
+       }
+
+       pr_bin_info_free(bin->info);
+       kfree(bin);
+}
+
+int pr_bin_info_cmp(struct pr_bin_info *b0, struct pr_bin_info *b1)
+{
+       return strcmp(b0->path, b1->path);
+}
+
+
+static void pr_probe_desc_list_free(struct list_head *head)
+{
+       struct pr_probe_desc *probe, *n;
+
+       list_for_each_entry_safe(probe, n, head, list) {
+               list_del(&probe->list);
+               pr_probe_desc_free(probe);
+       }
+}
+
+static int pr_probe_desc_list_create(struct msg_buf *mb, struct list_head *head)
+{
+       u32 i, cnt;
+
+       if (get_u32(mb, &cnt)) {
+               print_err("failed to read count of functions\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("probe count:%d", cnt);
+       if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) {
+               print_err("to match count of probes(%u)\n", cnt);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cnt; ++i) {
+               struct pr_probe_desc *probe;
+
+               print_parse_debug("probe #%d:\n", i + 1);
+               probe = pr_probe_desc_create(mb);
+               if (IS_ERR(probe)) {
+                       pr_probe_desc_list_free(head);
+                       return PTR_ERR(probe);
+               }
+
+               list_add(&probe->list, head);
+       }
+
+       return cnt;
+}
+
+
+struct pr_bin_desc *bin_info_by_lib(struct msg_buf *mb)
+{
+       u32 cnt;
+       char *path;
+       struct pr_bin_desc *bin = ERR_PTR(-EINVAL);
+
+       print_parse_debug("bin path:");
+       if (get_string(mb, &path)) {
+               print_err("failed to read path of binary\n");
+               return bin;
+       }
+
+       print_parse_debug("func count:");
+       if (get_u32(mb, &cnt)) {
+               print_err("failed to read count of functions\n");
+               goto free_path;
+       }
+
+       if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) {
+               print_err("to match count of functions(%u)\n", cnt);
+               goto free_path;
+       }
+
+       if (cnt) {
+               u32 i;
+               LIST_HEAD(probe_head);
+
+               for (i = 0; i < cnt; ++i) {
+                       struct pr_probe_desc *probe;
+                       print_parse_debug("func #%d:\n", i + 1);
+                       probe = pr_probe_desc_create(mb);
+                       if (IS_ERR(probe)) {
+                               /* set error to 'bin' */
+                               bin = ERR_PTR(PTR_ERR(probe));
+                               pr_probe_desc_list_free(&probe_head);
+                               goto free_path;
+                       }
+
+                       list_add(&probe->list, &probe_head);
+               }
+
+               bin = pr_bin_desc_create(path, &probe_head);
+               if (IS_ERR(bin))
+                       pr_probe_desc_list_free(&probe_head);
+       }
+
+free_path:
+       put_string(path);
+       return bin;
+}
+
+
+
+
+void bin_info_list_free(struct list_head *head)
+{
+       struct pr_bin_desc *bin, *n;
+
+       list_for_each_entry_safe(bin, n, head, list) {
+               list_del(&bin->list);
+               pr_bin_desc_free(bin);
+       }
+}
+
+int bin_info_list_create(struct msg_buf *mb, struct list_head *head)
+{
+       u32 i, cnt;
+
+       if (get_u32(mb, &cnt)) {
+               print_err("failed to read count of binaries\n");
+               return -EINVAL;
+       }
+       print_parse_debug("bin count:i%d", cnt);
+
+       if (remained_mb(mb) / MIN_SIZE_LIB_INST < cnt) {
+               print_err("to match count of binaries(%u)\n", cnt);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cnt; ++i) {
+               struct pr_bin_desc *bin;
+
+               print_parse_debug("bin #%d:\n", i_lib + 1);
+               bin = bin_info_by_lib(mb);
+               if (IS_ERR(bin)) {
+                       bin_info_list_free(head);
+                       return PTR_ERR(bin);
+               } else if (bin) {
+                       list_add(&bin->list, head);
+               }
+       }
+
+       return cnt;
+}
+
+
+/* ============================================================================
+ * ==                                 APP                                    ==
+ * ============================================================================
+ */
+
+/**
+ * @brief Creates and fills pr_app_desc struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @return Pointer to the filled app_inst_data struct on success;\n
+ * 0 on error.
+ */
+struct pr_app_desc *pr_app_desc_create(struct msg_buf *mb)
+{
+       int cnt_probe, cnt_bin, ret = -EINVAL;
+       struct pr_app_info *app_info;
+       struct pr_app_desc *app;
+       LIST_HEAD(probe_head);
+       LIST_HEAD(bin_head);
+
+       app = kmalloc(sizeof(*app), GFP_KERNEL);
+       if (!app) {
+               print_err("%s: Out of memory\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       app_info = pr_app_info_create(mb);
+       if (IS_ERR(app_info)) {
+               ret = PTR_ERR(app_info);
+               goto free_app_inst;
+       }
+
+       app->info = app_info;
+       app->pfg = NULL;
+       INIT_LIST_HEAD(&app->list);
+       INIT_LIST_HEAD(&app->bin_head);
+
+       cnt_probe = pr_probe_desc_list_create(mb, &probe_head);
+       if (cnt_probe < 0) {
+               ret = cnt_probe;
+               goto free_app_info;
+       } else if (cnt_probe) {
+               struct pr_bin_desc *bin;
+
+               bin = pr_bin_desc_create(app_info->path, &probe_head);
+               if (IS_ERR(bin)) {
+                       pr_probe_desc_list_free(&probe_head);
+                       ret = PTR_ERR(bin);
+                       goto free_app_info;
+               }
+
+               /* add pr_bin_desc */
+               list_add(&bin->list, &app->bin_head);
+       }
+
+       cnt_bin = bin_info_list_create(mb, &app->bin_head);
+       if (cnt_bin < 0) {
+               ret = cnt_bin;
+               goto free_bins;
+       }
+
+       return app;
+
+free_bins:
+       bin_info_list_free(&app->bin_head);
+free_app_info:
+       pr_app_info_free(app_info);
+free_app_inst:
+       kfree(app);
+       return ERR_PTR(ret);
+}
+
+/**
+ * @brief pr_app_desc cleanup.
+ *
+ * @param ai Pointer to the target app_inst_data.
+ * @return Void.
+ */
+void pr_app_desc_free(struct pr_app_desc *app)
+{
+       bin_info_list_free(&app->bin_head);
+       pr_app_info_free(app->info);
+       kfree(app);
+}
+
+
+/* ============================================================================
+ * ==                                US_INST                                 ==
+ * ============================================================================
+ */
+
+/**
+ * @brief Creates and fills us_inst_data struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param head Pointer to the list head.
+ * @return u32 count of created elements.
+ */
+u32 create_us_inst_data(struct msg_buf *mb,
+                       struct list_head *head)
+{
+       u32 cnt, i;
+
+       print_parse_debug("us_inst_data:\n");
+
+       print_parse_debug("app count:");
+       if (get_u32(mb, &cnt)) {
+               print_err("failed to read count of applications\n");
+               return 0;
+       }
+
+       if (remained_mb(mb) / MIN_SIZE_APP_INST < cnt) {
+               print_err("to match count of applications(%u)\n", cnt);
+               return 0;
+       }
+
+       for (i = 0; i < cnt; ++i) {
+               struct pr_app_desc *app;
+
+               print_parse_debug("app #%d:\n", i + 1);
+               app = pr_app_desc_create(mb);
+               if (IS_ERR(app))
+                       goto err;
+
+               list_add_tail(&app->list, head);
+       }
+
+       return cnt;
+
+err:
+       destroy_us_inst_data(head);
+       return 0;
+}
+
+/**
+ * @brief us_inst_data cleanup.
+ *
+ * @param head Pointer to the list head.
+ * @return Void.
+ */
+void destroy_us_inst_data(struct list_head *head)
+{
+       struct pr_app_desc *app, *n;
+
+       list_for_each_entry_safe(app, n, head, list) {
+               list_del(&app->list);
+               pr_app_desc_free(app);
+       }
+}
diff --git a/modules/parser/msg_parser.h b/modules/parser/msg_parser.h
new file mode 100644 (file)
index 0000000..9620e65
--- /dev/null
@@ -0,0 +1,163 @@
+/**
+ * @file parser/msg_parser.h
+ * @author Vyacheslav Cherkashin
+ * @author Vitaliy Cherepanov
+ *
+ * @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
+ *
+ * Message parsing interface declaration.
+ */
+
+
+#ifndef _MSG_PARSER_H
+#define _MSG_PARSER_H
+
+#include <linux/types.h>
+#include <us_manager/probes/probes.h>
+
+struct img_ip;
+struct msg_buf;
+
+/**
+ * @enum APP_TYPE
+ * Supported application types.
+ */
+enum APP_TYPE {
+       AT_TIZEN_NATIVE_APP     = 0x01,     /**< Tizen native application. */
+       AT_PID                  = 0x02,         /**< App with specified PID. */
+       AT_COMMON_EXEC          = 0x03,     /**< Common application. */
+       AT_TIZEN_WEB_APP        = 0x04      /**< Tizen web application. */
+};
+
+/**
+ * @brief App type size defenition.
+ */
+enum {
+       SIZE_APP_TYPE = 4
+};
+
+/**
+ * @struct conf_data
+ * @brief Configuration struct.
+ */
+struct conf_data {
+       u64 use_features0;          /**< Feature flags. */
+       u64 use_features1;          /**< Feature flags. */
+       u32 sys_trace_period;       /**< Trace period. */
+       u32 data_msg_period;        /**< Data message period. */
+};
+
+/**
+ * @brief The pr_app_info struct
+ */
+struct pr_app_info {
+       enum APP_TYPE type;     /**< Application type. */
+       pid_t tgid;             /**< Application PID. */
+       char *id;               /**< Application ID */
+       char *path;             /**< Application execution path. */
+};
+
+/**
+ * @brief The pr_bin_info struct
+ */
+struct pr_bin_info {
+       char *path;
+};
+
+/**
+ * @brief The pr_app_desc struct
+ */
+struct pr_app_desc {
+       struct list_head list;
+
+       struct pr_app_info *info;
+       struct pf_group *pfg;
+       struct list_head bin_head;
+};
+
+/**
+ * @brief The pr_bin_desc struct
+ */
+struct pr_bin_desc {
+       struct list_head list;
+
+       struct pr_bin_info *info;
+
+       struct list_head probe_head;
+};
+
+struct pr_probe_desc {
+       struct list_head list;
+
+       /* register info */
+       u64 addr;
+       struct probe_desc p_desc;
+
+       /* unregister info */
+       struct img_ip *ip;
+};
+
+
+struct pr_app_info *pr_app_info_create(struct msg_buf *mb);
+void pr_app_info_free(struct pr_app_info *app_info);
+int pr_app_info_cmp(struct pr_app_info *app0, struct pr_app_info *app1);
+
+struct pr_bin_desc *pr_bin_desc_create(const char *path,
+                                      struct list_head *probe_list);
+void pr_bin_desc_free(struct pr_bin_desc *bin);
+
+int pr_bin_info_cmp(struct pr_bin_info *b0, struct pr_bin_info *b1);
+
+struct pr_probe_desc *pr_probe_desc_create(struct msg_buf *mb);
+void pr_probe_desc_free(struct pr_probe_desc *probe_info);
+int probe_inst_info_cmp(struct pr_probe_desc *p0, struct pr_probe_desc *p1);
+
+struct conf_data *create_conf_data(struct msg_buf *mb);
+void destroy_conf_data(struct conf_data *conf);
+
+void save_config(const struct conf_data *conf);
+void restore_config(struct conf_data *conf);
+
+struct pr_app_desc *pr_app_desc_create(struct msg_buf *mb);
+void pr_app_desc_free(struct pr_app_desc *app);
+
+u32 create_us_inst_data(struct msg_buf *mb, struct list_head *head);
+void destroy_us_inst_data(struct list_head *head);
+
+
+/**
+ * @brief Constant defenitions.
+ */
+enum {
+       MIN_SIZE_STRING = 1,
+       MIN_SIZE_FUNC_INST = 8 /* address size */ +
+                            MIN_SIZE_STRING,
+       MIN_SIZE_LIB_INST = MIN_SIZE_STRING +
+                           4 /* lib counter */,
+       MIN_SIZE_APP_INFO = SIZE_APP_TYPE + MIN_SIZE_STRING + MIN_SIZE_STRING,
+       MIN_SIZE_APP_INST = MIN_SIZE_APP_INFO +
+                           4 /* probe counter */ +
+                           4 /* lib counter */,
+};
+
+#endif /* _MSG_PARSER_H */
diff --git a/modules/parser/parser_defs.h b/modules/parser/parser_defs.h
new file mode 100644 (file)
index 0000000..be56704
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * @file modules/parser/parser_defs.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov:
+ *
+ * @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
+ *
+ * Parser defenitions.
+ */
+
+
+#ifndef __SWAP_DRIVER_DEVICE_DEFS_H__
+#define __SWAP_DRIVER_DEVICE_DEFS_H__
+
+#include <linux/kernel.h>
+
+/* #define PARSE_DEBUG */
+
+/** Prints debug message. */
+#define print_debug(msg, args...) \
+       printk(KERN_DEBUG "SWAP_PARSER DEBUG : " msg, ##args)
+/** Prints info message. */
+#define print_msg(msg, args...)   \
+       printk(KERN_INFO "SWAP_PARSER : " msg, ##args)
+/** Prints warning message. */
+#define print_warn(msg, args...)  \
+       printk(KERN_WARNING "SWAP_PARSER WARNING : " msg, ##args)
+/** Prints error message. */
+#define print_err(msg, args...)   \
+       printk(KERN_ERR "SWAP_PARSER ERROR : " msg, ##args)
+/** Prints critical error message. */
+#define print_crit(msg, args...)  \
+       printk(KERN_CRIT "SWAP_PARSER CRITICAL : " msg, ##args)
+
+/* debug parse */
+#ifdef PARSE_DEBUG
+#define print_parse_debug(msg, args...) \
+       printk(KERN_DEBUG "SWAP_PARSER DEBUG : " msg, ##args)
+#else
+#define print_parse_debug(msg, args...) \
+       do {} while (0)
+#endif /* PARSE_DEBUG */
+
+#endif /* __SWAP_DRIVER_DEVICE_DEFS_H__ */
diff --git a/modules/parser/swap_msg_parser.c b/modules/parser/swap_msg_parser.c
new file mode 100644 (file)
index 0000000..0049e84
--- /dev/null
@@ -0,0 +1,187 @@
+/**
+ * parser/swap_msg_parser.c
+ * @author Vyacheslav Cherkashin
+ * @author Vitaliy Cherepanov
+ *
+ * @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
+ *
+ * Parser module interface implementation.
+ */
+
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/cpumask.h>
+#include <linux/uaccess.h>
+
+#include "parser_defs.h"
+#include "us_inst.h"
+#include "msg_buf.h"
+#include "msg_cmd.h"
+#include "usm_msg.h"
+#include "cpu_ctrl.h"
+#include "features.h"
+
+#include <driver/driver_to_msg.h>
+#include <driver/swap_ioctl.h>
+#include <master/swap_initializer.h>
+
+/**
+ * @enum MSG_ID
+ * @brief Message IDs.
+ */
+enum MSG_ID {
+       MSG_KEEP_ALIVE          = 0x0001,       /**< Keep alive message. */
+       MSG_START               = 0x0002,       /**< Start message. */
+       MSG_STOP                = 0x0003,       /**< Stop message. */
+       MSG_CONFIG              = 0x0004,       /**< Config message. */
+       MSG_SWAP_INST_ADD       = 0x0008,       /**< Swap inst add message. */
+       MSG_SWAP_INST_REMOVE    = 0x0009,       /**< Swap inst remove message. */
+       MSG_WRT_LAUNCHER_PORT   = 0x8001        /**< WRT launcher port. */
+};
+
+/**
+ * @struct basic_msg_fmt
+ * @brief Basic part of each message.
+ */
+struct basic_msg_fmt {
+       u32 msg_id;                         /**< Message ID. */
+       u32 len;                            /**< Message length. */
+} __packed;
+
+static int msg_handler(void __user *msg)
+{
+       int ret;
+       u32 size;
+       enum MSG_ID msg_id;
+       struct msg_buf mb;
+       void __user *payload;
+       struct basic_msg_fmt bmf;
+       enum { size_max = 128 * 1024 * 1024 };
+
+       ret = copy_from_user(&bmf, (void *)msg, sizeof(bmf));
+       if (ret)
+               return ret;
+
+       size = bmf.len;
+       if (size >= size_max) {
+               printk(KERN_INFO "%s: too large message, size=%u\n",
+                      __func__, size);
+               return -ENOMEM;
+       }
+
+       ret = init_mb(&mb, size);
+       if (ret)
+               return ret;
+
+       payload = msg + sizeof(bmf);
+       if (size) {
+               ret = copy_from_user(mb.begin, (void *)payload, size);
+               if (ret)
+                       goto uninit;
+       }
+
+       msg_id = bmf.msg_id;
+       switch (msg_id) {
+       case MSG_KEEP_ALIVE:
+               print_parse_debug("MSG_KEEP_ALIVE. size=%d\n", size);
+               ret = msg_keep_alive(&mb);
+               break;
+       case MSG_START:
+               print_parse_debug("MSG_START. size=%d\n", size);
+               ret = msg_start(&mb);
+               break;
+       case MSG_STOP:
+               print_parse_debug("MSG_STOP. size=%d\n", size);
+               ret = msg_stop(&mb);
+               break;
+       case MSG_CONFIG:
+               print_parse_debug("MSG_CONFIG. size=%d\n", size);
+               ret = msg_config(&mb);
+               break;
+       case MSG_SWAP_INST_ADD:
+               print_parse_debug("MSG_SWAP_INST_ADD. size=%d\n", size);
+               ret = msg_swap_inst_add(&mb);
+               break;
+       case MSG_SWAP_INST_REMOVE:
+               print_parse_debug("MSG_SWAP_INST_REMOVE. size=%d\n", size);
+               ret = msg_swap_inst_remove(&mb);
+               break;
+       case MSG_WRT_LAUNCHER_PORT: {
+               /* TODO: discuss wrt-launcher port transfer */
+               int port;
+               print_parse_debug("MSG_WRT_LAUNCHER_PORT. size=%d\n", size);
+               port = get_wrt_launcher_port();
+               if (copy_to_user(payload, &port, sizeof(port))) {
+                       ret = -EIO;
+                       break;
+               }
+               ret = port ? 0 : -EINVAL;
+               break;
+       }
+       default:
+               print_err("incorrect message ID [%u]. size=%d\n", msg_id, size);
+               ret = -EINVAL;
+               break;
+       }
+
+uninit:
+       uninit_mb(&mb);
+       return ret;
+}
+
+static struct driver_msg_handler dmsg_handler = {
+       .mod = THIS_MODULE,
+       .handler = msg_handler,
+};
+
+static int reg_msg_handler(void)
+{
+       driver_msg_handler_set(&dmsg_handler);
+       return 0;
+}
+
+static void unreg_msg_handler(void)
+{
+       driver_msg_handler_set(NULL);
+       app_list_unreg_all();
+
+       disable_all_features();
+}
+
+static int once(void)
+{
+       int ret;
+
+       ret = once_cmd();
+       if (ret)
+               return ret;
+
+       ret = init_cpu_deps();
+
+       return ret;
+}
+
+SWAP_LIGHT_INIT_MODULE(once, reg_msg_handler, unreg_msg_handler, NULL, NULL);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/parser/us_inst.c b/modules/parser/us_inst.c
new file mode 100644 (file)
index 0000000..78e5dd8
--- /dev/null
@@ -0,0 +1,426 @@
+/**
+ * parser/us_inst.c
+ * @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
+ *
+ * User-space instrumentation controls.
+ */
+
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/probes/probes.h>
+
+#include "msg_parser.h"
+#include "us_inst.h"
+#include "usm_msg.h"
+
+
+static struct pfg_msg_cb msg_cb = {
+       .msg_info = usm_msg_info,
+       .msg_status_info = usm_msg_status_info,
+       .msg_term = usm_msg_term,
+       .msg_map = usm_msg_map,
+       .msg_unmap = usm_msg_unmap
+};
+
+
+static int probe_inst_reg(struct pr_probe_desc *probe, struct pf_group *pfg,
+                         struct dentry *dentry)
+{
+       probe->ip = pf_register_probe(pfg, dentry, probe->addr, &probe->p_desc);
+       if (IS_ERR(probe->ip))
+               return PTR_ERR(probe->ip);
+
+       return 0;
+}
+
+static void probe_inst_unreg(struct pr_probe_desc *probe, struct pf_group *pfg)
+{
+       pf_unregister_probe(pfg, probe->ip);
+}
+
+static void do_bin_inst_unreg(struct list_head *head, struct pf_group *pfg)
+{
+       struct pr_probe_desc *probe;
+
+       list_for_each_entry(probe, head, list) {
+               probe_inst_unreg(probe, pfg);
+       }
+}
+
+static void bin_inst_unreg(struct pr_bin_desc *bin, struct pf_group *pfg)
+{
+       do_bin_inst_unreg(&bin->probe_head, pfg);
+}
+
+static int bin_inst_reg(struct pr_bin_desc *bin, struct pf_group *pfg)
+{
+       struct pr_probe_desc *probe, *n;
+       struct dentry *dentry;
+       LIST_HEAD(reg_head);
+
+       dentry = dentry_by_path(bin->info->path);
+       if (dentry == NULL) {
+               pr_warn("Cannot get dentry by path %s\n", bin->info->path);
+               return -EINVAL;
+       }
+
+       list_for_each_entry_safe(probe, n, &bin->probe_head, list) {
+               int ret;
+
+               ret = probe_inst_reg(probe, pfg, dentry);
+               if (!ret) {
+                       list_move(&probe->list, &reg_head);
+               } else {
+                       do_bin_inst_unreg(&reg_head, pfg);
+                       return ret;
+               }
+       }
+
+       list_splice(&reg_head, &bin->probe_head);
+       return 0;
+}
+
+static struct pf_group *get_pfg_by_app_info(struct pr_app_info *app)
+{
+       struct pf_group *pfg = ERR_PTR(-EINVAL);
+       struct dentry *dentry;
+
+       dentry = dentry_by_path(app->path);
+       if (dentry == NULL)
+               return pfg;
+
+       switch (app->type) {
+       case AT_PID:
+               if (app->tgid == 0) {
+                       if (app->path[0] == '\0')
+                               pfg = get_pf_group_dumb(dentry);
+                       else
+                               goto pf_dentry;
+               } else {
+                       pfg = get_pf_group_by_tgid(app->tgid, dentry);
+               }
+               break;
+       case AT_TIZEN_WEB_APP:
+               pfg = get_pf_group_by_comm(app->id, dentry);
+               break;
+       case AT_TIZEN_NATIVE_APP:
+       case AT_COMMON_EXEC:
+ pf_dentry:
+               pfg = get_pf_group_by_dentry(dentry, dentry);
+               break;
+       default:
+               pr_info("ERROR: app_type=0x%x\n", app->type);
+               break;
+       }
+
+       if (!pfg)
+               pfg = ERR_PTR(-ENOMEM);
+
+       if (!IS_ERR(pfg)) {
+               /* TODO: move to other location and chack return value */
+               pfg_msg_cb_set(pfg, &msg_cb);
+       }
+
+       return pfg;
+}
+
+static void do_us_app_inst_unreg(struct pr_app_desc *app,
+                                struct list_head *head)
+{
+       struct pr_bin_desc *bin;
+
+       list_for_each_entry(bin, head, list) {
+               bin_inst_unreg(bin, app->pfg);
+       }
+       put_pf_group(app->pfg);
+       app->pfg = NULL;
+}
+
+static void us_app_inst_unreg(struct pr_app_desc *app)
+{
+       do_us_app_inst_unreg(app, &app->bin_head);
+}
+
+static int us_app_inst_reg(struct pr_app_desc *app)
+{
+       struct pf_group *pfg;
+       struct pr_bin_desc *bin, *n;
+       LIST_HEAD(reg_head);
+
+       pfg = get_pfg_by_app_info(app->info);
+       if (IS_ERR(pfg))
+               return PTR_ERR(pfg);
+
+       app->pfg = pfg;
+       list_for_each_entry_safe(bin, n, &app->bin_head, list) {
+               int ret;
+
+               ret = bin_inst_reg(bin, app->pfg);
+               if (!ret) {
+                       list_move(&bin->list, &reg_head);
+               } else {
+                       do_us_app_inst_unreg(app, &reg_head);
+                       return ret;
+               }
+       }
+
+       list_splice(&reg_head, &app->bin_head);
+       return 0;
+}
+
+
+static struct pr_probe_desc *find_probe(struct list_head *head,
+                                       struct pr_probe_desc *probe)
+{
+       struct pr_probe_desc *p;
+
+       list_for_each_entry(p, head, list) {
+               if (!probe_inst_info_cmp(probe, p))
+                       return p;
+       }
+
+       return NULL;
+}
+
+static struct pr_bin_desc *find_bin(struct list_head *head,
+                                   struct pr_bin_info *info)
+{
+       struct pr_bin_desc *bin;
+
+       list_for_each_entry(bin, head, list) {
+               if (!pr_bin_info_cmp(bin->info, info))
+                       return bin;
+       }
+
+       return NULL;
+}
+
+static struct pr_app_desc *find_app(struct list_head *head,
+                                   struct pr_app_info *app_info)
+{
+       struct pr_app_desc *app;
+
+       list_for_each_entry(app, head, list) {
+               if (!pr_app_info_cmp(app->info, app_info))
+                       return app;
+       }
+
+       return NULL;
+}
+
+static void us_probe_get_equal_elements(struct list_head *probe_head,
+                                       struct list_head *test_probe_head,
+                                       struct list_head *out_probe_head)
+{
+       struct pr_probe_desc *test_probe, *n;
+
+       list_for_each_entry_safe(test_probe, n, test_probe_head, list) {
+               struct pr_probe_desc *probe;
+
+               probe = find_probe(probe_head, test_probe);
+               if (probe) {
+                       list_move(&probe->list, out_probe_head);
+
+                       /* remove probe */
+                       list_del(&test_probe->list);
+                       pr_probe_desc_free(test_probe);
+               } else {
+                       return;
+               }
+       }
+}
+
+static void us_bin_get_equal_elements(struct list_head *bin_head,
+                                     struct list_head *test_bin_head,
+                                     struct list_head *out_bin_head)
+{
+       struct pr_bin_desc *test_bin, *n;
+
+       list_for_each_entry_safe(test_bin, n, test_bin_head, list) {
+               struct pr_bin_desc *bin;
+               LIST_HEAD(out_probe_head);
+
+               bin = find_bin(bin_head, test_bin->info);
+               if (!bin)
+                       return;
+
+               us_probe_get_equal_elements(&bin->probe_head,
+                                           &test_bin->probe_head,
+                                           &out_probe_head);
+
+               /* check all probes found */
+               if (list_empty(&test_bin->probe_head)) {
+                       list_move(&test_bin->list, out_bin_head);
+                       list_splice(&out_probe_head, &test_bin->probe_head);
+               } else {
+                       list_splice(&out_probe_head, &bin->probe_head);
+               }
+       }
+}
+
+static void us_app_get_equal_elements(struct list_head *app_head,
+                                     struct list_head *test_app_head,
+                                     struct list_head *out_app_head)
+{
+       struct pr_app_desc *test_app, *n;
+
+       list_for_each_entry_safe(test_app, n, test_app_head, list) {
+               struct pr_app_desc *app;
+               LIST_HEAD(out_bin_head);
+
+               app = find_app(app_head, test_app->info);
+               if (!app)
+                       return;
+
+               us_bin_get_equal_elements(&app->bin_head,
+                                         &test_app->bin_head,
+                                         &out_bin_head);
+
+               /* check all bins found */
+               if (list_empty(&test_app->bin_head)) {
+                       list_move(&test_app->list, out_app_head);
+                       list_splice(&out_bin_head, &test_app->bin_head);
+               } else {
+                       list_splice(&out_bin_head, &app->bin_head);
+               }
+       }
+}
+
+
+static void bin_list_splice(struct list_head *list, struct list_head *head)
+{
+       struct pr_bin_desc *new_bin, *n;
+
+       list_for_each_entry_safe(new_bin, n, list, list) {
+               struct pr_bin_desc *bin;
+
+               bin = find_bin(head, new_bin->info);
+               if (bin) {
+                       list_splice_init(&new_bin->probe_head,
+                                        &bin->probe_head);
+
+                       list_del(&new_bin->list);
+                       pr_bin_desc_free(new_bin);
+               } else {
+                       list_move(&new_bin->list, head);
+               }
+       }
+}
+
+static void app_list_splice(struct list_head *list, struct list_head *head)
+{
+       struct pr_app_desc *new_app, *n;
+
+       list_for_each_entry_safe(new_app, n, list, list) {
+               struct pr_app_desc *app;
+
+               app = find_app(head, new_app->info);
+               if (app) {
+                       bin_list_splice(&new_app->bin_head, &app->bin_head);
+
+                       list_del(&new_app->list);
+                       put_pf_group(app->pfg);
+                       pr_app_desc_free(new_app);
+               } else {
+                       list_move(&new_app->list, head);
+               }
+       }
+}
+
+static void app_list_free(struct list_head *head)
+{
+       struct pr_app_desc *app, *n;
+
+       list_for_each_entry_safe(app, n, head, list) {
+               list_del(&app->list);
+               pr_app_desc_free(app);
+       }
+}
+
+static void do_app_list_unreg(struct list_head *head)
+{
+       struct pr_app_desc *app;
+
+       list_for_each_entry(app, head, list) {
+               us_app_inst_unreg(app);
+       }
+}
+
+
+
+static LIST_HEAD(app_head);
+
+/* After call the 'head' list is empty, do not free it. */
+int app_list_unreg(struct list_head *head)
+{
+       LIST_HEAD(out_app_head);
+
+       us_app_get_equal_elements(&app_head, head, &out_app_head);
+
+       /* check all apps found */
+       if (!list_empty(head)) {
+               app_list_splice(&out_app_head, &app_head);
+               return -EINVAL;
+       }
+
+       do_app_list_unreg(&out_app_head);
+       app_list_free(&out_app_head);
+       return 0;
+}
+
+/* After call the 'head' list is empty, do not free it. */
+int app_list_reg(struct list_head *head)
+{
+       LIST_HEAD(reg_head);
+       struct pr_app_desc *app, *n;
+
+       list_for_each_entry_safe(app, n, head, list) {
+               int ret;
+
+               ret = us_app_inst_reg(app);
+               if (!ret) {
+                       list_move(&app->list, &reg_head);
+               } else {
+                       do_app_list_unreg(&reg_head);
+                       list_splice(&reg_head, head);
+                       app_list_free(head);
+                       return ret;
+               }
+       }
+
+       app_list_splice(&reg_head, &app_head);
+       return 0;
+}
+
+void app_list_unreg_all(void)
+{
+       do_app_list_unreg(&app_head);
+       app_list_free(&app_head);
+}
diff --git a/modules/parser/us_inst.h b/modules/parser/us_inst.h
new file mode 100644 (file)
index 0000000..9db9e1f
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * @file parser/us_inst.h
+ * @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
+ *
+ * User-space instrumentation controls interface.
+ */
+
+
+#ifndef _US_INST_H
+#define _US_INST_H
+
+int app_list_reg(struct list_head *head);
+int app_list_unreg(struct list_head *head);
+void app_list_unreg_all(void);
+
+#endif /* _US_INST_H */
diff --git a/modules/parser/usm_msg.c b/modules/parser/usm_msg.c
new file mode 100644 (file)
index 0000000..71009ac
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/dcache.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/version.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/net.h>
+#include <writer/swap_msg.h>
+#include <master/swap_deps.h>
+#include <us_manager/sspt/sspt.h>      /* ... check_vma() */
+
+
+#define USM_PREFIX      KERN_INFO "[USM] "
+
+
+struct kmem_info {
+       const char *name;
+       unsigned long start;
+       unsigned long end;
+};
+
+#if defined(CONFIG_ARM64) || defined(CONFIG_X86_32)
+static void kmem_info_fill_common(struct kmem_info *info, struct task_struct *task)
+{
+       unsigned long vdso;
+       struct vm_area_struct *vma_vdso;
+
+       vdso = (unsigned long)task->mm->context.vdso;
+       vma_vdso = find_vma_intersection(task->mm, vdso, vdso + 1);
+       if (vma_vdso) {
+               info->name = "[vdso]";
+               info->start = vma_vdso->vm_start;
+               info->end = vma_vdso->vm_end;
+       } else {
+               pr_err(USM_PREFIX "Cannot get VDSO mapping\n");
+               info->name = NULL;
+               info->start = 0;
+               info->end = 0;
+       }
+}
+#endif /* defined(CONFIG_ARM64) || defined(CONFIG_X86_32) */
+
+static void kmem_info_fill(struct kmem_info *info, struct task_struct *task)
+{
+#if defined(CONFIG_ARM)
+       info->name = "[vectors]";
+       info->start = CONFIG_VECTORS_BASE;
+       info->end = CONFIG_VECTORS_BASE + PAGE_SIZE;
+#elif defined(CONFIG_ARM64)
+       if (test_ti_thread_flag(task_thread_info(task), TIF_32BIT)) {
+               info->name = "[vectors]";
+               info->start = AARCH32_VECTORS_BASE;
+               info->end = AARCH32_VECTORS_BASE + PAGE_SIZE;
+       } else {
+               kmem_info_fill_common(info, task);
+       }
+#elif defined(CONFIG_X86_32)
+       kmem_info_fill_common(info, task);
+#endif /* CONFIG_arch */
+}
+
+static inline struct timespec get_task_start_time(struct task_struct *task)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0)
+       return ns_to_timespec(task->real_start_time);
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
+       return task->real_start_time;
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
+}
+
+
+
+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;
+       }
+
+       path_get(&file->f_path);
+       filename = d_path(&file->f_path, tmp_buf, TMP_BUF_LEN);
+       path_put(&file->f_path);
+
+       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 task_struct *task)
+{
+       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, task);
+
+       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 task_struct *task)
+{
+       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 = task->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, task);
+       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_path.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, get_task_start_time(task));
+
+       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);
+       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);
+}
+
+
+
+
+
+/* ============================================================================
+ * =                          MSG_PROCESS_STATUS_INFO                         =
+ * ============================================================================
+ */
+struct ofile {
+       u32 fd;
+       u64 size;
+       char path[0];
+} __packed;
+
+struct osock {
+       u32 fd;
+       u32 ip;
+       u32 port;
+} __packed;
+
+static int pack_ofile(void *data, size_t size, int fd, struct file *file,
+                     loff_t fsize)
+{
+       int ret;
+       struct ofile *ofile;
+
+       if (size < sizeof(*ofile))
+               return -ENOMEM;
+
+       ofile = (struct ofile *)data;
+       ofile->fd = (u32)fd;
+       ofile->size = (u64)fsize;
+
+       ret = pack_path(ofile->path, size - sizeof(*ofile), file);
+       if (ret < 0)
+               return ret;
+
+       return sizeof(*ofile) + ret;
+}
+
+static int is_file_mode(umode_t mode)
+{
+       return S_ISREG(mode);
+}
+
+static int pack_osock(void *data, size_t size, int fd, struct file *file,
+                     loff_t fsize)
+{
+       struct osock *pack_sock;
+       struct socket *sock;
+       struct sockaddr_storage addr;
+       struct sockaddr *saddr = (struct sockaddr *)&addr;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+       int ret_size = sizeof(*pack_sock);
+       int addrlen;
+       int err;
+
+       if (size < sizeof(*pack_sock))
+               return -ENOMEM;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+       sock = sockfd_lookup(fd, &err);
+#else
+       sock = sock_from_file(file, &err);
+#endif  /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
+       if (!sock)
+               return 0;
+
+       kernel_getsockname(sock, saddr, &addrlen);
+
+       pack_sock = (struct osock *)data;
+       pack_sock->fd = (u32)fd;
+       pack_sock->ip = (u32)0x0;
+       pack_sock->port = 0;
+
+       switch (saddr->sa_family) {
+       case AF_INET:
+               pack_sock->ip = (u32)(sin->sin_addr.s_addr);
+               pack_sock->port = ntohs(sin->sin_port);
+               break;
+       default:
+               pr_info("[USM] ignored unknown address type: %u\n",
+                       (unsigned int)saddr->sa_family);
+               ret_size = 0;
+               break;
+       }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+       sockfd_put(sock);
+#endif  /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
+
+       return ret_size;
+}
+
+static int is_sock_mode(umode_t mode)
+{
+       return S_ISSOCK(mode);
+}
+
+typedef int (*pack_func_t)(void *data, size_t size, int fd, struct file *file,
+                           loff_t fsize);
+typedef int (*check_mode_func_t)(umode_t mode);
+
+static int pack_descriptors(void *data, size_t size, pack_func_t pack_func,
+                           check_mode_func_t check_mode,
+                           struct files_struct *files)
+{
+       int ret, fd;
+       const size_t old_size = size;
+       u32 *desc_cnt;
+
+       /* pack descriptor count */
+       desc_cnt = (u32 *)data;
+       *desc_cnt = 0;
+       data += 4;
+       size -= 4;
+
+       /* pack descriptors list */
+       rcu_read_lock();
+       for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
+               struct file *file;
+               struct inode *inode;
+               loff_t fsize;
+
+               file = fcheck_files(files, fd);
+               if (file == NULL)
+                       continue;
+
+               inode = file->f_path.dentry->d_inode;
+               /* check inode and if it is a regular file */
+               if (!inode || !check_mode(inode->i_mode))
+                       continue;
+
+               fsize = inode->i_size;
+               rcu_read_unlock();
+
+               ret = pack_func(data, size, fd, file, fsize);
+               if (ret < 0) {
+                       goto exit;
+               } else if (ret > 0) {
+                       /* increment if data packed only */
+                       data += ret;
+                       size -= ret;
+                       ++(*desc_cnt);
+               }
+
+               rcu_read_lock();
+       }
+
+       rcu_read_unlock();
+       ret = old_size - size;
+
+exit:
+       return ret;
+}
+
+static int pack_status_info(void *data, size_t size, struct task_struct *task)
+{
+       int ret;
+       const size_t old_size = size;
+       struct files_struct *files;
+
+       files = swap_get_files_struct(task);
+       if (!files)
+               return -EIO;
+
+       /* pack pid */
+       *((u32 *)data) = (u32)task->tgid;
+       data += 4;
+       size -= 4;
+
+       /* pack file descriptors */
+       ret = pack_descriptors(data, size, pack_ofile, is_file_mode, files);
+       if (ret < 0)
+               goto put_fstruct;
+       data += ret;
+       size -= ret;
+
+       /* pack sock descriptors */
+       ret = pack_descriptors(data, size, pack_osock, is_sock_mode, files);
+       if (ret < 0)
+               goto put_fstruct;
+       data += ret;
+       size -= ret;
+
+       ret = old_size - size;
+
+put_fstruct:
+       swap_put_files_struct(files);
+       return ret;
+}
+
+void usm_msg_status_info(struct task_struct *task)
+{
+       int ret;
+       void *data;
+       size_t size;
+       struct swap_msg *m;
+
+       m = swap_msg_get(MSG_PROCESS_STATUS_INFO);
+
+       data = swap_msg_payload(m);
+       size = swap_msg_size(m);
+       ret = pack_status_info(data, size, task);
+       if (ret < 0) {
+               printk(USM_PREFIX "ERROR: MSG_PROCESS_STATUS_INFO "
+                      "packing, ret=%d\n", ret);
+               goto put_msg;
+       }
+
+       swap_msg_flush(m, ret);
+
+put_msg:
+       swap_msg_put(m);
+}
diff --git a/modules/parser/usm_msg.h b/modules/parser/usm_msg.h
new file mode 100644 (file)
index 0000000..6c9345d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#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);
+void usm_msg_status_info(struct task_struct *task);
+
+
+#endif /* _USM_MSG_H */
diff --git a/modules/preload/Kbuild b/modules/preload/Kbuild
new file mode 100644 (file)
index 0000000..466b89b
--- /dev/null
@@ -0,0 +1,9 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_preload.o
+swap_preload-y := preload_module.o \
+                  preload_control.o \
+                  preload_debugfs.o \
+                  preload_probe.o \
+                  preload_threads.o \
+                  preload_process.o
diff --git a/modules/preload/preload.h b/modules/preload/preload.h
new file mode 100644 (file)
index 0000000..7034222
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __PRELOAD__
+#define __PRELOAD__
+
+#define PRELOAD_PREFIX "SWAP_PRELOAD: "
+#define PRELOAD_MAX_ATTEMPTS 10
+#define PRELOAD_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
+
+#endif /* __PRELOAD__ */
diff --git a/modules/preload/preload_control.c b/modules/preload/preload_control.c
new file mode 100644 (file)
index 0000000..7d6567e
--- /dev/null
@@ -0,0 +1,324 @@
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/us_common_file.h>
+
+#include "preload.h"
+#include "preload_module.h"
+#include "preload_control.h"
+#include "preload_probe.h"
+
+struct bin_desc {
+       struct list_head list;
+       struct dentry *dentry;
+       char *filename;
+};
+
+struct list_desc {
+       struct list_head list;
+       rwlock_t lock;
+       int cnt;
+};
+
+static struct list_desc target = {
+       .list = LIST_HEAD_INIT(target.list),
+       .lock = __RW_LOCK_UNLOCKED(&target.lock),
+       .cnt = 0
+};
+
+static struct list_desc ignored = {
+       .list = LIST_HEAD_INIT(ignored.list),
+       .lock = __RW_LOCK_UNLOCKED(&ignored.lock),
+       .cnt = 0
+};
+
+static inline struct task_struct *__get_task_struct(void)
+{
+       return current;
+}
+
+static struct bin_desc *__alloc_binary(struct dentry *dentry, char *name,
+                                      int namelen)
+{
+       struct bin_desc *p = NULL;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
+
+       INIT_LIST_HEAD(&p->list);
+       p->filename = kmalloc(namelen + 1, GFP_KERNEL);
+       if (!p->filename)
+               goto fail;
+       memcpy(p->filename, name, namelen);
+       p->filename[namelen] = '\0';
+       p->dentry = dentry;
+
+       return p;
+fail:
+       kfree(p);
+       return NULL;
+}
+
+static void __free_binary(struct bin_desc *p)
+{
+       kfree(p->filename);
+       kfree(p);
+}
+
+static void __free_binaries(struct list_desc *tl)
+{
+       struct bin_desc *p, *n;
+       struct list_head rm_head;
+
+       INIT_LIST_HEAD(&rm_head);
+       write_lock(&tl->lock);
+       list_for_each_entry_safe(p, n, &tl->list, list) {
+               list_move(&p->list, &rm_head);
+       }
+       tl->cnt = 0;
+       write_unlock(&tl->lock);
+
+       list_for_each_entry_safe(p, n, &rm_head, list) {
+               list_del(&p->list);
+               swap_put_dentry(p->dentry);
+               __free_binary(p);
+       }
+}
+
+static bool __check_dentry_already_exist(struct dentry *dentry,
+                                        struct list_desc *tl)
+{
+       struct bin_desc *p;
+       bool ret = false;
+
+       read_lock(&tl->lock);
+       list_for_each_entry(p, &tl->list, list) {
+               if (p->dentry == dentry) {
+                       ret = true;
+                       goto out;
+               }
+       }
+out:
+       read_unlock(&tl->lock);
+
+       return ret;
+}
+
+static int __add_binary(struct dentry *dentry, char *filename,
+                       struct list_desc *tl)
+{
+       struct bin_desc *p;
+       size_t len;
+
+       if (__check_dentry_already_exist(dentry, tl)) {
+               printk(PRELOAD_PREFIX "Binary already exist\n");
+               return EALREADY;
+       }
+
+       /* Filename should be < PATH_MAX */
+       len = strnlen(filename, PATH_MAX);
+       if (len == PATH_MAX)
+               return -EINVAL;
+
+       p = __alloc_binary(dentry, filename, len);
+       if (!p)
+               return -ENOMEM;
+
+       write_lock(&tl->lock);
+       list_add_tail(&p->list, &tl->list);
+       tl->cnt++;
+       write_unlock(&tl->lock);
+
+       return 0;
+}
+
+static struct dentry *__get_caller_dentry(struct task_struct *task,
+                                         unsigned long caller)
+{
+       struct vm_area_struct *vma = NULL;
+
+       if (unlikely(task->mm == NULL))
+               goto get_caller_dentry_fail;
+
+       vma = find_vma_intersection(task->mm, caller, caller + 1);
+       if (unlikely(vma == NULL || vma->vm_file == NULL))
+               goto get_caller_dentry_fail;
+
+       return vma->vm_file->f_path.dentry;
+
+get_caller_dentry_fail:
+
+       return NULL;
+}
+
+static bool __check_if_instrumented(struct task_struct *task,
+                                   struct dentry *dentry)
+{
+       return __check_dentry_already_exist(dentry, &target);
+}
+
+static bool __is_instrumented(void *caller)
+{
+       struct task_struct *task = __get_task_struct();
+       struct dentry *caller_dentry = __get_caller_dentry(task,
+                                                          (unsigned long) caller);
+
+       if (caller_dentry == NULL)
+               return false;
+
+       return __check_if_instrumented(task, caller_dentry);
+}
+
+static unsigned int __get_names(struct list_desc *tl, char ***filenames_p)
+{
+       unsigned int i, ret = 0;
+       struct bin_desc *p;
+       char **a = NULL;
+
+       read_lock(&tl->lock);
+       if (tl->cnt == 0)
+               goto out;
+
+       a = kmalloc(sizeof(*a) * tl->cnt, GFP_KERNEL);
+       if (!a)
+               goto out;
+
+       i = 0;
+       list_for_each_entry(p, &tl->list, list) {
+               if (i >= tl->cnt)
+                       break;
+               a[i++] = p->filename;
+       }
+
+       *filenames_p = a;
+       ret = i;
+out:
+       read_unlock(&tl->lock);
+       return ret;
+}
+
+
+/* Called only form handlers. If we're there, then it is instrumented. */
+enum preload_call_type pc_call_type_always_inst(void *caller)
+{
+       if (__is_instrumented(caller))
+               return INTERNAL_CALL;
+
+       return EXTERNAL_CALL;
+
+}
+
+enum preload_call_type pc_call_type(struct sspt_ip *ip, void *caller)
+{
+       if (__is_instrumented(caller))
+               return INTERNAL_CALL;
+
+       if (ip->desc->info.pl_i.flags & SWAP_PRELOAD_ALWAYS_RUN)
+               return EXTERNAL_CALL;
+
+       return NOT_INSTRUMENTED;
+}
+
+int pc_add_instrumented_binary(char *filename)
+{
+       struct dentry *dentry = swap_get_dentry(filename);
+       int res = 0;
+
+       if (dentry == NULL)
+               return -EINVAL;
+
+       res = __add_binary(dentry, filename, &target);
+       if (res != 0)
+               swap_put_dentry(dentry);
+
+       return res > 0 ? 0 : res;
+}
+
+int pc_clean_instrumented_bins(void)
+{
+       __free_binaries(&target);
+
+       return 0;
+}
+
+int pc_add_ignored_binary(char *filename)
+{
+       struct dentry *dentry = swap_get_dentry(filename);
+       int res = 0;
+
+       if (dentry == NULL)
+               return -EINVAL;
+
+       res = __add_binary(dentry, filename, &ignored);
+       if (res != 0)
+               swap_put_dentry(dentry);
+
+       return res > 0 ? 0 : res;
+}
+
+int pc_clean_ignored_bins(void)
+{
+       __free_binaries(&ignored);
+
+       return 0;
+}
+
+unsigned int pc_get_target_names(char ***filenames_p)
+{
+       return __get_names(&target, filenames_p);
+}
+
+void pc_release_target_names(char ***filenames_p)
+{
+       kfree(*filenames_p);
+}
+
+unsigned int pc_get_ignored_names(char ***filenames_p)
+{
+       return __get_names(&ignored, filenames_p);
+}
+
+void pc_release_ignored_names(char ***filenames_p)
+{
+       kfree(*filenames_p);
+}
+
+bool pc_check_dentry_is_ignored(struct dentry *dentry)
+{
+       struct bin_desc *p;
+       bool ret = false;
+
+       if (dentry == NULL)
+               return false;
+
+       read_lock(&ignored.lock);
+
+       list_for_each_entry(p, &ignored.list, list) {
+               if (p->dentry == dentry) {
+                       ret = true;
+                       break;
+               }
+       }
+
+       read_unlock(&ignored.lock);
+
+       return ret;
+}
+
+int pc_init(void)
+{
+       return 0;
+}
+
+void pc_exit(void)
+{
+       __free_binaries(&target);
+       __free_binaries(&ignored);
+}
diff --git a/modules/preload/preload_control.h b/modules/preload/preload_control.h
new file mode 100644 (file)
index 0000000..4e6f1d0
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __PRELOAD_CONTROL_H__
+#define __PRELOAD_CONTROL_H__
+
+struct sspt_ip;
+
+enum preload_call_type {
+       NOT_INSTRUMENTED,
+       EXTERNAL_CALL,
+       INTERNAL_CALL
+};
+
+int pc_init(void);
+void pc_exit(void);
+
+enum preload_call_type pc_call_type_always_inst(void *caller);
+enum preload_call_type pc_call_type(struct sspt_ip *ip, void *caller);
+int pc_add_instrumented_binary(char *filename);
+int pc_clean_instrumented_bins(void);
+int pc_add_ignored_binary(char *filename);
+int pc_clean_ignored_bins(void);
+
+unsigned int pc_get_target_names(char ***filenames_p);
+void pc_release_target_names(char ***filenames_p);
+
+unsigned int pc_get_ignored_names(char ***filenames_p);
+void pc_release_ignored_names(char ***filenames_p);
+
+bool pc_check_dentry_is_ignored(struct dentry *dentry);
+
+#endif /* __PRELOAD_HANDLERS_CONTROL_H__ */
diff --git a/modules/preload/preload_debugfs.c b/modules/preload/preload_debugfs.c
new file mode 100644 (file)
index 0000000..e480fa9
--- /dev/null
@@ -0,0 +1,725 @@
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/limits.h>
+#include <asm/uaccess.h>
+#include <master/swap_debugfs.h>
+#include <master/swap_initializer.h>
+#include "preload.h"
+#include "preload_module.h"
+#include "preload_debugfs.h"
+#include "preload_control.h"
+#include "preload_process.h"
+
+static const char PRELOAD_FOLDER[] = "preload";
+static const char PRELOAD_TARGET[] = "target_binaries";
+static const char PRELOAD_IGNORED[] = "ignored_binaries";
+static const char PRELOAD_BINARIES_LIST[] = "bins_list";
+static const char PRELOAD_BINARIES_ADD[] = "bins_add";
+static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove";
+static const char PRELOAD_ENABLE[] = "enable";
+static const char PRELOAD_BY_PATH[] = "by_path";
+static const char PRELOAD_BY_PID[] = "by_pid";
+static const char PRELOAD_BY_ID[] = "by_id";
+static const char PRELOAD_ADD[] = "add";
+static const char PRELOAD_DEL[] = "del";
+static const char PRELOAD_DEL_ALL[] = "del_all";
+static const char PRELOAD_PTHREAD[] = "pthread";
+static const char PRELOAD_PATH[] = "path";
+static const char PRELOAD_MINIMAL_INIT[] = "minimal_init_off";
+
+static struct dentry *preload_root;
+static struct dentry *target_list = NULL;
+static struct dentry *target_add = NULL;
+static struct dentry *target_remove = NULL;
+static struct dentry *ignored_list = NULL;
+static struct dentry *ignored_add = NULL;
+static struct dentry *ignored_remove = NULL;
+
+
+/* Type for functions that add process by path and by id */
+typedef int (*sh_t)(const char *);
+
+/* Type for functions that add process by pid */
+typedef int (*ph_t)(pid_t);
+
+/* Type for function that handles unsigned long grabbed from userspace */
+typedef int (*ulh_t)(unsigned long);
+
+
+/* remove end-line symbols */
+static void rm_endline_symbols(char *buf, size_t len)
+{
+       char *p, *buf_end;
+
+       buf_end = buf + len;
+       for (p = buf; p != buf_end; ++p)
+               if (*p == '\n' || *p == '\r')
+                       *p = '\0';
+}
+
+static ssize_t get_string(const char __user *buf, size_t len, char **kbuf)
+{
+       char *string;
+       ssize_t ret;
+
+       string = kmalloc(len + 1, GFP_KERNEL);
+       if (!string) {
+               pr_warn(PRELOAD_PREFIX "No mem for user string!\n");
+               return -ENOMEM;
+       }
+
+       if (copy_from_user(string, buf, len)) {
+               pr_warn(PRELOAD_PREFIX "Failed to copy data from user!\n");
+               ret = -EINVAL;
+               goto get_string_fail;
+       }
+
+       string[len] = '\0';
+       rm_endline_symbols(string, len);
+       *kbuf = string;
+
+       return len;
+
+get_string_fail:
+       kfree(string);
+
+       return ret;
+}
+
+
+static ssize_t get_ul_and_call(const char __user *buf, size_t len, ulh_t cb)
+{
+       ssize_t ret;
+       char *ulstring;
+       unsigned long ul;
+
+       ret = get_string(buf, len, &ulstring);
+       if (ret != len)
+               return ret;
+
+       ret = kstrtoul(ulstring, 16, &ul);
+       if (ret)
+               goto get_ul_write_out;
+
+       ret = cb(ul);
+
+get_ul_write_out:
+       kfree(ulstring);
+
+       return ret == 0 ? len : ret;
+}
+
+static ssize_t get_string_and_call(const char __user *buf, size_t len, sh_t cb)
+{
+       char *string;
+       ssize_t ret;
+
+       ret = get_string(buf, len, &string);
+       if (ret != len)
+               return ret;
+
+       ret = cb(string);
+       if (ret)
+               pr_warn(PRELOAD_PREFIX "Error adding process by <%s>\n",
+                       string);
+
+       kfree(string);
+
+       return ret == 0 ? len : ret;
+}
+
+static ssize_t get_pid_and_call(const char __user *buf, size_t len, ph_t cb)
+{
+       char *string;
+       pid_t pid;
+       ssize_t ret;
+
+       ret = get_string(buf, len, &string);
+       if (ret != len)
+               return ret;
+
+       ret = kstrtoul(string, 10, (unsigned long *)&pid);
+       if (ret) {
+               pr_warn(PRELOAD_PREFIX "Invalid PID!\n");
+               goto get_pid_out;
+       }
+
+       ret = cb(pid);
+       if (ret)
+               pr_warn(PRELOAD_PREFIX "Error adding process by <%s>\n",
+                       string);
+
+get_pid_out:
+       kfree(string);
+
+       return ret == 0 ? len : ret;
+}
+
+/* ===========================================================================
+ * =                           TARGET PROCESSES                              =
+ * ===========================================================================
+ */
+
+static ssize_t by_path_add_write(struct file *file, const char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, pp_add_by_path);
+}
+
+static ssize_t by_path_del_write(struct file *file, const char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, pp_del_by_path);
+}
+
+static ssize_t by_pid_add_write(struct file *file, const char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       return get_pid_and_call(buf, len, pp_add_by_pid);
+}
+
+static ssize_t by_pid_del_write(struct file *file, const char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       return get_pid_and_call(buf, len, pp_del_by_pid);
+}
+
+static ssize_t by_id_add_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, pp_add_by_id);
+}
+
+static ssize_t by_id_del_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, pp_del_by_id);
+}
+
+static ssize_t del_all_write(struct file *file, const char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       pp_del_all();
+
+       WARN(pc_clean_instrumented_bins(), PRELOAD_PREFIX
+            "Error while cleaning target bins\n");
+       WARN(pc_clean_ignored_bins(), PRELOAD_PREFIX
+            "Error while cleaning ignored bins\n");
+
+       return len;
+}
+
+static const struct file_operations by_path_add_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = by_path_add_write,
+};
+
+static const struct file_operations by_path_del_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = by_path_del_write,
+};
+
+static const struct file_operations by_pid_add_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = by_pid_add_write,
+};
+
+static const struct file_operations by_pid_del_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = by_pid_del_write,
+};
+
+static const struct file_operations by_id_add_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = by_id_add_write,
+};
+
+static const struct file_operations by_id_del_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = by_id_del_write,
+};
+
+static const struct file_operations del_all_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = del_all_write,
+};
+
+/* ===========================================================================
+ * =                              ENABLE                                     =
+ * ===========================================================================
+ */
+
+static ssize_t enable_read(struct file *file, char __user *buf,
+                          size_t len, loff_t *ppos)
+{
+       char val[2];
+
+       val[0] = (pm_status() == PRELOAD_ON ? '1' : '0');
+       val[1] = '\0';
+
+       return simple_read_from_buffer(buf, len, ppos, val, 2);
+}
+
+static ssize_t enable_write(struct file *file, const char __user *buf,
+                           size_t len, loff_t *ppos)
+{
+       ssize_t ret = 0;
+       char val[2];
+       size_t val_size;
+
+       val_size = min(len, (sizeof(val) - 1));
+       if (copy_from_user(val, buf, val_size))
+               return -EFAULT;
+
+       val[1] = '\0';
+       switch (val[0]) {
+       case '0':
+               ret = pm_switch(PRELOAD_OFF);
+               break;
+       case '1':
+               ret = pm_switch(PRELOAD_ON);
+               break;
+       default:
+               printk(PRELOAD_PREFIX "Invalid state!\n");
+               return -EINVAL;
+       }
+
+       return ret == 0 ? len : ret;
+}
+
+static const struct file_operations enable_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = enable_write,
+       .read = enable_read,
+};
+
+
+/* ===========================================================================
+ * =                                BIN PATH                                 =
+ * ===========================================================================
+ */
+
+static ssize_t bin_add_write(struct file *file, const char __user *buf,
+                          size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto bin_add_write_out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto bin_add_write_out;
+       }
+
+       path[len - 1] = '\0';
+
+       if (file->f_path.dentry == target_add)
+               ret = pc_add_instrumented_binary(path);
+       else if (file->f_path.dentry == ignored_add)
+               ret = pc_add_ignored_binary(path);
+       else {
+               /* Should never occur */
+               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+                      file->f_path.dentry->d_name.name);
+               ret = -EINVAL;
+               goto bin_add_write_out;
+       }
+
+
+       if (ret != 0) {
+               printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
+               ret = -EINVAL;
+               goto bin_add_write_out;
+       }
+
+       ret = len;
+
+bin_add_write_out:
+       kfree(path);
+
+       return ret;
+}
+
+static ssize_t bin_remove_write(struct file *file, const char __user *buf,
+                             size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+
+       if (file->f_path.dentry == target_remove)
+               ret = pc_clean_instrumented_bins();
+       else if (file->f_path.dentry == ignored_remove)
+               ret = pc_clean_ignored_bins();
+       else {
+               /* Should never occur */
+               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+                      file->f_path.dentry->d_name.name);
+               ret = -EINVAL;
+               goto bin_remove_write_out;
+       }
+
+       if (ret != 0) {
+               printk(PRELOAD_PREFIX "Error during clean!\n");
+               ret = -EINVAL;
+               goto bin_remove_write_out;
+       }
+
+       ret = len;
+
+bin_remove_write_out:
+       return ret;
+}
+
+static ssize_t bin_list_read(struct file *file, char __user *usr_buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int i;
+       unsigned int files_cnt = 0;
+       ssize_t len = 0, tmp, ret = 0;
+       char **filenames = NULL;
+       char *buf = NULL;
+       char *ptr = NULL;
+
+       if (file->f_path.dentry == target_list) {
+               files_cnt = pc_get_target_names(&filenames);
+       } else if (file->f_path.dentry == ignored_list) {
+               files_cnt = pc_get_ignored_names(&filenames);
+       } else {
+               /* Should never occur */
+               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+                      file->f_path.dentry->d_name.name);
+               ret = 0;
+               goto bin_list_read_out;
+       }
+
+       if (files_cnt == 0) {
+               printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
+               ret = 0;
+               goto bin_list_read_fail;
+       }
+
+       for (i = 0; i < files_cnt; i++)
+               len += strlen(filenames[i]);
+
+       buf = kmalloc(len + files_cnt, GFP_KERNEL);
+       if (buf == NULL) {
+               ret = 0;
+               goto bin_list_read_fail;
+       }
+
+       ptr = buf;
+
+       for (i = 0; i < files_cnt; i++) {
+               tmp = strlen(filenames[i]);
+               memcpy(ptr, filenames[i], tmp);
+               ptr += tmp;
+               *ptr = '\n';
+               ptr += 1;
+       }
+
+       ret = simple_read_from_buffer(usr_buf, count, ppos, buf, len);
+
+       kfree(buf);
+
+bin_list_read_fail:
+       if (file->f_path.dentry == target_list) {
+               pc_release_target_names(&filenames);
+       } else if (file->f_path.dentry == ignored_list)  {
+               pc_release_ignored_names(&filenames);
+       } else {
+               /* Should never occur */
+               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+                      file->f_path.dentry->d_name.name);
+               ret = 0;
+       }
+
+bin_list_read_out:
+       return ret;
+}
+
+static const struct file_operations bin_list_file_ops = {
+       .owner = THIS_MODULE,
+       .read = bin_list_read
+};
+
+static const struct file_operations bin_add_file_ops = {
+       .owner = THIS_MODULE,
+       .write = bin_add_write,
+};
+
+static const struct file_operations bin_remove_file_ops = {
+       .owner = THIS_MODULE,
+       .write = bin_remove_write,
+};
+
+
+
+/* ===========================================================================
+ * =                             PTHREAD                                     =
+ * ===========================================================================
+ */
+
+static ssize_t pthread_path_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, pp_set_pthread_path);
+}
+
+static ssize_t init_off_write(struct file *file, const char __user *buf,
+                             size_t len, loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, pp_set_init_offset);
+}
+
+static const struct file_operations pthread_path_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = pthread_path_write,
+};
+
+static const struct file_operations pthread_init_off_fops = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write = init_off_write,
+};
+
+
+
+
+
+
+int pd_init(void)
+{
+       struct dentry *swap_dentry, *root, *target_path, *ignored_path,
+                     *by_path, *by_pid, *by_id, *pthread, *dentry;
+       int ret;
+
+       ret = -ENODEV;
+       if (!debugfs_initialized())
+               goto fail;
+
+       ret = -ENOENT;
+       swap_dentry = swap_debugfs_getdir();
+       if (!swap_dentry)
+               goto fail;
+
+       ret = -ENOMEM;
+       root = swap_debugfs_create_dir(PRELOAD_FOLDER, swap_dentry);
+       if (IS_ERR_OR_NULL(root))
+               goto fail;
+
+       preload_root = root;
+
+       target_path = swap_debugfs_create_dir(PRELOAD_TARGET, root);
+       if (IS_ERR_OR_NULL(target_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       target_list = swap_debugfs_create_file(PRELOAD_BINARIES_LIST,
+                                              PRELOAD_DEFAULT_PERMS,
+                                              target_path,
+                                              NULL, &bin_list_file_ops);
+       if (IS_ERR_OR_NULL(target_list)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       target_add = swap_debugfs_create_file(PRELOAD_BINARIES_ADD,
+                                             PRELOAD_DEFAULT_PERMS,
+                                             target_path,
+                                             NULL, &bin_add_file_ops);
+       if (IS_ERR_OR_NULL(target_add)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       target_remove = swap_debugfs_create_file(PRELOAD_BINARIES_REMOVE,
+                                                PRELOAD_DEFAULT_PERMS,
+                                                target_path,
+                                                NULL, &bin_remove_file_ops);
+       if (IS_ERR_OR_NULL(target_remove)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       ignored_path = swap_debugfs_create_dir(PRELOAD_IGNORED, root);
+       if (IS_ERR_OR_NULL(ignored_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       ignored_list = swap_debugfs_create_file(PRELOAD_BINARIES_LIST,
+                                               PRELOAD_DEFAULT_PERMS,
+                                               ignored_path,
+                                               NULL, &bin_list_file_ops);
+       if (IS_ERR_OR_NULL(ignored_list)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       ignored_add = swap_debugfs_create_file(PRELOAD_BINARIES_ADD,
+                                              PRELOAD_DEFAULT_PERMS,
+                                              ignored_path,
+                                              NULL, &bin_add_file_ops);
+       if (IS_ERR_OR_NULL(ignored_add)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       ignored_remove = swap_debugfs_create_file(PRELOAD_BINARIES_REMOVE,
+                                                 PRELOAD_DEFAULT_PERMS,
+                                                 ignored_path, NULL,
+                                                 &bin_remove_file_ops);
+       if (IS_ERR_OR_NULL(ignored_remove)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       by_path = swap_debugfs_create_dir(PRELOAD_BY_PATH, root);
+       if (IS_ERR_OR_NULL(by_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_ADD, PRELOAD_DEFAULT_PERMS,
+                                         by_path, NULL, &by_path_add_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_DEL, PRELOAD_DEFAULT_PERMS,
+                                         by_path, NULL, &by_path_del_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       by_pid = swap_debugfs_create_dir(PRELOAD_BY_PID, root);
+       if (IS_ERR_OR_NULL(by_pid)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_ADD, PRELOAD_DEFAULT_PERMS,
+                                         by_pid, NULL, &by_pid_add_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_DEL, PRELOAD_DEFAULT_PERMS,
+                                         by_pid, NULL, &by_pid_del_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       by_id = swap_debugfs_create_dir(PRELOAD_BY_ID, root);
+       if (IS_ERR_OR_NULL(by_id)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_ADD, PRELOAD_DEFAULT_PERMS,
+                                         by_id, NULL, &by_id_add_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_DEL, PRELOAD_DEFAULT_PERMS,
+                                         by_id, NULL, &by_id_del_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_DEL_ALL,
+                                         PRELOAD_DEFAULT_PERMS,
+                                         root, NULL, &del_all_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_ENABLE, PRELOAD_DEFAULT_PERMS,
+                                         root, NULL, &enable_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       pthread = swap_debugfs_create_dir(PRELOAD_PTHREAD, root);
+       if (IS_ERR_OR_NULL(pthread)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_PATH, PRELOAD_DEFAULT_PERMS,
+                                         pthread, NULL, &pthread_path_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       dentry = swap_debugfs_create_file(PRELOAD_MINIMAL_INIT,
+                                         PRELOAD_DEFAULT_PERMS, pthread, NULL,
+                                         &pthread_init_off_fops);
+       if (IS_ERR_OR_NULL(dentry)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       return 0;
+
+remove:
+
+       debugfs_remove_recursive(root);
+
+fail:
+       printk(PRELOAD_PREFIX "Debugfs initialization failure: %d\n", ret);
+
+       return ret;
+}
+
+void pd_exit(void)
+{
+       if (preload_root)
+               debugfs_remove_recursive(preload_root);
+       target_list = NULL;
+       target_add = NULL;
+       target_remove = NULL;
+       ignored_list = NULL;
+       ignored_add = NULL;
+       ignored_remove = NULL;
+       preload_root = NULL;
+}
diff --git a/modules/preload/preload_debugfs.h b/modules/preload/preload_debugfs.h
new file mode 100644 (file)
index 0000000..bae931d
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __PRELOAD_HANDLERS_DEBUGFS_H__
+#define __PRELOAD_HANDLERS_DEBUGFS_H__
+
+struct dentry;
+
+int pd_init(void);
+void pd_exit(void);
+
+#endif /* __PRELOAD_HANDLERS_DEBUGFS_H__ */
diff --git a/modules/preload/preload_module.c b/modules/preload/preload_module.c
new file mode 100644 (file)
index 0000000..fd63bdf
--- /dev/null
@@ -0,0 +1,603 @@
+#include <linux/bug.h>
+#include <linux/slab.h>
+#include <linux/namei.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <writer/kernel_operations.h>
+#include <writer/swap_msg.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+#include <us_manager/us_common_file.h>
+#include <loader/loader.h>
+#include <master/swap_initializer.h>
+#include "preload.h"
+#include "preload_module.h"
+#include "preload_debugfs.h"
+#include "preload_control.h"
+#include "preload_threads.h"
+#include "preload_process.h"
+
+enum {
+       /* task preload flags */
+       HANDLER_RUNNING = 0x1
+};
+
+struct user_ptrs {
+       char *caller;
+       char *orig;
+       char *call_type;
+};
+
+static enum preload_status _status = PRELOAD_OFF;
+static DEFINE_MUTEX(status_change);
+
+
+static inline bool _is_enable_no_lock(void)
+{
+       return _status;
+}
+
+static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task,
+                                                      unsigned long caddr)
+{
+       struct vm_area_struct *vma = NULL;
+
+       if ((task == NULL) || (task->mm == NULL))
+               return NULL;
+       vma = find_vma_intersection(task->mm, caddr, caddr + 1);
+
+       return vma;
+}
+
+static inline bool __is_probe_non_block(struct sspt_ip *ip)
+{
+       if (ip->desc->info.pl_i.flags & SWAP_PRELOAD_NON_BLOCK_PROBE)
+               return true;
+
+       return false;
+}
+
+static inline bool __inverted(struct sspt_ip *ip)
+{
+       unsigned long flags = ip->desc->info.pl_i.flags;
+
+       if (flags & SWAP_PRELOAD_INVERTED_PROBE)
+               return true;
+
+       return false;
+}
+
+static inline bool __check_flag_and_call_type(struct sspt_ip *ip,
+                                             enum preload_call_type ct)
+{
+       bool inverted = __inverted(ip);
+
+       if (ct != NOT_INSTRUMENTED || inverted)
+               return true;
+
+       return false;
+}
+
+static inline bool __is_handlers_call(struct vm_area_struct *caller,
+                                     struct pd_t *pd)
+{
+       struct hd_t *hd;
+
+       if (caller == NULL || caller->vm_file == NULL ||
+           caller->vm_file->f_path.dentry == NULL) {
+               return false;
+       }
+
+       hd = lpd_get_hd(pd, caller->vm_file->f_path.dentry);
+       if (hd != NULL)
+               return true;
+
+       return false;
+}
+
+static inline bool __should_drop(struct sspt_ip *ip, enum preload_call_type ct)
+{
+       if (ct == NOT_INSTRUMENTED)
+               return true;
+
+       return false;
+}
+
+static inline int __msg_sanitization(char *user_msg, size_t len,
+                                    struct user_ptrs *ptrs)
+{
+       if (ptrs->caller &&
+           (ptrs->caller < user_msg || ptrs->caller > user_msg + len))
+               return -EINVAL;
+
+       if (ptrs->orig &&
+           (ptrs->orig < user_msg || ptrs->orig > user_msg + len))
+               return -EINVAL;
+
+       if (ptrs->call_type &&
+           (ptrs->call_type < user_msg || ptrs->call_type > user_msg + len))
+               return -EINVAL;
+
+       return 0;
+}
+
+
+
+
+static unsigned long __do_preload_entry(struct uretprobe_instance *ri,
+                                       struct pt_regs *regs,
+                                       struct hd_t *hd)
+{
+       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
+       unsigned long offset = ip->desc->info.pl_i.handler;
+       unsigned long vaddr = 0;
+       unsigned long base;
+       struct vm_area_struct *cvma;
+       struct pd_t *pd;
+       struct pt_data_t ptd;
+
+       base = lpd_get_handlers_base(hd);
+       if (base == 0)
+               return 0;       /* handlers isn't mapped */
+
+       /* jump to preloaded handler */
+       vaddr = base + offset;
+       ptd.caller = get_regs_ret_func(regs);
+       cvma = __get_vma_by_addr(current, ptd.caller);
+       ptd.call_type = pc_call_type(ip, (void *)ptd.caller);
+       ptd.disable_addr = __is_probe_non_block(ip) ? ip->orig_addr : 0;
+       ptd.orig = ip->orig_addr;
+       pd = lpd_get_parent_pd(hd);
+
+       /* jump only if caller is instumented and it is not a system lib -
+        * this leads to some errors
+        */
+       if (cvma != NULL && cvma->vm_file != NULL &&
+           !pc_check_dentry_is_ignored(cvma->vm_file->f_path.dentry) &&
+           __check_flag_and_call_type(ip, ptd.call_type) &&
+           !__is_handlers_call(cvma, pd)) {
+
+               ptd.drop = __should_drop(ip, ptd.call_type);
+               if (pt_set_data(current, &ptd) != 0)
+                       printk(PRELOAD_PREFIX "Error! Failed to store data for %d/%d\n",
+                              current->tgid, current->pid);
+               /* args are not changed */
+               loader_module_prepare_ujump(ri, regs, vaddr);
+               if (ptd.disable_addr == 0)
+                       pt_set_flags(current, HANDLER_RUNNING);
+       }
+
+       return vaddr;
+}
+
+static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+       struct hd_t *hd;
+       unsigned long old_pc = swap_get_upc(regs);
+       unsigned long flags = pt_get_flags(current);
+       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
+       unsigned long vaddr = 0;
+       struct dentry *dentry = ip->desc->info.pl_i.dentry;
+
+       if (dentry == NULL)
+               goto out_set_orig;
+
+       if ((flags & HANDLER_RUNNING) ||
+           pt_check_disabled_probe(current, ip->orig_addr))
+               goto out_set_orig;
+
+       hd = lpd_get_hd(pd, dentry);
+       if (hd == NULL)
+               goto out_set_orig;
+
+       if ((lpd_get_state(hd) == NOT_LOADED ||
+           lpd_get_state(hd) == FAILED) && lpd_get_init_state(pd))
+               vaddr = loader_not_loaded_entry(ri, regs, pd, hd);
+       else if (lpd_get_state(hd) == LOADED)
+               vaddr =__do_preload_entry(ri, regs, hd);
+
+out_set_orig:
+       loader_set_priv_origin(ri, vaddr);
+
+       /* PC change check */
+       return old_pc != swap_get_upc(regs);
+}
+
+static void __do_preload_ret(struct uretprobe_instance *ri, struct hd_t *hd)
+{
+       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
+       unsigned long flags = pt_get_flags(current);
+       unsigned long offset = ip->desc->info.pl_i.handler;
+       unsigned long vaddr = 0;
+
+       if ((flags & HANDLER_RUNNING) ||
+           pt_check_disabled_probe(current, ip->orig_addr)) {
+               bool non_blk_probe = __is_probe_non_block(ip);
+
+               /* drop the flag if the handler has completed */
+               vaddr = lpd_get_handlers_base(hd) + offset;
+               if (vaddr && (loader_get_priv_origin(ri) == vaddr)) {
+                       if (pt_put_data(current) != 0)
+                               printk(PRELOAD_PREFIX "Error! Failed to put "
+                                      "caller slot for %d/%d\n", current->tgid,
+                                      current->pid);
+                       if (!non_blk_probe) {
+                               flags &= ~HANDLER_RUNNING;
+                               pt_set_flags(current, flags);
+                       }
+               }
+       }
+}
+
+static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
+       struct dentry *dentry = ip->desc->info.pl_i.dentry;
+       struct hd_t *hd;
+
+       if (dentry == NULL)
+               return 0;
+
+       hd = lpd_get_hd(pd, dentry);
+       if (hd == NULL)
+               return 0;
+
+       switch (lpd_get_state(hd)) {
+       case NOT_LOADED:
+               /* loader has not yet been mapped... just ignore */
+               break;
+       case LOADING:
+               loader_loading_ret(ri, regs, pd, hd);
+               break;
+       case LOADED:
+               __do_preload_ret(ri, hd);
+               break;
+       case FAILED:
+               loader_failed_ret(ri, regs, pd, hd);
+               break;
+       case ERROR:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+
+
+
+
+static void __write_data_on_demand(char *user, char *msg, size_t len,
+                                  struct user_ptrs *ptrs,
+                                  unsigned long caller_addr)
+{
+       unsigned long caller_ptr = 0, orig_ptr = 0, ct_ptr = 0;
+       unsigned long caller = 0, orig = 0;
+       unsigned char call_type = 0;
+       int ret;
+
+       /* Evaluate addresses whereto write data as:
+        * pointer from user - user buffer beggining + kernel buffer beginning
+        *  If incoming pointer is NULL - do not write
+        */
+
+       if (ptrs->orig) {
+               orig_ptr = (unsigned long)(ptrs->orig - user + msg);
+
+               ret = pt_get_orig(current, &orig);
+               if (ret) {
+                       orig = 0xbadbeef;
+                       printk(PRELOAD_PREFIX "No orig for %d/%d\n",
+                              current->tgid, current->pid);
+               }
+
+               /* Types should be the same as in preload lib!!! */
+               *(uint64_t *)orig_ptr = (uint64_t)orig;
+       }
+
+       if (caller_addr && ptrs->caller && ptrs->call_type) {
+               caller_ptr = (unsigned long)(ptrs->caller - user + msg);
+               ct_ptr = (unsigned long)(ptrs->call_type - user + msg);
+
+               caller = caller_addr;
+               call_type =
+                   pc_call_type_always_inst((void *)caller);
+
+               /* Types should be the same as in preload lib!!! */
+               *(uint64_t *)caller_ptr = (uint64_t)caller;
+               *(uint32_t *)ct_ptr = (uint32_t)call_type;
+
+               return;
+       }
+
+       if (ptrs->caller) {
+               caller_ptr = (unsigned long)(ptrs->caller - user + msg);
+
+               ret = pt_get_caller(current, &caller);
+               if (ret) {
+                       caller = 0xbadbeef;
+                       printk(PRELOAD_PREFIX "No caller for %d/%d\n",
+                              current->tgid, current->pid);
+               }
+
+               /* Types should be the same as in preload lib!!! */
+               *(uint64_t *)caller_ptr = (uint64_t)caller;
+       }
+
+       if (ptrs->call_type) {
+               ct_ptr = (unsigned long)(ptrs->call_type - user + msg);
+
+               ret = pt_get_call_type(current, &call_type);
+               if (ret) {
+                       call_type = 0xff;
+                       printk(PRELOAD_PREFIX "No call type for %d/%d\n",
+                              current->tgid, current->pid);
+               }
+
+               /* Types should be the same as in preload lib!!! */
+               *(uint32_t *)ct_ptr = (uint32_t)call_type;
+       }
+}
+
+static int write_msg_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct user_ptrs ptrs;
+       char *user_buf, *buf;
+       size_t len;
+       unsigned long caller_addr;
+       int ret;
+
+       /* FIXME: swap_get_uarg uses get_user(), it might sleep */
+       user_buf = (char *)swap_get_uarg(regs, 0);
+       len = swap_get_uarg(regs, 1);
+       ptrs.call_type = (char *)swap_get_uarg(regs, 2);
+       ptrs.caller = (char *)swap_get_uarg(regs, 3);
+       caller_addr = swap_get_uarg(regs, 4);
+       ptrs.orig = (char *)swap_get_uarg(regs, 5);
+
+       if (ptrs.caller || ptrs.call_type || ptrs.orig) {
+               ret = __msg_sanitization(user_buf, len, &ptrs);
+               if (ret != 0) {
+                       printk(PRELOAD_PREFIX "Invalid message pointers!\n");
+                       return 0;
+               }
+               ret = pt_get_drop(current);
+               if (ret > 0)
+                       return 0;
+       }
+
+       buf = kmalloc(len, GFP_ATOMIC);
+       if (buf == NULL) {
+               printk(PRELOAD_PREFIX "No mem for buffer! Size = %zd\n", len);
+               return 0;
+       }
+
+       ret = read_proc_vm_atomic(current, (unsigned long)user_buf, buf, len);
+       if (ret < 0) {
+               printk(PRELOAD_PREFIX "Cannot copy data from userspace! Size = "
+                                     "%zd ptr 0x%lx ret %d\n", len,
+                                     (unsigned long)user_buf, ret);
+               goto write_msg_fail;
+       }
+
+       __write_data_on_demand(user_buf, buf, len, &ptrs, caller_addr);
+
+       ret = swap_msg_raw(buf, len);
+       if (ret != len)
+               printk(PRELOAD_PREFIX "Error writing probe lib message\n");
+
+write_msg_fail:
+       kfree(buf);
+
+       return 0;
+}
+
+static int get_caller_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       unsigned long caller;
+       int ret;
+
+       ret = pt_get_caller(current, &caller);
+       if (ret != 0) {
+               caller = 0xbadbeef;
+               printk(PRELOAD_PREFIX "Error! Cannot get caller address for "
+                      "%d/%d\n", current->tgid, current->pid);
+       }
+
+       swap_put_uarg(regs, 0, caller);
+
+       return 0;
+}
+
+static int get_call_type_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       unsigned char call_type;
+       int ret;
+
+       ret = pt_get_call_type(current, &call_type);
+       if (ret != 0) {
+               call_type = 0xff;
+               printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n",
+                      current->tgid, current->pid);
+       }
+
+       swap_put_uarg(regs, 0, call_type);
+
+       return 0;
+}
+
+
+
+
+
+int pm_get_caller_init(struct sspt_ip *ip)
+{
+       struct uprobe *up = &ip->uprobe;
+
+       up->pre_handler = get_caller_handler;
+
+       return 0;
+}
+
+void pm_get_caller_exit(struct sspt_ip *ip)
+{
+}
+
+int pm_get_call_type_init(struct sspt_ip *ip)
+{
+       struct uprobe *up = &ip->uprobe;
+
+       up->pre_handler = get_call_type_handler;
+
+       return 0;
+}
+
+void pm_get_call_type_exit(struct sspt_ip *ip)
+{
+}
+
+int pm_write_msg_init(struct sspt_ip *ip)
+{
+       struct uprobe *up = &ip->uprobe;
+
+       up->pre_handler = write_msg_handler;
+
+       return 0;
+}
+
+void pm_write_msg_exit(struct sspt_ip *ip)
+{
+}
+
+
+
+int pm_uprobe_init(struct sspt_ip *ip)
+{
+       struct uretprobe *rp = &ip->retprobe;
+       struct dentry *dentry;
+       const char *path = ip->desc->info.pl_i.path;
+
+       rp->entry_handler = preload_us_entry;
+       rp->handler = preload_us_ret;
+
+       /* Get dentry and set it in probe info struct */
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL) {
+               pr_warn(PRELOAD_PREFIX "Error! Cannot get handler %s\n", path);
+               return -EINVAL;
+       }
+       ip->desc->info.pl_i.dentry = dentry;
+
+       /* Add handler to loader */
+       loader_add_handler(path);
+
+       /* FIXME actually additional data_size is needed only when we jump
+        * to dlopen */
+       loader_set_rp_data_size(rp);
+
+       return 0;
+}
+
+void pm_uprobe_exit(struct sspt_ip *ip)
+{
+       struct dentry *dentry = ip->desc->info.pl_i.dentry;
+
+       WARN_ON(!dentry);
+
+       if (dentry)
+               swap_put_dentry(dentry);
+}
+
+int pm_switch(enum preload_status stat)
+{
+       int ret = 0;
+
+       mutex_lock(&status_change);
+       switch (stat) {
+       case PRELOAD_ON:
+               if (_is_enable_no_lock())
+                       goto pm_switch_unlock;
+
+               ret = pp_enable();
+               if (!ret)
+                       _status = PRELOAD_ON;
+               break;
+       case PRELOAD_OFF:
+               if (!_is_enable_no_lock())
+                       goto pm_switch_unlock;
+
+               pp_disable();
+               _status = PRELOAD_OFF;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+pm_switch_unlock:
+       mutex_unlock(&status_change);
+
+       return ret;
+}
+
+enum preload_status pm_status(void)
+{
+       enum preload_status s;
+
+       mutex_lock(&status_change);
+       s = _status;
+       mutex_unlock(&status_change);
+
+       return s;
+}
+
+static int pm_init(void)
+{
+       int ret;
+
+       ret = pd_init();
+       if (ret)
+               goto out_err;
+
+       ret = pc_init();
+       if (ret)
+               goto control_init_fail;
+
+       ret = pt_init();
+       if (ret)
+               goto threads_init_fail;
+
+       ret = register_preload_probes();
+       if (ret)
+               goto probes_register_fail;
+
+       return 0;
+
+probes_register_fail:
+       pt_exit();
+
+threads_init_fail:
+       pc_exit();
+
+control_init_fail:
+       pd_exit();
+
+out_err:
+       return ret;
+}
+
+static void pm_exit(void)
+{
+       unregister_preload_probes();
+       pt_exit();
+       pc_exit();
+       pd_exit();
+}
+
+SWAP_LIGHT_INIT_MODULE(NULL, pm_init, pm_exit, NULL, NULL);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP Preload Module");
+MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/modules/preload/preload_module.h b/modules/preload/preload_module.h
new file mode 100644 (file)
index 0000000..fd19bee
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __PRELOAD_MODULE_H__
+#define __PRELOAD_MODULE_H__
+
+struct sspt_ip;
+struct dentry;
+
+
+enum preload_status {
+       PRELOAD_ON,
+       PRELOAD_OFF
+};
+
+enum preload_status pm_status(void);
+int pm_switch(enum preload_status stat);
+
+int pm_uprobe_init(struct sspt_ip *ip);
+void pm_uprobe_exit(struct sspt_ip *ip);
+
+int pm_get_caller_init(struct sspt_ip *ip);
+void pm_get_caller_exit(struct sspt_ip *ip);
+int pm_get_call_type_init(struct sspt_ip *ip);
+void pm_get_call_type_exit(struct sspt_ip *ip);
+int pm_write_msg_init(struct sspt_ip *ip);
+void pm_write_msg_exit(struct sspt_ip *ip);
+
+#endif /* __PRELOAD_MODULE_H__ */
diff --git a/modules/preload/preload_probe.c b/modules/preload/preload_probe.c
new file mode 100644 (file)
index 0000000..3db3fd0
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/preload_probe.c
+ *
+ * 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, 2014
+ *
+ * 2014         Alexander Aksenov: Preload implement
+ *
+ */
+
+#include <linux/module.h>
+#include <us_manager/us_manager.h>
+#include <us_manager/probes/register_probes.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <uprobe/swap_uprobes.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include "preload_probe.h"
+#include "preload.h"
+#include "preload_module.h"
+
+static int preload_info_copy(struct probe_info *dest,
+                             const struct probe_info *source)
+{
+       memcpy(dest, source, sizeof(*source));
+
+       return 0;
+}
+
+static void preload_info_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *preload_get_uprobe(struct sspt_ip *ip)
+{
+       return &ip->retprobe.up;
+}
+
+/* Registers probe if preload is 'running' or 'ready'.
+ */
+static int preload_register_probe(struct sspt_ip *ip)
+{
+       return swap_register_uretprobe(&ip->retprobe);
+}
+
+static void preload_unregister_probe(struct sspt_ip *ip, int disarm)
+{
+       __swap_unregister_uretprobe(&ip->retprobe, disarm);
+}
+
+static void preload_init(struct sspt_ip *ip)
+{
+       pm_uprobe_init(ip);
+}
+
+static void preload_uninit(struct sspt_ip *ip)
+{
+       pm_uprobe_exit(ip);
+
+       preload_info_cleanup(&ip->desc->info);
+}
+
+static struct probe_iface preload_iface = {
+       .init = preload_init,
+       .uninit = preload_uninit,
+       .reg = preload_register_probe,
+       .unreg = preload_unregister_probe,
+       .get_uprobe = preload_get_uprobe,
+       .copy = preload_info_copy,
+       .cleanup = preload_info_cleanup
+};
+
+static int get_caller_info_copy(struct probe_info *dest,
+                               const struct probe_info *source)
+{
+       memcpy(dest, source, sizeof(*source));
+
+       return 0;
+}
+
+static void get_caller_info_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *get_caller_get_uprobe(struct sspt_ip *ip)
+{
+       return &ip->uprobe;
+}
+
+static int get_caller_register_probe(struct sspt_ip *ip)
+{
+       return swap_register_uprobe(&ip->uprobe);
+}
+
+static void get_caller_unregister_probe(struct sspt_ip *ip, int disarm)
+{
+       __swap_unregister_uprobe(&ip->uprobe, disarm);
+}
+
+static void get_caller_init(struct sspt_ip *ip)
+{
+       pm_get_caller_init(ip);
+}
+
+static void get_caller_uninit(struct sspt_ip *ip)
+{
+       pm_get_caller_exit(ip);
+
+       get_caller_info_cleanup(&ip->desc->info);
+}
+
+static struct probe_iface get_caller_iface = {
+       .init = get_caller_init,
+       .uninit = get_caller_uninit,
+       .reg = get_caller_register_probe,
+       .unreg = get_caller_unregister_probe,
+       .get_uprobe = get_caller_get_uprobe,
+       .copy = get_caller_info_copy,
+       .cleanup = get_caller_info_cleanup
+};
+
+static void get_call_type_init(struct sspt_ip *ip)
+{
+       pm_get_call_type_init(ip);
+}
+
+static void get_call_type_uninit(struct sspt_ip *ip)
+{
+       pm_get_call_type_exit(ip);
+
+       get_caller_info_cleanup(&ip->desc->info);
+}
+
+static struct probe_iface get_call_type_iface = {
+       .init = get_call_type_init,
+       .uninit = get_call_type_uninit,
+       .reg = get_caller_register_probe,
+       .unreg = get_caller_unregister_probe,
+       .get_uprobe = get_caller_get_uprobe,
+       .copy = get_caller_info_copy,
+       .cleanup = get_caller_info_cleanup
+};
+
+static void write_msg_init(struct sspt_ip *ip)
+{
+       pm_write_msg_init(ip);
+}
+
+static int write_msg_reg(struct sspt_ip *ip)
+{
+       return get_caller_register_probe(ip);
+}
+
+static void write_msg_uninit(struct sspt_ip *ip)
+{
+       pm_write_msg_exit(ip);
+
+       get_caller_info_cleanup(&ip->desc->info);
+}
+
+static struct probe_iface write_msg_iface = {
+       .init = write_msg_init,
+       .uninit = write_msg_uninit,
+       .reg = write_msg_reg,
+       .unreg = get_caller_unregister_probe,
+       .get_uprobe = get_caller_get_uprobe,
+       .copy = get_caller_info_copy,
+       .cleanup = get_caller_info_cleanup
+};
+
+int register_preload_probes(void)
+{
+       int ret;
+
+       ret = swap_register_probe_type(SWAP_PRELOAD_PROBE, &preload_iface);
+       if (ret != 0)
+               return ret;
+
+       ret = swap_register_probe_type(SWAP_GET_CALLER, &get_caller_iface);
+       if (ret != 0)
+               return ret;
+
+       ret = swap_register_probe_type(SWAP_GET_CALL_TYPE, &get_call_type_iface);
+       if (ret != 0)
+               return ret;
+
+       ret = swap_register_probe_type(SWAP_WRITE_MSG, &write_msg_iface);
+
+       return ret;
+}
+
+void unregister_preload_probes(void)
+{
+       swap_unregister_probe_type(SWAP_PRELOAD_PROBE);
+       swap_unregister_probe_type(SWAP_GET_CALLER);
+       swap_unregister_probe_type(SWAP_GET_CALL_TYPE);
+       swap_unregister_probe_type(SWAP_WRITE_MSG);
+}
diff --git a/modules/preload/preload_probe.h b/modules/preload/preload_probe.h
new file mode 100644 (file)
index 0000000..f068b89
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/preload_probe.h
+ *
+ * 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, 2014
+ *
+ * 2014         Alexander Aksenov: FBI implement
+ *
+ */
+
+#ifndef __PRELOAD_HANDLERS_PROBE_H__
+#define __PRELOAD_HANDLERS_PROBE_H__
+
+/* Probe flags description:
+ *
+ *    0 - handler is ran only when probe has fired from a target binary;
+ *    1 - handler is always ran;
+ *
+ *   00 - probe is disabling internal probes;
+ *   10 - probe is non blocking one;
+ *
+ *  000 - probe is executed for instrumented binaries
+ *  100 - probe is executed for non-instrumented binaries
+ */
+
+enum {
+       SWAP_PRELOAD_ALWAYS_RUN =       (1 << 0),
+       SWAP_PRELOAD_NON_BLOCK_PROBE =  (1 << 1),
+       SWAP_PRELOAD_INVERTED_PROBE =   (1 << 2)
+};
+
+/* Preload probe info. */
+struct preload_info {
+       unsigned long handler;              /* Handler offset in probe library. */
+       unsigned char flags;                /* Preload probe flags. */
+       const char *path;                   /* Library with handler */
+       struct dentry *dentry;              /* Handler file dentry */
+};
+
+/* Get caller probe info */
+struct get_caller_info {
+};
+
+/* Get call type probe info */
+struct get_call_type_info {
+};
+
+/* Write message probe info */
+struct write_msg_info {
+};
+
+int register_preload_probes(void);
+void unregister_preload_probes(void);
+
+#endif /* __PRELOAD_HANDLERS_PROBE_H__ */
diff --git a/modules/preload/preload_process.c b/modules/preload/preload_process.c
new file mode 100644 (file)
index 0000000..1b777b1
--- /dev/null
@@ -0,0 +1,461 @@
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <us_manager/us_common_file.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/probes/probe_info_new.h>
+#include <loader/loader.h>
+#include "preload.h"
+#include "preload_process.h"
+
+
+enum task_id_t {
+       SET_BY_PATH,
+       SET_BY_PID,
+       SET_BY_ID
+};
+
+struct process_t {
+       struct list_head list;
+       struct pf_group *pfg;
+       enum task_id_t idt;
+       union {
+               struct dentry *dentry;
+               pid_t pid;
+               char *id;
+       };
+       struct probe_new p_init;
+};
+
+struct bin_data_t {
+       struct dentry *dentry;
+       unsigned long off;
+};
+
+/* For process list elements checker */
+typedef struct process_t *(*checker_t)(struct process_t *, void *);
+
+static LIST_HEAD(_reg_proc_list);
+static LIST_HEAD(_unreg_proc_list);
+static DEFINE_MUTEX(_proc_list_lock);
+
+static struct bin_data_t _pthread_init;
+
+static inline void _lock_proc_list(void)
+{
+       mutex_lock(&_proc_list_lock);
+}
+
+static inline void _unlock_proc_list(void)
+{
+       mutex_unlock(&_proc_list_lock);
+}
+
+static inline struct process_t *_check_by_dentry(struct process_t *proc,
+                                                void *data)
+{
+       struct dentry *dentry = data;
+
+       if (proc->idt == SET_BY_PATH && proc->dentry == dentry)
+               return proc;
+
+       return NULL;
+}
+
+static inline struct process_t *_check_by_pid(struct process_t *proc,
+                                             void *data)
+{
+       pid_t pid = *(pid_t *)data;
+
+       if (proc->idt == SET_BY_PID && proc->pid == pid)
+               return proc;
+
+       return NULL;
+}
+
+static inline struct process_t *_check_by_id(struct process_t *proc, void *data)
+{
+       char *id = data;
+
+       if (proc->idt == SET_BY_ID && proc->id == id)
+               return proc;
+
+       return NULL;
+}
+
+static inline bool _is_pthread_data_available(void)
+{
+       return (_pthread_init.dentry && _pthread_init.off);
+}
+
+
+
+
+static int pthread_init_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+
+       lpd_set_init_state(pd, false);
+
+       return 0;
+}
+
+static int pthread_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+
+       lpd_set_init_state(pd, true);
+
+       return 0;
+}
+
+static struct probe_desc pin_pinit = MAKE_URPROBE(pthread_init_eh,
+                                                 pthread_init_rh, 0);
+
+static int _proc_reg_no_lock(struct process_t *proc)
+{
+       int ret;
+
+       proc->p_init.desc = &pin_pinit;
+       proc->p_init.offset = _pthread_init.off;
+       ret = pin_register(&proc->p_init, proc->pfg, _pthread_init.dentry);
+       if (ret)
+               pr_warn(PRELOAD_PREFIX "Can't register pthread init probe\n");
+
+       return ret;
+}
+
+static void _proc_unreg_no_lock(struct process_t *proc)
+{
+       pin_unregister(&proc->p_init, proc->pfg);
+}
+
+static struct process_t *_proc_create(struct pf_group *pfg)
+{
+       struct process_t *proc;
+
+       proc = kzalloc(sizeof(*proc), GFP_KERNEL);
+       if (!proc) {
+               pr_warn(PRELOAD_PREFIX "No mem to alloc proccess_t struct!\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       INIT_LIST_HEAD(&proc->list);
+       proc->pfg = pfg;
+
+       return proc;
+}
+
+static void _proc_destroy(struct process_t *proc)
+{
+       if (proc->pfg)
+               put_pf_group(proc->pfg);
+
+       if (proc->idt == SET_BY_PATH)
+               swap_put_dentry(proc->dentry);
+
+       if (proc->idt == SET_BY_ID)
+               kfree(proc->id);
+
+       kfree(proc);
+}
+
+static int _add_to_list(struct process_t *proc)
+{
+       _lock_proc_list();
+       list_add_tail(&proc->list, &_unreg_proc_list);
+       _unlock_proc_list();
+
+       return 0;
+}
+
+/* checker - used to check process list candidates, chosen by type of
+ * registration (path, pid, id)
+ * data - pointer to target process data, checker compares candidate with
+ */
+
+static struct process_t *_get_from_list_no_lock(checker_t checker, void *data,
+                                               struct list_head *list)
+{
+       struct process_t *proc;
+
+       list_for_each_entry(proc, list, list) {
+               if (checker(proc, data))
+                       return proc;
+       }
+
+       return NULL;
+}
+
+static void _delete_from_list(checker_t checker, void *data)
+{
+       struct process_t *proc;
+
+       _lock_proc_list();
+       proc = _get_from_list_no_lock(checker, data, &_unreg_proc_list);
+       if (proc) {
+               list_del(&proc->list);
+               _proc_destroy(proc);
+               goto delete_from_list_unlock;
+       }
+
+       proc = _get_from_list_no_lock(checker, data, &_reg_proc_list);
+       if (proc) {
+               list_del(&proc->list);
+               _proc_unreg_no_lock(proc);
+               _proc_destroy(proc);
+       }
+
+delete_from_list_unlock:
+       _unlock_proc_list();
+}
+
+
+
+int pp_add_by_path(const char *path)
+{
+       struct dentry *dentry;
+       struct pf_group *pfg;
+       struct process_t *proc;
+       int ret;
+
+       dentry = swap_get_dentry(path);
+       if (!dentry) {
+               pr_warn(PRELOAD_PREFIX "Can't get dentry for <%s>\n", path);
+               return -EINVAL;
+       }
+
+       pfg = get_pf_group_by_dentry(dentry, dentry);
+       if (pfg == NULL) {
+               ret = -ENOMEM;
+               goto by_path_put_dentry;
+       }
+
+       proc = _proc_create(pfg);
+       if (!proc) {
+               ret = -EINVAL;
+               goto by_path_put_pfg;
+       }
+
+       proc->idt = SET_BY_PATH;
+       proc->dentry = dentry;
+
+       ret = _add_to_list(proc);
+       if (ret)
+               goto by_path_free;
+
+       return 0;
+
+by_path_free:
+       kfree(proc);
+
+by_path_put_pfg:
+       put_pf_group(pfg);
+
+by_path_put_dentry:
+       swap_put_dentry(dentry);
+
+       return ret;
+}
+
+int pp_add_by_pid(pid_t pid)
+{
+       struct pf_group *pfg;
+       struct process_t *proc;
+       int ret;
+
+       pfg = get_pf_group_by_tgid(pid, NULL);
+       if (pfg == NULL)
+               return -ENOMEM;
+
+       proc = _proc_create(pfg);
+       if (!proc) {
+               ret = -EINVAL;
+               goto by_pid_put_pfg;
+       }
+
+       proc->idt = SET_BY_PID;
+       proc->pid = pid;
+
+       ret = _add_to_list(proc);
+       if (ret)
+               goto by_pid_free;
+
+       return 0;
+
+by_pid_free:
+       kfree(proc);
+
+by_pid_put_pfg:
+       put_pf_group(pfg);
+
+       return ret;
+}
+
+int pp_add_by_id(const char *id)
+{
+       char *new_id;
+       struct pf_group *pfg;
+       struct process_t *proc;
+       int ret;
+
+       new_id = kstrdup(id, GFP_KERNEL);
+       if (!new_id)
+               return -ENOMEM;
+
+       pfg = get_pf_group_by_comm((char *)id, NULL);
+       if (pfg == NULL) {
+               ret = -ENOMEM;
+               goto by_id_free_new_id;
+       }
+
+       proc = _proc_create(pfg);
+       if (!proc) {
+               ret = -EINVAL;
+               goto by_id_put_pfg;
+       }
+
+       proc->idt = SET_BY_ID;
+       proc->id = new_id;
+
+       ret = _add_to_list(proc);
+       if (ret)
+               goto by_id_free;
+
+       return 0;
+
+by_id_free:
+       kfree(proc);
+
+by_id_put_pfg:
+       put_pf_group(pfg);
+
+by_id_free_new_id:
+       kfree(new_id);
+
+       return ret;
+}
+
+int pp_del_by_path(const char *path)
+{
+       struct dentry *dentry;
+
+       dentry = swap_get_dentry(path);
+       if (!dentry) {
+               pr_warn(PRELOAD_PREFIX "No dentry for <%s>\n", path);
+               return -EINVAL;
+       }
+
+       _delete_from_list(_check_by_dentry, dentry);
+
+       swap_put_dentry(dentry);
+
+       return 0;
+}
+
+int pp_del_by_pid(pid_t pid)
+{
+       _delete_from_list(_check_by_pid, &pid);
+
+       return 0;
+}
+
+int pp_del_by_id(const char *id)
+{
+       _delete_from_list(_check_by_id, (void *)id);
+
+       return 0;
+}
+
+void pp_del_all(void)
+{
+       struct process_t *tmp, *proc;
+
+       _lock_proc_list();
+
+       list_for_each_entry_safe(proc, tmp, &_unreg_proc_list, list) {
+               list_del(&proc->list);
+               _proc_destroy(proc);
+       }
+
+       list_for_each_entry_safe(proc, tmp, &_reg_proc_list, list) {
+               list_del(&proc->list);
+               _proc_unreg_no_lock(proc);
+               _proc_destroy(proc);
+       }
+
+       _unlock_proc_list();
+}
+
+void pp_disable(void)
+{
+       struct process_t *proc;
+
+       _lock_proc_list();
+
+       list_for_each_entry(proc, &_reg_proc_list, list) {
+               _proc_unreg_no_lock(proc);
+               list_move_tail(&proc->list, &_unreg_proc_list);
+       }
+
+       _unlock_proc_list();
+}
+
+int pp_enable(void)
+{
+       struct process_t *proc;
+       int ret;
+
+       if (!_is_pthread_data_available())
+               return -EINVAL;
+
+       _lock_proc_list();
+
+       list_for_each_entry(proc, &_unreg_proc_list, list) {
+               ret = _proc_reg_no_lock(proc);
+               if (ret)
+                       goto enable_pp_fail;
+               else
+                       list_move_tail(&proc->list, &_reg_proc_list);
+       }
+
+       _unlock_proc_list();
+
+       return 0;
+
+enable_pp_fail:
+       _unlock_proc_list();
+
+       pr_warn(PRELOAD_PREFIX "Error register probes, disabling...\n");
+       pp_disable();
+
+       return ret;
+}
+
+int pp_set_pthread_path(const char *path)
+{
+       struct dentry *dentry;
+
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL)
+               return -EINVAL;
+
+       if (_pthread_init.dentry != NULL)
+               swap_put_dentry(_pthread_init.dentry);
+
+       _pthread_init.dentry = dentry;
+
+       return 0;
+}
+
+int pp_set_init_offset(unsigned long off)
+{
+       _pthread_init.off = off;
+
+       return 0;
+}
diff --git a/modules/preload/preload_process.h b/modules/preload/preload_process.h
new file mode 100644 (file)
index 0000000..5799f9c
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PRELOAD_PROCESS_H__
+#define __PRELOAD_PROCESS_H__
+
+int pp_add_by_path(const char *path);
+int pp_add_by_pid(pid_t pid);
+int pp_add_by_id(const char *id);
+
+int pp_del_by_path(const char *path);
+int pp_del_by_pid(pid_t pid);
+int pp_del_by_id(const char *id);
+void pp_del_all(void);
+
+int pp_enable(void);
+void pp_disable(void);
+
+int pp_set_pthread_path(const char *path);
+int pp_set_init_offset(unsigned long off);
+
+#endif /* __PRELOAD_PROCESS_H__ */
diff --git a/modules/preload/preload_threads.c b/modules/preload/preload_threads.c
new file mode 100644 (file)
index 0000000..1d49d6b
--- /dev/null
@@ -0,0 +1,322 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/list.h>
+#include <kprobe/swap_ktd.h>
+#include "preload.h"
+#include "preload_threads.h"
+
+struct preload_td {
+       struct list_head slots;
+       unsigned long flags;
+};
+
+struct thread_slot {
+       struct list_head list;
+       struct list_head disabled_addrs;
+
+       unsigned long caller;
+       unsigned long orig;
+       unsigned char call_type;
+       bool drop;   /* TODO Workaround, remove when will be possible to install
+                     * several us probes at the same addr. */
+};
+
+struct disabled_addr {
+       struct list_head list;
+       unsigned long addr;
+};
+
+static void preload_ktd_init(struct task_struct *task, void *data)
+{
+       struct preload_td *td = (struct preload_td *)data;
+
+       INIT_LIST_HEAD(&td->slots);
+       td->flags = 0;
+}
+
+static void preload_ktd_exit(struct task_struct *task, void *data)
+{
+       /* TODO: to be implement */
+}
+
+static struct ktask_data preload_ktd = {
+       .init = preload_ktd_init,
+       .exit = preload_ktd_exit,
+       .size = sizeof(struct preload_td),
+};
+
+
+static inline struct preload_td *get_preload_td(struct task_struct *task)
+{
+       return (struct preload_td *)swap_ktd(&preload_ktd, task);
+}
+
+unsigned long pt_get_flags(struct task_struct *task)
+{
+       return get_preload_td(task)->flags;
+}
+
+void pt_set_flags(struct task_struct *task, unsigned long flags)
+{
+       get_preload_td(task)->flags = flags;
+}
+
+
+static inline bool __is_addr_found(struct disabled_addr *da,
+                                  unsigned long addr)
+{
+       if (da->addr == addr)
+               return true;
+
+       return false;
+}
+
+static inline void __remove_from_disable_list(struct disabled_addr *da)
+{
+       list_del(&da->list);
+       kfree(da);
+}
+
+static inline void __remove_whole_disable_list(struct thread_slot *slot)
+{
+       struct disabled_addr *da, *n;
+
+       list_for_each_entry_safe(da, n, &slot->disabled_addrs, list)
+               __remove_from_disable_list(da);
+}
+
+static inline void __init_slot(struct thread_slot *slot)
+{
+       slot->caller = 0;
+       slot->orig = 0;
+       slot->call_type = 0;
+       slot->drop = false;
+       INIT_LIST_HEAD(&slot->disabled_addrs);
+}
+
+static inline void __reinit_slot(struct thread_slot *slot)
+{
+       __remove_whole_disable_list(slot);
+       __init_slot(slot);
+}
+
+static inline void __set_slot(struct thread_slot *slot,
+                             struct task_struct *task, unsigned long caller,
+                             unsigned long orig, unsigned char call_type,
+                             bool drop)
+{
+       slot->caller = caller;
+       slot->orig = orig;
+       slot->call_type = call_type;
+       slot->drop = drop;
+}
+
+static inline int __add_to_disable_list(struct thread_slot *slot,
+                                       unsigned long disable_addr)
+{
+       struct disabled_addr *da = kmalloc(sizeof(*da), GFP_ATOMIC);
+
+       if (da == NULL)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&da->list);
+       da->addr = disable_addr;
+       list_add_tail(&da->list, &slot->disabled_addrs);
+
+       return 0;
+}
+
+static inline struct disabled_addr *__find_disabled_addr(struct thread_slot *slot,
+                                                        unsigned long addr)
+{
+       struct disabled_addr *da;
+
+       list_for_each_entry(da, &slot->disabled_addrs, list)
+               if (__is_addr_found(da, addr))
+                       return da;
+
+       return NULL;
+}
+
+/* Adds a new slot */
+static inline struct thread_slot *__grow_slot(void)
+{
+       struct thread_slot *tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
+
+       if (tmp == NULL)
+               return NULL;
+
+       INIT_LIST_HEAD(&tmp->list);
+       __init_slot(tmp);
+
+       return tmp;
+}
+
+/* Free slot */
+static void __clean_slot(struct thread_slot *slot)
+{
+       list_del(&slot->list);
+       kfree(slot);
+}
+
+/* There is no list_last_entry in Linux 3.10 */
+#ifndef list_last_entry
+#define list_last_entry(ptr, type, member) \
+       list_entry((ptr)->prev, type, member)
+#endif /* list_last_entry */
+
+static inline struct thread_slot *__get_task_slot(struct task_struct *task)
+{
+       struct preload_td *td = get_preload_td(task);
+
+       return list_empty(&td->slots) ? NULL :
+               list_last_entry(&td->slots, struct thread_slot, list);
+}
+
+
+
+
+int pt_set_data(struct task_struct *task, struct pt_data_t *data)
+{
+       struct preload_td *td = get_preload_td(task);
+       struct thread_slot *slot;
+       unsigned long caller, disable_addr, orig;
+       unsigned char call_type;
+       bool drop;
+       int ret = 0;
+
+       caller = data->caller;
+       disable_addr = data->disable_addr;
+       orig = data->orig;
+       call_type = data->call_type;
+       drop = data->drop;
+
+       slot = __grow_slot();
+       if (slot == NULL) {
+               ret = -ENOMEM;
+               goto set_data_done;
+       }
+
+       if ((disable_addr != 0) &&
+           (__add_to_disable_list(slot, disable_addr) != 0)) {
+               printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc memory!\n");
+               ret = -ENOMEM;
+               goto set_data_done;
+       }
+
+       __set_slot(slot, task, caller, orig, call_type, drop);
+       list_add_tail(&slot->list, &td->slots);
+
+set_data_done:
+       return ret;
+}
+
+int pt_get_caller(struct task_struct *task, unsigned long *caller)
+{
+       struct thread_slot *slot;
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+               *caller = slot->caller;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+int pt_get_orig(struct task_struct *task, unsigned long *orig)
+{
+       struct thread_slot *slot;
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+               *orig = slot->caller;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+int pt_get_call_type(struct task_struct *task,
+                                 unsigned char *call_type)
+{
+       struct thread_slot *slot;
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+               *call_type = slot->call_type;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+int pt_get_drop(struct task_struct *task)
+{
+       struct thread_slot *slot;
+
+       slot = __get_task_slot(task);
+       if (slot != NULL)
+               return (int)slot->drop;
+
+       return -EINVAL;
+}
+
+bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr)
+{
+       struct thread_slot *slot;
+       bool ret = false;
+
+       slot = __get_task_slot(task);
+       if (slot != NULL)
+               ret = __find_disabled_addr(slot, addr) == NULL ? false : true;
+
+       return ret;
+}
+
+void pt_enable_probe(struct task_struct *task, unsigned long addr)
+{
+       struct thread_slot *slot;
+       struct disabled_addr *da;
+
+       slot = __get_task_slot(task);
+       if (slot == NULL) {
+               printk(KERN_ERR PRELOAD_PREFIX "Error! Slot not found!\n");
+               goto enable_probe_failed;
+       }
+
+       da = __find_disabled_addr(slot, addr);
+       if (da != NULL)
+               __remove_from_disable_list(da);
+
+enable_probe_failed:
+       return; /* make gcc happy: cannot place label right before '}' */
+}
+
+int pt_put_data(struct task_struct *task)
+{
+       struct thread_slot *slot;
+       int ret = 0;
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+               __reinit_slot(slot);
+               __clean_slot(slot); /* remove from list */
+       }
+
+       return ret;
+}
+
+int pt_init(void)
+{
+       return swap_ktd_reg(&preload_ktd);
+}
+
+void pt_exit(void)
+{
+       swap_ktd_unreg(&preload_ktd);
+}
diff --git a/modules/preload/preload_threads.h b/modules/preload/preload_threads.h
new file mode 100644 (file)
index 0000000..43844c7
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __PRELOAD_HANDLERS_THREADS_H__
+#define __PRELOAD_HANLDERS_THREADS_H__
+
+struct task_struct;
+
+struct pt_data_t {
+       unsigned long caller;
+       unsigned long disable_addr;
+       unsigned long orig;
+       unsigned char call_type;
+       bool drop;
+};
+
+unsigned long pt_get_flags(struct task_struct *task);
+void pt_set_flags(struct task_struct *task, unsigned long flags);
+
+int pt_set_data(struct task_struct *task, struct pt_data_t *data);
+
+int pt_get_caller(struct task_struct *task, unsigned long *caller);
+int pt_get_orig(struct task_struct *task, unsigned long *orig);
+int pt_get_call_type(struct task_struct *task, unsigned char *call_type);
+int pt_get_drop(struct task_struct *task);
+bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr);
+
+void pt_enable_probe(struct task_struct *task, unsigned long addr);
+int pt_put_data(struct task_struct *task);
+int pt_init(void);
+void pt_exit(void);
+
+#endif /* __PRELOAD_HANDLERS_THREADS_H__ */
diff --git a/modules/retprobe/Kbuild b/modules/retprobe/Kbuild
new file mode 100644 (file)
index 0000000..c61030c
--- /dev/null
@@ -0,0 +1,6 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_retprobe.o
+swap_retprobe-y := \
+    retprobe.o \
+    rp_msg.o
diff --git a/modules/retprobe/retprobe.c b/modules/retprobe/retprobe.c
new file mode 100644 (file)
index 0000000..db5b75a
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/retprobe/retprobe.c
+ *
+ * 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, 2014
+ *
+ * 2014         Alexander Aksenov: Probes interface implement
+ *
+ */
+
+#include "retprobe.h"
+#include <us_manager/us_manager.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/probes/register_probes.h>
+#include <uprobe/swap_uprobes.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "rp_msg.h"
+
+
+static int retprobe_copy(struct probe_info *dest,
+                        const struct probe_info *source)
+{
+       size_t len;
+
+       memcpy(dest, source, sizeof(*source));
+
+       len = strlen(source->rp_i.args) + 1;
+       dest->rp_i.args = kmalloc(len, GFP_ATOMIC);
+       if (dest->rp_i.args == NULL)
+               return -ENOMEM;
+       memcpy(dest->rp_i.args, source->rp_i.args, len);
+
+       return 0;
+}
+
+
+static void retprobe_cleanup(struct probe_info *probe_i)
+{
+       kfree(probe_i->rp_i.args);
+}
+
+
+
+static struct uprobe *retprobe_get_uprobe(struct sspt_ip *ip)
+{
+       return &ip->retprobe.up;
+}
+
+static int retprobe_register_probe(struct sspt_ip *ip)
+{
+       return swap_register_uretprobe(&ip->retprobe);
+}
+
+static void retprobe_unregister_probe(struct sspt_ip *ip, int disarm)
+{
+       __swap_unregister_uretprobe(&ip->retprobe, disarm);
+}
+
+
+static int retprobe_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct uretprobe *rp = ri->rp;
+
+       if (rp && get_quiet() == QT_OFF) {
+               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
+               const char *fmt = ip->desc->info.rp_i.args;
+               const unsigned long func_addr = (unsigned long)ip->orig_addr;
+
+               rp_msg_entry(regs, func_addr, fmt);
+       }
+
+       return 0;
+}
+
+static int retprobe_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct uretprobe *rp = ri->rp;
+
+       if (rp && get_quiet() == QT_OFF) {
+               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
+               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->desc->info.rp_i.ret_type;
+
+               rp_msg_exit(regs, func_addr, ret_type, ret_addr);
+       }
+
+       return 0;
+}
+
+static void retprobe_init(struct sspt_ip *ip)
+{
+       ip->retprobe.entry_handler = retprobe_entry_handler;
+       ip->retprobe.handler = retprobe_ret_handler;
+       ip->retprobe.maxactive = 0;
+}
+
+static void retprobe_uninit(struct sspt_ip *ip)
+{
+       retprobe_cleanup(&ip->desc->info);
+}
+
+
+static struct probe_iface retprobe_iface = {
+       .init = retprobe_init,
+       .uninit = retprobe_uninit,
+       .reg = retprobe_register_probe,
+       .unreg = retprobe_unregister_probe,
+       .get_uprobe = retprobe_get_uprobe,
+       .copy = retprobe_copy,
+       .cleanup = retprobe_cleanup
+};
+
+static int __init retprobe_module_init(void)
+{
+       return swap_register_probe_type(SWAP_RETPROBE, &retprobe_iface);
+}
+
+static void __exit retprobe_module_exit(void)
+{
+       swap_unregister_probe_type(SWAP_RETPROBE);
+}
+
+module_init(retprobe_module_init);
+module_exit(retprobe_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP retprobe");
+MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/modules/retprobe/retprobe.h b/modules/retprobe/retprobe.h
new file mode 100644 (file)
index 0000000..7a82781
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/uretprobe.h
+ *
+ * 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, 2014
+ *
+ * 2014         Alexander Aksenov: Probes interface implement
+ *
+ */
+
+#ifndef __URETPROBE_H__
+#define __URETPROBE_H__
+
+/* Common retprobe info */
+struct retprobe_info {
+       char *args;
+       char ret_type;
+};
+
+#endif /* __URETPROBE_H__ */
diff --git a/modules/retprobe/rp_msg.c b/modules/retprobe/rp_msg.c
new file mode 100644 (file)
index 0000000..3fb4426
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <writer/swap_msg.h>
+#include <writer/kernel_operations.h>
+#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 = raw_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);
+}
+EXPORT_SYMBOL_GPL(rp_msg_entry);
+
+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 = raw_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);
+}
+EXPORT_SYMBOL_GPL(rp_msg_exit);
diff --git a/modules/retprobe/rp_msg.h b/modules/retprobe/rp_msg.h
new file mode 100644 (file)
index 0000000..a2e3b28
--- /dev/null
@@ -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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#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/modules/sampler/Kbuild b/modules/sampler/Kbuild
new file mode 100644 (file)
index 0000000..f948655
--- /dev/null
@@ -0,0 +1,11 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../writer/Module.symvers
+
+obj-m := swap_sampler.o
+swap_sampler-y := swap_sampler_module.o
+
+ifdef CONFIG_HIGH_RES_TIMERS
+    swap_sampler-y += sampler_hrtimer.o
+else
+    swap_sampler-y += sampler_timer.o
+endif
diff --git a/modules/sampler/kernel_operations.h b/modules/sampler/kernel_operations.h
new file mode 100644 (file)
index 0000000..04d8fa9
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * @file sampler/kernel_operations.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Parser definitions.
+ */
+
+#ifndef __KERNEL_OPERATIONS_H__
+#define __KERNEL_OPERATIONS_H__
+
+#include <linux/kernel.h>
+
+/** Prints debug message.*/
+#define print_debug(msg, args...) \
+       printk(KERN_DEBUG "SWAP_SAMPLER DEBUG : " msg, ##args)
+/** Prints info message.*/
+#define print_msg(msg, args...)   \
+       printk(KERN_INFO "SWAP_SAMPLER : " msg, ##args)
+/** Prints warning message.*/
+#define print_warn(msg, args...)  \
+       printk(KERN_WARNING "SWAP_SAMPLER WARNING : " msg, ##args)
+/** Prints error message.*/
+#define print_err(msg, args...)   \
+       printk(KERN_ERR "SWAP_SAMPLER ERROR : " msg, ##args)
+/** Prints critical error message.*/
+#define print_crit(msg, args...)  \
+       printk(KERN_CRIT "SWAP_SAMPLER CRITICAL : " msg, ##args)
+
+#endif /* __KERNEL_OPERATIONS_H__ */
diff --git a/modules/sampler/sampler_hrtimer.c b/modules/sampler/sampler_hrtimer.c
new file mode 100644 (file)
index 0000000..b445212
--- /dev/null
@@ -0,0 +1,123 @@
+/**
+ * sampler/sampler_hrtimer.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Sampler for high resolution timers.
+ */
+
+
+
+#include <linux/types.h>
+#include <linux/version.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include "sampler_timers.h"
+
+
+static u64 sampler_timer_quantum;
+static DEFINE_PER_CPU(struct hrtimer, swap_hrtimer);
+static int swap_hrtimer_running;
+
+/**
+ * @brief Restarts sampling.
+ *
+ * @param timer Pointer to hrtimer struct.
+ * @return hrtimer_restart flag.
+ */
+restart_ret sampler_timers_restart(swap_timer *timer)
+{
+       restart_ret ret;
+
+       hrtimer_forward_now(timer, ns_to_ktime(sampler_timer_quantum));
+       ret = HRTIMER_RESTART;
+
+       return ret;
+}
+
+/**
+ * @brief Sets running flag true.
+ *
+ * @return Void.
+ */
+void sampler_timers_set_run(void)
+{
+       swap_hrtimer_running = 1;
+}
+
+/**
+ * @brief Sets running flag false.
+ *
+ * @return Void.
+ */
+void sampler_timers_set_stop(void)
+{
+       swap_hrtimer_running = 0;
+}
+
+/**
+ * @brief Starts timer sampling.
+ *
+ * @param restart_func Pointer to restart function.
+ * @return Void.
+ */
+void sampler_timers_start(void *restart_func)
+{
+       struct hrtimer *hrtimer = &__get_cpu_var(swap_hrtimer);
+
+       if (!swap_hrtimer_running)
+               return;
+
+       hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hrtimer->function = restart_func;
+       hrtimer_start(hrtimer, ns_to_ktime(sampler_timer_quantum),
+                 HRTIMER_MODE_REL_PINNED);
+}
+
+/**
+ * @brief Stops timer sampling.
+ *
+ * @param cpu Online CPUs.
+ * @return Void.
+ */
+void sampler_timers_stop(int cpu)
+{
+       struct hrtimer *hrtimer = &per_cpu(swap_hrtimer, cpu);
+
+       if (!swap_hrtimer_running)
+               return;
+
+       hrtimer_cancel(hrtimer);
+}
+
+/**
+ * @brief Sets timer quantum.
+ *
+ * @param timer_quantum Timer quantum.
+ * @return Void.
+ */
+void sampler_timers_set_quantum(unsigned int timer_quantum)
+{
+       u64 tmp = (u64)timer_quantum;
+       sampler_timer_quantum = tmp * 1000 * 1000;
+}
diff --git a/modules/sampler/sampler_timer.c b/modules/sampler/sampler_timer.c
new file mode 100644 (file)
index 0000000..6a86ac8
--- /dev/null
@@ -0,0 +1,121 @@
+/**
+ * sampler/sampler_timer.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Sampler based on common timers.
+ */
+
+
+
+#include "sampler_timers.h"
+
+
+
+static unsigned long sampler_timer_quantum;
+static DEFINE_PER_CPU(struct timer_list, swap_timer);
+static int swap_timer_running;
+
+/**
+ * @brief Restarts sampling.
+ *
+ * @param timer Pointer to timer_list struct.
+ * @return 0.
+ */
+restart_ret sampler_timers_restart(swap_timer *timer)
+{
+       restart_ret ret;
+
+       mod_timer_pinned((struct timer_list *)timer,
+                    jiffies + sampler_timer_quantum);
+       ret = 0;
+
+       return ret;
+}
+
+/**
+ * @brief Sets running flag true.
+ *
+ * @return Void.
+ */
+void sampler_timers_set_run(void)
+{
+       swap_timer_running = 1;
+}
+
+/**
+ * @brief Sets running flag false.
+ *
+ * @return Void.
+ */
+void sampler_timers_set_stop(void)
+{
+       swap_timer_running = 0;
+}
+
+/**
+ * @brief Starts timer sampling.
+ *
+ * @param restart_func Pointer to restart function.
+ * @return Void.
+ */
+void sampler_timers_start(void *restart_func)
+{
+       struct timer_list *timer = &__get_cpu_var(swap_timer);
+
+       if (!swap_timer_running)
+               return;
+
+       init_timer(timer);
+       timer->data = (unsigned long)timer;
+       timer->function = restart_func;
+
+       mod_timer_pinned(timer, jiffies + sampler_timer_quantum);
+}
+
+/**
+ * @brief Stops timer sampling.
+ *
+ * @param cpu Online CPUs.
+ * @return Void.
+ */
+void sampler_timers_stop(int cpu)
+{
+       struct timer_list *timer = &per_cpu(swap_timer, cpu);
+
+       if (!swap_timer_running)
+               return;
+       del_timer_sync(timer);
+}
+
+/**
+ * @brief Sets timer quantum.
+ *
+ * @param timer_quantum Timer quantum.
+ * @return Void.
+ */
+void sampler_timers_set_quantum(unsigned int timer_quantum)
+{
+       sampler_timer_quantum = timer_quantum;
+}
diff --git a/modules/sampler/sampler_timers.h b/modules/sampler/sampler_timers.h
new file mode 100644 (file)
index 0000000..e9b83d2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  SWAP sampler
+ *  modules/sampler/sampler_timers.h
+ *
+ * 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, 2013
+ *
+ * 2013         Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
+ *
+ */
+
+
+
+#ifndef __SAMPLER_TIMERS_H__
+#define __SAMPLER_TIMERS_H__
+
+
+/* ===================== INCLUDE ==================== */
+
+#if defined(CONFIG_HIGH_RES_TIMERS)
+
+#include <linux/hrtimer.h>
+
+#else /* CONFIG_HIGH_RES_TIMERS */
+
+#include <linux/timer.h>
+
+#endif /* CONFIG_HIGH_RES_TIMERS */
+
+/* ==================== TYPE DEFS =================== */
+
+#if defined(CONFIG_HIGH_RES_TIMERS)
+
+typedef struct hrtimer   swap_timer;
+typedef enum hrtimer_restart   restart_ret;
+
+#else /* CONFIG_HIGH_RES_TIMERS */
+
+typedef struct timer_list   swap_timer;
+typedef int   restart_ret;
+
+#endif /* CONFIG_HIGH_RES_TIMERS */
+
+
+/* ====================== FUNCS ===================== */
+
+restart_ret sampler_timers_restart(swap_timer *timer);
+void sampler_timers_stop(int cpu);
+void sampler_timers_start(void *unused);
+void sampler_timers_set_quantum(unsigned int timer_quantum);
+void sampler_timers_set_run(void);
+void sampler_timers_set_stop(void);
+
+#endif /* __SAMPLER_TIMERS_H__ */
diff --git a/modules/sampler/swap_sampler_errors.h b/modules/sampler/swap_sampler_errors.h
new file mode 100644 (file)
index 0000000..d673b4d
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * @file sampler/swap_sampler_errors.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Sampler error codes.
+ */
+
+
+/**
+ * @enum _swap_sampler_errors
+ * @brief Sampler errors.
+ */
+enum _swap_sampler_errors {
+       E_SS_SUCCESS = 0,           /**< Success. */
+       E_SS_WRONG_QUANTUM = 1      /**< Wrong timer quantum set. */
+};
diff --git a/modules/sampler/swap_sampler_module.c b/modules/sampler/swap_sampler_module.c
new file mode 100644 (file)
index 0000000..94cb506
--- /dev/null
@@ -0,0 +1,207 @@
+/**
+ * sampler/swap_sampler_module.c
+ * @author Andreev S.V.: SWAP Sampler implementation
+ * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
+ *
+ * @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
+ *
+ * Timer-based sampling module.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+
+#include "swap_sampler_module.h"
+#include "swap_sampler_errors.h"
+#include "kernel_operations.h"
+#include "sampler_timers.h"
+
+
+static BLOCKING_NOTIFIER_HEAD(swap_sampler_notifier_list);
+static swap_sample_cb_t sampler_cb;
+
+static restart_ret swap_timer_restart(swap_timer *timer)
+{
+       sampler_cb(task_pt_regs(current));
+
+       return sampler_timers_restart(timer);
+}
+
+static int swap_timer_start(void)
+{
+       get_online_cpus();
+       sampler_timers_set_run();
+
+       on_each_cpu(sampler_timers_start, swap_timer_restart, 1);
+       put_online_cpus();
+
+       return E_SS_SUCCESS;
+}
+
+static void swap_timer_stop(void)
+{
+       int cpu;
+
+       get_online_cpus();
+
+       for_each_online_cpu(cpu)
+               sampler_timers_stop(cpu);
+       sampler_timers_set_stop();
+       put_online_cpus();
+}
+
+static int swap_cpu_notify(struct notifier_block *self,
+                                   unsigned long action, void *hcpu)
+{
+       long cpu = (long) hcpu;
+
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               smp_call_function_single(cpu, sampler_timers_start,
+                                swap_timer_restart, 1);
+               break;
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               sampler_timers_stop(cpu);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata swap_cpu_notifier = {
+       .notifier_call = swap_cpu_notify,
+};
+
+static int do_swap_sampler_start(unsigned int timer_quantum)
+{
+       if (timer_quantum <= 0)
+               return -EINVAL;
+
+       sampler_timers_set_quantum(timer_quantum);
+       swap_timer_start();
+
+       return 0;
+}
+
+static void do_swap_sampler_stop(void)
+{
+       swap_timer_stop();
+}
+
+static DEFINE_MUTEX(mutex_run);
+static int sampler_run;
+
+
+/**
+ * @brief Starts sampling with specified timer quantum.
+ *
+ * @param timer_quantum Timer quantum for sampling.
+ * @return 0 on success, error code on error.
+ */
+int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb)
+{
+       int ret = -EINVAL;
+
+       mutex_lock(&mutex_run);
+       if (sampler_run) {
+               printk(KERN_INFO "sampler profiling is already run!\n");
+               goto unlock;
+       }
+
+       sampler_cb = cb;
+
+       ret = do_swap_sampler_start(timer_quantum);
+       if (ret == 0)
+               sampler_run = 1;
+
+unlock:
+       mutex_unlock(&mutex_run);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_sampler_start);
+
+
+/**
+ * @brief Stops sampling.
+ *
+ * @return 0 on success, error code on error.
+ */
+int swap_sampler_stop(void)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_run);
+       if (sampler_run == 0) {
+               printk(KERN_INFO "energy profiling is not running!\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       do_swap_sampler_stop();
+
+       sampler_run = 0;
+unlock:
+       mutex_unlock(&mutex_run);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_sampler_stop);
+
+static int __init sampler_init(void)
+{
+       int retval;
+
+       retval = register_hotcpu_notifier(&swap_cpu_notifier);
+       if (retval) {
+               print_err("Error of register_hotcpu_notifier()\n");
+               return retval;
+       }
+
+       print_msg("Sample ininitialization success\n");
+
+       return E_SS_SUCCESS;
+}
+
+static void __exit sampler_exit(void)
+{
+       if (sampler_run)
+               do_swap_sampler_stop();
+
+       unregister_hotcpu_notifier(&swap_cpu_notifier);
+
+       print_msg("Sampler uninitialized\n");
+}
+
+module_init(sampler_init);
+module_exit(sampler_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP sampling module");
+MODULE_AUTHOR("Andreev S.V., Aksenov A.S.");
diff --git a/modules/sampler/swap_sampler_module.h b/modules/sampler/swap_sampler_module.h
new file mode 100644 (file)
index 0000000..7c0ef7d
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * @file sampler/swap_sampler_module.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Sampling module interface declaration.
+ */
+
+
+/* SWAP Sampler interface */
+
+#ifndef __SWAP_SAMPLER_MODULE_H__
+#define __SWAP_SAMPLER_MODULE_H__
+
+
+typedef void (*swap_sample_cb_t)(struct pt_regs *);
+
+
+/* Starts the SWAP Sampler */
+int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb);
+
+/* Stops the SWAP Sampler */
+int swap_sampler_stop(void);
+
+#endif /* __SWAP_SAMPLER_MODULE_H__ */
diff --git a/modules/task_ctx/Kbuild b/modules/task_ctx/Kbuild
new file mode 100644 (file)
index 0000000..b90f7a6
--- /dev/null
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers
+
+obj-m := swap_taskctx.o
+swap_taskctx-y := task_ctx.o
diff --git a/modules/task_ctx/task_ctx.c b/modules/task_ctx/task_ctx.c
new file mode 100644 (file)
index 0000000..cfd54f1
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kconfig.h>
+#include <linux/completion.h>
+#include <ksyms/ksyms.h>
+#include <kprobe/swap_ktd.h>
+#include <master/swap_initializer.h>
+#include "task_ctx.h"
+
+
+enum { WAIT_TIMEOUT = 1500 };  /* max waiting time the signal delivery */
+
+struct call_task {
+       taskctx_t func;
+       void *data;
+
+       bool is_running;
+       struct completion comp0;
+       struct completion comp1;
+};
+
+
+static void (*swap_signal_wake_up_state)(struct task_struct *t,
+                                        unsigned int state);
+
+static struct sighand_struct *swap_lock_task_sighand(struct task_struct *tsk,
+                                                    unsigned long *flags)
+{
+       struct sighand_struct *sighand;
+
+       for (;;) {
+               local_irq_save(*flags);
+               rcu_read_lock();
+
+               sighand = rcu_dereference(tsk->sighand);
+               if (unlikely(sighand == NULL)) {
+                       rcu_read_unlock();
+                       local_irq_restore(*flags);
+                       break;
+               }
+
+               spin_lock(&sighand->siglock);
+               if (likely(sighand == tsk->sighand)) {
+                       rcu_read_unlock();
+                       break;
+               }
+               spin_unlock(&sighand->siglock);
+
+               rcu_read_unlock();
+               local_irq_restore(*flags);
+       }
+
+       return sighand;
+}
+
+static inline void swap_unlock_task_sighand(struct task_struct *tsk,
+                                           unsigned long *flags)
+{
+        spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
+}
+
+static int fake_signal_wake_up(struct task_struct *p)
+{
+       unsigned long flags;
+
+       if (swap_lock_task_sighand(p, &flags) == NULL)
+               return -ESRCH;
+
+       swap_signal_wake_up_state(p, 0);
+       swap_unlock_task_sighand(p, &flags);
+
+       return 0;
+}
+
+
+static void ktd_init(struct task_struct *task, void *data)
+{
+       struct call_task **call = (struct call_task **)data;
+
+       *call = NULL;
+}
+
+static void ktd_exit(struct task_struct *task, void *data)
+{
+       struct call_task **call = (struct call_task **)data;
+
+       WARN(*call, "call is not NULL");
+}
+
+static struct ktask_data ktd = {
+       .init = ktd_init,
+       .exit = ktd_exit,
+       .size = sizeof(struct call_task *),
+};
+
+static void call_set(struct task_struct *task, struct call_task *call)
+{
+       *(struct call_task **)swap_ktd(&ktd, task) = call;
+}
+
+static struct call_task *call_get(struct task_struct *task)
+{
+       return *(struct call_task **)swap_ktd(&ktd, task);
+}
+
+
+int taskctx_run(struct task_struct *task, taskctx_t func, void *data)
+{
+       if (IS_ENABLED(CONFIG_SWAP_KERNEL_IMMUTABLE))
+               return -ENOSYS;
+
+       if (task == current) {
+               func(data);
+       } else {
+               int ret;
+               unsigned long jiff;
+               struct call_task call = {
+                       .func = func,
+                       .data = data,
+                       .comp0 = COMPLETION_INITIALIZER(call.comp0),
+                       .comp1 = COMPLETION_INITIALIZER(call.comp1),
+                       .is_running = false,
+               };
+
+               /* check task possibility to receive signals */
+               if (task->flags & (PF_KTHREAD | PF_EXITING | PF_SIGNALED))
+                       return -EINVAL;
+
+               /* set call by task */
+               call_set(task, &call);
+
+               ret = fake_signal_wake_up(task);
+               if (ret) {
+                       /* reset call by task */
+                       call_set(task, NULL);
+                       pr_err("cannot send signal to task[%u %u %s] flags=%08x state=%08lx\n",
+                              task->tgid, task->pid, task->comm,
+                              task->flags, task->state);
+                       return ret;
+               }
+
+               jiff = msecs_to_jiffies(WAIT_TIMEOUT);
+               wait_for_completion_timeout(&call.comp0, jiff);
+
+               /* reset call by task */
+               call_set(task, NULL);
+
+               /* wait the return from sig_pre_handler() */
+               synchronize_sched();
+
+               if (call.is_running)
+                       wait_for_completion(&call.comp1);
+
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(taskctx_run);
+
+
+static void sig_handler(void)
+{
+       struct call_task *call = call_get(current);
+
+       if (call) {
+               call_set(current, NULL);
+               call->is_running = true;
+
+               complete(&call->comp0);
+               call->func(call->data);
+               complete(&call->comp1);
+       }
+}
+
+
+#ifdef CONFIG_SWAP_HOOK_SIGNAL
+# include <swap/hook_signal.h>
+void hook_handler(struct ksignal *ksig)
+{
+       sig_handler();
+}
+
+struct hook_signal hook_signal = {
+       .owner = THIS_MODULE,
+       .hook = hook_handler,
+};
+
+static int signal_reg(void)
+{
+       int ret = hook_signal_reg(&hook_signal);
+       if (ret)
+               pr_err("Cannot register hook_signal, ret=%d\n", ret);
+
+       return ret;
+}
+
+static void signal_unreg(void)
+{
+       hook_signal_unreg(&hook_signal);
+}
+
+static int signal_once(void)
+{
+       return 0;
+}
+
+#else /* !CONFIG_SWAP_HOOK_SIGNAL */
+# include <kprobe/swap_kprobes.h>
+
+static int sig_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       sig_handler();
+
+       return 0;
+}
+
+static struct kprobe sig_kprobe = {
+       .pre_handler = sig_pre_handler,
+};
+
+static int signal_reg(void)
+{
+       int ret = swap_register_kprobe(&sig_kprobe);
+       if (ret)
+               pr_err("register sig_kprobe ret=%d\n", ret);
+
+       return ret;
+}
+
+static void signal_unreg(void)
+{
+       swap_unregister_kprobe(&sig_kprobe);
+}
+
+static int signal_once(void)
+{
+       const char *sym;
+
+       sym = "signal_wake_up_state";
+       swap_signal_wake_up_state = (void *)swap_ksyms(sym);
+       if (swap_signal_wake_up_state == NULL)
+               goto not_found;
+
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+       sym = "get_signal";
+# else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) */
+       sym = "get_signal_to_deliver";
+# endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) */
+       sig_kprobe.addr = swap_ksyms(sym);
+       if (sig_kprobe.addr == 0)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       printk("Cannot find address for '%s'!\n", sym);
+       return -ESRCH;
+}
+#endif /* CONFIG_SWAP_HOOK_SIGNAL */
+
+
+static int use_cnt = 0;
+static DEFINE_MUTEX(use_lock);
+
+int taskctx_get(void)
+{
+       int ret = 0;
+
+       mutex_lock(&use_lock);
+       if (use_cnt == 0) {
+               ret = signal_reg();
+               if (ret)
+                       goto unlock;
+       }
+
+       ++use_cnt;
+
+unlock:
+       mutex_unlock(&use_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(taskctx_get);
+
+void taskctx_put(void)
+{
+       mutex_lock(&use_lock);
+       if (use_cnt == 0) {
+               WARN_ON("call put_task_context() without get_task_context");
+               goto unlock;
+       }
+
+       --use_cnt;
+       if (use_cnt == 0)
+               signal_unreg();
+
+unlock:
+       mutex_unlock(&use_lock);
+}
+EXPORT_SYMBOL_GPL(taskctx_put);
+
+
+static int taskctx_once(void)
+{
+       return signal_once();
+}
+
+static int taskctx_init(void)
+{
+       return swap_ktd_reg(&ktd);
+}
+
+static void taskctx_uninit(void)
+{
+       WARN(use_cnt, "use_cnt=%d\n", use_cnt);
+       swap_ktd_unreg(&ktd);
+}
+
+SWAP_LIGHT_INIT_MODULE(taskctx_once, taskctx_init, taskctx_uninit, NULL, NULL);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/task_ctx/task_ctx.h b/modules/task_ctx/task_ctx.h
new file mode 100644 (file)
index 0000000..a4c84b6
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _TASK_CTX_H
+#define _TASK_CTX_H
+
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+struct task_struct;
+
+typedef void (*taskctx_t)(void *info);
+
+
+int taskctx_run(struct task_struct *task, taskctx_t func, void *data);
+
+int taskctx_get(void);
+void taskctx_put(void);
+
+
+#endif /* _TASK_CTX_H */
diff --git a/modules/tests/Kbuild b/modules/tests/Kbuild
new file mode 100644 (file)
index 0000000..9817995
--- /dev/null
@@ -0,0 +1,3 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := kprobe_tests/
diff --git a/modules/tests/kprobe_tests/Kbuild b/modules/tests/kprobe_tests/Kbuild
new file mode 100644 (file)
index 0000000..5718978
--- /dev/null
@@ -0,0 +1,7 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_kp_tests.o
+swap_kp_tests-y := \
+       kp_module.o \
+       kp_tests.o \
+       krp_tests.o \
diff --git a/modules/tests/kprobe_tests/kp_module.c b/modules/tests/kprobe_tests/kp_module.c
new file mode 100644 (file)
index 0000000..a0e1c80
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/kallsyms.h>
+#include "kp_module.h"
+
+
+static asmlinkage long (*olog_sys_write)(unsigned int, const char __user *, size_t);
+
+static long write_to_stdout(const char *buf, size_t len)
+{
+       long ret;
+
+       mm_segment_t fs = get_fs();
+       set_fs(get_ds());
+       ret = olog_sys_write(1, buf, len);
+       set_fs(fs);
+
+       return ret;
+}
+
+static int olog_init(void)
+{
+       olog_sys_write = (void *)kallsyms_lookup_name("sys_write");
+       if (olog_sys_write == NULL) {
+               pr_err("ERR: not found 'sys_write' symbol\n");
+               return -ESRCH;
+       }
+
+       return 0;
+}
+
+void olog(const char *fmt, ...)
+{
+       char buf[256];
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       printk("%s", buf);
+       write_to_stdout(buf, strlen(buf));
+}
+
+
+
+
+static void print_mod_info(void)
+{
+       struct module *mod = THIS_MODULE;
+
+       printk("### MOD_INFO:\n");
+       printk("    core: %p..%p\n", mod->module_init, mod->module_init + mod->init_text_size);
+       printk("    init: %p..%p\n", mod->module_core, mod->module_core + mod->core_text_size);
+       printk("\n");
+}
+
+
+/* TODO: move declare to header */
+int kp_tests_run(void);
+int krp_tests_run(void);
+
+static int __init tests_init(void)
+{
+       int ret;
+
+       ret = olog_init();
+       if (ret)
+               return ret;
+
+       print_mod_info();
+
+       olog("### Begin tests ###\n");
+       kp_tests_run();
+       krp_tests_run();
+       olog("### End tests ###\n");
+
+       return -1;
+}
+
+static void __exit tests_exit(void)
+{
+}
+
+module_init(tests_init);
+module_exit(tests_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/tests/kprobe_tests/kp_module.h b/modules/tests/kprobe_tests/kp_module.h
new file mode 100644 (file)
index 0000000..e3f0b2b
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _KP_MODULE_H
+#define _KP_MODULE_H
+
+
+void olog(const char *fmt, ...);
+
+
+#endif /* _KP_MODULE_H */
diff --git a/modules/tests/kprobe_tests/kp_tests.c b/modules/tests/kprobe_tests/kp_tests.c
new file mode 100644 (file)
index 0000000..6386f50
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <kprobe/swap_kprobes.h>
+#include "kp_module.h"
+
+
+static struct task_struct *cur_task;
+
+
+static struct kprobe *kp_create(char *name,
+                               int (*pre_h)(struct kprobe *, struct pt_regs *))
+{
+       struct kprobe *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (p) {
+               p->symbol_name = name;
+               p->pre_handler = pre_h;
+       }
+
+       return p;
+}
+
+static void kp_free(struct kprobe *p)
+{
+       memset(p, 0x10, sizeof(*p));
+}
+
+#define kp_reg(ptr, name, handler) \
+       do { \
+               ptr = kp_create(name, handler); \
+               swap_register_kprobe(ptr); \
+       } while (0)
+
+#define kp_unreg(ptr) \
+       do { \
+               swap_unregister_kprobe(ptr); \
+               kp_free(ptr); \
+               ptr = NULL; \
+       } while (0)
+
+
+noinline char *my_kstrdup(const char *s, gfp_t gfp)
+{
+       return kstrdup(s, gfp);
+}
+
+noinline void my_kfree(const void *data)
+{
+       kfree(data);
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *                                 recursion                                  *
+ ******************************************************************************
+ */
+static int kstrdup_cnt;
+static int kfree_cnt;
+
+static struct kprobe *kp_kstrdup;
+static int kstrdup_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       char *str;
+
+       str = my_kstrdup("from_kfree_h", GFP_ATOMIC);
+       my_kfree(str);
+
+       ++kstrdup_cnt;
+
+       return 0;
+}
+
+static struct kprobe *kp_kfree;
+static int kfree_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       ++kfree_cnt;
+
+       return 0;
+}
+
+static void run_test_recursion(void)
+{
+       char *str;
+
+       str = my_kstrdup("test_string_0", GFP_KERNEL);
+       my_kfree(str);
+
+       str = my_kstrdup("test_string_1", GFP_KERNEL);
+       my_kfree(str);
+}
+
+static void do_test_recursion(void)
+{
+       kp_reg(kp_kfree, "my_kfree", kfree_h);
+       kp_reg(kp_kstrdup, "my_kstrdup", kstrdup_h);
+
+       run_test_recursion();
+
+       kp_unreg(kp_kstrdup);
+       kp_unreg(kp_kfree);
+}
+
+
+static void test_recursion(void)
+{
+       olog("Recursion:\n");
+
+       kstrdup_cnt = 0;
+       kfree_cnt = 0;
+
+       do_test_recursion();
+
+       if (kstrdup_cnt == 2 && kfree_cnt == 2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: kstrdup_cnt=%d kfree_cnt=%d\n",
+                      kstrdup_cnt, kfree_cnt);
+       }
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *            recursion and multiple handlers (Aggregate probe)               *
+ ******************************************************************************
+ */
+static int kfree2_cnt;
+
+static struct kprobe *kp_kfree2;
+static int kfree2_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       if (current != cur_task || in_interrupt())
+               return 0;
+
+       ++kfree2_cnt;
+       return 0;
+}
+
+static void pre_test_recursion_and_mh(void)
+{
+       kstrdup_cnt = 0;
+       kfree_cnt = 0;
+       kfree2_cnt = 0;
+}
+
+static void post_test_recursion_and_mh(void)
+{
+       if (kstrdup_cnt == 2 && kfree_cnt == 2 && kfree2_cnt == 2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: kstrdup_cnt=%d kfree_cnt=%d kfree2_cnt=%d\n",
+                    kstrdup_cnt, kfree_cnt, kfree2_cnt);
+       }
+}
+
+static void test_recursion_and_multiple_handlers(void)
+{
+       olog("Recursion and multiple handlers:\n");
+
+       pre_test_recursion_and_mh();
+
+       kp_reg(kp_kfree2, "my_kfree", kfree2_h);
+       do_test_recursion();
+       kp_unreg(kp_kfree2);
+
+       post_test_recursion_and_mh();
+}
+
+static void test_recursion_and_multiple_handlers2(void)
+{
+       olog("Recursion and multiple handlers [II]:\n");
+
+       pre_test_recursion_and_mh();
+
+       kp_reg(kp_kfree, "my_kfree", kfree_h);
+       kp_reg(kp_kstrdup, "my_kstrdup", kstrdup_h);
+       kp_reg(kp_kfree2, "my_kfree", kfree2_h);
+
+       run_test_recursion();
+
+       kp_unreg(kp_kstrdup);
+       kp_unreg(kp_kfree);
+       kp_unreg(kp_kfree2);
+
+       post_test_recursion_and_mh();
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *                        swap_unregister_kprobe(), sync                      *
+ ******************************************************************************
+ */
+
+static const char task_name[] = "my_task";
+
+static int is_my_task(void)
+{
+       return !strcmp(task_name, current->comm);
+}
+
+static int find_module_cnt;
+
+static struct kprobe *kp_find_module;
+static int find_module_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       if (is_my_task()) {
+               might_sleep();
+               ++find_module_cnt;
+
+               /* sleep 0.5 sec */
+               msleep(500);
+               schedule();
+
+               ++find_module_cnt;
+       }
+
+       return 0;
+}
+
+static int kthread_my_fn(void *data)
+{
+       find_module("o_lo_lo");
+       find_module("o_lo_lo");
+
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+       }
+
+       return 0;
+}
+
+
+static void do_test_sync_unreg(unsigned int ms)
+{
+       struct task_struct *task;
+
+       kp_reg(kp_find_module, "find_module", find_module_h);
+
+       task = kthread_run(kthread_my_fn, NULL, task_name);
+       if (IS_ERR(task)) {
+               olog("ERROR: kthread_run()\n");
+               goto unreg;
+       }
+
+       /* waiting for kthread_my_fn() call */
+       msleep(ms);
+unreg:
+       kp_unreg(kp_find_module);
+       if (!IS_ERR(task))
+               kthread_stop(task);
+}
+
+static void test_sync_unreg(void)
+{
+       olog("Unreg kp:\n");
+
+       find_module_cnt = 0;
+
+       do_test_sync_unreg(200);
+
+       if (find_module_cnt == 2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: find_module_cnt=%d\n", find_module_cnt);
+       }
+}
+
+
+
+/*
+ ******************************************************************************
+ *             swap_unregister_kprobe(), sync and multiple handlers           *
+ ******************************************************************************
+ */
+static int find_module2_cnt;
+
+static struct kprobe *kp_find_module2;
+static int find_module2_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       if (is_my_task()) {
+               ++find_module2_cnt;
+
+               /* sleep 0.5 sec */
+               msleep(500);
+
+               ++find_module2_cnt;
+       }
+
+       return 0;
+}
+
+static void pre_test_sync_unreg_and_mh(void)
+{
+       find_module_cnt = 0;
+       find_module2_cnt = 0;
+}
+
+static void post_test_sync_unreg_and_mh(int cnt, int cnt2)
+{
+       if (find_module_cnt == cnt && find_module2_cnt == cnt2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: find_module_cnt=%d find_module2_cnt=%d\n",
+                    find_module_cnt, find_module2_cnt);
+       }
+}
+
+static void do_test_sync_unreg_and_mh(unsigned int ms)
+{
+       struct task_struct *task;
+
+       kp_reg(kp_find_module, "find_module", find_module_h);
+       kp_reg(kp_find_module2, "find_module", find_module2_h);
+
+       task = kthread_run(kthread_my_fn, NULL, task_name);
+       if (IS_ERR(task)) {
+               olog("ERROR: kthread_run()\n");
+               goto unreg;
+       }
+
+       /* waiting for kthread_my_fn() call */
+       msleep(ms);
+unreg:
+       kp_unreg(kp_find_module2);
+       kp_unreg(kp_find_module);
+       if (!IS_ERR(task))
+               kthread_stop(task);
+}
+
+static void test_sync_unreg_and_multiple_handlers(void)
+{
+       olog("Unreg kp and multiple handlers:\n");
+
+       pre_test_sync_unreg_and_mh();
+
+       do_test_sync_unreg_and_mh(700);
+
+       post_test_sync_unreg_and_mh(2, 2);
+}
+
+static void do_test_sync_unreg_and_mh2(unsigned int ms)
+{
+       struct task_struct *task;
+
+       kp_reg(kp_find_module, "find_module", find_module_h);
+       kp_reg(kp_find_module2, "find_module", find_module2_h);
+
+       task = kthread_run(kthread_my_fn, NULL, task_name);
+       if (IS_ERR(task)) {
+               olog("ERROR: kthread_run()\n");
+               goto unreg;
+       }
+
+       /* waiting for kthread_my_fn() call */
+       msleep(ms);
+unreg:
+       kp_unreg(kp_find_module);
+       kp_unreg(kp_find_module2);
+       if (!IS_ERR(task))
+               kthread_stop(task);
+}
+
+static void test_sync_unreg_and_multiple_handlers2(void)
+{
+       olog("Unreg kp and multiple handlers [II]:\n");
+
+       pre_test_sync_unreg_and_mh();
+
+       do_test_sync_unreg_and_mh2(700);
+
+       post_test_sync_unreg_and_mh(2, 2);
+}
+
+int kp_tests_run(void)
+{
+       cur_task = current;
+
+       test_recursion();
+       test_recursion_and_multiple_handlers();
+       test_recursion_and_multiple_handlers2();
+       // add 3
+
+       test_sync_unreg();
+       test_sync_unreg_and_multiple_handlers();
+       test_sync_unreg_and_multiple_handlers2();
+
+       return 0;
+}
diff --git a/modules/tests/kprobe_tests/krp_tests.c b/modules/tests/kprobe_tests/krp_tests.c
new file mode 100644 (file)
index 0000000..db59126
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <kprobe/swap_kprobes.h>
+#include "kp_module.h"
+
+
+static struct kretprobe *krp_create(char *name,
+                                   int (*eh)(struct kretprobe_instance *, struct pt_regs *),
+                                   int (*rh)(struct kretprobe_instance *, struct pt_regs *),
+                                   size_t data_size)
+{
+       struct kretprobe *rp;
+
+       rp = kzalloc(sizeof(*rp), GFP_KERNEL);
+       if (rp) {
+               rp->kp.symbol_name = name;
+               rp->entry_handler = eh;
+               rp->handler = rh;
+               rp->data_size = data_size;
+       }
+
+       return rp;
+}
+
+static void krp_free(struct kretprobe *rp)
+{
+       memset(rp, 0x10, sizeof(*rp));
+}
+
+#define krp_reg(ptr, name, eh, rh, sz) \
+       do { \
+               ptr = krp_create(name, eh, rh, sz); \
+               swap_register_kretprobe(ptr); \
+       } while (0)
+
+#define krp_unreg(ptr) \
+       do { \
+               swap_unregister_kretprobe(ptr); \
+               krp_free(ptr); \
+               ptr = NULL; \
+       } while (0)
+
+
+
+
+
+struct test_func_data {
+       long v0, v1, v2, v3, v4, v5, v6, v7;
+};
+
+static struct test_func_data tf_data_tmp;
+static unsigned long tf_data_tmp_ret;
+
+
+static long do_test_func(long v0, long v1, long v2, long v3,
+                        long v4, long v5, long v6, long v7)
+{
+       return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7;
+}
+
+static noinline long test_func(long v0, long v1, long v2, long v3,
+                              long v4, long v5, long v6, long v7)
+{
+       return do_test_func(v0, v1, v2, v3, v4, v5, v6, v7);
+}
+
+static int test_func_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct test_func_data *data = (struct test_func_data *)ri->data;
+
+       data->v0 = swap_get_karg(regs, 0);
+       data->v1 = swap_get_karg(regs, 1);
+       data->v2 = swap_get_karg(regs, 2);
+       data->v3 = swap_get_karg(regs, 3);
+       data->v4 = swap_get_karg(regs, 4);
+       data->v5 = swap_get_karg(regs, 5);
+       data->v6 = swap_get_karg(regs, 6);
+       data->v7 = swap_get_karg(regs, 7);
+
+       pr_info("E data=[%ld %ld %ld %ld %ld %ld %ld %ld]\n",
+               data->v0, data->v1, data->v2, data->v3,
+               data->v4, data->v5, data->v6, data->v7);
+
+       return 0;
+}
+
+static int test_func_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct test_func_data *data = (struct test_func_data *)ri->data;
+
+       tf_data_tmp_ret = regs_return_value(regs);
+       tf_data_tmp = *data;
+
+       pr_info("R data=[%ld %ld %ld %ld %ld %ld %ld %ld] ret=%ld\n",
+               data->v0, data->v1, data->v2, data->v3,
+               data->v4, data->v5, data->v6, data->v7,
+               tf_data_tmp_ret);
+
+       return 0;
+}
+
+struct kretprobe *test_func_krp;
+
+static struct test_func_data tf_data_gage = {
+       .v0 = 0,
+       .v1 = 1,
+       .v2 = 2,
+       .v3 = 3,
+       .v4 = 4,
+       .v5 = 5,
+       .v6 = 6,
+       .v7 = 7,
+};
+
+static void pre_test_krp(void)
+{
+       memset(&tf_data_tmp, 0, sizeof(tf_data_tmp));
+       tf_data_tmp_ret = 0;
+}
+
+static void post_test_krp(void)
+{
+       long ret;
+
+       ret = do_test_func(tf_data_gage.v0, tf_data_gage.v1, tf_data_gage.v2, tf_data_gage.v3,
+                          tf_data_gage.v4, tf_data_gage.v5, tf_data_gage.v6, tf_data_gage.v7);
+
+       if (tf_data_tmp_ret == ret &&
+           memcmp(&tf_data_gage, &tf_data_tmp, sizeof(tf_data_gage)) == 0) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR:\n"
+                    "        tf_data_gage=[%ld %ld %ld %ld %ld %ld %ld %ld] ret=%ld\n"
+                    "        tf_data_tmp =[%ld %ld %ld %ld %ld %ld %ld %ld] ret=%ld\n",
+                    tf_data_gage.v0, tf_data_gage.v1,
+                    tf_data_gage.v2, tf_data_gage.v3,
+                    tf_data_gage.v4, tf_data_gage.v5,
+                    tf_data_gage.v6, tf_data_gage.v7, ret,
+                    tf_data_tmp.v0, tf_data_tmp.v1,
+                    tf_data_tmp.v2, tf_data_tmp.v3,
+                    tf_data_tmp.v4, tf_data_tmp.v5,
+                    tf_data_tmp.v6, tf_data_tmp.v7, tf_data_tmp_ret);
+       }
+}
+
+static void do_test_krp(void)
+{
+       krp_reg(test_func_krp, "test_func",
+               test_func_eh, test_func_rh,
+               sizeof(struct test_func_data));
+
+       test_func(tf_data_gage.v0, tf_data_gage.v1, tf_data_gage.v2, tf_data_gage.v3,
+                 tf_data_gage.v4, tf_data_gage.v5, tf_data_gage.v6, tf_data_gage.v7);
+
+       krp_unreg(test_func_krp);
+}
+
+static void test_krp(void)
+{
+       olog("Kretprobe (get_args{8} and ri->data):\n");
+
+       pre_test_krp();
+
+       do_test_krp();
+
+       post_test_krp();
+}
+
+int krp_tests_run(void)
+{
+       test_krp();
+
+       return 0;
+}
diff --git a/modules/tests/kprobe_tests/run_kp_tests.sh b/modules/tests/kprobe_tests/run_kp_tests.sh
new file mode 100644 (file)
index 0000000..d912090
--- /dev/null
@@ -0,0 +1,11 @@
+
+cd /opt/swap/sdk
+
+insmod swap_master.ko
+echo 1 > /sys/kernel/debug/swap/enable
+insmod swap_kprobe.ko
+
+insmod swap_kp_tests.ko 2>/dev/null
+
+rmmod swap_kprobe
+rmmod swap_master
diff --git a/modules/uihv/Kbuild b/modules/uihv/Kbuild
new file mode 100644 (file)
index 0000000..9ae0694
--- /dev/null
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_uihv.o
+swap_uihv-y := uihv_module.o \
+               uihv_debugfs.o
diff --git a/modules/uihv/uihv.h b/modules/uihv/uihv.h
new file mode 100644 (file)
index 0000000..1e0b0c7
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __UIHV_H__
+#define __UIHV_H__
+
+#define UIHV_PREFIX "SWAP_UIHV: "
+#define UIHV_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
+
+#endif /* __UIHV_H__ */
diff --git a/modules/uihv/uihv_debugfs.c b/modules/uihv/uihv_debugfs.c
new file mode 100644 (file)
index 0000000..b02b6af
--- /dev/null
@@ -0,0 +1,237 @@
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <master/swap_debugfs.h>
+#include "uihv.h"
+#include "uihv_module.h"
+
+static const char UIHV_FOLDER[] = "uihv";
+static const char UIHV_PATH[] = "path";
+static const char UIHV_APP_INFO[] = "app_info";
+static const char UIHV_ENABLE[] = "enable";
+
+static struct dentry *uihv_root;
+
+
+
+/* ===========================================================================
+ * =                           UI VIEWER PATH                                =
+ * ===========================================================================
+ */
+
+
+static ssize_t uihv_path_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto uihv_path_write_out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto uihv_path_write_out;
+       }
+
+       path[len - 1] = '\0';
+
+       if (uihv_set_handler(path) != 0) {
+               printk(UIHV_PREFIX "Cannot set ui viewer path %s\n", path);
+               ret = -EINVAL;
+               goto uihv_path_write_out;
+       }
+
+       ret = len;
+
+       printk(UIHV_PREFIX "Set ui viewer path %s\n", path);
+
+uihv_path_write_out:
+       kfree(path);
+
+       return ret;
+}
+
+static const struct file_operations uihv_path_file_ops = {
+       .owner = THIS_MODULE,
+       .write = uihv_path_write,
+};
+
+
+/*
+ * format:
+ *     main:app_path
+ *
+ * sample:
+ *     0x00000d60:/bin/app_sample
+ */
+static int uihv_add_app_info(const char *buf, size_t len)
+{
+       int n, ret;
+       char *app_path;
+       unsigned long main_addr;
+       const char fmt[] = "%%lx:/%%%ds";
+       char fmt_buf[64];
+
+       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
+       if (n <= 0)
+               return -EINVAL;
+
+       app_path = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (app_path == NULL)
+               return -ENOMEM;
+
+       n = sscanf(buf, fmt_buf, &main_addr, app_path + 1);
+       if (n != 2) {
+               ret = -EINVAL;
+               goto free_app_path;
+       }
+       app_path[0] = '/';
+
+       printk(UIHV_PREFIX "Set ui viewer app path %s, main offset 0x%lx\n", app_path, main_addr);
+
+       ret = uihv_data_set(app_path, main_addr);
+
+free_app_path:
+       kfree(app_path);
+       return ret;
+}
+
+static ssize_t write_uihv_app_info(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t len, loff_t *ppos)
+{
+       ssize_t ret = len;
+       char *buf;
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (buf == NULL) {
+               ret = -ENOMEM;
+               goto free_buf;
+       }
+
+       if (copy_from_user(buf, user_buf, len)) {
+               ret = -EINVAL;
+               goto free_buf;
+       }
+
+       buf[len - 1] = '\0';
+
+       if (uihv_add_app_info(buf, len))
+               ret = -EINVAL;
+
+free_buf:
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations uihv_app_info_file_ops = {
+       .owner = THIS_MODULE,
+       .write = write_uihv_app_info,
+};
+
+static ssize_t write_uihv_enable(struct file *file,
+                                const char __user *user_buf,
+                                size_t len, loff_t *ppos)
+{
+       ssize_t ret = len;
+       char *buf;
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (copy_from_user(buf, user_buf, len)) {
+               ret = -EINVAL;
+               goto free_buf;
+       }
+
+       buf[len - 1] = '\0';
+
+       if (buf[0] == '0')
+               ret = uihv_disable();
+       else
+               ret = uihv_enable();
+
+free_buf:
+       kfree(buf);
+
+out:
+       return ret;
+}
+
+static const struct file_operations uihv_enable_file_ops = {
+       .owner = THIS_MODULE,
+       .write = write_uihv_enable,
+};
+
+int uihv_dfs_init(void)
+{
+       struct dentry *swap_dentry, *root, *path, *app_info, *uihv_enable;
+       int ret;
+
+       ret = -ENODEV;
+       if (!debugfs_initialized())
+               goto fail;
+
+       ret = -ENOENT;
+       swap_dentry = swap_debugfs_getdir();
+       if (!swap_dentry)
+               goto fail;
+
+       ret = -ENOMEM;
+       root = swap_debugfs_create_dir(UIHV_FOLDER, swap_dentry);
+       if (IS_ERR_OR_NULL(root))
+               goto fail;
+
+       uihv_root = root;
+
+       path = swap_debugfs_create_file(UIHV_PATH, UIHV_DEFAULT_PERMS, root,
+                                       NULL, &uihv_path_file_ops);
+       if (IS_ERR_OR_NULL(path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       app_info = swap_debugfs_create_file(UIHV_APP_INFO,
+                                           UIHV_DEFAULT_PERMS, root, NULL,
+                                           &uihv_app_info_file_ops);
+       if (IS_ERR_OR_NULL(app_info)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       uihv_enable = swap_debugfs_create_file(UIHV_ENABLE,
+                                              UIHV_DEFAULT_PERMS, root, NULL,
+                                              &uihv_enable_file_ops);
+       if (IS_ERR_OR_NULL(uihv_enable)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       return 0;
+
+remove:
+       debugfs_remove_recursive(root);
+
+fail:
+       printk(UIHV_PREFIX "Debugfs initialization failure: %d\n", ret);
+
+       return ret;
+}
+
+void uihv_dfs_exit(void)
+{
+       if (uihv_root)
+               debugfs_remove_recursive(uihv_root);
+
+       uihv_root = NULL;
+}
diff --git a/modules/uihv/uihv_debugfs.h b/modules/uihv/uihv_debugfs.h
new file mode 100644 (file)
index 0000000..59841c0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __UIHV_DEBUGFS_H__
+#define __UIHV_DEBUGFS_H__
+
+int uihv_dfs_init(void);
+void uihv_dfs_exit(void);
+
+#endif /* __UIHV_DEBUGFS_H__ */
diff --git a/modules/uihv/uihv_module.c b/modules/uihv/uihv_module.c
new file mode 100644 (file)
index 0000000..5d983be
--- /dev/null
@@ -0,0 +1,221 @@
+#include <linux/namei.h>
+#include <us_manager/us_manager_common.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/callbacks.h>
+#include <us_manager/probes/probe_info_new.h>
+#include <us_manager/us_common_file.h>
+#include <writer/kernel_operations.h>
+#include <master/swap_initializer.h>
+#include <writer/swap_msg.h>
+#include <loader/loader.h>
+#include "uihv.h"
+#include "uihv_module.h"
+#include "uihv_debugfs.h"
+
+#define page_to_proc(page) ((page)->file->proc)
+#define ip_to_proc(ip) page_to_proc((ip)->page)
+#define urp_to_ip(rp) container_of(rp, struct sspt_ip, retprobe)
+
+static DEFINE_MUTEX(mutex_enable);
+
+static struct dentry *uihv_dentry = NULL;
+
+
+/* ============================================================================
+ * =                               ui_viewer                                  =
+ * ============================================================================
+ */
+
+/* main handler for ui viewer */
+static int uihv_main_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static int uihv_main_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
+static struct probe_desc pin_main = MAKE_URPROBE(uihv_main_eh,
+                                                    uihv_main_rh, 0);
+
+struct ui_viewer_data {
+       struct dentry *app_dentry;
+       struct probe_new p_main;
+       struct pf_group *pfg;
+       bool enable;
+};
+
+static struct ui_viewer_data __ui_data;
+
+static int uihv_data_inst(void)
+{
+       struct pf_group *pfg;
+
+       pfg = get_pf_group_by_dentry(__ui_data.app_dentry,
+                                    (void *)__ui_data.app_dentry);
+       if (!pfg)
+               return -ENOMEM;
+
+       __ui_data.pfg = pfg;
+
+       return 0;
+}
+
+int uihv_data_set(const char *app_path, unsigned long main_addr)
+{
+       struct dentry *dentry;
+
+       if (__ui_data.enable) {
+               pr_err("UIHV already enabled, can't set data\n");
+               return -EBUSY;
+       }
+
+       dentry = dentry_by_path(app_path);
+       if (dentry == NULL)
+               return -ENOENT;
+
+       __ui_data.app_dentry = dentry;
+       __ui_data.p_main.desc = &pin_main;
+       __ui_data.p_main.offset = main_addr;
+
+       return uihv_data_inst();
+}
+
+int uihv_set_handler(char *path)
+{
+       struct dentry *dentry;
+       int ret;
+
+       if (uihv_dentry != NULL) {
+               swap_put_dentry(uihv_dentry);
+               uihv_dentry = NULL;
+       }
+
+       dentry = swap_get_dentry(path);
+       if (dentry == NULL) {
+               printk(KERN_WARNING UIHV_PREFIX "Error! Cannot get handler %s\n",
+                          path);
+               return -EINVAL;
+       }
+
+       ret = loader_add_handler(path);
+       if (ret != 0)
+               return ret;
+
+       uihv_dentry = dentry;
+
+       return 0;
+}
+
+
+
+/* ============================================================================
+ * =                          ui viewer handlers                              =
+ * ============================================================================
+ */
+static int uihv_main_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+       struct hd_t *hd;
+       unsigned long old_pc = swap_get_upc(regs);
+       unsigned long vaddr = 0;
+
+       if (uihv_dentry == NULL)
+               return 0;
+
+       hd = lpd_get_hd(pd, uihv_dentry);
+       if (hd == NULL)
+               return 0;
+
+       if (lpd_get_state(hd) == NOT_LOADED)
+               vaddr = loader_not_loaded_entry(ri, regs, pd, hd);
+
+       loader_set_priv_origin(ri, vaddr);
+
+       /* PC change check */
+       return old_pc != swap_get_upc(regs);
+}
+
+static int uihv_main_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pd_t *pd = lpd_get_by_task(current);
+       struct hd_t *hd;
+
+       if (uihv_dentry == NULL)
+               return 0;
+
+       hd = lpd_get_hd(pd, uihv_dentry);
+       if (hd == NULL)
+               return 0;
+
+       if (lpd_get_state(hd) == LOADING)
+               loader_loading_ret(ri, regs, pd, hd);
+
+       return 0;
+}
+
+int uihv_enable(void)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_enable);
+       if (__ui_data.enable) {
+               pr_err("UIHV already enabled\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = pin_register(&__ui_data.p_main, __ui_data.pfg,
+                          __ui_data.app_dentry);
+       if (ret)
+               goto out;
+
+       __ui_data.enable = true;
+
+out:
+       mutex_unlock(&mutex_enable);
+       return ret;
+}
+
+int uihv_disable(void)
+{
+       int ret = 0;
+
+       mutex_lock(&mutex_enable);
+       if (!__ui_data.enable) {
+               pr_err("UIHV already disabled\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       pin_unregister(&__ui_data.p_main, __ui_data.pfg);
+       put_pf_group(__ui_data.pfg);
+       __ui_data.pfg = NULL;
+       __ui_data.enable = false;
+
+out:
+       mutex_unlock(&mutex_enable);
+       return ret;
+}
+
+static int uihv_init(void)
+{
+       int ret;
+
+       ret = uihv_dfs_init();
+
+       return ret;
+}
+
+static void uihv_exit(void)
+{
+       if (uihv_dentry != NULL) {
+               swap_put_dentry(uihv_dentry);
+               uihv_dentry = NULL;
+       }
+
+       uihv_dfs_exit();
+}
+
+SWAP_LIGHT_INIT_MODULE(NULL, uihv_init, uihv_exit, NULL, NULL);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP UI Hierarchy Viewer");
+MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>, Anastasia Lypa");
diff --git a/modules/uihv/uihv_module.h b/modules/uihv/uihv_module.h
new file mode 100644 (file)
index 0000000..e6413a7
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __UIHV_MODULE_H__
+#define __UIHV_MODULE_H__
+
+int uihv_data_set(const char *app_path, unsigned long main_addr);
+int uihv_set_handler(char *path);
+int uihv_enable(void);
+int uihv_disable(void);
+
+#endif /* __UIHV_MODULE_H__ */
diff --git a/modules/uprobe/Kbuild b/modules/uprobe/Kbuild
new file mode 100644 (file)
index 0000000..ad4d051
--- /dev/null
@@ -0,0 +1,29 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers
+
+obj-m := swap_uprobe.o
+swap_uprobe-y := swap_uprobes.o
+
+### ARM
+swap_uprobe-$(CONFIG_ARM) += \
+       arch/arm/swap-asm/swap_uprobes.o \
+       ../arch/arm/probes/probes_thumb.o \
+       ../arch/arm/probes/decode_thumb.o \
+       ../arch/arm/probes/probes.o \
+       ../arch/arm/uprobe/swap_uprobe.o
+
+
+### ARM64
+swap_uprobe-$(CONFIG_ARM64) += \
+       arch/arm64/swap-asm/swap_uprobes.o \
+       arch/arm64/swap-asm/uprobes-arm64.o \
+       ../arch/arm/probes/probes_arm.o \
+       ../arch/arm/probes/decode_thumb.o \
+       ../arch/arm/probes/probes_thumb.o \
+       ../arch/arm/probes/probes.o \
+       ../arch/arm/uprobe/swap_uprobe.o
+
+
+### X86
+swap_uprobe-$(CONFIG_X86) += arch/x86/swap-asm/swap_uprobes.o \
+                            arch/x86/swap-asm/swap_sc_patch.o
diff --git a/modules/uprobe/arch/arm/swap-asm/swap_uprobes.c b/modules/uprobe/arch/arm/swap-asm/swap_uprobes.c
new file mode 100644 (file)
index 0000000..6da9d14
--- /dev/null
@@ -0,0 +1,401 @@
+/**
+ * uprobe/arch/asm-arm/swap_uprobes.c
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Arch-dependent uprobe interface implementation for ARM.
+ */
+
+
+#include <linux/init.h>                        /* need for asm/traps.h */
+#include <linux/sched.h>               /* need for asm/traps.h */
+
+#include <linux/ptrace.h>              /* need for asm/traps.h */
+#include <asm/traps.h>
+
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <uprobe/swap_uprobes.h>
+#include <arch/arm/probes/probes_arm.h>
+#include <arch/arm/probes/probes_thumb.h>
+#include <swap-asm/swap_kprobes.h>
+#include "swap_uprobes.h"
+
+
+/**
+ * @brief Prepares uprobe for ARM.
+ *
+ * @param up Pointer to the uprobe.
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int arch_prepare_uprobe(struct uprobe *p)
+{
+       int ret;
+
+       ret = arch_prepare_uprobe_arm(p);
+       if (!ret) {
+               /* for uretprobe */
+               add_uprobe_table(p);
+       }
+
+       return ret;
+}
+
+/**
+ * @brief Analysis opcodes.
+ *
+ * @param rp Pointer to the uretprobe.
+ * @return Void.
+ */
+void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
+{
+       /* Remove retprobe if first insn overwrites lr */
+       rp->thumb_noret = noret_thumb(rp->up.opcode);
+       rp->arm_noret = noret_arm(rp->up.opcode);
+}
+
+/**
+ * @brief Prepates uretprobe for ARM.
+ *
+ * @param ri Pointer to the uretprobe instance.
+ * @param regs Pointer to CPU register data.
+ * @return Error code.
+ */
+int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       unsigned long thumb, bp_offset;
+
+       thumb = ri->preload.use ? ri->preload.thumb : thumb_mode(regs);
+       bp_offset = thumb ? 0x1b : sizeof(long) * PROBES_TRAMP_RET_BREAK_IDX;
+
+       /* save original return address */
+       ri->ret_addr = (uprobe_opcode_t *)regs->ARM_lr;
+
+       /* replace return address with break point adddress */
+       regs->ARM_lr = (unsigned long)(ri->rp->up.insn) + bp_offset;
+
+       /* save stack pointer address */
+       ri->sp = (uprobe_opcode_t *)regs->ARM_sp;
+
+       /* Set flag of current mode */
+       ri->sp = (uprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
+
+       return 0;
+}
+
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
+{
+       /* Understand function mode */
+       return ((unsigned long)ri->sp & 1) ?
+                       ((unsigned long)ri->rp->up.insn + 0x1b) :
+                       (unsigned long)(ri->rp->up.insn +
+                                       PROBES_TRAMP_RET_BREAK_IDX);
+}
+
+/**
+ * @brief Disarms uretprobe instance.
+ *
+ * @param ri Pointer to the uretprobe instance
+ * @param task Pointer to the task for which the uretprobe instance
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task)
+{
+       struct pt_regs *uregs = task_pt_regs(ri->task);
+       unsigned long ra = uregs->ARM_lr;
+       unsigned long *tramp = (unsigned long *)arch_tramp_by_ri(ri);
+       unsigned long *sp = (unsigned long *)((long)ri->sp & ~1);
+       unsigned long *stack = sp - URETPROBE_STACK_DEPTH + 1;
+       unsigned long *found = NULL;
+       unsigned long *buf[URETPROBE_STACK_DEPTH];
+       unsigned long vaddr = (unsigned long)ri->rp->up.addr;
+       int i, retval;
+
+       /* check stack */
+       retval = read_proc_vm_atomic(task, (unsigned long)stack,
+                                    buf, sizeof(buf));
+       if (retval != sizeof(buf)) {
+               printk(KERN_INFO "---> %s (%d/%d): failed to read "
+                      "stack from %08lx\n", task->comm, task->tgid, task->pid,
+                      (unsigned long)stack);
+               retval = -EFAULT;
+               goto check_lr;
+       }
+
+       /* search the stack from the bottom */
+       for (i = URETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
+               if (buf[i] == tramp) {
+                       found = stack + i;
+                       break;
+               }
+       }
+
+       if (!found) {
+               retval = -ESRCH;
+               goto check_lr;
+       }
+
+       printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
+              "%08lx (%08lx /%+d) - %lx, set ret_addr=%p\n",
+              task->comm, task->tgid, task->pid,
+              (unsigned long)found, (unsigned long)sp,
+              found - sp, vaddr, ri->ret_addr);
+       retval = write_proc_vm_atomic(task, (unsigned long)found,
+                                     &ri->ret_addr,
+                                     sizeof(ri->ret_addr));
+       if (retval != sizeof(ri->ret_addr)) {
+               printk(KERN_INFO "---> %s (%d/%d): "
+                      "failed to write value to %08lx",
+                      task->comm, task->tgid, task->pid, (unsigned long)found);
+               retval = -EFAULT;
+       } else {
+               retval = 0;
+       }
+
+check_lr: /* check lr anyway */
+       if (ra == (unsigned long)tramp) {
+               printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
+                      "lr = %08lx - %lx, set ret_addr=%p\n",
+                      task->comm, task->tgid, task->pid, ra, vaddr, ri->ret_addr);
+
+               swap_set_uret_addr(uregs, (unsigned long)ri->ret_addr);
+               retval = 0;
+       } else if (retval) {
+               printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at "
+                      "sp = %08lx, lr = %08lx - %lx, ret_addr=%p\n",
+                      task->comm, task->tgid, task->pid,
+                      (unsigned long)sp, ra, vaddr, ri->ret_addr);
+       }
+
+       return retval;
+}
+
+/**
+ * @brief Jump pre-handler.
+ *
+ * @param p Pointer to the uprobe.
+ * @param regs Pointer to CPU register data.
+ * @return 0.
+ */
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct ujprobe *jp = container_of(p, struct ujprobe, up);
+       entry_point_t entry = (entry_point_t)jp->entry;
+
+       if (entry) {
+               entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
+                     regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
+       } else {
+               arch_ujprobe_return();
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Gets trampoline address.
+ *
+ * @param p Pointer to the uprobe.
+ * @param regs Pointer to CPU register data.
+ * @return Trampoline address.
+ */
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
+{
+       return thumb_mode(regs) ?
+                       (unsigned long)(p->insn) + 0x1b :
+                       (unsigned long)(p->insn +
+                                       PROBES_TRAMP_RET_BREAK_IDX);
+}
+
+/**
+ * @brief Restores return address.
+ *
+ * @param orig_ret_addr Original return address.
+ * @param regs Pointer to CPU register data.
+ * @return Void.
+ */
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
+{
+       regs->ARM_lr = orig_ret_addr;
+       regs->ARM_pc = orig_ret_addr & ~0x1;
+
+       if (regs->ARM_lr & 0x1)
+               regs->ARM_cpsr |= PSR_T_BIT;
+       else
+               regs->ARM_cpsr &= ~PSR_T_BIT;
+}
+
+/**
+ * @brief Removes uprobe.
+ *
+ * @param up Pointer to the uprobe.
+ * @return Void.
+ */
+void arch_remove_uprobe(struct uprobe *up)
+{
+       swap_slot_free(up->sm, up->insn);
+}
+
+static int urp_handler(struct pt_regs *regs, pid_t tgid)
+{
+       struct uprobe *p;
+       unsigned long flags;
+       unsigned long vaddr = regs->ARM_pc;
+       unsigned long offset_bp = thumb_mode(regs) ?
+                                 0x1a :
+                                 4 * PROBES_TRAMP_RET_BREAK_IDX;
+       unsigned long tramp_addr = vaddr - offset_bp;
+
+       local_irq_save(flags);
+       p = get_uprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
+       if (unlikely(p == NULL)) {
+               local_irq_restore(flags);
+
+               pr_info("no_uprobe: Not one of ours: let kernel handle it %lx\n",
+                       vaddr);
+               return 1;
+       }
+
+       get_up(p);
+       local_irq_restore(flags);
+       trampoline_uprobe_handler(p, regs);
+       put_up(p);
+
+       return 0;
+}
+/**
+ * @brief Prepares singlestep for current CPU.
+ *
+ * @param p Pointer to kprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+static void arch_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
+{
+       if (p->ainsn.insn.handler) {
+               regs->ARM_pc += 4;
+               p->ainsn.insn.handler(p->opcode, &p->ainsn.insn, regs);
+       } else {
+               regs->ARM_pc = (unsigned long)p->insn;
+       }
+}
+
+/**
+ * @brief Breakpoint instruction handler.
+ *
+ * @param regs Pointer to CPU register data.
+ * @param instr Instruction.
+ * @return uprobe_handler results.
+ */
+static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+{
+       int ret = 0;
+       struct uprobe *p;
+       unsigned long flags;
+       unsigned long vaddr = regs->ARM_pc | !!thumb_mode(regs);
+       pid_t tgid = current->tgid;
+
+       local_irq_save(flags);
+       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+       if (p) {
+               get_up(p);
+               local_irq_restore(flags);
+               if (!p->pre_handler || !p->pre_handler(p, regs))
+                       arch_prepare_singlestep(p, regs);
+               put_up(p);
+       } else {
+               local_irq_restore(flags);
+               ret = urp_handler(regs, tgid);
+
+               /* check ARM/THUMB CPU mode matches installed probe mode */
+               if (ret) {
+                       vaddr ^= 1;
+
+                       local_irq_save(flags);
+                       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+                       if (p) {
+                               get_up(p);
+                               local_irq_restore(flags);
+                               pr_err("invalid mode: thumb=%d addr=%p insn=%08x\n",
+                                      !!thumb_mode(regs), p->addr, p->opcode);
+                               ret = 0;
+
+                               disarm_uprobe(p, current);
+                               put_up(p);
+                       } else {
+                               local_irq_restore(flags);
+                       }
+               }
+       }
+
+       return ret;
+}
+
+/* userspace probes hook (arm) */
+static struct undef_hook undef_hook_for_us_arm = {
+       .instr_mask     = 0xffffffff,
+       .instr_val      = BREAK_ARM,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = USR_MODE,
+       .fn             = uprobe_trap_handler
+};
+
+/* userspace probes hook (thumb) */
+static struct undef_hook undef_hook_for_us_thumb = {
+       .instr_mask     = 0xffffffff,
+       .instr_val      = BREAK_THUMB,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = USR_MODE,
+       .fn             = uprobe_trap_handler
+};
+
+/**
+ * @brief Installs breakpoint hooks.
+ *
+ * @return 0.
+ */
+int swap_arch_init_uprobes(void)
+{
+       swap_register_undef_hook(&undef_hook_for_us_arm);
+       swap_register_undef_hook(&undef_hook_for_us_thumb);
+
+       return 0;
+}
+
+/**
+ * @brief Uninstalls breakpoint hooks.
+ *
+ * @return Void.
+ */
+void swap_arch_exit_uprobes(void)
+{
+       swap_unregister_undef_hook(&undef_hook_for_us_thumb);
+       swap_unregister_undef_hook(&undef_hook_for_us_arm);
+}
diff --git a/modules/uprobe/arch/arm/swap-asm/swap_uprobes.h b/modules/uprobe/arch/arm/swap-asm/swap_uprobes.h
new file mode 100644 (file)
index 0000000..87d8159
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ * @file uprobe/arch/asm-arm/swap_uprobes.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Arch-dependent uprobe interface declaration.
+ */
+
+
+#ifndef _ARM_SWAP_UPROBES_H
+#define _ARM_SWAP_UPROBES_H
+
+
+#include <linux/uaccess.h>
+#include <arch/arm/probes/probes.h>
+#include <arch/arm/uprobe/swap_uprobe.h>
+
+
+/** Uprobes trampoline length */
+#define UPROBES_TRAMP_LEN      PROBES_TRAMP_LEN
+
+
+struct task_struct;
+struct uprobe;
+struct arch_insn;
+struct uretprobe;
+struct uretprobe_instance;
+
+typedef u32 uprobe_opcode_t;
+
+
+/**
+ * @struct arch_insn
+ * @brief Architecture depend copy of original instruction.
+ * @var arch_insn::insn
+ * Copy of the original instruction.
+ */
+struct arch_insn {
+       struct arch_insn_arm insn;
+};
+
+
+static inline u32 swap_get_urp_float(struct pt_regs *regs)
+{
+       return regs->ARM_r0;
+}
+
+static inline u64 swap_get_urp_double(struct pt_regs *regs)
+{
+
+       return regs->ARM_r0 | (u64)regs->ARM_r1 << 32;
+}
+
+static inline void arch_ujprobe_return(void)
+{
+}
+
+int arch_prepare_uprobe(struct uprobe *up);
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
+static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
+{
+       return 0;
+}
+
+#define arch_urp_check_opcode NULL /* Arch doesn't requires special callback */
+void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
+int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task);
+
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
+void arch_remove_uprobe(struct uprobe *up);
+
+static inline int arch_arm_uprobe(struct uprobe *p)
+{
+       return arch_arm_uprobe_arm(p);
+}
+
+static inline void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+{
+       arch_disarm_uprobe_arm(p, task);
+}
+
+static inline unsigned long swap_get_upc(struct pt_regs *regs)
+{
+       return swap_get_upc_arm(regs);
+}
+
+static inline void swap_set_upc(struct pt_regs *regs, unsigned long val)
+{
+       swap_set_upc_arm(regs, val);
+}
+
+static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
+{
+       return swap_get_uarg_arm(regs, n);
+}
+
+static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
+                                 unsigned long val)
+{
+       swap_put_uarg_arm(regs, n, val);
+}
+
+static inline unsigned long swap_get_uret_addr(struct pt_regs *regs)
+{
+       return swap_get_uret_addr_arm(regs);
+}
+
+static inline void swap_set_uret_addr(struct pt_regs *regs, unsigned long val)
+{
+       swap_set_uret_addr_arm(regs, val);
+}
+
+int swap_arch_init_uprobes(void);
+void swap_arch_exit_uprobes(void);
+
+#endif /* _ARM_SWAP_UPROBES_H */
diff --git a/modules/uprobe/arch/arm64/swap-asm/swap_uprobes.c b/modules/uprobe/arch/arm64/swap-asm/swap_uprobes.c
new file mode 100644 (file)
index 0000000..d5e2627
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/kconfig.h>
+#include <linux/types.h>
+#include <asm/traps.h>
+#include <arch/arm/uprobe/swap_uprobe.h>
+#include <uprobe/swap_uprobes.h>
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_td_raw.h>
+#include <kprobe/swap_kprobes_deps.h>  /* FIXME: remove it */
+#include <swap-asm/swap_probes.h>
+#include <arch/arm/uprobe/swap_uprobe.h>
+#include <swap-asm/dbg_interface.h>
+#include "uprobes-arm64.h"
+
+
+#define BRK_BP                 0x45
+#define BRK_PSEUDO_SS          0x54
+#define BRK_URP                        0x67
+#define BRK64_OPCODE_BP                MAKE_BRK(BRK_BP)
+#define BRK64_OPCODE_PSEUDO_SS MAKE_BRK(BRK_PSEUDO_SS)
+#define BRK64_OPCODE_URP       MAKE_BRK(BRK_URP)
+
+
+enum arch_mode {
+       AM_UNKNOWN,
+       AM_THUMB,
+       AM_ARM,
+       AM_ARM64
+};
+
+#define ARM64_MODE_VADDR_MASK          ((unsigned long)1 << 63)
+
+static enum arch_mode get_arch_mode(unsigned long vaddr)
+{
+       if (vaddr & 1)
+               return AM_THUMB;
+
+       if (vaddr & ARM64_MODE_VADDR_MASK)
+               return AM_ARM64;
+
+       return AM_ARM;
+}
+
+static unsigned long get_real_addr(unsigned long vaddr)
+{
+       return vaddr & ~(ARM64_MODE_VADDR_MASK | 1);
+}
+
+static unsigned long get_64bit_addr(unsigned long raddr)
+{
+       return raddr | ARM64_MODE_VADDR_MASK;
+}
+
+struct uprobe_ctlblk {
+       struct uprobe *p;
+};
+
+static struct td_raw td_raw;
+
+static struct uprobe_ctlblk *current_ctlblk(void)
+{
+       return (struct uprobe_ctlblk *)swap_td_raw(&td_raw, current);
+}
+
+static struct uprobe *get_current_uprobe(void)
+{
+       return current_ctlblk()->p;
+}
+
+static void set_current_uprobe(struct uprobe *p)
+{
+       current_ctlblk()->p = p;
+}
+
+static void reset_current_uprobe(void)
+{
+       set_current_uprobe(NULL);
+}
+
+
+static unsigned long trampoline_addr_arm64(struct uprobe *p)
+{
+       return (unsigned long)(p->insn + URP_RET_BREAK_IDX);
+}
+
+static int prepare_uretprobe_arm64(struct uretprobe_instance *ri,
+                                  struct pt_regs *regs)
+{
+       unsigned long bp_addr, ret_addr;
+
+       ret_addr = regs->regs[30] | ARM64_MODE_VADDR_MASK;
+       bp_addr = trampoline_addr_arm64(&ri->rp->up);
+
+       ri->sp = (uprobe_opcode_t *)regs->sp;
+       ri->ret_addr = (uprobe_opcode_t *)ret_addr;
+
+       /* replace the return address (regs[30] - lr) */
+       regs->regs[30] = bp_addr;
+
+       return 0;
+}
+
+int arch_prepare_uretprobe(struct uretprobe_instance *ri,
+                          struct pt_regs *regs)
+{
+       if (get_arch_mode((unsigned long)ri->rp->up.addr) == AM_ARM64)
+               return prepare_uretprobe_arm64(ri, regs);
+       else
+               return prepare_uretprobe_arm(ri, regs);
+}
+
+static void arch_opcode_analysis_uretprobe_arm64(struct uretprobe *rp)
+{
+       /* FIXME: to implement */
+}
+
+void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
+{
+       if (get_arch_mode((unsigned long)rp->up.addr) == AM_ARM64)
+               arch_opcode_analysis_uretprobe_arm64(rp);
+       else
+               arch_opcode_analysis_uretprobe_arm(rp);
+}
+
+/**
+ * @brief Gets trampoline address.
+ *
+ * @param p Pointer to the kprobe.
+ * @param regs Pointer to CPU register data.
+ * @return Trampoline address.
+ */
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
+{
+       if (get_arch_mode((unsigned long)p->addr) == AM_ARM64)
+               return trampoline_addr_arm64(p);
+       else
+               return arch_get_trampoline_addr_arm(p, regs);
+}
+
+static unsigned long arch_tramp_by_ri_arm64(struct uretprobe_instance *ri)
+{
+       return trampoline_addr_arm64(&ri->rp->up);
+}
+
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
+{
+       if (get_arch_mode((unsigned long)ri->rp->up.addr) == AM_ARM64)
+               return arch_tramp_by_ri_arm64(ri);
+       else
+               return arch_tramp_by_ri_arm(ri);
+}
+
+static int arch_disarm_urp_inst_arm64(struct uretprobe_instance *ri,
+                                     struct task_struct *task)
+{
+       struct pt_regs *uregs = task_pt_regs(ri->task);
+       u64 ra = uregs->regs[30];
+       u64 raddr, tramp, found = 0;
+       u64 sp = (u64)ri->sp;
+       u64 ret_addr = (u64)ri->ret_addr;
+       u64 stack = sp - 8 * (URETPROBE_STACK_DEPTH + 1);
+       u64 buf[URETPROBE_STACK_DEPTH];
+       int i, ret;
+
+       raddr = get_real_addr((unsigned long)ri->rp->up.addr);
+       tramp = arch_tramp_by_ri_arm64(ri);
+
+       /* check stack */
+       ret = read_proc_vm_atomic(task, stack, buf, sizeof(buf));
+       if (ret != sizeof(buf)) {
+               pr_info("---> %s (%d/%d): failed to read stack from %016llx\n",
+                       task->comm, task->tgid, task->pid, stack);
+               ret = -EFAULT;
+               goto check_lr;
+       }
+
+       /* search the stack from the bottom */
+       for (i = URETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
+               if (buf[i] == tramp) {
+                       found = stack + 8 * i;
+                       break;
+               }
+       }
+
+       if (!found) {
+               ret = -ESRCH;
+               goto check_lr;
+       }
+
+       pr_info("---> %s (%d/%d): trampoline found at "
+               "%016llx (%016llx /%+lld) - %llx, set ret_addr=%016llx\n",
+               task->comm, task->tgid, task->pid,
+               found, sp,
+               found - sp, raddr, ret_addr);
+       ret = write_proc_vm_atomic(task, found, &ret_addr, 8);
+       if (ret != 8) {
+               pr_info("---> %s (%d/%d): failed to write value to %016llx",
+                       task->comm, task->tgid, task->pid, found);
+               ret = -EFAULT;
+       } else {
+               ret = 0;
+       }
+
+check_lr: /* check lr anyway */
+       if (ra == tramp) {
+               pr_info("---> %s (%d/%d): trampoline found at "
+                       "lr = %016llx - %llx, set ret_addr=%016llx\n",
+                       task->comm, task->tgid, task->pid, ra, raddr,
+                       ret_addr);
+
+               /* set ret_addr */
+               uregs->regs[30] = ret_addr;
+               ret = 0;
+       } else if (ret) {
+               pr_info("---> %s (%d/%d): trampoline NOT found at "
+                       "sp=%016llx, lr=%016llx - %llx, ret_addr=%016llx\n",
+                       task->comm, task->tgid, task->pid,
+                       sp, ra, raddr, ret_addr);
+       }
+
+       return ret;
+}
+
+/**
+ * @brief Disarms uretprobe instance.
+ *
+ * @param ri Pointer to the uretprobe instance
+ * @param task Pointer to the task for which the uretprobe instance
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task)
+{
+       if (get_arch_mode((unsigned long)ri->rp->up.addr) == AM_ARM64)
+               return arch_disarm_urp_inst_arm64(ri, task);
+       else
+               return arch_disarm_urp_inst_arm(ri, task);
+}
+
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
+{
+       if (get_arch_mode(orig_ret_addr) == AM_ARM64) {
+               regs->pc = get_real_addr(orig_ret_addr);
+       } else {
+               set_orig_ret_addr_arm(orig_ret_addr, regs);
+       }
+}
+
+static enum dbg_code urp_handler(struct pt_regs *regs, unsigned int esr)
+{
+       struct uprobe *p;
+       unsigned long pc = regs->pc;
+       unsigned long insn_addr = pc - sizeof(u32) * URP_RET_BREAK_IDX;
+
+       p = get_uprobe_by_insn_slot((void *)insn_addr, current->tgid, regs);
+       if (p == NULL) {
+               pr_err("no_uretprobe: Not one of ours: let "
+                      "kernel handle it %lx\n", pc);
+               return DBG_ERROR;
+       }
+
+       local_irq_enable();
+       trampoline_uprobe_handler(p, regs);
+
+       return DBG_HANDLED;
+}
+
+static int arch_arm_uprobe_arm64(struct uprobe *p)
+{
+       int ret;
+       unsigned long vaddr = (unsigned long)p->addr;
+       unsigned long raddr = get_real_addr(vaddr);
+       u32 insn = BRK64_OPCODE_BP;
+
+       ret = write_proc_vm_atomic(p->task, raddr, &insn, sizeof(insn));
+       if (!ret) {
+               pr_err("failed to write memory addr=%lx\n", vaddr);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+static void arch_disarm_uprobe_arm64(struct uprobe *p,
+                                    struct task_struct *task)
+{
+       unsigned long vaddr = (unsigned long)p->addr;
+       unsigned long raddr = get_real_addr(vaddr);
+       int ret;
+
+       ret = write_proc_vm_atomic(task, raddr, &p->opcode, sizeof(p->opcode));
+       if (!ret)
+               pr_err("failed to write memory vaddr=%lx\n", vaddr);
+}
+
+int arch_arm_uprobe(struct uprobe *p)
+{
+       int ret;
+       unsigned long vaddr = (unsigned long)p->addr;
+
+       switch (get_arch_mode(vaddr)) {
+       case AM_THUMB:
+       case AM_ARM:
+               ret = arch_arm_uprobe_arm(p);
+               break;
+       case AM_ARM64:
+               ret = arch_arm_uprobe_arm64(p);
+               break;
+       default:
+               pr_err("Error: unknown mode vaddr=%lx\n", vaddr);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+{
+       unsigned long vaddr = (unsigned long)p->addr;
+
+       switch (get_arch_mode(vaddr)) {
+       case AM_THUMB:
+       case AM_ARM:
+               arch_disarm_uprobe_arm(p, task);
+               break;
+       case AM_ARM64:
+               arch_disarm_uprobe_arm64(p, task);
+               break;
+       default:
+               pr_err("Error: unknown mode vaddr=%lx\n", vaddr);
+               break;
+       }
+}
+
+
+static void arch_prepare_simulate_arm64(struct uprobe *p)
+{
+       if (p->ainsn.prepare)
+               p->ainsn.prepare(p, &p->ainsn);
+}
+
+static int arch_prepare_ss_arm64(struct uprobe *p, u32 insn, u32 __user *utramp)
+{
+       u32 tramp[2];
+
+       /* prepare insn slot */
+       tramp[0] = insn;
+       tramp[1] = BRK64_OPCODE_PSEUDO_SS;
+
+       if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp, 8)) {
+               pr_err("%s: failed to write memory %p\n", __func__, utramp);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+static int arch_uretprobe_set_break_arm64(struct uprobe *p, u32 __user *utramp)
+{
+       int ret;
+       u32 urp_brk = BRK64_OPCODE_URP;
+       unsigned long brk_addr = (unsigned long)(utramp + URP_RET_BREAK_IDX);
+
+       ret = write_proc_vm_atomic(p->task, brk_addr, &urp_brk, sizeof(urp_brk));
+       if (ret != sizeof(urp_brk)) {
+               pr_err("%s failed to write memory %016lx\n",
+                      __func__, brk_addr);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+static int arch_prepare_uprobe_arm64(struct uprobe *p)
+{
+       int ret = 0;
+       struct task_struct *task = p->task;
+       unsigned long vaddr = (unsigned long)p->addr;
+       unsigned long raddr = get_real_addr(vaddr);
+       u32 insn, __user *utramp;
+
+       ret = read_proc_vm_atomic(task, raddr, &insn, sizeof(insn));
+       if (ret != sizeof(insn)) {
+               pr_err("failed to read memory %lx!\n", raddr);
+               return -EINVAL;
+       }
+
+       utramp = swap_slot_alloc(p->sm);
+       if (utramp == NULL) {
+               pr_err("ERROR: cannot allocate trampoline (%016lx)\n", vaddr);
+               return -ENOMEM;
+       }
+
+       switch (arm64_uprobe_decode_insn(insn, &p->ainsn)) {
+       case INSN_REJECTED:     /* insn not supported */
+               ret = -EINVAL;
+               break;
+
+       case INSN_GOOD_NO_SLOT: /* insn need simulation */
+               arch_prepare_simulate_arm64(p);
+               ret = 0;
+               break;
+
+       case INSN_GOOD:         /* instruction uses slot */
+               ret = arch_prepare_ss_arm64(p, insn, utramp);
+               break;
+       };
+
+       if (ret)
+               goto fail;
+
+       ret = arch_uretprobe_set_break_arm64(p, utramp);
+       if (ret)
+               goto fail;
+
+       p->insn = utramp;
+       p->opcode = insn;
+
+       return 0;
+
+fail:
+       swap_slot_free(p->sm, utramp);
+       return ret;
+}
+
+int arch_prepare_uprobe(struct uprobe *p)
+{
+       int ret;
+
+       if (get_arch_mode((unsigned long)p->addr) == AM_ARM64) {
+               ret = arch_prepare_uprobe_arm64(p);
+       } else {
+               ret = arch_prepare_uprobe_arm(p);
+       }
+
+       if (!ret) {
+               /* for uretprobe */
+               add_uprobe_table(p);
+       }
+
+       return ret;
+}
+
+void arch_remove_uprobe(struct uprobe *p)
+{
+       swap_slot_free(p->sm, p->insn);
+}
+
+static void simulate_insn_arm64(struct uprobe *p, struct pt_regs *regs)
+{
+       if (p->ainsn.handler)
+               p->ainsn.handler(p->opcode, (long)p->addr, regs);
+
+       reset_current_uprobe();
+}
+
+static void setup_ss_arm64(struct uprobe *p, struct pt_regs *regs)
+{
+       /* set trampoline */
+       regs->pc = (u64)p->insn;
+
+       set_current_uprobe(p);
+}
+
+static void setup_singlestep(struct uprobe *p, struct pt_regs *regs)
+{
+       if (p->ainsn.handler)
+               simulate_insn_arm64(p, regs);
+       else
+               setup_ss_arm64(p, regs);
+}
+
+static enum dbg_code uprobe_handler_compat(struct pt_regs *regs)
+{
+       pr_err("ARM and THUMB modes not supported\n");
+       return DBG_ERROR;
+}
+
+static enum dbg_code uprobe_handler_arm64(struct pt_regs *regs)
+{
+       struct uprobe *p;
+
+       p = get_uprobe((void *)get_64bit_addr(regs->pc), current->tgid);
+       if (p) {
+               if (!p->pre_handler || !p->pre_handler(p, regs))
+                       setup_singlestep(p, regs);
+       } else {
+               return DBG_ERROR;
+       }
+
+       return DBG_HANDLED;
+}
+
+static enum dbg_code uprobe_handler(struct pt_regs *regs, unsigned int esr)
+{
+       local_irq_enable();
+
+       return compat_user_mode(regs) ?
+                       uprobe_handler_compat(regs) :
+                       uprobe_handler_arm64(regs);
+}
+
+static enum dbg_code uprobe_ss_handler(struct pt_regs *regs, unsigned int esr)
+{
+       struct uprobe *p;
+
+       p = get_current_uprobe();
+       if (p) {
+               regs->pc = (u64)p->addr + 4;
+               reset_current_uprobe();
+       }
+
+       return DBG_HANDLED;
+}
+
+
+static struct brk_hook dbg_up_bp = {
+       .spsr_mask = PSR_MODE_MASK,
+       .spsr_val = PSR_MODE_EL0t,
+       .esr_mask = DBG_BRK_ESR_MASK,
+       .esr_val = DBG_BRK_ESR(BRK_BP),
+       .fn = uprobe_handler,
+};
+
+static struct brk_hook dbg_up_ss = {
+       .spsr_mask = PSR_MODE_MASK,
+       .spsr_val = PSR_MODE_EL0t,
+       .esr_mask = DBG_BRK_ESR_MASK,
+       .esr_val = DBG_BRK_ESR(BRK_PSEUDO_SS),
+       .fn = uprobe_ss_handler,
+};
+
+static struct brk_hook dbg_urp_bp = {
+       .spsr_mask = PSR_MODE_MASK,
+       .spsr_val = PSR_MODE_EL0t,
+       .esr_mask = DBG_BRK_ESR_MASK,
+       .esr_val = DBG_BRK_ESR(BRK_URP),
+       .fn = urp_handler,
+};
+
+
+static void arch_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
+{
+       if (p->ainsn.insn.handler) {
+               regs->pc += 4;
+               p->ainsn.insn.handler(p->opcode, &p->ainsn.insn, regs);
+       } else {
+               regs->pc = (unsigned long)p->insn;
+       }
+}
+
+static int urp_handler_aarch32(struct pt_regs *regs, pid_t tgid)
+{
+       struct uprobe *p;
+       unsigned long vaddr = regs->pc;
+       unsigned long offset_bp = compat_thumb_mode(regs) ?
+                                 0x1a :
+                                 4 * PROBES_TRAMP_RET_BREAK_IDX;
+       unsigned long tramp_addr = vaddr - offset_bp;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       p = get_uprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
+       if (unlikely(p == NULL)) {
+               local_irq_restore(flags);
+
+               pr_info("no_uprobe: Not one of ours: let kernel handle it %lx\n",
+                       vaddr);
+               return 1;
+       }
+
+       get_up(p);
+       local_irq_restore(flags);
+       trampoline_uprobe_handler(p, regs);
+       put_up(p);
+
+       return 0;
+}
+
+static int uprobe_handler_aarch32(struct pt_regs *regs, u32 instr)
+{
+       int ret = 0;
+       struct uprobe *p;
+       unsigned long flags;
+       unsigned long vaddr = regs->pc | !!compat_thumb_mode(regs);
+       pid_t tgid = current->tgid;
+
+       local_irq_enable();
+
+       local_irq_save(flags);
+       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+       if (p) {
+               get_up(p);
+               local_irq_restore(flags);
+
+               if (!p->pre_handler || !p->pre_handler(p, regs))
+                       arch_prepare_singlestep(p, regs);
+
+               put_up(p);
+       } else {
+               local_irq_restore(flags);
+               ret = urp_handler_aarch32(regs, tgid);
+
+               /* check ARM/THUMB CPU mode matches installed probe mode */
+               if (ret == 1) {
+                       vaddr ^= 1;
+
+                       local_irq_save(flags);
+                       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+                       if (p) {
+                               get_up(p);
+                               local_irq_restore(flags);
+                               pr_err("invalid mode: thumb=%d addr=%p insn=%08x\n",
+                                      !!compat_thumb_mode(regs), p->addr, p->opcode);
+                               ret = 0;
+
+                               disarm_uprobe(p, current);
+                               put_up(p);
+                       } else {
+                               local_irq_restore(flags);
+                       }
+               }
+       }
+
+       return ret;
+}
+
+
+static void (*__register_undef_hook)(struct undef_hook *hook);
+static void (*__unregister_undef_hook)(struct undef_hook *hook);
+
+static int undef_hook_once(void)
+{
+       const char *sym;
+
+       sym = "register_undef_hook";
+       __register_undef_hook = (void *)swap_ksyms(sym);
+       if (__register_undef_hook == NULL)
+               goto not_found;
+
+       sym = "unregister_undef_hook";
+       __unregister_undef_hook = (void *)swap_ksyms(sym);
+       if (__unregister_undef_hook == NULL)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       pr_err("ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+
+}
+
+static struct undef_hook undef_hook_arm = {
+       .instr_mask = 0xffffffff,
+       .instr_val = BREAK_ARM,
+       .pstate_mask = COMPAT_PSR_MODE_MASK,
+       .pstate_val = COMPAT_PSR_MODE_USR,
+       .fn = uprobe_handler_aarch32,
+};
+
+static struct undef_hook undef_hook_thumb = {
+       .instr_mask = 0xffff,
+       .instr_val = BREAK_THUMB,
+       .pstate_mask = COMPAT_PSR_MODE_MASK,
+       .pstate_val = COMPAT_PSR_MODE_USR,
+       .fn = uprobe_handler_aarch32,
+};
+
+int swap_arch_init_uprobes(void)
+{
+       int ret;
+
+       ret = undef_hook_once();
+       if (ret)
+               return ret;
+
+       ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk));
+       if (ret)
+               return ret;
+
+       if (!IS_ENABLED(CONFIG_SWAP_KERNEL_IMMUTABLE)) {
+               /* for aarch64 */
+               dbg_brk_hook_reg(&dbg_up_ss);
+               dbg_brk_hook_reg(&dbg_up_bp);
+               dbg_brk_hook_reg(&dbg_urp_bp);
+       } else {
+               pr_err("64-bit uprobes doesn't supported in case of Immutable kernel\n");
+       }
+
+       /* for aarch32 */
+       __register_undef_hook(&undef_hook_arm);
+       __register_undef_hook(&undef_hook_thumb);
+
+       return 0;
+}
+
+void swap_arch_exit_uprobes(void)
+{
+       /* for aarch32 */
+       __unregister_undef_hook(&undef_hook_thumb);
+       __unregister_undef_hook(&undef_hook_arm);
+
+       if (!IS_ENABLED(CONFIG_SWAP_KERNEL_IMMUTABLE)) {
+               /* for aarch64 */
+               dbg_brk_hook_unreg(&dbg_urp_bp);
+               dbg_brk_hook_unreg(&dbg_up_bp);
+               dbg_brk_hook_unreg(&dbg_up_ss);
+       }
+
+       swap_td_raw_unreg(&td_raw);
+}
diff --git a/modules/uprobe/arch/arm64/swap-asm/swap_uprobes.h b/modules/uprobe/arch/arm64/swap-asm/swap_uprobes.h
new file mode 100644 (file)
index 0000000..2a36785
--- /dev/null
@@ -0,0 +1,296 @@
+#ifndef _ASM_ARM64_UPROBES_H
+#define _ASM_ARM64_UPROBES_H
+
+/*
+ * 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, 2014
+ *
+ * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <arch/arm/probes/probes.h>
+#include <arch/arm/uprobe/swap_uprobe.h>
+
+
+#define UP_TRAMP_INSN_CNT  3 /* | opcode | ss_bp | urp_bp | */
+#define UPROBES_TRAMP_LEN  (UP_TRAMP_INSN_CNT * 4) /* 4 - instruction size */
+#define URP_RET_BREAK_IDX  2
+
+
+struct uprobe;
+struct arch_insn;
+struct uretprobe;
+struct task_struct;
+struct uretprobe_instance;
+
+
+typedef unsigned long (uprobes_pstate_check_t)(unsigned long pstate);
+typedef unsigned long (uprobes_condition_check_t)(struct uprobe *p,
+                                                 struct pt_regs *regs);
+typedef void (uprobes_prepare_t)(struct uprobe *p, struct arch_insn *asi);
+typedef void (uprobes_handler_t)(u32 opcode, long addr, struct pt_regs *regs);
+
+
+struct arch_insn {
+       /* arm */
+       struct arch_insn_arm insn;
+
+       /* arm64 */
+       uprobes_pstate_check_t *pstate_cc;
+       uprobes_condition_check_t *check_condn;
+       uprobes_prepare_t *prepare;
+       uprobes_handler_t *handler;
+};
+
+
+typedef u32 uprobe_opcode_t;
+
+static inline u32 swap_get_float(struct pt_regs *regs, unsigned long n)
+{
+       u32 *ptr;
+       register unsigned long w0 asm ("w0");
+
+       switch (n) {
+       case 0:
+               asm volatile("fmov w0, s0");
+               break;
+       case 1:
+               asm volatile("fmov w0, s1");
+               break;
+       case 2:
+               asm volatile("fmov w0, s2");
+               break;
+       case 3:
+               asm volatile("fmov w0, s3");
+               break;
+       case 4:
+               asm volatile("fmov w0, s4");
+               break;
+       case 5:
+               asm volatile("fmov w0, s5");
+               break;
+       case 6:
+               asm volatile("fmov w0, s6");
+               break;
+       case 7:
+               asm volatile("fmov w0, s7");
+               break;
+       default:
+               w0 = 0;
+               ptr = (u32 *)((u64 *)regs->sp + n - 8);
+               if (get_user(w0, ptr))
+                       pr_err("failed to dereference a pointer\n");
+
+               break;
+       }
+
+       return w0;
+}
+
+static inline u64 swap_get_double(struct pt_regs *regs, unsigned long n)
+{
+       u64 *ptr;
+       register unsigned long x0 asm ("x0");
+
+       switch (n) {
+       case 0:
+               asm volatile("fmov x0, d0");
+               break;
+       case 1:
+               asm volatile("fmov x0, d1");
+               break;
+       case 2:
+               asm volatile("fmov x0, d2");
+               break;
+       case 3:
+               asm volatile("fmov x0, d3");
+               break;
+       case 4:
+               asm volatile("fmov x0, d4");
+               break;
+       case 5:
+               asm volatile("fmov x0, d5");
+               break;
+       case 6:
+               asm volatile("fmov x0, d6");
+               break;
+       case 7:
+               asm volatile("fmov x0, d7");
+               break;
+       default:
+               x0 = 0;
+               ptr = (u64 *)regs->sp + n - 8;
+               if (get_user(x0, ptr))
+                       pr_err("failed to dereference a pointer\n");
+
+               break;
+       }
+
+       return x0;
+}
+
+static inline u32 swap_get_urp_float(struct pt_regs *regs)
+{
+       return swap_get_float(regs, 0);
+}
+
+static inline u64 swap_get_urp_double(struct pt_regs *regs)
+{
+       return swap_get_double(regs, 0);
+}
+
+static inline unsigned long swap_get_upc_arm64(struct pt_regs *regs)
+{
+       return regs->pc;
+}
+
+static inline void swap_set_upc_arm64(struct pt_regs *regs, unsigned long val)
+{
+       regs->pc = val;
+}
+
+static inline unsigned long swap_get_uarg_arm64(struct pt_regs *regs,
+                                               unsigned long n)
+{
+       u64 *ptr, val;
+
+       if (n < 8)
+               return regs->regs[n];
+
+       ptr = (u64 *)regs->sp + n - 8;
+       if (get_user(val, ptr))
+               pr_err("failed to dereference a pointer, ptr=%p\n", ptr);
+
+       return val;
+}
+
+static inline void swap_put_uarg_arm64(struct pt_regs *regs, unsigned long n,
+                                      unsigned long val)
+{
+       if (n < 8) {
+               regs->regs[n] = val;
+       } else {
+               u64 *ptr = (u64 *)regs->sp + n - 8;
+               if (put_user(val, ptr))
+                       pr_err("Failed to dereference a pointer, ptr=%p\n", ptr);
+       }
+}
+
+static inline unsigned long swap_get_uret_addr_arm64(struct pt_regs *regs)
+{
+       return regs->regs[30];
+}
+
+static inline void swap_set_uret_addr_arm64(struct pt_regs *regs,
+                                           unsigned long val)
+{
+       regs->regs[30] = val;
+}
+
+static inline unsigned long swap_get_upc(struct pt_regs *regs)
+{
+       if (compat_user_mode(regs))
+               return swap_get_upc_arm(regs);
+       else
+               return swap_get_upc_arm64(regs);
+}
+
+static inline void swap_set_upc(struct pt_regs *regs, unsigned long val)
+{
+       if (compat_user_mode(regs))
+               swap_set_upc_arm(regs, val);
+       else
+               swap_set_upc_arm64(regs, val);
+}
+
+static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
+{
+       if (compat_user_mode(regs))
+               return swap_get_uarg_arm(regs, n);
+       else
+               return swap_get_uarg_arm64(regs, n);
+}
+
+static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
+                                unsigned long val)
+{
+       if (compat_user_mode(regs))
+               return swap_put_uarg_arm(regs, n, val);
+       else
+               return swap_put_uarg_arm64(regs, n, val);
+}
+
+static inline unsigned long swap_get_uret_addr(struct pt_regs *regs)
+{
+       if (compat_user_mode(regs))
+               return swap_get_uret_addr_arm(regs);
+       else
+               return swap_get_uret_addr_arm64(regs);
+}
+
+static inline void swap_set_uret_addr(struct pt_regs *regs, unsigned long val)
+{
+       if (compat_user_mode(regs))
+               swap_set_uret_addr_arm(regs, val);
+       else
+               swap_set_uret_addr_arm64(regs, val);
+}
+
+int arch_prepare_uprobe(struct uprobe *p);
+void arch_remove_uprobe(struct uprobe *p);
+
+static inline int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       WARN(1, "not implemented"); /* FIXME: to implement */
+       return 0;
+}
+
+static inline int longjmp_break_uhandler(struct uprobe *p,
+                                        struct pt_regs *regs)
+{
+       WARN(1, "not implemented"); /* FIXME: to implement */
+       return 0;
+}
+
+
+int arch_arm_uprobe(struct uprobe *p);
+void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
+
+
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
+int arch_prepare_uretprobe(struct uretprobe_instance *ri,
+                          struct pt_regs *regs);
+
+#define arch_urp_check_opcode NULL /* Arch doesn't requires special callback */
+void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task);
+
+static inline void arch_ujprobe_return(void)
+{
+       WARN(1, "not implemented"); /* FIXME: to implement */
+}
+
+int swap_arch_init_uprobes(void);
+void swap_arch_exit_uprobes(void);
+
+
+#endif /* _ASM_ARM64_UPROBES_H */
diff --git a/modules/uprobe/arch/arm64/swap-asm/uprobes-arm64.c b/modules/uprobe/arch/arm64/swap-asm/uprobes-arm64.c
new file mode 100644 (file)
index 0000000..c0173bb
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/kprobes-arm64.c
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+
+#include <asm/ptrace.h>
+#include <uprobe/swap_uprobes.h>
+#include <swap-asm/simulate-insn.h>
+#include <swap-asm/condn-helpers.h>
+
+#include "uprobes-decode.h"
+#include "uprobes-arm64.h"
+
+
+/*
+ * condition check functions for uprobes simulation
+ */
+static unsigned long __check_pstate(struct uprobe *p, struct pt_regs *regs)
+{
+       struct arch_insn *asi = &p->ainsn;
+       unsigned long pstate = regs->pstate & 0xffffffff;
+
+       return asi->pstate_cc(pstate);
+}
+
+static unsigned long __check_cbz(struct uprobe *p, struct pt_regs *regs)
+{
+       return check_cbz((u32)p->opcode, regs);
+}
+
+static unsigned long __check_cbnz(struct uprobe *p, struct pt_regs *regs)
+{
+       return check_cbnz((u32)p->opcode, regs);
+}
+
+static unsigned long __check_tbz(struct uprobe *p, struct pt_regs *regs)
+{
+       return check_tbz((u32)p->opcode, regs);
+}
+
+static unsigned long __check_tbnz(struct uprobe *p, struct pt_regs *regs)
+{
+       return check_tbnz((u32)p->opcode, regs);
+}
+
+/*
+ * prepare functions for instruction simulation
+ */
+static void prepare_none(struct uprobe *p, struct arch_insn *asi)
+{
+}
+
+static void prepare_bcond(struct uprobe *p, struct arch_insn *asi)
+{
+       uprobe_opcode_t insn = p->opcode;
+
+       asi->check_condn = __check_pstate;
+       asi->pstate_cc = probe_condition_checks[insn & 0xf];
+}
+
+static void prepare_cbz_cbnz(struct uprobe *p, struct arch_insn *asi)
+{
+       uprobe_opcode_t insn = p->opcode;
+
+       asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz;
+}
+
+static void prepare_tbz_tbnz(struct uprobe *p, struct arch_insn *asi)
+{
+       uprobe_opcode_t insn = p->opcode;
+
+       asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz;
+}
+
+
+/* Load literal (PC-relative) instructions
+ * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
+ *
+ * opcode[26]: V=0, Load GP registers, simulate them.
+ * Encoding: xx01 1000 xxxx xxxx xxxx xxxx xxxx xxxx
+ *     opcode[31:30]: op = 00, 01 - LDR literal
+ *     opcode[31:30]: op = 10,    - LDRSW literal
+ *
+ * 1.   V=1 -Load FP/AdvSIMD registers
+ *     Encoding: xx01 1100 xxxx xxxx xxxx xxxx xxxx xxxx
+ * 2.   V=0,opc=11 -PRFM(Prefetch literal)
+ *     Encoding: 1101 1000 xxxx xxxx xxxx xxxx xxxx xxxx
+ *     Reject FP/AdvSIMD literal load & PRFM literal.
+ */
+static const struct aarch64_decode_item load_literal_subtable[] = {
+       DECODE_REJECT(0x1C000000, 0x3F000000),
+       DECODE_REJECT(0xD8000000, 0xFF000000),
+       DECODE_LITERAL(0x18000000, 0xBF000000, prepare_none,
+                      simulate_ldr_literal),
+       DECODE_LITERAL(0x98000000, 0xFF000000, prepare_none,
+                      simulate_ldrsw_literal),
+       DECODE_END,
+};
+
+/* AArch64 instruction decode table for kprobes:
+ * The instruction will fall into one of the 3 groups:
+ *  1. Single stepped out-of-the-line slot.
+ *     -Most instructions fall in this group, those does not
+ *      depend on PC address.
+ *
+ *  2. Should be simulated because of PC-relative/literal access.
+ *     -All branching and PC-relative insrtcutions are simulated
+ *      in C code, making use of saved pt_regs
+ *      Catch: SIMD/NEON register context are not saved while
+ *      entering debug exception, so are rejected for now.
+ *
+ *  3. Cannot be probed(not safe) so are rejected.
+ *     - Exception generation and exception return instructions
+ *     - Exclusive monitor(LDREX/STREX family)
+ *
+ */
+static const struct aarch64_decode_item aarch64_decode_table[] = {
+       /*
+        * Data processing - PC relative(literal) addressing:
+        * Encoding: xxx1 0000 xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_LITERAL(0x10000000, 0x1F000000, prepare_none,
+                       simulate_adr_adrp),
+
+       /*
+        * Data processing - Add/Substract Immediate:
+        * Encoding: xxx1 0001 xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x11000000, 0x1F000000),
+
+       /*
+        * Data processing
+        * Encoding:
+        *      xxx1 0010 0xxx xxxx xxxx xxxx xxxx xxxx (Logical)
+        *      xxx1 0010 1xxx xxxx xxxx xxxx xxxx xxxx (Move wide)
+        *      xxx1 0011 0xxx xxxx xxxx xxxx xxxx xxxx (Bitfield)
+        *      xxx1 0011 1xxx xxxx xxxx xxxx xxxx xxxx (Extract)
+        */
+       DECODE_SINGLESTEP(0x12000000, 0x1E000000),
+
+       /*
+        * Data processing - SIMD/FP/AdvSIMD/Crypto-AES/SHA
+        * Encoding: xxx0 111x xxxx xxxx xxxx xxxx xxxx xxxx
+        * Encoding: xxx1 111x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x0E000000, 0x0E000000),
+
+       /*
+        * Data processing - Register
+        * Encoding: xxxx 101x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x0A000000, 0x0E000000),
+
+       /* Branching Instructions
+        *
+        * Encoding:
+        *  x001 01xx xxxx xxxx xxxx xxxx xxxx xxxx (uncondtional Branch)
+        *  x011 010x xxxx xxxx xxxx xxxx xxxx xxxx (compare & branch)
+        *  x011 011x xxxx xxxx xxxx xxxx xxxx xxxx (Test & Branch)
+        *  0101 010x xxxx xxxx xxxx xxxx xxxx xxxx (Conditional, immediate)
+        *  1101 011x xxxx xxxx xxxx xxxx xxxx xxxx (Unconditional,register)
+        */
+       DECODE_BRANCH(0x14000000, 0x7C000000, prepare_none,
+                       simulate_b_bl),
+       DECODE_BRANCH(0x34000000, 0x7E000000, prepare_cbz_cbnz,
+                     simulate_cbz_cbnz),
+       DECODE_BRANCH(0x36000000, 0x7E000000, prepare_tbz_tbnz,
+                     simulate_tbz_tbnz),
+       DECODE_BRANCH(0x54000000, 0xFE000000, prepare_bcond,
+                       simulate_b_cond),
+       DECODE_BRANCH(0xD6000000, 0xFE000000, prepare_none,
+                     simulate_br_blr_ret),
+
+       /* System insn:
+        * Encoding: 1101 0101 00xx xxxx xxxx xxxx xxxx xxxx
+        *
+        * Note: MSR immediate (update PSTATE daif) is not safe handling
+        * within kprobes, rejected.
+        *
+        * Don't re-arrange these decode table entries.
+        */
+       DECODE_REJECT(0xD500401F, 0xFFF8F01F),
+       DECODE_SINGLESTEP(0xD5000000, 0xFFC00000),
+
+       /* Exception Generation:
+        * Encoding:  1101 0100 xxxx xxxx xxxx xxxx xxxx xxxx
+        * Instructions: SVC, HVC, SMC, BRK, HLT, DCPS1, DCPS2, DCPS3
+        */
+       DECODE_REJECT(0xD4000000, 0xFF000000),
+
+       /*
+        * Load/Store - Exclusive monitor
+        * Encoding: xx00 1000 xxxx xxxx xxxx xxxx xxxx xxxx
+        *
+        * Reject exlusive monitor'ed instructions
+        */
+       DECODE_REJECT(0x08000000, 0x3F000000),
+
+       /*
+        * Load/Store - PC relative(literal):
+        * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE(0x18000000, 0x3B000000, load_literal_subtable),
+
+       /*
+        * Load/Store - Register Pair
+        * Encoding:
+        *      xx10 1x00 0xxx xxxx xxxx xxxx xxxx xxxx
+        *      xx10 1x00 1xxx xxxx xxxx xxxx xxxx xxxx
+        *      xx10 1x01 0xxx xxxx xxxx xxxx xxxx xxxx
+        *      xx10 1x01 1xxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_SINGLESTEP(0x28000000, 0x3A000000),
+
+       /*
+        * Load/Store - Register
+        * Encoding:
+        *      xx11 1x00 xx0x xxxx xxxx 00xx xxxx xxxx (unscaled imm)
+        *      xx11 1x00 xx0x xxxx xxxx 01xx xxxx xxxx (imm post-indexed)
+        *      xx11 1x00 xx0x xxxx xxxx 10xx xxxx xxxx (unpriviledged)
+        *      xx11 1x00 xx0x xxxx xxxx 11xx xxxx xxxx (imm pre-indexed)
+        *
+        *      xx11 1x00 xx10 xxxx xxxx xx10 xxxx xxxx (register offset)
+        *
+        *      xx11 1x01 xxxx xxxx xxxx xxxx xxxx xxxx (unsigned imm)
+        */
+       DECODE_SINGLESTEP(0x38000000, 0x3B200000),
+       DECODE_SINGLESTEP(0x38200200, 0x38300300),
+       DECODE_SINGLESTEP(0x39000000, 0x3B000000),
+
+       /*
+        * Load/Store - AdvSIMD
+        * Encoding:
+        *  0x00 1100 0x00 0000 xxxx xxxx xxxx xxxx (Multiple-structure)
+        *  0x00 1100 1x0x xxxx xxxx xxxx xxxx xxxx (Multi-struct post-indexed)
+        *  0x00 1101 0xx0 0000 xxxx xxxx xxxx xxxx (Single-structure))
+        *  0x00 1101 1xxx xxxx xxxx xxxx xxxx xxxx (Single-struct post-index)
+        */
+       DECODE_SINGLESTEP(0x0C000000, 0xBFBF0000),
+       DECODE_SINGLESTEP(0x0C800000, 0xBFA00000),
+       DECODE_SINGLESTEP(0x0D000000, 0xBF9F0000),
+       DECODE_SINGLESTEP(0x0D800000, 0xBF800000),
+
+       /* Unallocated:         xxx0 0xxx xxxx xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT(0x00000000, 0x18000000),
+       DECODE_END,
+};
+
+static int uprobe_decode_insn(u32 insn, struct arch_insn *asi,
+                             const struct aarch64_decode_item *tbl)
+{
+       unsigned int entry, ret = INSN_REJECTED;
+
+       for (entry = 0; !decode_table_end(tbl[entry]); entry++) {
+               if (decode_table_hit(tbl[entry], insn))
+                       break;
+       }
+
+       switch (decode_get_type(tbl[entry])) {
+       case DECODE_TYPE_END:
+       case DECODE_TYPE_REJECT:
+       default:
+               ret = INSN_REJECTED;
+               break;
+
+       case DECODE_TYPE_SINGLESTEP:
+               ret = INSN_GOOD;
+               break;
+
+       case DECODE_TYPE_SIMULATE:
+               asi->prepare = decode_prepare_fn(tbl[entry]);
+               asi->handler = decode_handler_fn(tbl[entry]);
+               ret = INSN_GOOD_NO_SLOT;
+               break;
+
+       case DECODE_TYPE_TABLE:
+               /* recurse with next level decode table */
+               ret = uprobe_decode_insn(insn, asi,
+                                        decode_sub_table(tbl[entry]));
+       };
+
+       return ret;
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ */
+enum uprobe_insn arm64_uprobe_decode_insn(u32 insn, struct arch_insn *asi)
+{
+       return uprobe_decode_insn(insn, asi, aarch64_decode_table);
+}
diff --git a/modules/uprobe/arch/arm64/swap-asm/uprobes-arm64.h b/modules/uprobe/arch/arm64/swap-asm/uprobes-arm64.h
new file mode 100644 (file)
index 0000000..6eed2d6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/kprobes-arm64.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_UPROBES_ARM64_H
+#define _ARM_UPROBES_ARM64_H
+
+
+enum uprobe_insn {
+       INSN_REJECTED,
+       INSN_GOOD_NO_SLOT,
+       INSN_GOOD,
+};
+
+
+enum uprobe_insn arm64_uprobe_decode_insn(u32 insn, struct arch_insn *asi);
+
+
+#endif /* _ARM_UPROBES_ARM64_H */
diff --git a/modules/uprobe/arch/arm64/swap-asm/uprobes-decode.h b/modules/uprobe/arch/arm64/swap-asm/uprobes-decode.h
new file mode 100644 (file)
index 0000000..8564df2
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * Copied from: arch/arm64/kernel/probes-decode.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM64_KERNEL_UPROBES_DECODE_H
+#define _ARM64_KERNEL_UPROBES_DECODE_H
+
+
+#include "swap_uprobes.h"
+
+
+/*
+ * The following definitions and macros are used to build instruction
+ * decoding tables.
+ */
+enum decode_type {
+       DECODE_TYPE_END,
+       DECODE_TYPE_SINGLESTEP,
+       DECODE_TYPE_SIMULATE,
+       DECODE_TYPE_TABLE,
+       DECODE_TYPE_REJECT,
+};
+
+struct aarch64_decode_item;
+
+struct aarch64_decode_header {
+       enum decode_type type;
+       u32 mask;
+       u32 val;
+};
+
+struct aarch64_decode_actions {
+       uprobes_prepare_t *prepare;
+       uprobes_handler_t *handler;
+};
+
+struct aarch64_decode_table {
+       const struct aarch64_decode_item *tbl;
+};
+
+union aarch64_decode_handler {
+       struct aarch64_decode_actions actions;
+       struct aarch64_decode_table table;
+};
+
+struct aarch64_decode_item {
+       struct aarch64_decode_header header;
+       union aarch64_decode_handler decode;
+};
+
+#define decode_get_type(_entry)         ((_entry).header.type)
+
+#define decode_table_end(_entry)               \
+       ((_entry).header.type == DECODE_TYPE_END)
+
+#define decode_table_hit(_entry, insn)         \
+       ((insn & (_entry).header.mask) == (_entry).header.val)
+
+#define decode_prepare_fn(_entry)      ((_entry).decode.actions.prepare)
+#define decode_handler_fn(_entry)      ((_entry).decode.actions.handler)
+#define decode_sub_table(_entry)       ((_entry).decode.table.tbl)
+
+#define DECODE_ADD_HEADER(_type, _val, _mask)  \
+       .header = {                             \
+               .type = _type,                  \
+               .mask = _mask,                  \
+               .val = _val,                    \
+       }
+
+#define DECODE_ADD_ACTION(_prepare, _handler)  \
+       .decode = {                             \
+               .actions = {                    \
+                       .prepare = _prepare,    \
+                       .handler = _handler,    \
+               }                               \
+       }
+
+#define DECODE_ADD_TABLE(_table)               \
+       .decode = {                             \
+               .table = {.tbl = _table}        \
+       }
+
+#define DECODE_REJECT(_v, _m)                                  \
+       { DECODE_ADD_HEADER(DECODE_TYPE_REJECT, _v, _m) }
+
+#define DECODE_SINGLESTEP(_v, _m)                              \
+       { DECODE_ADD_HEADER(DECODE_TYPE_SINGLESTEP, _v, _m) }
+
+#define DECODE_SIMULATE(_v, _m, _p, _h)                                \
+       { DECODE_ADD_HEADER(DECODE_TYPE_SIMULATE, _v, _m),      \
+         DECODE_ADD_ACTION(_p, _h) }
+
+#define DECODE_TABLE(_v, _m, _table)                           \
+       { DECODE_ADD_HEADER(DECODE_TYPE_TABLE, _v, _m),         \
+         DECODE_ADD_TABLE(_table) }
+
+#define DECODE_LITERAL(_v, _m, _p, _h) DECODE_SIMULATE(_v, _m, _p, _h)
+#define DECODE_BRANCH(_v, _m, _p, _h)  DECODE_SIMULATE(_v, _m, _p, _h)
+
+/* should be the last element in decode structure */
+#define DECODE_END     { .header = {.type = DECODE_TYPE_END, } }
+
+#endif /* _ARM64_KERNEL_UPROBES_DECODE_H */
diff --git a/modules/uprobe/arch/x86/swap-asm/swap_sc_patch.c b/modules/uprobe/arch/x86/swap-asm/swap_sc_patch.c
new file mode 100644 (file)
index 0000000..7ffc3fa
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * swap_sc_patch.c
+ * @author Dmitry Kovalenko <d.kovalenko@samsung.com>
+ * @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, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Patching of sys_call_table
+ */
+
+#include <ksyms/ksyms.h>
+#include "swap_sc_patch.h"
+
+static unsigned long original_syscall;
+static int patched_syscall = -1;
+
+/* disable write protection */
+#define swap_disable_wprot()           \
+       asm("pushl %eax \n"             \
+           "movl %cr0, %eax \n"        \
+           "andl $0xfffeffff, %eax \n" \
+           "movl %eax, %cr0 \n"        \
+           "popl %eax");
+
+/* enable write protection */
+#define swap_enable_wprot()           \
+       asm("push %eax \n"             \
+           "movl %cr0, %eax \n"       \
+           "orl $0x00010000, %eax \n" \
+           "movl %eax, %cr0 \n"       \
+           "popl %eax");
+
+void patch_syscall(int syscall_n, unsigned long new_syscall_addr)
+{
+       unsigned long tmp;
+       unsigned long *sc_table;
+
+       /*
+        * Search for sys_call_table (4 bytes before sysenter_after_call)
+        * sysenter_do_call function which locates before sysenter_after_call
+        * has sys_call_table address in call instruction (latest instruction)
+        */
+       tmp = swap_ksyms("sysenter_after_call");
+       sc_table = *(unsigned long **)(tmp - 4);
+
+       swap_disable_wprot();
+       original_syscall = sc_table[syscall_n];
+       sc_table[syscall_n] = new_syscall_addr;
+       patched_syscall = syscall_n;
+       swap_enable_wprot();
+}
+
+void swap_depatch_syscall(void)
+{
+       if (patched_syscall == -1) {
+               printk(KERN_WARNING
+                      "SWAP SC_PATCH: there is no patched syscalls");
+               return;
+       }
+
+       patch_syscall(patched_syscall, original_syscall);
+       patched_syscall = -1;
+}
+
+asmlinkage long sys_swap_func(void)
+{
+       /* Your code here */
+
+       return -ENOSYS;
+}
+
+#define NI_SYSCALL4SWAP 31
+void swap_patch_syscall(void)
+{
+       patch_syscall(NI_SYSCALL4SWAP, (unsigned long)&sys_swap_func);
+}
diff --git a/modules/uprobe/arch/x86/swap-asm/swap_sc_patch.h b/modules/uprobe/arch/x86/swap-asm/swap_sc_patch.h
new file mode 100644 (file)
index 0000000..9b42fac
--- /dev/null
@@ -0,0 +1,2 @@
+void swap_depatch_syscall(void);
+void swap_patch_syscall(void);
diff --git a/modules/uprobe/arch/x86/swap-asm/swap_uprobes.c b/modules/uprobe/arch/x86/swap-asm/swap_uprobes.c
new file mode 100644 (file)
index 0000000..a2d5794
--- /dev/null
@@ -0,0 +1,793 @@
+/**
+ * uprobe/arch/asm-x86/swap_uprobes.c
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Arch-dependent uprobe interface implementation for x86.
+ */
+
+
+#include <linux/kdebug.h>
+
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_td_raw.h>
+#include <kprobe/swap_kprobes.h>
+#include <uprobe/swap_uprobes.h>
+
+#include "swap_uprobes.h"
+
+
+struct save_context {
+       struct pt_regs save_regs;
+       struct pt_regs *ptr_regs;
+       unsigned long val;
+       int (*handler)(struct uprobe *, struct pt_regs *);
+};
+
+/**
+ * @struct uprobe_ctlblk
+ * @brief Uprobe control block
+ */
+struct uprobe_ctlblk {
+       unsigned long flags;            /**< Flags */
+       struct uprobe *p;               /**< Pointer to the uprobe */
+
+       struct save_context ctx;
+};
+
+
+static struct td_raw td_raw;
+
+
+static unsigned long trampoline_addr(struct uprobe *up)
+{
+       return (unsigned long)(up->insn + UPROBES_TRAMP_RET_BREAK_IDX);
+}
+
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
+{
+       return trampoline_addr(&ri->rp->up);
+}
+
+static struct uprobe_ctlblk *current_ucb(void)
+{
+       return (struct uprobe_ctlblk *)swap_td_raw(&td_raw, current);
+}
+
+static struct save_context *current_ctx(void)
+{
+       return &current_ucb()->ctx;
+}
+
+static struct uprobe *get_current_probe(void)
+{
+       return current_ucb()->p;
+}
+
+static void set_current_probe(struct uprobe *p)
+{
+       current_ucb()->p = p;
+}
+
+static void save_current_flags(struct pt_regs *regs)
+{
+       current_ucb()->flags = regs->flags;
+}
+
+static void restore_current_flags(struct pt_regs *regs, unsigned long flags)
+{
+       regs->flags &= ~IF_MASK;
+       regs->flags |= flags & IF_MASK;
+}
+
+/**
+ * @brief Prepares uprobe for x86.
+ *
+ * @param up Pointer to the uprobe.
+ * @return 0 on success,\n
+ * -1 on error.
+ */
+int arch_prepare_uprobe(struct uprobe *p)
+{
+       struct task_struct *task = p->task;
+       u8 tramp[UPROBES_TRAMP_LEN + BP_INSN_SIZE];     /* BP for uretprobe */
+
+       if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
+                                tramp, MAX_INSN_SIZE)) {
+               printk(KERN_ERR "failed to read memory %p!\n", p->addr);
+               return -EINVAL;
+       }
+
+       if (p->check_opcode_cb) {
+               int ret;
+               ret = p->check_opcode_cb((uprobe_opcode_t *)tramp);
+               if (ret)
+                       return ret;
+       }
+
+       tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+
+       p->opcode = tramp[0];
+       p->ainsn.boostable = swap_can_boost(tramp) ? 0 : -1;
+
+       p->insn = swap_slot_alloc(p->sm);
+       if (p->insn == NULL) {
+               printk(KERN_ERR "trampoline out of memory\n");
+               return -ENOMEM;
+       }
+
+       if (!write_proc_vm_atomic(task, (unsigned long)p->insn,
+                                 tramp, sizeof(tramp))) {
+               swap_slot_free(p->sm, p->insn);
+               printk(KERN_INFO "failed to write memory %p!\n", tramp);
+               return -EINVAL;
+       }
+
+       /* for uretprobe */
+       add_uprobe_table(p);
+
+       return 0;
+}
+
+/**
+ * @brief Jump pre-handler.
+ *
+ * @param p Pointer to the uprobe.
+ * @param regs Pointer to CPU register data.
+ * @return 0.
+ */
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct ujprobe *jp = container_of(p, struct ujprobe, up);
+       entry_point_t entry = (entry_point_t)jp->entry;
+       unsigned long args[6];
+
+       /* FIXME some user space apps crash if we clean interrupt bit */
+       /* regs->EREG(flags) &= ~IF_MASK; */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+       trace_hardirqs_off();
+#endif
+
+       /* read first 6 args from stack */
+       if (!read_proc_vm_atomic(current, regs->EREG(sp) + 4,
+                                args, sizeof(args)))
+               printk(KERN_WARNING
+                      "failed to read user space func arguments %lx!\n",
+                      regs->sp + 4);
+
+       if (entry)
+               entry(args[0], args[1], args[2], args[3], args[4], args[5]);
+       else
+               arch_ujprobe_return();
+
+       return 0;
+}
+
+/**
+ * @brief Check opcode is applicable for retprobe
+ *
+ * @param opcode Pointer to opcode
+ * @return result of checking
+ */
+int arch_urp_check_opcode(uprobe_opcode_t *opcode)
+{
+       enum { call_relative_opcode = 0xe8 };
+
+       /* do not set uprobe for retprobe if insn is relative call */
+       if (opcode[0] == call_relative_opcode) {
+               pr_err("failed to set retprobe to relative call\n");
+               return -ENOEXEC;
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Prepares uretprobe for x86.
+ *
+ * @param ri Pointer to the uretprobe instance.
+ * @param regs Pointer to CPU register data.
+ * @return Void.
+ */
+int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       /* Replace the return addr with trampoline addr */
+       unsigned long ra = trampoline_addr(&ri->rp->up);
+       unsigned long ret_addr;
+       ri->sp = (kprobe_opcode_t *)regs->sp;
+
+       if (get_user(ret_addr, (unsigned long *)regs->sp)) {
+               pr_err("failed to read user space func ra %lx addr=%p!\n",
+                      regs->sp, ri->rp->up.addr);
+               return -EINVAL;
+       }
+
+       if (put_user(ra, (unsigned long *)regs->sp)) {
+               pr_err("failed to write user space func ra %lx!\n", regs->sp);
+               return -EINVAL;
+       }
+
+       ri->ret_addr = (uprobe_opcode_t *)ret_addr;
+
+       return 0;
+}
+
+static bool get_long(struct task_struct *task,
+                    unsigned long vaddr, unsigned long *val)
+{
+       return sizeof(*val) != read_proc_vm_atomic(task, vaddr,
+                                                  val, sizeof(*val));
+}
+
+static bool put_long(struct task_struct *task,
+                    unsigned long vaddr, unsigned long *val)
+{
+       return sizeof(*val) != write_proc_vm_atomic(task, vaddr,
+                                                   val, sizeof(*val));
+}
+
+/**
+ * @brief Disarms uretprobe on x86 arch.
+ *
+ * @param ri Pointer to the uretprobe instance.
+ * @param task Pointer to the task for which the probe.
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task)
+{
+       unsigned long ret_addr;
+       unsigned long sp = (unsigned long)ri->sp;
+       unsigned long tramp_addr = trampoline_addr(&ri->rp->up);
+
+       if (get_long(task, sp, &ret_addr)) {
+               printk(KERN_INFO "---> %s (%d/%d): failed to read stack from %08lx\n",
+                      task->comm, task->tgid, task->pid, sp);
+               return -EFAULT;
+       }
+
+       if (tramp_addr == ret_addr) {
+               if (put_long(task, sp, (unsigned long *)&ri->ret_addr)) {
+                       printk(KERN_INFO "---> %s (%d/%d): failed to write "
+                              "orig_ret_addr to %08lx",
+                              task->comm, task->tgid, task->pid, sp);
+                       return -EFAULT;
+               }
+       } else {
+               printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at sp = %08lx\n",
+                      task->comm, task->tgid, task->pid, sp);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Gets trampoline address.
+ *
+ * @param p Pointer to the uprobe.
+ * @param regs Pointer to CPU register data.
+ * @return Trampoline address.
+ */
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
+{
+       return trampoline_addr(p);
+}
+
+/**
+ * @brief Restores return address.
+ *
+ * @param orig_ret_addr Original return address.
+ * @param regs Pointer to CPU register data.
+ * @return Void.
+ */
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
+{
+       regs->EREG(ip) = orig_ret_addr;
+}
+
+/**
+ * @brief Removes uprobe.
+ *
+ * @param up Pointer to the target uprobe.
+ * @return Void.
+ */
+void arch_remove_uprobe(struct uprobe *p)
+{
+       swap_slot_free(p->sm, p->insn);
+}
+
+int arch_arm_uprobe(struct uprobe *p)
+{
+       int ret;
+       uprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
+       unsigned long vaddr = (unsigned long)p->addr;
+
+       ret = write_proc_vm_atomic(p->task, vaddr, &insn, sizeof(insn));
+       if (!ret) {
+               pr_err("arch_arm_uprobe: failed to write memory tgid=%u vaddr=%08lx\n",
+                      p->task->tgid, vaddr);
+
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+{
+       int ret;
+       unsigned long vaddr = (unsigned long)p->addr;
+
+       ret = write_proc_vm_atomic(task, vaddr, &p->opcode, sizeof(p->opcode));
+       if (!ret) {
+               pr_err("arch_disarm_uprobe: failed to write memory tgid=%u, vaddr=%08lx\n",
+                      task->tgid, vaddr);
+       }
+}
+
+static void set_user_jmp_op(void *from, void *to)
+{
+       struct __arch_jmp_op {
+               char op;
+               long raddr;
+       } __packed jop;
+
+       jop.raddr = (long)(to) - ((long)(from) + 5);
+       jop.op = RELATIVEJUMP_INSTRUCTION;
+
+       if (put_user(jop.op, (char *)from) ||
+           put_user(jop.raddr, (long *)(from + 1)))
+               pr_err("failed to write jump opcode to user space %p\n", from);
+}
+
+static void resume_execution(struct uprobe *p,
+                            struct pt_regs *regs,
+                            unsigned long flags)
+{
+       unsigned long *tos, tos_dword = 0;
+       unsigned long copy_eip = (unsigned long)p->insn;
+       unsigned long orig_eip = (unsigned long)p->addr;
+       uprobe_opcode_t insns[2];
+
+       regs->EREG(flags) &= ~TF_MASK;
+
+       tos = (unsigned long *)&tos_dword;
+       if (get_user(tos_dword, (unsigned long *)regs->sp)) {
+               pr_err("failed to read from user space sp=%lx!\n", regs->sp);
+               return;
+       }
+
+       if (get_user(*(unsigned short *)insns, (unsigned short *)p->insn)) {
+               pr_err("failed to read first 2 opcodes %p!\n", p->insn);
+               return;
+       }
+
+       switch (insns[0]) {
+       case 0x9c: /* pushfl */
+               *tos &= ~(TF_MASK | IF_MASK);
+               *tos |= flags & (TF_MASK | IF_MASK);
+               break;
+       case 0xc2: /* iret/ret/lret */
+       case 0xc3:
+       case 0xca:
+       case 0xcb:
+       case 0xcf:
+       case 0xea: /* jmp absolute -- eip is correct */
+               /* eip is already adjusted, no more changes required */
+               p->ainsn.boostable = 1;
+               goto no_change;
+       case 0xe8: /* call relative - Fix return addr */
+               *tos = orig_eip + (*tos - copy_eip);
+               break;
+       case 0x9a: /* call absolute -- same as call absolute, indirect */
+               *tos = orig_eip + (*tos - copy_eip);
+
+               if (put_user(tos_dword, (unsigned long *)regs->sp)) {
+                       pr_err("failed to write dword to sp=%lx\n", regs->sp);
+                       return;
+               }
+
+               goto no_change;
+       case 0xff:
+               if ((insns[1] & 0x30) == 0x10) {
+                       /*
+                        * call absolute, indirect
+                        * Fix return addr; eip is correct.
+                        * But this is not boostable
+                        */
+                       *tos = orig_eip + (*tos - copy_eip);
+
+                       if (put_user(tos_dword, (unsigned long *)regs->sp)) {
+                               pr_err("failed to write dword to sp=%lx\n", regs->sp);
+                               return;
+                       }
+
+                       goto no_change;
+               } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
+                                                          * indirect */
+                          ((insns[1] & 0x31) == 0x21)) {
+                       /* jmp far, absolute indirect */
+                       /* eip is correct. And this is boostable */
+                       p->ainsn.boostable = 1;
+                       goto no_change;
+               }
+       case 0xf3:
+               if (insns[1] == 0xc3)
+                       /* repz ret special handling: no more changes */
+                       goto no_change;
+               break;
+       default:
+               break;
+       }
+
+       if (put_user(tos_dword, (unsigned long *)regs->sp)) {
+               pr_err("failed to write dword to sp=%lx\n", regs->sp);
+               return;
+       }
+
+       if (p->ainsn.boostable == 0) {
+               if ((regs->EREG(ip) > copy_eip) && (regs->EREG(ip) - copy_eip) +
+                   5 < MAX_INSN_SIZE) {
+                       /*
+                        * These instructions can be executed directly if it
+                        * jumps back to correct address.
+                        */
+                       set_user_jmp_op((void *) regs->EREG(ip),
+                                       (void *)orig_eip +
+                                       (regs->EREG(ip) - copy_eip));
+                       p->ainsn.boostable = 1;
+               } else {
+                       p->ainsn.boostable = -1;
+               }
+       }
+
+       regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
+
+no_change:
+       return;
+}
+
+static void prepare_tramp(struct uprobe *p, struct pt_regs *regs)
+{
+       regs->ip = (unsigned long)p->insn;
+}
+
+static void prepare_ss(struct pt_regs *regs)
+{
+       /* set single step mode */
+       regs->flags |= TF_MASK;
+       regs->flags &= ~IF_MASK;
+}
+
+
+static unsigned long resume_userspace_addr;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
+static void __rcu_nmi_enter(void) {}
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
+#error "This kernel is not support"
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */
+static void (*__rcu_nmi_enter)(void);
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */
+
+static void __used __up_handler(void)
+{
+       struct pt_regs *regs = current_ctx()->ptr_regs;
+       struct thread_info *tinfo = current_thread_info();
+       struct uprobe *p = current_ucb()->p;
+
+       /* restore KS regs */
+       *regs = current_ctx()->save_regs;
+
+       /* call handler */
+       current_ctx()->handler(p, regs);
+
+       /* resume_userspace */
+       asm volatile (
+               "movl %0, %%esp\n"
+               "movl %1, %%ebp\n"
+               "jmpl *%2\n"
+               : /* No outputs. */
+               : "r" (regs), "r" (tinfo) , "r" (resume_userspace_addr)
+       );
+}
+
+void up_handler(void);
+__asm(
+       "up_handler:\n"
+       /* skip hex tractor-driver bytes to make some free space (skip regs) */
+       "sub $0x300, %esp\n"
+       "jmp __up_handler\n"
+);
+
+static int exceptions_handler(struct pt_regs *regs,
+                             int (*handler)(struct uprobe *, struct pt_regs *))
+{
+       /* save regs */
+       current_ctx()->save_regs = *regs;
+       current_ctx()->ptr_regs = regs;
+
+       /* set handler */
+       current_ctx()->handler = handler;
+
+       /* setup regs to return to KS */
+       regs->ip = (unsigned long)up_handler;
+       regs->ds = __USER_DS;
+       regs->es = __USER_DS;
+       regs->fs = __KERNEL_PERCPU;
+       regs->cs = __KERNEL_CS | get_kernel_rpl();
+       regs->gs = 0;
+       regs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
+
+       /*
+        * Here rcu_nmi_enter() call is needed, because we change
+        * US context to KS context as a result rcu_nmi_exit() will
+        * be called on exiting exception and rcu_nmi_enter() and
+        * rcu_nmi_exit() calls must be consistent
+        */
+       __rcu_nmi_enter();
+
+       return 1;
+}
+
+static int uprobe_handler_retprobe(struct uprobe *p, struct pt_regs *regs)
+{
+       int ret;
+
+       ret = trampoline_uprobe_handler(p, regs);
+       set_current_probe(NULL);
+       put_up(p);
+
+       return ret;
+}
+
+static int uprobe_handler_part2(struct uprobe *p, struct pt_regs *regs)
+{
+       if (p->pre_handler && !p->pre_handler(p, regs)) {
+               prepare_tramp(p, regs);
+               if (p->ainsn.boostable == 1 && !p->post_handler)
+                       goto exit_and_put_up;
+
+               save_current_flags(regs);
+               set_current_probe(p);
+               prepare_ss(regs);
+
+               return 1;
+       }
+
+exit_and_put_up:
+       set_current_probe(NULL);
+       put_up(p);
+       return 1;
+}
+
+static int uprobe_handler_atomic(struct pt_regs *regs)
+{
+       pid_t tgid = current->tgid;
+       unsigned long vaddr = regs->ip - 1;
+       struct uprobe *p = get_uprobe((void *)vaddr, tgid);
+
+       if (p) {
+               get_up(p);
+               if (p->pre_handler) {
+                       set_current_probe(p);
+                       exceptions_handler(regs, uprobe_handler_part2);
+               } else {
+                       uprobe_handler_part2(p, regs);
+               }
+       } else {
+               unsigned long tramp_vaddr;
+
+               tramp_vaddr = vaddr - UPROBES_TRAMP_RET_BREAK_IDX;
+               p = get_uprobe_by_insn_slot((void *)tramp_vaddr, tgid, regs);
+               if (p == NULL) {
+                       pr_info("no_uprobe\n");
+                       return 0;
+               }
+
+               set_current_probe(p);
+               get_up(p);
+               exceptions_handler(regs, uprobe_handler_retprobe);
+       }
+
+       return 1;
+}
+
+static int post_uprobe_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       unsigned long flags = current_ucb()->flags;
+
+       resume_execution(p, regs, flags);
+       restore_current_flags(regs, flags);
+
+       /* reset current probe */
+       set_current_probe(NULL);
+       put_up(p);
+
+       return 1;
+}
+
+static int post_uprobe_handler_atomic(struct pt_regs *regs)
+{
+       struct uprobe *p = get_current_probe();
+
+       if (p) {
+               exceptions_handler(regs, post_uprobe_handler);
+       } else {
+               pr_info("task[%u %u %s] current uprobe is not found\n",
+                       current->tgid, current->pid, current->comm);
+       }
+
+       return !!p;
+}
+
+static int uprobe_exceptions_notify(struct notifier_block *self,
+                                   unsigned long val, void *data)
+{
+       struct die_args *args = (struct die_args *)data;
+       int ret = NOTIFY_DONE;
+
+       if (args->regs == NULL || !swap_user_mode(args->regs))
+               return ret;
+
+       switch (val) {
+#ifdef CONFIG_KPROBES
+       case DIE_INT3:
+#else
+       case DIE_TRAP:
+#endif
+               if (uprobe_handler_atomic(args->regs))
+                       ret = NOTIFY_STOP;
+               break;
+       case DIE_DEBUG:
+               if (post_uprobe_handler_atomic(args->regs))
+                       ret = NOTIFY_STOP;
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static struct notifier_block uprobe_exceptions_nb = {
+       .notifier_call = uprobe_exceptions_notify,
+       .priority = INT_MAX
+};
+
+struct up_valid_struct {
+       struct uprobe *p;
+       bool found;
+};
+
+static int __uprobe_is_valid(struct uprobe *p, void *data)
+{
+       struct up_valid_struct *valid = (struct up_valid_struct *)data;
+
+       if (valid->p == p) {
+               valid->found = true;
+               return 1;
+       }
+
+       return 0;
+}
+
+static bool uprobe_is_valid(struct uprobe *p)
+{
+       struct up_valid_struct valid = {
+               .p = p,
+               .found = false,
+       };
+
+       for_each_uprobe(__uprobe_is_valid, (void *)&valid);
+
+       return valid.found;
+}
+
+static int do_exit_handler(struct kprobe *kp, struct pt_regs *regs)
+{
+       struct uprobe *p;
+
+       p = get_current_probe();
+       if (p && uprobe_is_valid(p)) {
+               set_current_probe(NULL);
+               put_up(p);
+       }
+
+       return 0;
+}
+
+static struct kprobe kp_do_exit = {
+       .pre_handler = do_exit_handler
+};
+
+/**
+ * @brief Registers notify.
+ *
+ * @return register_die_notifier result.
+ */
+int swap_arch_init_uprobes(void)
+{
+       int ret;
+       const char *sym;
+
+       sym = "resume_userspace";
+       resume_userspace_addr = swap_ksyms(sym);
+       if (resume_userspace_addr == 0)
+               goto not_found;
+
+       sym = "do_exit";
+       kp_do_exit.addr = swap_ksyms(sym);
+       if (kp_do_exit.addr == 0)
+               goto not_found;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+       sym = "rcu_nmi_enter";
+       __rcu_nmi_enter = (void *)swap_ksyms(sym);
+       if (__rcu_nmi_enter == NULL)
+               goto not_found;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
+
+       ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk));
+       if (ret)
+               return ret;
+
+       ret = register_die_notifier(&uprobe_exceptions_nb);
+       if (ret)
+               goto unreg_td;
+
+       ret = swap_register_kprobe(&kp_do_exit);
+       if (ret)
+               goto unreg_exeption;
+
+       return 0;
+
+unreg_exeption:
+       unregister_die_notifier(&uprobe_exceptions_nb);
+unreg_td:
+       swap_td_raw_unreg(&td_raw);
+       return ret;
+
+not_found:
+       pr_err("symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+/**
+ * @brief Unregisters notify.
+ *
+ * @return Void.
+ */
+void swap_arch_exit_uprobes(void)
+{
+       swap_unregister_kprobe(&kp_do_exit);
+       unregister_die_notifier(&uprobe_exceptions_nb);
+       swap_td_raw_unreg(&td_raw);
+}
+
diff --git a/modules/uprobe/arch/x86/swap-asm/swap_uprobes.h b/modules/uprobe/arch/x86/swap-asm/swap_uprobes.h
new file mode 100644 (file)
index 0000000..7a153de
--- /dev/null
@@ -0,0 +1,163 @@
+/**
+ * @file uprobe/arch/asm-x86/swap_uprobes.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Arch-dependent uprobe interface declaration.
+ */
+
+#ifndef _X86_SWAP_UPROBES_H
+#define _X86_SWAP_UPROBES_H
+
+
+#include <swap-asm/swap_kprobes.h>      /* FIXME: for UPROBES_TRAMP_LEN */
+
+
+struct uprobe;
+struct uretprobe;
+struct uretprobe_instance;
+
+typedef u8 uprobe_opcode_t;
+
+/**
+ * @struct arch_insn
+ * @brief Architecture depend copy of original instruction.
+ * @var arch_insn::insn
+ * Copy of the original instruction.
+ * @var arch_insn::boostable
+ * If this flag is not 0, this kprobe can be boost when its
+ * post_handler and break_handler is not set.
+ */
+struct arch_insn {
+       int boostable;
+};
+
+
+static inline u32 swap_get_urp_float(struct pt_regs *regs)
+{
+       u32 st0;
+
+       asm volatile ("fstps    %0" : "=m" (st0));
+
+       return st0;
+}
+
+static inline u64 swap_get_urp_double(struct pt_regs *regs)
+{
+       u64 st1;
+
+       asm volatile ("fstpl    %0" : "=m" (st1));
+
+       return st1;
+}
+
+static inline void arch_ujprobe_return(void)
+{
+}
+
+int arch_prepare_uprobe(struct uprobe *up);
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
+static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
+{
+       return 0;
+}
+
+static inline int arch_opcode_analysis_uretprobe(struct uretprobe *rp)
+{
+       return 0;
+}
+
+int arch_urp_check_opcode(uprobe_opcode_t *opcode);
+int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task);
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
+void arch_remove_uprobe(struct uprobe *up);
+int arch_arm_uprobe(struct uprobe *p);
+void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
+
+static inline unsigned long swap_get_upc(struct pt_regs *regs)
+{
+       return regs->ip;
+}
+
+static inline void swap_set_upc(struct pt_regs *regs, unsigned long val)
+{
+       regs->ip = val;
+}
+
+static inline unsigned long swap_get_ustack_val(struct pt_regs *regs,
+                                               unsigned long n)
+{
+       u32 *ptr, addr = 0;
+
+       ptr = (u32 *)regs->sp + n;
+       if (get_user(addr, ptr))
+               pr_err("Failed to dereference a pointer, ptr=%p\n", ptr);
+
+       return addr;
+}
+
+static inline void swap_set_ustack_val(struct pt_regs *regs, unsigned long n,
+                                      unsigned long val)
+{
+       u32 *ptr;
+
+       ptr = (u32 *)regs->sp + n;
+       if (put_user(val, ptr))
+               pr_err("Failed to dereference a pointer, ptr=%p\n", ptr);
+}
+
+static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
+{
+       /* 1 - return address saved on top of the stack */
+       return swap_get_ustack_val(regs, n + 1);
+}
+
+static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
+                                unsigned long val)
+{
+       /* 1 - return address saved on top of the stack */
+       swap_set_ustack_val(regs, n + 1, val);
+}
+
+static inline unsigned long swap_get_uret_addr(struct pt_regs *regs)
+{
+       return swap_get_ustack_val(regs, 0);
+}
+
+static inline void swap_set_uret_addr(struct pt_regs *regs, unsigned long val)
+{
+       swap_set_ustack_val(regs, 0, val);
+}
+
+
+int swap_arch_init_uprobes(void);
+void swap_arch_exit_uprobes(void);
+
+#endif /* _X86_SWAP_UPROBES_H */
diff --git a/modules/uprobe/swap_uaccess.h b/modules/uprobe/swap_uaccess.h
new file mode 100644 (file)
index 0000000..7a9215e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+
+static const char *strdup_from_user(const char __user *user_s, gfp_t gfp)
+{
+       enum { max_str_len = 1024 };
+       char *str;
+       int len_s, ret;
+
+       len_s = strnlen_user(user_s, max_str_len - 1);
+       str = kmalloc(len_s + 1, gfp);
+       if (str == NULL)
+               return NULL;
+
+       ret = copy_from_user(str, user_s, len_s);
+       if (ret < 0) {
+               kfree(str);
+               return NULL;
+       }
+
+       str[len_s] = '\0';
+
+       return str;
+}
diff --git a/modules/uprobe/swap_uprobes.c b/modules/uprobe/swap_uprobes.c
new file mode 100644 (file)
index 0000000..d25b2d7
--- /dev/null
@@ -0,0 +1,988 @@
+/**
+ * uprobe/swap_uprobes.c
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Uprobes implementation.
+ */
+
+
+#include <linux/hash.h>
+#include <linux/sched.h>
+#include <linux/mempolicy.h>
+#include <linux/module.h>
+
+#include <master/swap_initializer.h>
+#include <kprobe/swap_slots.h>
+#include <kprobe/swap_kdebug.h>
+#include <kprobe/swap_kprobes_deps.h>
+
+#include <swap-asm/swap_uprobes.h>
+
+#include "swap_uprobes.h"
+
+
+enum {
+       UPROBE_HASH_BITS  = 10,
+       UPROBE_TABLE_SIZE = (1 << UPROBE_HASH_BITS)
+};
+
+static DEFINE_RWLOCK(st_lock);
+static struct hlist_head slot_table[UPROBE_TABLE_SIZE];
+static DEFINE_MUTEX(up_mtx);   /* Protects uprobe_table */
+struct hlist_head uprobe_table[UPROBE_TABLE_SIZE];
+
+static DEFINE_MUTEX(urp_mtx);  /* Protects uretprobe_inst_table */
+static struct hlist_head uretprobe_inst_table[UPROBE_TABLE_SIZE];
+
+#define DEBUG_PRINT_HASH_TABLE 0
+
+#if DEBUG_PRINT_HASH_TABLE
+void print_uprobe_hash_table(void)
+{
+       int i;
+       struct hlist_head *head;
+       struct uprobe *p;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       /* print uprobe table */
+       for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
+               head = &uprobe_insn_slot_table[i];
+               swap_hlist_for_each_entry_rcu(p, node, head, is_hlist) {
+                       printk(KERN_INFO "####### find U tgid=%u, addr=0x%lx\n",
+                                       p->task->tgid, (unsigned long)p->addr);
+               }
+       }
+}
+#endif
+
+/*
+ * Keep all fields in the uprobe consistent
+ */
+static inline void copy_uprobe(struct uprobe *old_p, struct uprobe *p)
+{
+       memcpy(&p->opcode, &old_p->opcode, sizeof(uprobe_opcode_t));
+       memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_insn));
+       memcpy(&p->insn, &old_p->insn, sizeof(uprobe_opcode_t *));
+}
+
+/*
+ * Aggregate handlers for multiple uprobes support - these handlers
+ * take care of invoking the individual uprobe handlers on p->list
+ */
+static int aggr_pre_uhandler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct uprobe *up;
+       int ret;
+
+       list_for_each_entry_rcu(up, &p->list, list) {
+               if (up->pre_handler) {
+                       ret = up->pre_handler(up, regs);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void aggr_post_uhandler(struct uprobe *p, struct pt_regs *regs,
+                              unsigned long flags)
+{
+       struct uprobe *up;
+
+       list_for_each_entry_rcu(up, &p->list, list) {
+               if (up->post_handler)
+                       up->post_handler(up, regs, flags);
+       }
+}
+
+static int aggr_fault_uhandler(struct uprobe *p,
+                              struct pt_regs *regs,
+                              int trapnr)
+{
+       return 0;
+}
+
+static int aggr_break_uhandler(struct uprobe *p, struct pt_regs *regs)
+{
+       return 0;
+}
+
+/*
+ * Add the new probe to old_p->list. Fail if this is the
+ * second ujprobe at the address - two ujprobes can't coexist
+ */
+static int add_new_uprobe(struct uprobe *old_p, struct uprobe *p)
+{
+       if (p->break_handler) {
+               if (old_p->break_handler)
+                       return -EEXIST;
+
+               list_add_tail_rcu(&p->list, &old_p->list);
+               old_p->break_handler = aggr_break_uhandler;
+       } else {
+               list_add_rcu(&p->list, &old_p->list);
+       }
+
+       if (p->post_handler && !old_p->post_handler)
+               old_p->post_handler = aggr_post_uhandler;
+
+       return 0;
+}
+
+/*
+ * Fill in the required fields of the "manager uprobe". Replace the
+ * earlier uprobe in the hlist with the manager uprobe
+ */
+static inline void add_aggr_uprobe(struct uprobe *ap, struct uprobe *p)
+{
+       copy_uprobe(p, ap);
+
+       ap->addr = p->addr;
+       ap->pre_handler = aggr_pre_uhandler;
+       ap->fault_handler = aggr_fault_uhandler;
+
+       if (p->post_handler)
+               ap->post_handler = aggr_post_uhandler;
+
+       if (p->break_handler)
+               ap->break_handler = aggr_break_uhandler;
+
+       INIT_LIST_HEAD(&ap->list);
+       list_add_rcu(&p->list, &ap->list);
+
+       hlist_replace_rcu(&p->hlist, &ap->hlist);
+}
+
+/*
+ * This is the second or subsequent uprobe at the address - handle
+ * the intricacies
+ */
+static int register_aggr_uprobe(struct uprobe *old_p, struct uprobe *p)
+{
+       int ret = 0;
+
+       if (old_p->pre_handler == aggr_pre_uhandler) {
+               copy_uprobe(old_p, p);
+               ret = add_new_uprobe(old_p, p);
+       } else {
+               struct uprobe *uap = kzalloc(sizeof(*uap), GFP_KERNEL);
+               if (!uap)
+                       return -ENOMEM;
+
+               uap->task = p->task;
+               add_aggr_uprobe(uap, old_p);
+               copy_uprobe(uap, p);
+               ret = add_new_uprobe(uap, p);
+       }
+
+       return ret;
+}
+
+static int arm_uprobe(struct uprobe *p)
+{
+       return arch_arm_uprobe(p);
+}
+
+/**
+ * @brief Disarms uprobe.
+ *
+ * @param p Pointer to the uprobe.
+ * @param task Pointer to the target task.
+ * @return Void.
+ */
+void disarm_uprobe(struct uprobe *p, struct task_struct *task)
+{
+       arch_disarm_uprobe(p, task);
+}
+EXPORT_SYMBOL_GPL(disarm_uprobe);
+
+static void init_uprobes_insn_slots(void)
+{
+       int i;
+       for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
+               INIT_HLIST_HEAD(&slot_table[i]);
+}
+
+static void init_uprobe_table(void)
+{
+       int i;
+       for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
+               INIT_HLIST_HEAD(&uprobe_table[i]);
+}
+
+static void init_uretprobe_inst_table(void)
+{
+       int i;
+       for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
+               INIT_HLIST_HEAD(&uretprobe_inst_table[i]);
+}
+
+/**
+ * @brief Gets uprobe.
+ *
+ * @param addr Probe's address.
+ * @param tgid Probes's thread group ID.
+ * @return Pointer to the uprobe on success,\n
+ * NULL otherwise.
+ */
+struct uprobe *get_uprobe(void *addr, pid_t tgid)
+{
+       struct hlist_head *head;
+       struct uprobe *p;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       head = &uprobe_table[hash_ptr(addr, UPROBE_HASH_BITS)];
+       swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
+               if (p->addr == addr && p->task->tgid == tgid)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/**
+ * @brief Adds uprobe to hlist when trampoline have been made.
+ *
+ * @param p Pointer to the uprobe.
+ * @return Void.
+ */
+void add_uprobe_table(struct uprobe *p)
+{
+       write_lock(&st_lock);
+       hlist_add_head(&p->is_hlist,
+                      &slot_table[hash_ptr(p->insn, UPROBE_HASH_BITS)]);
+       write_unlock(&st_lock);
+}
+
+static void del_uprobe_table(struct uprobe *p)
+{
+       write_lock(&st_lock);
+       if (!hlist_unhashed(&p->is_hlist))
+               hlist_del(&p->is_hlist);
+       write_unlock(&st_lock);
+}
+
+/**
+ * @brief Gets uprobe by insn slot.
+ *
+ * @param addr Probe's address.
+ * @param tgit Probe's thread group ID.
+ * @param regs Pointer to CPU registers data.
+ * @return Pointer to the uprobe on success,\n
+ * NULL otherwise.
+ */
+struct uprobe *get_uprobe_by_insn_slot(void *addr,
+                                      pid_t tgid,
+                                      struct pt_regs *regs)
+{
+       struct hlist_head *head;
+       struct uprobe *p;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       read_lock(&st_lock);
+       head = &slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
+       swap_hlist_for_each_entry(p, node, head, is_hlist) {
+               if (p->insn == addr && p->task->tgid == tgid) {
+                       read_unlock(&st_lock);
+                       return p;
+               }
+       }
+       read_unlock(&st_lock);
+
+       return NULL;
+}
+
+
+static void remove_uprobe(struct uprobe *up)
+{
+       del_uprobe_table(up);
+       arch_remove_uprobe(up);
+}
+
+static struct hlist_head *uretprobe_inst_table_head(void *hash_key)
+{
+       return &uretprobe_inst_table[hash_ptr(hash_key, UPROBE_HASH_BITS)];
+}
+
+/* Called with urp_mtx held */
+static void add_urp_inst(struct uretprobe_instance *ri)
+{
+       /*
+        * Remove rp inst off the free list -
+        * Add it back when probed function returns
+        */
+       hlist_del(&ri->uflist);
+
+       /* Add rp inst onto table */
+       INIT_HLIST_NODE(&ri->hlist);
+       hlist_add_head(&ri->hlist, uretprobe_inst_table_head(ri->task->mm));
+
+       /* Also add this rp inst to the used list. */
+       INIT_HLIST_NODE(&ri->uflist);
+       hlist_add_head(&ri->uflist, &ri->rp->used_instances);
+}
+
+/* Called with urp_mtx held */
+static void recycle_urp_inst(struct uretprobe_instance *ri)
+{
+       if (ri->rp) {
+               hlist_del(&ri->hlist);
+               /* remove rp inst off the used list */
+               hlist_del(&ri->uflist);
+               /* put rp inst back onto the free list */
+               INIT_HLIST_NODE(&ri->uflist);
+               hlist_add_head(&ri->uflist, &ri->rp->free_instances);
+       }
+}
+
+/* Called with urp_mtx held */
+static struct uretprobe_instance *get_used_urp_inst(struct uretprobe *rp)
+{
+       struct uretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
+               return ri;
+       }
+
+       return NULL;
+}
+
+/**
+ * @brief Gets free uretprobe instanse for the specified uretprobe without
+ * allocation. Called with urp_mtx held.
+ *
+ * @param rp Pointer to the uretprobe.
+ * @return Pointer to the uretprobe_instance on success,\n
+ * NULL otherwise.
+ */
+struct uretprobe_instance *get_free_urp_inst_no_alloc(struct uretprobe *rp)
+{
+       struct uretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
+               return ri;
+       }
+
+       return NULL;
+}
+
+/* Called with urp_mtx held */
+static void free_urp_inst(struct uretprobe *rp)
+{
+       struct uretprobe_instance *ri;
+       while ((ri = get_free_urp_inst_no_alloc(rp)) != NULL) {
+               hlist_del(&ri->uflist);
+               kfree(ri);
+       }
+}
+
+#define COMMON_URP_NR 10
+
+static int alloc_nodes_uretprobe(struct uretprobe *rp)
+{
+       int alloc_nodes;
+       struct uretprobe_instance *inst;
+       int i;
+
+#if 1 /* def CONFIG_PREEMPT */
+       rp->maxactive += max(COMMON_URP_NR, 2 * NR_CPUS);
+#else
+       rp->maxacpptive += NR_CPUS;
+#endif
+       alloc_nodes = COMMON_URP_NR;
+
+       for (i = 0; i < alloc_nodes; ++i) {
+               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_ATOMIC);
+               if (inst == NULL) {
+                       free_urp_inst(rp);
+                       return -ENOMEM;
+               }
+               INIT_HLIST_NODE(&inst->uflist);
+               hlist_add_head(&inst->uflist, &rp->free_instances);
+       }
+
+       return 0;
+}
+
+/* Called with urp_mtx held */
+static struct uretprobe_instance *get_free_urp_inst(struct uretprobe *rp)
+{
+       struct uretprobe_instance *ri;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
+               return ri;
+       }
+
+       if (!alloc_nodes_uretprobe(rp)) {
+               swap_hlist_for_each_entry(ri, node,
+                                         &rp->free_instances, uflist) {
+                       return ri;
+               }
+       }
+
+       return NULL;
+}
+/* =================================================================== */
+
+
+void for_each_uprobe(int (*func)(struct uprobe *, void *), void *data)
+{
+       int i;
+       struct uprobe *p;
+       struct hlist_head *head;
+       struct hlist_node *tnode;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
+               head = &uprobe_table[i];
+               swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
+                       if (func(p, data))
+                               return;
+               }
+       }
+}
+
+static int wait_up_action(atomic_t *val)
+{
+       BUG_ON(atomic_read(val));
+       schedule();
+       return 0;
+}
+
+static void wait_up(struct uprobe *p)
+{
+       wait_on_atomic_t(&p->usage, wait_up_action, TASK_UNINTERRUPTIBLE);
+}
+
+/**
+ * @brief Registers uprobe.
+ *
+ * @param up Pointer to the uprobe to register.
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int swap_register_uprobe(struct uprobe *p)
+{
+       int ret = 0;
+       struct uprobe *old_p;
+
+       if (!p->addr)
+               return -EINVAL;
+
+       p->insn = NULL;
+       INIT_LIST_HEAD(&p->list);
+       atomic_set(&p->usage, 1);
+
+       /* get the first item */
+       old_p = get_uprobe(p->addr, p->task->tgid);
+       if (old_p) {
+               ret = register_aggr_uprobe(old_p, p);
+               goto out;
+       }
+
+       INIT_HLIST_NODE(&p->is_hlist);
+
+       ret = arch_prepare_uprobe(p);
+       if (ret) {
+               DBPRINTF("goto out\n", ret);
+               goto out;
+       }
+
+       DBPRINTF("before out ret = 0x%x\n", ret);
+
+       /* TODO: add uprobe (must be in function) */
+       INIT_HLIST_NODE(&p->hlist);
+       hlist_add_head_rcu(&p->hlist,
+                          &uprobe_table[hash_ptr(p->addr, UPROBE_HASH_BITS)]);
+
+       ret = arm_uprobe(p);
+       if (ret) {
+               hlist_del_rcu(&p->hlist);
+               synchronize_rcu();
+               remove_uprobe(p);
+       }
+
+out:
+       DBPRINTF("out ret = 0x%x\n", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_register_uprobe);
+
+/**
+ * @brief Unregisters uprobe.
+ *
+ * @param up Pointer to the uprobe.
+ * @param disarm Disarm flag. When true uprobe is disarmed.
+ * @return Void.
+ */
+void __swap_unregister_uprobe(struct uprobe *p, int disarm)
+{
+       struct uprobe *old_p, *list_p;
+       int cleanup_p;
+
+       /* we MUST check probe for uncreated process  */
+       if (!p->task)
+               return;
+
+       mutex_lock(&up_mtx);
+       rcu_read_lock();
+       old_p = get_uprobe(p->addr, p->task->tgid);
+       rcu_read_unlock();
+       if (unlikely(!old_p))
+               goto out_unlock;
+
+       if (p != old_p) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(list_p, &old_p->list, list) {
+                       if (list_p == p) {
+                               /* uprobe p is a valid probe */
+                               rcu_read_unlock();
+                               goto valid_p;
+                       }
+               }
+               rcu_read_unlock();
+               goto out_unlock;
+       }
+
+valid_p:
+       if ((old_p == p) || ((old_p->pre_handler == aggr_pre_uhandler) &&
+           (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
+               /* Only probe on the hash list */
+               if (disarm)
+                       disarm_uprobe(p, p->task);
+
+               hlist_del_rcu(&old_p->hlist);
+               cleanup_p = 1;
+       } else {
+               list_del_rcu(&p->list);
+               cleanup_p = 0;
+       }
+
+       if (cleanup_p) {
+               if (p != old_p) {
+                       list_del_rcu(&p->list);
+                       kfree(old_p);
+               }
+
+               if (!in_atomic()) {
+                       synchronize_sched();
+
+                       atomic_dec(&p->usage);
+                       wait_up(p);
+               }
+
+               remove_uprobe(p);
+       } else {
+               if (p->break_handler)
+                       old_p->break_handler = NULL;
+
+               if (p->post_handler) {
+                       rcu_read_lock();
+                       list_for_each_entry_rcu(list_p, &old_p->list, list) {
+                               if (list_p->post_handler) {
+                                       cleanup_p = 2;
+                                       break;
+                               }
+                       }
+                       rcu_read_unlock();
+
+                       if (cleanup_p == 0)
+                               old_p->post_handler = NULL;
+               }
+       }
+
+out_unlock:
+       mutex_unlock(&up_mtx);
+}
+EXPORT_SYMBOL_GPL(__swap_unregister_uprobe);
+
+/**
+ * @brief Unregisters uprobe. Main interface function, wrapper for
+ * __swap_unregister_uprobe.
+ *
+ * @param up Pointer to the uprobe.
+ * @return Void.
+ */
+void swap_unregister_uprobe(struct uprobe *up)
+{
+       __swap_unregister_uprobe(up, 1);
+}
+
+/**
+ * @brief Registers ujprobe.
+ *
+ * @param uj Pointer to the ujprobe function.
+ * @return 0 on success,\n
+ * error code on error.
+ */
+int swap_register_ujprobe(struct ujprobe *jp)
+{
+       int ret = 0;
+
+       /* Todo: Verify probepoint is a function entry point */
+       jp->up.pre_handler = setjmp_upre_handler;
+       jp->up.break_handler = longjmp_break_uhandler;
+
+       ret = swap_register_uprobe(&jp->up);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_register_ujprobe);
+
+/**
+ * @brief Unregisters ujprobe.
+ *
+ * @param jp Pointer to the ujprobe.
+ * @param disarm Disarm flag, passed to __swap_unregister_uprobe.
+ * @return Void.
+ */
+void __swap_unregister_ujprobe(struct ujprobe *jp, int disarm)
+{
+       __swap_unregister_uprobe(&jp->up, disarm);
+}
+EXPORT_SYMBOL_GPL(__swap_unregister_ujprobe);
+
+/**
+ * @brief Unregisters ujprobe. Main interface function, wrapper for
+ * __swap_unregister_ujprobe.
+ *
+ * @param jp Pointer to the jprobe.
+ * @return Void.
+ */
+void swap_unregister_ujprobe(struct ujprobe *jp)
+{
+       __swap_unregister_ujprobe(jp, 1);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_ujprobe);
+
+/**
+ * @brief Trampoline uprobe handler.
+ *
+ * @param p Pointer to the uprobe.
+ * @param regs Pointer to CPU register data.
+ * @return 1
+ */
+int trampoline_uprobe_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct uretprobe_instance *ri = NULL;
+       struct uprobe *up;
+       struct hlist_head *head = uretprobe_inst_table_head(current->mm);
+       unsigned long tramp_addr = arch_get_trampoline_addr(p, regs);
+       unsigned long orig_ret_addr = 0;
+       struct hlist_node *tmp;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more then one
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       uretprobe_trampoline
+        */
+       mutex_lock(&urp_mtx);
+       swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+               if (ri->task != current) {
+                       /* another task is sharing our hash bucket */
+                       continue;
+               }
+
+               up = NULL;
+               if (ri->rp) {
+                       up = &ri->rp->up;
+
+                       if (ri->rp->handler)
+                               ri->rp->handler(ri, regs);
+               }
+
+               orig_ret_addr = (unsigned long)ri->ret_addr;
+               recycle_urp_inst(ri);
+
+               if (orig_ret_addr != tramp_addr || up == NULL) {
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+               }
+       }
+       mutex_unlock(&urp_mtx);
+
+       /* orig_ret_addr is NULL when there is no need to restore anything
+        * (all the magic is performed inside handler) */
+       if (likely(orig_ret_addr))
+               arch_set_orig_ret_addr(orig_ret_addr, regs);
+
+       return 1;
+}
+
+static int pre_handler_uretprobe(struct uprobe *p, struct pt_regs *regs)
+{
+       struct uretprobe *rp = container_of(p, struct uretprobe, up);
+       struct uretprobe_instance *ri;
+       int ret = 0;
+
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+# if defined(CONFIG_ARM64)
+#  define thumb_mode(regs)     compat_thumb_mode(regs)
+# endif /* defined(CONFIG_ARM64) */
+       int noret = thumb_mode(regs) ? rp->thumb_noret : rp->arm_noret;
+
+       if (noret)
+               return 0;
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+
+       /* TODO: consider to only swap the
+        * RA after the last pre_handler fired */
+
+       /* TODO: test - remove retprobe after func entry but before its exit */
+       mutex_lock(&urp_mtx);
+       ri = get_free_urp_inst(rp);
+       if (ri != NULL) {
+               int err;
+
+               ri->rp = rp;
+               ri->task = current;
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+               ri->preload.use = false;
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+               if (rp->entry_handler)
+                       ret = rp->entry_handler(ri, regs);
+
+               add_urp_inst(ri);
+
+               err = arch_prepare_uretprobe(ri, regs);
+               if (err) {
+                       recycle_urp_inst(ri);
+                       ++rp->nmissed;
+               }
+       } else {
+               ++rp->nmissed;
+       }
+       mutex_unlock(&urp_mtx);
+
+       return ret;
+}
+
+/**
+ * @brief Registers uretprobe.
+ *
+ * @param rp Pointer to the uretprobe.
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int swap_register_uretprobe(struct uretprobe *rp)
+{
+       int i, ret = 0;
+       struct uretprobe_instance *inst;
+
+       DBPRINTF("START\n");
+
+       rp->up.pre_handler = pre_handler_uretprobe;
+       rp->up.post_handler = NULL;
+       rp->up.fault_handler = NULL;
+       rp->up.break_handler = NULL;
+       /* Set callback to check for unsupported insns */
+       rp->up.check_opcode_cb = arch_urp_check_opcode;
+
+       /* Pre-allocate memory for max kretprobe instances */
+       if (rp->maxactive <= 0) {
+#if 1 /* def CONFIG_PREEMPT */
+               rp->maxactive = max(10, 2 * NR_CPUS);
+#else
+               rp->maxactive = NR_CPUS;
+#endif
+       }
+
+       INIT_HLIST_HEAD(&rp->used_instances);
+       INIT_HLIST_HEAD(&rp->free_instances);
+
+       for (i = 0; i < rp->maxactive; i++) {
+               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_KERNEL);
+               if (inst == NULL) {
+                       ret = -ENOMEM;
+                       goto register_err;
+               }
+
+               INIT_HLIST_NODE(&inst->uflist);
+               hlist_add_head(&inst->uflist, &rp->free_instances);
+       }
+
+       rp->nmissed = 0;
+
+       /* Establish function entry probe point */
+       ret = swap_register_uprobe(&rp->up);
+       if (ret)
+               goto register_err;
+
+       arch_opcode_analysis_uretprobe(rp);
+
+       return 0;
+
+register_err:
+       free_urp_inst(rp);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_register_uretprobe);
+
+/**
+ * @brief Unregisters uretprobe.
+ *
+ * @param rp Pointer to the ureprobe.
+ * @param disarm Disarm flag, passed to __swap_unregister_uprobe
+ * @return Void.
+ */
+void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm)
+{
+       struct uretprobe_instance *ri;
+
+       __swap_unregister_uprobe(&rp->up, disarm);
+
+       mutex_lock(&urp_mtx);
+       while ((ri = get_used_urp_inst(rp)) != NULL) {
+               /* FIXME: arch_disarm_urp_inst() for no current context */
+               if (arch_disarm_urp_inst(ri, ri->task) != 0)
+                       printk(KERN_INFO "%s (%d/%d): "
+                              "cannot disarm urp instance (%08lx)\n",
+                              ri->task->comm, ri->task->tgid, ri->task->pid,
+                              (unsigned long)rp->up.addr);
+
+               recycle_urp_inst(ri);
+       }
+
+       while ((ri = get_used_urp_inst(rp)) != NULL) {
+               ri->rp = NULL;
+               hlist_del(&ri->uflist);
+       }
+       mutex_unlock(&urp_mtx);
+
+       free_urp_inst(rp);
+}
+EXPORT_SYMBOL_GPL(__swap_unregister_uretprobe);
+
+/**
+ * @brief Unregistets uretprobe. Main interface function, wrapper for
+ * __swap_unregister_uretprobe.
+ *
+ * @param rp Pointer to the uretprobe.
+ * @return Void.
+ */
+void swap_unregister_uretprobe(struct uretprobe *rp)
+{
+       __swap_unregister_uretprobe(rp, 1);
+}
+EXPORT_SYMBOL_GPL(swap_unregister_uretprobe);
+
+/**
+ * @brief Unregisters all uprobes for task's thread group ID.
+ *
+ * @param task Pointer to the task_struct
+ * @return Void.
+ */
+void swap_unregister_all_uprobes(struct task_struct *task)
+{
+       struct hlist_head *head;
+       struct uprobe *p;
+       int i;
+       struct hlist_node *tnode;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
+               head = &uprobe_table[i];
+               swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
+                       if (p->task->tgid == task->tgid) {
+                               printk(KERN_INFO "%s: delete uprobe at %p[%lx]"
+                                      " for %s/%d\n", __func__, p->addr,
+                                      (unsigned long)p->opcode,
+                                      task->comm, task->pid);
+                               swap_unregister_uprobe(p);
+                       }
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(swap_unregister_all_uprobes);
+
+/**
+ * @brief Arch-independent wrapper for arch_ujprobe_return.
+ *
+ * @return Void.
+ */
+void swap_ujprobe_return(void)
+{
+       arch_ujprobe_return();
+}
+EXPORT_SYMBOL_GPL(swap_ujprobe_return);
+
+void swap_uretprobe_free_task(struct task_struct *armed,
+                             struct task_struct *will_disarm, bool recycle)
+{
+       struct uretprobe_instance *ri;
+       struct hlist_head *hhead = uretprobe_inst_table_head(armed->mm);
+       struct hlist_node *n;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       mutex_lock(&urp_mtx);
+       swap_hlist_for_each_entry_safe(ri, node, n, hhead, hlist) {
+               if (armed != ri->task)
+                       continue;
+
+               if (will_disarm)
+                       arch_disarm_urp_inst(ri, will_disarm);
+
+               if (recycle)
+                       recycle_urp_inst(ri);
+       }
+       mutex_unlock(&urp_mtx);
+}
+EXPORT_SYMBOL_GPL(swap_uretprobe_free_task);
+
+
+static int once(void)
+{
+       init_uprobe_table();
+       init_uprobes_insn_slots();
+       init_uretprobe_inst_table();
+
+       return 0;
+}
+
+SWAP_LIGHT_INIT_MODULE(once, swap_arch_init_uprobes, swap_arch_exit_uprobes,
+                      NULL, NULL);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/uprobe/swap_uprobes.h b/modules/uprobe/swap_uprobes.h
new file mode 100644 (file)
index 0000000..e481d79
--- /dev/null
@@ -0,0 +1,228 @@
+/**
+ * @file uprobe/swap_uprobes.h
+ * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
+ * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
+ * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
+ * separating core and arch parts
+ *
+ * @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, 2006-2010
+ *
+ * @section DESCRIPTION
+ *
+ * Uprobes interface declaration.
+ */
+
+#ifndef _SWAP_UPROBES_H
+#define _SWAP_UPROBES_H
+
+
+#include <master/wait.h>
+#include <swap-asm/swap_uprobes.h>
+
+
+#define URETPROBE_STACK_DEPTH 64
+
+
+/**
+ * @brief Uprobe pre-handler pointer.
+ */
+typedef int (*uprobe_pre_handler_t) (struct uprobe *, struct pt_regs *);
+
+/**
+ * @brief Uprobe break handler pointer.
+ */
+typedef int (*uprobe_break_handler_t) (struct uprobe *, struct pt_regs *);
+
+/**
+ * @brief Uprobe post handler pointer.
+ */
+typedef void (*uprobe_post_handler_t) (struct uprobe *,
+                                      struct pt_regs *,
+                                      unsigned long flags);
+
+/**
+ * @brief Uprobe fault handler pointer.
+ */
+typedef int (*uprobe_fault_handler_t) (struct uprobe *,
+                                      struct pt_regs *,
+                                      int trapnr);
+
+/**
+ * @struct uprobe
+ * @brief Stores uprobe data.
+ */
+struct uprobe {
+       struct hlist_node hlist; /**< Hash list.*/
+       /** List of probes to search by instruction slot.*/
+       struct hlist_node is_hlist;
+       /** List of uprobes for multi-handler support.*/
+       struct list_head list;
+       /** Location of the probe point. */
+       uprobe_opcode_t *addr;
+       /** Called before addr is executed.*/
+       uprobe_pre_handler_t pre_handler;
+       /** Called after addr is executed, unless...*/
+       uprobe_post_handler_t post_handler;
+       /** ... called if executing addr causes a fault (eg. page fault).*/
+       uprobe_fault_handler_t fault_handler;
+       /** Return 1 if it handled fault, otherwise kernel will see it.*/
+       uprobe_break_handler_t break_handler;
+       /** Saved opcode (which has been replaced with breakpoint).*/
+       uprobe_opcode_t opcode;
+       atomic_t usage;
+#ifdef CONFIG_ARM
+       /** Safe/unsafe to use probe on ARM.*/
+       unsigned safe_arm:1;
+       /** Safe/unsafe to use probe on Thumb.*/
+       unsigned safe_thumb:1;
+#endif
+       uprobe_opcode_t __user *insn;
+       struct arch_insn ainsn;              /**< Copy of the original instruction.*/
+       struct task_struct *task;            /**< Pointer to the task struct */
+       struct slot_manager *sm;             /**< Pointer to slot manager */
+       int (*check_opcode_cb)(uprobe_opcode_t *opcode); /**< Callback check opcode */
+};
+
+
+void swap_uretprobe_free_task(struct task_struct *task,
+                             struct task_struct *dtask, bool recycle);
+
+
+/**
+ * @brief Uprobe pre-entry handler.
+ */
+typedef unsigned long (*uprobe_pre_entry_handler_t)(void *priv_arg,
+                                                   struct pt_regs *regs);
+
+/**
+ * @struct ujprobe
+ * @brief Stores ujprobe data, based on uprobe.
+ */
+struct ujprobe {
+       struct uprobe up;       /**< Uprobe for this ujprobe */
+       void *entry;            /**< Probe handling code to jump to */
+       /** Handler which will be called before 'entry' */
+       uprobe_pre_entry_handler_t pre_entry;
+       void *priv_arg;         /**< Private args for handler */
+       char *args;             /**< Function args format string */
+};
+
+struct uretprobe_instance;
+
+/**
+ * @brief Uretprobe handler.
+ */
+typedef int (*uretprobe_handler_t)(struct uretprobe_instance *,
+                                  struct pt_regs *);
+
+/**
+ * @strict uretprobe
+ * @brief Function-return probe.
+ *
+ * Note:
+ * User needs to provide a handler function, and initialize maxactive.
+ */
+struct uretprobe {
+       struct uprobe up;                   /**< Uprobe for this uretprobe */
+       uretprobe_handler_t handler;        /**< Uretprobe handler */
+       uretprobe_handler_t entry_handler;  /**< Uretprobe entry handler */
+       /** Maximum number of instances of the probed function that can be
+        * active concurrently. */
+       int maxactive;
+       /** Tracks the number of times the probed function's return was
+        * ignored, due to maxactive being too low. */
+       int nmissed;
+       size_t data_size;                   /**< Instance data size */
+       struct hlist_head free_instances;   /**< Free instances list */
+       struct hlist_head used_instances;   /**< Used instances list */
+
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+       unsigned arm_noret:1;               /**< No-return flag for ARM */
+       unsigned thumb_noret:1;             /**< No-return flag for Thumb */
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
+};
+
+/**
+ * @struct uretprobe_instance
+ * @brief Structure for each uretprobe instance.
+ */
+struct uretprobe_instance {
+       /* either on free list or used list */
+       struct hlist_node uflist;           /**< Free list */
+       struct hlist_node hlist;            /**< Used list */
+       struct uretprobe *rp;               /**< Pointer to the parent uretprobe */
+       uprobe_opcode_t *ret_addr;          /**< Return address */
+       uprobe_opcode_t *sp;                /**< Pointer to stack */
+       struct task_struct *task;           /**< Pointer to the task struct */
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+       /* FIXME Preload: if this flag is set then ignore the thumb_mode(regs)
+        * check in arch_prepare_uretprobe and use thumb trampoline. For the
+        * moment we have to explicitly force arm mode when jumping to preload
+        * handlers but we need the correct (i.e. original) retprobe tramp set
+        * anyway. */
+       struct {
+               unsigned use:1;
+               unsigned thumb:1;
+       } preload;
+#endif
+       char data[0];                       /**< Custom data */
+};
+
+
+static void inline get_up(struct uprobe *p)
+{
+       atomic_inc(&p->usage);
+}
+
+static void inline put_up(struct uprobe *p)
+{
+       if (atomic_dec_and_test(&p->usage))
+               wake_up_atomic_t(&p->usage);
+}
+
+void for_each_uprobe(int (*func)(struct uprobe *, void *), void *data);
+int swap_register_uprobe(struct uprobe *p);
+void swap_unregister_uprobe(struct uprobe *p);
+void __swap_unregister_uprobe(struct uprobe *up, int disarm);
+
+int swap_register_ujprobe(struct ujprobe *jp);
+void swap_unregister_ujprobe(struct ujprobe *jp);
+void __swap_unregister_ujprobe(struct ujprobe *jp, int disarm);
+
+int swap_register_uretprobe(struct uretprobe *rp);
+void swap_unregister_uretprobe(struct uretprobe *rp);
+void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm);
+
+void swap_unregister_all_uprobes(struct task_struct *task);
+
+void swap_ujprobe_return(void);
+struct uprobe *get_uprobe(void *addr, pid_t tgid);
+struct uprobe *get_uprobe_by_insn_slot(void *addr,
+                                       pid_t tgid,
+                                       struct pt_regs *regs);
+
+void disarm_uprobe(struct uprobe *p, struct task_struct *task);
+
+int trampoline_uprobe_handler(struct uprobe *p, struct pt_regs *regs);
+
+void add_uprobe_table(struct uprobe *p);
+
+#endif /*  _SWAP_UPROBES_H */
diff --git a/modules/us_manager/Kbuild b/modules/us_manager/Kbuild
new file mode 100644 (file)
index 0000000..a3f8629
--- /dev/null
@@ -0,0 +1,26 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../writer/Module.symvers \
+                       $(src)/../kprobe/Module.symvers \
+                       $(src)/../uprobe/Module.symvers
+
+obj-m := swap_us_manager.o
+swap_us_manager-y := \
+    helper.o \
+    us_manager.o \
+    us_slot_manager.o \
+    debugfs_us_manager.o \
+    sspt/sspt_ip.o \
+    sspt/sspt_page.o \
+    sspt/sspt_file.o \
+    sspt/sspt_proc.o \
+    sspt/sspt_feature.o \
+    sspt/sspt_filter.o \
+    pf/pf_group.o \
+    pf/proc_filters.o \
+    img/img_ip.o \
+    img/img_file.o \
+    img/img_proc.o \
+    probes/probes.o \
+    probes/probe_info_new.o \
+    callbacks.o \
+    usm_hook.o
diff --git a/modules/us_manager/callbacks.c b/modules/us_manager/callbacks.c
new file mode 100644 (file)
index 0000000..23a8dc8
--- /dev/null
@@ -0,0 +1,139 @@
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "callbacks.h"
+
+static LIST_HEAD(cbs_list);
+static DEFINE_MUTEX(cbs_mutex);
+static int cur_handle = 0;
+
+struct cb_item {
+       struct list_head list;
+       enum callback_t type;
+       int handle;
+       void (*func)(void);
+};
+
+static inline void __lock_cbs_list(void)
+{
+       mutex_lock(&cbs_mutex);
+}
+
+static inline void __unlock_cbs_list(void)
+{
+       mutex_unlock(&cbs_mutex);
+}
+
+static inline int __get_new_handle(void)
+{
+       return cur_handle++;
+}
+
+static inline void __free_cb(struct cb_item *cb)
+{
+       list_del(&cb->list);
+       kfree(cb);
+}
+
+static struct cb_item *__get_cb_by_handle(int handle)
+{
+       struct cb_item *cb;
+
+       list_for_each_entry(cb, &cbs_list, list)
+               if (cb->handle == handle)
+                       return cb;
+
+       return NULL;
+}
+
+
+/**
+ * @brief Executes callbacks on start/stop
+ *
+ * @param cbt Callback type
+ * @return Void
+ */
+void exec_cbs(enum callback_t cbt)
+{
+       struct cb_item *cb;
+
+       __lock_cbs_list();
+
+       list_for_each_entry(cb, &cbs_list, list)
+               if (cb->type == cbt)
+                       cb->func();
+
+       __unlock_cbs_list();
+}
+
+/**
+ * @brief Removes all callbacks from list
+ *
+ * @return Void
+ */
+void remove_all_cbs(void)
+{
+       struct cb_item *cb, *n;
+
+       __lock_cbs_list();
+
+       list_for_each_entry_safe(cb, n, &cbs_list, list)
+               __free_cb(cb);
+
+       __unlock_cbs_list();
+}
+
+/**
+ * @brief Registers callback on event
+ *
+ * @param cbt Callback type
+ * @param func Callback function
+ * @return Handle on succes, error code on error
+ */
+int us_manager_reg_cb(enum callback_t cbt, void (*func)(void))
+{
+       struct cb_item *cb;
+       int handle;
+
+       cb = kmalloc(sizeof(*cb), GFP_KERNEL);
+       if (cb == NULL)
+               return -ENOMEM;
+
+       handle = __get_new_handle();
+
+       INIT_LIST_HEAD(&cb->list);
+       cb->type = cbt;
+       cb->handle = handle;
+       cb->func = func;
+
+       __lock_cbs_list();
+       list_add_tail(&cb->list, &cbs_list);
+       __unlock_cbs_list();
+
+       return handle;
+}
+EXPORT_SYMBOL_GPL(us_manager_reg_cb);
+
+/**
+ * @brief Unegisters callback by handle
+ *
+ * @param handle Callback handle
+ * @return Void
+ */
+void us_manager_unreg_cb(int handle)
+{
+       struct cb_item *cb;
+
+       __lock_cbs_list();
+
+       cb = __get_cb_by_handle(handle);
+       if (cb == NULL)
+               goto handle_not_found;
+
+       __free_cb(cb);
+
+handle_not_found:
+       __unlock_cbs_list();
+}
+EXPORT_SYMBOL_GPL(us_manager_unreg_cb);
diff --git a/modules/us_manager/callbacks.h b/modules/us_manager/callbacks.h
new file mode 100644 (file)
index 0000000..ba835d4
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __CALLBACKS_H__
+#define __CALLBACKS_H__
+
+enum callback_t {
+       START_CB = 0,
+       STOP_CB,
+};
+
+/* Gets callback type (on start or on stop) and function pointer.
+ * Returns positive callback's handle that is used to unregister on success,
+ * negative error code otherwise.
+ * Exported function. */
+int us_manager_reg_cb(enum callback_t cbt, void (*func)(void));
+
+/* Gets handle and unregisters function with this handle.
+ * Exported function. */
+void us_manager_unreg_cb(int handle);
+
+/* Used to execute callbacks when start/stop is occuring. */
+void exec_cbs(enum callback_t cbt);
+
+/* Removes all callbacks */
+void remove_all_cbs(void);
+
+#endif /* __CALLBACKS_H__ */
diff --git a/modules/us_manager/debugfs_us_manager.c b/modules/us_manager/debugfs_us_manager.c
new file mode 100644 (file)
index 0000000..a1305be
--- /dev/null
@@ -0,0 +1,125 @@
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include <master/swap_debugfs.h>
+#include <master/swap_initializer.h>
+#include <us_manager/sspt/sspt_proc.h>
+
+#include "debugfs_us_manager.h"
+
+#define MAX_APPS_COUNT  8   /* According to daemon defenitions */
+#define PID_STRING      21  /* Maximum pid string = 20 (max digits count in
+                             * unsigned int on 64-bit arch) + 1 (for \n) */
+
+/* ============================================================================
+ * =                          FOPS_TASKS                                      =
+ * ============================================================================
+ */
+
+struct read_buf {
+       char *begin;
+       char *ptr;
+       char *end;
+};
+
+static void on_each_proc_callback(struct sspt_proc *proc, void *data)
+{
+       struct read_buf *rbuf = (struct read_buf *)data;
+       char pid_str[PID_STRING];
+       int len;
+
+       /* skip process */
+       if (!sspt_proc_is_send_event(proc))
+               return;
+
+       snprintf(pid_str, sizeof(pid_str), "%d", proc->tgid);
+
+       len = strlen(pid_str);
+
+       if (rbuf->end - rbuf->ptr < len + 2)
+               return;
+
+       memcpy(rbuf->ptr, pid_str, len);
+       rbuf->ptr += len;
+
+       *rbuf->ptr = ' ';
+       ++rbuf->ptr;
+}
+
+static ssize_t read_tasks(struct file *file, char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       char buf[PID_STRING * MAX_APPS_COUNT];
+       struct read_buf rbuf = {
+               .begin = buf,
+               .ptr = buf,
+               .end = buf + sizeof(buf)
+       };
+
+       on_each_proc_no_lock(on_each_proc_callback, (void *)&rbuf);
+
+       if (rbuf.ptr != rbuf.begin)
+               rbuf.ptr--;
+
+       *rbuf.ptr = '\n';
+
+       return simple_read_from_buffer(user_buf, count, ppos, rbuf.begin,
+                                  rbuf.ptr - rbuf.begin);
+}
+
+static const struct file_operations fops_tasks = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .read = read_tasks,
+       .llseek = default_llseek
+};
+
+/* ============================================================================
+ * =                          INIT/EXIT                                       =
+ * ============================================================================
+ */
+
+static struct dentry *us_manager_dir;
+
+/**
+ * @brief Destroy debugfs for us_manager
+ *
+ * @return Void
+ */
+void exit_debugfs_us_manager(void)
+{
+       if (us_manager_dir)
+               debugfs_remove_recursive(us_manager_dir);
+
+       us_manager_dir = NULL;
+}
+
+/**
+ * @brief Create debugfs for us_manager
+ *
+ * @return Error code
+ */
+int init_debugfs_us_manager(void)
+{
+       struct dentry *swap_dir, *dentry;
+
+       swap_dir = swap_debugfs_getdir();
+       if (swap_dir == NULL)
+               return -ENOENT;
+
+       us_manager_dir = swap_debugfs_create_dir(US_MANAGER_DFS_DIR, swap_dir);
+       if (us_manager_dir == NULL)
+               return -ENOMEM;
+
+       dentry = swap_debugfs_create_file(US_MANAGER_TASKS, 0600,
+                                         us_manager_dir, NULL, &fops_tasks);
+       if (dentry == NULL)
+               goto fail;
+
+       return 0;
+
+fail:
+       exit_debugfs_us_manager();
+       return -ENOMEM;
+}
diff --git a/modules/us_manager/debugfs_us_manager.h b/modules/us_manager/debugfs_us_manager.h
new file mode 100644 (file)
index 0000000..11c281b
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __DEBUGFS_US_MANAGER_H__
+#define __DEBUGFS_US_MANAGER_H__
+
+/**
+ * @file us_manager/debugfs_us_manager.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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, 2014
+ */
+
+/**
+ * @def US_MANAGER_DFS_DIR @hideinitializer
+ * Name in debugfs
+ */
+#define US_MANAGER_DFS_DIR "us_manager"
+
+/**
+ * @def US_MANAGER_DFS_DIR @hideinitializer
+ * Name in debugfs
+ */
+#define US_MANAGER_TASKS   "tasks"
+
+int init_debugfs_us_manager(void);
+void exit_debugfs_us_manager(void);
+
+#endif /* __DEBUGFS_US_MANAGER_H__ */
diff --git a/modules/us_manager/helper.c b/modules/us_manager/helper.c
new file mode 100644 (file)
index 0000000..55dfffc
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/helper.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include "sspt/sspt.h"
+#include "sspt/sspt_filter.h"
+#include "helper.h"
+#include "usm_hook.h"
+
+
+/* do_page_fault() */
+static void hh_page_fault(unsigned long addr)
+{
+       unsigned long page_addr = addr & PAGE_MASK;
+
+       call_page_fault(current, page_addr);
+}
+
+
+/* copy_process() */
+static void disarm_ip(struct sspt_ip *ip, void *data)
+{
+       struct task_struct *child = (struct task_struct *)data;
+       struct uprobe *up;
+
+       up = probe_info_get_uprobe(ip->desc->type, ip);
+       if (up)
+               disarm_uprobe(up, child);
+}
+
+static void hh_clean_task(struct task_struct *parent, struct task_struct *child)
+{
+       struct sspt_proc *proc;
+
+       proc = sspt_proc_get_by_task(parent);
+       if (proc) {
+               /* disarm up for child */
+               sspt_proc_on_each_ip(proc, disarm_ip, (void *)child);
+
+               /* disarm urp for child */
+               swap_uretprobe_free_task(parent, child, false);
+
+               sspt_proc_put(proc);
+       }
+}
+
+
+/* mm_release() */
+static void hh_mm_release(struct task_struct *task)
+{
+       struct mm_struct *mm = task->mm;
+
+       if (mm == NULL) {
+               pr_err("mm is NULL\n");
+               return;
+       }
+
+       /* TODO: this lock for synchronizing to disarm urp */
+       down_write(&mm->mmap_sem);
+       if (task != task->group_leader) {
+               struct sspt_proc *proc;
+
+               if (task != current) {
+                       pr_err("call mm_release in isn't current context\n");
+                       goto up_mmsem;
+               }
+
+               /* if the thread is killed we need to discard pending
+                * uretprobe instances which have not triggered yet */
+               proc = sspt_proc_by_task(task);
+               if (proc)
+                       swap_uretprobe_free_task(task, task, true);
+       } else {
+               call_mm_release(task);
+       }
+
+up_mmsem:
+       up_write(&mm->mmap_sem);
+}
+
+
+/* do_munmap() */
+struct msg_unmap_data {
+       unsigned long start;
+       unsigned long end;
+};
+
+static void msg_unmap(struct sspt_filter *f, void *data)
+{
+       if (f->pfg_is_inst) {
+               struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
+
+               if (cb && cb->msg_unmap) {
+                       struct msg_unmap_data *msg_data;
+
+                       msg_data = (struct msg_unmap_data *)data;
+                       cb->msg_unmap(msg_data->start, msg_data->end);
+               }
+       }
+}
+
+static void __remove_unmap_probes(struct sspt_proc *proc,
+                                 unsigned long start, unsigned long end)
+{
+       LIST_HEAD(head);
+
+       if (sspt_proc_get_files_by_region(proc, &head, start, end)) {
+               struct sspt_file *file, *n;
+               struct task_struct *task = proc->leader;
+
+               list_for_each_entry_safe(file, n, &head, list) {
+                       if (file->vm_start >= end)
+                               continue;
+
+                       if (file->vm_start >= start)
+                               sspt_file_uninstall(file, task, US_UNINSTALL);
+                       /* TODO: else: uninstall pages: * start..file->vm_end */
+               }
+
+               sspt_proc_insert_files(proc, &head);
+       }
+}
+
+static void hh_munmap(unsigned long start, unsigned long end)
+{
+       struct sspt_proc *proc;
+
+       proc = sspt_proc_get_by_task(current);
+       if (proc) {
+               struct msg_unmap_data msg_data = {
+                       .start = start,
+                       .end = end,
+               };
+
+               __remove_unmap_probes(proc, start, end);
+
+               /* send unmap region */
+               sspt_proc_on_each_filter(proc, msg_unmap, (void *)&msg_data);
+
+               sspt_proc_put(proc);
+       }
+}
+
+
+/* do_mmap_pgoff() */
+static void msg_map(struct sspt_filter *f, void *data)
+{
+       if (f->pfg_is_inst) {
+               struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
+
+               if (cb && cb->msg_map)
+                       cb->msg_map((struct vm_area_struct *)data);
+       }
+}
+
+static void hh_mmap(struct file *file, unsigned long addr)
+{
+       struct sspt_proc *proc;
+       struct task_struct *task;
+       struct vm_area_struct *vma;
+
+       task = current->group_leader;
+       if (is_kthread(task))
+               return;
+
+       if (IS_ERR_VALUE(addr))
+               return;
+
+       proc = sspt_proc_get_by_task(task);
+       if (proc == NULL)
+               return;
+
+       vma = find_vma_intersection(task->mm, addr, addr + 1);
+       if (vma && check_vma(vma)) {
+               usm_hook_mmap(proc, vma);
+               sspt_proc_on_each_filter(proc, msg_map, (void *)vma);
+       }
+
+       sspt_proc_put(proc);
+}
+
+
+/* set_task_comm() */
+static void hh_set_comm(struct task_struct *task)
+{
+       if (task == current)
+               check_task_and_install(current);
+}
+
+
+/* release_task() */
+static void hh_change_leader(struct task_struct *prev,
+                            struct task_struct *next)
+{
+       sspt_change_leader(prev, next);
+}
+
+
+#ifdef CONFIG_SWAP_HOOK_USAUX
+# include "helper_hook.c"
+#else /* CONFIG_SWAP_HOOK_USAUX */
+# include "helper_kprobe.c"
+#endif /* CONFIG_SWAP_HOOK_USAUX */
diff --git a/modules/us_manager/helper.h b/modules/us_manager/helper.h
new file mode 100644 (file)
index 0000000..242a53e
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * @file us_manager/helper.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+#ifndef _HELPER_H
+#define _HELPER_H
+
+#include <linux/sched.h>
+
+static inline int is_kthread(struct task_struct *task)
+{
+       return !task->mm;
+}
+
+int helper_once(void);
+int helper_init(void);
+void helper_uninit(void);
+
+int helper_reg(void);
+void helper_unreg_top(void);
+void helper_unreg_bottom(void);
+
+#endif /* _HELPER_H */
diff --git a/modules/us_manager/helper_hook.c b/modules/us_manager/helper_hook.c
new file mode 100644 (file)
index 0000000..972e9db
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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, 2016
+ *
+ *  2016  Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ */
+
+
+#include <linux/rwsem.h>
+#include <swap/hook_usaux.h>
+#include <kprobe/swap_ktd.h>
+
+
+struct hooks_td {
+       bool in_copy_process;
+};
+
+static void hooks_td_init(struct task_struct *task, void *data)
+{
+       struct hooks_td *td = (struct hooks_td *)data;
+
+       td->in_copy_process = false;
+}
+
+static void hooks_td_exit(struct task_struct *task, void *data)
+{
+       struct hooks_td *td = (struct hooks_td *)data;
+
+       WARN(td->in_copy_process, "in_copy_process=%d", td->in_copy_process);
+}
+
+static struct ktask_data hooks_ktd = {
+       .init = hooks_td_init,
+       .exit = hooks_td_exit,
+       .size = sizeof(struct hooks_td),
+};
+
+static struct hooks_td *current_hooks_td(void)
+{
+       return (struct hooks_td *)swap_ktd(&hooks_ktd, current);
+}
+
+
+static atomic_t run_flag = ATOMIC_INIT(0);
+
+static void hook_start(void)
+{
+       atomic_set(&run_flag, 1);
+}
+
+static void hook_stop(void)
+{
+       atomic_set(&run_flag, 0);
+}
+
+static bool hook_is_running(void)
+{
+       return atomic_read(&run_flag);
+}
+
+
+static void hook_page_fault(unsigned long addr)
+{
+       if (hook_is_running())
+               hh_page_fault(addr);
+}
+
+static DECLARE_RWSEM(copy_process_sem);
+
+static void hook_copy_process_pre(void)
+{
+       if (hook_is_running()) {
+               down_read(&copy_process_sem);
+               if (hook_is_running())
+                       current_hooks_td()->in_copy_process = true;
+               else
+                       up_read(&copy_process_sem);
+       }
+}
+
+static void hook_copy_process_post(struct task_struct *task)
+{
+       struct task_struct *parent = current;
+       struct hooks_td *td = current_hooks_td();
+
+       if (!td->in_copy_process)
+               return;
+
+       if (IS_ERR(task))
+               goto out;
+
+       /* check flags CLONE_VM */
+       if (task->mm != parent->mm)
+               hh_clean_task(current, task);
+
+out:
+       up_read(&copy_process_sem);
+       td->in_copy_process = false;
+}
+
+static void hook_mm_release(struct task_struct *task)
+{
+       hh_mm_release(task);
+}
+
+static void hook_munmap(unsigned long start, unsigned long end)
+{
+       hh_munmap(start, end);
+}
+
+static void hook_mmap(struct file *file, unsigned long addr)
+{
+       hh_mmap(file, addr);
+}
+
+static void hook_set_comm(struct task_struct *task)
+{
+       if (hook_is_running())
+               hh_set_comm(task);
+}
+
+static void hook_change_leader(struct task_struct *prev,
+                               struct task_struct *next)
+{
+       hh_change_leader(prev, next);
+}
+
+static struct hook_usaux hook_usaux = {
+       .owner = THIS_MODULE,
+       .page_fault = hook_page_fault,
+       .copy_process_pre = hook_copy_process_pre,
+       .copy_process_post = hook_copy_process_post,
+       .mm_release = hook_mm_release,
+       .munmap = hook_munmap,
+       .mmap = hook_mmap,
+       .set_comm = hook_set_comm,
+       .change_leader = hook_change_leader,
+};
+
+int helper_once(void)
+{
+       return 0;
+}
+
+int helper_init(void)
+{
+       return swap_ktd_reg(&hooks_ktd);
+}
+
+void helper_uninit(void)
+{
+       swap_ktd_unreg(&hooks_ktd);
+}
+
+int helper_reg(void)
+{
+       int ret;
+
+       ret = hook_usaux_set(&hook_usaux);
+       if (ret)
+               return ret;
+
+       hook_start();
+       return ret;
+}
+
+void helper_unreg_top(void)
+{
+       hook_stop();
+}
+
+void helper_unreg_bottom(void)
+{
+       /* waiting for copy_process() finishing */
+       down_write(&copy_process_sem);
+       up_write(&copy_process_sem);
+
+       hook_usaux_reset();
+}
diff --git a/modules/us_manager/helper_kprobe.c b/modules/us_manager/helper_kprobe.c
new file mode 100644 (file)
index 0000000..0ea58cb
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * 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, 2016
+ *
+ *  2016    Vyacheslav Cherkashin
+ */
+
+
+#include <linux/kconfig.h>
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <ksyms/ksyms.h>
+#include <writer/kernel_operations.h>
+#include "us_slot_manager.h"
+#include "sspt/sspt.h"
+#include "sspt/sspt_filter.h"
+#include "helper.h"
+
+
+static atomic_t stop_flag = ATOMIC_INIT(0);
+
+
+/*
+ ******************************************************************************
+ *                               do_page_fault()                              *
+ ******************************************************************************
+ */
+
+struct pf_data {
+       unsigned long addr;
+
+       struct pt_regs *pf_regs;
+       unsigned long save_pc;
+};
+
+static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct pf_data *data = (struct pf_data *)ri->data;
+
+#if defined(CONFIG_ARM)
+       data->addr = swap_get_karg(regs, 0);
+       data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 2);
+       data->save_pc = data->pf_regs->ARM_pc;
+#elif defined(CONFIG_X86_32)
+       data->addr = read_cr2();
+       data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 0);
+       data->save_pc = data->pf_regs->ip;
+#elif defined(CONFIG_ARM64)
+       data->addr = swap_get_karg(regs, 0);
+       data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 2);
+       data->save_pc = data->pf_regs->pc;
+       /* FIXME: to implement */
+#else
+       #error "this architecture is not supported"
+#endif /* CONFIG_arch */
+
+       if (data->addr) {
+               int ret = 0;
+               struct sspt_proc *proc;
+
+               proc = sspt_proc_get_by_task(current);
+               if (proc) {
+                       if (proc->r_state_addr == data->addr) {
+                               /* skip ret_handler_pf() for current task */
+                               ret = 1;
+                       }
+
+                       sspt_proc_put(proc);
+               }
+
+               return ret;
+       }
+
+       return 0;
+}
+
+static unsigned long cb_pf(void *data)
+{
+       unsigned long addr = *(unsigned long *)data;
+
+       hh_page_fault(addr);
+
+       return 0;
+}
+
+/* Detects when IPs are really loaded into phy mem and installs probes. */
+static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct task_struct *task = current;
+       struct pf_data *data = (struct pf_data *)ri->data;
+       unsigned long addr;
+       int ret;
+
+       if (is_kthread(task))
+               return 0;
+
+       /* skip fixup page_fault */
+#if defined(CONFIG_ARM)
+       if (data->save_pc != data->pf_regs->ARM_pc)
+               return 0;
+#elif defined(CONFIG_X86_32)
+       if (data->save_pc != data->pf_regs->ip)
+               return 0;
+#elif defined(CONFIG_ARM64)
+       if (data->save_pc != data->pf_regs->pc)
+               return 0;
+#endif /* CONFIG_arch */
+
+       /* TODO: check return value */
+       addr = data->addr;
+       ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_pf,
+                         &addr, sizeof(addr));
+
+       if (ret == 0)
+               ri->ret_addr = (unsigned long *)get_jump_addr();
+
+       return 0;
+}
+
+static struct kretprobe mf_kretprobe = {
+       .entry_handler = entry_handler_pf,
+       .handler = ret_handler_pf,
+       .data_size = sizeof(struct pf_data)
+};
+
+static int register_mf(void)
+{
+       int ret;
+
+       ret = swap_register_kretprobe(&mf_kretprobe);
+       if (ret)
+               pr_err("swap_register_kretprobe(handle_mm_fault) ret=%d!\n", ret);
+
+       return ret;
+}
+
+static void unregister_mf(void)
+{
+       swap_unregister_kretprobe(&mf_kretprobe);
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                              copy_process()                                *
+ ******************************************************************************
+ */
+static atomic_t rm_uprobes_child_cnt = ATOMIC_INIT(0);
+
+static unsigned long cb_clean_child(void *data)
+{
+       struct task_struct *parent = current;
+       struct task_struct *child = *(struct task_struct **)data;
+
+       hh_clean_task(parent, child);
+
+       atomic_dec(&rm_uprobes_child_cnt);
+       return 0;
+}
+
+static void rm_uprobes_child(struct kretprobe_instance *ri,
+                            struct pt_regs *regs, struct task_struct *child)
+{
+       int ret;
+
+       if (!sspt_proc_by_task(current))
+               return;
+
+       /* set jumper */
+       ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
+                         cb_clean_child, &child, sizeof(child));
+       if (ret == 0) {
+               atomic_inc(&rm_uprobes_child_cnt);
+               ri->ret_addr = (unsigned long *)get_jump_addr();
+       } else {
+               WARN_ON(1);
+       }
+}
+
+
+static int pre_handler_cp(struct kprobe *p, struct pt_regs *regs)
+{
+       if (is_kthread(current))
+               goto out;
+
+       if (atomic_read(&stop_flag))
+               call_mm_release(current);
+
+out:
+       return 0;
+}
+
+static atomic_t copy_process_cnt = ATOMIC_INIT(0);
+
+static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       atomic_inc(&copy_process_cnt);
+
+       return 0;
+}
+
+/* Delete uprobs in children at fork */
+static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct task_struct *task;
+
+       task = (struct task_struct *)regs_return_value(regs);
+       if (IS_ERR(task))
+               goto out;
+
+       if (task->mm != current->mm)    /* check flags CLONE_VM */
+               rm_uprobes_child(ri, regs, task);
+out:
+       atomic_dec(&copy_process_cnt);
+       return 0;
+}
+
+static struct kretprobe cp_kretprobe = {
+       .entry_handler = entry_handler_cp,
+       .handler = ret_handler_cp,
+};
+
+static struct kprobe cp_kprobe = {
+       .pre_handler = pre_handler_cp
+};
+
+static int register_cp(void)
+{
+       int ret;
+
+
+       ret = swap_register_kprobe(&cp_kprobe);
+       if (ret)
+               pr_err("swap_register_kprobe(copy_process) ret=%d!\n", ret);
+
+       ret = swap_register_kretprobe(&cp_kretprobe);
+       if (ret) {
+               pr_err("swap_register_kretprobe(copy_process) ret=%d!\n", ret);
+               swap_unregister_kprobe(&cp_kprobe);
+       }
+
+       return ret;
+}
+
+static void unregister_cp(void)
+{
+       swap_unregister_kretprobe_top(&cp_kretprobe, 0);
+       do {
+               synchronize_sched();
+       } while (atomic_read(&copy_process_cnt));
+       swap_unregister_kretprobe_bottom(&cp_kretprobe);
+       swap_unregister_kprobe(&cp_kprobe);
+
+       do {
+               synchronize_sched();
+       } while (atomic_read(&rm_uprobes_child_cnt));
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                                mm_release()                                *
+ ******************************************************************************
+ */
+
+/* Detects when target process removes IPs. */
+static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
+
+       hh_mm_release(task);
+
+       return 0;
+}
+
+static struct kprobe mr_kprobe = {
+       .pre_handler = mr_pre_handler
+};
+
+static int register_mr(void)
+{
+       int ret;
+
+       ret = swap_register_kprobe(&mr_kprobe);
+       if (ret)
+               pr_err("swap_register_kprobe(mm_release) ret=%d!\n", ret);
+
+       return ret;
+}
+
+static void unregister_mr(void)
+{
+       swap_unregister_kprobe(&mr_kprobe);
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                                 do_munmap()                                *
+ ******************************************************************************
+ */
+struct unmap_data {
+       unsigned long start;
+       size_t len;
+};
+
+static atomic_t unmap_cnt = ATOMIC_INIT(0);
+
+static unsigned long cb_munmap(void *data)
+{
+       struct unmap_data *umd = (struct unmap_data *)data;
+
+       hh_munmap(umd->start, umd->start + umd->len);
+
+       atomic_dec(&unmap_cnt);
+       return 0;
+}
+
+static int entry_handler_unmap(struct kretprobe_instance *ri,
+                              struct pt_regs *regs)
+{
+       struct unmap_data *data = (struct unmap_data *)ri->data;
+
+       data->start = swap_get_karg(regs, 1);
+       data->len = (size_t)PAGE_ALIGN(swap_get_karg(regs, 2));
+
+       atomic_inc(&unmap_cnt);
+       return 0;
+}
+
+static int ret_handler_unmap(struct kretprobe_instance *ri,
+                            struct pt_regs *regs)
+{
+       int ret;
+
+       if (regs_return_value(regs)) {
+               atomic_dec(&unmap_cnt);
+               return 0;
+       }
+
+       ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_munmap,
+                         (struct unmap_data *)ri->data,
+                         sizeof(struct unmap_data));
+       if (ret == 0) {
+               ri->ret_addr = (unsigned long *)get_jump_addr();
+       } else {
+               WARN_ON(1);
+               atomic_dec(&unmap_cnt);
+       }
+
+       return 0;
+}
+
+static struct kretprobe unmap_kretprobe = {
+       .entry_handler = entry_handler_unmap,
+       .handler = ret_handler_unmap,
+       .data_size = sizeof(struct unmap_data)
+};
+
+static int register_unmap(void)
+{
+       int ret;
+
+       ret = swap_register_kretprobe(&unmap_kretprobe);
+       if (ret)
+               pr_err("swap_register_kprobe(do_munmap) ret=%d!\n", ret);
+
+       return ret;
+}
+
+static void unregister_unmap(void)
+{
+       swap_unregister_kretprobe_top(&unmap_kretprobe, 0);
+       do {
+               synchronize_sched();
+       } while (atomic_read(&unmap_cnt));
+       swap_unregister_kretprobe_bottom(&unmap_kretprobe);
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                               do_mmap_pgoff()                              *
+ ******************************************************************************
+ */
+static int ret_handler_mmap(struct kretprobe_instance *ri,
+                           struct pt_regs *regs)
+{
+       unsigned long addr = regs_return_value(regs);
+
+       hh_mmap(NULL, addr);
+
+       return 0;
+}
+
+static struct kretprobe mmap_kretprobe = {
+       .handler = ret_handler_mmap
+};
+
+static int register_mmap(void)
+{
+       int ret;
+
+       ret = swap_register_kretprobe(&mmap_kretprobe);
+       if (ret)
+               pr_err("swap_register_kretprobe(do_mmap_pgoff) ret=%d!\n", ret);
+
+       return ret;
+}
+
+static void unregister_mmap(void)
+{
+       swap_unregister_kretprobe(&mmap_kretprobe);
+}
+
+
+
+
+
+/*
+ ******************************************************************************
+ *                               set_task_comm()                              *
+ ******************************************************************************
+ */
+struct comm_data {
+       struct task_struct *task;
+};
+
+static unsigned long cb_check_and_install(void *data)
+{
+       hh_set_comm(current);
+
+       return 0;
+}
+
+static int entry_handler_comm(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       struct comm_data *data = (struct comm_data *)ri->data;
+
+       data->task = (struct task_struct *)swap_get_karg(regs, 0);
+
+       return 0;
+}
+
+static int ret_handler_comm(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct task_struct *task;
+       int ret;
+
+       if (is_kthread(current))
+               return 0;
+
+       task = ((struct comm_data *)ri->data)->task;
+       if (task != current)
+               return 0;
+
+       ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
+                         cb_check_and_install, NULL, 0);
+       if (ret == 0)
+               ri->ret_addr = (unsigned long *)get_jump_addr();
+
+       return 0;
+}
+
+static struct kretprobe comm_kretprobe = {
+       .entry_handler = entry_handler_comm,
+       .handler = ret_handler_comm,
+       .data_size = sizeof(struct comm_data)
+};
+
+static int register_comm(void)
+{
+       int ret;
+
+       ret = swap_register_kretprobe(&comm_kretprobe);
+       if (ret)
+               pr_err("swap_register_kretprobe(set_task_comm) ret=%d!\n", ret);
+
+       return ret;
+}
+
+static void unregister_comm(void)
+{
+       swap_unregister_kretprobe(&comm_kretprobe);
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *                               release_task()                               *
+ ******************************************************************************
+ */
+static int release_task_h(struct kprobe *p, struct pt_regs *regs)
+{
+       struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
+       struct task_struct *cur = current;
+
+       if (cur->flags & PF_KTHREAD)
+               return 0;
+
+       /* EXEC: change group leader */
+       if (cur != task && task->pid == cur->pid)
+               hh_change_leader(task, cur);
+
+       return 0;
+}
+
+struct kprobe release_task_kp = {
+       .pre_handler = release_task_h,
+};
+
+static int reg_release_task(void)
+{
+       return swap_register_kprobe(&release_task_kp);
+}
+
+static void unreg_release_task(void)
+{
+       swap_unregister_kprobe(&release_task_kp);
+}
+
+
+
+
+
+/**
+ * @brief Registration of helper
+ *
+ * @return Error code
+ */
+int helper_reg(void)
+{
+       int ret = 0;
+
+       atomic_set(&stop_flag, 0);
+
+       /* tracking group leader changing */
+       ret = reg_release_task();
+       if (ret)
+               return ret;
+
+       /*
+        * install probe on 'set_task_comm' to detect when field comm struct
+        * task_struct changes
+        */
+       ret = register_comm();
+       if (ret)
+               goto unreg_rel_task;
+
+       /* install probe on 'do_munmap' to detect when for remove US probes */
+       ret = register_unmap();
+       if (ret)
+               goto unreg_comm;
+
+       /* install probe on 'mm_release' to detect when for remove US probes */
+       ret = register_mr();
+       if (ret)
+               goto unreg_unmap;
+
+       /* install probe on 'copy_process' to disarm children process */
+       ret = register_cp();
+       if (ret)
+               goto unreg_mr;
+
+       /* install probe on 'do_mmap_pgoff' to detect when mapping file */
+       ret = register_mmap();
+       if (ret)
+               goto unreg_cp;
+
+       /*
+        * install probe on 'handle_mm_fault' to detect when US pages will be
+        * loaded
+        */
+       ret = register_mf();
+       if (ret)
+               goto unreg_mmap;
+
+       return ret;
+
+unreg_mmap:
+       unregister_mmap();
+
+unreg_cp:
+       unregister_cp();
+
+unreg_mr:
+       unregister_mr();
+
+unreg_unmap:
+       unregister_unmap();
+
+unreg_comm:
+       unregister_comm();
+
+unreg_rel_task:
+       unreg_release_task();
+
+       return ret;
+}
+
+/**
+ * @brief Unegistration of helper bottom
+ *
+ * @return Void
+ */
+void helper_unreg_top(void)
+{
+       unregister_mf();
+       atomic_set(&stop_flag, 1);
+}
+
+/**
+ * @brief Unegistration of helper top
+ *
+ * @return Void
+ */
+void helper_unreg_bottom(void)
+{
+       unregister_mmap();
+       unregister_cp();
+       unregister_mr();
+       unregister_unmap();
+       unregister_comm();
+       unreg_release_task();
+}
+
+/**
+ * @brief Initialization of helper
+ *
+ * @return Error code
+ */
+int helper_once(void)
+{
+       const char *sym;
+
+       sym = "do_page_fault";
+       mf_kretprobe.kp.addr = swap_ksyms(sym);
+       if (mf_kretprobe.kp.addr == 0)
+               goto not_found;
+
+       sym = "copy_process";
+       cp_kretprobe.kp.addr = swap_ksyms_substr(sym);
+       if (cp_kretprobe.kp.addr == 0)
+               goto not_found;
+       cp_kprobe.addr = cp_kretprobe.kp.addr;
+
+       sym = "mm_release";
+       mr_kprobe.addr = swap_ksyms(sym);
+       if (mr_kprobe.addr == 0)
+               goto not_found;
+
+       sym = "do_munmap";
+       unmap_kretprobe.kp.addr = swap_ksyms(sym);
+       if (unmap_kretprobe.kp.addr == 0)
+               goto not_found;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+       sym = "do_mmap";
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) */
+       sym = "do_mmap_pgoff";
+#endif  /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) */
+       mmap_kretprobe.kp.addr = swap_ksyms(sym);
+       if (mmap_kretprobe.kp.addr == 0)
+               goto not_found;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+       sym = "__set_task_comm";
+#else  /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */
+       sym = "set_task_comm";
+#endif  /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */
+       comm_kretprobe.kp.addr = swap_ksyms(sym);
+       if (comm_kretprobe.kp.addr == 0)
+               goto not_found;
+
+       sym = "release_task";
+       release_task_kp.addr = swap_ksyms(sym);
+       if (release_task_kp.addr == 0)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       pr_err("ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+int helper_init(void)
+{
+       return 0;
+}
+
+void helper_uninit(void)
+{
+}
diff --git a/modules/us_manager/img/img_file.c b/modules/us_manager/img/img_file.c
new file mode 100644 (file)
index 0000000..e5165d9
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/img/img_file.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include "img_file.h"
+#include "img_ip.h"
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/dcache.h>
+#include <linux/atomic.h>
+
+
+static atomic_t file_counter = ATOMIC_INIT(0);
+
+
+static void img_del_ip_by_list(struct img_ip *ip);
+
+/**
+ * @brief Create img_file struct
+ *
+ * @param dentry Dentry of file
+ * @return Pointer to the created img_file struct
+ */
+struct img_file *img_file_create(struct dentry *dentry)
+{
+       struct img_file *file;
+
+       file = kmalloc(sizeof(*file), GFP_ATOMIC);
+       if (file == NULL) {
+               pr_err("%s: failed to allocate memory\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+       atomic_inc(&file_counter);
+
+       file->dentry = dentry;
+       INIT_LIST_HEAD(&file->list);
+       INIT_LIST_HEAD(&file->ips.head);
+       mutex_init(&file->ips.mtx);
+       atomic_set(&file->use, 1);
+
+       return file;
+}
+
+/**
+ * @brief Remove img_file struct
+ *
+ * @param file remove object
+ * @return Void
+ */
+static void img_file_free(struct img_file *file)
+{
+       struct img_ip *ip, *tmp;
+
+       list_for_each_entry_safe(ip, tmp, &file->ips.head, list) {
+               img_del_ip_by_list(ip);
+               img_ip_clean(ip);
+               img_ip_put(ip);
+       }
+
+       atomic_dec(&file_counter);
+       kfree(file);
+}
+
+/* called with mutex_[lock/unlock](&file->ips.mtx) */
+static void img_add_ip_by_list(struct img_file *file, struct img_ip *ip)
+{
+       list_add(&ip->list, &file->ips.head);
+}
+
+/* called with mutex_[lock/unlock](&file->ips.mtx) */
+static void img_del_ip_by_list(struct img_ip *ip)
+{
+       list_del(&ip->list);
+}
+
+void img_file_get(struct img_file *file)
+{
+       WARN_ON(!atomic_read(&file->use));
+       atomic_inc(&file->use);
+}
+
+void img_file_put(struct img_file *file)
+{
+       if (atomic_dec_and_test(&file->use))
+               img_file_free(file);
+}
+
+
+/**
+ * @brief Add instrumentation pointer
+ *
+ * @param file Pointer to the img_file struct
+ * @param addr Function address
+ * @param probe_Pointer to a probe_info structure with an information about
+ * the probe.
+ * @return Error code
+ */
+struct img_ip *img_file_add_ip(struct img_file *file, unsigned long addr,
+                              struct probe_desc *pd)
+{
+       struct img_ip *ip;
+
+       ip = img_ip_create(addr, pd, file);
+       if (IS_ERR(ip))
+               return ip;
+
+       mutex_lock(&file->ips.mtx);
+       img_add_ip_by_list(file, ip);
+       mutex_unlock(&file->ips.mtx);
+
+       return ip;
+}
+
+/**
+ * @brief Delete img_ip struct from img_file struct
+ *
+ * @param file Pointer to the img_file struct
+ * @param addr Function address
+ * @return Error code
+ */
+void img_file_del_ip(struct img_file *file, struct img_ip *ip)
+{
+       mutex_lock(&file->ips.mtx);
+       img_del_ip_by_list(ip);
+       mutex_unlock(&file->ips.mtx);
+
+       img_ip_clean(ip);
+       img_ip_put(ip);
+}
+
+/**
+ * @brief Check on absence img_ip structs in img_file struct
+ *
+ * @param file Pointer to the img_file struct
+ * @return
+ *       - 0 - not empty
+ *       - 1 - empty
+ */
+int img_file_empty(struct img_file *file)
+{
+       return list_empty(&file->ips.head);
+}
+
+bool img_file_is_unloadable(void)
+{
+       return !(atomic_read(&file_counter) + !img_ip_is_unloadable());
+}
+
+/**
+ * @brief For debug
+ *
+ * @param file Pointer to the img_file struct
+ * @return Void
+ */
+
+/* debug */
+void img_file_print(struct img_file *file)
+{
+       struct img_ip *ip;
+
+       printk(KERN_INFO "###      d_iname=%s\n", file->dentry->d_iname);
+
+       mutex_lock(&file->ips.mtx);
+       list_for_each_entry(ip, &file->ips.head, list) {
+               img_ip_print(ip);
+       }
+       mutex_unlock(&file->ips.mtx);
+}
+/* debug */
diff --git a/modules/us_manager/img/img_file.h b/modules/us_manager/img/img_file.h
new file mode 100644 (file)
index 0000000..e84bcaa
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * @file us_manager/img/img_file.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ */
+
+
+#ifndef _IMG_FILE_H
+#define _IMG_FILE_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+
+struct probe_desc;
+
+/**
+ * @struct img_file
+ * @breaf Image of file
+ */
+struct img_file {
+       /* img_proc */
+       struct list_head list;          /**< List for img_proc */
+
+       /* img_ip */
+       struct {
+               struct mutex mtx;
+               struct list_head head;  /**< Head for img_ip */
+       } ips;
+
+       struct dentry *dentry;          /**< Dentry of file */
+       atomic_t use;
+};
+
+struct img_file *img_file_create(struct dentry *dentry);
+void img_file_get(struct img_file *file);
+void img_file_put(struct img_file *file);
+
+struct img_ip *img_file_add_ip(struct img_file *file, unsigned long addr,
+                              struct probe_desc *pd);
+void img_file_del_ip(struct img_file *file, struct img_ip *ip);
+
+int img_file_empty(struct img_file *file);
+bool img_file_is_unloadable(void);
+
+/* debug */
+void img_file_print(struct img_file *file);
+/* debug */
+
+#endif /* _IMG_FILE_H */
+
diff --git a/modules/us_manager/img/img_ip.c b/modules/us_manager/img/img_ip.c
new file mode 100644 (file)
index 0000000..da7f6e2
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/img/img_ip.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include "img_ip.h"
+#include "img_file.h"
+#include <us_manager/probes/use_probes.h>
+#include <us_manager/sspt/sspt.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+
+
+static atomic_t ip_counter = ATOMIC_INIT(0);
+
+/**
+ * @brief Create img_ip struct
+ *
+ * @param addr Function address
+ * @param probe_i Pointer to the probe info data.
+ * @return Pointer to the created img_ip struct
+ */
+struct img_ip *img_ip_create(unsigned long addr, struct probe_desc *pd,
+                            struct img_file *file)
+{
+       struct img_ip *ip;
+
+       ip = kmalloc(sizeof(*ip), GFP_KERNEL);
+       if (!ip)
+               return ERR_PTR(-ENOMEM);
+       atomic_inc(&ip_counter);
+
+       INIT_LIST_HEAD(&ip->list);
+       kref_init(&ip->ref);
+       mutex_init(&ip->sspt.mtx);
+       INIT_LIST_HEAD(&ip->sspt.head);
+       ip->addr = addr;
+       ip->desc = pd;
+       ip->file = file;
+
+       return ip;
+}
+
+static void img_ip_release(struct kref *ref)
+{
+       struct img_ip *ip = container_of(ref, struct img_ip, ref);
+
+       WARN_ON(!list_empty(&ip->sspt.head));
+
+       atomic_dec(&ip_counter);
+       kfree(ip);
+}
+
+void img_ip_clean(struct img_ip *ip)
+{
+       struct sspt_ip *p;
+
+       img_ip_lock(ip);
+       while(!list_empty(&ip->sspt.head)) {
+               p = list_first_entry(&ip->sspt.head, struct sspt_ip ,img_list);
+               sspt_ip_get(p);
+               img_ip_unlock(ip);
+
+               if (sspt_page_is_installed_ip(p->page, p))
+                       sspt_unregister_usprobe(NULL, p, US_UNREGS_PROBE);
+
+               sspt_ip_clean(p);
+
+               img_ip_lock(ip);
+               sspt_ip_put(p);
+       }
+       img_ip_unlock(ip);
+}
+
+void img_ip_get(struct img_ip *ip)
+{
+       kref_get(&ip->ref);
+}
+
+void img_ip_put(struct img_ip *ip)
+{
+       kref_put(&ip->ref, img_ip_release);
+}
+
+void img_ip_add_ip(struct img_ip *ip, struct sspt_ip *sspt_ip)
+{
+       sspt_ip->img_ip = ip;
+       list_add(&sspt_ip->img_list, &ip->sspt.head);
+}
+
+void img_ip_lock(struct img_ip *ip)
+{
+       mutex_lock(&ip->sspt.mtx);
+}
+
+void img_ip_unlock(struct img_ip *ip)
+{
+       mutex_unlock(&ip->sspt.mtx);
+}
+
+bool img_ip_is_unloadable(void)
+{
+       return !atomic_read(&ip_counter);
+}
+
+/**
+ * @brief For debug
+ *
+ * @param ip Pointer to the img_ip struct
+ * @return Void
+ */
+
+/* debug */
+void img_ip_print(struct img_ip *ip)
+{
+       if (ip->desc->type == SWAP_RETPROBE)
+               printk(KERN_INFO "###            addr=8%lx, args=%s\n",
+                      ip->addr, ip->desc->info.rp_i.args);
+}
+/* debug */
diff --git a/modules/us_manager/img/img_ip.h b/modules/us_manager/img/img_ip.h
new file mode 100644 (file)
index 0000000..b68c943
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * @file us_manager/img/img_ip.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ */
+
+
+#ifndef _IMG_IP_H
+#define _IMG_IP_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+
+
+struct sspt_ip;
+struct img_file;
+struct probe_desc;
+
+/**
+ * @struct img_ip
+ * @breaf Image of instrumentation pointer
+ */
+struct img_ip {
+       /* img_file */
+       struct list_head list;          /**< List for img_file */
+       struct img_file *file;          /**< Pointer on the file (parent) */
+
+       struct kref ref;
+
+       /* sspt_ip */
+       struct {
+               struct mutex mtx;
+               struct list_head head;
+       } sspt;
+
+       unsigned long addr;             /**< Function address */
+       struct probe_desc *desc;        /**< Probe info */
+};
+
+struct img_ip *img_ip_create(unsigned long addr, struct probe_desc *info,
+                            struct img_file *file);
+void img_ip_clean(struct img_ip *ip);
+void img_ip_get(struct img_ip *ip);
+void img_ip_put(struct img_ip *ip);
+
+void img_ip_add_ip(struct img_ip *ip, struct sspt_ip *sspt_ip);
+void img_ip_lock(struct img_ip *ip);
+void img_ip_unlock(struct img_ip *ip);
+
+bool img_ip_is_unloadable(void);
+
+/* debug */
+void img_ip_print(struct img_ip *ip);
+/* debug */
+
+#endif /* _IMG_IP_H */
diff --git a/modules/us_manager/img/img_proc.c b/modules/us_manager/img/img_proc.c
new file mode 100644 (file)
index 0000000..40f6470
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/img/img_proc.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/sspt/sspt_file.h>
+#include "img_ip.h"
+#include "img_proc.h"
+#include "img_file.h"
+
+
+struct img_proc {
+       /* img_file */
+       struct {
+               struct list_head head;
+               struct mutex mtx;
+       } files;
+};
+
+
+static atomic_t proc_counter = ATOMIC_INIT(0);
+
+static void img_del_file_by_list(struct img_file *file);
+
+/**
+ * @brief Create img_proc struct
+ *
+ * @return Pointer to the created img_proc struct
+ */
+struct img_proc *img_proc_create(void)
+{
+       struct img_proc *proc;
+
+       proc = kmalloc(sizeof(*proc), GFP_ATOMIC);
+       if (proc) {
+               atomic_inc(&proc_counter);
+               INIT_LIST_HEAD(&proc->files.head);
+               mutex_init(&proc->files.mtx);
+       }
+
+       return proc;
+}
+
+/**
+ * @brief Remove img_proc struct
+ *
+ * @param file remove object
+ * @return Void
+ */
+void img_proc_free(struct img_proc *proc)
+{
+       struct img_file *file, *tmp;
+
+       mutex_lock(&proc->files.mtx);
+       list_for_each_entry_safe(file, tmp, &proc->files.head, list) {
+               img_del_file_by_list(file);
+               img_file_put(file);
+       }
+       mutex_unlock(&proc->files.mtx);
+
+       atomic_dec(&proc_counter);
+       kfree(proc);
+}
+
+/* called with mutex_[lock/unlock](&proc->files.mtx) */
+static void img_add_file_by_list(struct img_proc *proc, struct img_file *file)
+{
+       list_add(&file->list, &proc->files.head);
+}
+
+/* called with mutex_[lock/unlock](&proc->files.mtx) */
+static void img_del_file_by_list(struct img_file *file)
+{
+       list_del(&file->list);
+}
+
+/* called with mutex_[lock/unlock](&proc->files.mtx) */
+static struct img_file *img_file_find(struct img_proc *proc,
+                                     struct dentry *dentry)
+{
+       struct img_file *file;
+
+       list_for_each_entry(file, &proc->files.head, list) {
+               if (file->dentry == dentry)
+                       return file;
+       }
+
+       return NULL;
+}
+
+/**
+ * @brief Add instrumentation pointer
+ *
+ * @param proc Pointer to the img_proc struct
+ * @param dentry Dentry of file
+ * @param addr Function address
+ * @param probe_i Pointer to a probe_info struct related with the probe
+ * @return Error code
+ */
+struct img_ip *img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
+                              unsigned long addr, struct probe_desc *pd)
+{
+       struct img_file *file;
+
+       mutex_lock(&proc->files.mtx);
+       file = img_file_find(proc, dentry);
+       if (!file) {
+               file = img_file_create(dentry);
+               if (IS_ERR(file)) {
+                       mutex_unlock(&proc->files.mtx);
+
+                       /* handle type cast */
+                       return ERR_PTR(PTR_ERR(file));
+               }
+
+               img_add_file_by_list(proc, file);
+       }
+       mutex_unlock(&proc->files.mtx);
+
+       return img_file_add_ip(file, addr, pd);
+}
+
+/**
+ * @brief Remove instrumentation pointer
+ *
+ * @param proc Pointer to the img_proc struct
+ * @param dentry Dentry of file
+ * @param args Function address
+ * @return Error code
+ */
+void img_proc_del_ip(struct img_proc *proc, struct img_ip *ip)
+{
+       struct img_file *file = ip->file;
+
+       mutex_lock(&proc->files.mtx);
+       img_file_del_ip(file, ip);
+       if (img_file_empty(file)) {
+               img_del_file_by_list(file);
+               img_file_put(file);
+       }
+       mutex_unlock(&proc->files.mtx);
+}
+
+void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc)
+{
+       struct sspt_file *file;
+       struct img_file *i_file;
+
+       mutex_lock(&i_proc->files.mtx);
+       list_for_each_entry(i_file, &i_proc->files.head, list) {
+               file = sspt_proc_find_file_or_new(proc, i_file->dentry);
+               if (file) {
+                       struct img_ip *i_ip;
+
+                       mutex_lock(&i_file->ips.mtx);
+                       list_for_each_entry(i_ip, &i_file->ips.head, list)
+                               sspt_file_add_ip(file, i_ip);
+                       mutex_unlock(&i_file->ips.mtx);
+               }
+       }
+       mutex_unlock(&i_proc->files.mtx);
+}
+
+bool img_proc_is_unloadable(void)
+{
+       return !(atomic_read(&proc_counter) + !img_file_is_unloadable());
+}
+
+/**
+ * @brief For debug
+ *
+ * @param proc Pointer to the img_proc struct
+ * @return Void
+ */
+
+/* debug */
+void img_proc_print(struct img_proc *proc)
+{
+       struct img_file *file;
+
+       printk(KERN_INFO "### img_proc_print:\n");
+
+       mutex_lock(&proc->files.mtx);
+       list_for_each_entry(file, &proc->files.head, list) {
+               img_file_print(file);
+       }
+       mutex_unlock(&proc->files.mtx);
+}
+/* debug */
diff --git a/modules/us_manager/img/img_proc.h b/modules/us_manager/img/img_proc.h
new file mode 100644 (file)
index 0000000..c9f0fc3
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * @file us_manager/img/img_proc.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @section LICENCE
+ * 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
+ */
+
+
+#ifndef _IMG_PROC_H
+#define _IMG_PROC_H
+
+#include <linux/types.h>
+
+struct dentry;
+struct sspt_proc;
+struct probe_desc;
+
+
+struct img_proc *img_proc_create(void);
+void img_proc_free(struct img_proc *proc);
+
+struct img_ip *img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
+                              unsigned long addr, struct probe_desc *pd);
+void img_proc_del_ip(struct img_proc *proc, struct img_ip *ip);
+
+void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc);
+bool img_proc_is_unloadable(void);
+
+/* debug */
+void img_proc_print(struct img_proc *proc);
+/* debug */
+
+#endif /* _IMG_PROC_H */
diff --git a/modules/us_manager/pf/pf_group.c b/modules/us_manager/pf/pf_group.c
new file mode 100644 (file)
index 0000000..6dfcf94
--- /dev/null
@@ -0,0 +1,875 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/pf/pf_group.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/namei.h>
+#include <linux/mman.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+#include "pf_group.h"
+#include "proc_filters.h"
+#include "../sspt/sspt_filter.h"
+#include "../us_manager_common.h"
+#include <us_manager/img/img_proc.h>
+#include <us_manager/img/img_file.h>
+#include <us_manager/img/img_ip.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/helper.h>
+#include <us_manager/us_common_file.h>
+#include <task_ctx/task_ctx.h>
+
+
+struct pf_group {
+       struct list_head list;
+       struct img_proc *i_proc;
+       struct proc_filter filter;
+       struct pfg_msg_cb *msg_cb;
+       atomic_t usage;
+
+       spinlock_t pl_lock;     /* for proc_list */
+       struct list_head proc_list;
+};
+
+struct pl_struct {
+       struct list_head list;
+       struct sspt_proc *proc;
+};
+
+
+static atomic_t pfg_counter = ATOMIC_INIT(0);
+
+static LIST_HEAD(pfg_list);
+static DECLARE_RWSEM(pfg_list_sem);
+static DECLARE_RWSEM(uninstall_sem);
+
+static void pfg_list_rlock(void)
+{
+       down_read(&pfg_list_sem);
+}
+
+static void pfg_list_runlock(void)
+{
+       up_read(&pfg_list_sem);
+}
+
+static void pfg_list_wlock(void)
+{
+       down_write(&pfg_list_sem);
+}
+
+static void pfg_list_wunlock(void)
+{
+       up_write(&pfg_list_sem);
+}
+
+
+/* struct pl_struct */
+static struct pl_struct *create_pl_struct(struct sspt_proc *proc)
+{
+       struct pl_struct *pls = kmalloc(sizeof(*pls), GFP_ATOMIC);
+
+       if (pls) {
+               INIT_LIST_HEAD(&pls->list);
+               pls->proc = sspt_proc_get(proc);
+       }
+
+       return pls;
+}
+
+static void free_pl_struct(struct pl_struct *pls)
+{
+       sspt_proc_put(pls->proc);
+       kfree(pls);
+}
+/* struct pl_struct */
+
+static struct pf_group *pfg_create(void)
+{
+       struct pf_group *pfg = kmalloc(sizeof(*pfg), GFP_ATOMIC);
+
+       if (pfg == NULL)
+               return NULL;
+
+       pfg->i_proc = img_proc_create();
+       if (pfg->i_proc == NULL)
+               goto create_pfg_fail;
+
+       INIT_LIST_HEAD(&pfg->list);
+       memset(&pfg->filter, 0, sizeof(pfg->filter));
+       spin_lock_init(&pfg->pl_lock);
+       INIT_LIST_HEAD(&pfg->proc_list);
+       pfg->msg_cb = NULL;
+       atomic_set(&pfg->usage, 1);
+
+       atomic_inc(&pfg_counter);
+       return pfg;
+
+create_pfg_fail:
+
+       kfree(pfg);
+
+       return NULL;
+}
+
+static void pfg_free(struct pf_group *pfg)
+{
+       struct pl_struct *pl, *n;
+
+       img_proc_free(pfg->i_proc);
+       free_pf(&pfg->filter);
+       list_for_each_entry_safe(pl, n, &pfg->proc_list, list) {
+               sspt_proc_del_filter(pl->proc, pfg);
+               free_pl_struct(pl);
+       }
+
+       atomic_dec(&pfg_counter);
+       kfree(pfg);
+}
+
+bool pfg_is_unloadable(void)
+{
+       return !(atomic_read(&pfg_counter) + !img_proc_is_unloadable());
+}
+
+static int pfg_add_proc(struct pf_group *pfg, struct sspt_proc *proc)
+{
+       struct pl_struct *pls;
+
+       pls = create_pl_struct(proc);
+       if (pls == NULL)
+               return -ENOMEM;
+
+       spin_lock(&pfg->pl_lock);
+       list_add(&pls->list, &pfg->proc_list);
+       spin_unlock(&pfg->pl_lock);
+
+       return 0;
+}
+
+static int pfg_del_proc(struct pf_group *pfg, struct sspt_proc *proc)
+{
+       struct pl_struct *pls, *pls_free = NULL;
+
+       spin_lock(&pfg->pl_lock);
+       list_for_each_entry(pls, &pfg->proc_list, list) {
+               if (pls->proc == proc) {
+                       list_del(&pls->list);
+                       pls_free = pls;
+                       break;
+               }
+       }
+       spin_unlock(&pfg->pl_lock);
+
+       if (pls_free)
+               free_pl_struct(pls_free);
+
+       return !!pls_free;
+}
+
+
+/* called with pfg_list_lock held */
+static void pfg_add_to_list(struct pf_group *pfg)
+{
+       list_add(&pfg->list, &pfg_list);
+}
+
+/* called with pfg_list_lock held */
+static void pfg_del_from_list(struct pf_group *pfg)
+{
+       list_del(&pfg->list);
+}
+
+
+static void msg_info(struct sspt_filter *f, void *data)
+{
+       if (f->pfg_is_inst == false) {
+               struct pfg_msg_cb *cb;
+
+               f->pfg_is_inst = true;
+
+               cb = pfg_msg_cb_get(f->pfg);
+               if (cb) {
+                       struct dentry *dentry;
+
+                       dentry = (struct dentry *)f->pfg->filter.priv;
+
+                       if (cb->msg_info)
+                               cb->msg_info(f->proc->leader, dentry);
+
+                       if (cb->msg_status_info)
+                               cb->msg_status_info(f->proc->leader);
+               }
+       }
+}
+
+static void first_install(struct task_struct *task, struct sspt_proc *proc)
+{
+       down_write(&task->mm->mmap_sem);
+       sspt_proc_on_each_filter(proc, msg_info, NULL);
+       sspt_proc_install(proc);
+       up_write(&task->mm->mmap_sem);
+}
+
+static void subsequent_install(struct task_struct *task,
+                              struct sspt_proc *proc, unsigned long page_addr)
+{
+       down_write(&task->mm->mmap_sem);
+       sspt_proc_install_page(proc, page_addr);
+       up_write(&task->mm->mmap_sem);
+}
+
+
+/**
+ * @brief Get dentry struct by path
+ *
+ * @param path Path to file
+ * @return Pointer on dentry struct on NULL
+ */
+struct dentry *dentry_by_path(const char *path)
+{
+       struct dentry *d;
+
+       d = swap_get_dentry(path);
+       if (d)
+               dput(d);
+
+       return d;
+}
+EXPORT_SYMBOL_GPL(dentry_by_path);
+
+
+int pfg_msg_cb_set(struct pf_group *pfg, struct pfg_msg_cb *msg_cb)
+{
+       if (pfg->msg_cb)
+               return -EBUSY;
+
+       pfg->msg_cb = msg_cb;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pfg_msg_cb_set);
+
+void pfg_msg_cb_reset(struct pf_group *pfg)
+{
+       pfg->msg_cb = NULL;
+}
+EXPORT_SYMBOL_GPL(pfg_msg_cb_reset);
+
+struct pfg_msg_cb *pfg_msg_cb_get(struct pf_group *pfg)
+{
+       return pfg->msg_cb;
+}
+
+/**
+ * @brief Get pf_group struct by dentry
+ *
+ * @param dentry Dentry of file
+ * @param priv Private data
+ * @return Pointer on pf_group struct
+ */
+struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv)
+{
+       struct pf_group *pfg;
+
+       pfg_list_wlock();
+       list_for_each_entry(pfg, &pfg_list, list) {
+               if (check_pf_by_dentry(&pfg->filter, dentry)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
+       }
+
+       pfg = pfg_create();
+       if (pfg == NULL)
+               goto unlock;
+
+       set_pf_by_dentry(&pfg->filter, dentry, priv);
+
+       pfg_add_to_list(pfg);
+
+unlock:
+       pfg_list_wunlock();
+       return pfg;
+}
+EXPORT_SYMBOL_GPL(get_pf_group_by_dentry);
+
+/**
+ * @brief Get pf_group struct by TGID
+ *
+ * @param tgid Thread group ID
+ * @param priv Private data
+ * @return Pointer on pf_group struct
+ */
+struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv)
+{
+       struct pf_group *pfg;
+
+       pfg_list_wlock();
+       list_for_each_entry(pfg, &pfg_list, list) {
+               if (check_pf_by_tgid(&pfg->filter, tgid)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
+       }
+
+       pfg = pfg_create();
+       if (pfg == NULL)
+               goto unlock;
+
+       set_pf_by_tgid(&pfg->filter, tgid, priv);
+
+       pfg_add_to_list(pfg);
+
+unlock:
+       pfg_list_wunlock();
+       return pfg;
+}
+EXPORT_SYMBOL_GPL(get_pf_group_by_tgid);
+
+/**
+ * @brief Get pf_group struct by comm
+ *
+ * @param comm Task comm
+ * @param priv Private data
+ * @return Pointer on pf_group struct
+ */
+struct pf_group *get_pf_group_by_comm(char *comm, void *priv)
+{
+       int ret;
+       struct pf_group *pfg;
+
+       pfg_list_wlock();
+       list_for_each_entry(pfg, &pfg_list, list) {
+               if (check_pf_by_comm(&pfg->filter, comm)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
+       }
+
+       pfg = pfg_create();
+       if (pfg == NULL)
+               goto unlock;
+
+       ret = set_pf_by_comm(&pfg->filter, comm, priv);
+       if (ret) {
+               printk(KERN_ERR "ERROR: set_pf_by_comm, ret=%d\n", ret);
+               pfg_free(pfg);
+               pfg = NULL;
+               goto unlock;
+       }
+
+       pfg_add_to_list(pfg);
+unlock:
+       pfg_list_wunlock();
+       return pfg;
+}
+EXPORT_SYMBOL_GPL(get_pf_group_by_comm);
+
+/**
+ * @brief Get pf_group struct for each process
+ *
+ * @param priv Private data
+ * @return Pointer on pf_group struct
+ */
+struct pf_group *get_pf_group_dumb(void *priv)
+{
+       struct pf_group *pfg;
+
+       pfg_list_wlock();
+       list_for_each_entry(pfg, &pfg_list, list) {
+               if (check_pf_dumb(&pfg->filter)) {
+                       atomic_inc(&pfg->usage);
+                       goto unlock;
+               }
+       }
+
+       pfg = pfg_create();
+       if (pfg == NULL)
+               goto unlock;
+
+       set_pf_dumb(&pfg->filter, priv);
+
+       pfg_add_to_list(pfg);
+
+unlock:
+       pfg_list_wunlock();
+       return pfg;
+}
+EXPORT_SYMBOL_GPL(get_pf_group_dumb);
+
+/**
+ * @brief Put pf_group struct
+ *
+ * @param pfg Pointer to the pf_group struct
+ * @return Void
+ */
+void put_pf_group(struct pf_group *pfg)
+{
+       if (atomic_dec_and_test(&pfg->usage)) {
+               pfg_list_wlock();
+               pfg_del_from_list(pfg);
+               pfg_list_wunlock();
+
+               pfg_free(pfg);
+       }
+}
+EXPORT_SYMBOL_GPL(put_pf_group);
+
+/**
+ * @brief Register prober for pf_grpup struct
+ *
+ * @param pfg Pointer to the pf_group struct
+ * @param dentry Dentry of file
+ * @param offset Function offset
+ * @param probe_info Pointer to the related probe_info struct
+ * @return pointer to the img_ip struct or error
+ */
+struct img_ip *pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
+                                unsigned long offset, struct probe_desc *pd)
+{
+       return img_proc_add_ip(pfg->i_proc, dentry, offset, pd);
+}
+EXPORT_SYMBOL_GPL(pf_register_probe);
+
+/**
+ * @brief Unregister prober from pf_grpup struct
+ *
+ * @param pfg Pointer to the pf_group struct
+ * @param ip Pointer to the img_ip struct
+ * @return Void
+ */
+void pf_unregister_probe(struct pf_group *pfg, struct img_ip *ip)
+{
+       WARN(IS_ERR_OR_NULL(ip), "invalid img_ip");
+       img_proc_del_ip(pfg->i_proc, ip);
+}
+EXPORT_SYMBOL_GPL(pf_unregister_probe);
+
+static int check_task_on_filters(struct task_struct *task)
+{
+       int ret = 0;
+       struct pf_group *pfg;
+
+       pfg_list_rlock();
+       list_for_each_entry(pfg, &pfg_list, list) {
+               if (check_task_f(&pfg->filter, task)) {
+                       ret = 1;
+                       goto unlock;
+               }
+       }
+
+unlock:
+       pfg_list_runlock();
+       return ret;
+}
+
+enum pf_inst_flag {
+       PIF_NONE,
+       PIF_FIRST,
+       PIF_SECOND,
+       PIF_ADD_PFG
+};
+
+static enum pf_inst_flag pfg_check_task(struct task_struct *task)
+{
+       struct pf_group *pfg;
+       struct sspt_proc *proc = NULL;
+       enum pf_inst_flag flag = PIF_NONE;
+
+       pfg_list_rlock();
+       list_for_each_entry(pfg, &pfg_list, list) {
+               bool put_flag = false;
+
+               if (check_task_f(&pfg->filter, task) == NULL)
+                       continue;
+
+               if (proc == NULL) {
+                       proc = sspt_proc_get_by_task(task);
+                       put_flag = !!proc;
+               }
+
+               if (proc) {
+                       flag = flag == PIF_NONE ? PIF_SECOND : flag;
+               } else if (task->tgid == task->pid) {
+                       proc = sspt_proc_get_by_task_or_new(task);
+                       if (proc == NULL) {
+                               printk(KERN_ERR "cannot create sspt_proc\n");
+                               break;
+                       }
+                       put_flag = true;
+                       flag = PIF_FIRST;
+               }
+
+               if (proc) {
+                       mutex_lock(&proc->filters.mtx);
+                               if (sspt_proc_is_filter_new(proc, pfg)) {
+                                       img_proc_copy_to_sspt(pfg->i_proc, proc);
+                                       sspt_proc_add_filter(proc, pfg);
+                                       pfg_add_proc(pfg, proc);
+                                       flag = flag == PIF_FIRST ? flag : PIF_ADD_PFG;
+                       }
+                       mutex_unlock(&proc->filters.mtx);
+                       if (put_flag)
+                               sspt_proc_put(proc);
+               }
+       }
+       pfg_list_runlock();
+
+       return flag;
+}
+
+static void pfg_all_del_proc(struct sspt_proc *proc)
+{
+       struct pf_group *pfg;
+
+       pfg_list_rlock();
+       list_for_each_entry(pfg, &pfg_list, list)
+               pfg_del_proc(pfg, proc);
+       pfg_list_runlock();
+}
+
+/**
+ * @brief Check task and install probes on demand
+ *
+ * @prarm task Pointer on the task_struct struct
+ * @return Void
+ */
+void check_task_and_install(struct task_struct *task)
+{
+       struct sspt_proc *proc;
+       enum pf_inst_flag flag;
+
+       flag = pfg_check_task(task);
+       switch (flag) {
+       case PIF_FIRST:
+               proc = sspt_proc_get_by_task(task);
+               if (proc) {
+                       sspt_proc_priv_create(proc);
+                       first_install(task, proc);
+                       sspt_proc_put(proc);
+               }
+               break;
+       case PIF_ADD_PFG:
+               proc = sspt_proc_get_by_task(task);
+               if (proc) {
+                       first_install(task, proc);
+                       sspt_proc_put(proc);
+               }
+               break;
+
+       case PIF_NONE:
+       case PIF_SECOND:
+               break;
+       }
+}
+
+/**
+ * @brief Check task and install probes on demand
+ *
+ * @prarm task Pointer on the task_struct struct
+ * @param page_addr Page fault address
+ * @return Void
+ */
+void call_page_fault(struct task_struct *task, unsigned long page_addr)
+{
+       struct sspt_proc *proc;
+       enum pf_inst_flag flag;
+
+       flag = pfg_check_task(task);
+       switch (flag) {
+       case PIF_FIRST:
+               proc = sspt_proc_get_by_task(task);
+               if (proc) {
+                       sspt_proc_priv_create(proc);
+                       first_install(task, proc);
+                       sspt_proc_put(proc);
+               }
+               break;
+       case PIF_ADD_PFG:
+               proc = sspt_proc_get_by_task(task);
+               if (proc) {
+                       first_install(task, proc);
+                       sspt_proc_put(proc);
+               }
+               break;
+
+       case PIF_SECOND:
+               proc = sspt_proc_get_by_task(task);
+               if (proc) {
+                       subsequent_install(task, proc, page_addr);
+                       sspt_proc_put(proc);
+               }
+               break;
+
+       case PIF_NONE:
+               break;
+       }
+}
+
+/**
+ * @brief Uninstall probes from the sspt_proc struct
+ *
+ * @prarm proc Pointer on the sspt_proc struct
+ * @return Void
+ */
+
+/* called with sspt_proc_write_lock() */
+void uninstall_proc(struct sspt_proc *proc)
+{
+       struct task_struct *task = proc->leader;
+
+       sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
+       sspt_proc_cleanup(proc);
+}
+
+
+static void mmr_from_exit(struct sspt_proc *proc)
+{
+       BUG_ON(proc->leader != current);
+
+       sspt_proc_write_lock();
+       list_del(&proc->list);
+       sspt_proc_write_unlock();
+
+       uninstall_proc(proc);
+
+       pfg_all_del_proc(proc);
+}
+
+static void mmr_from_exec(struct sspt_proc *proc)
+{
+       BUG_ON(proc->leader != current);
+
+       if (proc->suspect.after_exec) {
+               sspt_proc_uninstall(proc, proc->leader, US_UNREGS_PROBE);
+       } else {
+               mmr_from_exit(proc);
+       }
+}
+
+/**
+ * @brief Remove probes from the task on demand
+ *
+ * @prarm task Pointer on the task_struct struct
+ * @return Void
+ */
+void call_mm_release(struct task_struct *task)
+{
+       struct sspt_proc *proc;
+
+       down_read(&uninstall_sem);
+       proc = sspt_proc_get_by_task(task);
+       if (proc) {
+               if (task->flags & PF_EXITING)
+                       mmr_from_exit(proc);
+               else
+                       mmr_from_exec(proc);
+               sspt_proc_put(proc);
+       }
+       up_read(&uninstall_sem);
+}
+
+/**
+ * @brief Legacy code, it is need remove
+ *
+ * @param addr Page address
+ * @return Void
+ */
+void uninstall_page(unsigned long addr)
+{
+
+}
+
+
+static void install_cb(void *unused)
+{
+       check_task_and_install(current);
+}
+
+
+
+
+struct task_item {
+       struct list_head list;
+       struct task_struct *task;
+};
+
+static void tasks_get(struct list_head *head)
+{
+       struct task_item *item;
+       struct task_struct *task;
+
+       rcu_read_lock();
+       for_each_process(task) {
+               if (task->flags & PF_KTHREAD)
+                       continue;
+
+               if (sspt_proc_by_task(task))
+                       continue;
+
+               /* TODO: get rid of GFP_ATOMIC */
+               item = kmalloc(sizeof(*item), GFP_ATOMIC);
+               if (item == NULL) {
+                       WARN(1, "out of memory\n");
+                       goto unlock;
+               }
+
+               get_task_struct(task);
+               item->task = task;
+               list_add(&item->list, head);
+       }
+
+unlock:
+       rcu_read_unlock();
+}
+
+static void tasks_install_and_put(struct list_head *head)
+{
+       struct task_item *item, *n;
+
+       list_for_each_entry_safe(item, n, head, list) {
+               int ret;
+               struct task_struct *task;
+
+               task = item->task;
+               if (!check_task_on_filters(task))
+                       goto put_task;
+
+               ret = taskctx_run(task, install_cb, NULL);
+               if (ret) {
+                       pr_err("cannot tracking task[%u %u %s] ret=%d\n",
+                              task->tgid, task->pid, task->comm, ret);
+               }
+
+put_task:
+               put_task_struct(task);
+               list_del(&item->list);
+               kfree(item);
+       }
+}
+
+static void do_install_all(void)
+{
+       LIST_HEAD(head);
+
+       tasks_get(&head);
+       tasks_install_and_put(&head);
+}
+
+/**
+ * @brief Install probes on running processes
+ *
+ * @return Void
+ */
+void install_all(void)
+{
+       int ret;
+
+       ret = taskctx_get();
+       if (!ret) {
+               do_install_all();
+               taskctx_put();
+       } else {
+               pr_err("taskctx_get ret=%d\n", ret);
+       }
+}
+
+/**
+ * @brief Uninstall probes from all processes
+ *
+ * @return Void
+ */
+void uninstall_all(void)
+{
+       struct list_head *proc_list = sspt_proc_list();
+
+       down_write(&uninstall_sem);
+       sspt_proc_write_lock();
+       while (!list_empty(proc_list)) {
+               struct sspt_proc *proc;
+               proc = list_first_entry(proc_list, struct sspt_proc, list);
+
+               list_del(&proc->list);
+
+               sspt_proc_write_unlock();
+               uninstall_proc(proc);
+               sspt_proc_write_lock();
+       }
+       sspt_proc_write_unlock();
+       up_write(&uninstall_sem);
+}
+
+static void __do_get_proc(struct sspt_proc *proc, void *data)
+{
+       struct task_struct *task = proc->leader;
+
+       get_task_struct(task);
+       proc->__task = task;
+       proc->__mm = get_task_mm(task);
+}
+
+static void __do_put_proc(struct sspt_proc *proc, void *data)
+{
+       if (proc->__mm) {
+               mmput(proc->__mm);
+               proc->__mm = NULL;
+       }
+
+       if (proc->__task) {
+               put_task_struct(proc->__task);
+               proc->__task = NULL;
+       }
+}
+
+void get_all_procs(void)
+{
+       sspt_proc_read_lock();
+       on_each_proc_no_lock(__do_get_proc, NULL);
+       sspt_proc_read_unlock();
+}
+
+void put_all_procs(void)
+{
+       sspt_proc_read_lock();
+       on_each_proc_no_lock(__do_put_proc, NULL);
+       sspt_proc_read_unlock();
+}
+
+/**
+ * @brief For debug
+ *
+ * @param pfg Pointer to the pf_group struct
+ * @return Void
+ */
+
+/* debug */
+void pfg_print(struct pf_group *pfg)
+{
+       img_proc_print(pfg->i_proc);
+}
+EXPORT_SYMBOL_GPL(pfg_print);
+/* debug */
diff --git a/modules/us_manager/pf/pf_group.h b/modules/us_manager/pf/pf_group.h
new file mode 100644 (file)
index 0000000..a9f74f7
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * @file us_manager/pf/pf_group.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+
+#ifndef _PF_GROUP_H
+#define _PF_GROUP_H
+
+#include <linux/types.h>
+
+struct img_ip;
+struct dentry;
+struct pf_group;
+struct sspt_proc;
+struct probe_desc;
+
+
+struct pfg_msg_cb {
+       void (*msg_info)(struct task_struct *task, struct dentry *dentry);
+       void (*msg_status_info)(struct task_struct *task);
+       void (*msg_term)(struct task_struct *task);
+       void (*msg_map)(struct vm_area_struct *vma);
+       void (*msg_unmap)(unsigned long start, unsigned long end);
+};
+
+
+/* FIXME: use swap_get_dentry() and swap_put_dentry() */
+struct dentry *dentry_by_path(const char *path);
+
+struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv);
+struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv);
+struct pf_group *get_pf_group_by_comm(char *comm, void *priv);
+struct pf_group *get_pf_group_dumb(void *priv);
+void put_pf_group(struct pf_group *pfg);
+bool pfg_is_unloadable(void);
+
+int pfg_msg_cb_set(struct pf_group *pfg, struct pfg_msg_cb *msg_cb);
+void pfg_msg_cb_reset(struct pf_group *pfg);
+struct pfg_msg_cb *pfg_msg_cb_get(struct pf_group *pfg);
+
+struct img_ip *pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
+                            unsigned long offset, struct probe_desc *pd);
+void pf_unregister_probe(struct pf_group *pfg, struct img_ip *ip);
+
+void install_all(void);
+void uninstall_all(void);
+
+void get_all_procs(void);
+void put_all_procs(void);
+
+void call_page_fault(struct task_struct *task, unsigned long page_addr);
+void call_mm_release(struct task_struct *task);
+void check_task_and_install(struct task_struct *task);
+void uninstall_proc(struct sspt_proc *proc);
+
+void uninstall_page(unsigned long addr);
+
+/* debug */
+void pfg_print(struct pf_group *pfg);
+/* debug */
+
+#endif /* _PF_GROUP_H */
diff --git a/modules/us_manager/pf/proc_filters.c b/modules/us_manager/pf/proc_filters.c
new file mode 100644 (file)
index 0000000..d3d5d98
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/pf/proc_filters.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm_types.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include "proc_filters.h"
+#include <us_manager/sspt/sspt.h>
+
+
+#define VOIDP2PID(x)   ((pid_t)(unsigned long)(x))
+#define PID2VOIDP(x)   ((void *)(unsigned long)(x))
+
+static int check_dentry(struct task_struct *task, struct dentry *dentry)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = task->mm;
+
+       if (mm == NULL)
+               return 0;
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (check_vma(vma) && vma->vm_file->f_path.dentry == dentry)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static struct task_struct *call_by_dentry(struct proc_filter *self,
+                                        struct task_struct *task)
+{
+       struct dentry *dentry = (struct dentry *)self->data;
+
+       if (!dentry || check_dentry(task, dentry))
+               return task;
+
+       return NULL;
+}
+
+static inline void free_by_dentry(struct proc_filter *self)
+{
+       return;
+}
+
+static struct task_struct *call_by_tgid(struct proc_filter *self,
+                                      struct task_struct *task)
+{
+       pid_t tgid = VOIDP2PID(self->data);
+
+       if (task->tgid == tgid)
+               return task;
+
+       return NULL;
+}
+
+static inline void free_by_tgid(struct proc_filter *self)
+{
+       return;
+}
+
+static struct task_struct *call_by_comm(struct proc_filter *self,
+                                      struct task_struct *task)
+{
+       struct task_struct *parent;
+       char *comm = (char *)self->data;
+       size_t len = strnlen(comm, TASK_COMM_LEN);
+
+       if (!strncmp(comm, task->group_leader->comm, len))
+               return task;
+
+       parent = task->parent;
+       if (parent && !strncmp(comm, parent->comm, len))
+               return task;
+
+       return NULL;
+}
+
+static inline void free_by_comm(struct proc_filter *self)
+{
+       kfree(self->data);
+}
+
+/* Dumb call. Each task is exactly what we are looking for :) */
+static struct task_struct *call_dumb(struct proc_filter *self,
+                                    struct task_struct *task)
+{
+       return task;
+}
+
+/**
+ * @brief Filling pf_group struct by dentry
+ *
+ * @param pf Pointer to the proc_filter struct
+ * @param dentry Dentry
+ * @param priv Private data
+ * @return Void
+ */
+void set_pf_by_dentry(struct proc_filter *pf, struct dentry *dentry, void *priv)
+{
+       pf->call = &call_by_dentry;
+       pf->data = (void *)dentry;
+       pf->priv = priv;
+}
+
+/**
+ * @brief Filling pf_group struct by TGID
+ *
+ * @param pf Pointer to the proc_filter struct
+ * @param tgid Thread group ID
+ * @param priv Private data
+ * @return Void
+ */
+void set_pf_by_tgid(struct proc_filter *pf, pid_t tgid, void *priv)
+{
+       pf->call = &call_by_tgid;
+       pf->data = PID2VOIDP(tgid);
+       pf->priv = priv;
+}
+
+/**
+ * @brief Fill proc_filter struct for given comm
+ *
+ * @param pf Pointer to the proc_filter struct
+ * @param comm Task comm
+ * @param priv Private data
+ * @return 0 on suceess, error code on error.
+ */
+int set_pf_by_comm(struct proc_filter *pf, char *comm, void *priv)
+{
+       size_t len = strnlen(comm, TASK_COMM_LEN);
+       char *new_comm = kmalloc(len, GFP_KERNEL);
+
+       if (new_comm == NULL)
+               return -ENOMEM;
+
+       /* copy comm */
+       memcpy(new_comm, comm, len - 1);
+       new_comm[len - 1] = '\0';
+
+       pf->call = &call_by_comm;
+       pf->data = new_comm;
+       pf->priv = priv;
+
+       return 0;
+}
+
+/**
+ * @brief Filling pf_group struct for each process
+ *
+ * @param pf Pointer to the proc_filter struct
+ * @param priv Private data
+ * @return Void
+ */
+void set_pf_dumb(struct proc_filter *pf, void *priv)
+{
+       pf->call = &call_dumb;
+       pf->data = NULL;
+       pf->priv = priv;
+}
+
+/**
+ * @brief Free proc_filter struct
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @return Void
+ */
+void free_pf(struct proc_filter *filter)
+{
+       if (filter->call == &call_by_dentry)
+               free_by_dentry(filter);
+       else if (filter->call == &call_by_tgid)
+               free_by_tgid(filter);
+       else if (filter->call == &call_by_comm)
+               free_by_comm(filter);
+}
+
+/**
+ * @brief Check pf_group struct by dentry
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @param dentry Dentry
+ * @return
+ *       - 0 - false
+ *       - 1 - true
+ */
+int check_pf_by_dentry(struct proc_filter *filter, struct dentry *dentry)
+{
+       return filter->data == (void *)dentry &&
+              filter->call == &call_by_dentry;
+}
+
+/**
+ * @brief Check pf_group struct by TGID
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @param tgid Thread group ID
+ * @return
+ *       - 0 - false
+ *       - 1 - true
+ */
+int check_pf_by_tgid(struct proc_filter *filter, pid_t tgid)
+{
+       return filter->data == PID2VOIDP(tgid)
+           && filter->call == &call_by_tgid;
+}
+
+/**
+ * @brief Check proc_filter struct by comm
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @param comm Task comm
+ * @return
+ *       - 0 - false
+ *       - 1 - true
+ */
+int check_pf_by_comm(struct proc_filter *filter, char *comm)
+{
+       return ((filter->call == &call_by_comm) && (filter->data != NULL) &&
+               (!strncmp(filter->data, comm, TASK_COMM_LEN - 1)));
+}
+
+/**
+ * @brief Dumb check always true if filter is a dumb one
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @return
+ *       - 0 - false
+ *       - 1 - true
+ */
+int check_pf_dumb(struct proc_filter *filter)
+{
+       return filter->call == &call_dumb;
+}
+
+/**
+ * @brief Get priv from pf_group struct
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @return Pointer to the priv
+ */
+void *get_pf_priv(struct proc_filter *filter)
+{
+       return filter->priv;
+}
+
+/* Check function for call_page_fault() and other frequently called
+filter-check functions. It is used to call event-oriented and long-term filters
+only on specified events, but not every time memory map is changed. When
+iteraiting over the filters list, call this function on each step passing here
+pointer on filter. If it returns 1 then the filter should not be called. */
+int ignore_pf(struct proc_filter *filter)
+{
+       return filter->call == &call_by_comm;
+}
diff --git a/modules/us_manager/pf/proc_filters.h b/modules/us_manager/pf/proc_filters.h
new file mode 100644 (file)
index 0000000..fe96276
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * @file us_manager/pf/proc_filters.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+
+#ifndef _PROC_FILTERS_H
+#define _PROC_FILTERS_H
+
+#include <linux/types.h>
+
+struct dentry;
+struct task_struct;
+
+/**
+ * @struct proc_filter
+ * @breaf Filter for process
+ */
+struct proc_filter {
+       /** Callback for filtering */
+       struct task_struct *(*call)(struct proc_filter *self,
+                                   struct task_struct *task);
+       void *data;             /**< Data of callback */
+       void *priv;             /**< Private data */
+};
+
+/**
+ * @def check_task_f @hideinitializer
+ * Call filter on the task
+ *
+ * @param filter Pointer to the proc_filter struct
+ * @param task Pointer to the task_struct struct
+ */
+#define check_task_f(filter, task) ((filter)->call(filter, task))
+
+void set_pf_by_dentry(struct proc_filter *pf, struct dentry *dentry,
+                     void *priv);
+void set_pf_by_tgid(struct proc_filter *pf, pid_t tgid, void *priv);
+int set_pf_by_comm(struct proc_filter *pf, char *comm, void *priv);
+void set_pf_dumb(struct proc_filter *pf, void *priv);
+
+
+int check_pf_by_dentry(struct proc_filter *filter, struct dentry *dentry);
+int check_pf_by_tgid(struct proc_filter *filter, pid_t tgid);
+int check_pf_by_comm(struct proc_filter *filter, char *comm);
+int check_pf_dumb(struct proc_filter *filter);
+void *get_pf_priv(struct proc_filter *filter);
+
+void free_pf(struct proc_filter *filter);
+
+int ignore_pf(struct proc_filter *filter);
+
+#endif /* _PROC_FILTERS_H */
diff --git a/modules/us_manager/probes/probe_info_new.c b/modules/us_manager/probes/probe_info_new.c
new file mode 100644 (file)
index 0000000..303f332
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include "probes.h"
+#include "probe_info_new.h"
+#include "register_probes.h"
+
+
+/*
+ * handlers
+ */
+static int urp_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct uretprobe *rp = ri->rp;
+
+       if (rp) {
+               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
+               struct probe_desc *pd = NULL;
+
+               pd = ip->desc;
+               if (pd && pd->u.rp.entry_handler)
+                       return pd->u.rp.entry_handler(ri, regs);
+
+       }
+
+       return 0;
+}
+
+static int urp_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct uretprobe *rp = ri->rp;
+
+       if (rp) {
+               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
+               struct probe_desc *pd = NULL;
+
+               pd = ip->desc;
+               if (pd && pd->u.rp.ret_handler)
+                       return pd->u.rp.ret_handler(ri, regs);
+       }
+
+       return 0;
+}
+
+static int uprobe_handler(struct uprobe *p, struct pt_regs *regs)
+{
+       struct sspt_ip *ip = container_of(p, struct sspt_ip, uprobe);
+       struct probe_desc *pd = NULL;
+
+       pd = ip->desc;
+       if (pd && pd->u.p.handler)
+               return pd->u.p.handler(p, regs);
+
+       return 0;
+}
+
+/*
+ * register/unregister interface
+ */
+int pin_register(struct probe_new *probe, struct pf_group *pfg,
+                struct dentry *dentry)
+{
+       struct img_ip *ip;
+
+       ip = pf_register_probe(pfg, dentry, probe->offset, probe->desc);
+       if (IS_ERR(ip)) {
+               pr_err("%s: register probe failed\n", __func__);
+               return PTR_ERR(ip);
+       }
+
+       probe->priv = ip;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pin_register);
+
+void pin_unregister(struct probe_new *probe, struct pf_group *pfg)
+{
+       struct img_ip *ip = probe->priv;
+
+       pf_unregister_probe(pfg, ip);
+}
+EXPORT_SYMBOL_GPL(pin_unregister);
+
+
+
+
+
+/*
+ * SWAP_NEW_UP
+ */
+static int up_copy(struct probe_info *dst, const struct probe_info *src)
+{
+       return 0;
+}
+
+static void up_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *up_get_uprobe(struct sspt_ip *ip)
+{
+       return &ip->uprobe;
+}
+
+static int up_register_probe(struct sspt_ip *ip)
+{
+       return swap_register_uprobe(&ip->uprobe);
+}
+
+static void up_unregister_probe(struct sspt_ip *ip, int disarm)
+{
+       __swap_unregister_uprobe(&ip->uprobe, disarm);
+}
+
+static void up_init(struct sspt_ip *ip)
+{
+       ip->uprobe.pre_handler = uprobe_handler;
+}
+
+static void up_uninit(struct sspt_ip *ip)
+{
+}
+
+static struct probe_iface up_iface = {
+       .init = up_init,
+       .uninit = up_uninit,
+       .reg = up_register_probe,
+       .unreg = up_unregister_probe,
+       .get_uprobe = up_get_uprobe,
+       .copy = up_copy,
+       .cleanup = up_cleanup
+};
+
+
+
+
+
+/*
+ * SWAP_NEW_URP
+ */
+static int urp_copy(struct probe_info *dst, const struct probe_info *src)
+{
+       return 0;
+}
+
+static void urp_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *urp_get_uprobe(struct sspt_ip *ip)
+{
+       return &ip->retprobe.up;
+}
+
+static int urp_register_probe(struct sspt_ip *ip)
+{
+       return swap_register_uretprobe(&ip->retprobe);
+}
+
+static void urp_unregister_probe(struct sspt_ip *ip, int disarm)
+{
+       __swap_unregister_uretprobe(&ip->retprobe, disarm);
+}
+
+static void urp_init(struct sspt_ip *ip)
+{
+       ip->retprobe.entry_handler = urp_entry_handler;
+       ip->retprobe.handler = urp_ret_handler;
+       ip->retprobe.maxactive = 0;
+       /* FIXME: make dynamic size field 'data_size' */
+#ifdef CONFIG_ARM64
+       /*
+        * Loader module use field uretprobe_instance.data for storing
+        * 'struct us_priv'. For ARM64 it requires much more space.
+        */
+       ip->retprobe.data_size = 512 - sizeof(struct uretprobe_instance);
+#else /* CONFIG_ARM64 */
+       ip->retprobe.data_size = 128;
+#endif /* CONFIG_ARM64 */
+}
+
+static void urp_uninit(struct sspt_ip *ip)
+{
+}
+
+static struct probe_iface urp_iface = {
+       .init = urp_init,
+       .uninit = urp_uninit,
+       .reg = urp_register_probe,
+       .unreg = urp_unregister_probe,
+       .get_uprobe = urp_get_uprobe,
+       .copy = urp_copy,
+       .cleanup = urp_cleanup
+};
+
+
+
+
+/*
+ * init/exit()
+ */
+int pin_init(void)
+{
+       int ret;
+
+       ret = swap_register_probe_type(SWAP_NEW_UP, &up_iface);
+       if (ret)
+               return ret;
+
+       ret = swap_register_probe_type(SWAP_NEW_URP, &urp_iface);
+       if (ret)
+               swap_unregister_probe_type(SWAP_NEW_UP);
+
+       return ret;
+}
+
+void pin_exit(void)
+{
+       swap_unregister_probe_type(SWAP_NEW_URP);
+       swap_unregister_probe_type(SWAP_NEW_UP);
+}
diff --git a/modules/us_manager/probes/probe_info_new.h b/modules/us_manager/probes/probe_info_new.h
new file mode 100644 (file)
index 0000000..6c43481
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef _PROBE_INFO_NEW_H
+#define _PROBE_INFO_NEW_H
+
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <uprobe/swap_uprobes.h>
+#include "probes.h"
+
+
+struct dentry;
+struct pf_group;
+
+
+struct probe_info_new {
+       enum probe_t type;
+       union {
+               struct {
+                       uprobe_pre_handler_t handler;
+               } p;
+
+               struct {
+                       uretprobe_handler_t entry_handler;
+                       uretprobe_handler_t ret_handler;
+                       /*
+                        * FIXME: make dynamic size,
+                        *        currently data_size = sizeof(void *)
+                        */
+                       size_t data_size;
+               } rp;
+       } u;
+
+       /* private */
+       struct probe_info info;
+};
+
+struct probe_new {
+       /* reg data */
+       unsigned long offset;
+       struct probe_desc *desc;
+
+       /* unreg data */
+       void *priv;
+};
+
+
+#define MAKE_UPROBE(_handler)                          \
+       {                                               \
+               .type = SWAP_NEW_UP,                    \
+               .u.p.handler = _handler                 \
+       }
+
+#define MAKE_URPROBE(_entry, _ret, _size)              \
+       {                                               \
+               .type = SWAP_NEW_URP,                   \
+               .u.rp.entry_handler = _entry,           \
+               .u.rp.ret_handler = _ret,               \
+               .u.rp.data_size = _size                 \
+       }
+
+struct probe_info_otg {
+       struct probe_info info;
+       struct probe_info_new *data;    /* field 'data[0]' in probe_info struct */
+};
+
+int pin_register(struct probe_new *probe, struct pf_group *pfg,
+                struct dentry *dentry);
+void pin_unregister(struct probe_new *probe, struct pf_group *pfg);
+
+
+int pin_init(void);
+void pin_exit(void);
+
+
+#endif /* _PROBE_INFO_NEW_H */
diff --git a/modules/us_manager/probes/probes.c b/modules/us_manager/probes/probes.c
new file mode 100644 (file)
index 0000000..37f59f1
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/probes.c
+ *
+ * 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, 2014
+ *
+ * 2014         Alexander Aksenov: Probes interface implement
+ *
+ */
+
+#include "probes.h"
+#include "register_probes.h"
+#include "use_probes.h"
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+static struct probe_iface *probes_methods[SWAP_PROBE_MAX_VAL] = { NULL };
+
+/* 1 - correct probe type
+   0 - wrong probe type
+*/
+static inline int correct_probe_type(enum probe_t probe_type)
+{
+       if (probe_type >= SWAP_PROBE_MAX_VAL)
+               return 0;
+
+       return 1;
+}
+
+static inline int methods_exist(enum probe_t probe_type)
+{
+       if (!correct_probe_type(probe_type) ||
+           (probes_methods[probe_type] == NULL)) {
+               printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * @brief Calls specified probe type init method.
+ *
+ * @param pi Pointer to the probe_info.
+ * @param ip Pointer to the probe us_ip struct.
+ * @return Void.
+ */
+void probe_info_init(enum probe_t type, struct sspt_ip *ip)
+{
+       if (!methods_exist(type)) {
+               return;
+       }
+
+       probes_methods[type]->init(ip);
+}
+
+/**
+ * @brief Calls specified probe type uninit method.
+ *
+ * @param pi Pointer to the probe_info.
+ * @param ip Pointer to the probe us_ip struct.
+ * @return Void.
+ */
+void probe_info_uninit(enum probe_t type, struct sspt_ip *ip)
+{
+       if (!methods_exist(type)) {
+               return;
+       }
+
+       probes_methods[type]->uninit(ip);
+}
+
+/**
+ * @brief Calls specified probe type register method.
+ *
+ * @param pi Pointer to the probe_info.
+ * @param ip Pointer to the probe us_ip struct.
+ * @return -EINVAL on wrong probe type, method result otherwise.
+ */
+int probe_info_register(enum probe_t type, struct sspt_ip *ip)
+{
+       if (!methods_exist(type)) {
+               return -EINVAL;
+       }
+
+       return probes_methods[type]->reg(ip);
+}
+
+/**
+ * @brief Calls specified probe type unregister method.
+ *
+ * @param pi Pointer to the probe_info.
+ * @param ip Pointer to the probe us_ip struct.
+ * @param disarm Disarm flag.
+ * @return Void.
+ */
+void probe_info_unregister(enum probe_t type, struct sspt_ip *ip, int disarm)
+{
+       if (!methods_exist(type)) {
+               return;
+       }
+
+       probes_methods[type]->unreg(ip, disarm);
+}
+
+/**
+ * @brief Calls specified probe type get underlying uprobe method.
+ *
+ * @param pi Pointer to the probe_info.
+ * @param ip Pointer to the probe us_ip struct.
+ * @return Pointer to the uprobe struct, NULL on error.
+ */
+struct uprobe *probe_info_get_uprobe(enum probe_t type, struct sspt_ip *ip)
+{
+       if (!methods_exist(type)) {
+               return NULL;
+       }
+
+       return probes_methods[type]->get_uprobe(ip);
+}
+
+/**
+ * @brief Registers probe type.
+ *
+ * @param probe_type Number, associated with this probe type.
+ * @param pi Pointer to the probe interface structure
+ * @return 0 on succes, error code on error.
+ */
+int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi)
+{
+       if (!correct_probe_type(probe_type)) {
+               printk(KERN_ERR "SWAP US_MANAGER: incorrect probe type!\n");
+               return -EINVAL;
+       }
+
+       if (probes_methods[probe_type] != NULL)
+               printk(KERN_WARNING "SWAP US_MANAGER: Re-registering probe %d\n",
+                  probe_type);
+
+       probes_methods[probe_type] = pi;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_register_probe_type);
+
+/**
+ * @brief Unregisters probe type.
+ *
+ * @param probe_type Probe type that should be unregistered.
+ * @return Void.
+ */
+void swap_unregister_probe_type(enum probe_t probe_type)
+{
+       if (!correct_probe_type(probe_type)) {
+               printk(KERN_ERR "SWAP US_MANAGER: incorrect probe type!\n");
+               return;
+       }
+
+       probes_methods[probe_type] = NULL;
+}
+EXPORT_SYMBOL_GPL(swap_unregister_probe_type);
diff --git a/modules/us_manager/probes/probes.h b/modules/us_manager/probes/probes.h
new file mode 100644 (file)
index 0000000..8683006
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/probes.h
+ *
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * @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, 2014
+ *
+ * 2014 Alexander Aksenov : Probes interface implement
+ * 2014 Vitaliy Cherepanov: Portage
+ *
+ */
+
+
+#ifndef __PROBES_H__
+#define __PROBES_H__
+
+#include <linux/types.h>
+#include <uprobe/swap_uprobes.h>
+
+#include <preload/preload_probe.h>   /* TODO Remove */
+#include <retprobe/retprobe.h>       /* TODO Remove */
+#include <fbiprobe/fbiprobe.h>       /* TODO Remove */
+
+
+
+/* All probe types. Only us_manager should know about them - it is its own
+ * business to install proper probes on proper places.
+ */
+enum probe_t {
+       SWAP_RETPROBE = 0,          /* Retprobe */
+       SWAP_FBIPROBE = 1,          /* FBI probe */
+       SWAP_PRELOAD_PROBE = 2,     /* Preload probe */
+       SWAP_GET_CALLER = 4,        /* Get caller probe. Supports preload */
+       SWAP_GET_CALL_TYPE = 5,     /* Get call type probe. Supports preload */
+       SWAP_WRITE_MSG = 6,         /* Write messages from user space directly to 
+                                    * kernel. Supports preload */
+       SWAP_NEW_UP,
+       SWAP_NEW_URP,
+       SWAP_PROBE_MAX_VAL          /* Probes max value. */
+};
+
+/* Probe info stuct. It contains the whole information about probe. */
+struct probe_info {
+       /* Union of all SWAP supported probe types */
+       union {
+               struct retprobe_info rp_i;
+               struct fbi_info fbi_i;
+               struct preload_info pl_i;
+               struct get_caller_info gc_i;
+               struct get_call_type_info gct_i;
+               struct write_msg_info wm_i;
+       };
+};
+
+struct probe_desc {
+       enum probe_t type;
+
+       union {
+               struct {
+                       uprobe_pre_handler_t handler;
+               } p;
+
+               struct {
+                       uretprobe_handler_t entry_handler;
+                       uretprobe_handler_t ret_handler;
+                       /*
+                        * FIXME: make dynamic size,
+                        *        currently data_size = sizeof(void *)
+                        */
+                       size_t data_size;
+               } rp;
+       } u;
+
+       struct probe_info info;
+};
+
+#endif /* __PROBES_H__ */
diff --git a/modules/us_manager/probes/register_probes.h b/modules/us_manager/probes/register_probes.h
new file mode 100644 (file)
index 0000000..f981056
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __REGISTER_PROBES_H__
+#define __REGISTER_PROBES_H__
+
+#include "probes.h"
+
+struct sspt_ip;
+
+struct probe_iface {
+       void (*init)(struct sspt_ip *);
+       void (*uninit)(struct sspt_ip *);
+       int (*reg)(struct sspt_ip *);
+       void (*unreg)(struct sspt_ip *, int);
+       struct uprobe *(*get_uprobe)(struct sspt_ip *);
+       int (*copy)(struct probe_info *, const struct probe_info *);
+       void (*cleanup)(struct probe_info *);
+};
+
+int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi);
+void swap_unregister_probe_type(enum probe_t probe_type);
+
+#endif /* __REGISTER_PROBES_H__ */
diff --git a/modules/us_manager/probes/use_probes.h b/modules/us_manager/probes/use_probes.h
new file mode 100644 (file)
index 0000000..a925194
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __USE_PROBES_H__
+#define __USE_PROBES_H__
+
+#include "probes.h"
+
+struct sspt_ip;
+
+void probe_info_init(enum probe_t type, struct sspt_ip *ip);
+void probe_info_uninit(enum probe_t type, struct sspt_ip *ip);
+int probe_info_register(enum probe_t type, struct sspt_ip *ip);
+void probe_info_unregister(enum probe_t type, struct sspt_ip *ip, int disarm);
+struct uprobe *probe_info_get_uprobe(enum probe_t type, struct sspt_ip *ip);
+int probe_info_copy(const struct probe_info *pi, struct probe_info *dest);
+void probe_info_cleanup(struct probe_info *pi);
+
+#endif /* __USE_PROBES_H__ */
diff --git a/modules/us_manager/sspt/sspt.h b/modules/us_manager/sspt/sspt.h
new file mode 100644 (file)
index 0000000..1754acc
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __SSPT__
+#define __SSPT__
+
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/driver/sspt/sspt.h
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include "sspt_ip.h"
+#include "sspt_page.h"
+#include "sspt_file.h"
+#include "sspt_proc.h"
+#include "sspt_debug.h"
+#include <uprobe/swap_uprobes.h>
+
+
+#include <us_manager/us_manager.h>
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/probes/use_probes.h>
+
+
+static inline 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 inline int sspt_register_usprobe(struct sspt_ip *ip)
+{
+       int ret;
+       struct uprobe *up = NULL;
+
+       up = probe_info_get_uprobe(ip->desc->type, ip);
+
+       if (!up) {
+               printk(KERN_INFO "SWAP US_MANAGER: failed getting uprobe!\n");
+               return -EINVAL;
+       }
+
+       up->addr = (uprobe_opcode_t *)ip->orig_addr;
+       up->task = ip->page->file->proc->leader;
+       up->sm = ip->page->file->proc->sm;
+
+       ret = probe_info_register(ip->desc->type, ip);
+       if (ret) {
+               struct sspt_file *file = ip->page->file;
+               char *name = file->dentry->d_iname;
+               unsigned long addr = (unsigned long)up->addr;
+               unsigned long offset = addr - file->vm_start;
+
+               printk(KERN_ERR "probe_info_register failed %d (%s:%lx|%lx)\n",
+                               ret, name, offset,
+                               (unsigned long)ip->retprobe.up.opcode);
+       }
+
+       return ret;
+}
+
+static inline int sspt_unregister_usprobe(struct task_struct *task,
+                                         struct sspt_ip *ip,
+                                         enum US_FLAGS flag)
+{
+       struct uprobe *up = NULL;
+
+       switch (flag) {
+       case US_UNREGS_PROBE:
+               probe_info_unregister(ip->desc->type, ip, 1);
+               break;
+       case US_DISARM:
+               up = probe_info_get_uprobe(ip->desc->type, ip);
+               if (up)
+                       disarm_uprobe(up, task);
+               break;
+       case US_UNINSTALL:
+               probe_info_unregister(ip->desc->type, ip, 0);
+               break;
+       default:
+               panic("incorrect value flag=%d", flag);
+       }
+
+       return 0;
+}
+
+#endif /* __SSPT__ */
diff --git a/modules/us_manager/sspt/sspt_debug.h b/modules/us_manager/sspt/sspt_debug.h
new file mode 100644 (file)
index 0000000..afd9595
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef __SSPT_DEBUG__
+#define __SSPT_DEBUG__
+
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/driver/sspt/sspt_debug.h
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include <kprobe/swap_kprobes_deps.h>
+#include <us_manager/probes/probes.h>
+
+
+static inline void print_retprobe(struct uretprobe *rp)
+{
+       printk(KERN_INFO "###         RP: handler=%lx\n",
+                       (unsigned long)rp->handler);
+}
+
+static inline void print_ip(struct sspt_ip *ip, int i)
+{
+       if (ip->desc->type == SWAP_RETPROBE) {
+               struct uretprobe *rp = &ip->retprobe;
+
+               printk(KERN_INFO "###       addr[%2d]=%lx, R_addr=%lx\n",
+                      i, (unsigned long)ip->offset,
+                      (unsigned long)rp->up.addr);
+               print_retprobe(rp);
+       }
+}
+
+static inline void print_page_probes(const struct sspt_page *page)
+{
+       int i = 0;
+       struct sspt_ip *ip;
+
+       printk(KERN_INFO "###     offset=%lx\n", page->offset);
+       printk(KERN_INFO "###     no install:\n");
+       list_for_each_entry(ip, &page->ip_list.not_inst, list) {
+               print_ip(ip, i);
+               ++i;
+       }
+
+       printk(KERN_INFO "###     install:\n");
+       list_for_each_entry(ip, &page->ip_list.inst, list) {
+               print_ip(ip, i);
+               ++i;
+       }
+}
+
+static inline void print_file_probes(struct sspt_file *file)
+{
+       int i;
+       unsigned long table_size;
+       struct sspt_page *page = NULL;
+       struct hlist_head *head = NULL;
+       static unsigned char *NA = "N/A";
+       unsigned char *name;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       if (file == NULL) {
+               printk(KERN_INFO "### file_p == NULL\n");
+               return;
+       }
+
+       table_size = (1 << file->htable.bits);
+       name = (file->dentry) ? file->dentry->d_iname : NA;
+
+       printk(KERN_INFO "### print_file_probes: path=%s, d_iname=%s, "
+              "table_size=%lu, vm_start=%lx\n",
+              file->dentry->d_iname, name, table_size, file->vm_start);
+
+       down_read(&file->htable.sem);
+       for (i = 0; i < table_size; ++i) {
+               head = &file->htable.heads[i];
+               swap_hlist_for_each_entry_rcu(page, node, head, hlist) {
+                       print_page_probes(page);
+               }
+       }
+       up_read(&file->htable.sem);
+}
+
+static inline void print_proc_probes(struct sspt_proc *proc)
+{
+       struct sspt_file *file;
+
+       printk(KERN_INFO "### print_proc_probes\n");
+       down_read(&proc->files.sem);
+       list_for_each_entry(file, &proc->files.head, list) {
+               print_file_probes(file);
+       }
+       up_read(&proc->files.sem);
+       printk(KERN_INFO "### print_proc_probes\n");
+}
+
+
+#endif /* __SSPT_DEBUG__ */
diff --git a/modules/us_manager/sspt/sspt_feature.c b/modules/us_manager/sspt/sspt_feature.c
new file mode 100644 (file)
index 0000000..bc2c84d
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/us_manager/sspt/sspt_feature.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include "sspt_feature.h"
+#include "sspt_proc.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+
+struct sspt_feature {
+       struct list_head feature_list;
+};
+
+struct sspt_feature_img {
+       struct list_head list;
+
+       void *(*alloc)(void);
+       void (*free)(void *data);
+};
+
+struct sspt_feature_data {
+       struct list_head list;
+
+       struct sspt_feature_img *img;
+       void *data;
+};
+
+static DEFINE_SPINLOCK(feature_img_lock);
+static LIST_HEAD(feature_img_list);
+
+static struct sspt_feature_data *create_feature_data(
+       struct sspt_feature_img *img)
+{
+       struct sspt_feature_data *fd;
+
+       fd = kmalloc(sizeof(*fd), GFP_ATOMIC);
+       if (fd) {
+               INIT_LIST_HEAD(&fd->list);
+               fd->img = img;
+               fd->data = img->alloc();
+       }
+
+       return fd;
+}
+
+static void destroy_feature_data(struct sspt_feature_data *fd)
+{
+       fd->img->free(fd->data);
+       kfree(fd);
+}
+
+/**
+ * @brief Create sspt_feature struct
+ *
+ * @return Pointer to the created sspt_feature struct
+ */
+struct sspt_feature *sspt_create_feature(void)
+{
+       struct sspt_feature *f;
+
+       f = kmalloc(sizeof(*f), GFP_ATOMIC);
+       if (f) {
+               struct sspt_feature_data *fd;
+               struct sspt_feature_img *fi;
+               unsigned long flags;
+
+               INIT_LIST_HEAD(&f->feature_list);
+
+               spin_lock_irqsave(&feature_img_lock, flags);
+               list_for_each_entry(fi, &feature_img_list, list) {
+                       fd = create_feature_data(fi);
+                        if (fd) /* add to list */
+                               list_add(&fd->list, &f->feature_list);
+               }
+               spin_unlock_irqrestore(&feature_img_lock, flags);
+       }
+
+       return f;
+}
+
+/**
+ * @brief Destroy sspt_feature struct
+ *
+ * @param f remove object
+ * @return Void
+ */
+void sspt_destroy_feature(struct sspt_feature *f)
+{
+       struct sspt_feature_data *fd, *n;
+
+       list_for_each_entry_safe(fd, n, &f->feature_list, list) {
+               /* delete from list */
+               list_del(&fd->list);
+               destroy_feature_data(fd);
+       }
+
+       kfree(f);
+}
+
+static void add_feature_img_to_list(struct sspt_feature_img *fi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&feature_img_lock, flags);
+       list_add(&fi->list, &feature_img_list);
+       spin_unlock_irqrestore(&feature_img_lock, flags);
+}
+
+static void del_feature_img_from_list(struct sspt_feature_img *fi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&feature_img_lock, flags);
+       list_del(&fi->list);
+       spin_unlock_irqrestore(&feature_img_lock, flags);
+}
+
+static struct sspt_feature_img *create_feature_img(void *(*alloc)(void),
+                                                  void (*free)(void *data))
+{
+       struct sspt_feature_img *fi;
+
+       fi = kmalloc(sizeof(*fi), GFP_ATOMIC);
+       if (fi) {
+               INIT_LIST_HEAD(&fi->list);
+               fi->alloc = alloc;
+               fi->free = free;
+
+               add_feature_img_to_list(fi);
+       }
+
+       return fi;
+}
+
+static void destroy_feature_img(struct sspt_feature_img *fi)
+{
+       del_feature_img_from_list(fi);
+
+       kfree(fi);
+}
+
+static void del_feature_by_img(struct sspt_feature *f,
+                              struct sspt_feature_img *img)
+{
+       struct sspt_feature_data *fd;
+
+       list_for_each_entry(fd, &f->feature_list, list) {
+               if (img == fd->img) {
+                       /* delete from list */
+                       list_del(&fd->list);
+                       destroy_feature_data(fd);
+                       break;
+               }
+       }
+}
+
+static void del_feature_from_proc(struct sspt_proc *proc, void *data)
+{
+       del_feature_by_img(proc->feature, (struct sspt_feature_img *)data);
+}
+
+/**
+ * @brief Get data for feature
+ *
+ * @param f Pointer to the sspt_feature struct
+ * @param id Feature ID
+ * @return Pointer to the data
+ */
+void *sspt_get_feature_data(struct sspt_feature *f, sspt_feature_id_t id)
+{
+       struct sspt_feature_img *img = (struct sspt_feature_img *)id;
+       struct sspt_feature_data *fd;
+
+       list_for_each_entry(fd, &f->feature_list, list) {
+               if (img == fd->img)
+                       return fd->data;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sspt_get_feature_data);
+
+/**
+ * @brief Register sspt feature
+ *
+ * @param alloc Callback for allocating data
+ * @param free Callback to release data
+ * @return Feature ID
+ */
+sspt_feature_id_t sspt_register_feature(void *(*alloc)(void),
+                                       void (*free)(void *data))
+{
+       struct sspt_feature_img *fi;
+
+       fi = create_feature_img(alloc, free);
+
+       /* TODO: add to already instrumentation process */
+
+       return (sspt_feature_id_t)fi;
+}
+EXPORT_SYMBOL_GPL(sspt_register_feature);
+
+/**
+ * @brief Unregister sspt feature
+ *
+ * @param id Feature ID
+ * @return Void
+ */
+void sspt_unregister_feature(sspt_feature_id_t id)
+{
+       struct sspt_feature_img *fi = (struct sspt_feature_img *)id;
+
+       on_each_proc(del_feature_from_proc, (void *)fi);
+       destroy_feature_img(fi);
+}
+EXPORT_SYMBOL_GPL(sspt_unregister_feature);
diff --git a/modules/us_manager/sspt/sspt_feature.h b/modules/us_manager/sspt/sspt_feature.h
new file mode 100644 (file)
index 0000000..a500bc6
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _SSPT_FEATUER_H
+#define _SSPT_FEATUER_H
+
+/**
+ * @file us_manager/sspt/sspt_feature.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+struct sspt_feature;
+
+typedef void *sspt_feature_id_t;       /**< @brief sspt feature ID type */
+#define SSPT_FEATURE_ID_BAD    NULL    /**< @def SSPT_FEATURE_ID_BAD */
+
+struct sspt_feature *sspt_create_feature(void);
+void sspt_destroy_feature(struct sspt_feature *f);
+
+void *sspt_get_feature_data(struct sspt_feature *f, sspt_feature_id_t id);
+sspt_feature_id_t sspt_register_feature(void *(*alloc)(void),
+                                       void (*free)(void *data));
+void sspt_unregister_feature(sspt_feature_id_t id);
+
+#endif /* _SSPT_FEATUER_H */
diff --git a/modules/us_manager/sspt/sspt_file.c b/modules/us_manager/sspt/sspt_file.c
new file mode 100644 (file)
index 0000000..2c74b74
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/driver/sspt/sspt_file.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include "sspt.h"
+#include "sspt_file.h"
+#include "sspt_page.h"
+#include "sspt_proc.h"
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <linux/sched.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <us_manager/probes/probes.h>
+#include <us_manager/img/img_ip.h>
+
+static int calculation_hash_bits(int cnt)
+{
+       int bits;
+       for (bits = 1; cnt >>= 1; ++bits)
+               ;
+
+       return bits;
+}
+
+static unsigned long htable_size(const struct sspt_file *file)
+{
+       return 1 << file->htable.bits;
+}
+
+static struct hlist_head *htable_head_by_idx(const struct sspt_file *file,
+                                            unsigned long idx)
+{
+       return &file->htable.heads[idx];
+}
+
+static struct hlist_head *htable_head_by_key(const struct sspt_file *file,
+                                            unsigned long offset)
+{
+       unsigned long idx = hash_ptr((void *)offset, file->htable.bits);
+
+       return htable_head_by_idx(file, idx);
+}
+
+/**
+ * @brief Create sspt_file struct
+ *
+ * @param dentry Dentry of file
+ * @param page_cnt Size of hash-table
+ * @return Pointer to the created sspt_file struct
+ */
+struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt)
+{
+       int i, table_size;
+       struct hlist_head *heads;
+       struct sspt_file *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
+
+       if (obj == NULL)
+               return NULL;
+
+       INIT_LIST_HEAD(&obj->list);
+       obj->proc = NULL;
+       obj->dentry = dentry;
+       obj->loaded = 0;
+       obj->vm_start = 0;
+       obj->vm_end = 0;
+
+       obj->htable.bits = calculation_hash_bits(page_cnt);
+       table_size = htable_size(obj);
+
+       heads = kmalloc(sizeof(*obj->htable.heads) * table_size, GFP_ATOMIC);
+       if (heads == NULL)
+               goto err;
+
+       for (i = 0; i < table_size; ++i)
+               INIT_HLIST_HEAD(&heads[i]);
+
+       obj->htable.heads = heads;
+       init_rwsem(&obj->htable.sem);
+
+       return obj;
+
+err:
+       kfree(obj);
+       return NULL;
+}
+
+/**
+ * @brief Remove sspt_file struct
+ *
+ * @param file remove object
+ * @return Void
+ */
+void sspt_file_free(struct sspt_file *file)
+{
+       struct hlist_head *head;
+       struct sspt_page *page;
+       int i, table_size = htable_size(file);
+       struct hlist_node *n;
+       DECLARE_NODE_PTR_FOR_HLIST(p);
+
+       down_write(&file->htable.sem);
+       for (i = 0; i < table_size; ++i) {
+               head = htable_head_by_idx(file, i);
+               swap_hlist_for_each_entry_safe(page, p, n, head, hlist) {
+                       hlist_del(&page->hlist);
+                       sspt_page_clean(page);
+                       sspt_page_put(page);
+               }
+       }
+       up_write(&file->htable.sem);
+
+       kfree(file->htable.heads);
+       kfree(file);
+}
+
+static void sspt_add_page(struct sspt_file *file, struct sspt_page *page)
+{
+       page->file = file;
+       hlist_add_head(&page->hlist, htable_head_by_key(file, page->offset));
+}
+
+static struct sspt_page *sspt_find_page(struct sspt_file *file,
+                                       unsigned long offset)
+{
+       struct hlist_head *head = htable_head_by_key(file, offset);
+       struct sspt_page *page;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       swap_hlist_for_each_entry(page, node, head, hlist) {
+               if (page->offset == offset)
+                       return page;
+       }
+
+       return NULL;
+}
+
+static struct sspt_page *sspt_find_page_or_new(struct sspt_file *file,
+                                              unsigned long offset)
+{
+       struct sspt_page *page;
+
+       down_write(&file->htable.sem);
+       page = sspt_find_page(file, offset);
+       if (page == NULL) {
+               page = sspt_page_create(offset);
+               if (page)
+                       sspt_add_page(file, page);
+       }
+       up_write(&file->htable.sem);
+
+       return page;
+}
+
+/**
+ * @brief Get sspt_page from sspt_file
+ *
+ * @param file Pointer to the sspt_file struct
+ * @param page Page address
+ * @return Pointer to the sspt_page struct
+ */
+struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
+                                       unsigned long page)
+{
+       unsigned long offset;
+       struct sspt_page *p;
+
+       if (file->vm_start > page || file->vm_end < page) {
+               /* TODO: or panic?! */
+               printk(KERN_INFO "ERROR: file_p[vm_start..vm_end] <> page: "
+                      "file_p[vm_start=%lx, vm_end=%lx, "
+                      "d_iname=%s] page=%lx\n",
+                      file->vm_start, file->vm_end,
+                      file->dentry->d_iname, page);
+               return NULL;
+       }
+
+       offset = page - file->vm_start;
+
+       down_read(&file->htable.sem);
+       p = sspt_find_page(file, offset);
+       up_read(&file->htable.sem);
+
+       return p;
+}
+
+/**
+ * @brief Add instruction pointer to sspt_file
+ *
+ * @param file Pointer to the sspt_file struct
+ * @param offset File offset
+ * @param args Function arguments
+ * @param ret_type Return type
+ * @return Void
+ */
+void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip)
+{
+       unsigned long offset = 0;
+       struct sspt_page *page = NULL;
+       struct sspt_ip *ip = NULL;
+
+       offset = img_ip->addr & PAGE_MASK;
+       page = sspt_find_page_or_new(file, offset);
+       if (!page)
+               return;
+
+       ip = sspt_ip_create(img_ip, page);
+       if (!ip)
+               return;
+
+       probe_info_init(ip->desc->type, ip);
+}
+
+void sspt_file_on_each_ip(struct sspt_file *file,
+                         void (*func)(struct sspt_ip *, void *), void *data)
+{
+       int i;
+       const int table_size = htable_size(file);
+       struct sspt_page *page;
+       struct hlist_head *head;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       down_read(&file->htable.sem);
+       for (i = 0; i < table_size; ++i) {
+               head = htable_head_by_idx(file, i);
+               swap_hlist_for_each_entry(page, node, head, hlist)
+                       sspt_page_on_each_ip(page, func, data);
+       }
+       up_read(&file->htable.sem);
+}
+
+/**
+ * @brief Check install sspt_file (legacy code, it is need remove)
+ *
+ * @param file Pointer to the sspt_file struct
+ * @return
+ *       - 0 - false
+ *       - 1 - true
+ */
+int sspt_file_check_install_pages(struct sspt_file *file)
+{
+       int ret = 0;
+       int i, table_size;
+       struct sspt_page *page;
+       struct hlist_head *head;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       table_size = htable_size(file);
+
+       down_read(&file->htable.sem);
+       for (i = 0; i < table_size; ++i) {
+               head = htable_head_by_idx(file, i);
+               swap_hlist_for_each_entry(page, node, head, hlist) {
+                       if (sspt_page_is_installed(page)) {
+                               ret = 1;
+                               goto unlock;
+                       }
+               }
+       }
+
+unlock:
+       up_read(&file->htable.sem);
+       return ret;
+}
+
+/**
+ * @brief Install sspt_file
+ *
+ * @param file Pointer to the sspt_file struct
+ * @return Void
+ */
+void sspt_file_install(struct sspt_file *file)
+{
+       struct sspt_page *page = NULL;
+       struct hlist_head *head = NULL;
+       int i, table_size = htable_size(file);
+       unsigned long page_addr;
+       struct mm_struct *mm;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       down_read(&file->htable.sem);
+       for (i = 0; i < table_size; ++i) {
+               head = htable_head_by_idx(file, i);
+               swap_hlist_for_each_entry(page, node, head, hlist) {
+                       unsigned long offset = page->offset;
+
+#ifdef CONFIG_64BIT
+                       /* Reset most significant bit for only 64-bit */
+                       offset &= (~(1UL << 63));
+#endif /* CONFIG_64BIT */
+
+                       page_addr = file->vm_start + offset;
+                       if (page_addr < file->vm_start ||
+                           page_addr >= file->vm_end)
+                               continue;
+
+                       mm = page->file->proc->leader->mm;
+                       if (page_present(mm, page_addr))
+                               sspt_register_page(page, file);
+               }
+       }
+       up_read(&file->htable.sem);
+}
+
+/**
+ * @brief Uninstall sspt_file
+ *
+ * @param file Pointer to the sspt_file struct
+ * @param task Pointer to the task_stract struct
+ * @param flag Action for probes
+ * @return Void
+ */
+int sspt_file_uninstall(struct sspt_file *file,
+                       struct task_struct *task,
+                       enum US_FLAGS flag)
+{
+       int i, err = 0;
+       int table_size = htable_size(file);
+       struct sspt_page *page;
+       struct hlist_head *head;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       down_read(&file->htable.sem);
+       for (i = 0; i < table_size; ++i) {
+               head = htable_head_by_idx(file, i);
+               swap_hlist_for_each_entry(page, node, head, hlist) {
+                       err = sspt_unregister_page(page, flag, task);
+                       if (err != 0) {
+                               printk(KERN_INFO "ERROR sspt_file_uninstall: "
+                                      "err=%d\n", err);
+                               up_read(&file->htable.sem);
+                               return err;
+                       }
+               }
+       }
+       up_read(&file->htable.sem);
+
+       if (flag != US_DISARM) {
+               file->loaded = 0;
+               file->vm_start = 0;
+               file->vm_end = 0;
+       }
+
+       return err;
+}
+
+/**
+ * @brief Set mapping for sspt_file
+ *
+ * @param file Pointer to the sspt_file struct
+ * @param vma Pointer to the vm_area_struct struct
+ * @return Void
+ */
+void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma)
+{
+       if (file->loaded == 0) {
+               file->loaded = 1;
+               file->vm_start = vma->vm_start;
+               file->vm_end = vma->vm_end;
+       }
+}
diff --git a/modules/us_manager/sspt/sspt_file.h b/modules/us_manager/sspt/sspt_file.h
new file mode 100644 (file)
index 0000000..38d34aa
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef __SSPT_FILE__
+#define __SSPT_FILE__
+
+/**
+ * @file us_manager/sspt/sspt_file.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+#include "sspt_ip.h"
+#include <linux/types.h>
+#include <linux/rwsem.h>
+
+enum US_FLAGS;
+struct vm_area_struct;
+
+/**
+ * @struct sspt_file
+ * @breaf Image of file for specified process
+ */
+struct sspt_file {
+       /* sspt_proc */
+       struct list_head list;          /**< For sspt_proc */
+       struct sspt_proc *proc;         /**< Pointer to the proc (parent) */
+
+       /* sspt_page */
+       struct {
+               struct rw_semaphore sem;        /**< Semaphore for hash-table */
+               unsigned long bits;             /**< Hash-table size */
+               struct hlist_head *heads;       /**< Heads for pages */
+       } htable;
+
+       struct dentry *dentry;          /**< Dentry of file */
+       unsigned long vm_start;         /**< VM start */
+       unsigned long vm_end;           /**< VM end */
+       unsigned loaded:1;              /**< Flag of loading */
+};
+
+
+struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt);
+void sspt_file_free(struct sspt_file *file);
+
+struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
+                                       unsigned long page);
+void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip);
+
+void sspt_file_on_each_ip(struct sspt_file *file,
+                         void (*func)(struct sspt_ip *, void *), void *data);
+
+int sspt_file_check_install_pages(struct sspt_file *file);
+void sspt_file_install(struct sspt_file *file);
+int sspt_file_uninstall(struct sspt_file *file,
+                       struct task_struct *task,
+                       enum US_FLAGS flag);
+void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma);
+
+#endif /* __SSPT_FILE__ */
diff --git a/modules/us_manager/sspt/sspt_filter.c b/modules/us_manager/sspt/sspt_filter.c
new file mode 100644 (file)
index 0000000..f7a0799
--- /dev/null
@@ -0,0 +1,36 @@
+#include <linux/list.h>
+#include <linux/slab.h>
+#include "sspt_filter.h"
+#include "sspt_proc.h"
+#include "../pf/pf_group.h"
+
+
+struct sspt_filter *sspt_filter_create(struct sspt_proc *proc,
+                                      struct pf_group *pfg)
+{
+       struct sspt_filter *fl;
+
+       fl = kmalloc(sizeof(*fl), GFP_ATOMIC);
+       if (fl == NULL)
+               return NULL;
+
+       INIT_LIST_HEAD(&fl->list);
+
+       fl->proc = proc;
+       fl->pfg = pfg;
+       fl->pfg_is_inst = false;
+
+       return fl;
+}
+
+void sspt_filter_free(struct sspt_filter *fl)
+{
+       if (fl->pfg_is_inst) {
+               struct pfg_msg_cb *cb = pfg_msg_cb_get(fl->pfg);
+
+               if (cb && cb->msg_term)
+                       cb->msg_term(fl->proc->leader);
+       }
+
+       kfree(fl);
+}
diff --git a/modules/us_manager/sspt/sspt_filter.h b/modules/us_manager/sspt/sspt_filter.h
new file mode 100644 (file)
index 0000000..faeac80
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __SSPT_FILTER_H__
+#define __SSPT_FILTER_H__
+
+#include <linux/types.h>
+
+struct pf_group;
+struct sspt_proc;
+
+struct sspt_filter {
+       struct list_head list;
+       struct sspt_proc *proc;
+       struct pf_group *pfg;
+       bool pfg_is_inst;
+};
+
+struct sspt_filter *sspt_filter_create(struct sspt_proc *proc,
+                                      struct pf_group *pfg);
+void sspt_filter_free(struct sspt_filter *fl);
+
+#endif /* __SSPT_FILTER_H__ */
diff --git a/modules/us_manager/sspt/sspt_ip.c b/modules/us_manager/sspt/sspt_ip.c
new file mode 100644 (file)
index 0000000..0f0b4ff
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/driver/sspt/ip.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include "sspt_ip.h"
+#include "sspt_page.h"
+#include "sspt_file.h"
+#include <us_manager/probes/use_probes.h>
+#include <us_manager/img/img_ip.h>
+
+/**
+ * @brief Create us_ip struct
+ *
+ * @param page User page
+ * @param offset Function offset from the beginning of the page
+ * @param probe_i Pointer to the probe data.
+ * @param page Pointer to the parent sspt_page struct
+ * @return Pointer to the created us_ip struct
+ */
+struct sspt_ip *sspt_ip_create(struct img_ip *img_ip, struct sspt_page *page)
+{
+       struct sspt_ip *ip;
+
+       ip = kmalloc(sizeof(*ip), GFP_ATOMIC);
+       if (!ip)
+               return NULL;
+
+       memset(ip, 0, sizeof(*ip));
+       INIT_LIST_HEAD(&ip->list);
+       INIT_LIST_HEAD(&ip->img_list);
+       ip->offset = img_ip->addr & ~PAGE_MASK;
+       ip->desc = img_ip->desc;
+       atomic_set(&ip->usage, 2);      /* for 'img_ip' and 'page' */
+
+       /* add to img_ip list */
+       img_ip_get(img_ip);
+       img_ip_lock(img_ip);
+       img_ip_add_ip(img_ip, ip);
+       img_ip_unlock(img_ip);
+
+       /* add to page list */
+       sspt_page_get(page);
+       sspt_page_lock(page);
+       sspt_page_add_ip(page, ip);
+       sspt_page_unlock(page);
+
+       return ip;
+}
+
+static void sspt_ip_free(struct sspt_ip *ip)
+{
+       WARN_ON(!list_empty(&ip->list) || !list_empty(&ip->img_list));
+
+       kfree(ip);
+}
+
+void sspt_ip_get(struct sspt_ip *ip)
+{
+       atomic_inc(&ip->usage);
+}
+
+void sspt_ip_put(struct sspt_ip *ip)
+{
+       if (atomic_dec_and_test(&ip->usage))
+               sspt_ip_free(ip);
+}
+
+void sspt_ip_clean(struct sspt_ip *ip)
+{
+       bool put_page = false;
+       bool put_ip = false;
+
+       /* remove from page */
+       sspt_page_lock(ip->page);
+       if (!list_empty(&ip->list)) {
+               list_del_init(&ip->list);
+               put_page = true;
+       }
+       sspt_page_unlock(ip->page);
+       if (put_page) {
+               sspt_page_put(ip->page);
+               sspt_ip_put(ip);
+       }
+
+       /* remove from img_ip */
+       img_ip_lock(ip->img_ip);
+       if (!list_empty(&ip->img_list)) {
+               list_del_init(&ip->img_list);
+               put_ip = true;
+       }
+       img_ip_unlock(ip->img_ip);
+       if (put_ip) {
+               img_ip_put(ip->img_ip);
+               sspt_ip_put(ip);
+       }
+}
diff --git a/modules/us_manager/sspt/sspt_ip.h b/modules/us_manager/sspt/sspt_ip.h
new file mode 100644 (file)
index 0000000..226173e
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _SSPT_IP
+#define _SSPT_IP
+
+/**
+ * @file us_manager/sspt/ip.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <uprobe/swap_uprobes.h>
+#include <us_manager/probes/probes.h>
+
+struct sspt_page;
+
+/**
+ * @struct sspt_ip
+ * @breaf Image of instrumentation pointer for specified process
+ */
+struct sspt_ip {
+       /* sspt_page */
+       struct list_head list;      /**< For sspt_page */
+       struct sspt_page *page;     /**< Pointer on the page (parent) */
+
+       /* img_ip */
+       struct img_ip *img_ip;      /**< Pointer on the img_ip (parent) */
+       struct list_head img_list;  /**< For img_ip */
+
+       atomic_t usage;
+
+       unsigned long orig_addr;    /**< Function address */
+       unsigned long offset;       /**< Page offset */
+
+       struct probe_desc *desc;    /**< Probe's data */
+
+       union {
+               struct uretprobe retprobe;
+               struct uprobe uprobe;
+       };
+};
+
+
+struct sspt_ip *sspt_ip_create(struct img_ip *img_ip, struct sspt_page *page);
+void sspt_ip_clean(struct sspt_ip *ip);
+void sspt_ip_get(struct sspt_ip *ip);
+void sspt_ip_put(struct sspt_ip *ip);
+
+
+#endif /* _SSPT_IP */
diff --git a/modules/us_manager/sspt/sspt_page.c b/modules/us_manager/sspt/sspt_page.c
new file mode 100644 (file)
index 0000000..6fa19a2
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/driver/sspt/sspt_page.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include "sspt.h"
+#include "sspt_page.h"
+#include "sspt_file.h"
+#include "sspt_ip.h"
+#include <us_manager/probes/use_probes.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+/**
+ * @brief Create sspt_page struct
+ *
+ * @param offset File ofset
+ * @return Pointer to the created sspt_page struct
+ */
+struct sspt_page *sspt_page_create(unsigned long offset)
+{
+       struct sspt_page *obj = kmalloc(sizeof(*obj), GFP_KERNEL);
+       if (obj) {
+               INIT_HLIST_NODE(&obj->hlist);
+               mutex_init(&obj->ip_list.mtx);
+               INIT_LIST_HEAD(&obj->ip_list.inst);
+               INIT_LIST_HEAD(&obj->ip_list.not_inst);
+               obj->offset = offset;
+               obj->file = NULL;
+               kref_init(&obj->ref);
+       }
+
+       return obj;
+}
+
+void sspt_page_clean(struct sspt_page *page)
+{
+       struct sspt_ip *ip, *n;
+       LIST_HEAD(head);
+
+       sspt_page_lock(page);
+       WARN_ON(!list_empty(&page->ip_list.inst));
+       list_for_each_entry_safe(ip, n, &page->ip_list.inst, list) {
+               sspt_ip_get(ip);
+               list_move(&ip->list, &head);
+       }
+
+       list_for_each_entry_safe(ip, n, &page->ip_list.not_inst, list) {
+               sspt_ip_get(ip);
+               list_move(&ip->list, &head);
+       }
+
+       while (!list_empty(&head)) {
+               ip = list_first_entry(&head, struct sspt_ip ,list);
+               sspt_page_unlock(page);
+
+               sspt_ip_clean(ip);
+
+               sspt_page_lock(page);
+               sspt_ip_put(ip);
+       }
+       sspt_page_unlock(page);
+}
+
+static void sspt_page_release(struct kref *ref)
+{
+       struct sspt_page *page = container_of(ref, struct sspt_page, ref);
+
+       WARN_ON(!list_empty(&page->ip_list.inst) ||
+               !list_empty(&page->ip_list.not_inst));
+
+       kfree(page);
+}
+
+void sspt_page_get(struct sspt_page *page)
+{
+       kref_get(&page->ref);
+}
+
+void sspt_page_put(struct sspt_page *page)
+{
+       kref_put(&page->ref, sspt_page_release);
+}
+
+/**
+ * @brief Add instruction pointer to sspt_page
+ *
+ * @param page Pointer to the sspt_page struct
+ * @param ip Pointer to the us_ip struct
+ * @return Void
+ */
+void sspt_page_add_ip(struct sspt_page *page, struct sspt_ip *ip)
+{
+       ip->page = page;
+       list_add(&ip->list, &page->ip_list.not_inst);
+}
+
+void sspt_page_lock(struct sspt_page *page)
+{
+       mutex_lock(&page->ip_list.mtx);
+}
+
+void sspt_page_unlock(struct sspt_page *page)
+{
+       mutex_unlock(&page->ip_list.mtx);
+}
+
+/**
+ * @brief Check if probes are set on the page
+ *
+ * @param page Pointer to the sspt_page struct
+ * @return Boolean
+ */
+bool sspt_page_is_installed(struct sspt_page *page)
+{
+       return !list_empty(&page->ip_list.inst);
+}
+
+bool sspt_page_is_installed_ip(struct sspt_page *page, struct sspt_ip *ip)
+{
+       bool result = false; /* not installed by default */
+       struct sspt_ip *p;
+
+       sspt_page_lock(page);
+       list_for_each_entry(p, &page->ip_list.inst, list) {
+               if (p == ip) {
+                       result = true;
+                       goto unlock;
+               }
+       }
+
+unlock:
+       sspt_page_unlock(page);
+
+       return result;
+}
+
+/**
+ * @brief Install probes on the page
+ *
+ * @param page Pointer to the sspt_page struct
+ * @param file Pointer to the sspt_file struct
+ * @return Error code
+ */
+int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
+{
+       int err = 0;
+       struct sspt_ip *ip, *n;
+       LIST_HEAD(not_inst_head);
+
+       mutex_lock(&page->ip_list.mtx);
+       if (list_empty(&page->ip_list.not_inst))
+               goto unlock;
+
+       list_for_each_entry_safe(ip, n, &page->ip_list.not_inst, list) {
+               /* set virtual address */
+               ip->orig_addr = file->vm_start + page->offset + ip->offset;
+
+               err = sspt_register_usprobe(ip);
+               if (err) {
+                       sspt_ip_get(ip);
+                       list_move(&ip->list, &not_inst_head);
+                       continue;
+               }
+       }
+
+       list_splice_init(&page->ip_list.not_inst, &page->ip_list.inst);
+
+unlock:
+       mutex_unlock(&page->ip_list.mtx);
+
+       list_for_each_entry_safe(ip, n, &not_inst_head, list) {
+               sspt_ip_clean(ip);
+               sspt_ip_put(ip);
+       }
+
+       return 0;
+}
+
+/**
+ * @brief Uninstall probes on the page
+ *
+ * @param page Pointer to the sspt_page struct
+ * @param flag Action for probes
+ * @param task Pointer to the task_struct struct
+ * @return Error code
+ */
+int sspt_unregister_page(struct sspt_page *page,
+                        enum US_FLAGS flag,
+                        struct task_struct *task)
+{
+       int err = 0;
+       struct sspt_ip *ip;
+
+       mutex_lock(&page->ip_list.mtx);
+       if (list_empty(&page->ip_list.inst))
+               goto unlock;
+
+       list_for_each_entry(ip, &page->ip_list.inst, list) {
+               err = sspt_unregister_usprobe(task, ip, flag);
+               if (err != 0) {
+                       WARN_ON(1);
+                       break;
+               }
+       }
+
+       if (flag != US_DISARM)
+               list_splice_init(&page->ip_list.inst, &page->ip_list.not_inst);
+
+unlock:
+       mutex_unlock(&page->ip_list.mtx);
+       return err;
+}
+
+void sspt_page_on_each_ip(struct sspt_page *page,
+                         void (*func)(struct sspt_ip *, void *), void *data)
+{
+       struct sspt_ip *ip;
+
+       mutex_lock(&page->ip_list.mtx);
+       list_for_each_entry(ip, &page->ip_list.inst, list)
+               func(ip, data);
+       mutex_unlock(&page->ip_list.mtx);
+}
diff --git a/modules/us_manager/sspt/sspt_page.h b/modules/us_manager/sspt/sspt_page.h
new file mode 100644 (file)
index 0000000..bf7fa89
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef __SSPT_PAGE__
+#define __SSPT_PAGE__
+
+/**
+ * @file us_manager/sspt/sspt_page.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/kref.h>
+
+struct sspt_ip;
+struct sspt_file;
+struct task_struct;
+enum US_FLAGS;
+
+/**
+ * @struct sspt_page
+ * @breaf Image of page for specified process
+ */
+struct sspt_page {
+       /* sspt_file */
+       struct hlist_node hlist;                /**< For sspt_file */
+       struct sspt_file *file;                 /**< Ptr to the file (parent) */
+
+       /* sspt_ip */
+       struct {
+               struct mutex mtx;               /**< Lock page */
+               struct list_head inst;          /**< For installed ip */
+               struct list_head not_inst;      /**< For don'tinstalled ip */
+       } ip_list;
+
+       unsigned long offset;                   /**< File offset */
+
+       struct kref ref;
+};
+
+struct sspt_page *sspt_page_create(unsigned long offset);
+void sspt_page_clean(struct sspt_page *page);
+void sspt_page_get(struct sspt_page *page);
+void sspt_page_put(struct sspt_page *page);
+
+bool sspt_page_is_installed_ip(struct sspt_page *page, struct sspt_ip *ip);
+void sspt_page_add_ip(struct sspt_page *page, struct sspt_ip *ip);
+void sspt_page_lock(struct sspt_page *page);
+void sspt_page_unlock(struct sspt_page *page);
+
+bool sspt_page_is_installed(struct sspt_page *page);
+
+int sspt_register_page(struct sspt_page *page, struct sspt_file *file);
+
+int sspt_unregister_page(struct sspt_page *page,
+                        enum US_FLAGS flag,
+                        struct task_struct *task);
+
+void sspt_page_on_each_ip(struct sspt_page *page,
+                         void (*func)(struct sspt_ip *, void *), void *data);
+
+#endif /* __SSPT_PAGE__ */
diff --git a/modules/us_manager/sspt/sspt_proc.c b/modules/us_manager/sspt/sspt_proc.c
new file mode 100644 (file)
index 0000000..bf6a2e6
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/driver/sspt/sspt_proc.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include "sspt.h"
+#include "sspt_proc.h"
+#include "sspt_page.h"
+#include "sspt_feature.h"
+#include "sspt_filter.h"
+#include "../pf/proc_filters.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <kprobe/swap_ktd.h>
+#include <us_manager/us_slot_manager.h>
+
+static LIST_HEAD(proc_probes_list);
+static DEFINE_RWLOCK(sspt_proc_rwlock);
+
+
+struct list_head *sspt_proc_list()
+{
+       return &proc_probes_list;
+}
+
+/**
+ * @brief Global read lock for sspt_proc
+ *
+ * @return Void
+ */
+void sspt_proc_read_lock(void)
+{
+       read_lock(&sspt_proc_rwlock);
+}
+
+/**
+ * @brief Global read unlock for sspt_proc
+ *
+ * @return Void
+ */
+void sspt_proc_read_unlock(void)
+{
+       read_unlock(&sspt_proc_rwlock);
+}
+
+/**
+ * @brief Global write lock for sspt_proc
+ *
+ * @return Void
+ */
+void sspt_proc_write_lock(void)
+{
+       write_lock(&sspt_proc_rwlock);
+}
+
+/**
+ * @brief Global write unlock for sspt_proc
+ *
+ * @return Void
+ */
+void sspt_proc_write_unlock(void)
+{
+       write_unlock(&sspt_proc_rwlock);
+}
+
+struct ktd_proc {
+       struct sspt_proc *proc;
+       spinlock_t lock;
+};
+
+static void ktd_init(struct task_struct *task, void *data)
+{
+       struct ktd_proc *kproc = (struct ktd_proc *)data;
+
+       kproc->proc = NULL;
+       spin_lock_init(&kproc->lock);
+}
+
+static void ktd_exit(struct task_struct *task, void *data)
+{
+       struct ktd_proc *kproc = (struct ktd_proc *)data;
+
+       WARN_ON(kproc->proc);
+}
+
+static struct ktask_data ktd = {
+       .init = ktd_init,
+       .exit = ktd_exit,
+       .size = sizeof(struct ktd_proc),
+};
+
+static struct ktd_proc *kproc_by_task(struct task_struct *task)
+{
+       return (struct ktd_proc *)swap_ktd(&ktd, task);
+}
+
+int sspt_proc_init(void)
+{
+       return swap_ktd_reg(&ktd);
+}
+
+void sspt_proc_uninit(void)
+{
+       swap_ktd_unreg(&ktd);
+}
+
+void sspt_change_leader(struct task_struct *prev, struct task_struct *next)
+{
+       struct ktd_proc *prev_kproc;
+
+       prev_kproc = kproc_by_task(prev);
+       spin_lock(&prev_kproc->lock);
+       if (prev_kproc->proc) {
+               struct ktd_proc *next_kproc;
+
+               next_kproc = kproc_by_task(next);
+               get_task_struct(next);
+
+               /* Change the keeper sspt_proc */
+               BUG_ON(next_kproc->proc);
+
+               spin_lock(&next_kproc->lock);
+               next_kproc->proc = prev_kproc->proc;
+               prev_kproc->proc = NULL;
+               spin_unlock(&next_kproc->lock);
+
+               /* Set new the task leader to sspt_proc */
+               next_kproc->proc->leader = next;
+
+               put_task_struct(prev);
+       }
+       spin_unlock(&prev_kproc->lock);
+}
+
+static void sspt_reset_proc(struct task_struct *task)
+{
+       struct ktd_proc *kproc;
+
+       kproc = kproc_by_task(task->group_leader);
+       spin_lock(&kproc->lock);
+       kproc->proc = NULL;
+       spin_unlock(&kproc->lock);
+}
+
+
+
+
+
+static struct sspt_proc *sspt_proc_create(struct task_struct *leader)
+{
+       struct sspt_proc *proc = kzalloc(sizeof(*proc), GFP_KERNEL);
+
+       if (proc) {
+               proc->feature = sspt_create_feature();
+               if (proc->feature == NULL) {
+                       kfree(proc);
+                       return NULL;
+               }
+
+               INIT_LIST_HEAD(&proc->list);
+               INIT_LIST_HEAD(&proc->files.head);
+               init_rwsem(&proc->files.sem);
+               proc->tgid = leader->tgid;
+               proc->leader = leader;
+               /* FIXME: change the task leader */
+               proc->sm = create_sm_us(leader);
+               mutex_init(&proc->filters.mtx);
+               INIT_LIST_HEAD(&proc->filters.head);
+               atomic_set(&proc->usage, 1);
+
+               get_task_struct(proc->leader);
+
+               proc->suspect.after_exec = 1;
+               proc->suspect.after_fork = 0;
+       }
+
+       return proc;
+}
+
+static void sspt_proc_free(struct sspt_proc *proc)
+{
+       put_task_struct(proc->leader);
+       free_sm_us(proc->sm);
+       sspt_destroy_feature(proc->feature);
+       kfree(proc);
+}
+
+/**
+ * @brief Remove sspt_proc struct
+ *
+ * @param proc remove object
+ * @return Void
+ */
+
+/* called with sspt_proc_write_lock() */
+void sspt_proc_cleanup(struct sspt_proc *proc)
+{
+       struct sspt_file *file, *n;
+
+       sspt_proc_del_all_filters(proc);
+
+       down_write(&proc->files.sem);
+       list_for_each_entry_safe(file, n, &proc->files.head, list) {
+               list_del(&file->list);
+               sspt_file_free(file);
+       }
+       up_write(&proc->files.sem);
+
+       sspt_destroy_feature(proc->feature);
+
+       free_sm_us(proc->sm);
+       sspt_reset_proc(proc->leader);
+       sspt_proc_put(proc);
+}
+
+struct sspt_proc *sspt_proc_get(struct sspt_proc *proc)
+{
+       atomic_inc(&proc->usage);
+
+       return proc;
+}
+
+void sspt_proc_put(struct sspt_proc *proc)
+{
+       if (atomic_dec_and_test(&proc->usage)) {
+               if (proc->__mm) {
+                       mmput(proc->__mm);
+                       proc->__mm = NULL;
+               }
+               if (proc->__task) {
+                       put_task_struct(proc->__task);
+                       proc->__task = NULL;
+               }
+
+               WARN_ON(kproc_by_task(proc->leader)->proc);
+
+               put_task_struct(proc->leader);
+               kfree(proc);
+       }
+}
+EXPORT_SYMBOL_GPL(sspt_proc_put);
+
+struct sspt_proc *sspt_proc_by_task(struct task_struct *task)
+{
+       return kproc_by_task(task->group_leader)->proc;
+}
+EXPORT_SYMBOL_GPL(sspt_proc_by_task);
+
+struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task)
+{
+       struct ktd_proc *kproc = kproc_by_task(task->group_leader);
+       struct sspt_proc *proc;
+
+       spin_lock(&kproc->lock);
+       proc = kproc->proc;
+       if (proc)
+               sspt_proc_get(proc);
+       spin_unlock(&kproc->lock);
+
+       return proc;
+}
+EXPORT_SYMBOL_GPL(sspt_proc_get_by_task);
+
+/**
+ * @brief Call func() on each proc (no lock)
+ *
+ * @param func Callback
+ * @param data Data for callback
+ * @return Void
+ */
+void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *), void *data)
+{
+       struct sspt_proc *proc, *tmp;
+
+       list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) {
+               func(proc, data);
+       }
+}
+
+/**
+ * @brief Call func() on each proc
+ *
+ * @param func Callback
+ * @param data Data for callback
+ * @return Void
+ */
+void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data)
+{
+       sspt_proc_read_lock();
+       on_each_proc_no_lock(func, data);
+       sspt_proc_read_unlock();
+}
+EXPORT_SYMBOL_GPL(on_each_proc);
+
+/**
+ * @brief Get sspt_proc by task or create sspt_proc
+ *
+ * @param task Pointer on the task_struct struct
+ * @param priv Private data
+ * @return Pointer on the sspt_proc struct
+ */
+struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task)
+{
+       static DEFINE_MUTEX(local_mutex);
+       struct ktd_proc *kproc;
+       struct sspt_proc *proc;
+       struct task_struct *leader = task->group_leader;
+
+       kproc = kproc_by_task(leader);
+       if (kproc->proc)
+               goto out;
+
+       proc = sspt_proc_create(leader);
+
+       spin_lock(&kproc->lock);
+       if (kproc->proc == NULL) {
+               sspt_proc_get(proc);
+               kproc->proc = proc;
+               proc = NULL;
+
+               sspt_proc_write_lock();
+               list_add(&kproc->proc->list, &proc_probes_list);
+               sspt_proc_write_unlock();
+       }
+       spin_unlock(&kproc->lock);
+
+       if (proc)
+               sspt_proc_free(proc);
+
+out:
+       return kproc->proc;
+}
+
+/**
+ * @brief Check sspt_proc on empty
+ *
+ * @return Pointer on the sspt_proc struct
+ */
+void sspt_proc_check_empty(void)
+{
+       WARN_ON(!list_empty(&proc_probes_list));
+}
+
+static void sspt_proc_add_file(struct sspt_proc *proc, struct sspt_file *file)
+{
+       down_write(&proc->files.sem);
+       list_add(&file->list, &proc->files.head);
+       file->proc = proc;
+       up_write(&proc->files.sem);
+}
+
+/**
+ * @brief Get sspt_file from sspt_proc by dentry or new
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @param dentry Dentry of file
+ * @return Pointer on the sspt_file struct
+ */
+struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
+                                            struct dentry *dentry)
+{
+       struct sspt_file *file;
+
+       file = sspt_proc_find_file(proc, dentry);
+       if (file == NULL) {
+               file = sspt_file_create(dentry, 10);
+               if (file)
+                       sspt_proc_add_file(proc, file);
+       }
+
+       return file;
+}
+
+/**
+ * @brief Get sspt_file from sspt_proc by dentry
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @param dentry Dentry of file
+ * @return Pointer on the sspt_file struct
+ */
+struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
+                                     struct dentry *dentry)
+{
+       struct sspt_file *file;
+
+       down_read(&proc->files.sem);
+       list_for_each_entry(file, &proc->files.head, list) {
+               if (dentry == file->dentry)
+                       goto unlock;
+       }
+       file = NULL;
+
+unlock:
+       up_read(&proc->files.sem);
+
+       return file;
+}
+
+/**
+ * @brief Install probes on the page to monitored process
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @param page_addr Page address
+ * @return Void
+ */
+void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr)
+{
+       struct mm_struct *mm = proc->leader->mm;
+       struct vm_area_struct *vma;
+
+       vma = find_vma_intersection(mm, page_addr, page_addr + 1);
+       if (vma && check_vma(vma)) {
+               struct dentry *dentry = vma->vm_file->f_path.dentry;
+               struct sspt_file *file = sspt_proc_find_file(proc, dentry);
+               if (file) {
+                       sspt_file_set_mapping(file, vma);
+                       sspt_file_install(file);
+               }
+       }
+}
+
+/**
+ * @brief Install probes to monitored process
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @return Void
+ */
+void sspt_proc_install(struct sspt_proc *proc)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = proc->leader->mm;
+
+       proc->first_install = 1;
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (check_vma(vma)) {
+                       struct dentry *dentry = vma->vm_file->f_path.dentry;
+                       struct sspt_file *file =
+                               sspt_proc_find_file(proc, dentry);
+                       if (file) {
+                               sspt_file_set_mapping(file, vma);
+                               sspt_file_install(file);
+                       }
+               }
+       }
+}
+
+/**
+ * @brief Uninstall probes to monitored process
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @param task Pointer on the task_struct struct
+ * @param flag Action for probes
+ * @return Error code
+ */
+int sspt_proc_uninstall(struct sspt_proc *proc,
+                       struct task_struct *task,
+                       enum US_FLAGS flag)
+{
+       int err = 0;
+       struct sspt_file *file;
+
+       down_read(&proc->files.sem);
+       list_for_each_entry(file, &proc->files.head, list) {
+               err = sspt_file_uninstall(file, task, flag);
+               if (err != 0) {
+                       printk(KERN_INFO "ERROR sspt_proc_uninstall: err=%d\n",
+                              err);
+                       break;
+               }
+       }
+       up_read(&proc->files.sem);
+
+       return err;
+}
+
+static int intersection(unsigned long start_a, unsigned long end_a,
+                       unsigned long start_b, unsigned long end_b)
+{
+       return start_a < start_b ?
+                       end_a > start_b :
+                       start_a < end_b;
+}
+
+/**
+ * @brief Get sspt_file list by region (remove sspt_file from sspt_proc list)
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @param head[out] Pointer on the head list
+ * @param start Region start
+ * @param len Region length
+ * @return Error code
+ */
+int sspt_proc_get_files_by_region(struct sspt_proc *proc,
+                                 struct list_head *head,
+                                 unsigned long start, unsigned long end)
+{
+       int ret = 0;
+       struct sspt_file *file, *n;
+
+       down_write(&proc->files.sem);
+       list_for_each_entry_safe(file, n, &proc->files.head, list) {
+               if (intersection(file->vm_start, file->vm_end, start, end)) {
+                       ret = 1;
+                       list_move(&file->list, head);
+               }
+       }
+       up_write(&proc->files.sem);
+
+       return ret;
+}
+
+/**
+ * @brief Insert sspt_file to sspt_proc list
+ *
+ * @param proc Pointer on the sspt_proc struct
+ * @param head Pointer on the head list
+ * @return Void
+ */
+void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head)
+{
+       down_write(&proc->files.sem);
+       list_splice(head, &proc->files.head);
+       up_write(&proc->files.sem);
+}
+
+/**
+ * @brief Add sspt_filter to sspt_proc list
+ *
+ * @param proc Pointer to sspt_proc struct
+ * @param pfg Pointer to pf_group struct
+ * @return Void
+ */
+void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg)
+{
+       struct sspt_filter *f;
+
+       f = sspt_filter_create(proc, pfg);
+       if (f)
+               list_add(&f->list, &proc->filters.head);
+}
+
+/**
+ * @brief Remove sspt_filter from sspt_proc list
+ *
+ * @param proc Pointer to sspt_proc struct
+ * @param pfg Pointer to pf_group struct
+ * @return Void
+ */
+void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg)
+{
+       struct sspt_filter *fl, *tmp;
+
+       mutex_lock(&proc->filters.mtx);
+       list_for_each_entry_safe(fl, tmp, &proc->filters.head, list) {
+               if (fl->pfg == pfg) {
+                       list_del(&fl->list);
+                       sspt_filter_free(fl);
+               }
+       }
+       mutex_unlock(&proc->filters.mtx);
+}
+
+/**
+ * @brief Remove all sspt_filters from sspt_proc list
+ *
+ * @param proc Pointer to sspt_proc struct
+ * @return Void
+ */
+void sspt_proc_del_all_filters(struct sspt_proc *proc)
+{
+       struct sspt_filter *fl, *tmp;
+
+       mutex_lock(&proc->filters.mtx);
+       list_for_each_entry_safe(fl, tmp, &proc->filters.head, list) {
+               list_del(&fl->list);
+               sspt_filter_free(fl);
+       }
+       mutex_unlock(&proc->filters.mtx);
+}
+
+/**
+ * @brief Check if sspt_filter is already in sspt_proc list
+ *
+ * @param proc Pointer to sspt_proc struct
+ * @param pfg Pointer to pf_group struct
+ * @return Boolean
+ */
+bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg)
+{
+       struct sspt_filter *fl;
+
+       list_for_each_entry(fl, &proc->filters.head, list)
+               if (fl->pfg == pfg)
+                       return false;
+
+       return true;
+}
+
+void sspt_proc_on_each_filter(struct sspt_proc *proc,
+                             void (*func)(struct sspt_filter *, void *),
+                             void *data)
+{
+       struct sspt_filter *fl;
+
+       list_for_each_entry(fl, &proc->filters.head, list)
+               func(fl, data);
+}
+
+void sspt_proc_on_each_ip(struct sspt_proc *proc,
+                         void (*func)(struct sspt_ip *, void *), void *data)
+{
+       struct sspt_file *file;
+
+       down_read(&proc->files.sem);
+       list_for_each_entry(file, &proc->files.head, list)
+               sspt_file_on_each_ip(file, func, data);
+       up_read(&proc->files.sem);
+}
+
+static void is_send_event(struct sspt_filter *f, void *data)
+{
+       bool *is_send = (bool *)data;
+
+       if (!*is_send && f->pfg_is_inst)
+               *is_send = !!pfg_msg_cb_get(f->pfg);
+}
+
+bool sspt_proc_is_send_event(struct sspt_proc *proc)
+{
+       bool is_send = false;
+
+       /* FIXME: add read lock (deadlock in sampler) */
+       sspt_proc_on_each_filter(proc, is_send_event, (void *)&is_send);
+
+       return is_send;
+}
+
+
+static struct sspt_proc_cb *proc_cb;
+
+int sspt_proc_cb_set(struct sspt_proc_cb *cb)
+{
+       if (cb && proc_cb)
+               return -EBUSY;
+
+       proc_cb = cb;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sspt_proc_cb_set);
+
+void sspt_proc_priv_create(struct sspt_proc *proc)
+{
+       if (proc_cb && proc_cb->priv_create)
+               proc->private_data = proc_cb->priv_create(proc);
+}
+
+void sspt_proc_priv_destroy(struct sspt_proc *proc)
+{
+       if (proc->first_install && proc_cb && proc_cb->priv_destroy)
+               proc_cb->priv_destroy(proc, proc->private_data);
+}
diff --git a/modules/us_manager/sspt/sspt_proc.h b/modules/us_manager/sspt/sspt_proc.h
new file mode 100644 (file)
index 0000000..aaaa469
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef __SSPT_PROC__
+#define __SSPT_PROC__
+
+/**
+ * @file us_manager/sspt/sspt_proc.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include "sspt_file.h"
+
+struct slot_manager;
+struct task_struct;
+struct pf_group;
+struct sspt_filter;
+struct sspt_ip;
+
+/** Flags for sspt_*_uninstall() */
+enum US_FLAGS {
+       US_UNREGS_PROBE,        /**< probes remove and disarm */
+       US_DISARM,              /**< probes disarm */
+       US_UNINSTALL            /**< probes remove from list install */
+};
+
+/**
+ * @struct sspt_proc
+ * @breaf Image of process for specified process
+ */
+struct sspt_proc {
+       struct list_head list;          /**< For global process list */
+
+       /* sspt_file */
+       struct {
+               struct rw_semaphore sem;/**< Semaphore for files list */
+               struct list_head head;  /**< For sspt_file */
+       } files;
+
+       pid_t tgid;                     /**< Thread group ID */
+       struct task_struct *leader;     /**< Ptr to the task leader */
+       struct mm_struct *__mm;
+       struct task_struct *__task;
+       struct slot_manager *sm;        /**< Ptr to the manager slot */
+
+       struct {
+               unsigned after_exec:1;
+               unsigned after_fork:1;
+       } suspect;
+
+       struct {
+               struct mutex mtx;       /**< Mutex for filter list */
+               struct list_head head;  /**< Filter head */
+       } filters;
+
+       unsigned first_install:1;       /**< Install flag */
+       struct sspt_feature *feature;   /**< Ptr to the feature */
+       atomic_t usage;
+
+       /* FIXME: for preload (remove those fields) */
+       unsigned long r_state_addr;     /**< address of r_state */
+       void *private_data;             /**< Process private data */
+};
+
+struct sspt_proc_cb {
+       void *(*priv_create)(struct sspt_proc *);
+       void (*priv_destroy)(struct sspt_proc *, void *);
+};
+
+
+struct list_head *sspt_proc_list(void);
+
+struct sspt_proc *sspt_proc_by_task(struct task_struct *task);
+struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task);
+struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task);
+struct sspt_proc *sspt_proc_get(struct sspt_proc *proc);
+void sspt_proc_put(struct sspt_proc *proc);
+void sspt_proc_cleanup(struct sspt_proc *proc);
+
+void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *),
+                         void *data);
+void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data);
+
+void sspt_proc_check_empty(void);
+
+struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
+                                     struct dentry *dentry);
+struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
+                                            struct dentry *dentry);
+void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr);
+void sspt_proc_install(struct sspt_proc *proc);
+int sspt_proc_uninstall(struct sspt_proc *proc,
+                       struct task_struct *task,
+                       enum US_FLAGS flag);
+
+int sspt_proc_get_files_by_region(struct sspt_proc *proc,
+                                 struct list_head *head,
+                                 unsigned long start, unsigned long end);
+void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head);
+
+void sspt_proc_read_lock(void);
+void sspt_proc_read_unlock(void);
+void sspt_proc_write_lock(void);
+void sspt_proc_write_unlock(void);
+
+void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg);
+void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg);
+void sspt_proc_del_all_filters(struct sspt_proc *proc);
+bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg);
+
+void sspt_proc_on_each_filter(struct sspt_proc *proc,
+                             void (*func)(struct sspt_filter *, void *),
+                             void *data);
+
+void sspt_proc_on_each_ip(struct sspt_proc *proc,
+                         void (*func)(struct sspt_ip *, void *), void *data);
+
+bool sspt_proc_is_send_event(struct sspt_proc *proc);
+
+int sspt_proc_cb_set(struct sspt_proc_cb *cb);
+void sspt_proc_priv_create(struct sspt_proc *proc);
+void sspt_proc_priv_destroy(struct sspt_proc *proc);
+
+void sspt_change_leader(struct task_struct *prev, struct task_struct *next);
+int sspt_proc_init(void);
+void sspt_proc_uninit(void);
+
+
+#endif /* __SSPT_PROC__ */
diff --git a/modules/us_manager/us_common_file.h b/modules/us_manager/us_common_file.h
new file mode 100644 (file)
index 0000000..f18b6ce
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/us_manager_common_file.h
+ *
+ * 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, 2017
+ *
+ * 2017         Alexander Aksenov: SWAP us_manager implement
+ *
+ */
+
+#ifndef __US_MANAGER_COMMON_FILE_H__
+#define __US_MANAGER_COMMON_FILE_H__
+
+#include <linux/dcache.h>
+#include <linux/namei.h>
+
+static inline struct dentry *swap_get_dentry(const char *filepath)
+{
+       struct path path;
+       struct dentry *dentry = NULL;
+
+       if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) {
+               dentry = dget(path.dentry);
+               path_put(&path);
+       }
+
+       return dentry;
+}
+
+static inline void swap_put_dentry(struct dentry *dentry)
+{
+       dput(dentry);
+}
+
+#endif /* __US_MANAGER_COMMON_FILE_H__ */
diff --git a/modules/us_manager/us_manager.c b/modules/us_manager/us_manager.c
new file mode 100644 (file)
index 0000000..e6101b9
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/us_manager.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/stop_machine.h>
+#include "pf/pf_group.h"
+#include "sspt/sspt_proc.h"
+#include "probes/probe_info_new.h"
+#include "helper.h"
+#include "us_manager.h"
+#include "debugfs_us_manager.h"
+#include "callbacks.h"
+#include <writer/event_filter.h>
+#include <master/swap_initializer.h>
+
+
+static DEFINE_MUTEX(mutex_inst);
+static enum status_type status = ST_OFF;
+
+
+static int __do_usm_stop(void *data)
+{
+       get_all_procs();
+
+       return 0;
+}
+
+static void do_usm_stop(void)
+{
+       int ret;
+
+       exec_cbs(STOP_CB);
+       helper_unreg_top();
+
+       ret = stop_machine(__do_usm_stop, NULL, NULL);
+       if (ret)
+               printk("do_usm_stop failed: %d\n", ret);
+
+       uninstall_all();
+       helper_unreg_bottom();
+       sspt_proc_check_empty();
+}
+
+static int do_usm_start(void)
+{
+       int ret;
+
+       ret = helper_reg();
+       if (ret)
+               return ret;
+
+       install_all();
+
+       exec_cbs(START_CB);
+
+       return 0;
+}
+
+/**
+ * @brief Get instrumentation status
+ *
+ * @return Instrumentation status
+ */
+enum status_type usm_get_status(void)
+{
+       mutex_lock(&mutex_inst);
+       return status;
+}
+EXPORT_SYMBOL_GPL(usm_get_status);
+
+/**
+ * @brief Put instrumentation status
+ *
+ * @param st Instrumentation status
+ * @return Void
+ */
+void usm_put_status(enum status_type st)
+{
+       status = st;
+       mutex_unlock(&mutex_inst);
+}
+EXPORT_SYMBOL_GPL(usm_put_status);
+
+/**
+ * @brief Stop instrumentation
+ *
+ * @return Error code
+ */
+int usm_stop(void)
+{
+       int ret = 0;
+
+       if (usm_get_status() == ST_OFF) {
+               printk(KERN_INFO "US instrumentation is not running!\n");
+               ret = -EINVAL;
+               goto put;
+       }
+
+       do_usm_stop();
+
+put:
+       usm_put_status(ST_OFF);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usm_stop);
+
+/**
+ * @brief Start instrumentation
+ *
+ * @return Error code
+ */
+int usm_start(void)
+{
+       int ret = -EINVAL;
+       enum status_type st;
+
+       st = usm_get_status();
+       if (st == ST_ON) {
+               printk(KERN_INFO "US instrumentation is already run!\n");
+               goto put;
+       }
+
+       ret = do_usm_start();
+       if (ret == 0)
+               st = ST_ON;
+
+put:
+       usm_put_status(st);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usm_start);
+
+
+
+
+
+/* ============================================================================
+ * ===                                QUIET                                 ===
+ * ============================================================================
+ */
+static enum quiet_type quiet = QT_ON;
+
+/**
+ * @brief Set quiet mode
+ *
+ * @param q Quiet mode
+ * @return Void
+ */
+void set_quiet(enum quiet_type q)
+{
+       quiet = q;
+}
+EXPORT_SYMBOL_GPL(set_quiet);
+
+/**
+ * @brief Get quiet mode
+ *
+ * @return Quiet mode
+ */
+enum quiet_type get_quiet(void)
+{
+       return quiet;
+}
+EXPORT_SYMBOL_GPL(get_quiet);
+
+
+
+
+
+/* ============================================================================
+ * ===                              US_FILTER                               ===
+ * ============================================================================
+ */
+static int us_filter(struct task_struct *task)
+{
+       struct sspt_proc *proc;
+
+       /* FIXME: add read lock (deadlock in sampler) */
+       proc = sspt_proc_by_task(task);
+       if (proc)
+               return sspt_proc_is_send_event(proc);
+
+       return 0;
+}
+
+static struct ev_filter ev_us_filter = {
+       .name = "traced_process_only",
+       .filter = us_filter
+};
+
+static int init_us_filter(void)
+{
+       int ret;
+
+       ret = event_filter_register(&ev_us_filter);
+       if (ret)
+               return ret;
+
+       return event_filter_set(ev_us_filter.name);
+}
+
+static void exit_us_filter(void)
+{
+       event_filter_unregister(&ev_us_filter);
+}
+
+
+
+
+
+static int usm_once(void)
+{
+       int ret;
+
+       ret = helper_once();
+
+       return ret;
+}
+
+static int init_us_manager(void)
+{
+       int ret;
+
+       ret = helper_init();
+       if (ret)
+               return ret;
+
+       ret = sspt_proc_init();
+       if (ret)
+               goto uninit_helper;
+
+       ret = pin_init();
+       if (ret)
+               goto uninit_proc;
+
+       ret = init_us_filter();
+       if (ret)
+               goto uninit_pin;
+
+       return 0;
+
+uninit_pin:
+       pin_exit();
+uninit_proc:
+       sspt_proc_uninit();
+uninit_helper:
+       helper_uninit();
+
+       return ret;
+}
+
+static void exit_us_manager(void)
+{
+       if (status == ST_ON)
+               BUG_ON(usm_stop());
+
+       remove_all_cbs();
+
+       exit_us_filter();
+       pin_exit();
+       sspt_proc_uninit();
+       helper_uninit();
+
+       WARN_ON(!pfg_is_unloadable());
+}
+
+SWAP_LIGHT_INIT_MODULE(usm_once, init_us_manager, exit_us_manager,
+                      init_debugfs_us_manager, exit_debugfs_us_manager);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/us_manager/us_manager.h b/modules/us_manager/us_manager.h
new file mode 100644 (file)
index 0000000..f1bf081
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * @file us_manager/us_manager.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+#ifndef _US_MANAGER_H
+#define _US_MANAGER_H
+
+
+/** Quiet mode */
+enum quiet_type {
+       QT_ON,          /**< Quiet mode - on */
+       QT_OFF          /**< Quiet mode - off */
+};
+
+/** Instrumentation status */
+enum status_type {
+       ST_OFF,         /**< Instrumentation status - off */
+       ST_ON           /**< Instrumentation status - on */
+};
+
+void set_quiet(enum quiet_type q);
+enum quiet_type get_quiet(void);
+
+enum status_type usm_get_status(void);
+void usm_put_status(enum status_type st);
+
+int usm_start(void);
+int usm_stop(void);
+
+#endif /* _US_MANAGER_H */
diff --git a/modules/us_manager/us_manager_common.h b/modules/us_manager/us_manager_common.h
new file mode 100644 (file)
index 0000000..4400e31
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/us_slot_manager.c
+ *
+ * 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, 2013
+ *
+ * 2013         Alexander Aksenov: SWAP us_manager implement
+ *
+ */
+
+
+#include <linux/mm.h>
+#include <linux/version.h>
+
+/*
+ * TODO: move declaration and definition swap_do_mmap_pgoff()
+ *       from swap_kprobe.ko to swap_us_manager.ko
+ */
+#include <kprobe/swap_kprobes_deps.h>
+
+
+static inline unsigned long __swap_do_mmap(struct file *filp,
+                                          unsigned long addr,
+                                          unsigned long len,
+                                          unsigned long prot,
+                                          unsigned long flag,
+                                          unsigned long offset)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 3, 0)
+       unsigned long populate;
+
+       return swap_do_mmap(filp, addr, len, prot,
+                                 flag, 0, offset, &populate);
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+       unsigned long populate;
+
+       return swap_do_mmap_pgoff(filp, addr, len, prot,
+                                 flag, offset, &populate);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+       return swap_do_mmap_pgoff(filp, addr, len, prot, flag, offset);
+#else
+       return do_mmap(filp, addr, len, prot, flag, offset);
+#endif
+}
diff --git a/modules/us_manager/us_slot_manager.c b/modules/us_manager/us_slot_manager.c
new file mode 100644 (file)
index 0000000..56e8f28
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/us_slot_manager.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/list.h>
+
+#include <kprobe/swap_slots.h>
+#include <swap-asm/swap_kprobes.h>
+#include <swap-asm/swap_uprobes.h>
+#include "us_manager_common.h"
+
+
+static void *sm_alloc_us(struct slot_manager *sm)
+{
+       unsigned long addr;
+
+       addr = __swap_do_mmap(NULL, 0, PAGE_SIZE,
+                             PROT_EXEC | PROT_READ | PROT_WRITE,
+                             MAP_ANONYMOUS | MAP_PRIVATE, 0);
+       return (void *)addr;
+}
+
+static void sm_free_us(struct slot_manager *sm, void *ptr)
+{
+       /*
+        * E. G.: This code provides kernel dump because of rescheduling while
+        * atomic. As workaround, this code was commented. In this case we will
+        * have memory leaks for instrumented process, but instrumentation
+        * process should functionate correctly. Planned that good solution for
+        * this problem will be done during redesigning KProbe for improving
+        * supportability and performance.
+        */
+#if 0
+       struct task_struct *task = sm->data;
+
+       mm = get_task_mm(task);
+       if (mm) {
+               down_write(&mm->mmap_sem);
+               do_munmap(mm, (unsigned long)(ptr), PAGE_SIZE);
+               up_write(&mm->mmap_sem);
+               mmput(mm);
+       }
+#endif
+       /* FIXME: implement the removal of memory for task */
+}
+
+/**
+ * @brief Create slot_manager struct for US
+ *
+ * @param task Pointer to the task_struct struct
+ * @return Pointer to the created slot_manager struct
+ */
+struct slot_manager *create_sm_us(struct task_struct *task)
+{
+       struct slot_manager *sm = kmalloc(sizeof(*sm), GFP_ATOMIC);
+
+       if (sm == NULL)
+               return NULL;
+
+       sm->slot_size = UPROBES_TRAMP_LEN;
+       sm->alloc = sm_alloc_us;
+       sm->free = sm_free_us;
+       INIT_HLIST_HEAD(&sm->page_list);
+       sm->data = task;
+
+       return sm;
+}
+
+/**
+ * @brief Remove slot_manager struct for US
+ *
+ * @param sm remove object
+ * @return Void
+ */
+void free_sm_us(struct slot_manager *sm)
+{
+       if (sm == NULL)
+               return;
+
+       if (!hlist_empty(&sm->page_list)) {
+               printk(KERN_WARNING "SWAP US_MANAGER: Error! Slot manager is "
+                                   "not empty!\n");
+               return;
+       }
+
+       kfree(sm);
+}
diff --git a/modules/us_manager/us_slot_manager.h b/modules/us_manager/us_slot_manager.h
new file mode 100644 (file)
index 0000000..144d4a4
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * @file us_manager/us_slot_manager.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ */
+
+
+#ifndef _US_SLOT_MANAGER_H
+#define _US_SLOT_MANAGER_H
+
+struct task_struct;
+struct slot_manager;
+
+struct slot_manager *create_sm_us(struct task_struct *task);
+void free_sm_us(struct slot_manager *sm);
+
+#endif /* _US_SLOT_MANAGER_H */
diff --git a/modules/us_manager/usm_hook.c b/modules/us_manager/usm_hook.c
new file mode 100644 (file)
index 0000000..c41fd94
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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, 2017
+ *
+ * 2017         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/rwsem.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <kprobe/swap_kprobes_deps.h> // for swap_hlist_for_each_entry
+#include "usm_hook.h"
+
+
+static HLIST_HEAD(hook_head);
+static DECLARE_RWSEM(hook_sem);
+
+
+int usm_hook_reg(struct usm_hook *hook)
+{
+       if (!try_module_get(hook->owner))
+               return -ENODEV;
+
+       INIT_HLIST_NODE(&hook->node);
+
+       down_write(&hook_sem);
+       hlist_add_head(&hook->node, &hook_head);
+       up_write(&hook_sem);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usm_hook_reg);
+
+void usm_hook_unreg(struct usm_hook *hook)
+{
+       down_write(&hook_sem);
+       hlist_del(&hook->node);
+       up_write(&hook_sem);
+
+       module_put(hook->owner);
+}
+EXPORT_SYMBOL_GPL(usm_hook_unreg);
+
+void usm_hook_mmap(struct sspt_proc *proc, struct vm_area_struct *vma)
+{
+       struct usm_hook *hook;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+
+       down_read(&hook_sem);
+       swap_hlist_for_each_entry(hook, node, &hook_head, node) {
+               if (hook->mmap)
+                       hook->mmap(proc, vma);
+       }
+       up_read(&hook_sem);
+}
diff --git a/modules/us_manager/usm_hook.h b/modules/us_manager/usm_hook.h
new file mode 100644 (file)
index 0000000..132b337
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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, 2017
+ *
+ * 2017         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_USM_HOOK_H
+#define _SWAP_USM_HOOK_H
+
+
+#include <linux/list.h>
+
+
+struct module;
+struct sspt_proc;
+struct vm_area_struct;
+
+
+struct usm_hook {
+       struct hlist_node node;
+       struct module *owner;
+
+       /*
+        * mmap hook called only for vma which we can instrument
+        * (e.g. vma->vm_file is already validate)
+        */
+       void (*mmap)(struct sspt_proc *proc, struct vm_area_struct *vma);
+};
+
+
+int usm_hook_reg(struct usm_hook *hook);
+void usm_hook_unreg(struct usm_hook *hook);
+
+
+/* private interface */
+void usm_hook_mmap(struct sspt_proc *proc, struct vm_area_struct *vma);
+
+
+#endif /* _SWAP_USM_HOOK_H */
+
diff --git a/modules/writer/Kbuild b/modules/writer/Kbuild
new file mode 100644 (file)
index 0000000..1c938cf
--- /dev/null
@@ -0,0 +1,10 @@
+EXTRA_CFLAGS := $(extra_cflags)
+KBUILD_EXTRA_SYMBOLS = $(src)/../buffer/Module.symvers \
+                       $(src)/../driver/Module.symvers
+
+obj-m := swap_writer.o
+swap_writer-y := swap_writer_module.o \
+                 debugfs_writer.o \
+                 event_filter.o \
+                 swap_msg.o
+
diff --git a/modules/writer/debugfs_writer.c b/modules/writer/debugfs_writer.c
new file mode 100644 (file)
index 0000000..a79e9b6
--- /dev/null
@@ -0,0 +1,299 @@
+/**
+ * writer/debugfs_writer.c
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ * Writer debugfs implementation.
+ */
+
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <master/swap_debugfs.h>
+#include <master/swap_initializer.h>
+#include "swap_msg.h"
+#include "event_filter.h"
+
+
+/* ============================================================================
+ * ===                               BUFFER                                 ===
+ * ============================================================================
+ */
+static char *common_buf;
+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();
+}
+
+
+
+
+
+/* ============================================================================
+ * ===                             FOPS_RAW                                 ===
+ * ============================================================================
+ */
+static ssize_t write_raw(struct file *file, const char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       int ret;
+       void *buf;
+
+       if (count > subbuf_size)
+               return -EINVAL;
+
+       buf = get_current_buf();
+       if (copy_from_user(buf, user_buf, count)) {
+               ret = -EFAULT;
+               goto put_buf;
+       }
+
+       ret = swap_msg_raw(buf, count);
+
+put_buf:
+       put_current_buf();
+       return ret;
+}
+
+static const struct file_operations fops_raw = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .write =        write_raw,
+       .llseek =       default_llseek
+};
+
+
+
+
+
+/* ============================================================================
+ * ===                        FOPS_AVAILABLE_FILTERS                        ===
+ * ============================================================================
+ */
+struct read_buf {
+       char *begin;
+       char *ptr;
+       char *end;
+};
+
+static void func_for_read(struct ev_filter *f, void *data)
+{
+       struct read_buf *rbuf = (struct read_buf *)data;
+       int len = strlen(f->name);
+
+       if (rbuf->end - rbuf->ptr < len + 2)
+               return;
+
+       if (rbuf->ptr != rbuf->begin) {
+               *rbuf->ptr = ' ';
+               ++rbuf->ptr;
+       }
+
+       memcpy(rbuf->ptr, f->name, len);
+       rbuf->ptr += len;
+}
+
+static ssize_t read_af(struct file *file, char __user *user_buf,
+                      size_t count, loff_t *ppos)
+{
+       char buf[512];
+       struct read_buf rbuf = {
+               .begin = buf,
+               .ptr = buf,
+               .end = buf + sizeof(buf)
+       };
+
+       event_filter_on_each(func_for_read, (void *)&rbuf);
+
+       *rbuf.ptr = '\n';
+       ++rbuf.ptr;
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      rbuf.begin, rbuf.ptr - rbuf.begin);
+}
+
+static const struct file_operations fops_available_filters = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .read =         read_af,
+       .llseek =       default_llseek
+};
+
+
+
+
+
+/* ============================================================================
+ * ===                              FOPS_FILTER                             ===
+ * ============================================================================
+ */
+static ssize_t read_filter(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       const char *name = event_filter_get();
+       int len = strlen(name);
+       char *buf;
+       ssize_t ret;
+
+       buf = kmalloc(len + 2, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       memcpy(buf, name, len);
+       buf[len] = '\0';
+       buf[len + 1] = '\n';
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, len + 2);
+       kfree(buf);
+
+       return ret;
+}
+
+static ssize_t write_filter(struct file *file, const char __user *user_buf,
+                       size_t count, loff_t *ppos)
+{
+       enum { len = 32 };
+       char buf[len], name[len];
+       size_t buf_size;
+       ssize_t ret;
+
+       buf_size = min(count, (size_t)(len - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[len - 1] = '\0';
+       ret = sscanf(buf, "%31s", name);
+       if (ret != 1)
+               return -EINVAL;
+
+       ret = event_filter_set(name);
+       if (ret)
+               return -EINVAL;
+
+       return count;
+}
+
+static const struct file_operations fops_filter = {
+       .owner = THIS_MODULE,
+       .open = swap_init_simple_open,
+       .release = swap_init_simple_release,
+       .read =         read_filter,
+       .write =        write_filter,
+       .llseek =       default_llseek
+};
+
+
+
+
+
+/* ============================================================================
+ * ===                              INIT/EXIT                               ===
+ * ============================================================================
+ */
+static struct dentry *writer_dir;
+
+/**
+ * @brief Removes writer debugfs.
+ *
+ * @return Void.
+ */
+void exit_debugfs_writer(void)
+{
+       if (writer_dir)
+               debugfs_remove_recursive(writer_dir);
+
+       writer_dir = NULL;
+
+       exit_buffer();
+}
+
+/**
+ * @brief Initializes writer debugfs.
+ *
+ * @return 0 on success, error code on error.
+ */
+int init_debugfs_writer(void)
+{
+       int ret;
+       struct dentry *swap_dir, *dentry;
+
+       ret = init_buffer();
+       if (ret)
+               return ret;
+
+       swap_dir = swap_debugfs_getdir();
+       if (swap_dir == NULL)
+               return -ENOENT;
+
+       writer_dir = swap_debugfs_create_dir("writer", swap_dir);
+       if (writer_dir == NULL)
+               return -ENOMEM;
+
+       dentry = swap_debugfs_create_file("raw", 0600, writer_dir,
+                                         NULL, &fops_raw);
+       if (dentry == NULL)
+               goto fail;
+
+       dentry = swap_debugfs_create_file("available_filters", 0600, writer_dir,
+                                         NULL, &fops_available_filters);
+       if (dentry == NULL)
+               goto fail;
+
+       dentry = swap_debugfs_create_file("filter", 0600, writer_dir,
+                                         NULL, &fops_filter);
+       if (dentry == NULL)
+               goto fail;
+
+       return 0;
+
+fail:
+       exit_debugfs_writer();
+       return -ENOMEM;
+}
diff --git a/modules/writer/debugfs_writer.h b/modules/writer/debugfs_writer.h
new file mode 100644 (file)
index 0000000..d5e1fc3
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * @file writer/debugfs_writer.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ * Writer debugfs interface declaration.
+ */
+
+#ifndef _DEBUGFS_WRITER_H
+#define _DEBUGFS_WRITER_H
+
+int init_debugfs_writer(void);
+void exit_debugfs_writer(void);
+
+#endif /* _DEBUGFS_WRITER_H */
diff --git a/modules/writer/event_filter.c b/modules/writer/event_filter.c
new file mode 100644 (file)
index 0000000..2496110
--- /dev/null
@@ -0,0 +1,172 @@
+/**
+ * writer/event_filter.c
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ * Events filter.
+ */
+
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include "event_filter.h"
+
+
+static LIST_HEAD(filter_list);
+
+static int func_none(struct task_struct *task)
+{
+       return 1;
+}
+
+static struct ev_filter filter_none = {
+       .name = "all",
+       .filter = func_none
+};
+
+static struct ev_filter *filter_current = &filter_none;
+
+int check_event(struct task_struct *task)
+{
+       return filter_current->filter(task);
+}
+EXPORT_SYMBOL_GPL(check_event);
+
+static struct ev_filter *event_filter_find(const char *name)
+{
+       struct ev_filter *f, *tmp;
+
+       list_for_each_entry_safe(f, tmp, &filter_list, list) {
+               if (strcmp(f->name, name) == 0)
+                       return f;
+       }
+
+       return NULL;
+}
+
+/**
+ * @brief Registers event filter.
+ *
+ * @param f Pointer to the event filter.
+ * @return 0 on success, error code on error.
+ */
+int event_filter_register(struct ev_filter *f)
+{
+       if (event_filter_find(f->name))
+               return -EINVAL;
+
+       INIT_LIST_HEAD(&f->list);
+       list_add(&f->list, &filter_list);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(event_filter_register);
+
+/**
+ * @brief Unregisters event filter.
+ *
+ * @param f Pointer to the event filter.
+ * @return Void.
+ */
+void event_filter_unregister(struct ev_filter *f)
+{
+       struct ev_filter *filter, *tmp;
+
+       if (filter_current == f)
+               filter_current = &filter_none;
+
+       list_for_each_entry_safe(filter, tmp, &filter_list, list) {
+               if (filter == f) {
+                       list_del(&filter->list);
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(event_filter_unregister);
+
+/**
+ * @brief Sets event filter by its name.
+ *
+ * @param name Filter name.
+ * @return 0 on success, error code on error.
+ */
+int event_filter_set(const char *name)
+{
+       struct ev_filter *f;
+
+       f = event_filter_find(name);
+       if (f == NULL)
+               return -EINVAL;
+
+       filter_current = f;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(event_filter_set);
+
+/**
+ * @brief Gets filter name.
+ *
+ * @return Pointer to the filter name string.
+ */
+const char *event_filter_get(void)
+{
+       return filter_current->name;
+}
+
+/**
+ * @brief Runs specified callback for each filter in list.
+ *
+ * @param func Specified callback.
+ * @param data Pointer to the data passed to the callback.
+ * @return Void.
+ */
+void event_filter_on_each(void (*func)(struct ev_filter *, void *),
+                         void *data)
+{
+       struct ev_filter *f, *tmp;
+
+       list_for_each_entry_safe(f, tmp, &filter_list, list)
+               func(f, data);
+}
+
+/**
+ * @brief Initializes event filter.
+ *
+ * @return Initialization result.
+ */
+int event_filter_init(void)
+{
+       return event_filter_register(&filter_none);
+}
+
+/**
+ * @brief Uninitializes event filter.
+ *
+ * @return Void.
+ */
+void event_filter_exit(void)
+{
+       event_filter_unregister(&filter_none);
+}
diff --git a/modules/writer/event_filter.h b/modules/writer/event_filter.h
new file mode 100644 (file)
index 0000000..1b420eb
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * @file writer/event_filter.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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
+ *
+ * Event filter interface declaration.
+ */
+
+
+#ifndef _EVENT_FILTER_H
+#define _EVENT_FILTER_H
+
+
+#include <linux/list.h>
+
+struct task_struct;
+
+/**
+ * @struct ev_filter
+ * @bref Event filter structure.
+ */
+struct ev_filter {
+       struct list_head list;                  /**< Filter list head. */
+       char *name;                             /**< Filter name. */
+       int (*filter)(struct task_struct *);    /**< Filter function. */
+};
+
+
+int check_event(struct task_struct *task);
+
+int event_filter_register(struct ev_filter *f);
+void event_filter_unregister(struct ev_filter *f);
+int event_filter_set(const char *name);
+const char *event_filter_get(void);
+
+void event_filter_on_each(void (*func)(struct ev_filter *, void *),
+                         void *data);
+
+int event_filter_init(void);
+void event_filter_exit(void);
+
+#endif /* _EVENT_FILTER_H */
diff --git a/modules/writer/kernel_operations.h b/modules/writer/kernel_operations.h
new file mode 100644 (file)
index 0000000..b2bf043
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * @file writer/kernel_operations.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Writer kernel operations.
+ */
+
+/* Kernel functions wrap */
+
+#ifndef __KERNEL_OPERATIONS_H__
+#define __KERNEL_OPERATIONS_H__
+
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <asm/ptrace.h>
+
+
+/* ARCH-DEPENDED OPERATIONS */
+
+
+/* Regs manipulations */
+#if defined(CONFIG_ARM)
+
+#define get_regs_ret_func(regs)     (regs->ARM_lr)    /**< Get lr reg. */
+#define get_regs_ret_val(regs)      (regs->ARM_r0)    /**< Get ret val. */
+#define get_regs_stack_ptr(regs)    (regs->ARM_sp)    /**< Get stack pointer. */
+
+#elif defined(CONFIG_X86_32)
+
+#define get_regs_ret_val(regs)      (regs->ax)        /**< Get ret val. */
+#define get_regs_stack_ptr(regs)    (regs->sp)        /**< Get stack pointer. */
+
+static inline u32 get_regs_ret_func(struct pt_regs *regs)
+{
+       u32 *sp, addr = 0;
+
+       if (user_mode(regs)) {
+               sp = (u32 *)regs->sp;
+               if (get_user(addr, sp))
+                       pr_info("failed to dereference a pointer, sp=%p, "
+                               "pc=%lx\n", sp, regs->ip - 1);
+       } else {
+               sp = (u32 *)kernel_stack_pointer(regs);
+               addr = *sp;
+       }
+
+       return addr;
+}
+
+#elif defined(CONFIG_ARM64)
+
+static inline u64 get_regs_ret_func(struct pt_regs *regs)
+{
+       if (compat_user_mode(regs))
+               return regs->compat_lr;
+       else
+               return regs->regs[30];
+}
+
+#endif /* CONFIG_arch */
+
+#endif /* __KERNEL_OPERATIONS_H__ */
diff --git a/modules/writer/swap_msg.c b/modules/writer/swap_msg.c
new file mode 100644 (file)
index 0000000..cf20fd6
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * 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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <buffer/swap_buffer_module.h>
+#include <swap-asm/swap_kprobes.h>
+#include <swap-asm/swap_uprobes.h>
+#include "swap_msg.h"
+
+
+#define MSG_PREFIX     "[SWAP_MSG] "
+
+
+/* simple buffer */
+struct sb_struct {
+       size_t subbuf_size;
+
+       size_t count;
+       void *data;
+};
+
+static int sb_init(struct sb_struct *sb, size_t count, size_t subbuf_size)
+{
+       sb->data = vmalloc(count * subbuf_size);
+       if (!sb->data)
+               return -ENOMEM;
+
+       sb->count = count;
+       sb->subbuf_size = subbuf_size;
+
+       return 0;
+}
+
+static void sb_uninit(struct sb_struct *sb)
+{
+       vfree(sb->data);
+}
+
+static void *sb_data(struct sb_struct *sb, size_t idx)
+{
+       return sb->data + sb->subbuf_size * idx;
+}
+
+static size_t sb_idx(struct sb_struct *sb, void *data)
+{
+       return (data - sb->data) / sb->subbuf_size;
+}
+
+static bool sb_contains(struct sb_struct *sb, void *data)
+{
+       void *begin = sb->data;
+       void *end = sb->data + sb->count * sb->subbuf_size;
+
+       return data >= begin && data < end;
+}
+
+static size_t sb_count(struct sb_struct *sb)
+{
+       return sb->count;
+}
+
+
+/* pool buffer */
+struct pb_struct {
+       spinlock_t lock;
+       size_t free_first;
+       size_t free_count;
+
+       struct sb_struct buf;
+};
+
+static void *pb_data(struct pb_struct *pb, size_t idx)
+{
+       return sb_data(&pb->buf, idx);
+}
+
+static size_t pb_idx(struct pb_struct *pb, void *data)
+{
+       return sb_idx(&pb->buf, data);
+}
+
+static void pb_val_set(struct pb_struct *pb, size_t idx, size_t val)
+{
+       *(size_t *)pb_data(pb, idx) = val;
+}
+
+static size_t pb_val_get(struct pb_struct *pb, size_t idx)
+{
+       return *(size_t *)pb_data(pb, idx);
+}
+
+static int pb_init(struct pb_struct *pb, size_t count, size_t subbuf_size)
+{
+       int ret;
+       size_t idx;
+
+       ret = sb_init(&pb->buf, count, subbuf_size);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&pb->lock);
+       pb->free_first = 0;
+       pb->free_count = count;
+
+       for (idx = 0; idx < count; ++idx)
+               pb_val_set(pb, idx, idx + 1);
+
+       return 0;
+}
+
+static void pb_uninit(struct pb_struct *pb)
+{
+       WARN(sb_count(&pb->buf) != pb->free_count,
+            "count=%zu free_conut=%zu\n", sb_count(&pb->buf), pb->free_count);
+
+       sb_uninit(&pb->buf);
+}
+
+static void *pb_buf_get(struct pb_struct *pb)
+{
+       void *data;
+       unsigned long flags;
+
+       if (!pb->free_count)
+               return NULL;
+
+       spin_lock_irqsave(&pb->lock, flags);
+       data = pb_data(pb, pb->free_first);
+       pb->free_first = pb_val_get(pb, pb->free_first);
+       --pb->free_count;
+       spin_unlock_irqrestore(&pb->lock, flags);
+
+       return data;
+}
+
+static void pb_buf_put(struct pb_struct *pb, void *data)
+{
+       unsigned long flags;
+       size_t idx = pb_idx(pb, data);
+
+       spin_lock_irqsave(&pb->lock, flags);
+       pb_val_set(pb, idx, pb->free_first);
+       pb->free_first = idx;
+       ++pb->free_count;
+       spin_unlock_irqrestore(&pb->lock, flags);
+}
+
+
+struct swap_msg {
+       u32 msg_id;
+       u32 seq_num;
+       u64 time;
+       u32 len;
+       char payload[0];
+} __packed;
+
+
+static struct sb_struct cpu_buf;
+static struct pb_struct pool_buffer;
+static atomic_t seq_num = ATOMIC_INIT(-1);
+static atomic_t discarded = ATOMIC_INIT(0);
+
+
+int swap_msg_init(void)
+{
+       int ret;
+
+       ret = sb_init(&cpu_buf, NR_CPUS, SWAP_MSG_BUF_SIZE);
+       if (ret) {
+               pr_err(MSG_PREFIX "Cannot init cpu_buf, ret=%d\n", ret);
+               return ret;
+       }
+
+       ret = pb_init(&pool_buffer, NR_CPUS * 32, SWAP_MSG_BUF_SIZE);
+       if (ret) {
+               sb_uninit(&cpu_buf);
+               pr_err(MSG_PREFIX "Cannot init ring_buffer, ret=%d\n", ret);
+       }
+
+       return ret;
+}
+
+void swap_msg_exit(void)
+{
+       pb_uninit(&pool_buffer);
+       sb_uninit(&cpu_buf);
+}
+
+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 swap_msg *m;
+
+       m = pb_buf_get(&pool_buffer);
+       if (!m)
+               m = sb_data(&cpu_buf, get_cpu());
+
+       m->msg_id = (u32)id;
+       m->seq_num = atomic_inc_return(&seq_num);
+       m->time = swap_msg_current_time();
+
+       return m;
+}
+EXPORT_SYMBOL_GPL(swap_msg_get);
+
+static int __swap_msg_flush(struct swap_msg *m, size_t size, bool wakeup)
+{
+       if (unlikely(size >= SWAP_MSG_PAYLOAD_SIZE))
+               return -ENOMEM;
+
+       m->len = size;
+
+       if (swap_buffer_write(m, SWAP_MSG_PRIV_DATA + size, wakeup) !=
+           (SWAP_MSG_PRIV_DATA + size)) {
+               atomic_inc(&discarded);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int swap_msg_flush(struct swap_msg *m, size_t size)
+{
+       return __swap_msg_flush(m, size, true);
+}
+EXPORT_SYMBOL_GPL(swap_msg_flush);
+
+int swap_msg_flush_wakeupoff(struct swap_msg *m, size_t size)
+{
+       return __swap_msg_flush(m, size, false);
+}
+EXPORT_SYMBOL_GPL(swap_msg_flush_wakeupoff);
+
+void swap_msg_put(struct swap_msg *m)
+{
+       if (unlikely(sb_contains(&cpu_buf, m)))
+               put_cpu();
+       else
+               pb_buf_put(&pool_buffer, m);
+}
+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) */
+                       *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) */
+#ifdef CONFIG_ARM64
+                       if (len < 4)
+                               return -ENOMEM;
+
+                       tmp_u32 = (u32 *)buf;
+                       *tmp_u32 = swap_get_float(regs, i);
+                       buf += 4;
+                       len -= 4;
+                       break;
+#endif /* CONFIG_ARM64 */
+                       /* For others case f == d */
+               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;
+#ifdef CONFIG_ARM64
+                       *tmp_u64 = swap_get_double(regs, i);
+#else /* CONFIG_ARM64 */
+                       *tmp_u64 = get_arg(regs, i);
+                       ++i;
+                       *tmp_u64 |= (u64)get_arg(regs, i) << 32;
+#endif /* CONFIG_ARM64 */
+                       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) {
+               pr_err(MSG_PREFIX "ERROR: message RAW small size=%zu\n", size);
+               return -EINVAL;
+       }
+
+       if (m->len + sizeof(*m) != size) {
+               pr_err(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, true) != 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) {
+               pr_err(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/modules/writer/swap_msg.h b/modules/writer/swap_msg.h
new file mode 100644 (file)
index 0000000..5d86f95
--- /dev/null
@@ -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 <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_MSG_H
+#define _SWAP_MSG_H
+
+#include <linux/version.h>
+#include <linux/types.h>
+
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0)
+
+#include <linux/ktime.h>       /* Needed by timekeeping.h */
+#include <linux/timekeeping.h> /* Now getnstimeofday() is here */
+
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
+
+#include <linux/time.h>
+
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
+
+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_PROCESS_STATUS_INFO         = 0x000e,
+       MSG_CONTEXT_SWITCH_ENTRY        = 0x0010,
+       MSG_CONTEXT_SWITCH_EXIT         = 0x0011,
+       MSG_PROC_MAP                    = 0x0012,
+       MSG_PROC_UNMAP                  = 0x0013,
+       MSG_PROC_COMM                   = 0x0014,
+       MSG_WEB_PROFILING               = 0x0015,
+       MSG_NSP                         = 0x0019,
+       MSG_WSP                         = 0x001a,
+       MSG_FBI                         = 0x0020
+};
+
+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;
+}
+
+static inline u64 swap_msg_current_time(void)
+{
+       struct timespec ts;
+       getnstimeofday(&ts);
+       return swap_msg_spec2time(&ts);
+}
+
+struct swap_msg *swap_msg_get(enum swap_msg_id id);
+int swap_msg_flush(struct swap_msg *m, size_t size);
+int swap_msg_flush_wakeupoff(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/modules/writer/swap_writer_errors.h b/modules/writer/swap_writer_errors.h
new file mode 100644 (file)
index 0000000..def1f47
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * @file writer/swap_writer_errors.h
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ *
+ * @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
+ *
+ * Writer module error codes.
+ */
+
+#ifndef __SWAP_WRITER_ERRORS_H__
+#define __SWAP_WRITER_ERRORS_H__
+
+/**
+ * @enum _swap_writer_errors
+ * Error codes.
+ */
+enum _swap_writer_errors {
+       E_SW_SUCCESS = 0                /**< Success. */
+};
+
+#endif /* __SWAP_WRITER_ERRORS_H__ */
diff --git a/modules/writer/swap_writer_module.c b/modules/writer/swap_writer_module.c
new file mode 100644 (file)
index 0000000..f945a81
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * writer/swap_writer_module.c
+ * @author Alexander Aksenov <a.aksenov@samsung.com>
+ * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ * @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
+ *
+ * Packing and writing data.
+ */
+
+
+#include <linux/module.h>
+#include <master/swap_initializer.h>
+#include "swap_msg.h"
+#include "event_filter.h"
+#include "debugfs_writer.h"
+
+
+static int core_init(void)
+{
+       int ret;
+
+       ret = swap_msg_init();
+       if (ret)
+               return ret;
+
+       ret = event_filter_init();
+       if (ret)
+               swap_msg_exit();
+
+       return ret;
+}
+
+static void core_exit(void)
+{
+       event_filter_exit();
+       swap_msg_exit();
+}
+
+SWAP_LIGHT_INIT_MODULE(NULL, core_init, core_exit,
+                      init_debugfs_writer, exit_debugfs_writer);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP Writer module");
+MODULE_AUTHOR("Cherkashin V., Aksenov A.S.");
diff --git a/modules/wsp/Kbuild b/modules/wsp/Kbuild
new file mode 100644 (file)
index 0000000..580bb29
--- /dev/null
@@ -0,0 +1,8 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_wsp.o
+swap_wsp-y := wsp_module.o \
+              wsp_msg.o \
+              wsp_debugfs.o \
+              wsp.o \
+              wsp_res.o
diff --git a/modules/wsp/wsp.c b/modules/wsp/wsp.c
new file mode 100644 (file)
index 0000000..66b8cbe
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <linux/string.h>
+#include <us_manager/sspt/sspt.h>
+#include <us_manager/probes/probe_info_new.h>
+#include "wsp.h"
+#include "wsp_res.h"
+#include "wsp_msg.h"
+
+struct wsp_probe {
+       const char *name;
+       struct probe_new probe;
+};
+
+struct wsp_bin {
+       const char *name;
+       unsigned long cnt;
+       struct wsp_probe *probe_array;
+};
+
+static char *webapp_path;
+static char *chromium_path;
+
+#define WSP_PROBE_MAKE(_name_, _offset_,  _desc_)      \
+{                                                      \
+       .name = (_name_),                               \
+       .probe.offset = (_offset_),                     \
+       .probe.desc = (_desc_)                          \
+}
+
+/*
+ * res_request
+ */
+/* blink::ResourceLoader.m_request.m_url */
+#define URL_OFFSET             84
+/* base::String.m_impl.m_ptr */
+#define URL_LEN_OFFSET         4
+#define URL_DATA_OFFSET                12
+
+static char *path_get_from_object(unsigned long ptr)
+{
+       char *path;
+       unsigned long url, len, ret;
+
+       get_user(url, (unsigned long __user *)(ptr + URL_OFFSET));
+       get_user(len, (unsigned long __user *)(url + URL_LEN_OFFSET));
+       path = kzalloc(len + 1, GFP_KERNEL);
+       if (!path)
+               return NULL;
+
+       ret = copy_from_user(path,
+                            (const void __user *)(url + URL_DATA_OFFSET),
+                            len);
+       if (ret) {
+               kfree(path);
+               path = NULL;
+       } else {
+               path[len] = '\0';
+       }
+
+       return path;
+}
+
+static int res_request_handle(struct uprobe *p, struct pt_regs *regs)
+{
+       unsigned long ptr;
+       char *path;
+
+       ptr = (unsigned long)swap_get_uarg(regs, 0);
+       path = path_get_from_object(ptr);
+       if (path) {
+               int id = wsp_resource_data_add(ptr, path);
+               if (id >= 0)
+                       wsp_msg(WSP_RES_LOAD_BEGIN, id, path);
+       }
+
+       return 0;
+}
+
+static struct probe_desc res_request = MAKE_UPROBE(res_request_handle);
+
+/*
+ * res_finish
+ */
+static int res_finish_ehandle(struct uretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       int id;
+       unsigned long ptr = (unsigned long)swap_get_uarg(regs, 0);
+
+       id = wsp_resource_data_id(ptr);
+       if (id >= 0) {
+               *(unsigned long *)ri->data = ptr;
+               wsp_msg(WSP_RES_PROC_BEGIN, id, NULL);
+       }
+
+       return 0;
+}
+
+static int res_finish_rhandle(struct uretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       int id;
+       unsigned long ptr;
+
+       ptr = *(unsigned long *)ri->data;
+       id = wsp_resource_data_id(ptr);
+       if (id >= 0) {
+               wsp_msg(WSP_RES_PROC_END, id, NULL);
+               wsp_msg(WSP_RES_LOAD_END, id, NULL);
+               wsp_resource_data_del(ptr);
+       }
+
+       return 0;
+}
+
+static struct probe_desc res_finish =
+               MAKE_URPROBE(res_finish_ehandle, res_finish_rhandle,
+                            sizeof(unsigned long));
+
+/*
+ * redraw
+ */
+static int redraw_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       wsp_msg(WSP_DRAW_BEGIN, 0, NULL);
+
+       return 0;
+}
+
+static int redraw_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       wsp_msg(WSP_DRAW_END, 0, NULL);
+
+       return 0;
+}
+
+static struct probe_desc redraw = MAKE_URPROBE(redraw_eh, redraw_rh, 0);
+
+/* blink::ResourceLoader::start() */
+#define RES_REQ "_ZN5blink14ResourceLoader5startEv"
+/* blink::ResourceLoader::didFinishLoading(WebURLLoader*, double , int64_t) */
+#define RES_FINISH "_ZN5blink14ResourceLoader16didFinishLoadingEPNS_12WebURLLoaderEdx"
+
+/* content::RenderWidget::DidCommitAndDrawCompositorFrame */
+#define REDRAW "_ZN7content23CompositorOutputSurface11SwapBuffersEPN2cc15CompositorFrameE"
+
+static struct wsp_probe __probe_array[] = {
+       /* res */
+       WSP_PROBE_MAKE(RES_REQ, 0, &res_request),
+       WSP_PROBE_MAKE(RES_FINISH, 0, &res_finish),
+
+       /* redraw */
+       WSP_PROBE_MAKE(REDRAW, 0, &redraw),
+};
+
+static struct wsp_bin chromium_bin = {
+       .name = NULL,
+       .probe_array = __probe_array,
+       .cnt = ARRAY_SIZE(__probe_array)
+};
+
+/* check chromium_bin array on init address */
+static bool wsp_is_addr_init(void)
+{
+       int i;
+
+       for (i = 0; i < chromium_bin.cnt; ++i)
+               if (chromium_bin.probe_array[i].probe.offset == 0)
+                       return false;
+
+       return true;
+}
+
+static int wsp_bin_register(struct pf_group *pfg, struct wsp_bin *bin)
+{
+       int i, ret;
+       struct dentry *dentry;
+
+       dentry = dentry_by_path(bin->name);
+       if (!dentry) {
+               pr_err("dentry not found (path='%s'\n", bin->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < bin->cnt; ++i) {
+               struct wsp_probe *p = &bin->probe_array[i];
+
+               ret = pin_register(&p->probe, pfg, dentry);
+               if (ret) {
+                       pr_err("failed to register WSP probe (%lx:%d)\n",
+                              p->probe.offset, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void wsp_bin_unregister(struct pf_group *pfg, struct wsp_bin *bin)
+{
+       int i;
+       struct dentry *dentry;
+
+       dentry = dentry_by_path(bin->name);
+       if (!dentry) {
+               pr_err("dentry not found (path='%s'\n", bin->name);
+               return;
+       }
+
+       for (i = 0; i < bin->cnt; ++i) {
+               struct wsp_probe *p = &bin->probe_array[i];
+
+               pin_unregister(&p->probe, pfg);
+       }
+}
+
+static char *do_set_path(char *path, size_t len)
+{
+       char *p;
+
+       p = kmalloc(len, GFP_KERNEL);
+       if (!p)
+               return NULL;
+
+       strncpy(p, path, len);
+       return p;
+}
+
+static void do_free_path(char **dest)
+{
+       kfree(*dest);
+       *dest = NULL;
+}
+
+static struct pf_group *g_pfg;
+
+static int wsp_app_register(void)
+{
+       struct dentry *dentry;
+
+       if (!webapp_path || !chromium_path) {
+               pr_err("WSP: some required paths are not set!\n");
+               return -EINVAL;
+       }
+
+       chromium_bin.name = chromium_path;
+
+       dentry = dentry_by_path(webapp_path);
+       if (!dentry) {
+               pr_err("dentry not found (path='%s'\n", webapp_path);
+               return -EINVAL;
+       }
+
+       g_pfg = get_pf_group_by_dentry(dentry, (void *)dentry);
+       if (!g_pfg) {
+               pr_err("WSP: g_pfg is NULL (by dentry=%p)\n", dentry);
+               return -ENOMEM;
+       }
+
+       return wsp_bin_register(g_pfg, &chromium_bin);
+}
+
+static void wsp_app_unregister(void)
+{
+       if (!chromium_bin.name) {
+               pr_err("WSP: chromium path is not initialized\n");
+               return;
+       }
+
+       wsp_bin_unregister(g_pfg, &chromium_bin);
+       put_pf_group(g_pfg);
+}
+
+static int do_wsp_on(void)
+{
+       int ret;
+
+       ret = wsp_res_init();
+       if (ret)
+               return ret;
+
+       ret = wsp_app_register();
+       if (ret)
+               wsp_res_exit();
+
+       return ret;
+}
+
+static int do_wsp_off(void)
+{
+       wsp_app_unregister();
+       wsp_res_exit();
+
+       return 0;
+}
+
+static enum wsp_mode g_mode = WSP_OFF;
+static DEFINE_MUTEX(g_mode_mutex);
+
+int wsp_set_addr(const char *name, unsigned long offset)
+{
+       int i, ret = 0;
+
+       if (mutex_trylock(&g_mode_mutex) == 0)
+               return -EBUSY;
+
+       for (i = 0; i < chromium_bin.cnt; ++i) {
+               if (!strcmp(name, chromium_bin.probe_array[i].name)) {
+                       chromium_bin.probe_array[i].probe.offset = offset;
+                       goto unlock;
+               }
+       }
+
+       ret = -EINVAL;
+
+unlock:
+       mutex_unlock(&g_mode_mutex);
+       return ret;
+}
+
+int wsp_set_mode(enum wsp_mode mode)
+{
+       int ret = -EINVAL;
+
+       if (g_mode == mode)
+               return -EBUSY;
+
+       mutex_lock(&g_mode_mutex);
+       switch (mode) {
+       case WSP_ON:
+               ret = wsp_is_addr_init() ? do_wsp_on() : -EPERM;
+               break;
+       case WSP_OFF:
+               ret = do_wsp_off();
+               break;
+       }
+
+       if (!ret)
+               g_mode = mode;
+
+       mutex_unlock(&g_mode_mutex);
+       return ret;
+}
+
+enum wsp_mode wsp_get_mode(void)
+{
+       return g_mode;
+}
+
+void wsp_set_webapp_path(char *path, size_t len)
+{
+       do_free_path(&webapp_path);
+       webapp_path = do_set_path(path, len);
+}
+
+void wsp_set_chromium_path(char *path, size_t len)
+{
+       do_free_path(&chromium_path);
+       chromium_path = do_set_path(path, len);
+}
+
+int wsp_init(void)
+{
+       return 0;
+}
+
+void wsp_exit(void)
+{
+       wsp_set_mode(WSP_OFF);
+       do_free_path(&webapp_path);
+       do_free_path(&chromium_path);
+}
diff --git a/modules/wsp/wsp.h b/modules/wsp/wsp.h
new file mode 100644 (file)
index 0000000..8b45e1d
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _WSP_H
+#define _WSP_H
+
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+enum wsp_mode {
+       WSP_ON,
+       WSP_OFF
+};
+
+int wsp_set_addr(const char *name, unsigned long offset);
+
+int wsp_set_mode(enum wsp_mode mode);
+enum wsp_mode wsp_get_mode(void);
+
+void wsp_set_webapp_path(char *path, size_t len);
+void wsp_set_chromium_path(char *path, size_t len);
+
+int wsp_init(void);
+void wsp_exit(void);
+
+#endif /* _WSP_H */
diff --git a/modules/wsp/wsp_debugfs.c b/modules/wsp/wsp_debugfs.c
new file mode 100644 (file)
index 0000000..c117f75
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <master/swap_debugfs.h>
+#include "wsp.h"
+#include "wsp_debugfs.h"
+
+static int do_write_cmd(const char *buf, size_t count)
+{
+       int n, ret = 0;
+       char *name;
+       unsigned long offset;
+
+       name = kmalloc(count, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       n = sscanf(buf, "%lx %1024s", &offset, name);
+       if (n != 2) {
+               ret = -EINVAL;
+               goto free_name;
+       }
+
+       ret = wsp_set_addr(name, offset);
+
+free_name:
+       kfree(name);
+       return ret;
+}
+
+/* ============================================================================
+ * ===                          DEBUGFS FOR CMD                             ===
+ * ============================================================================
+ */
+static ssize_t write_cmd(struct file *file, const char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       enum { max_count = 1024 };
+       int ret;
+       char *buf;
+
+       if (count > max_count)
+               return -ENOMEM;
+
+       buf = kmalloc(count + 1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, user_buf, count)) {
+               ret = -EFAULT;
+               goto free_buf;
+       }
+
+       buf[count] = '\0';
+       ret = do_write_cmd(buf, count);
+
+free_buf:
+       kfree(buf);
+       return ret ? ret : count;
+}
+
+static const struct file_operations fops_cmd = {
+       .write =        write_cmd,
+       .llseek =       default_llseek,
+};
+
+/* ============================================================================
+ * ===                         DEBUGFS FOR ENABLE                           ===
+ * ============================================================================
+ */
+static ssize_t read_enabled(struct file *file, char __user *user_buf,
+                           size_t count, loff_t *ppos)
+{
+       char buf[2];
+
+       buf[0] = wsp_get_mode() == WSP_OFF ? '0' : '1';
+       buf[1] = '\n';
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       int ret = 0;
+       char buf[32];
+       size_t buf_size;
+
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       switch (buf[0]) {
+       case '1':
+               ret = wsp_set_mode(WSP_ON);
+               break;
+       case '0':
+               ret = wsp_set_mode(WSP_OFF);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static const struct file_operations fops_enabled = {
+       .read =         read_enabled,
+       .write =        write_enabled,
+       .llseek =       default_llseek,
+};
+
+/* ============================================================================
+ * ===                       DEBUGFS FOR WEBAPP_PATH                        ===
+ * ============================================================================
+ */
+static ssize_t write_webapp_path(struct file *file,
+                                const char __user *user_buf,
+                                size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (!path) {
+               ret = -ENOMEM;
+               goto write_webapp_path_failed;
+       }
+
+       if (copy_from_user(path, user_buf, len)) {
+               ret = -EINVAL;
+               goto write_webapp_path_failed;
+       }
+
+       path[len - 1] = '\0';
+       wsp_set_webapp_path(path, len);
+
+       ret = len;
+
+write_webapp_path_failed:
+       kfree(path);
+
+       return ret;
+}
+
+static const struct file_operations fops_webapp_path = {
+       .write = write_webapp_path
+};
+
+/* ============================================================================
+ * ===                      DEBUGFS FOR EWEBKIT_PATH                        ===
+ * ============================================================================
+ */
+static ssize_t write_ewebkit_path(struct file *file,
+                                 const char __user *user_buf,
+                                 size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (!path) {
+               ret = -ENOMEM;
+               goto write_ewebkit_path_failed;
+       }
+
+       if (copy_from_user(path, user_buf, len)) {
+               ret = -EINVAL;
+               goto write_ewebkit_path_failed;
+       }
+
+       path[len - 1] = '\0';
+
+       wsp_set_chromium_path(path, len);
+
+       ret = len;
+
+write_ewebkit_path_failed:
+       kfree(path);
+
+       return ret;
+}
+
+static const struct file_operations fops_ewebkit_path = {
+       .write = write_ewebkit_path
+};
+
+static struct dentry *wsp_dir;
+
+void wsp_debugfs_exit(void)
+{
+       debugfs_remove_recursive(wsp_dir);
+       wsp_dir = NULL;
+}
+
+int wsp_debugfs_init(void)
+{
+       struct dentry *dentry;
+
+       dentry = swap_debugfs_getdir();
+       if (!dentry)
+               return -ENOENT;
+
+       wsp_dir = swap_debugfs_create_dir("wsp", dentry);
+       if (!wsp_dir)
+               return -ENOMEM;
+
+       dentry = swap_debugfs_create_file("enabled", 0600, wsp_dir, NULL,
+                                         &fops_enabled);
+       if (!dentry)
+               goto fail;
+
+       dentry = swap_debugfs_create_file("cmd", 0600, wsp_dir, NULL,
+                                         &fops_cmd);
+       if (!dentry)
+               goto fail;
+
+       dentry = swap_debugfs_create_file("webapp_path", 0600, wsp_dir, NULL,
+                                         &fops_webapp_path);
+       if (!dentry)
+               goto fail;
+
+       dentry = swap_debugfs_create_file("ewebkit_path", 0600, wsp_dir, NULL,
+                                         &fops_ewebkit_path);
+       if (!dentry)
+               goto fail;
+
+       return 0;
+
+fail:
+       wsp_debugfs_exit();
+       return -ENOMEM;
+}
diff --git a/modules/wsp/wsp_debugfs.h b/modules/wsp/wsp_debugfs.h
new file mode 100644 (file)
index 0000000..db3ea17
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _WSP_DEBUGFS_H
+#define _WSP_DEBUGFS_H
+
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+int wsp_debugfs_init(void);
+void wsp_debugfs_exit(void);
+
+#endif /* _WSP_DEBUGFS_H */
diff --git a/modules/wsp/wsp_module.c b/modules/wsp/wsp_module.c
new file mode 100644 (file)
index 0000000..2c5d490
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <master/swap_initializer.h>
+#include "wsp.h"
+#include "wsp_debugfs.h"
+
+SWAP_LIGHT_INIT_MODULE(NULL, wsp_init, wsp_exit,
+                      wsp_debugfs_init, wsp_debugfs_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/modules/wsp/wsp_msg.c b/modules/wsp/wsp_msg.c
new file mode 100644 (file)
index 0000000..a0532cd
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * wsp/wsp_msg.c
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <writer/swap_msg.h>
+#include "wsp_msg.h"
+
+/*
+ * MSG_WSP (payload):
+ * +-------------+----------+----------+
+ * | name        | type     | length   |
+ * +-------------+----------+----------+
+ * | PID         | int      |      4   |
+ * | wsp_id      | int      |      4   |
+ * | wsp_payload | variable | variable |
+ * +-------------+----------+----------+
+
+ * wsp_id:
+ *   - WSP_RES_LOAD_BEGIN = 0x0001
+ *   - WSP_RES_LOAD_END   = 0x0002
+ *   - WSP_RES_PROC_BEGIN = 0x0003
+ *   - WSP_RES_PROC_END   = 0x0004
+ *   - WSP_DRAW_BEGIN     = 0x0005
+ *   - WSP_DRAW_END       = 0x0006
+ *
+ * wsp_payload:
+ *
+ * 1. WSP_RES_LOAD_BEGIN:
+ *         +--------+--------+----------+
+ *         | name   | type   |  length  |
+ *         +--------+--------+----------+
+ *         | res_id | int    |     4    |
+ *         | path   | string | variable |
+ *         +--------+--------+----------+
+ *
+ * 2. WSP_RES_LOAD_END, WSP_RES_PROC_BEGIN, WSP_RES_PROC_END:
+ *         +--------+--------+----------+
+ *         | name   | type   |  length  |
+ *         +--------+--------+----------+
+ *         | res_id | int    |     4    |
+ *         +--------+--------+----------+
+ *
+ * 3. WSP_DRAW_BEGIN, WSP_DRAW_END:
+ *         no wsp_payload
+ */
+
+static int pack_wsp_msg(void *data, size_t size, enum wsp_id id,
+                       u32 res_id, const char *path)
+{
+       size_t len;
+       const size_t old_size = size;
+
+       /* write PID */
+       *(u32 *)data = (u32)current->tgid;
+       data += 4;
+       size -= 4;
+
+       /* write wsp_id */
+       *(u32 *)data = (u32)id;
+       data += 4;
+       size -= 4;
+
+       /* pack wsp_payload */
+       switch (id) {
+       case WSP_RES_LOAD_BEGIN:
+               len = strlen(path) + 1;
+               if (size < len + 4)
+                       return -ENOMEM;
+
+               /* '+ 4' - skip space for res_id */
+               memcpy(data + 4, path, len);
+               size -= len;
+       case WSP_RES_LOAD_END:
+       case WSP_RES_PROC_BEGIN:
+       case WSP_RES_PROC_END:
+               /* write res_id */
+               *(u32 *)data = res_id;
+               size -= 4;
+               break;
+
+       case WSP_DRAW_BEGIN:
+       case WSP_DRAW_END:
+               break;
+
+       default:
+               pr_err("unknown wsp_id: id=%u\n", (unsigned int)id);
+               return -EINVAL;
+       }
+
+       return old_size - size;
+}
+
+void wsp_msg(enum wsp_id id, u32 res_id, const char *path)
+{
+       int ret;
+       void *data;
+       size_t size;
+       struct swap_msg *m;
+
+       m = swap_msg_get(MSG_WSP);
+       data = swap_msg_payload(m);
+       size = swap_msg_size(m);
+       ret = pack_wsp_msg(data, size, id, res_id, path);
+       if (ret < 0) {
+               pr_err("error MSG_WSP packing, ret=%d\n", ret);
+               goto put_msg;
+       }
+
+       swap_msg_flush(m, ret);
+
+put_msg:
+       swap_msg_put(m);
+}
diff --git a/modules/wsp/wsp_msg.h b/modules/wsp/wsp_msg.h
new file mode 100644 (file)
index 0000000..fc02009
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _WSP_MSG_H
+#define _WSP_MSG_H
+
+/*
+ * wsp/wsp_msg.h
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <linux/types.h>
+
+enum wsp_id {
+       WSP_RES_LOAD_BEGIN = 0x0001,
+       WSP_RES_LOAD_END   = 0x0002,
+       WSP_RES_PROC_BEGIN = 0x0003,
+       WSP_RES_PROC_END   = 0x0004,
+       WSP_DRAW_BEGIN     = 0x0005,
+       WSP_DRAW_END       = 0x0006
+};
+
+void wsp_msg(enum wsp_id id, u32 res_id, const char *path);
+
+#endif /* _WSP_MSG_H */
diff --git a/modules/wsp/wsp_res.c b/modules/wsp/wsp_res.c
new file mode 100644 (file)
index 0000000..2ad640f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include "wsp_res.h"
+
+static atomic_t __resource_id = ATOMIC_INIT(0);
+
+static inline int __wsp_resource_id(void)
+{
+       return atomic_inc_return(&__resource_id);
+}
+
+struct wsp_resource_data {
+       struct list_head list;
+       int id;
+       unsigned long addr;
+       char *path;
+};
+
+static LIST_HEAD(__resources_list);
+static DEFINE_MUTEX(__resources_mutex);
+
+static struct wsp_resource_data *wsp_resource_data_alloc(void)
+{
+       struct wsp_resource_data *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
+
+       INIT_LIST_HEAD(&p->list);
+
+       return p;
+}
+
+static void wsp_resource_data_free(struct wsp_resource_data *p)
+{
+       if (!p)
+               return;
+
+       kfree(p->path);
+       kfree(p);
+}
+
+static struct wsp_resource_data *wsp_resource_data_find(unsigned long addr)
+{
+       struct wsp_resource_data *p;
+
+       list_for_each_entry(p, &__resources_list, list)
+               if (p->addr == addr)
+                       return p;
+
+       return NULL;
+}
+
+int wsp_resource_data_id(unsigned long addr)
+{
+       int ret = -1;
+       struct wsp_resource_data *p;
+
+       mutex_lock(&__resources_mutex);
+       p = wsp_resource_data_find(addr);
+       if (p)
+               ret = p->id;
+       mutex_unlock(&__resources_mutex);
+
+       return ret;
+}
+
+int wsp_resource_data_add(unsigned long addr, char *path)
+{
+       int ret = -1;
+       struct wsp_resource_data *p;
+
+       mutex_lock(&__resources_mutex);
+       p = wsp_resource_data_find(addr);
+       if (p) {
+               ret = p->id;
+               goto out;
+       }
+       p = wsp_resource_data_alloc();
+       if (p) {
+               p->id = __wsp_resource_id();
+               p->addr = addr;
+               p->path = path;
+               list_add_tail(&p->list, &__resources_list);
+               ret = p->id;
+       }
+
+out:
+       mutex_unlock(&__resources_mutex);
+
+       return ret;
+}
+
+void wsp_resource_data_del(unsigned long addr)
+{
+       struct wsp_resource_data *p;
+
+       mutex_lock(&__resources_mutex);
+       p = wsp_resource_data_find(addr);
+       if (p) {
+               list_del(&p->list);
+               wsp_resource_data_free(p);
+       }
+
+       mutex_unlock(&__resources_mutex);
+}
+
+/* ============================================================================
+ * =                                init/exit()                               =
+ * ============================================================================
+ */
+int wsp_res_init(void)
+{
+       return 0;
+}
+
+void wsp_res_exit(void)
+{
+       struct wsp_resource_data *p, *tmp;
+
+       mutex_lock(&__resources_mutex);
+       list_for_each_entry_safe(p, tmp, &__resources_list, list) {
+               list_del(&p->list);
+               wsp_resource_data_free(p);
+       }
+       mutex_unlock(&__resources_mutex);
+}
diff --git a/modules/wsp/wsp_res.h b/modules/wsp/wsp_res.h
new file mode 100644 (file)
index 0000000..9c13478
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _WSP_TDATA_H
+#define _WSP_TDATA_H
+
+/*
+ * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * @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, see <http://www.gnu.org/licenses/>.
+ *
+ * @section COPYRIGHT
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ *
+ * Web startup profiling
+ */
+
+#include <linux/types.h>
+
+int wsp_resource_data_add(unsigned long addr, char *path);
+void wsp_resource_data_del(unsigned long addr);
+int wsp_resource_data_id(unsigned long addr);
+
+int wsp_res_init(void);
+void wsp_res_exit(void);
+
+#endif /* _WSP_TDATA_H */
diff --git a/nsp/Kbuild b/nsp/Kbuild
deleted file mode 100644 (file)
index 86ea819..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_nsp.o
-swap_nsp-y := \
-       nsp_module.o \
-       nsp.o \
-       nsp_msg.o \
-       nsp_debugfs.o
diff --git a/nsp/nsp.c b/nsp/nsp.c
deleted file mode 100644 (file)
index 39d8d29..0000000
--- a/nsp/nsp.c
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <writer/swap_msg.h>
-#include <kprobe/swap_ktd.h>
-#include <uprobe/swap_uaccess.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/probes/probe_info_new.h>
-#include "nsp.h"
-#include "nsp_msg.h"
-#include "nsp_print.h"
-#include "nsp_debugfs.h"
-
-
-/* ============================================================================
- * =                                 probes                                   =
- * ============================================================================
- */
-
-/* dlopen@plt */
-static int dlopen_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int dlopen_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_desc pin_dlopen = MAKE_URPROBE(dlopen_eh, dlopen_rh, 0);
-static struct probe_new p_dlopen = {
-       .desc = &pin_dlopen
-};
-
-/* dlsym@plt */
-static int dlsym_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int dlsym_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_desc pin_dlsym = MAKE_URPROBE(dlsym_eh, dlsym_rh, 0);
-static struct probe_new p_dlsym = {
-       .desc = &pin_dlsym
-};
-
-/* main */
-static int main_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int main_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_desc pin_main = MAKE_URPROBE(main_eh, main_rh, 0);
-
-/* appcore_efl_main */
-static int ac_efl_main_h(struct uprobe *p, struct pt_regs *regs);
-static struct probe_desc pin_ac_efl_main = MAKE_UPROBE(ac_efl_main_h);
-static struct probe_new p_ac_efl_main = {
-       .desc = &pin_ac_efl_main
-};
-
-/* appcore_init@plt */
-static int ac_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_desc pin_ac_init = MAKE_URPROBE(NULL, ac_init_rh, 0);
-static struct probe_new p_ac_init = {
-       .desc = &pin_ac_init
-};
-
-/* elm_run@plt */
-static int elm_run_h(struct uprobe *p, struct pt_regs *regs);
-static struct probe_desc pin_elm_run = MAKE_UPROBE(elm_run_h);
-static struct probe_new p_elm_run = {
-       .desc = &pin_elm_run
-};
-
-/* __do_app */
-static int do_app_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int do_app_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_desc pin_do_app = MAKE_URPROBE(do_app_eh, do_app_rh, 0);
-static struct probe_new p_do_app = {
-       .desc = &pin_do_app
-};
-
-
-
-
-
-/* ============================================================================
- * =                the variables are initialized by the user                 =
- * ============================================================================
- */
-static const char *lpad_path;
-static struct dentry *lpad_dentry;
-
-static const char *libappcore_path;
-static struct dentry *libappcore_dentry;
-static const char *libcapi_path;
-static struct dentry *libcapi_dentry;
-
-static void uninit_variables(void)
-{
-       kfree(lpad_path);
-       lpad_path = NULL;
-       lpad_dentry = NULL;
-
-       kfree(libappcore_path);
-       libappcore_path = NULL;
-       libappcore_dentry = NULL;
-
-       kfree(libcapi_path);
-       libcapi_path = NULL;
-       libcapi_dentry = NULL;
-}
-
-static bool is_init(void)
-{
-       return lpad_dentry && libappcore_dentry && libcapi_dentry;
-}
-
-static int do_set_lpad_info(const char *path, unsigned long dlopen,
-                           unsigned long dlsym)
-{
-       struct dentry *dentry;
-       const char *new_path;
-
-       dentry = dentry_by_path(path);
-       if (dentry == NULL) {
-               pr_err("dentry not found (path='%s')\n", path);
-               return -EINVAL;
-       }
-
-       new_path = kstrdup(path, GFP_KERNEL);
-       if (new_path == NULL) {
-               pr_err("out of memory\n");
-               return -ENOMEM;
-       }
-
-       kfree(lpad_path);
-
-       lpad_path = new_path;
-       lpad_dentry = dentry;
-       p_dlopen.offset = dlopen;
-       p_dlsym.offset = dlsym;
-
-       return 0;
-}
-
-static int do_set_appcore_info(struct nsp_info_data *info)
-{
-       struct dentry *dentry;
-       const char *new_path;
-       int ret = 0;
-
-       new_path = kstrdup(info->appcore_path, GFP_KERNEL);
-       if (!new_path)
-               return -ENOMEM;
-       kfree(libappcore_path);
-       libappcore_path = new_path;
-
-       new_path = kstrdup(info->capi_path, GFP_KERNEL);
-       if (!new_path) {
-               ret = -ENOMEM;
-               goto fail_alloc;
-       }
-       kfree(libcapi_path);
-       libcapi_path = new_path;
-
-       dentry = dentry_by_path(info->appcore_path);
-       if (!dentry) {
-               pr_err("dentry not found (path='%s')\n", info->appcore_path);
-               ret = -EINVAL;
-               goto fail;
-       }
-       libappcore_dentry = dentry;
-
-       dentry = dentry_by_path(info->capi_path);
-       if (!dentry) {
-               pr_err("dentry not found (path='%s')\n", info->capi_path);
-               ret = -EINVAL;
-               goto fail;
-       }
-       libcapi_dentry = dentry;
-
-       p_ac_efl_main.offset = info->ac_efl_init;
-       p_do_app.offset = info->do_app;
-       p_ac_init.offset = info->ac_init;
-       p_elm_run.offset = info->elm_run;
-
-       return 0;
-
-fail:
-       kfree(libcapi_path);
-       libcapi_path = NULL;
-fail_alloc:
-       kfree(libappcore_path);
-       libappcore_path = NULL;
-
-       return ret;
-}
-
-
-
-
-
-/* ============================================================================
- * =                                nsp_data                                  =
- * ============================================================================
- */
-struct nsp_data {
-       struct list_head list;
-
-       const char *app_path;
-       struct dentry *app_dentry;
-       struct probe_new p_main;
-
-       struct pf_group *pfg;
-};
-
-static LIST_HEAD(nsp_data_list);
-
-static struct nsp_data *nsp_data_create(const char *app_path,
-                                       unsigned long main_addr)
-{
-       struct dentry *dentry;
-       struct nsp_data *data;
-
-       dentry = dentry_by_path(app_path);
-       if (dentry == NULL)
-               return ERR_PTR(-ENOENT);
-
-       data = kmalloc(sizeof(*data), GFP_KERNEL);
-       if (data == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       data->app_path = kstrdup(app_path, GFP_KERNEL);
-       if (data->app_path == NULL) {
-               kfree(data);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       data->app_dentry = dentry;
-       data->p_main.desc = &pin_main;
-       data->p_main.offset = main_addr;
-       data->pfg = NULL;
-
-       return data;
-}
-
-static void nsp_data_destroy(struct nsp_data *data)
-{
-       kfree(data->app_path);
-       kfree(data);
-}
-
-static struct nsp_data *nsp_data_find(const struct dentry *dentry)
-{
-       struct nsp_data *data;
-
-       list_for_each_entry(data, &nsp_data_list, list) {
-               if (data->app_dentry == dentry)
-                       return data;
-       }
-
-       return NULL;
-}
-
-static struct nsp_data *nsp_data_find_by_path(const char *path)
-{
-       struct nsp_data *data;
-
-       list_for_each_entry(data, &nsp_data_list, list) {
-               if (strcmp(data->app_path, path) == 0)
-                       return data;
-       }
-
-       return NULL;
-}
-
-static void nsp_data_add(struct nsp_data *data)
-{
-       list_add(&data->list, &nsp_data_list);
-}
-
-static void nsp_data_rm(struct nsp_data *data)
-{
-       list_del(&data->list);
-}
-
-static int nsp_data_inst(struct nsp_data *data)
-{
-       int ret;
-       struct pf_group *pfg;
-
-       pfg = get_pf_group_by_dentry(lpad_dentry, (void *)data->app_dentry);
-       if (pfg == NULL)
-               return -ENOMEM;
-
-       ret = pin_register(&p_dlsym, pfg, lpad_dentry);
-       if (ret)
-               goto put_g;
-
-       ret = pin_register(&p_dlopen, pfg, lpad_dentry);
-       if (ret)
-               goto ur_dlsym;
-
-       ret = pin_register(&data->p_main, pfg, data->app_dentry);
-       if (ret)
-               goto ur_dlopen;
-
-       ret = pin_register(&p_ac_efl_main, pfg, libappcore_dentry);
-       if (ret)
-               goto ur_main;
-
-       ret = pin_register(&p_ac_init, pfg, libcapi_dentry);
-       if (ret)
-               goto ur_ac_efl_main;
-
-       ret = pin_register(&p_elm_run, pfg, libcapi_dentry);
-       if (ret)
-               goto ur_ac_init;
-
-       ret = pin_register(&p_do_app, pfg, libappcore_dentry);
-       if (ret)
-               goto ur_elm_run;
-
-       data->pfg = pfg;
-
-       return 0;
-
-ur_elm_run:
-       pin_unregister(&p_elm_run, pfg);
-ur_ac_init:
-       pin_unregister(&p_ac_init, pfg);
-ur_ac_efl_main:
-       pin_unregister(&p_ac_efl_main, pfg);
-ur_main:
-       pin_unregister(&data->p_main, pfg);
-ur_dlopen:
-       pin_unregister(&p_dlopen, pfg);
-ur_dlsym:
-       pin_unregister(&p_dlsym, pfg);
-put_g:
-       put_pf_group(pfg);
-       return ret;
-}
-
-static void nsp_data_uninst(struct nsp_data *data)
-{
-       struct pf_group *pfg = data->pfg;
-
-       pin_unregister(&p_do_app, pfg);
-       pin_unregister(&p_elm_run, pfg);
-       pin_unregister(&p_ac_init, pfg);
-       pin_unregister(&p_ac_efl_main, pfg);
-       pin_unregister(&data->p_main, pfg);
-       pin_unregister(&p_dlopen, pfg);
-       pin_unregister(&p_dlsym, pfg);
-       put_pf_group(pfg);
-
-       data->pfg = NULL;
-}
-
-static int __nsp_add(const char *app_path, unsigned long main_addr)
-{
-       struct nsp_data *data;
-
-       if (nsp_data_find_by_path(app_path))
-               return -EEXIST;
-
-       data = nsp_data_create(app_path, main_addr);
-       if (IS_ERR(data))
-               return PTR_ERR(data);
-
-       nsp_data_add(data);
-
-       return 0;
-}
-
-static int __nsp_rm(const char *path)
-{
-       struct dentry *dentry;
-       struct nsp_data *data;
-
-       dentry = dentry_by_path(path);
-       if (dentry == NULL)
-               return -ENOENT;
-
-       data = nsp_data_find(dentry);
-       if (data == NULL)
-               return -ESRCH;
-
-       nsp_data_rm(data);
-       nsp_data_destroy(data);
-
-       return 0;
-}
-
-static int __nsp_rm_all(void)
-{
-       struct nsp_data *data, *n;
-
-       list_for_each_entry_safe(data, n, &nsp_data_list, list) {
-               nsp_data_rm(data);
-               nsp_data_destroy(data);
-       }
-
-       return 0;
-}
-
-static void __nsp_disabel(void)
-{
-       struct nsp_data *data;
-
-       list_for_each_entry(data, &nsp_data_list, list) {
-               if (data->pfg)
-                       nsp_data_uninst(data);
-       }
-}
-
-static int __nsp_enable(void)
-{
-       int ret;
-       struct nsp_data *data;
-
-       list_for_each_entry(data, &nsp_data_list, list) {
-               ret = nsp_data_inst(data);
-               if (ret)
-                       goto fail;
-       }
-
-       return 0;
-
-fail:
-       __nsp_disabel();
-       return ret;
-}
-
-
-
-
-
-
-
-/* ============================================================================
- * =                             set parameters                               =
- * ============================================================================
- */
-#define F_ARG1(m, t, a)                m(t, a)
-#define F_ARG2(m, t, a, ...)   m(t, a), F_ARG1(m, __VA_ARGS__)
-#define F_ARG3(m, t, a, ...)   m(t, a), F_ARG2(m, __VA_ARGS__)
-#define F_ARG(n, m, ...)       F_ARG##n(m, __VA_ARGS__)
-
-#define M_TYPE_AND_ARG(t, a)   t a
-#define M_ARG(t, a)            a
-
-#define DECLARE_SAFE_FUNC(n, func_name, do_func, ...)  \
-int func_name(F_ARG(n, M_TYPE_AND_ARG,  __VA_ARGS__))  \
-{                                                      \
-       int ret;                                        \
-       mutex_lock(&stat_mutex);                        \
-       if (stat == NS_ON) {                            \
-               ret = -EBUSY;                           \
-               goto unlock;                            \
-       }                                               \
-       ret = do_func(F_ARG(n, M_ARG,  __VA_ARGS__));   \
-unlock:                                                        \
-       mutex_unlock(&stat_mutex);                      \
-       return ret;                                     \
-}
-
-#define DECLARE_SAFE_FUNC0(name, _do)          DECLARE_SAFE_FUNC(1, name, _do, void, /* */);
-#define DECLARE_SAFE_FUNC1(name, _do, ...)     DECLARE_SAFE_FUNC(1, name, _do, __VA_ARGS__);
-#define DECLARE_SAFE_FUNC2(name, _do, ...)     DECLARE_SAFE_FUNC(2, name, _do, __VA_ARGS__);
-#define DECLARE_SAFE_FUNC3(name, _do, ...)     DECLARE_SAFE_FUNC(3, name, _do, __VA_ARGS__);
-
-
-static DEFINE_MUTEX(stat_mutex);
-static enum nsp_stat stat = NS_OFF;
-
-DECLARE_SAFE_FUNC2(nsp_add, __nsp_add, const char *, app_path,
-                  unsigned long, main_addr);
-DECLARE_SAFE_FUNC1(nsp_rm, __nsp_rm, const char *, app_path);
-DECLARE_SAFE_FUNC0(nsp_rm_all, __nsp_rm_all);
-DECLARE_SAFE_FUNC3(nsp_set_lpad_info, do_set_lpad_info,
-                  const char *, path, unsigned long, dlopen,
-                  unsigned long, dlsym);
-DECLARE_SAFE_FUNC1(nsp_set_appcore_info, do_set_appcore_info,
-                  struct nsp_info_data *, info);
-
-
-
-
-
-/* ============================================================================
- * =                               set stat                                   =
- * ============================================================================
- */
-static int set_stat_off(void)
-{
-       if (stat == NS_OFF)
-               return -EINVAL;
-
-       __nsp_disabel();
-
-       stat = NS_OFF;
-
-       return 0;
-}
-
-static int set_stat_on(void)
-{
-       if (is_init() == false)
-               return -EPERM;
-
-       if (stat == NS_ON)
-               return -EINVAL;
-
-       __nsp_enable();
-
-       stat = NS_ON;
-
-       return 0;
-}
-
-int nsp_set_stat(enum nsp_stat st)
-{
-       int ret = -EINVAL;
-
-       mutex_lock(&stat_mutex);
-       switch (st) {
-       case NS_OFF:
-               ret = set_stat_off();
-               break;
-       case NS_ON:
-               ret = set_stat_on();
-               break;
-       }
-       mutex_unlock(&stat_mutex);
-
-       return ret;
-}
-
-enum nsp_stat nsp_get_stat(void)
-{
-       return stat;
-}
-
-
-
-
-
-/* ============================================================================
- * =                                 tdata                                    =
- * ============================================================================
- */
-enum nsp_proc_stat {
-       NPS_OPEN_E,             /* mapping begin */
-       NPS_OPEN_R,
-       NPS_SYM_E,
-       NPS_SYM_R,              /* mapping end   */
-       NPS_MAIN_E,             /* main begin    */
-       NPS_AC_EFL_MAIN_E,      /* main end      */
-       NPS_AC_INIT_R,          /* create begin  */
-       NPS_ELM_RUN_E,          /* create end    */
-       NPS_DO_APP_E,           /* reset begin   */
-       NPS_DO_APP_R            /* reset end     */
-};
-
-struct tdata {
-       enum nsp_proc_stat stat;
-       struct nsp_data *nsp_data;
-       u64 time;
-       void __user *handle;
-       struct probe_new p_main;
-};
-
-
-static void ktd_init(struct task_struct *task, void *data)
-{
-       struct tdata *tdata = (struct tdata *)data;
-
-       tdata->nsp_data = NULL;
-}
-
-static struct ktask_data ktd = {
-       .init = ktd_init,
-       .size = sizeof(struct tdata),
-};
-
-static struct tdata *tdata_get(struct task_struct *task)
-{
-       return (struct tdata *)swap_ktd(&ktd, task);
-}
-
-
-
-
-
-/* ============================================================================
- * =                                handlers                                  =
- * ============================================================================
- */
-static int dlopen_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       const char __user *user_s = (const char __user *)swap_get_uarg(regs, 0);
-       const char *path;
-       struct nsp_data *nsp_data;
-
-       path = strdup_from_user(user_s, GFP_ATOMIC);
-       if (path == NULL)
-               return 0;
-
-       nsp_data = nsp_data_find_by_path(path);
-       if (nsp_data) {
-               struct tdata *tdata = tdata_get(current);
-
-               /* init tdata */
-               if (tdata->nsp_data == NULL) {
-                       tdata->stat = NPS_OPEN_E;
-                       tdata->time = swap_msg_current_time();
-                       tdata->nsp_data = nsp_data;
-               }
-       }
-
-       kfree(path);
-       return 0;
-}
-
-static int dlopen_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct tdata *tdata = tdata_get(current);
-       void *handle = (void *)regs_return_value(regs);
-
-       if ((tdata->stat == NPS_OPEN_E) && handle) {
-               tdata->stat = NPS_OPEN_R;
-               tdata->handle = handle;
-       } else {
-               tdata->handle = NULL;
-       }
-
-       return 0;
-}
-
-static int dlsym_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct tdata *tdata = tdata_get(current);
-       void __user *handle = (void __user *)swap_get_uarg(regs, 0);
-       const char __user *str = (const char __user *)swap_get_uarg(regs, 1);
-
-       if (handle == tdata->handle && tdata->stat == NPS_OPEN_R) {
-               const char *name;
-
-               name = strdup_from_user(str, GFP_ATOMIC);
-               if (name && (strcmp(name, "main") == 0))
-                       tdata->stat = NPS_SYM_E;
-
-               kfree(name);
-       }
-
-       return 0;
-}
-
-static int dlsym_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct tdata *tdata = tdata_get(current);
-
-       if (tdata->handle && tdata->stat == NPS_SYM_E)
-               tdata->stat = NPS_SYM_R;
-
-       return 0;
-}
-
-static void stage_begin(enum nsp_proc_stat priv, enum nsp_proc_stat cur)
-{
-       struct tdata *tdata = tdata_get(current);
-
-       if (tdata->handle && tdata->stat == priv) {
-               tdata->stat = cur;
-               tdata->time = swap_msg_current_time();
-       }
-}
-
-static void stage_end(enum nsp_proc_stat priv, enum nsp_proc_stat cur,
-                     enum nsp_msg_stage st)
-{
-       struct tdata *tdata = tdata_get(current);
-       u64 time_start;
-       u64 time_end;
-
-       if (tdata->handle && tdata->stat == priv) {
-               tdata->stat = cur;
-               time_start = tdata->time;
-
-               time_end = swap_msg_current_time();
-               nsp_msg(st, time_start, time_end);
-       }
-}
-
-static int main_h(struct uprobe *p, struct pt_regs *regs)
-{
-       struct tdata *tdata = tdata_get(current);
-       u64 time_start;
-       u64 time_end;
-
-       if (tdata->handle && tdata->stat == NPS_SYM_R) {
-               tdata->stat = NPS_MAIN_E;
-               time_start = tdata->time;
-               time_end = swap_msg_current_time();
-               tdata->time = time_end;
-
-               nsp_msg(NMS_MAPPING, time_start, time_end);
-       }
-
-       return 0;
-}
-
-/* FIXME: workaround for simultaneously nsp and main() function profiling */
-#include <retprobe/rp_msg.h>
-#include <us_manager/us_manager.h>
-
-static int main_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct uretprobe *rp = ri->rp;
-
-       if (rp) {
-               main_h(&rp->up, regs);
-
-               if (get_quiet() == QT_OFF) {
-                       struct sspt_ip *ip;
-                       unsigned long func_addr;
-
-                       ip = container_of(rp, struct sspt_ip, retprobe);
-                       func_addr = (unsigned long)ip->orig_addr;
-                       rp_msg_entry(regs, func_addr, "p");
-               }
-       }
-
-       return 0;
-}
-
-static int main_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct uretprobe *rp = ri->rp;
-
-       if (rp && get_quiet() == QT_OFF) {
-               struct sspt_ip *ip;
-               unsigned long func_addr;
-               unsigned long ret_addr;
-
-               ip = container_of(rp, struct sspt_ip, retprobe);
-               func_addr = (unsigned long)ip->orig_addr;
-               ret_addr = (unsigned long)ri->ret_addr;
-               rp_msg_exit(regs, func_addr, 'n', ret_addr);
-       }
-
-       return 0;
-}
-
-static int ac_efl_main_h(struct uprobe *p, struct pt_regs *regs)
-{
-       stage_end(NPS_MAIN_E, NPS_AC_EFL_MAIN_E, NMS_MAIN);
-       return 0;
-}
-
-static int ac_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       stage_begin(NPS_AC_EFL_MAIN_E, NPS_AC_INIT_R);
-       return 0;
-}
-
-static int elm_run_h(struct uprobe *p, struct pt_regs *regs)
-{
-       stage_end(NPS_AC_INIT_R, NPS_ELM_RUN_E, NMS_CREATE);
-       return 0;
-}
-
-static int do_app_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       int event = swap_get_uarg(regs, 0);
-       enum { AE_RESET = 5 };  /* FIXME: hardcode */
-
-       if (event == AE_RESET)
-               stage_begin(NPS_ELM_RUN_E, NPS_DO_APP_E);
-
-       return 0;
-}
-
-static int do_app_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       stage_end(NPS_DO_APP_E, NPS_DO_APP_R, NMS_RESET);
-       return 0;
-}
-
-
-
-
-
-int nsp_init(void)
-{
-       return swap_ktd_reg(&ktd);
-}
-
-void nsp_exit(void)
-{
-       if (stat == NS_ON)
-               set_stat_off();
-
-       uninit_variables();
-       swap_ktd_unreg(&ktd);
-}
diff --git a/nsp/nsp.h b/nsp/nsp.h
deleted file mode 100644 (file)
index 35236a4..0000000
--- a/nsp/nsp.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _NSP_H
-#define _NSP_H
-
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-enum offset_t {
-       OS_CREATE,
-       OS_RESET
-};
-
-enum nsp_stat {
-       NS_OFF,
-       NS_ON
-};
-
-struct nsp_info_data {
-       const char *appcore_path;
-       unsigned long ac_efl_init;
-       unsigned long do_app;
-
-       const char *capi_path;
-       unsigned long ac_init;
-       unsigned long elm_run;
-};
-
-int nsp_init(void);
-void nsp_exit(void);
-
-int nsp_set_lpad_info(const char *path, unsigned long dlopen,
-                     unsigned long dlsym);
-int nsp_set_appcore_info(struct nsp_info_data *info);
-
-int nsp_set_stat(enum nsp_stat st);
-enum nsp_stat nsp_get_stat(void);
-
-int nsp_add(const char *app_path, unsigned long main_addr);
-int nsp_rm(const char *app_path);
-int nsp_rm_all(void);
-
-
-#endif /* _NSP_H */
diff --git a/nsp/nsp_debugfs.c b/nsp/nsp_debugfs.c
deleted file mode 100644 (file)
index ebf0eb4..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/limits.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "nsp.h"
-
-
-/* remove end-line symbols */
-static void rm_endline_symbols(char *buf, size_t len)
-{
-       char *p, *buf_end;
-
-       buf_end = buf + len;
-       for (p = buf; p != buf_end; ++p)
-               if (*p == '\n' || *p == '\r')
-                       *p = '\0';
-}
-
-/*
- * format:
- *     main:app_path
- *
- * sample:
- *     0x00000d60:/bin/app_sample
- */
-static int do_add(const char *buf, size_t len)
-{
-       int n, ret;
-       char *app_path;
-       unsigned long main_addr;
-       const char fmt[] = "%%lx:/%%%ds";
-       char fmt_buf[64];
-
-       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
-       if (n <= 0)
-               return -EINVAL;
-
-       app_path = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (app_path == NULL)
-               return -ENOMEM;
-
-       n = sscanf(buf, fmt_buf, &main_addr, app_path + 1);
-       if (n != 2) {
-               ret = -EINVAL;
-               goto free_app_path;
-       }
-       app_path[0] = '/';
-
-       ret = nsp_add(app_path, main_addr);
-
-free_app_path:
-       kfree(app_path);
-       return ret;
-}
-
-/*
- * format:
- *     path
- *
- * sample:
- *     /tmp/sample
- */
-static int do_rm(const char *buf, size_t len)
-{
-       return nsp_rm(buf);
-}
-
-static int do_rm_all(const char *buf, size_t len)
-{
-       return nsp_rm_all();
-}
-
-/*
- * format:
- *     dlopen_addr@plt:dlsym_addr@plt:launchpad_path
- *
- * sample:
- *     0x000234:0x000342:/usr/bin/launchpad-loader
- */
-static int do_set_lpad_info(const char *data, size_t len)
-{
-       int n, ret;
-       unsigned long dlopen_addr;
-       unsigned long dlsym_addr;
-       char *lpad_path;
-       const char fmt[] = "%%lx:%%lx:/%%%ds";
-       char fmt_buf[64];
-
-       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
-       if (n <= 0)
-               return -EINVAL;
-
-       lpad_path = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (lpad_path == NULL)
-               return -ENOMEM;
-
-       n = sscanf(data, fmt_buf, &dlopen_addr, &dlsym_addr, lpad_path + 1);
-       if (n != 3) {
-               ret = -EINVAL;
-               goto free_lpad_path;
-       }
-       lpad_path[0] = '/';
-
-       ret = nsp_set_lpad_info(lpad_path, dlopen_addr, dlsym_addr);
-
-free_lpad_path:
-       kfree(lpad_path);
-       return ret;
-}
-
-/*
- * format:
- *     appcore_efl_init:__do_app:libappcore-efl ui_app_init:elm_run@plt:libcapi-appfw-application
- *
- * sample:
- *     0x2000:0x2ed0:/usr/lib/libappcore-efl.so.1 0x2b20:0x11f0:/usr/lib/libcapi-appfw-application.so.0
- */
-static int do_set_appcore_info(const char *data, size_t len)
-{
-       int n, ret;
-       struct nsp_info_data info;
-       const char fmt[] = "%%lx:%%lx:/%%%ds %%lx:%%lx:/%%%ds";
-       char fmt_buf[64];
-       char *appcore_path, *capi_path;
-
-       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2, PATH_MAX - 2);
-       if (n <= 0)
-               return -EINVAL;
-
-       appcore_path = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (!appcore_path)
-               return -ENOMEM;
-
-       capi_path = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (!capi_path) {
-               ret = -ENOMEM;
-               goto fail_alloc;
-       }
-
-       n = sscanf(data, fmt_buf,
-                  &info.ac_efl_init, &info.do_app, appcore_path + 1,
-                  &info.ac_init, &info.elm_run, capi_path + 1);
-       if (n != 6) {
-               ret = -EINVAL;
-               goto fail;
-       }
-       appcore_path[0] = '/';
-       capi_path[0] = '/';
-
-       info.appcore_path = appcore_path;
-       info.capi_path = capi_path;
-       ret = nsp_set_appcore_info(&info);
-
-fail:
-       kfree(capi_path);
-fail_alloc:
-       kfree(appcore_path);
-       return ret;
-}
-
-/*
- * format:
- *     0 byte - type
- *     1 byte - ' '
- *     2.. bytes - data
- */
-static int do_cmd(const char *data, size_t len)
-{
-       char type;
-       size_t len_data;
-       const char *cmd_data;
-
-       if (len) {
-               if (data[0] == 'c')
-                       return do_rm_all(data + 1, len - 1);
-       }
-       /*
-        * 0 byte - type
-        * 1 byte - ' '
-        */
-       if (len < 2 || data[1] != ' ')
-               return -EINVAL;
-
-       len_data = len - 2;
-       cmd_data = data + 2;
-       type = data[0];
-       switch (type) {
-       case 'a':
-               return do_add(cmd_data, len_data);
-       case 'b':
-               return do_set_lpad_info(cmd_data, len_data);
-       case 'l':
-               return do_set_appcore_info(cmd_data, len_data);
-       case 'r':
-               return do_rm(cmd_data, len_data);
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-
-
-
-/* ============================================================================
- * ===                          DEBUGFS FOR CMD                             ===
- * ============================================================================
- */
-static ssize_t write_cmd(struct file *file, const char __user *user_buf,
-                        size_t count, loff_t *ppos)
-{
-       char *buf;
-       ssize_t ret = count;
-
-       buf = kmalloc(count + 1, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
-
-       if (copy_from_user(buf, user_buf, count)) {
-               ret = -EFAULT;
-               goto free_buf;
-       }
-
-       buf[count] = '\0';
-       rm_endline_symbols(buf, count);
-
-       if (do_cmd(buf, count))
-               ret = -EINVAL;
-
-free_buf:
-       kfree(buf);
-
-       return ret;
-}
-
-static ssize_t read_cmd(struct file *file, char __user *user_buf,
-                       size_t count, loff_t *ppos)
-{
-       const char help[] =
-                       "use:\n"
-                       "\ta $app_path - add\n"
-                       "\tr $app_path - remove\n"
-                       "\tc - remove all\n"
-                       "\tb dlopen_addr@plt:dlsym_addr@plt:launchpad_path\n"
-                       "\tl appcore_efl_init:__do_app:libappcore-efl_path ui_app_init:elm_run@plt:libcapi-appfw-application_path\n";
-       ssize_t ret;
-
-       ret = simple_read_from_buffer(user_buf, count, ppos,
-                                     help, sizeof(help));
-
-       return ret;
-}
-
-static const struct file_operations fops_cmd = {
-       .read =         read_cmd,
-       .write =        write_cmd,
-       .llseek =       default_llseek
-};
-
-
-
-
-/* ============================================================================
- * ===                         DEBUGFS FOR ENABLE                           ===
- * ============================================================================
- */
-static ssize_t read_enabled(struct file *file, char /*__user*/ *user_buf,
-                           size_t count, loff_t *ppos)
-{
-       char buf[2];
-
-       buf[0] = nsp_get_stat() == NS_OFF ? '0' : '1';
-       buf[1] = '\n';
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static ssize_t write_enabled(struct file *file, const char /*__user*/ *user_buf,
-                            size_t count, loff_t *ppos)
-{
-       int ret = 0;
-       char buf[32];
-       size_t buf_size;
-
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       buf[buf_size] = '\0';
-       switch (buf[0]) {
-       case '1':
-               ret = nsp_set_stat(NS_ON);
-               break;
-       case '0':
-               ret = nsp_set_stat(NS_OFF);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static const struct file_operations fops_enabled = {
-       .read =         read_enabled,
-       .write =        write_enabled,
-       .llseek =       default_llseek,
-};
-
-
-
-
-static struct dentry *nsp_dir = NULL;
-
-void nsp_debugfs_exit(void)
-{
-       if (nsp_dir)
-               debugfs_remove_recursive(nsp_dir);
-
-       nsp_dir = NULL;
-}
-
-int nsp_debugfs_init(void)
-{
-       struct dentry *dentry;
-
-       dentry = swap_debugfs_getdir();
-       if (dentry == NULL)
-               return -ENOENT;
-
-       nsp_dir = swap_debugfs_create_dir("nsp", dentry);
-       if (nsp_dir == NULL)
-               return -ENOMEM;
-
-       dentry = swap_debugfs_create_file("cmd", 0600, nsp_dir, NULL,
-                                         &fops_cmd);
-       if (dentry == NULL)
-               goto fail;
-
-       dentry = swap_debugfs_create_file("enabled", 0600, nsp_dir, NULL,
-                                         &fops_enabled);
-       if (dentry == NULL)
-               goto fail;
-
-       return 0;
-
-fail:
-       nsp_debugfs_exit();
-       return -ENOMEM;
-}
diff --git a/nsp/nsp_debugfs.h b/nsp/nsp_debugfs.h
deleted file mode 100644 (file)
index 62565b7..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _NSP_DEBUGFS_H
-#define _NSP_DEBUGFS_H
-
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-int nsp_debugfs_init(void);
-void nsp_debugfs_exit(void);
-
-
-#endif /* _NSP_DEBUGFS_H */
diff --git a/nsp/nsp_module.c b/nsp/nsp_module.c
deleted file mode 100644 (file)
index e40f8ee..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "nsp.h"
-#include "nsp_debugfs.h"
-
-
-SWAP_LIGHT_INIT_MODULE(NULL, nsp_init, nsp_exit,
-                      nsp_debugfs_init, nsp_debugfs_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/nsp/nsp_msg.c b/nsp/nsp_msg.c
deleted file mode 100644 (file)
index b48c3a1..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <writer/swap_msg.h>
-#include "nsp_msg.h"
-
-
-struct nsp_msg_struct {
-       u32 pid;
-       u32 stage;
-       u64 begin_time;
-       u64 end_time;
-} __packed;
-
-
-void nsp_msg(enum nsp_msg_stage stage, u64 begin_time, u64 end_time)
-{
-       struct swap_msg *m;
-       struct nsp_msg_struct *nsp;
-
-       m = swap_msg_get(MSG_NSP);
-
-       nsp = (struct nsp_msg_struct *)swap_msg_payload(m);
-       nsp->pid = (u32)current->tgid;
-       nsp->stage = (u32)stage;
-       nsp->begin_time = begin_time;
-       nsp->end_time = end_time;
-
-       swap_msg_flush(m, sizeof(*nsp));
-       swap_msg_put(m);
-}
diff --git a/nsp/nsp_msg.h b/nsp/nsp_msg.h
deleted file mode 100644 (file)
index 17d50ba..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-#ifndef _NSP_MSG_H
-#define _NSP_MSG_H
-
-
-#include <linux/types.h>
-
-
-enum nsp_msg_stage {
-       NMS_MAPPING     = 0x00,
-       NMS_MAIN        = 0x01,
-       NMS_CREATE      = 0x02,
-       NMS_RESET       = 0x03,
-};
-
-
-void nsp_msg(enum nsp_msg_stage stage, u64 begin_time, u64 end_time);
-
-
-#endif /* _NSP_MSG_H */
diff --git a/nsp/nsp_print.h b/nsp/nsp_print.h
deleted file mode 100644 (file)
index d4d68d4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-#ifndef _NSP_PRINT_H
-#define _NSP_PRINT_H
-
-
-#include <linux/printk.h>
-
-
-#define NSP_PREFIX "[NSP] "
-
-#define nsp_print(...) printk(NSP_PREFIX __VA_ARGS__)
-
-
-#endif /* _NSP_PRINT_H */
diff --git a/pack.sh b/pack.sh
deleted file mode 100755 (executable)
index 3186cbc..0000000
--- a/pack.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash -ex
-
-if [ $# -ne 1 ]; then
-       echo "Usage $0 <dest_dir>"
-       exit 0
-fi
-
-scrdir=$(dirname $(readlink -f $0))
-
-dest=$1
-mkdir -p $dest
-
-mode=0666
-
-modules="master/swap_master.ko
-        buffer/swap_buffer.ko
-        ksyms/swap_ksyms.ko
-        driver/swap_driver.ko
-        writer/swap_writer.ko
-        kprobe/swap_kprobe.ko
-        ks_manager/swap_ks_manager.ko
-        uprobe/swap_uprobe.ko
-        us_manager/swap_us_manager.ko
-        ks_features/swap_ks_features.ko
-        sampler/swap_sampler.ko
-        energy/swap_energy.ko
-        parser/swap_message_parser.ko
-        retprobe/swap_retprobe.ko
-        loader/swap_loader.ko
-        preload/swap_preload.ko
-        uihv/swap_uihv.ko
-        fbiprobe/swap_fbiprobe.ko
-        wsp/swap_wsp.ko
-        nsp/swap_nsp.ko
-        task_ctx/swap_taskctx.ko
-        got_patcher/swap_gtp.ko"
-
-for i in $modules; do
-       mv $scrdir/$i $dest/
-       chmod 0666 $dest/$(basename $i)
-done
index aecca2f50eeeb6a7b9ec5d93918de728b1de6191..222e96ba44c01399009235c1893049a7d88a8cc6 100755 (executable)
@@ -56,6 +56,7 @@ Kernel modules for SWAP
 %setup -q
 
 %build
+cd modules
 %ifarch armv7l
 # TM1
 ./build.sh --kernel /boot/kernel/devel/kernel-devel-tizen_tm1 --arch arm clean
@@ -109,7 +110,7 @@ mv /tmp/emul_swap_modules %{buildroot}/opt/swap/sdk/
   %endif
  %endif
 %endif
-install -m 770 deploy.sh -t %{buildroot}/opt/swap/sdk
+install -m 770 modules/deploy.sh -t %{buildroot}/opt/swap/sdk
 
 
 # mkdir -p %{buildroot}/usr/share/license
diff --git a/parser/Kbuild b/parser/Kbuild
deleted file mode 100644 (file)
index 7faf7ba..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../energy/Module.symvers \
-                       $(src)/../ks_features/Module.symvers \
-                       $(src)/../driver/Module.symvers \
-                       $(src)/../writer/Module.symvers \
-                       $(src)/../us_manager/Module.symvers \
-                       $(src)/../sampler/Module.symvers
-
-obj-m := swap_message_parser.o
-swap_message_parser-y := swap_msg_parser.o \
-                         msg_parser.o \
-                         msg_buf.o \
-                         msg_cmd.o \
-                         features.o \
-                         us_inst.o \
-                         cpu_ctrl.o \
-                         usm_msg.o
diff --git a/parser/cpu_ctrl.c b/parser/cpu_ctrl.c
deleted file mode 100644 (file)
index f5498b9..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * parser/cpu_ctrl.c
- * @author Vasiliy Ulyanov <v.ulyanov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * CPU controls implementation.
- */
-
-#include <linux/cpumask.h>
-#include <linux/cpu.h>
-#include <ksyms/ksyms.h>
-
-#ifdef CONFIG_SMP
-static void (*swap_cpu_maps_update_begin)(void);
-static void (*swap_cpu_maps_update_done)(void);
-static int (*swap_cpu_down)(unsigned int, int);
-static int (*swap_cpu_up)(unsigned int, int);
-
-/**
- * @brief Disables nonboot CPUs lock.
- *
- * @param mask Pointer to CPU mask struct.
- * @return 0 on success, error code on error.
- */
-int swap_disable_nonboot_cpus_lock(struct cpumask *mask)
-{
-       int boot_cpu, cpu;
-       int ret = 0;
-
-       swap_cpu_maps_update_begin();
-       cpumask_clear(mask);
-
-       boot_cpu = cpumask_first(cpu_online_mask);
-
-       for_each_online_cpu(cpu) {
-               if (cpu == boot_cpu)
-                       continue;
-               ret = swap_cpu_down(cpu, 0);
-               if (ret == 0)
-                       cpumask_set_cpu(cpu, mask);
-               printk(KERN_INFO "===> SWAP CPU[%d] down(%d)\n", cpu, ret);
-       }
-
-       WARN_ON(num_online_cpus() > 1);
-       return ret;
-}
-
-/**
- * @brief Enables nonboot CPUs unlock.
- *
- * @param mask Pointer to CPU mask struct.
- * @return 0 on success, error code on error.
- */
-int swap_enable_nonboot_cpus_unlock(struct cpumask *mask)
-{
-       int cpu, ret = 0;
-
-       if (cpumask_empty(mask))
-               goto out;
-
-       for_each_cpu(cpu, mask) {
-               ret = swap_cpu_up(cpu, 0);
-               printk(KERN_INFO "===> SWAP CPU[%d] up(%d)\n", cpu, ret);
-       }
-
-out:
-       swap_cpu_maps_update_done();
-
-       return ret;
-}
-
-/**
- * @brief Intializes CPU controls.
- *
- * @return 0 on success, error code on error.
- */
-int init_cpu_deps(void)
-{
-       const char *sym = "cpu_maps_update_begin";
-
-       swap_cpu_maps_update_begin = (void *)swap_ksyms(sym);
-       if (!swap_cpu_maps_update_begin)
-               goto not_found;
-
-       sym = "cpu_maps_update_done";
-       swap_cpu_maps_update_done = (void *)swap_ksyms(sym);
-       if (!swap_cpu_maps_update_done)
-               goto not_found;
-
-       sym = "_cpu_up";
-       swap_cpu_up = (void *)swap_ksyms(sym);
-       if (!swap_cpu_up)
-               goto not_found;
-
-       sym = "_cpu_down";
-       swap_cpu_down = (void *)swap_ksyms(sym);
-       if (!swap_cpu_down)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol %s(...) not found\n", sym);
-       return -ESRCH;
-}
-
-#endif /* CONFIG_SMP */
diff --git a/parser/cpu_ctrl.h b/parser/cpu_ctrl.h
deleted file mode 100644 (file)
index 36d3ed1..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @file parser/cpu_ctrl.h
- * @author Vasiliy Ulyanov <v.ulyanov@samsung.com>
- *
- * @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, 2014
- *
- * @section DESCRIPTION
- *
- * CPU controls interface.
- */
-
-#ifndef _CPU_CTRL_H_
-#define _CPU_CTRL_H_
-
-struct cpumask;
-
-#ifdef CONFIG_SMP
-int swap_disable_nonboot_cpus_lock(struct cpumask *mask);
-int swap_enable_nonboot_cpus_unlock(struct cpumask *mask);
-
-int init_cpu_deps(void);
-
-#else /* CONFIG_SMP */
-
-static inline int swap_disable_nonboot_cpus_lock(struct cpumask *mask)
-{
-       return 0;
-}
-
-static inline int swap_enable_nonboot_cpus_unlock(struct cpumask *mask)
-{
-       return 0;
-}
-
-static inline int init_cpu_deps(void)
-{
-       return 0;
-}
-
-#endif /* CONFIG_SMP */
-
-#endif /* _CPU_CTRL_H_ */
diff --git a/parser/features.c b/parser/features.c
deleted file mode 100644 (file)
index da2d61d..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-/**
- * parser/features.c
- * @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
- *
- * Features control implementation.
- */
-
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <ks_features/ks_features.h>
-#include <us_manager/us_manager.h>
-#include "parser_defs.h"
-#include "features.h"
-#include "msg_parser.h"
-
-#include <writer/swap_msg.h>
-#include <writer/event_filter.h>
-#include <sampler/swap_sampler_module.h>
-#include <energy/energy.h>
-
-/**
- * @enum features_list
- * List of supported features.
- */
-enum features_list {
-       syscall_file    = (1 << 10),    /**< File operation syscalls tracing */
-       syscall_ipc     = (1 << 11),    /**< IPC syscall tracing */
-       syscall_process = (1 << 12),    /**< Process syscalls tracing */
-       syscall_signal  = (1 << 13),    /**< Signal syscalls tracing */
-       syscall_network = (1 << 14),    /**< Network syscalls tracing */
-       syscall_desc    = (1 << 15),    /**< Descriptor syscalls tracing */
-       context_switch  = (1 << 16),    /**< Context switch tracing */
-       func_sampling   = (1 << 19)     /**< Function sampling */
-};
-
-/**
- * @brief Start user-space instrumentation event handling.
- *
- * @param conf Pointer to conf_data config.
- * @return 0.
- */
-int set_us_inst(struct conf_data *conf)
-{
-       set_quiet(QT_OFF);
-
-       return 0;
-}
-
-/**
- * @brief Stop user-space instrumentation event handling.
- *
- * @return 0.
- */
-int unset_us_inst(void)
-{
-       set_quiet(QT_ON);
-
-       return 0;
-}
-
-/**
- * @brief Set syscall file feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_file(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_FILE);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall file feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_file(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_FILE);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall ipc feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_ipc(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_IPC);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall ipc feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_ipc(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_IPC);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall process feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_process(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_PROCESS);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall process feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_process(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_PROCESS);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall signal feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_signal(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_SIGNAL);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall signal feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_signal(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_SIGNAL);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall network feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_network(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_NET);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall network feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_network(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_NET);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall desc feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_desc(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_DESC);
-
-       return ret;
-}
-
-/**
- * @brief Set syscall desc feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_desc(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_DESC);
-
-       return ret;
-}
-
-/**
- * @brief Set context switch feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_context_switch(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_feature(FID_SWITCH);
-
-       return ret;
-}
-/**
- * @brief Set context switch feature off.
- *
- * @return unset_feature results.
- */
-int unset_context_switch(void)
-{
-       int ret;
-
-       ret = unset_feature(FID_SWITCH);
-
-       return ret;
-}
-
-
-
-
-
-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 = raw_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))
-               sample_msg(regs);
-}
-
-/**
- * @brief Set sampling feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_func_sampling(struct conf_data *conf)
-{
-       int ret;
-
-       ret = swap_sampler_start(conf->data_msg_period, sampler_cb);
-
-       return ret;
-}
-
-/**
- * @brief Set sampling feature off.
- *
- * @return unset_feature results.
- */
-int unset_func_sampling(void)
-{
-       int ret;
-
-       ret = swap_sampler_stop();
-
-       return ret;
-}
-
-static int set_func_energy(struct conf_data *conf)
-{
-       return set_energy();
-}
-
-static int unset_func_energy(void)
-{
-       return unset_energy();
-}
-
-static int set_sysfile_activity(struct conf_data *conf)
-{
-       return set_feature(FID_SYSFILE_ACTIVITY);
-}
-
-static int unset_sysfile_activity(void)
-{
-       return unset_feature(FID_SYSFILE_ACTIVITY);
-}
-
-/**
- * @struct feature_item
- * @brief Struct that describes feature.
- * @var feature_item::name
- * Feature name.
- * @var feature_item::set
- * Set feature callback.
- * @var feature_item::unset
- * Unset feature callback.
- */
-struct feature_item {
-       char *name;
-       int (*set)(struct conf_data *conf);
-       int (*unset)(void);
-};
-
-static struct feature_item feature_us_inst = {
-       .name = "user space instrumentation",
-       .set = set_us_inst,
-       .unset = unset_us_inst
-};
-
-static struct feature_item feature_syscall_file = {
-       .name = "file operation syscalls",
-       .set = set_syscall_file,
-       .unset = unset_syscall_file
-};
-
-static struct feature_item feature_syscall_ipc = {
-       .name = "IPC syscall",
-       .set = set_syscall_ipc,
-       .unset = unset_syscall_ipc
-};
-
-static struct feature_item feature_syscall_process = {
-       .name = "process syscalls",
-       .set = set_syscall_process,
-       .unset = unset_syscall_process
-};
-
-static struct feature_item feature_syscall_signal = {
-       .name = "signal syscalls",
-       .set = set_syscall_signal,
-       .unset = unset_syscall_signal
-};
-
-static struct feature_item feature_syscall_network = {
-       .name = "network syscalls",
-       .set = set_syscall_network,
-       .unset = unset_syscall_network
-};
-
-static struct feature_item feature_syscall_desc = {
-       .name = "descriptor syscalls",
-       .set = set_syscall_desc,
-       .unset = unset_syscall_desc
-};
-
-static struct feature_item feature_context_switch = {
-       .name = "context switch",
-       .set = set_context_switch,
-       .unset = unset_context_switch
-};
-
-static struct feature_item feature_func_sampling = {
-       .name = "function sampling",
-       .set = set_func_sampling,
-       .unset = unset_func_sampling
-};
-
-static struct feature_item feature_func_energy = {
-       .name = "energy",
-       .set = set_func_energy,
-       .unset = unset_func_energy
-};
-
-static struct feature_item feature_sysfile_activity = {
-       .name = "system file activity",
-       .set = set_sysfile_activity,
-       .unset = unset_sysfile_activity
-};
-
-static struct feature_item *feature_list[] = {
- /*  0 */      NULL,
- /*  1 */      NULL,
- /*  2 */      &feature_us_inst,
- /*  3 */      NULL,
- /*  4 */      NULL,
- /*  5 */      NULL,
- /*  6 */      NULL,
- /*  7 */      NULL,
- /*  8 */      NULL,
- /*  9 */      NULL,
- /* 10 */      &feature_syscall_file,
- /* 11 */      &feature_syscall_ipc,
- /* 12 */      &feature_syscall_process,
- /* 13 */      &feature_syscall_signal,
- /* 14 */      &feature_syscall_network,
- /* 15 */      &feature_syscall_desc,
- /* 16 */      &feature_context_switch,
- /* 17 */      NULL,
- /* 18 */      NULL,
- /* 19 */      &feature_func_sampling,
- /* 20 */      NULL,
- /* 21 */      NULL,
- /* 22 */      NULL,
- /* 23 */      NULL,
- /* 24 */      NULL,
- /* 25 */      NULL,
- /* 26 */      &feature_func_energy,
- /* 27 */      NULL,
- /* 28 */      NULL,
- /* 29 */      NULL,
- /* 30 */      NULL,
- /* 31 */      NULL,
- /* 32 */      NULL,
- /* 33 */      NULL,
- /* 34 */      NULL,
- /* 35 */      NULL,
- /* 36 */      NULL,
- /* 37 */      NULL,
- /* 38 */      NULL,
- /* 39 */      NULL,
- /* 40 */      NULL,
- /* 41 */      NULL,
- /* 42 */      NULL,
- /* 43 */      NULL,
- /* 44 */      NULL,
- /* 45 */      NULL,
- /* 46 */      NULL,
- /* 47 */      NULL,
- /* 48 */      &feature_sysfile_activity,
-};
-
-/**
- * @brief SIZE_FEATURE_LIST definition.
- */
-enum {
-       SIZE_FEATURE_LIST =
-       sizeof(feature_list) / sizeof(struct feature_item *),
-};
-
-static u64 feature_inst;
-static u64 feature_mask;
-
-/**
- * @brief Inits features list.
- *
- * @return 0.
- */
-int once_features(void)
-{
-       int i;
-       for (i = 0; i < SIZE_FEATURE_LIST; ++i) {
-               printk(KERN_INFO "### f init_feature_mask[%2d]=%p\n", i,
-                      feature_list[i]);
-               if (feature_list[i] != NULL) {
-                       feature_mask |= ((u64)1) << i;
-                       printk(KERN_INFO "### f name=%s\n",
-                              feature_list[i]->name);
-               }
-       }
-
-       return 0;
-}
-
-static int do_set_features(struct conf_data *conf)
-{
-       int i, ret;
-       u64 feature_XOR;
-       u64 features, features_backup;
-
-       /* TODO: field use_features1 is not used*/
-       features_backup = features = conf->use_features0;
-
-       features &= feature_mask;
-       feature_XOR = features ^ feature_inst;
-
-       for (i = 0; feature_XOR && i < SIZE_FEATURE_LIST; ++i) {
-               if ((feature_XOR & 1) && feature_list[i] != NULL) {
-                       u64 f_mask;
-                       if (features & 1)
-                               ret = feature_list[i]->set(conf);
-                       else
-                               ret = feature_list[i]->unset();
-
-                       if (ret) {
-                               char *func = features & 1 ? "set" : "unset";
-                               print_err("%s '%s' ret=%d\n",
-                                         func, feature_list[i]->name, ret);
-
-                               return ret;
-                       }
-                       f_mask = ~((u64)1 << i);
-                       feature_inst = (feature_inst & f_mask) |
-                                      (features_backup & ~f_mask);
-               }
-
-               features >>= 1;
-               feature_XOR >>= 1;
-       }
-
-       return 0;
-}
-
-static DEFINE_MUTEX(mutex_features);
-
-/**
- * @brief Wrapper for do_set_features with locking.
- *
- * @param conf Pointer to the current config.
- * @return do_set_features result.
- */
-int set_features(struct conf_data *conf)
-{
-       int ret;
-
-       mutex_lock(&mutex_features);
-       ret = do_set_features(conf);
-       mutex_unlock(&mutex_features);
-
-       return ret;
-}
-
-void disable_all_features(void)
-{
-       struct conf_data conf;
-
-       conf.use_features0 = 0;
-       conf.use_features1 = 0;
-       conf.data_msg_period = 0;
-       conf.sys_trace_period = 0;
-
-       BUG_ON(set_features(&conf));
-       BUG_ON(feature_inst);
-}
diff --git a/parser/features.h b/parser/features.h
deleted file mode 100644 (file)
index 09b7b09..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @file parser/features.h
- * @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
- *
- * Features control interface declaration.
- */
-
-
-#ifndef _FEATURES_H
-#define _FEATURES_H
-
-struct conf_data;
-
-int once_features(void);
-
-int set_features(struct conf_data *conf);
-void disable_all_features(void);
-
-#endif /* _FEATURES_H */
diff --git a/parser/msg_buf.c b/parser/msg_buf.c
deleted file mode 100644 (file)
index cdaf044..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * parser/msg_buf.c
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov
- *
- * @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
- *
- * Message buffer controls implementation.
- */
-
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "msg_buf.h"
-#include "parser_defs.h"
-
-/**
- * @brief Initializes message buffer.
- *
- * @param mb Pointer to message buffer struct.
- * @param size Size of the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int init_mb(struct msg_buf *mb, size_t size)
-{
-       if (size) {
-               mb->begin = vmalloc(size);
-               if (mb->begin == NULL) {
-                       printk(KERN_INFO "Cannot alloc memory!\n");
-                       return -ENOMEM;
-               }
-
-               mb->ptr = mb->begin;
-               mb->end = mb->begin + size;
-       } else
-               mb->begin = mb->end = mb->ptr = NULL;
-
-       return 0;
-}
-
-/**
- * @brief Uninitializes message buffer.
- *
- * @param mb Pointer to message buffer struct.
- * @return Void.
- */
-void uninit_mb(struct msg_buf *mb)
-{
-       vfree(mb->begin);
-}
-
-/**
- * @brief Checks if current buffer data pointer is at the end.
- *
- * @param mb Pointer to the message buffer struct.
- * @param size Size of the message buffer.
- * @return 1 - buffer ptr is not at the end,
- * 0 - buffer ptr is at the end,
- * -1 - buffer ptr is invalid (far away of the end).
- */
-int cmp_mb(struct msg_buf *mb, size_t size)
-{
-       char *tmp;
-
-       tmp = mb->ptr + size;
-       if (mb->end > tmp)
-               return 1;
-       else if (mb->end < tmp)
-               return -1;
-
-       return 0;
-}
-
-/**
- * @brief Gets remainder part of message buffer.
- *
- * @param mb Pointer to the message buffer struct.
- * @return Remainder part of message buffer.
- */
-size_t remained_mb(struct msg_buf *mb)
-{
-       return mb->end - mb->ptr;
-}
-
-/**
- * @brief Checks whether we reached the end of the message buffer or not.
- *
- * @param mb Pointer to the message buffer struct.
- * @return 1 - if message buffer end has been reached \n
- * 0 - otherwise.
- */
-int is_end_mb(struct msg_buf *mb)
-{
-       return mb->ptr == mb->end;
-}
-
-/**
- * @brief Reads 8 bits from message buffer and updates buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param val Pointer to the target variable where to put read value.
- * @return 0 on success, negative error code on error.
- */
-int get_u8(struct msg_buf *mb, u8 *val)
-{
-       if (cmp_mb(mb, sizeof(*val)) < 0)
-               return -EINVAL;
-
-       *val = *((u8 *)mb->ptr);
-       mb->ptr += sizeof(*val);
-
-       print_parse_debug("u8 ->%d;%08X\n", *val, *val);
-
-       return 0;
-}
-
-/**
- * @brief Reads 32 bits from message buffer and updates buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param val Pointer to the target variable where to put read value.
- * @return 0 on success, negative error code on error.
- */
-int get_u32(struct msg_buf *mb, u32 *val)
-{
-       if (cmp_mb(mb, sizeof(*val)) < 0)
-               return -EINVAL;
-
-       *val = *((u32 *)mb->ptr);
-       mb->ptr += sizeof(*val);
-
-       print_parse_debug("u32->%d;%08X\n", *val, *val);
-
-       return 0;
-}
-
-/**
- * @brief Reads 64 bits from message buffer and updates buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param val Pointer to the target variable where to put read value.
- * @return 0 on success, negative error code on error.
- */
-int get_u64(struct msg_buf *mb, u64 *val)
-{
-       if (cmp_mb(mb, sizeof(*val)) < 0)
-               return -EINVAL;
-
-       *val = *((u64 *)mb->ptr);
-       mb->ptr += sizeof(*val);
-       print_parse_debug("u64->%llu; 0x%016llX\n", *val, *val);
-
-       return 0;
-}
-
-/**
- * @brief Reads null-terminated string from message buffer and updates
- * buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param str Pointer to the target variable where to put read string.
- * @return 0 on success, negative error code on error.
- */
-int get_string(struct msg_buf *mb, char **str)
-{
-       size_t len, len_max;
-       enum { min_len_str = 1 };
-
-       if (cmp_mb(mb, min_len_str) < 0)
-               return -EINVAL;
-
-       len_max = remained_mb(mb) - 1;
-       len = strnlen(mb->ptr, len_max);
-
-       *str = kmalloc(len + 1, GFP_KERNEL);
-       if (*str == NULL)
-               return -ENOMEM;
-
-       memcpy(*str, mb->ptr, len);
-       (*str)[len] = '\0';
-
-       mb->ptr += len + 1;
-
-       print_parse_debug("str->'%s'\n", *str);
-       return 0;
-}
-
-/**
- * @brief Releases string memory allocated in get_string.
- *
- * @param str Pointer to the target string.
- * @return Void.
- */
-void put_string(const char *str)
-{
-       kfree(str);
-}
diff --git a/parser/msg_buf.h b/parser/msg_buf.h
deleted file mode 100644 (file)
index 14a5713..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @file parser/msg_buf.h
- * @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
- *
- * Message buffer interface declaration.
- */
-
-
-#ifndef _MSG_BUF_H
-#define _MSG_BUF_H
-
-#include <linux/types.h>
-
-/**
- * @struct msg_buf
- * @brief Stores pointers to the message buffer.
- */
-struct msg_buf {
-       char *begin;    /**< Pointer to the beginning of the buffer. */
-       char *end;      /**< Pointer to the end of the buffer. */
-       char *ptr;      /**< Buffer iterator. */
-};
-
-int init_mb(struct msg_buf *mb, size_t size);
-void uninit_mb(struct msg_buf *mb);
-
-int cmp_mb(struct msg_buf *mb, size_t size);
-size_t remained_mb(struct msg_buf *mb);
-int is_end_mb(struct msg_buf *mb);
-
-int get_u8(struct msg_buf *mb, u8 *val);
-int get_u32(struct msg_buf *mb, u32 *val);
-int get_u64(struct msg_buf *mb, u64 *val);
-
-int get_string(struct msg_buf *mb, char **str);
-void put_string(const char *str);
-
-#endif /* _MSG_BUF_H */
diff --git a/parser/msg_cmd.c b/parser/msg_cmd.c
deleted file mode 100644 (file)
index 3572345..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/**
- * parser/msg_cmd.c
- * @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
- *
- * Module's messages parsing implementation.
- */
-
-
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include "msg_parser.h"
-#include "msg_buf.h"
-#include "features.h"
-#include "parser_defs.h"
-#include "us_inst.h"
-#include <writer/swap_msg.h>
-#include <us_manager/us_manager.h>
-
-
-static int wrt_launcher_port;
-
-static int set_config(struct conf_data *conf)
-{
-       int ret;
-
-       ret = set_features(conf);
-
-       return ret;
-}
-
-/**
- * @brief Message "keep alive" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_keep_alive(struct msg_buf *mb)
-{
-       if (!is_end_mb(mb)) {
-               print_err("to long message, remained=%zu", remained_mb(mb));
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Message "start" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_start(struct msg_buf *mb)
-{
-       int ret = 0;
-       struct conf_data conf;
-       LIST_HEAD(app_head);
-
-       swap_msg_seq_num_reset();
-       swap_msg_discard_reset();
-
-       if (!create_us_inst_data(mb, &app_head))
-               return -EINVAL;
-
-       if (!is_end_mb(mb)) {
-               pr_info("Too long message, remained=%zu", remained_mb(mb));
-               destroy_us_inst_data(&app_head);
-               return -EINVAL;
-       }
-
-       ret = app_list_reg(&app_head);
-       if (ret) {
-               pr_info("Cannot mod us inst, ret = %d\n", ret);
-               return ret;
-       }
-
-       ret = usm_start();
-       if (ret) {
-               app_list_unreg_all();
-               return ret;
-       }
-
-       restore_config(&conf);
-       set_config(&conf);
-
-       return 0;
-}
-
-/**
- * @brief Message "stop" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_stop(struct msg_buf *mb)
-{
-       int ret = 0;
-       int discarded;
-
-       if (!is_end_mb(mb)) {
-               print_err("to long message, remained=%zu", remained_mb(mb));
-               return -EINVAL;
-       }
-
-       ret = usm_stop();
-       if (ret)
-               return ret;
-
-       app_list_unreg_all();
-       disable_all_features();
-
-       discarded = swap_msg_discard_get();
-       printk(KERN_INFO "discarded messages: %d\n", discarded);
-       swap_msg_discard_reset();
-
-       return ret;
-}
-
-/**
- * @brief Message "config" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_config(struct msg_buf *mb)
-{
-       int ret = 0;
-       struct conf_data *conf;
-       enum status_type st;
-
-       conf = create_conf_data(mb);
-       if (conf == NULL)
-               return -EINVAL;
-
-       if (!is_end_mb(mb)) {
-               print_err("to long message, remained=%zu", remained_mb(mb));
-               ret = -EINVAL;
-               goto free_conf_data;
-       }
-
-       st = usm_get_status();
-       if (st == ST_ON)
-               set_config(conf);
-
-       save_config(conf);
-       usm_put_status(st);
-
-free_conf_data:
-       destroy_conf_data(conf);
-
-       return ret;
-}
-
-/**
- * @brief Message "swap inst add" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_swap_inst_add(struct msg_buf *mb)
-{
-       LIST_HEAD(app_head);
-
-       if (!create_us_inst_data(mb, &app_head))
-               return -EINVAL;
-
-       if (!is_end_mb(mb)) {
-               pr_info("Too long message, remained=%zu", remained_mb(mb));
-               destroy_us_inst_data(&app_head);
-               return -EINVAL;
-       }
-
-       return app_list_reg(&app_head);
-}
-
-/**
- * @brief Message "swap inst remove" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_swap_inst_remove(struct msg_buf *mb)
-{
-       LIST_HEAD(app_head);
-
-       INIT_LIST_HEAD(&app_head);
-       if (!create_us_inst_data(mb, &app_head))
-               return -EINVAL;
-
-       if (!is_end_mb(mb)) {
-               pr_info("Too long message, remained=%zu", remained_mb(mb));
-               destroy_us_inst_data(&app_head);
-               return -EINVAL;
-       }
-
-       return app_list_unreg(&app_head);
-}
-
-void set_wrt_launcher_port(int port)
-{
-       wrt_launcher_port = port;
-}
-EXPORT_SYMBOL_GPL(set_wrt_launcher_port);
-
-#define GET_PORT_DELAY         100     /* msec */
-#define GET_PORT_TIMEOUT       10000   /* msec */
-
-int get_wrt_launcher_port(void)
-{
-       int port;
-       int timeout = GET_PORT_TIMEOUT;
-
-       do {
-               port = wrt_launcher_port;
-               timeout -= GET_PORT_DELAY;
-               mdelay(GET_PORT_DELAY);
-       } while (!port && timeout > 0);
-
-       set_wrt_launcher_port(0);
-
-       return port;
-}
-
-/**
- * @brief Initializes commands handling.
- *
- * @return Initialization results.
- */
-int once_cmd(void)
-{
-       return once_features();
-}
diff --git a/parser/msg_cmd.h b/parser/msg_cmd.h
deleted file mode 100644 (file)
index e078169..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @file parser/msg_cmd.h
- * @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
- *
- * Module's message handling interface declaration.
- */
-
-#ifndef _MSG_CMD_H
-#define _MSG_CMD_H
-
-struct msg_buf;
-
-int once_cmd(void);
-
-int msg_keep_alive(struct msg_buf *mb);
-int msg_start(struct msg_buf *mb);
-int msg_stop(struct msg_buf *mb);
-int msg_config(struct msg_buf *mb);
-int msg_swap_inst_add(struct msg_buf *mb);
-int msg_swap_inst_remove(struct msg_buf *mb);
-int get_wrt_launcher_port(void);
-void set_wrt_launcher_port(int port);
-
-#endif /* _MSG_CMD_H */
diff --git a/parser/msg_parser.c b/parser/msg_parser.c
deleted file mode 100644 (file)
index 285da4d..0000000
+++ /dev/null
@@ -1,1100 +0,0 @@
-/**
- * parser/msg_parser.c
- *
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @sectionLICENSE
- *
- * 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
- *
- * Message parsing implementation.
- */
-
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <us_manager/probes/probes.h>
-#include "msg_parser.h"
-#include "msg_buf.h"
-#include "parser_defs.h"
-
-/* ============================================================================
- * ==                               APP_INFO                                 ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills pr_app_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param ai Pointer to the target app_inst_data.
- * @return 0 on success, error code on error.
- */
-struct pr_app_info *pr_app_info_create(struct msg_buf *mb)
-{
-       int ret;
-       struct pr_app_info *app_info;
-       u32 app_type;
-       char *str_id, *exec_path;
-
-       app_info = kmalloc(sizeof(*app_info), GFP_KERNEL);
-       if (!app_info)
-               return ERR_PTR(-ENOMEM);
-
-       print_parse_debug("app_info:\n");
-       print_parse_debug("type:");
-       ret = get_u32(mb, &app_type);
-       if (ret) {
-               print_err("failed to read target application type\n");
-               goto free_app_info;
-       }
-
-       print_parse_debug("id:");
-       ret = get_string(mb, &str_id);
-       if (ret) {
-               print_err("failed to read target application ID\n");
-               goto free_app_info;
-       }
-
-       print_parse_debug("exec path:");
-       ret = get_string(mb, &exec_path);
-       if (ret) {
-               print_err("failed to read executable path\n");
-               goto free_id;
-       }
-
-       switch (app_type) {
-       case AT_TIZEN_NATIVE_APP:
-       case AT_TIZEN_WEB_APP:
-       case AT_COMMON_EXEC:
-               app_info->tgid = 0;
-               break;
-       case AT_PID: {
-               u32 tgid = 0;
-
-               if (*str_id != '\0') {
-                       ret = kstrtou32(str_id, 10, &tgid);
-                       if (ret) {
-                               print_err("converting string to PID, "
-                                         "str='%s'\n", str_id);
-                               goto free_exec_path;
-                       }
-               }
-
-               app_info->tgid = tgid;
-               break;
-       }
-       default:
-               print_err("wrong application type(%u)\n", app_type);
-               ret = -EINVAL;
-               goto free_exec_path;
-       }
-
-       app_info->type = (enum APP_TYPE)app_type;
-       app_info->id = str_id;
-       app_info->path = exec_path;
-
-       return app_info;
-
-free_exec_path:
-       put_string(exec_path);
-free_id:
-       put_string(str_id);
-free_app_info:
-       kfree(app_info);
-       return ERR_PTR(ret);
-}
-
-void pr_app_info_free(struct pr_app_info *app_info)
-{
-       put_string(app_info->path);
-       put_string(app_info->id);
-       kfree(app_info);
-}
-
-int pr_app_info_cmp(struct pr_app_info *app0, struct pr_app_info *app1)
-{
-       print_parse_debug("app0: %d, %d, %s, %s\n",
-                         app0->type, app0->tgid, app0->id, app0->path);
-
-       print_parse_debug("app1: %d, %d, %s, %s\n",
-                         app1->type, app1->tgid, app1->id, app1->path);
-
-       if ((app0->type == app1->type) &&
-           (app0->tgid == app1->tgid) &&
-           !strcmp(app0->id, app1->id) &&
-           !strcmp(app0->path, app1->path)) {
-               return 0;
-       }
-
-       return 1;
-}
-
-
-
-/* ============================================================================
- * ==                                CONFIG                                  ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills conf_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled conf_data struct on success;\n
- * NULL on error.
- */
-struct conf_data *create_conf_data(struct msg_buf *mb)
-{
-       struct conf_data *conf;
-       u64 use_features0, use_features1;
-       u32 stp, dmp;
-
-       print_parse_debug("conf_data:\n");
-
-       print_parse_debug("features:");
-       if (get_u64(mb, &use_features0)) {
-               print_err("failed to read use_features\n");
-               return NULL;
-       }
-
-       if (get_u64(mb, &use_features1)) {
-               print_err("failed to read use_features\n");
-               return NULL;
-       }
-
-       print_parse_debug("sys trace period:");
-       if (get_u32(mb, &stp)) {
-               print_err("failed to read sys trace period\n");
-               return NULL;
-       }
-
-       print_parse_debug("data msg period:");
-       if (get_u32(mb, &dmp)) {
-               print_err("failed to read data message period\n");
-               return NULL;
-       }
-
-       conf = kmalloc(sizeof(*conf), GFP_KERNEL);
-       if (conf == NULL) {
-               print_err("out of memory\n");
-               return NULL;
-       }
-
-       conf->use_features0 = use_features0;
-       conf->use_features1 = use_features1;
-       conf->sys_trace_period = stp;
-       conf->data_msg_period = dmp;
-
-       return conf;
-}
-
-/**
- * @brief conf_data cleanup.
- *
- * @param conf Pointer to the target conf_data.
- * @return Void.
- */
-void destroy_conf_data(struct conf_data *conf)
-{
-       kfree(conf);
-}
-
-static struct conf_data config;
-
-/**
- * @brief Saves config to static config variable.
- *
- * @param conf Variable to save.
- * @return Void.
- */
-void save_config(const struct conf_data *conf)
-{
-       memcpy(&config, conf, sizeof(config));
-}
-
-/**
- * @brief Restores config from static config variable.
- *
- * @param conf Variable to restore.
- * @return Void.
- */
-void restore_config(struct conf_data *conf)
-{
-       memcpy(conf, &config, sizeof(*conf));
-}
-
-
-
-/* ============================================================================
- * ==                             PROBES PARSING                             ==
- * ============================================================================
- */
-
-/**
- * @brief Gets retprobe data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pd Pointer to the probe_desc struct.
- * @return 0 on success, error code on error.
- */
-int get_retprobe(struct msg_buf *mb, struct probe_desc *pd)
-{
-       char *args;
-       char ret_type;
-
-       print_parse_debug("funct args:");
-       if (get_string(mb, &args)) {
-               print_err("failed to read data function arguments\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("funct ret type:");
-       if (get_u8(mb, (u8 *)&ret_type)) {
-               print_err("failed to read data function arguments\n");
-               goto free_args;
-       }
-
-       pd->type = SWAP_RETPROBE;
-       pd->info.rp_i.args = args;
-       pd->info.rp_i.ret_type = ret_type;
-
-       return 0;
-
-free_args:
-       put_string(args);
-       return -EINVAL;
-}
-
-/**
- * @brief Retprobe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_retprobe(struct probe_info *pi)
-{
-       put_string(pi->rp_i.args);
-}
-
-static int cmp_retprobe(struct probe_info *p0, struct probe_info *p1)
-{
-       if (p0->rp_i.ret_type == p1->rp_i.ret_type &&
-           !strcmp(p0->rp_i.args, p1->rp_i.args)) {
-               return 0;
-       }
-
-       return 1;
-}
-
-/**
- * @brief Gets preload data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pd Pointer to the probe_desc struct.
- * @return 0 on success, error code on error.
- */
-int get_preload_probe(struct msg_buf *mb, struct probe_desc *pd)
-{
-       u64 handler;
-       u8 flags;
-       char *path;
-
-       print_parse_debug("funct handler:");
-       if (get_u64(mb, &handler)) {
-               print_err("failed to read function handler\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("collect events flag:");
-       if (get_u8(mb, &flags)) {
-               print_err("failed to read collect events type\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("handler library:");
-       if (get_string(mb, &path)) {
-               print_err("failed to read handler library path\n");
-               return -EINVAL;
-       }
-
-       pd->type = SWAP_PRELOAD_PROBE;
-       pd->info.pl_i.handler = handler;
-       pd->info.pl_i.flags = flags;
-       pd->info.pl_i.path = path;
-
-       return 0;
-}
-
-/**
- * @brief Preload probe data cleanup.
- *
- * @param pi Pointer to the probe_info struct.
- * @return Void.
- */
-void put_preload_probe(struct probe_info *pi)
-{
-       put_string((char *)pi->pl_i.path);
-}
-
-static int cmp_preload_probe(struct probe_info *p0, struct probe_info *p1)
-{
-       if (p0->pl_i.handler == p1->pl_i.handler &&
-           p0->pl_i.flags == p1->pl_i.flags) {
-               return 0;
-       }
-
-       return 1;
-}
-
-/**
- * @brief Gets preload get_caller and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pd Pointer to the probe_desc struct.
- * @return 0 on success, error code on error.
- */
-
-int get_get_caller_probe(struct msg_buf *mb, struct probe_desc *pd)
-{
-       pd->type = SWAP_GET_CALLER;
-
-       return 0;
-}
-
-/**
- * @brief Preload get_caller probe data cleanup.
- *
- * @param pi Pointer to the probe_info struct.
- * @return Void.
- */
-void put_get_caller_probe(struct probe_info *pi)
-{
-}
-
-static int cmp_get_caller_probe(struct probe_info *p0, struct probe_info *p1)
-{
-       return 0;
-}
-
-/**
- * @brief Gets preload get_call_type and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pd Pointer to the probe_desc struct.
- * @return 0 on success, error code on error.
- */
-int get_get_call_type_probe(struct msg_buf *mb, struct probe_desc *pd)
-{
-       pd->type = SWAP_GET_CALL_TYPE;
-
-       return 0;
-}
-
-/**
- * @brief Preload get_call type probe data cleanup.
- *
- * @param pi Pointer to the probe_info struct.
- * @return Void.
- */
-void put_get_call_type_probe(struct probe_info *pi)
-{
-}
-
-static int cmp_get_caller_type_probe(struct probe_info *p0,
-                                    struct probe_info *p1)
-{
-       return 0;
-}
-
-/**
- * @brief Gets preload write_msg and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_write_msg_probe(struct msg_buf *mb, struct probe_desc *pd)
-{
-       pd->type = SWAP_WRITE_MSG;
-
-       return 0;
-}
-
-/**
- * @brief Preload write_msg type probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_write_msg_probe(struct probe_info *pi)
-{
-}
-
-static int cmp_write_msg_probe(struct probe_info *p0, struct probe_info *p1)
-{
-       return 0;
-}
-
-/**
- * @brief Gets FBI probe data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_fbi_data(struct msg_buf *mb, struct fbi_var_data *vd)
-{
-       u64 var_id;
-       u64 reg_offset;
-       u8 reg_n;
-       u32 data_size;
-       u8 steps_count, i;
-       struct fbi_step *steps = NULL;
-
-       print_parse_debug("var ID:");
-       if (get_u64(mb, &var_id)) {
-               print_err("failed to read var ID\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("register offset:");
-       if (get_u64(mb, &reg_offset)) {
-               print_err("failed to read register offset\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("register number:");
-       if (get_u8(mb, &reg_n)) {
-               print_err("failed to read number of the register\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("data size:");
-       if (get_u32(mb, &data_size)) {
-               print_err("failed to read data size\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("steps count:");
-       if (get_u8(mb, &steps_count)) {
-               print_err("failed to read steps count\n");
-               return -EINVAL;
-       }
-
-       if (steps_count > 0) {
-               steps = kmalloc(steps_count * sizeof(*vd->steps),
-                               GFP_KERNEL);
-               if (steps == NULL) {
-                       print_err("MALLOC FAIL\n");
-                       return -ENOMEM;
-               }
-
-               for (i = 0; i != steps_count; i++) {
-                       print_parse_debug("steps #%d ptr_order:", i);
-                       if (get_u8(mb, &(steps[i].ptr_order))) {
-                               print_err("failed to read pointer order(step #%d)\n",
-                                         i);
-                               goto free_steps;
-                       }
-                       print_parse_debug("steps #%d data_offset:", i);
-                       if (get_u64(mb, &(steps[i].data_offset))){
-                               print_err("failed to read offset (steps #%d)\n",
-                                         i);
-                               goto free_steps;
-                       }
-               }
-       }
-
-       vd->reg_n = reg_n;
-       vd->reg_offset = reg_offset;
-       vd->data_size = data_size;
-       vd->var_id = var_id;
-       vd->steps_count = steps_count;
-       vd->steps = steps;
-
-       return 0;
-
-free_steps:
-       kfree(steps);
-       return -EINVAL;
-}
-
-int get_fbi_probe(struct msg_buf *mb, struct probe_desc *pd)
-{
-       uint8_t var_count, i;
-       struct fbi_var_data *vars;
-
-       print_parse_debug("var count:");
-       if (get_u8(mb, &var_count)) {
-               print_err("failed to read var ID\n");
-               return -EINVAL;
-       }
-
-       vars = kmalloc(var_count * sizeof(*vars), GFP_KERNEL);
-       if (vars == NULL) {
-               print_err("alloc vars error\n");
-               goto err;
-       }
-
-       for (i = 0; i != var_count; i++) {
-               if (get_fbi_data(mb, &vars[i]) != 0)
-                       goto free_vars;
-       }
-
-       pd->type = SWAP_FBIPROBE;
-       pd->info.fbi_i.var_count = var_count;
-       pd->info.fbi_i.vars = vars;
-       return 0;
-
-free_vars:
-       kfree(vars);
-
-err:
-       return -EINVAL;
-
-}
-
-/**
- * @brief FBI probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising FBI probe.
- * @return Void.
- */
-void put_fbi_probe(struct probe_info *pi)
-{
-       /* FIXME: memory leak (vars) */
-       return;
-}
-
-static int cmp_fbi_probe(struct probe_info *p0, struct probe_info *p1)
-{
-       /* TODO: to implement */
-       return 0;
-}
-
-
-/* ============================================================================
- * ==                                 PROBE                                  ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills func_inst_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled func_inst_data struct on success;\n
- * 0 on error.
- */
-struct pr_probe_desc *pr_probe_desc_create(struct msg_buf *mb)
-{
-       int ret = -EINVAL;
-       struct pr_probe_desc *probe;
-       int (*get_probe)(struct msg_buf *mb, struct probe_desc *pd);
-       u64 addr;
-       u8 type;
-
-       print_parse_debug("func addr:");
-       if (get_u64(mb, &addr)) {
-               print_err("failed to read data function address\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       print_parse_debug("probe type:");
-       if (get_u8(mb, &type)) {
-               print_err("failed to read data probe type\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       probe = kmalloc(sizeof(*probe), GFP_KERNEL);
-       if (!probe) {
-               print_err("out of memory\n");
-               return ERR_PTR(-ENOMEM);
-       }
-       INIT_LIST_HEAD(&probe->list);
-
-       switch (type) {
-       case SWAP_RETPROBE:
-               get_probe = get_retprobe;
-               break;
-       case SWAP_PRELOAD_PROBE:
-               get_probe = get_preload_probe;
-               break;
-       case SWAP_GET_CALLER:
-               get_probe = get_get_caller_probe;
-               break;
-       case SWAP_GET_CALL_TYPE:
-               get_probe = get_get_call_type_probe;
-               break;
-       case SWAP_FBIPROBE:
-               get_probe = get_fbi_probe;
-               break;
-       case SWAP_WRITE_MSG:
-               get_probe = get_write_msg_probe;
-               break;
-       default:
-               printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n",
-                      type);
-               ret = -EINVAL;
-               goto err;
-       }
-
-       ret = get_probe(mb, &probe->p_desc);
-       if (ret)
-               goto err;
-
-       probe->addr = addr;
-       return probe;
-
-err:
-       kfree(probe);
-       return ERR_PTR(ret);
-}
-
-
-/**
- * @brief func_inst_data cleanup.
- *
- * @param fi Pointer to the target func_inst_data.
- * @return Void.
- */
-void pr_probe_desc_free(struct pr_probe_desc *probe)
-{
-       switch (probe->p_desc.type) {
-       case SWAP_RETPROBE:
-               put_retprobe(&(probe->p_desc.info));
-               break;
-       case SWAP_PRELOAD_PROBE:
-               put_preload_probe(&(probe->p_desc.info));
-               break;
-       case SWAP_GET_CALLER:
-               put_get_caller_probe(&(probe->p_desc.info));
-               break;
-       case SWAP_GET_CALL_TYPE:
-               put_get_call_type_probe(&(probe->p_desc.info));
-               break;
-       case SWAP_FBIPROBE:
-               put_fbi_probe(&(probe->p_desc.info));
-               break;
-       case SWAP_WRITE_MSG:
-               put_write_msg_probe(&(probe->p_desc.info));
-               break;
-       default:
-               pr_err("SWAP PARSER: Wrong probe type %d!\n",
-                      probe->p_desc.type);
-       }
-
-       kfree(probe);
-}
-
-int probe_inst_info_cmp(struct pr_probe_desc *p0, struct pr_probe_desc *p1)
-{
-       enum probe_t type;
-       int (*cmp_probe)(struct probe_info *p0, struct probe_info *p1);
-
-       if (p0->addr != p1->addr &&
-           p0->p_desc.type != p1->p_desc.type)
-               return 1;
-
-       type = p0->p_desc.type;
-       switch (type) {
-       case SWAP_RETPROBE:
-               cmp_probe = cmp_retprobe;
-               break;
-       case SWAP_PRELOAD_PROBE:
-               cmp_probe = cmp_preload_probe;
-               break;
-       case SWAP_GET_CALLER:
-               cmp_probe = cmp_get_caller_probe;
-               break;
-       case SWAP_GET_CALL_TYPE:
-               cmp_probe = cmp_get_caller_type_probe;
-               break;
-       case SWAP_FBIPROBE:
-               cmp_probe = cmp_fbi_probe;
-               break;
-       case SWAP_WRITE_MSG:
-               cmp_probe = cmp_write_msg_probe;
-               break;
-       default:
-               pr_err("SWAP PARSER: Wrong probe type %d!\n", type);
-               return 1;
-       }
-
-       return cmp_probe(&p0->p_desc.info, &p1->p_desc.info);
-}
-
-static struct pr_bin_info *pr_bin_info_create(const char *path)
-{
-       struct pr_bin_info *info;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return ERR_PTR(-ENOMEM);
-
-       info->path = kstrdup(path, GFP_KERNEL);
-       if (!info->path) {
-               kfree(info);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       return info;
-}
-
-static void pr_bin_info_free(struct pr_bin_info *info)
-{
-       kfree(info->path);
-       kfree(info);
-}
-
-
-struct pr_bin_desc *pr_bin_desc_create(const char *path,
-                                      struct list_head *probe_list)
-{
-       struct pr_bin_desc *bin;
-
-       bin = kmalloc(sizeof(*bin), GFP_KERNEL);
-       if (!bin)
-               return ERR_PTR(-ENOMEM);
-
-       bin->info = pr_bin_info_create(path);
-       if (IS_ERR(bin->info)) {
-               long err = PTR_ERR(bin->info);
-
-               kfree(bin);
-               return ERR_PTR(err);
-       }
-
-       INIT_LIST_HEAD(&bin->list);
-       INIT_LIST_HEAD(&bin->probe_head);
-       list_splice_init(probe_list, &bin->probe_head);
-
-       return bin;
-}
-
-void pr_bin_desc_free(struct pr_bin_desc *bin)
-{
-       struct pr_probe_desc *p, *n;
-
-       list_for_each_entry_safe(p, n, &bin->probe_head, list) {
-               list_del(&p->list);
-               pr_probe_desc_free(p);
-       }
-
-       pr_bin_info_free(bin->info);
-       kfree(bin);
-}
-
-int pr_bin_info_cmp(struct pr_bin_info *b0, struct pr_bin_info *b1)
-{
-       return strcmp(b0->path, b1->path);
-}
-
-
-static void pr_probe_desc_list_free(struct list_head *head)
-{
-       struct pr_probe_desc *probe, *n;
-
-       list_for_each_entry_safe(probe, n, head, list) {
-               list_del(&probe->list);
-               pr_probe_desc_free(probe);
-       }
-}
-
-static int pr_probe_desc_list_create(struct msg_buf *mb, struct list_head *head)
-{
-       u32 i, cnt;
-
-       if (get_u32(mb, &cnt)) {
-               print_err("failed to read count of functions\n");
-               return -EINVAL;
-       }
-
-       print_parse_debug("probe count:%d", cnt);
-       if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) {
-               print_err("to match count of probes(%u)\n", cnt);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cnt; ++i) {
-               struct pr_probe_desc *probe;
-
-               print_parse_debug("probe #%d:\n", i + 1);
-               probe = pr_probe_desc_create(mb);
-               if (IS_ERR(probe)) {
-                       pr_probe_desc_list_free(head);
-                       return PTR_ERR(probe);
-               }
-
-               list_add(&probe->list, head);
-       }
-
-       return cnt;
-}
-
-
-struct pr_bin_desc *bin_info_by_lib(struct msg_buf *mb)
-{
-       u32 cnt;
-       char *path;
-       struct pr_bin_desc *bin = ERR_PTR(-EINVAL);
-
-       print_parse_debug("bin path:");
-       if (get_string(mb, &path)) {
-               print_err("failed to read path of binary\n");
-               return bin;
-       }
-
-       print_parse_debug("func count:");
-       if (get_u32(mb, &cnt)) {
-               print_err("failed to read count of functions\n");
-               goto free_path;
-       }
-
-       if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) {
-               print_err("to match count of functions(%u)\n", cnt);
-               goto free_path;
-       }
-
-       if (cnt) {
-               u32 i;
-               LIST_HEAD(probe_head);
-
-               for (i = 0; i < cnt; ++i) {
-                       struct pr_probe_desc *probe;
-                       print_parse_debug("func #%d:\n", i + 1);
-                       probe = pr_probe_desc_create(mb);
-                       if (IS_ERR(probe)) {
-                               /* set error to 'bin' */
-                               bin = ERR_PTR(PTR_ERR(probe));
-                               pr_probe_desc_list_free(&probe_head);
-                               goto free_path;
-                       }
-
-                       list_add(&probe->list, &probe_head);
-               }
-
-               bin = pr_bin_desc_create(path, &probe_head);
-               if (IS_ERR(bin))
-                       pr_probe_desc_list_free(&probe_head);
-       }
-
-free_path:
-       put_string(path);
-       return bin;
-}
-
-
-
-
-void bin_info_list_free(struct list_head *head)
-{
-       struct pr_bin_desc *bin, *n;
-
-       list_for_each_entry_safe(bin, n, head, list) {
-               list_del(&bin->list);
-               pr_bin_desc_free(bin);
-       }
-}
-
-int bin_info_list_create(struct msg_buf *mb, struct list_head *head)
-{
-       u32 i, cnt;
-
-       if (get_u32(mb, &cnt)) {
-               print_err("failed to read count of binaries\n");
-               return -EINVAL;
-       }
-       print_parse_debug("bin count:i%d", cnt);
-
-       if (remained_mb(mb) / MIN_SIZE_LIB_INST < cnt) {
-               print_err("to match count of binaries(%u)\n", cnt);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cnt; ++i) {
-               struct pr_bin_desc *bin;
-
-               print_parse_debug("bin #%d:\n", i_lib + 1);
-               bin = bin_info_by_lib(mb);
-               if (IS_ERR(bin)) {
-                       bin_info_list_free(head);
-                       return PTR_ERR(bin);
-               } else if (bin) {
-                       list_add(&bin->list, head);
-               }
-       }
-
-       return cnt;
-}
-
-
-/* ============================================================================
- * ==                                 APP                                    ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills pr_app_desc struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled app_inst_data struct on success;\n
- * 0 on error.
- */
-struct pr_app_desc *pr_app_desc_create(struct msg_buf *mb)
-{
-       int cnt_probe, cnt_bin, ret = -EINVAL;
-       struct pr_app_info *app_info;
-       struct pr_app_desc *app;
-       LIST_HEAD(probe_head);
-       LIST_HEAD(bin_head);
-
-       app = kmalloc(sizeof(*app), GFP_KERNEL);
-       if (!app) {
-               print_err("%s: Out of memory\n", __func__);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       app_info = pr_app_info_create(mb);
-       if (IS_ERR(app_info)) {
-               ret = PTR_ERR(app_info);
-               goto free_app_inst;
-       }
-
-       app->info = app_info;
-       app->pfg = NULL;
-       INIT_LIST_HEAD(&app->list);
-       INIT_LIST_HEAD(&app->bin_head);
-
-       cnt_probe = pr_probe_desc_list_create(mb, &probe_head);
-       if (cnt_probe < 0) {
-               ret = cnt_probe;
-               goto free_app_info;
-       } else if (cnt_probe) {
-               struct pr_bin_desc *bin;
-
-               bin = pr_bin_desc_create(app_info->path, &probe_head);
-               if (IS_ERR(bin)) {
-                       pr_probe_desc_list_free(&probe_head);
-                       ret = PTR_ERR(bin);
-                       goto free_app_info;
-               }
-
-               /* add pr_bin_desc */
-               list_add(&bin->list, &app->bin_head);
-       }
-
-       cnt_bin = bin_info_list_create(mb, &app->bin_head);
-       if (cnt_bin < 0) {
-               ret = cnt_bin;
-               goto free_bins;
-       }
-
-       return app;
-
-free_bins:
-       bin_info_list_free(&app->bin_head);
-free_app_info:
-       pr_app_info_free(app_info);
-free_app_inst:
-       kfree(app);
-       return ERR_PTR(ret);
-}
-
-/**
- * @brief pr_app_desc cleanup.
- *
- * @param ai Pointer to the target app_inst_data.
- * @return Void.
- */
-void pr_app_desc_free(struct pr_app_desc *app)
-{
-       bin_info_list_free(&app->bin_head);
-       pr_app_info_free(app->info);
-       kfree(app);
-}
-
-
-/* ============================================================================
- * ==                                US_INST                                 ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills us_inst_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @param head Pointer to the list head.
- * @return u32 count of created elements.
- */
-u32 create_us_inst_data(struct msg_buf *mb,
-                       struct list_head *head)
-{
-       u32 cnt, i;
-
-       print_parse_debug("us_inst_data:\n");
-
-       print_parse_debug("app count:");
-       if (get_u32(mb, &cnt)) {
-               print_err("failed to read count of applications\n");
-               return 0;
-       }
-
-       if (remained_mb(mb) / MIN_SIZE_APP_INST < cnt) {
-               print_err("to match count of applications(%u)\n", cnt);
-               return 0;
-       }
-
-       for (i = 0; i < cnt; ++i) {
-               struct pr_app_desc *app;
-
-               print_parse_debug("app #%d:\n", i + 1);
-               app = pr_app_desc_create(mb);
-               if (IS_ERR(app))
-                       goto err;
-
-               list_add_tail(&app->list, head);
-       }
-
-       return cnt;
-
-err:
-       destroy_us_inst_data(head);
-       return 0;
-}
-
-/**
- * @brief us_inst_data cleanup.
- *
- * @param head Pointer to the list head.
- * @return Void.
- */
-void destroy_us_inst_data(struct list_head *head)
-{
-       struct pr_app_desc *app, *n;
-
-       list_for_each_entry_safe(app, n, head, list) {
-               list_del(&app->list);
-               pr_app_desc_free(app);
-       }
-}
diff --git a/parser/msg_parser.h b/parser/msg_parser.h
deleted file mode 100644 (file)
index 9620e65..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * @file parser/msg_parser.h
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov
- *
- * @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
- *
- * Message parsing interface declaration.
- */
-
-
-#ifndef _MSG_PARSER_H
-#define _MSG_PARSER_H
-
-#include <linux/types.h>
-#include <us_manager/probes/probes.h>
-
-struct img_ip;
-struct msg_buf;
-
-/**
- * @enum APP_TYPE
- * Supported application types.
- */
-enum APP_TYPE {
-       AT_TIZEN_NATIVE_APP     = 0x01,     /**< Tizen native application. */
-       AT_PID                  = 0x02,         /**< App with specified PID. */
-       AT_COMMON_EXEC          = 0x03,     /**< Common application. */
-       AT_TIZEN_WEB_APP        = 0x04      /**< Tizen web application. */
-};
-
-/**
- * @brief App type size defenition.
- */
-enum {
-       SIZE_APP_TYPE = 4
-};
-
-/**
- * @struct conf_data
- * @brief Configuration struct.
- */
-struct conf_data {
-       u64 use_features0;          /**< Feature flags. */
-       u64 use_features1;          /**< Feature flags. */
-       u32 sys_trace_period;       /**< Trace period. */
-       u32 data_msg_period;        /**< Data message period. */
-};
-
-/**
- * @brief The pr_app_info struct
- */
-struct pr_app_info {
-       enum APP_TYPE type;     /**< Application type. */
-       pid_t tgid;             /**< Application PID. */
-       char *id;               /**< Application ID */
-       char *path;             /**< Application execution path. */
-};
-
-/**
- * @brief The pr_bin_info struct
- */
-struct pr_bin_info {
-       char *path;
-};
-
-/**
- * @brief The pr_app_desc struct
- */
-struct pr_app_desc {
-       struct list_head list;
-
-       struct pr_app_info *info;
-       struct pf_group *pfg;
-       struct list_head bin_head;
-};
-
-/**
- * @brief The pr_bin_desc struct
- */
-struct pr_bin_desc {
-       struct list_head list;
-
-       struct pr_bin_info *info;
-
-       struct list_head probe_head;
-};
-
-struct pr_probe_desc {
-       struct list_head list;
-
-       /* register info */
-       u64 addr;
-       struct probe_desc p_desc;
-
-       /* unregister info */
-       struct img_ip *ip;
-};
-
-
-struct pr_app_info *pr_app_info_create(struct msg_buf *mb);
-void pr_app_info_free(struct pr_app_info *app_info);
-int pr_app_info_cmp(struct pr_app_info *app0, struct pr_app_info *app1);
-
-struct pr_bin_desc *pr_bin_desc_create(const char *path,
-                                      struct list_head *probe_list);
-void pr_bin_desc_free(struct pr_bin_desc *bin);
-
-int pr_bin_info_cmp(struct pr_bin_info *b0, struct pr_bin_info *b1);
-
-struct pr_probe_desc *pr_probe_desc_create(struct msg_buf *mb);
-void pr_probe_desc_free(struct pr_probe_desc *probe_info);
-int probe_inst_info_cmp(struct pr_probe_desc *p0, struct pr_probe_desc *p1);
-
-struct conf_data *create_conf_data(struct msg_buf *mb);
-void destroy_conf_data(struct conf_data *conf);
-
-void save_config(const struct conf_data *conf);
-void restore_config(struct conf_data *conf);
-
-struct pr_app_desc *pr_app_desc_create(struct msg_buf *mb);
-void pr_app_desc_free(struct pr_app_desc *app);
-
-u32 create_us_inst_data(struct msg_buf *mb, struct list_head *head);
-void destroy_us_inst_data(struct list_head *head);
-
-
-/**
- * @brief Constant defenitions.
- */
-enum {
-       MIN_SIZE_STRING = 1,
-       MIN_SIZE_FUNC_INST = 8 /* address size */ +
-                            MIN_SIZE_STRING,
-       MIN_SIZE_LIB_INST = MIN_SIZE_STRING +
-                           4 /* lib counter */,
-       MIN_SIZE_APP_INFO = SIZE_APP_TYPE + MIN_SIZE_STRING + MIN_SIZE_STRING,
-       MIN_SIZE_APP_INST = MIN_SIZE_APP_INFO +
-                           4 /* probe counter */ +
-                           4 /* lib counter */,
-};
-
-#endif /* _MSG_PARSER_H */
diff --git a/parser/parser_defs.h b/parser/parser_defs.h
deleted file mode 100644 (file)
index be56704..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file modules/parser/parser_defs.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov:
- *
- * @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
- *
- * Parser defenitions.
- */
-
-
-#ifndef __SWAP_DRIVER_DEVICE_DEFS_H__
-#define __SWAP_DRIVER_DEVICE_DEFS_H__
-
-#include <linux/kernel.h>
-
-/* #define PARSE_DEBUG */
-
-/** Prints debug message. */
-#define print_debug(msg, args...) \
-       printk(KERN_DEBUG "SWAP_PARSER DEBUG : " msg, ##args)
-/** Prints info message. */
-#define print_msg(msg, args...)   \
-       printk(KERN_INFO "SWAP_PARSER : " msg, ##args)
-/** Prints warning message. */
-#define print_warn(msg, args...)  \
-       printk(KERN_WARNING "SWAP_PARSER WARNING : " msg, ##args)
-/** Prints error message. */
-#define print_err(msg, args...)   \
-       printk(KERN_ERR "SWAP_PARSER ERROR : " msg, ##args)
-/** Prints critical error message. */
-#define print_crit(msg, args...)  \
-       printk(KERN_CRIT "SWAP_PARSER CRITICAL : " msg, ##args)
-
-/* debug parse */
-#ifdef PARSE_DEBUG
-#define print_parse_debug(msg, args...) \
-       printk(KERN_DEBUG "SWAP_PARSER DEBUG : " msg, ##args)
-#else
-#define print_parse_debug(msg, args...) \
-       do {} while (0)
-#endif /* PARSE_DEBUG */
-
-#endif /* __SWAP_DRIVER_DEVICE_DEFS_H__ */
diff --git a/parser/swap_msg_parser.c b/parser/swap_msg_parser.c
deleted file mode 100644 (file)
index 0049e84..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * parser/swap_msg_parser.c
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov
- *
- * @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
- *
- * Parser module interface implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/cpumask.h>
-#include <linux/uaccess.h>
-
-#include "parser_defs.h"
-#include "us_inst.h"
-#include "msg_buf.h"
-#include "msg_cmd.h"
-#include "usm_msg.h"
-#include "cpu_ctrl.h"
-#include "features.h"
-
-#include <driver/driver_to_msg.h>
-#include <driver/swap_ioctl.h>
-#include <master/swap_initializer.h>
-
-/**
- * @enum MSG_ID
- * @brief Message IDs.
- */
-enum MSG_ID {
-       MSG_KEEP_ALIVE          = 0x0001,       /**< Keep alive message. */
-       MSG_START               = 0x0002,       /**< Start message. */
-       MSG_STOP                = 0x0003,       /**< Stop message. */
-       MSG_CONFIG              = 0x0004,       /**< Config message. */
-       MSG_SWAP_INST_ADD       = 0x0008,       /**< Swap inst add message. */
-       MSG_SWAP_INST_REMOVE    = 0x0009,       /**< Swap inst remove message. */
-       MSG_WRT_LAUNCHER_PORT   = 0x8001        /**< WRT launcher port. */
-};
-
-/**
- * @struct basic_msg_fmt
- * @brief Basic part of each message.
- */
-struct basic_msg_fmt {
-       u32 msg_id;                         /**< Message ID. */
-       u32 len;                            /**< Message length. */
-} __packed;
-
-static int msg_handler(void __user *msg)
-{
-       int ret;
-       u32 size;
-       enum MSG_ID msg_id;
-       struct msg_buf mb;
-       void __user *payload;
-       struct basic_msg_fmt bmf;
-       enum { size_max = 128 * 1024 * 1024 };
-
-       ret = copy_from_user(&bmf, (void *)msg, sizeof(bmf));
-       if (ret)
-               return ret;
-
-       size = bmf.len;
-       if (size >= size_max) {
-               printk(KERN_INFO "%s: too large message, size=%u\n",
-                      __func__, size);
-               return -ENOMEM;
-       }
-
-       ret = init_mb(&mb, size);
-       if (ret)
-               return ret;
-
-       payload = msg + sizeof(bmf);
-       if (size) {
-               ret = copy_from_user(mb.begin, (void *)payload, size);
-               if (ret)
-                       goto uninit;
-       }
-
-       msg_id = bmf.msg_id;
-       switch (msg_id) {
-       case MSG_KEEP_ALIVE:
-               print_parse_debug("MSG_KEEP_ALIVE. size=%d\n", size);
-               ret = msg_keep_alive(&mb);
-               break;
-       case MSG_START:
-               print_parse_debug("MSG_START. size=%d\n", size);
-               ret = msg_start(&mb);
-               break;
-       case MSG_STOP:
-               print_parse_debug("MSG_STOP. size=%d\n", size);
-               ret = msg_stop(&mb);
-               break;
-       case MSG_CONFIG:
-               print_parse_debug("MSG_CONFIG. size=%d\n", size);
-               ret = msg_config(&mb);
-               break;
-       case MSG_SWAP_INST_ADD:
-               print_parse_debug("MSG_SWAP_INST_ADD. size=%d\n", size);
-               ret = msg_swap_inst_add(&mb);
-               break;
-       case MSG_SWAP_INST_REMOVE:
-               print_parse_debug("MSG_SWAP_INST_REMOVE. size=%d\n", size);
-               ret = msg_swap_inst_remove(&mb);
-               break;
-       case MSG_WRT_LAUNCHER_PORT: {
-               /* TODO: discuss wrt-launcher port transfer */
-               int port;
-               print_parse_debug("MSG_WRT_LAUNCHER_PORT. size=%d\n", size);
-               port = get_wrt_launcher_port();
-               if (copy_to_user(payload, &port, sizeof(port))) {
-                       ret = -EIO;
-                       break;
-               }
-               ret = port ? 0 : -EINVAL;
-               break;
-       }
-       default:
-               print_err("incorrect message ID [%u]. size=%d\n", msg_id, size);
-               ret = -EINVAL;
-               break;
-       }
-
-uninit:
-       uninit_mb(&mb);
-       return ret;
-}
-
-static struct driver_msg_handler dmsg_handler = {
-       .mod = THIS_MODULE,
-       .handler = msg_handler,
-};
-
-static int reg_msg_handler(void)
-{
-       driver_msg_handler_set(&dmsg_handler);
-       return 0;
-}
-
-static void unreg_msg_handler(void)
-{
-       driver_msg_handler_set(NULL);
-       app_list_unreg_all();
-
-       disable_all_features();
-}
-
-static int once(void)
-{
-       int ret;
-
-       ret = once_cmd();
-       if (ret)
-               return ret;
-
-       ret = init_cpu_deps();
-
-       return ret;
-}
-
-SWAP_LIGHT_INIT_MODULE(once, reg_msg_handler, unreg_msg_handler, NULL, NULL);
-
-MODULE_LICENSE("GPL");
diff --git a/parser/us_inst.c b/parser/us_inst.c
deleted file mode 100644 (file)
index 78e5dd8..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-/**
- * parser/us_inst.c
- * @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
- *
- * User-space instrumentation controls.
- */
-
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/probes/probes.h>
-
-#include "msg_parser.h"
-#include "us_inst.h"
-#include "usm_msg.h"
-
-
-static struct pfg_msg_cb msg_cb = {
-       .msg_info = usm_msg_info,
-       .msg_status_info = usm_msg_status_info,
-       .msg_term = usm_msg_term,
-       .msg_map = usm_msg_map,
-       .msg_unmap = usm_msg_unmap
-};
-
-
-static int probe_inst_reg(struct pr_probe_desc *probe, struct pf_group *pfg,
-                         struct dentry *dentry)
-{
-       probe->ip = pf_register_probe(pfg, dentry, probe->addr, &probe->p_desc);
-       if (IS_ERR(probe->ip))
-               return PTR_ERR(probe->ip);
-
-       return 0;
-}
-
-static void probe_inst_unreg(struct pr_probe_desc *probe, struct pf_group *pfg)
-{
-       pf_unregister_probe(pfg, probe->ip);
-}
-
-static void do_bin_inst_unreg(struct list_head *head, struct pf_group *pfg)
-{
-       struct pr_probe_desc *probe;
-
-       list_for_each_entry(probe, head, list) {
-               probe_inst_unreg(probe, pfg);
-       }
-}
-
-static void bin_inst_unreg(struct pr_bin_desc *bin, struct pf_group *pfg)
-{
-       do_bin_inst_unreg(&bin->probe_head, pfg);
-}
-
-static int bin_inst_reg(struct pr_bin_desc *bin, struct pf_group *pfg)
-{
-       struct pr_probe_desc *probe, *n;
-       struct dentry *dentry;
-       LIST_HEAD(reg_head);
-
-       dentry = dentry_by_path(bin->info->path);
-       if (dentry == NULL) {
-               pr_warn("Cannot get dentry by path %s\n", bin->info->path);
-               return -EINVAL;
-       }
-
-       list_for_each_entry_safe(probe, n, &bin->probe_head, list) {
-               int ret;
-
-               ret = probe_inst_reg(probe, pfg, dentry);
-               if (!ret) {
-                       list_move(&probe->list, &reg_head);
-               } else {
-                       do_bin_inst_unreg(&reg_head, pfg);
-                       return ret;
-               }
-       }
-
-       list_splice(&reg_head, &bin->probe_head);
-       return 0;
-}
-
-static struct pf_group *get_pfg_by_app_info(struct pr_app_info *app)
-{
-       struct pf_group *pfg = ERR_PTR(-EINVAL);
-       struct dentry *dentry;
-
-       dentry = dentry_by_path(app->path);
-       if (dentry == NULL)
-               return pfg;
-
-       switch (app->type) {
-       case AT_PID:
-               if (app->tgid == 0) {
-                       if (app->path[0] == '\0')
-                               pfg = get_pf_group_dumb(dentry);
-                       else
-                               goto pf_dentry;
-               } else {
-                       pfg = get_pf_group_by_tgid(app->tgid, dentry);
-               }
-               break;
-       case AT_TIZEN_WEB_APP:
-               pfg = get_pf_group_by_comm(app->id, dentry);
-               break;
-       case AT_TIZEN_NATIVE_APP:
-       case AT_COMMON_EXEC:
- pf_dentry:
-               pfg = get_pf_group_by_dentry(dentry, dentry);
-               break;
-       default:
-               pr_info("ERROR: app_type=0x%x\n", app->type);
-               break;
-       }
-
-       if (!pfg)
-               pfg = ERR_PTR(-ENOMEM);
-
-       if (!IS_ERR(pfg)) {
-               /* TODO: move to other location and chack return value */
-               pfg_msg_cb_set(pfg, &msg_cb);
-       }
-
-       return pfg;
-}
-
-static void do_us_app_inst_unreg(struct pr_app_desc *app,
-                                struct list_head *head)
-{
-       struct pr_bin_desc *bin;
-
-       list_for_each_entry(bin, head, list) {
-               bin_inst_unreg(bin, app->pfg);
-       }
-       put_pf_group(app->pfg);
-       app->pfg = NULL;
-}
-
-static void us_app_inst_unreg(struct pr_app_desc *app)
-{
-       do_us_app_inst_unreg(app, &app->bin_head);
-}
-
-static int us_app_inst_reg(struct pr_app_desc *app)
-{
-       struct pf_group *pfg;
-       struct pr_bin_desc *bin, *n;
-       LIST_HEAD(reg_head);
-
-       pfg = get_pfg_by_app_info(app->info);
-       if (IS_ERR(pfg))
-               return PTR_ERR(pfg);
-
-       app->pfg = pfg;
-       list_for_each_entry_safe(bin, n, &app->bin_head, list) {
-               int ret;
-
-               ret = bin_inst_reg(bin, app->pfg);
-               if (!ret) {
-                       list_move(&bin->list, &reg_head);
-               } else {
-                       do_us_app_inst_unreg(app, &reg_head);
-                       return ret;
-               }
-       }
-
-       list_splice(&reg_head, &app->bin_head);
-       return 0;
-}
-
-
-static struct pr_probe_desc *find_probe(struct list_head *head,
-                                       struct pr_probe_desc *probe)
-{
-       struct pr_probe_desc *p;
-
-       list_for_each_entry(p, head, list) {
-               if (!probe_inst_info_cmp(probe, p))
-                       return p;
-       }
-
-       return NULL;
-}
-
-static struct pr_bin_desc *find_bin(struct list_head *head,
-                                   struct pr_bin_info *info)
-{
-       struct pr_bin_desc *bin;
-
-       list_for_each_entry(bin, head, list) {
-               if (!pr_bin_info_cmp(bin->info, info))
-                       return bin;
-       }
-
-       return NULL;
-}
-
-static struct pr_app_desc *find_app(struct list_head *head,
-                                   struct pr_app_info *app_info)
-{
-       struct pr_app_desc *app;
-
-       list_for_each_entry(app, head, list) {
-               if (!pr_app_info_cmp(app->info, app_info))
-                       return app;
-       }
-
-       return NULL;
-}
-
-static void us_probe_get_equal_elements(struct list_head *probe_head,
-                                       struct list_head *test_probe_head,
-                                       struct list_head *out_probe_head)
-{
-       struct pr_probe_desc *test_probe, *n;
-
-       list_for_each_entry_safe(test_probe, n, test_probe_head, list) {
-               struct pr_probe_desc *probe;
-
-               probe = find_probe(probe_head, test_probe);
-               if (probe) {
-                       list_move(&probe->list, out_probe_head);
-
-                       /* remove probe */
-                       list_del(&test_probe->list);
-                       pr_probe_desc_free(test_probe);
-               } else {
-                       return;
-               }
-       }
-}
-
-static void us_bin_get_equal_elements(struct list_head *bin_head,
-                                     struct list_head *test_bin_head,
-                                     struct list_head *out_bin_head)
-{
-       struct pr_bin_desc *test_bin, *n;
-
-       list_for_each_entry_safe(test_bin, n, test_bin_head, list) {
-               struct pr_bin_desc *bin;
-               LIST_HEAD(out_probe_head);
-
-               bin = find_bin(bin_head, test_bin->info);
-               if (!bin)
-                       return;
-
-               us_probe_get_equal_elements(&bin->probe_head,
-                                           &test_bin->probe_head,
-                                           &out_probe_head);
-
-               /* check all probes found */
-               if (list_empty(&test_bin->probe_head)) {
-                       list_move(&test_bin->list, out_bin_head);
-                       list_splice(&out_probe_head, &test_bin->probe_head);
-               } else {
-                       list_splice(&out_probe_head, &bin->probe_head);
-               }
-       }
-}
-
-static void us_app_get_equal_elements(struct list_head *app_head,
-                                     struct list_head *test_app_head,
-                                     struct list_head *out_app_head)
-{
-       struct pr_app_desc *test_app, *n;
-
-       list_for_each_entry_safe(test_app, n, test_app_head, list) {
-               struct pr_app_desc *app;
-               LIST_HEAD(out_bin_head);
-
-               app = find_app(app_head, test_app->info);
-               if (!app)
-                       return;
-
-               us_bin_get_equal_elements(&app->bin_head,
-                                         &test_app->bin_head,
-                                         &out_bin_head);
-
-               /* check all bins found */
-               if (list_empty(&test_app->bin_head)) {
-                       list_move(&test_app->list, out_app_head);
-                       list_splice(&out_bin_head, &test_app->bin_head);
-               } else {
-                       list_splice(&out_bin_head, &app->bin_head);
-               }
-       }
-}
-
-
-static void bin_list_splice(struct list_head *list, struct list_head *head)
-{
-       struct pr_bin_desc *new_bin, *n;
-
-       list_for_each_entry_safe(new_bin, n, list, list) {
-               struct pr_bin_desc *bin;
-
-               bin = find_bin(head, new_bin->info);
-               if (bin) {
-                       list_splice_init(&new_bin->probe_head,
-                                        &bin->probe_head);
-
-                       list_del(&new_bin->list);
-                       pr_bin_desc_free(new_bin);
-               } else {
-                       list_move(&new_bin->list, head);
-               }
-       }
-}
-
-static void app_list_splice(struct list_head *list, struct list_head *head)
-{
-       struct pr_app_desc *new_app, *n;
-
-       list_for_each_entry_safe(new_app, n, list, list) {
-               struct pr_app_desc *app;
-
-               app = find_app(head, new_app->info);
-               if (app) {
-                       bin_list_splice(&new_app->bin_head, &app->bin_head);
-
-                       list_del(&new_app->list);
-                       put_pf_group(app->pfg);
-                       pr_app_desc_free(new_app);
-               } else {
-                       list_move(&new_app->list, head);
-               }
-       }
-}
-
-static void app_list_free(struct list_head *head)
-{
-       struct pr_app_desc *app, *n;
-
-       list_for_each_entry_safe(app, n, head, list) {
-               list_del(&app->list);
-               pr_app_desc_free(app);
-       }
-}
-
-static void do_app_list_unreg(struct list_head *head)
-{
-       struct pr_app_desc *app;
-
-       list_for_each_entry(app, head, list) {
-               us_app_inst_unreg(app);
-       }
-}
-
-
-
-static LIST_HEAD(app_head);
-
-/* After call the 'head' list is empty, do not free it. */
-int app_list_unreg(struct list_head *head)
-{
-       LIST_HEAD(out_app_head);
-
-       us_app_get_equal_elements(&app_head, head, &out_app_head);
-
-       /* check all apps found */
-       if (!list_empty(head)) {
-               app_list_splice(&out_app_head, &app_head);
-               return -EINVAL;
-       }
-
-       do_app_list_unreg(&out_app_head);
-       app_list_free(&out_app_head);
-       return 0;
-}
-
-/* After call the 'head' list is empty, do not free it. */
-int app_list_reg(struct list_head *head)
-{
-       LIST_HEAD(reg_head);
-       struct pr_app_desc *app, *n;
-
-       list_for_each_entry_safe(app, n, head, list) {
-               int ret;
-
-               ret = us_app_inst_reg(app);
-               if (!ret) {
-                       list_move(&app->list, &reg_head);
-               } else {
-                       do_app_list_unreg(&reg_head);
-                       list_splice(&reg_head, head);
-                       app_list_free(head);
-                       return ret;
-               }
-       }
-
-       app_list_splice(&reg_head, &app_head);
-       return 0;
-}
-
-void app_list_unreg_all(void)
-{
-       do_app_list_unreg(&app_head);
-       app_list_free(&app_head);
-}
diff --git a/parser/us_inst.h b/parser/us_inst.h
deleted file mode 100644 (file)
index 9db9e1f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @file parser/us_inst.h
- * @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
- *
- * User-space instrumentation controls interface.
- */
-
-
-#ifndef _US_INST_H
-#define _US_INST_H
-
-int app_list_reg(struct list_head *head);
-int app_list_unreg(struct list_head *head);
-void app_list_unreg_all(void);
-
-#endif /* _US_INST_H */
diff --git a/parser/usm_msg.c b/parser/usm_msg.c
deleted file mode 100644 (file)
index 71009ac..0000000
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/fs.h>
-#include <linux/net.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/dcache.h>
-#include <linux/fdtable.h>
-#include <linux/file.h>
-#include <linux/version.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/net.h>
-#include <writer/swap_msg.h>
-#include <master/swap_deps.h>
-#include <us_manager/sspt/sspt.h>      /* ... check_vma() */
-
-
-#define USM_PREFIX      KERN_INFO "[USM] "
-
-
-struct kmem_info {
-       const char *name;
-       unsigned long start;
-       unsigned long end;
-};
-
-#if defined(CONFIG_ARM64) || defined(CONFIG_X86_32)
-static void kmem_info_fill_common(struct kmem_info *info, struct task_struct *task)
-{
-       unsigned long vdso;
-       struct vm_area_struct *vma_vdso;
-
-       vdso = (unsigned long)task->mm->context.vdso;
-       vma_vdso = find_vma_intersection(task->mm, vdso, vdso + 1);
-       if (vma_vdso) {
-               info->name = "[vdso]";
-               info->start = vma_vdso->vm_start;
-               info->end = vma_vdso->vm_end;
-       } else {
-               pr_err(USM_PREFIX "Cannot get VDSO mapping\n");
-               info->name = NULL;
-               info->start = 0;
-               info->end = 0;
-       }
-}
-#endif /* defined(CONFIG_ARM64) || defined(CONFIG_X86_32) */
-
-static void kmem_info_fill(struct kmem_info *info, struct task_struct *task)
-{
-#if defined(CONFIG_ARM)
-       info->name = "[vectors]";
-       info->start = CONFIG_VECTORS_BASE;
-       info->end = CONFIG_VECTORS_BASE + PAGE_SIZE;
-#elif defined(CONFIG_ARM64)
-       if (test_ti_thread_flag(task_thread_info(task), TIF_32BIT)) {
-               info->name = "[vectors]";
-               info->start = AARCH32_VECTORS_BASE;
-               info->end = AARCH32_VECTORS_BASE + PAGE_SIZE;
-       } else {
-               kmem_info_fill_common(info, task);
-       }
-#elif defined(CONFIG_X86_32)
-       kmem_info_fill_common(info, task);
-#endif /* CONFIG_arch */
-}
-
-static inline struct timespec get_task_start_time(struct task_struct *task)
-{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0)
-       return ns_to_timespec(task->real_start_time);
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
-       return task->real_start_time;
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
-}
-
-
-
-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;
-       }
-
-       path_get(&file->f_path);
-       filename = d_path(&file->f_path, tmp_buf, TMP_BUF_LEN);
-       path_put(&file->f_path);
-
-       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 task_struct *task)
-{
-       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, task);
-
-       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 task_struct *task)
-{
-       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 = task->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, task);
-       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_path.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, get_task_start_time(task));
-
-       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);
-       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);
-}
-
-
-
-
-
-/* ============================================================================
- * =                          MSG_PROCESS_STATUS_INFO                         =
- * ============================================================================
- */
-struct ofile {
-       u32 fd;
-       u64 size;
-       char path[0];
-} __packed;
-
-struct osock {
-       u32 fd;
-       u32 ip;
-       u32 port;
-} __packed;
-
-static int pack_ofile(void *data, size_t size, int fd, struct file *file,
-                     loff_t fsize)
-{
-       int ret;
-       struct ofile *ofile;
-
-       if (size < sizeof(*ofile))
-               return -ENOMEM;
-
-       ofile = (struct ofile *)data;
-       ofile->fd = (u32)fd;
-       ofile->size = (u64)fsize;
-
-       ret = pack_path(ofile->path, size - sizeof(*ofile), file);
-       if (ret < 0)
-               return ret;
-
-       return sizeof(*ofile) + ret;
-}
-
-static int is_file_mode(umode_t mode)
-{
-       return S_ISREG(mode);
-}
-
-static int pack_osock(void *data, size_t size, int fd, struct file *file,
-                     loff_t fsize)
-{
-       struct osock *pack_sock;
-       struct socket *sock;
-       struct sockaddr_storage addr;
-       struct sockaddr *saddr = (struct sockaddr *)&addr;
-       struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
-       int ret_size = sizeof(*pack_sock);
-       int addrlen;
-       int err;
-
-       if (size < sizeof(*pack_sock))
-               return -ENOMEM;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
-       sock = sockfd_lookup(fd, &err);
-#else
-       sock = sock_from_file(file, &err);
-#endif  /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
-       if (!sock)
-               return 0;
-
-       kernel_getsockname(sock, saddr, &addrlen);
-
-       pack_sock = (struct osock *)data;
-       pack_sock->fd = (u32)fd;
-       pack_sock->ip = (u32)0x0;
-       pack_sock->port = 0;
-
-       switch (saddr->sa_family) {
-       case AF_INET:
-               pack_sock->ip = (u32)(sin->sin_addr.s_addr);
-               pack_sock->port = ntohs(sin->sin_port);
-               break;
-       default:
-               pr_info("[USM] ignored unknown address type: %u\n",
-                       (unsigned int)saddr->sa_family);
-               ret_size = 0;
-               break;
-       }
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
-       sockfd_put(sock);
-#endif  /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
-
-       return ret_size;
-}
-
-static int is_sock_mode(umode_t mode)
-{
-       return S_ISSOCK(mode);
-}
-
-typedef int (*pack_func_t)(void *data, size_t size, int fd, struct file *file,
-                           loff_t fsize);
-typedef int (*check_mode_func_t)(umode_t mode);
-
-static int pack_descriptors(void *data, size_t size, pack_func_t pack_func,
-                           check_mode_func_t check_mode,
-                           struct files_struct *files)
-{
-       int ret, fd;
-       const size_t old_size = size;
-       u32 *desc_cnt;
-
-       /* pack descriptor count */
-       desc_cnt = (u32 *)data;
-       *desc_cnt = 0;
-       data += 4;
-       size -= 4;
-
-       /* pack descriptors list */
-       rcu_read_lock();
-       for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
-               struct file *file;
-               struct inode *inode;
-               loff_t fsize;
-
-               file = fcheck_files(files, fd);
-               if (file == NULL)
-                       continue;
-
-               inode = file->f_path.dentry->d_inode;
-               /* check inode and if it is a regular file */
-               if (!inode || !check_mode(inode->i_mode))
-                       continue;
-
-               fsize = inode->i_size;
-               rcu_read_unlock();
-
-               ret = pack_func(data, size, fd, file, fsize);
-               if (ret < 0) {
-                       goto exit;
-               } else if (ret > 0) {
-                       /* increment if data packed only */
-                       data += ret;
-                       size -= ret;
-                       ++(*desc_cnt);
-               }
-
-               rcu_read_lock();
-       }
-
-       rcu_read_unlock();
-       ret = old_size - size;
-
-exit:
-       return ret;
-}
-
-static int pack_status_info(void *data, size_t size, struct task_struct *task)
-{
-       int ret;
-       const size_t old_size = size;
-       struct files_struct *files;
-
-       files = swap_get_files_struct(task);
-       if (!files)
-               return -EIO;
-
-       /* pack pid */
-       *((u32 *)data) = (u32)task->tgid;
-       data += 4;
-       size -= 4;
-
-       /* pack file descriptors */
-       ret = pack_descriptors(data, size, pack_ofile, is_file_mode, files);
-       if (ret < 0)
-               goto put_fstruct;
-       data += ret;
-       size -= ret;
-
-       /* pack sock descriptors */
-       ret = pack_descriptors(data, size, pack_osock, is_sock_mode, files);
-       if (ret < 0)
-               goto put_fstruct;
-       data += ret;
-       size -= ret;
-
-       ret = old_size - size;
-
-put_fstruct:
-       swap_put_files_struct(files);
-       return ret;
-}
-
-void usm_msg_status_info(struct task_struct *task)
-{
-       int ret;
-       void *data;
-       size_t size;
-       struct swap_msg *m;
-
-       m = swap_msg_get(MSG_PROCESS_STATUS_INFO);
-
-       data = swap_msg_payload(m);
-       size = swap_msg_size(m);
-       ret = pack_status_info(data, size, task);
-       if (ret < 0) {
-               printk(USM_PREFIX "ERROR: MSG_PROCESS_STATUS_INFO "
-                      "packing, ret=%d\n", ret);
-               goto put_msg;
-       }
-
-       swap_msg_flush(m, ret);
-
-put_msg:
-       swap_msg_put(m);
-}
diff --git a/parser/usm_msg.h b/parser/usm_msg.h
deleted file mode 100644 (file)
index 6c9345d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#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);
-void usm_msg_status_info(struct task_struct *task);
-
-
-#endif /* _USM_MSG_H */
diff --git a/preload/Kbuild b/preload/Kbuild
deleted file mode 100644 (file)
index 466b89b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_preload.o
-swap_preload-y := preload_module.o \
-                  preload_control.o \
-                  preload_debugfs.o \
-                  preload_probe.o \
-                  preload_threads.o \
-                  preload_process.o
diff --git a/preload/preload.h b/preload/preload.h
deleted file mode 100644 (file)
index 7034222..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __PRELOAD__
-#define __PRELOAD__
-
-#define PRELOAD_PREFIX "SWAP_PRELOAD: "
-#define PRELOAD_MAX_ATTEMPTS 10
-#define PRELOAD_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
-
-#endif /* __PRELOAD__ */
diff --git a/preload/preload_control.c b/preload/preload_control.c
deleted file mode 100644 (file)
index 7d6567e..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/us_common_file.h>
-
-#include "preload.h"
-#include "preload_module.h"
-#include "preload_control.h"
-#include "preload_probe.h"
-
-struct bin_desc {
-       struct list_head list;
-       struct dentry *dentry;
-       char *filename;
-};
-
-struct list_desc {
-       struct list_head list;
-       rwlock_t lock;
-       int cnt;
-};
-
-static struct list_desc target = {
-       .list = LIST_HEAD_INIT(target.list),
-       .lock = __RW_LOCK_UNLOCKED(&target.lock),
-       .cnt = 0
-};
-
-static struct list_desc ignored = {
-       .list = LIST_HEAD_INIT(ignored.list),
-       .lock = __RW_LOCK_UNLOCKED(&ignored.lock),
-       .cnt = 0
-};
-
-static inline struct task_struct *__get_task_struct(void)
-{
-       return current;
-}
-
-static struct bin_desc *__alloc_binary(struct dentry *dentry, char *name,
-                                      int namelen)
-{
-       struct bin_desc *p = NULL;
-
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return NULL;
-
-       INIT_LIST_HEAD(&p->list);
-       p->filename = kmalloc(namelen + 1, GFP_KERNEL);
-       if (!p->filename)
-               goto fail;
-       memcpy(p->filename, name, namelen);
-       p->filename[namelen] = '\0';
-       p->dentry = dentry;
-
-       return p;
-fail:
-       kfree(p);
-       return NULL;
-}
-
-static void __free_binary(struct bin_desc *p)
-{
-       kfree(p->filename);
-       kfree(p);
-}
-
-static void __free_binaries(struct list_desc *tl)
-{
-       struct bin_desc *p, *n;
-       struct list_head rm_head;
-
-       INIT_LIST_HEAD(&rm_head);
-       write_lock(&tl->lock);
-       list_for_each_entry_safe(p, n, &tl->list, list) {
-               list_move(&p->list, &rm_head);
-       }
-       tl->cnt = 0;
-       write_unlock(&tl->lock);
-
-       list_for_each_entry_safe(p, n, &rm_head, list) {
-               list_del(&p->list);
-               swap_put_dentry(p->dentry);
-               __free_binary(p);
-       }
-}
-
-static bool __check_dentry_already_exist(struct dentry *dentry,
-                                        struct list_desc *tl)
-{
-       struct bin_desc *p;
-       bool ret = false;
-
-       read_lock(&tl->lock);
-       list_for_each_entry(p, &tl->list, list) {
-               if (p->dentry == dentry) {
-                       ret = true;
-                       goto out;
-               }
-       }
-out:
-       read_unlock(&tl->lock);
-
-       return ret;
-}
-
-static int __add_binary(struct dentry *dentry, char *filename,
-                       struct list_desc *tl)
-{
-       struct bin_desc *p;
-       size_t len;
-
-       if (__check_dentry_already_exist(dentry, tl)) {
-               printk(PRELOAD_PREFIX "Binary already exist\n");
-               return EALREADY;
-       }
-
-       /* Filename should be < PATH_MAX */
-       len = strnlen(filename, PATH_MAX);
-       if (len == PATH_MAX)
-               return -EINVAL;
-
-       p = __alloc_binary(dentry, filename, len);
-       if (!p)
-               return -ENOMEM;
-
-       write_lock(&tl->lock);
-       list_add_tail(&p->list, &tl->list);
-       tl->cnt++;
-       write_unlock(&tl->lock);
-
-       return 0;
-}
-
-static struct dentry *__get_caller_dentry(struct task_struct *task,
-                                         unsigned long caller)
-{
-       struct vm_area_struct *vma = NULL;
-
-       if (unlikely(task->mm == NULL))
-               goto get_caller_dentry_fail;
-
-       vma = find_vma_intersection(task->mm, caller, caller + 1);
-       if (unlikely(vma == NULL || vma->vm_file == NULL))
-               goto get_caller_dentry_fail;
-
-       return vma->vm_file->f_path.dentry;
-
-get_caller_dentry_fail:
-
-       return NULL;
-}
-
-static bool __check_if_instrumented(struct task_struct *task,
-                                   struct dentry *dentry)
-{
-       return __check_dentry_already_exist(dentry, &target);
-}
-
-static bool __is_instrumented(void *caller)
-{
-       struct task_struct *task = __get_task_struct();
-       struct dentry *caller_dentry = __get_caller_dentry(task,
-                                                          (unsigned long) caller);
-
-       if (caller_dentry == NULL)
-               return false;
-
-       return __check_if_instrumented(task, caller_dentry);
-}
-
-static unsigned int __get_names(struct list_desc *tl, char ***filenames_p)
-{
-       unsigned int i, ret = 0;
-       struct bin_desc *p;
-       char **a = NULL;
-
-       read_lock(&tl->lock);
-       if (tl->cnt == 0)
-               goto out;
-
-       a = kmalloc(sizeof(*a) * tl->cnt, GFP_KERNEL);
-       if (!a)
-               goto out;
-
-       i = 0;
-       list_for_each_entry(p, &tl->list, list) {
-               if (i >= tl->cnt)
-                       break;
-               a[i++] = p->filename;
-       }
-
-       *filenames_p = a;
-       ret = i;
-out:
-       read_unlock(&tl->lock);
-       return ret;
-}
-
-
-/* Called only form handlers. If we're there, then it is instrumented. */
-enum preload_call_type pc_call_type_always_inst(void *caller)
-{
-       if (__is_instrumented(caller))
-               return INTERNAL_CALL;
-
-       return EXTERNAL_CALL;
-
-}
-
-enum preload_call_type pc_call_type(struct sspt_ip *ip, void *caller)
-{
-       if (__is_instrumented(caller))
-               return INTERNAL_CALL;
-
-       if (ip->desc->info.pl_i.flags & SWAP_PRELOAD_ALWAYS_RUN)
-               return EXTERNAL_CALL;
-
-       return NOT_INSTRUMENTED;
-}
-
-int pc_add_instrumented_binary(char *filename)
-{
-       struct dentry *dentry = swap_get_dentry(filename);
-       int res = 0;
-
-       if (dentry == NULL)
-               return -EINVAL;
-
-       res = __add_binary(dentry, filename, &target);
-       if (res != 0)
-               swap_put_dentry(dentry);
-
-       return res > 0 ? 0 : res;
-}
-
-int pc_clean_instrumented_bins(void)
-{
-       __free_binaries(&target);
-
-       return 0;
-}
-
-int pc_add_ignored_binary(char *filename)
-{
-       struct dentry *dentry = swap_get_dentry(filename);
-       int res = 0;
-
-       if (dentry == NULL)
-               return -EINVAL;
-
-       res = __add_binary(dentry, filename, &ignored);
-       if (res != 0)
-               swap_put_dentry(dentry);
-
-       return res > 0 ? 0 : res;
-}
-
-int pc_clean_ignored_bins(void)
-{
-       __free_binaries(&ignored);
-
-       return 0;
-}
-
-unsigned int pc_get_target_names(char ***filenames_p)
-{
-       return __get_names(&target, filenames_p);
-}
-
-void pc_release_target_names(char ***filenames_p)
-{
-       kfree(*filenames_p);
-}
-
-unsigned int pc_get_ignored_names(char ***filenames_p)
-{
-       return __get_names(&ignored, filenames_p);
-}
-
-void pc_release_ignored_names(char ***filenames_p)
-{
-       kfree(*filenames_p);
-}
-
-bool pc_check_dentry_is_ignored(struct dentry *dentry)
-{
-       struct bin_desc *p;
-       bool ret = false;
-
-       if (dentry == NULL)
-               return false;
-
-       read_lock(&ignored.lock);
-
-       list_for_each_entry(p, &ignored.list, list) {
-               if (p->dentry == dentry) {
-                       ret = true;
-                       break;
-               }
-       }
-
-       read_unlock(&ignored.lock);
-
-       return ret;
-}
-
-int pc_init(void)
-{
-       return 0;
-}
-
-void pc_exit(void)
-{
-       __free_binaries(&target);
-       __free_binaries(&ignored);
-}
diff --git a/preload/preload_control.h b/preload/preload_control.h
deleted file mode 100644 (file)
index 4e6f1d0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __PRELOAD_CONTROL_H__
-#define __PRELOAD_CONTROL_H__
-
-struct sspt_ip;
-
-enum preload_call_type {
-       NOT_INSTRUMENTED,
-       EXTERNAL_CALL,
-       INTERNAL_CALL
-};
-
-int pc_init(void);
-void pc_exit(void);
-
-enum preload_call_type pc_call_type_always_inst(void *caller);
-enum preload_call_type pc_call_type(struct sspt_ip *ip, void *caller);
-int pc_add_instrumented_binary(char *filename);
-int pc_clean_instrumented_bins(void);
-int pc_add_ignored_binary(char *filename);
-int pc_clean_ignored_bins(void);
-
-unsigned int pc_get_target_names(char ***filenames_p);
-void pc_release_target_names(char ***filenames_p);
-
-unsigned int pc_get_ignored_names(char ***filenames_p);
-void pc_release_ignored_names(char ***filenames_p);
-
-bool pc_check_dentry_is_ignored(struct dentry *dentry);
-
-#endif /* __PRELOAD_HANDLERS_CONTROL_H__ */
diff --git a/preload/preload_debugfs.c b/preload/preload_debugfs.c
deleted file mode 100644 (file)
index e480fa9..0000000
+++ /dev/null
@@ -1,725 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/limits.h>
-#include <asm/uaccess.h>
-#include <master/swap_debugfs.h>
-#include <master/swap_initializer.h>
-#include "preload.h"
-#include "preload_module.h"
-#include "preload_debugfs.h"
-#include "preload_control.h"
-#include "preload_process.h"
-
-static const char PRELOAD_FOLDER[] = "preload";
-static const char PRELOAD_TARGET[] = "target_binaries";
-static const char PRELOAD_IGNORED[] = "ignored_binaries";
-static const char PRELOAD_BINARIES_LIST[] = "bins_list";
-static const char PRELOAD_BINARIES_ADD[] = "bins_add";
-static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove";
-static const char PRELOAD_ENABLE[] = "enable";
-static const char PRELOAD_BY_PATH[] = "by_path";
-static const char PRELOAD_BY_PID[] = "by_pid";
-static const char PRELOAD_BY_ID[] = "by_id";
-static const char PRELOAD_ADD[] = "add";
-static const char PRELOAD_DEL[] = "del";
-static const char PRELOAD_DEL_ALL[] = "del_all";
-static const char PRELOAD_PTHREAD[] = "pthread";
-static const char PRELOAD_PATH[] = "path";
-static const char PRELOAD_MINIMAL_INIT[] = "minimal_init_off";
-
-static struct dentry *preload_root;
-static struct dentry *target_list = NULL;
-static struct dentry *target_add = NULL;
-static struct dentry *target_remove = NULL;
-static struct dentry *ignored_list = NULL;
-static struct dentry *ignored_add = NULL;
-static struct dentry *ignored_remove = NULL;
-
-
-/* Type for functions that add process by path and by id */
-typedef int (*sh_t)(const char *);
-
-/* Type for functions that add process by pid */
-typedef int (*ph_t)(pid_t);
-
-/* Type for function that handles unsigned long grabbed from userspace */
-typedef int (*ulh_t)(unsigned long);
-
-
-/* remove end-line symbols */
-static void rm_endline_symbols(char *buf, size_t len)
-{
-       char *p, *buf_end;
-
-       buf_end = buf + len;
-       for (p = buf; p != buf_end; ++p)
-               if (*p == '\n' || *p == '\r')
-                       *p = '\0';
-}
-
-static ssize_t get_string(const char __user *buf, size_t len, char **kbuf)
-{
-       char *string;
-       ssize_t ret;
-
-       string = kmalloc(len + 1, GFP_KERNEL);
-       if (!string) {
-               pr_warn(PRELOAD_PREFIX "No mem for user string!\n");
-               return -ENOMEM;
-       }
-
-       if (copy_from_user(string, buf, len)) {
-               pr_warn(PRELOAD_PREFIX "Failed to copy data from user!\n");
-               ret = -EINVAL;
-               goto get_string_fail;
-       }
-
-       string[len] = '\0';
-       rm_endline_symbols(string, len);
-       *kbuf = string;
-
-       return len;
-
-get_string_fail:
-       kfree(string);
-
-       return ret;
-}
-
-
-static ssize_t get_ul_and_call(const char __user *buf, size_t len, ulh_t cb)
-{
-       ssize_t ret;
-       char *ulstring;
-       unsigned long ul;
-
-       ret = get_string(buf, len, &ulstring);
-       if (ret != len)
-               return ret;
-
-       ret = kstrtoul(ulstring, 16, &ul);
-       if (ret)
-               goto get_ul_write_out;
-
-       ret = cb(ul);
-
-get_ul_write_out:
-       kfree(ulstring);
-
-       return ret == 0 ? len : ret;
-}
-
-static ssize_t get_string_and_call(const char __user *buf, size_t len, sh_t cb)
-{
-       char *string;
-       ssize_t ret;
-
-       ret = get_string(buf, len, &string);
-       if (ret != len)
-               return ret;
-
-       ret = cb(string);
-       if (ret)
-               pr_warn(PRELOAD_PREFIX "Error adding process by <%s>\n",
-                       string);
-
-       kfree(string);
-
-       return ret == 0 ? len : ret;
-}
-
-static ssize_t get_pid_and_call(const char __user *buf, size_t len, ph_t cb)
-{
-       char *string;
-       pid_t pid;
-       ssize_t ret;
-
-       ret = get_string(buf, len, &string);
-       if (ret != len)
-               return ret;
-
-       ret = kstrtoul(string, 10, (unsigned long *)&pid);
-       if (ret) {
-               pr_warn(PRELOAD_PREFIX "Invalid PID!\n");
-               goto get_pid_out;
-       }
-
-       ret = cb(pid);
-       if (ret)
-               pr_warn(PRELOAD_PREFIX "Error adding process by <%s>\n",
-                       string);
-
-get_pid_out:
-       kfree(string);
-
-       return ret == 0 ? len : ret;
-}
-
-/* ===========================================================================
- * =                           TARGET PROCESSES                              =
- * ===========================================================================
- */
-
-static ssize_t by_path_add_write(struct file *file, const char __user *buf,
-                                size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, pp_add_by_path);
-}
-
-static ssize_t by_path_del_write(struct file *file, const char __user *buf,
-                                size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, pp_del_by_path);
-}
-
-static ssize_t by_pid_add_write(struct file *file, const char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       return get_pid_and_call(buf, len, pp_add_by_pid);
-}
-
-static ssize_t by_pid_del_write(struct file *file, const char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       return get_pid_and_call(buf, len, pp_del_by_pid);
-}
-
-static ssize_t by_id_add_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, pp_add_by_id);
-}
-
-static ssize_t by_id_del_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, pp_del_by_id);
-}
-
-static ssize_t del_all_write(struct file *file, const char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       pp_del_all();
-
-       WARN(pc_clean_instrumented_bins(), PRELOAD_PREFIX
-            "Error while cleaning target bins\n");
-       WARN(pc_clean_ignored_bins(), PRELOAD_PREFIX
-            "Error while cleaning ignored bins\n");
-
-       return len;
-}
-
-static const struct file_operations by_path_add_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = by_path_add_write,
-};
-
-static const struct file_operations by_path_del_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = by_path_del_write,
-};
-
-static const struct file_operations by_pid_add_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = by_pid_add_write,
-};
-
-static const struct file_operations by_pid_del_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = by_pid_del_write,
-};
-
-static const struct file_operations by_id_add_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = by_id_add_write,
-};
-
-static const struct file_operations by_id_del_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = by_id_del_write,
-};
-
-static const struct file_operations del_all_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = del_all_write,
-};
-
-/* ===========================================================================
- * =                              ENABLE                                     =
- * ===========================================================================
- */
-
-static ssize_t enable_read(struct file *file, char __user *buf,
-                          size_t len, loff_t *ppos)
-{
-       char val[2];
-
-       val[0] = (pm_status() == PRELOAD_ON ? '1' : '0');
-       val[1] = '\0';
-
-       return simple_read_from_buffer(buf, len, ppos, val, 2);
-}
-
-static ssize_t enable_write(struct file *file, const char __user *buf,
-                           size_t len, loff_t *ppos)
-{
-       ssize_t ret = 0;
-       char val[2];
-       size_t val_size;
-
-       val_size = min(len, (sizeof(val) - 1));
-       if (copy_from_user(val, buf, val_size))
-               return -EFAULT;
-
-       val[1] = '\0';
-       switch (val[0]) {
-       case '0':
-               ret = pm_switch(PRELOAD_OFF);
-               break;
-       case '1':
-               ret = pm_switch(PRELOAD_ON);
-               break;
-       default:
-               printk(PRELOAD_PREFIX "Invalid state!\n");
-               return -EINVAL;
-       }
-
-       return ret == 0 ? len : ret;
-}
-
-static const struct file_operations enable_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = enable_write,
-       .read = enable_read,
-};
-
-
-/* ===========================================================================
- * =                                BIN PATH                                 =
- * ===========================================================================
- */
-
-static ssize_t bin_add_write(struct file *file, const char __user *buf,
-                          size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *path;
-
-       path = kmalloc(len, GFP_KERNEL);
-       if (path == NULL) {
-               ret = -ENOMEM;
-               goto bin_add_write_out;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto bin_add_write_out;
-       }
-
-       path[len - 1] = '\0';
-
-       if (file->f_path.dentry == target_add)
-               ret = pc_add_instrumented_binary(path);
-       else if (file->f_path.dentry == ignored_add)
-               ret = pc_add_ignored_binary(path);
-       else {
-               /* Should never occur */
-               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
-                      file->f_path.dentry->d_name.name);
-               ret = -EINVAL;
-               goto bin_add_write_out;
-       }
-
-
-       if (ret != 0) {
-               printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
-               ret = -EINVAL;
-               goto bin_add_write_out;
-       }
-
-       ret = len;
-
-bin_add_write_out:
-       kfree(path);
-
-       return ret;
-}
-
-static ssize_t bin_remove_write(struct file *file, const char __user *buf,
-                             size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-
-       if (file->f_path.dentry == target_remove)
-               ret = pc_clean_instrumented_bins();
-       else if (file->f_path.dentry == ignored_remove)
-               ret = pc_clean_ignored_bins();
-       else {
-               /* Should never occur */
-               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
-                      file->f_path.dentry->d_name.name);
-               ret = -EINVAL;
-               goto bin_remove_write_out;
-       }
-
-       if (ret != 0) {
-               printk(PRELOAD_PREFIX "Error during clean!\n");
-               ret = -EINVAL;
-               goto bin_remove_write_out;
-       }
-
-       ret = len;
-
-bin_remove_write_out:
-       return ret;
-}
-
-static ssize_t bin_list_read(struct file *file, char __user *usr_buf,
-                                size_t count, loff_t *ppos)
-{
-       unsigned int i;
-       unsigned int files_cnt = 0;
-       ssize_t len = 0, tmp, ret = 0;
-       char **filenames = NULL;
-       char *buf = NULL;
-       char *ptr = NULL;
-
-       if (file->f_path.dentry == target_list) {
-               files_cnt = pc_get_target_names(&filenames);
-       } else if (file->f_path.dentry == ignored_list) {
-               files_cnt = pc_get_ignored_names(&filenames);
-       } else {
-               /* Should never occur */
-               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
-                      file->f_path.dentry->d_name.name);
-               ret = 0;
-               goto bin_list_read_out;
-       }
-
-       if (files_cnt == 0) {
-               printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
-               ret = 0;
-               goto bin_list_read_fail;
-       }
-
-       for (i = 0; i < files_cnt; i++)
-               len += strlen(filenames[i]);
-
-       buf = kmalloc(len + files_cnt, GFP_KERNEL);
-       if (buf == NULL) {
-               ret = 0;
-               goto bin_list_read_fail;
-       }
-
-       ptr = buf;
-
-       for (i = 0; i < files_cnt; i++) {
-               tmp = strlen(filenames[i]);
-               memcpy(ptr, filenames[i], tmp);
-               ptr += tmp;
-               *ptr = '\n';
-               ptr += 1;
-       }
-
-       ret = simple_read_from_buffer(usr_buf, count, ppos, buf, len);
-
-       kfree(buf);
-
-bin_list_read_fail:
-       if (file->f_path.dentry == target_list) {
-               pc_release_target_names(&filenames);
-       } else if (file->f_path.dentry == ignored_list)  {
-               pc_release_ignored_names(&filenames);
-       } else {
-               /* Should never occur */
-               printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
-                      file->f_path.dentry->d_name.name);
-               ret = 0;
-       }
-
-bin_list_read_out:
-       return ret;
-}
-
-static const struct file_operations bin_list_file_ops = {
-       .owner = THIS_MODULE,
-       .read = bin_list_read
-};
-
-static const struct file_operations bin_add_file_ops = {
-       .owner = THIS_MODULE,
-       .write = bin_add_write,
-};
-
-static const struct file_operations bin_remove_file_ops = {
-       .owner = THIS_MODULE,
-       .write = bin_remove_write,
-};
-
-
-
-/* ===========================================================================
- * =                             PTHREAD                                     =
- * ===========================================================================
- */
-
-static ssize_t pthread_path_write(struct file *file, const char __user *buf,
-                                 size_t len, loff_t *ppos)
-{
-       return get_string_and_call(buf, len, pp_set_pthread_path);
-}
-
-static ssize_t init_off_write(struct file *file, const char __user *buf,
-                             size_t len, loff_t *ppos)
-{
-       return get_ul_and_call(buf, len, pp_set_init_offset);
-}
-
-static const struct file_operations pthread_path_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = pthread_path_write,
-};
-
-static const struct file_operations pthread_init_off_fops = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write = init_off_write,
-};
-
-
-
-
-
-
-int pd_init(void)
-{
-       struct dentry *swap_dentry, *root, *target_path, *ignored_path,
-                     *by_path, *by_pid, *by_id, *pthread, *dentry;
-       int ret;
-
-       ret = -ENODEV;
-       if (!debugfs_initialized())
-               goto fail;
-
-       ret = -ENOENT;
-       swap_dentry = swap_debugfs_getdir();
-       if (!swap_dentry)
-               goto fail;
-
-       ret = -ENOMEM;
-       root = swap_debugfs_create_dir(PRELOAD_FOLDER, swap_dentry);
-       if (IS_ERR_OR_NULL(root))
-               goto fail;
-
-       preload_root = root;
-
-       target_path = swap_debugfs_create_dir(PRELOAD_TARGET, root);
-       if (IS_ERR_OR_NULL(target_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       target_list = swap_debugfs_create_file(PRELOAD_BINARIES_LIST,
-                                              PRELOAD_DEFAULT_PERMS,
-                                              target_path,
-                                              NULL, &bin_list_file_ops);
-       if (IS_ERR_OR_NULL(target_list)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       target_add = swap_debugfs_create_file(PRELOAD_BINARIES_ADD,
-                                             PRELOAD_DEFAULT_PERMS,
-                                             target_path,
-                                             NULL, &bin_add_file_ops);
-       if (IS_ERR_OR_NULL(target_add)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       target_remove = swap_debugfs_create_file(PRELOAD_BINARIES_REMOVE,
-                                                PRELOAD_DEFAULT_PERMS,
-                                                target_path,
-                                                NULL, &bin_remove_file_ops);
-       if (IS_ERR_OR_NULL(target_remove)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       ignored_path = swap_debugfs_create_dir(PRELOAD_IGNORED, root);
-       if (IS_ERR_OR_NULL(ignored_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       ignored_list = swap_debugfs_create_file(PRELOAD_BINARIES_LIST,
-                                               PRELOAD_DEFAULT_PERMS,
-                                               ignored_path,
-                                               NULL, &bin_list_file_ops);
-       if (IS_ERR_OR_NULL(ignored_list)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       ignored_add = swap_debugfs_create_file(PRELOAD_BINARIES_ADD,
-                                              PRELOAD_DEFAULT_PERMS,
-                                              ignored_path,
-                                              NULL, &bin_add_file_ops);
-       if (IS_ERR_OR_NULL(ignored_add)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       ignored_remove = swap_debugfs_create_file(PRELOAD_BINARIES_REMOVE,
-                                                 PRELOAD_DEFAULT_PERMS,
-                                                 ignored_path, NULL,
-                                                 &bin_remove_file_ops);
-       if (IS_ERR_OR_NULL(ignored_remove)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       by_path = swap_debugfs_create_dir(PRELOAD_BY_PATH, root);
-       if (IS_ERR_OR_NULL(by_path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_ADD, PRELOAD_DEFAULT_PERMS,
-                                         by_path, NULL, &by_path_add_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_DEL, PRELOAD_DEFAULT_PERMS,
-                                         by_path, NULL, &by_path_del_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       by_pid = swap_debugfs_create_dir(PRELOAD_BY_PID, root);
-       if (IS_ERR_OR_NULL(by_pid)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_ADD, PRELOAD_DEFAULT_PERMS,
-                                         by_pid, NULL, &by_pid_add_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_DEL, PRELOAD_DEFAULT_PERMS,
-                                         by_pid, NULL, &by_pid_del_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       by_id = swap_debugfs_create_dir(PRELOAD_BY_ID, root);
-       if (IS_ERR_OR_NULL(by_id)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_ADD, PRELOAD_DEFAULT_PERMS,
-                                         by_id, NULL, &by_id_add_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_DEL, PRELOAD_DEFAULT_PERMS,
-                                         by_id, NULL, &by_id_del_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_DEL_ALL,
-                                         PRELOAD_DEFAULT_PERMS,
-                                         root, NULL, &del_all_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_ENABLE, PRELOAD_DEFAULT_PERMS,
-                                         root, NULL, &enable_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       pthread = swap_debugfs_create_dir(PRELOAD_PTHREAD, root);
-       if (IS_ERR_OR_NULL(pthread)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_PATH, PRELOAD_DEFAULT_PERMS,
-                                         pthread, NULL, &pthread_path_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       dentry = swap_debugfs_create_file(PRELOAD_MINIMAL_INIT,
-                                         PRELOAD_DEFAULT_PERMS, pthread, NULL,
-                                         &pthread_init_off_fops);
-       if (IS_ERR_OR_NULL(dentry)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       return 0;
-
-remove:
-
-       debugfs_remove_recursive(root);
-
-fail:
-       printk(PRELOAD_PREFIX "Debugfs initialization failure: %d\n", ret);
-
-       return ret;
-}
-
-void pd_exit(void)
-{
-       if (preload_root)
-               debugfs_remove_recursive(preload_root);
-       target_list = NULL;
-       target_add = NULL;
-       target_remove = NULL;
-       ignored_list = NULL;
-       ignored_add = NULL;
-       ignored_remove = NULL;
-       preload_root = NULL;
-}
diff --git a/preload/preload_debugfs.h b/preload/preload_debugfs.h
deleted file mode 100644 (file)
index bae931d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __PRELOAD_HANDLERS_DEBUGFS_H__
-#define __PRELOAD_HANDLERS_DEBUGFS_H__
-
-struct dentry;
-
-int pd_init(void);
-void pd_exit(void);
-
-#endif /* __PRELOAD_HANDLERS_DEBUGFS_H__ */
diff --git a/preload/preload_module.c b/preload/preload_module.c
deleted file mode 100644 (file)
index fd63bdf..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-#include <linux/bug.h>
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <writer/kernel_operations.h>
-#include <writer/swap_msg.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-#include <us_manager/us_common_file.h>
-#include <loader/loader.h>
-#include <master/swap_initializer.h>
-#include "preload.h"
-#include "preload_module.h"
-#include "preload_debugfs.h"
-#include "preload_control.h"
-#include "preload_threads.h"
-#include "preload_process.h"
-
-enum {
-       /* task preload flags */
-       HANDLER_RUNNING = 0x1
-};
-
-struct user_ptrs {
-       char *caller;
-       char *orig;
-       char *call_type;
-};
-
-static enum preload_status _status = PRELOAD_OFF;
-static DEFINE_MUTEX(status_change);
-
-
-static inline bool _is_enable_no_lock(void)
-{
-       return _status;
-}
-
-static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task,
-                                                      unsigned long caddr)
-{
-       struct vm_area_struct *vma = NULL;
-
-       if ((task == NULL) || (task->mm == NULL))
-               return NULL;
-       vma = find_vma_intersection(task->mm, caddr, caddr + 1);
-
-       return vma;
-}
-
-static inline bool __is_probe_non_block(struct sspt_ip *ip)
-{
-       if (ip->desc->info.pl_i.flags & SWAP_PRELOAD_NON_BLOCK_PROBE)
-               return true;
-
-       return false;
-}
-
-static inline bool __inverted(struct sspt_ip *ip)
-{
-       unsigned long flags = ip->desc->info.pl_i.flags;
-
-       if (flags & SWAP_PRELOAD_INVERTED_PROBE)
-               return true;
-
-       return false;
-}
-
-static inline bool __check_flag_and_call_type(struct sspt_ip *ip,
-                                             enum preload_call_type ct)
-{
-       bool inverted = __inverted(ip);
-
-       if (ct != NOT_INSTRUMENTED || inverted)
-               return true;
-
-       return false;
-}
-
-static inline bool __is_handlers_call(struct vm_area_struct *caller,
-                                     struct pd_t *pd)
-{
-       struct hd_t *hd;
-
-       if (caller == NULL || caller->vm_file == NULL ||
-           caller->vm_file->f_path.dentry == NULL) {
-               return false;
-       }
-
-       hd = lpd_get_hd(pd, caller->vm_file->f_path.dentry);
-       if (hd != NULL)
-               return true;
-
-       return false;
-}
-
-static inline bool __should_drop(struct sspt_ip *ip, enum preload_call_type ct)
-{
-       if (ct == NOT_INSTRUMENTED)
-               return true;
-
-       return false;
-}
-
-static inline int __msg_sanitization(char *user_msg, size_t len,
-                                    struct user_ptrs *ptrs)
-{
-       if (ptrs->caller &&
-           (ptrs->caller < user_msg || ptrs->caller > user_msg + len))
-               return -EINVAL;
-
-       if (ptrs->orig &&
-           (ptrs->orig < user_msg || ptrs->orig > user_msg + len))
-               return -EINVAL;
-
-       if (ptrs->call_type &&
-           (ptrs->call_type < user_msg || ptrs->call_type > user_msg + len))
-               return -EINVAL;
-
-       return 0;
-}
-
-
-
-
-static unsigned long __do_preload_entry(struct uretprobe_instance *ri,
-                                       struct pt_regs *regs,
-                                       struct hd_t *hd)
-{
-       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
-       unsigned long offset = ip->desc->info.pl_i.handler;
-       unsigned long vaddr = 0;
-       unsigned long base;
-       struct vm_area_struct *cvma;
-       struct pd_t *pd;
-       struct pt_data_t ptd;
-
-       base = lpd_get_handlers_base(hd);
-       if (base == 0)
-               return 0;       /* handlers isn't mapped */
-
-       /* jump to preloaded handler */
-       vaddr = base + offset;
-       ptd.caller = get_regs_ret_func(regs);
-       cvma = __get_vma_by_addr(current, ptd.caller);
-       ptd.call_type = pc_call_type(ip, (void *)ptd.caller);
-       ptd.disable_addr = __is_probe_non_block(ip) ? ip->orig_addr : 0;
-       ptd.orig = ip->orig_addr;
-       pd = lpd_get_parent_pd(hd);
-
-       /* jump only if caller is instumented and it is not a system lib -
-        * this leads to some errors
-        */
-       if (cvma != NULL && cvma->vm_file != NULL &&
-           !pc_check_dentry_is_ignored(cvma->vm_file->f_path.dentry) &&
-           __check_flag_and_call_type(ip, ptd.call_type) &&
-           !__is_handlers_call(cvma, pd)) {
-
-               ptd.drop = __should_drop(ip, ptd.call_type);
-               if (pt_set_data(current, &ptd) != 0)
-                       printk(PRELOAD_PREFIX "Error! Failed to store data for %d/%d\n",
-                              current->tgid, current->pid);
-               /* args are not changed */
-               loader_module_prepare_ujump(ri, regs, vaddr);
-               if (ptd.disable_addr == 0)
-                       pt_set_flags(current, HANDLER_RUNNING);
-       }
-
-       return vaddr;
-}
-
-static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-       struct hd_t *hd;
-       unsigned long old_pc = swap_get_upc(regs);
-       unsigned long flags = pt_get_flags(current);
-       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
-       unsigned long vaddr = 0;
-       struct dentry *dentry = ip->desc->info.pl_i.dentry;
-
-       if (dentry == NULL)
-               goto out_set_orig;
-
-       if ((flags & HANDLER_RUNNING) ||
-           pt_check_disabled_probe(current, ip->orig_addr))
-               goto out_set_orig;
-
-       hd = lpd_get_hd(pd, dentry);
-       if (hd == NULL)
-               goto out_set_orig;
-
-       if ((lpd_get_state(hd) == NOT_LOADED ||
-           lpd_get_state(hd) == FAILED) && lpd_get_init_state(pd))
-               vaddr = loader_not_loaded_entry(ri, regs, pd, hd);
-       else if (lpd_get_state(hd) == LOADED)
-               vaddr =__do_preload_entry(ri, regs, hd);
-
-out_set_orig:
-       loader_set_priv_origin(ri, vaddr);
-
-       /* PC change check */
-       return old_pc != swap_get_upc(regs);
-}
-
-static void __do_preload_ret(struct uretprobe_instance *ri, struct hd_t *hd)
-{
-       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
-       unsigned long flags = pt_get_flags(current);
-       unsigned long offset = ip->desc->info.pl_i.handler;
-       unsigned long vaddr = 0;
-
-       if ((flags & HANDLER_RUNNING) ||
-           pt_check_disabled_probe(current, ip->orig_addr)) {
-               bool non_blk_probe = __is_probe_non_block(ip);
-
-               /* drop the flag if the handler has completed */
-               vaddr = lpd_get_handlers_base(hd) + offset;
-               if (vaddr && (loader_get_priv_origin(ri) == vaddr)) {
-                       if (pt_put_data(current) != 0)
-                               printk(PRELOAD_PREFIX "Error! Failed to put "
-                                      "caller slot for %d/%d\n", current->tgid,
-                                      current->pid);
-                       if (!non_blk_probe) {
-                               flags &= ~HANDLER_RUNNING;
-                               pt_set_flags(current, flags);
-                       }
-               }
-       }
-}
-
-static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-       struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe);
-       struct dentry *dentry = ip->desc->info.pl_i.dentry;
-       struct hd_t *hd;
-
-       if (dentry == NULL)
-               return 0;
-
-       hd = lpd_get_hd(pd, dentry);
-       if (hd == NULL)
-               return 0;
-
-       switch (lpd_get_state(hd)) {
-       case NOT_LOADED:
-               /* loader has not yet been mapped... just ignore */
-               break;
-       case LOADING:
-               loader_loading_ret(ri, regs, pd, hd);
-               break;
-       case LOADED:
-               __do_preload_ret(ri, hd);
-               break;
-       case FAILED:
-               loader_failed_ret(ri, regs, pd, hd);
-               break;
-       case ERROR:
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-
-
-
-
-static void __write_data_on_demand(char *user, char *msg, size_t len,
-                                  struct user_ptrs *ptrs,
-                                  unsigned long caller_addr)
-{
-       unsigned long caller_ptr = 0, orig_ptr = 0, ct_ptr = 0;
-       unsigned long caller = 0, orig = 0;
-       unsigned char call_type = 0;
-       int ret;
-
-       /* Evaluate addresses whereto write data as:
-        * pointer from user - user buffer beggining + kernel buffer beginning
-        *  If incoming pointer is NULL - do not write
-        */
-
-       if (ptrs->orig) {
-               orig_ptr = (unsigned long)(ptrs->orig - user + msg);
-
-               ret = pt_get_orig(current, &orig);
-               if (ret) {
-                       orig = 0xbadbeef;
-                       printk(PRELOAD_PREFIX "No orig for %d/%d\n",
-                              current->tgid, current->pid);
-               }
-
-               /* Types should be the same as in preload lib!!! */
-               *(uint64_t *)orig_ptr = (uint64_t)orig;
-       }
-
-       if (caller_addr && ptrs->caller && ptrs->call_type) {
-               caller_ptr = (unsigned long)(ptrs->caller - user + msg);
-               ct_ptr = (unsigned long)(ptrs->call_type - user + msg);
-
-               caller = caller_addr;
-               call_type =
-                   pc_call_type_always_inst((void *)caller);
-
-               /* Types should be the same as in preload lib!!! */
-               *(uint64_t *)caller_ptr = (uint64_t)caller;
-               *(uint32_t *)ct_ptr = (uint32_t)call_type;
-
-               return;
-       }
-
-       if (ptrs->caller) {
-               caller_ptr = (unsigned long)(ptrs->caller - user + msg);
-
-               ret = pt_get_caller(current, &caller);
-               if (ret) {
-                       caller = 0xbadbeef;
-                       printk(PRELOAD_PREFIX "No caller for %d/%d\n",
-                              current->tgid, current->pid);
-               }
-
-               /* Types should be the same as in preload lib!!! */
-               *(uint64_t *)caller_ptr = (uint64_t)caller;
-       }
-
-       if (ptrs->call_type) {
-               ct_ptr = (unsigned long)(ptrs->call_type - user + msg);
-
-               ret = pt_get_call_type(current, &call_type);
-               if (ret) {
-                       call_type = 0xff;
-                       printk(PRELOAD_PREFIX "No call type for %d/%d\n",
-                              current->tgid, current->pid);
-               }
-
-               /* Types should be the same as in preload lib!!! */
-               *(uint32_t *)ct_ptr = (uint32_t)call_type;
-       }
-}
-
-static int write_msg_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct user_ptrs ptrs;
-       char *user_buf, *buf;
-       size_t len;
-       unsigned long caller_addr;
-       int ret;
-
-       /* FIXME: swap_get_uarg uses get_user(), it might sleep */
-       user_buf = (char *)swap_get_uarg(regs, 0);
-       len = swap_get_uarg(regs, 1);
-       ptrs.call_type = (char *)swap_get_uarg(regs, 2);
-       ptrs.caller = (char *)swap_get_uarg(regs, 3);
-       caller_addr = swap_get_uarg(regs, 4);
-       ptrs.orig = (char *)swap_get_uarg(regs, 5);
-
-       if (ptrs.caller || ptrs.call_type || ptrs.orig) {
-               ret = __msg_sanitization(user_buf, len, &ptrs);
-               if (ret != 0) {
-                       printk(PRELOAD_PREFIX "Invalid message pointers!\n");
-                       return 0;
-               }
-               ret = pt_get_drop(current);
-               if (ret > 0)
-                       return 0;
-       }
-
-       buf = kmalloc(len, GFP_ATOMIC);
-       if (buf == NULL) {
-               printk(PRELOAD_PREFIX "No mem for buffer! Size = %zd\n", len);
-               return 0;
-       }
-
-       ret = read_proc_vm_atomic(current, (unsigned long)user_buf, buf, len);
-       if (ret < 0) {
-               printk(PRELOAD_PREFIX "Cannot copy data from userspace! Size = "
-                                     "%zd ptr 0x%lx ret %d\n", len,
-                                     (unsigned long)user_buf, ret);
-               goto write_msg_fail;
-       }
-
-       __write_data_on_demand(user_buf, buf, len, &ptrs, caller_addr);
-
-       ret = swap_msg_raw(buf, len);
-       if (ret != len)
-               printk(PRELOAD_PREFIX "Error writing probe lib message\n");
-
-write_msg_fail:
-       kfree(buf);
-
-       return 0;
-}
-
-static int get_caller_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       unsigned long caller;
-       int ret;
-
-       ret = pt_get_caller(current, &caller);
-       if (ret != 0) {
-               caller = 0xbadbeef;
-               printk(PRELOAD_PREFIX "Error! Cannot get caller address for "
-                      "%d/%d\n", current->tgid, current->pid);
-       }
-
-       swap_put_uarg(regs, 0, caller);
-
-       return 0;
-}
-
-static int get_call_type_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       unsigned char call_type;
-       int ret;
-
-       ret = pt_get_call_type(current, &call_type);
-       if (ret != 0) {
-               call_type = 0xff;
-               printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n",
-                      current->tgid, current->pid);
-       }
-
-       swap_put_uarg(regs, 0, call_type);
-
-       return 0;
-}
-
-
-
-
-
-int pm_get_caller_init(struct sspt_ip *ip)
-{
-       struct uprobe *up = &ip->uprobe;
-
-       up->pre_handler = get_caller_handler;
-
-       return 0;
-}
-
-void pm_get_caller_exit(struct sspt_ip *ip)
-{
-}
-
-int pm_get_call_type_init(struct sspt_ip *ip)
-{
-       struct uprobe *up = &ip->uprobe;
-
-       up->pre_handler = get_call_type_handler;
-
-       return 0;
-}
-
-void pm_get_call_type_exit(struct sspt_ip *ip)
-{
-}
-
-int pm_write_msg_init(struct sspt_ip *ip)
-{
-       struct uprobe *up = &ip->uprobe;
-
-       up->pre_handler = write_msg_handler;
-
-       return 0;
-}
-
-void pm_write_msg_exit(struct sspt_ip *ip)
-{
-}
-
-
-
-int pm_uprobe_init(struct sspt_ip *ip)
-{
-       struct uretprobe *rp = &ip->retprobe;
-       struct dentry *dentry;
-       const char *path = ip->desc->info.pl_i.path;
-
-       rp->entry_handler = preload_us_entry;
-       rp->handler = preload_us_ret;
-
-       /* Get dentry and set it in probe info struct */
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL) {
-               pr_warn(PRELOAD_PREFIX "Error! Cannot get handler %s\n", path);
-               return -EINVAL;
-       }
-       ip->desc->info.pl_i.dentry = dentry;
-
-       /* Add handler to loader */
-       loader_add_handler(path);
-
-       /* FIXME actually additional data_size is needed only when we jump
-        * to dlopen */
-       loader_set_rp_data_size(rp);
-
-       return 0;
-}
-
-void pm_uprobe_exit(struct sspt_ip *ip)
-{
-       struct dentry *dentry = ip->desc->info.pl_i.dentry;
-
-       WARN_ON(!dentry);
-
-       if (dentry)
-               swap_put_dentry(dentry);
-}
-
-int pm_switch(enum preload_status stat)
-{
-       int ret = 0;
-
-       mutex_lock(&status_change);
-       switch (stat) {
-       case PRELOAD_ON:
-               if (_is_enable_no_lock())
-                       goto pm_switch_unlock;
-
-               ret = pp_enable();
-               if (!ret)
-                       _status = PRELOAD_ON;
-               break;
-       case PRELOAD_OFF:
-               if (!_is_enable_no_lock())
-                       goto pm_switch_unlock;
-
-               pp_disable();
-               _status = PRELOAD_OFF;
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-pm_switch_unlock:
-       mutex_unlock(&status_change);
-
-       return ret;
-}
-
-enum preload_status pm_status(void)
-{
-       enum preload_status s;
-
-       mutex_lock(&status_change);
-       s = _status;
-       mutex_unlock(&status_change);
-
-       return s;
-}
-
-static int pm_init(void)
-{
-       int ret;
-
-       ret = pd_init();
-       if (ret)
-               goto out_err;
-
-       ret = pc_init();
-       if (ret)
-               goto control_init_fail;
-
-       ret = pt_init();
-       if (ret)
-               goto threads_init_fail;
-
-       ret = register_preload_probes();
-       if (ret)
-               goto probes_register_fail;
-
-       return 0;
-
-probes_register_fail:
-       pt_exit();
-
-threads_init_fail:
-       pc_exit();
-
-control_init_fail:
-       pd_exit();
-
-out_err:
-       return ret;
-}
-
-static void pm_exit(void)
-{
-       unregister_preload_probes();
-       pt_exit();
-       pc_exit();
-       pd_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, pm_init, pm_exit, NULL, NULL);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP Preload Module");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/preload/preload_module.h b/preload/preload_module.h
deleted file mode 100644 (file)
index fd19bee..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __PRELOAD_MODULE_H__
-#define __PRELOAD_MODULE_H__
-
-struct sspt_ip;
-struct dentry;
-
-
-enum preload_status {
-       PRELOAD_ON,
-       PRELOAD_OFF
-};
-
-enum preload_status pm_status(void);
-int pm_switch(enum preload_status stat);
-
-int pm_uprobe_init(struct sspt_ip *ip);
-void pm_uprobe_exit(struct sspt_ip *ip);
-
-int pm_get_caller_init(struct sspt_ip *ip);
-void pm_get_caller_exit(struct sspt_ip *ip);
-int pm_get_call_type_init(struct sspt_ip *ip);
-void pm_get_call_type_exit(struct sspt_ip *ip);
-int pm_write_msg_init(struct sspt_ip *ip);
-void pm_write_msg_exit(struct sspt_ip *ip);
-
-#endif /* __PRELOAD_MODULE_H__ */
diff --git a/preload/preload_probe.c b/preload/preload_probe.c
deleted file mode 100644 (file)
index 3db3fd0..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/probes/preload_probe.c
- *
- * 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, 2014
- *
- * 2014         Alexander Aksenov: Preload implement
- *
- */
-
-#include <linux/module.h>
-#include <us_manager/us_manager.h>
-#include <us_manager/probes/register_probes.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <uprobe/swap_uprobes.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include "preload_probe.h"
-#include "preload.h"
-#include "preload_module.h"
-
-static int preload_info_copy(struct probe_info *dest,
-                             const struct probe_info *source)
-{
-       memcpy(dest, source, sizeof(*source));
-
-       return 0;
-}
-
-static void preload_info_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *preload_get_uprobe(struct sspt_ip *ip)
-{
-       return &ip->retprobe.up;
-}
-
-/* Registers probe if preload is 'running' or 'ready'.
- */
-static int preload_register_probe(struct sspt_ip *ip)
-{
-       return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void preload_unregister_probe(struct sspt_ip *ip, int disarm)
-{
-       __swap_unregister_uretprobe(&ip->retprobe, disarm);
-}
-
-static void preload_init(struct sspt_ip *ip)
-{
-       pm_uprobe_init(ip);
-}
-
-static void preload_uninit(struct sspt_ip *ip)
-{
-       pm_uprobe_exit(ip);
-
-       preload_info_cleanup(&ip->desc->info);
-}
-
-static struct probe_iface preload_iface = {
-       .init = preload_init,
-       .uninit = preload_uninit,
-       .reg = preload_register_probe,
-       .unreg = preload_unregister_probe,
-       .get_uprobe = preload_get_uprobe,
-       .copy = preload_info_copy,
-       .cleanup = preload_info_cleanup
-};
-
-static int get_caller_info_copy(struct probe_info *dest,
-                               const struct probe_info *source)
-{
-       memcpy(dest, source, sizeof(*source));
-
-       return 0;
-}
-
-static void get_caller_info_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *get_caller_get_uprobe(struct sspt_ip *ip)
-{
-       return &ip->uprobe;
-}
-
-static int get_caller_register_probe(struct sspt_ip *ip)
-{
-       return swap_register_uprobe(&ip->uprobe);
-}
-
-static void get_caller_unregister_probe(struct sspt_ip *ip, int disarm)
-{
-       __swap_unregister_uprobe(&ip->uprobe, disarm);
-}
-
-static void get_caller_init(struct sspt_ip *ip)
-{
-       pm_get_caller_init(ip);
-}
-
-static void get_caller_uninit(struct sspt_ip *ip)
-{
-       pm_get_caller_exit(ip);
-
-       get_caller_info_cleanup(&ip->desc->info);
-}
-
-static struct probe_iface get_caller_iface = {
-       .init = get_caller_init,
-       .uninit = get_caller_uninit,
-       .reg = get_caller_register_probe,
-       .unreg = get_caller_unregister_probe,
-       .get_uprobe = get_caller_get_uprobe,
-       .copy = get_caller_info_copy,
-       .cleanup = get_caller_info_cleanup
-};
-
-static void get_call_type_init(struct sspt_ip *ip)
-{
-       pm_get_call_type_init(ip);
-}
-
-static void get_call_type_uninit(struct sspt_ip *ip)
-{
-       pm_get_call_type_exit(ip);
-
-       get_caller_info_cleanup(&ip->desc->info);
-}
-
-static struct probe_iface get_call_type_iface = {
-       .init = get_call_type_init,
-       .uninit = get_call_type_uninit,
-       .reg = get_caller_register_probe,
-       .unreg = get_caller_unregister_probe,
-       .get_uprobe = get_caller_get_uprobe,
-       .copy = get_caller_info_copy,
-       .cleanup = get_caller_info_cleanup
-};
-
-static void write_msg_init(struct sspt_ip *ip)
-{
-       pm_write_msg_init(ip);
-}
-
-static int write_msg_reg(struct sspt_ip *ip)
-{
-       return get_caller_register_probe(ip);
-}
-
-static void write_msg_uninit(struct sspt_ip *ip)
-{
-       pm_write_msg_exit(ip);
-
-       get_caller_info_cleanup(&ip->desc->info);
-}
-
-static struct probe_iface write_msg_iface = {
-       .init = write_msg_init,
-       .uninit = write_msg_uninit,
-       .reg = write_msg_reg,
-       .unreg = get_caller_unregister_probe,
-       .get_uprobe = get_caller_get_uprobe,
-       .copy = get_caller_info_copy,
-       .cleanup = get_caller_info_cleanup
-};
-
-int register_preload_probes(void)
-{
-       int ret;
-
-       ret = swap_register_probe_type(SWAP_PRELOAD_PROBE, &preload_iface);
-       if (ret != 0)
-               return ret;
-
-       ret = swap_register_probe_type(SWAP_GET_CALLER, &get_caller_iface);
-       if (ret != 0)
-               return ret;
-
-       ret = swap_register_probe_type(SWAP_GET_CALL_TYPE, &get_call_type_iface);
-       if (ret != 0)
-               return ret;
-
-       ret = swap_register_probe_type(SWAP_WRITE_MSG, &write_msg_iface);
-
-       return ret;
-}
-
-void unregister_preload_probes(void)
-{
-       swap_unregister_probe_type(SWAP_PRELOAD_PROBE);
-       swap_unregister_probe_type(SWAP_GET_CALLER);
-       swap_unregister_probe_type(SWAP_GET_CALL_TYPE);
-       swap_unregister_probe_type(SWAP_WRITE_MSG);
-}
diff --git a/preload/preload_probe.h b/preload/preload_probe.h
deleted file mode 100644 (file)
index f068b89..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/probes/preload_probe.h
- *
- * 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, 2014
- *
- * 2014         Alexander Aksenov: FBI implement
- *
- */
-
-#ifndef __PRELOAD_HANDLERS_PROBE_H__
-#define __PRELOAD_HANDLERS_PROBE_H__
-
-/* Probe flags description:
- *
- *    0 - handler is ran only when probe has fired from a target binary;
- *    1 - handler is always ran;
- *
- *   00 - probe is disabling internal probes;
- *   10 - probe is non blocking one;
- *
- *  000 - probe is executed for instrumented binaries
- *  100 - probe is executed for non-instrumented binaries
- */
-
-enum {
-       SWAP_PRELOAD_ALWAYS_RUN =       (1 << 0),
-       SWAP_PRELOAD_NON_BLOCK_PROBE =  (1 << 1),
-       SWAP_PRELOAD_INVERTED_PROBE =   (1 << 2)
-};
-
-/* Preload probe info. */
-struct preload_info {
-       unsigned long handler;              /* Handler offset in probe library. */
-       unsigned char flags;                /* Preload probe flags. */
-       const char *path;                   /* Library with handler */
-       struct dentry *dentry;              /* Handler file dentry */
-};
-
-/* Get caller probe info */
-struct get_caller_info {
-};
-
-/* Get call type probe info */
-struct get_call_type_info {
-};
-
-/* Write message probe info */
-struct write_msg_info {
-};
-
-int register_preload_probes(void);
-void unregister_preload_probes(void);
-
-#endif /* __PRELOAD_HANDLERS_PROBE_H__ */
diff --git a/preload/preload_process.c b/preload/preload_process.c
deleted file mode 100644 (file)
index 1b777b1..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-#include <linux/err.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/namei.h>
-#include <linux/slab.h>
-#include <us_manager/us_common_file.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/probes/probe_info_new.h>
-#include <loader/loader.h>
-#include "preload.h"
-#include "preload_process.h"
-
-
-enum task_id_t {
-       SET_BY_PATH,
-       SET_BY_PID,
-       SET_BY_ID
-};
-
-struct process_t {
-       struct list_head list;
-       struct pf_group *pfg;
-       enum task_id_t idt;
-       union {
-               struct dentry *dentry;
-               pid_t pid;
-               char *id;
-       };
-       struct probe_new p_init;
-};
-
-struct bin_data_t {
-       struct dentry *dentry;
-       unsigned long off;
-};
-
-/* For process list elements checker */
-typedef struct process_t *(*checker_t)(struct process_t *, void *);
-
-static LIST_HEAD(_reg_proc_list);
-static LIST_HEAD(_unreg_proc_list);
-static DEFINE_MUTEX(_proc_list_lock);
-
-static struct bin_data_t _pthread_init;
-
-static inline void _lock_proc_list(void)
-{
-       mutex_lock(&_proc_list_lock);
-}
-
-static inline void _unlock_proc_list(void)
-{
-       mutex_unlock(&_proc_list_lock);
-}
-
-static inline struct process_t *_check_by_dentry(struct process_t *proc,
-                                                void *data)
-{
-       struct dentry *dentry = data;
-
-       if (proc->idt == SET_BY_PATH && proc->dentry == dentry)
-               return proc;
-
-       return NULL;
-}
-
-static inline struct process_t *_check_by_pid(struct process_t *proc,
-                                             void *data)
-{
-       pid_t pid = *(pid_t *)data;
-
-       if (proc->idt == SET_BY_PID && proc->pid == pid)
-               return proc;
-
-       return NULL;
-}
-
-static inline struct process_t *_check_by_id(struct process_t *proc, void *data)
-{
-       char *id = data;
-
-       if (proc->idt == SET_BY_ID && proc->id == id)
-               return proc;
-
-       return NULL;
-}
-
-static inline bool _is_pthread_data_available(void)
-{
-       return (_pthread_init.dentry && _pthread_init.off);
-}
-
-
-
-
-static int pthread_init_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-
-       lpd_set_init_state(pd, false);
-
-       return 0;
-}
-
-static int pthread_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-
-       lpd_set_init_state(pd, true);
-
-       return 0;
-}
-
-static struct probe_desc pin_pinit = MAKE_URPROBE(pthread_init_eh,
-                                                 pthread_init_rh, 0);
-
-static int _proc_reg_no_lock(struct process_t *proc)
-{
-       int ret;
-
-       proc->p_init.desc = &pin_pinit;
-       proc->p_init.offset = _pthread_init.off;
-       ret = pin_register(&proc->p_init, proc->pfg, _pthread_init.dentry);
-       if (ret)
-               pr_warn(PRELOAD_PREFIX "Can't register pthread init probe\n");
-
-       return ret;
-}
-
-static void _proc_unreg_no_lock(struct process_t *proc)
-{
-       pin_unregister(&proc->p_init, proc->pfg);
-}
-
-static struct process_t *_proc_create(struct pf_group *pfg)
-{
-       struct process_t *proc;
-
-       proc = kzalloc(sizeof(*proc), GFP_KERNEL);
-       if (!proc) {
-               pr_warn(PRELOAD_PREFIX "No mem to alloc proccess_t struct!\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       INIT_LIST_HEAD(&proc->list);
-       proc->pfg = pfg;
-
-       return proc;
-}
-
-static void _proc_destroy(struct process_t *proc)
-{
-       if (proc->pfg)
-               put_pf_group(proc->pfg);
-
-       if (proc->idt == SET_BY_PATH)
-               swap_put_dentry(proc->dentry);
-
-       if (proc->idt == SET_BY_ID)
-               kfree(proc->id);
-
-       kfree(proc);
-}
-
-static int _add_to_list(struct process_t *proc)
-{
-       _lock_proc_list();
-       list_add_tail(&proc->list, &_unreg_proc_list);
-       _unlock_proc_list();
-
-       return 0;
-}
-
-/* checker - used to check process list candidates, chosen by type of
- * registration (path, pid, id)
- * data - pointer to target process data, checker compares candidate with
- */
-
-static struct process_t *_get_from_list_no_lock(checker_t checker, void *data,
-                                               struct list_head *list)
-{
-       struct process_t *proc;
-
-       list_for_each_entry(proc, list, list) {
-               if (checker(proc, data))
-                       return proc;
-       }
-
-       return NULL;
-}
-
-static void _delete_from_list(checker_t checker, void *data)
-{
-       struct process_t *proc;
-
-       _lock_proc_list();
-       proc = _get_from_list_no_lock(checker, data, &_unreg_proc_list);
-       if (proc) {
-               list_del(&proc->list);
-               _proc_destroy(proc);
-               goto delete_from_list_unlock;
-       }
-
-       proc = _get_from_list_no_lock(checker, data, &_reg_proc_list);
-       if (proc) {
-               list_del(&proc->list);
-               _proc_unreg_no_lock(proc);
-               _proc_destroy(proc);
-       }
-
-delete_from_list_unlock:
-       _unlock_proc_list();
-}
-
-
-
-int pp_add_by_path(const char *path)
-{
-       struct dentry *dentry;
-       struct pf_group *pfg;
-       struct process_t *proc;
-       int ret;
-
-       dentry = swap_get_dentry(path);
-       if (!dentry) {
-               pr_warn(PRELOAD_PREFIX "Can't get dentry for <%s>\n", path);
-               return -EINVAL;
-       }
-
-       pfg = get_pf_group_by_dentry(dentry, dentry);
-       if (pfg == NULL) {
-               ret = -ENOMEM;
-               goto by_path_put_dentry;
-       }
-
-       proc = _proc_create(pfg);
-       if (!proc) {
-               ret = -EINVAL;
-               goto by_path_put_pfg;
-       }
-
-       proc->idt = SET_BY_PATH;
-       proc->dentry = dentry;
-
-       ret = _add_to_list(proc);
-       if (ret)
-               goto by_path_free;
-
-       return 0;
-
-by_path_free:
-       kfree(proc);
-
-by_path_put_pfg:
-       put_pf_group(pfg);
-
-by_path_put_dentry:
-       swap_put_dentry(dentry);
-
-       return ret;
-}
-
-int pp_add_by_pid(pid_t pid)
-{
-       struct pf_group *pfg;
-       struct process_t *proc;
-       int ret;
-
-       pfg = get_pf_group_by_tgid(pid, NULL);
-       if (pfg == NULL)
-               return -ENOMEM;
-
-       proc = _proc_create(pfg);
-       if (!proc) {
-               ret = -EINVAL;
-               goto by_pid_put_pfg;
-       }
-
-       proc->idt = SET_BY_PID;
-       proc->pid = pid;
-
-       ret = _add_to_list(proc);
-       if (ret)
-               goto by_pid_free;
-
-       return 0;
-
-by_pid_free:
-       kfree(proc);
-
-by_pid_put_pfg:
-       put_pf_group(pfg);
-
-       return ret;
-}
-
-int pp_add_by_id(const char *id)
-{
-       char *new_id;
-       struct pf_group *pfg;
-       struct process_t *proc;
-       int ret;
-
-       new_id = kstrdup(id, GFP_KERNEL);
-       if (!new_id)
-               return -ENOMEM;
-
-       pfg = get_pf_group_by_comm((char *)id, NULL);
-       if (pfg == NULL) {
-               ret = -ENOMEM;
-               goto by_id_free_new_id;
-       }
-
-       proc = _proc_create(pfg);
-       if (!proc) {
-               ret = -EINVAL;
-               goto by_id_put_pfg;
-       }
-
-       proc->idt = SET_BY_ID;
-       proc->id = new_id;
-
-       ret = _add_to_list(proc);
-       if (ret)
-               goto by_id_free;
-
-       return 0;
-
-by_id_free:
-       kfree(proc);
-
-by_id_put_pfg:
-       put_pf_group(pfg);
-
-by_id_free_new_id:
-       kfree(new_id);
-
-       return ret;
-}
-
-int pp_del_by_path(const char *path)
-{
-       struct dentry *dentry;
-
-       dentry = swap_get_dentry(path);
-       if (!dentry) {
-               pr_warn(PRELOAD_PREFIX "No dentry for <%s>\n", path);
-               return -EINVAL;
-       }
-
-       _delete_from_list(_check_by_dentry, dentry);
-
-       swap_put_dentry(dentry);
-
-       return 0;
-}
-
-int pp_del_by_pid(pid_t pid)
-{
-       _delete_from_list(_check_by_pid, &pid);
-
-       return 0;
-}
-
-int pp_del_by_id(const char *id)
-{
-       _delete_from_list(_check_by_id, (void *)id);
-
-       return 0;
-}
-
-void pp_del_all(void)
-{
-       struct process_t *tmp, *proc;
-
-       _lock_proc_list();
-
-       list_for_each_entry_safe(proc, tmp, &_unreg_proc_list, list) {
-               list_del(&proc->list);
-               _proc_destroy(proc);
-       }
-
-       list_for_each_entry_safe(proc, tmp, &_reg_proc_list, list) {
-               list_del(&proc->list);
-               _proc_unreg_no_lock(proc);
-               _proc_destroy(proc);
-       }
-
-       _unlock_proc_list();
-}
-
-void pp_disable(void)
-{
-       struct process_t *proc;
-
-       _lock_proc_list();
-
-       list_for_each_entry(proc, &_reg_proc_list, list) {
-               _proc_unreg_no_lock(proc);
-               list_move_tail(&proc->list, &_unreg_proc_list);
-       }
-
-       _unlock_proc_list();
-}
-
-int pp_enable(void)
-{
-       struct process_t *proc;
-       int ret;
-
-       if (!_is_pthread_data_available())
-               return -EINVAL;
-
-       _lock_proc_list();
-
-       list_for_each_entry(proc, &_unreg_proc_list, list) {
-               ret = _proc_reg_no_lock(proc);
-               if (ret)
-                       goto enable_pp_fail;
-               else
-                       list_move_tail(&proc->list, &_reg_proc_list);
-       }
-
-       _unlock_proc_list();
-
-       return 0;
-
-enable_pp_fail:
-       _unlock_proc_list();
-
-       pr_warn(PRELOAD_PREFIX "Error register probes, disabling...\n");
-       pp_disable();
-
-       return ret;
-}
-
-int pp_set_pthread_path(const char *path)
-{
-       struct dentry *dentry;
-
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL)
-               return -EINVAL;
-
-       if (_pthread_init.dentry != NULL)
-               swap_put_dentry(_pthread_init.dentry);
-
-       _pthread_init.dentry = dentry;
-
-       return 0;
-}
-
-int pp_set_init_offset(unsigned long off)
-{
-       _pthread_init.off = off;
-
-       return 0;
-}
diff --git a/preload/preload_process.h b/preload/preload_process.h
deleted file mode 100644 (file)
index 5799f9c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __PRELOAD_PROCESS_H__
-#define __PRELOAD_PROCESS_H__
-
-int pp_add_by_path(const char *path);
-int pp_add_by_pid(pid_t pid);
-int pp_add_by_id(const char *id);
-
-int pp_del_by_path(const char *path);
-int pp_del_by_pid(pid_t pid);
-int pp_del_by_id(const char *id);
-void pp_del_all(void);
-
-int pp_enable(void);
-void pp_disable(void);
-
-int pp_set_pthread_path(const char *path);
-int pp_set_init_offset(unsigned long off);
-
-#endif /* __PRELOAD_PROCESS_H__ */
diff --git a/preload/preload_threads.c b/preload/preload_threads.c
deleted file mode 100644 (file)
index 1d49d6b..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/list.h>
-#include <kprobe/swap_ktd.h>
-#include "preload.h"
-#include "preload_threads.h"
-
-struct preload_td {
-       struct list_head slots;
-       unsigned long flags;
-};
-
-struct thread_slot {
-       struct list_head list;
-       struct list_head disabled_addrs;
-
-       unsigned long caller;
-       unsigned long orig;
-       unsigned char call_type;
-       bool drop;   /* TODO Workaround, remove when will be possible to install
-                     * several us probes at the same addr. */
-};
-
-struct disabled_addr {
-       struct list_head list;
-       unsigned long addr;
-};
-
-static void preload_ktd_init(struct task_struct *task, void *data)
-{
-       struct preload_td *td = (struct preload_td *)data;
-
-       INIT_LIST_HEAD(&td->slots);
-       td->flags = 0;
-}
-
-static void preload_ktd_exit(struct task_struct *task, void *data)
-{
-       /* TODO: to be implement */
-}
-
-static struct ktask_data preload_ktd = {
-       .init = preload_ktd_init,
-       .exit = preload_ktd_exit,
-       .size = sizeof(struct preload_td),
-};
-
-
-static inline struct preload_td *get_preload_td(struct task_struct *task)
-{
-       return (struct preload_td *)swap_ktd(&preload_ktd, task);
-}
-
-unsigned long pt_get_flags(struct task_struct *task)
-{
-       return get_preload_td(task)->flags;
-}
-
-void pt_set_flags(struct task_struct *task, unsigned long flags)
-{
-       get_preload_td(task)->flags = flags;
-}
-
-
-static inline bool __is_addr_found(struct disabled_addr *da,
-                                  unsigned long addr)
-{
-       if (da->addr == addr)
-               return true;
-
-       return false;
-}
-
-static inline void __remove_from_disable_list(struct disabled_addr *da)
-{
-       list_del(&da->list);
-       kfree(da);
-}
-
-static inline void __remove_whole_disable_list(struct thread_slot *slot)
-{
-       struct disabled_addr *da, *n;
-
-       list_for_each_entry_safe(da, n, &slot->disabled_addrs, list)
-               __remove_from_disable_list(da);
-}
-
-static inline void __init_slot(struct thread_slot *slot)
-{
-       slot->caller = 0;
-       slot->orig = 0;
-       slot->call_type = 0;
-       slot->drop = false;
-       INIT_LIST_HEAD(&slot->disabled_addrs);
-}
-
-static inline void __reinit_slot(struct thread_slot *slot)
-{
-       __remove_whole_disable_list(slot);
-       __init_slot(slot);
-}
-
-static inline void __set_slot(struct thread_slot *slot,
-                             struct task_struct *task, unsigned long caller,
-                             unsigned long orig, unsigned char call_type,
-                             bool drop)
-{
-       slot->caller = caller;
-       slot->orig = orig;
-       slot->call_type = call_type;
-       slot->drop = drop;
-}
-
-static inline int __add_to_disable_list(struct thread_slot *slot,
-                                       unsigned long disable_addr)
-{
-       struct disabled_addr *da = kmalloc(sizeof(*da), GFP_ATOMIC);
-
-       if (da == NULL)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&da->list);
-       da->addr = disable_addr;
-       list_add_tail(&da->list, &slot->disabled_addrs);
-
-       return 0;
-}
-
-static inline struct disabled_addr *__find_disabled_addr(struct thread_slot *slot,
-                                                        unsigned long addr)
-{
-       struct disabled_addr *da;
-
-       list_for_each_entry(da, &slot->disabled_addrs, list)
-               if (__is_addr_found(da, addr))
-                       return da;
-
-       return NULL;
-}
-
-/* Adds a new slot */
-static inline struct thread_slot *__grow_slot(void)
-{
-       struct thread_slot *tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
-
-       if (tmp == NULL)
-               return NULL;
-
-       INIT_LIST_HEAD(&tmp->list);
-       __init_slot(tmp);
-
-       return tmp;
-}
-
-/* Free slot */
-static void __clean_slot(struct thread_slot *slot)
-{
-       list_del(&slot->list);
-       kfree(slot);
-}
-
-/* There is no list_last_entry in Linux 3.10 */
-#ifndef list_last_entry
-#define list_last_entry(ptr, type, member) \
-       list_entry((ptr)->prev, type, member)
-#endif /* list_last_entry */
-
-static inline struct thread_slot *__get_task_slot(struct task_struct *task)
-{
-       struct preload_td *td = get_preload_td(task);
-
-       return list_empty(&td->slots) ? NULL :
-               list_last_entry(&td->slots, struct thread_slot, list);
-}
-
-
-
-
-int pt_set_data(struct task_struct *task, struct pt_data_t *data)
-{
-       struct preload_td *td = get_preload_td(task);
-       struct thread_slot *slot;
-       unsigned long caller, disable_addr, orig;
-       unsigned char call_type;
-       bool drop;
-       int ret = 0;
-
-       caller = data->caller;
-       disable_addr = data->disable_addr;
-       orig = data->orig;
-       call_type = data->call_type;
-       drop = data->drop;
-
-       slot = __grow_slot();
-       if (slot == NULL) {
-               ret = -ENOMEM;
-               goto set_data_done;
-       }
-
-       if ((disable_addr != 0) &&
-           (__add_to_disable_list(slot, disable_addr) != 0)) {
-               printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc memory!\n");
-               ret = -ENOMEM;
-               goto set_data_done;
-       }
-
-       __set_slot(slot, task, caller, orig, call_type, drop);
-       list_add_tail(&slot->list, &td->slots);
-
-set_data_done:
-       return ret;
-}
-
-int pt_get_caller(struct task_struct *task, unsigned long *caller)
-{
-       struct thread_slot *slot;
-
-       slot = __get_task_slot(task);
-       if (slot != NULL) {
-               *caller = slot->caller;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-int pt_get_orig(struct task_struct *task, unsigned long *orig)
-{
-       struct thread_slot *slot;
-
-       slot = __get_task_slot(task);
-       if (slot != NULL) {
-               *orig = slot->caller;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-int pt_get_call_type(struct task_struct *task,
-                                 unsigned char *call_type)
-{
-       struct thread_slot *slot;
-
-       slot = __get_task_slot(task);
-       if (slot != NULL) {
-               *call_type = slot->call_type;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-int pt_get_drop(struct task_struct *task)
-{
-       struct thread_slot *slot;
-
-       slot = __get_task_slot(task);
-       if (slot != NULL)
-               return (int)slot->drop;
-
-       return -EINVAL;
-}
-
-bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr)
-{
-       struct thread_slot *slot;
-       bool ret = false;
-
-       slot = __get_task_slot(task);
-       if (slot != NULL)
-               ret = __find_disabled_addr(slot, addr) == NULL ? false : true;
-
-       return ret;
-}
-
-void pt_enable_probe(struct task_struct *task, unsigned long addr)
-{
-       struct thread_slot *slot;
-       struct disabled_addr *da;
-
-       slot = __get_task_slot(task);
-       if (slot == NULL) {
-               printk(KERN_ERR PRELOAD_PREFIX "Error! Slot not found!\n");
-               goto enable_probe_failed;
-       }
-
-       da = __find_disabled_addr(slot, addr);
-       if (da != NULL)
-               __remove_from_disable_list(da);
-
-enable_probe_failed:
-       return; /* make gcc happy: cannot place label right before '}' */
-}
-
-int pt_put_data(struct task_struct *task)
-{
-       struct thread_slot *slot;
-       int ret = 0;
-
-       slot = __get_task_slot(task);
-       if (slot != NULL) {
-               __reinit_slot(slot);
-               __clean_slot(slot); /* remove from list */
-       }
-
-       return ret;
-}
-
-int pt_init(void)
-{
-       return swap_ktd_reg(&preload_ktd);
-}
-
-void pt_exit(void)
-{
-       swap_ktd_unreg(&preload_ktd);
-}
diff --git a/preload/preload_threads.h b/preload/preload_threads.h
deleted file mode 100644 (file)
index 43844c7..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __PRELOAD_HANDLERS_THREADS_H__
-#define __PRELOAD_HANLDERS_THREADS_H__
-
-struct task_struct;
-
-struct pt_data_t {
-       unsigned long caller;
-       unsigned long disable_addr;
-       unsigned long orig;
-       unsigned char call_type;
-       bool drop;
-};
-
-unsigned long pt_get_flags(struct task_struct *task);
-void pt_set_flags(struct task_struct *task, unsigned long flags);
-
-int pt_set_data(struct task_struct *task, struct pt_data_t *data);
-
-int pt_get_caller(struct task_struct *task, unsigned long *caller);
-int pt_get_orig(struct task_struct *task, unsigned long *orig);
-int pt_get_call_type(struct task_struct *task, unsigned char *call_type);
-int pt_get_drop(struct task_struct *task);
-bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr);
-
-void pt_enable_probe(struct task_struct *task, unsigned long addr);
-int pt_put_data(struct task_struct *task);
-int pt_init(void);
-void pt_exit(void);
-
-#endif /* __PRELOAD_HANDLERS_THREADS_H__ */
diff --git a/retprobe/Kbuild b/retprobe/Kbuild
deleted file mode 100644 (file)
index c61030c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_retprobe.o
-swap_retprobe-y := \
-    retprobe.o \
-    rp_msg.o
diff --git a/retprobe/retprobe.c b/retprobe/retprobe.c
deleted file mode 100644 (file)
index db5b75a..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/retprobe/retprobe.c
- *
- * 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, 2014
- *
- * 2014         Alexander Aksenov: Probes interface implement
- *
- */
-
-#include "retprobe.h"
-#include <us_manager/us_manager.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/probes/register_probes.h>
-#include <uprobe/swap_uprobes.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include "rp_msg.h"
-
-
-static int retprobe_copy(struct probe_info *dest,
-                        const struct probe_info *source)
-{
-       size_t len;
-
-       memcpy(dest, source, sizeof(*source));
-
-       len = strlen(source->rp_i.args) + 1;
-       dest->rp_i.args = kmalloc(len, GFP_ATOMIC);
-       if (dest->rp_i.args == NULL)
-               return -ENOMEM;
-       memcpy(dest->rp_i.args, source->rp_i.args, len);
-
-       return 0;
-}
-
-
-static void retprobe_cleanup(struct probe_info *probe_i)
-{
-       kfree(probe_i->rp_i.args);
-}
-
-
-
-static struct uprobe *retprobe_get_uprobe(struct sspt_ip *ip)
-{
-       return &ip->retprobe.up;
-}
-
-static int retprobe_register_probe(struct sspt_ip *ip)
-{
-       return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void retprobe_unregister_probe(struct sspt_ip *ip, int disarm)
-{
-       __swap_unregister_uretprobe(&ip->retprobe, disarm);
-}
-
-
-static int retprobe_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct uretprobe *rp = ri->rp;
-
-       if (rp && get_quiet() == QT_OFF) {
-               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
-               const char *fmt = ip->desc->info.rp_i.args;
-               const unsigned long func_addr = (unsigned long)ip->orig_addr;
-
-               rp_msg_entry(regs, func_addr, fmt);
-       }
-
-       return 0;
-}
-
-static int retprobe_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct uretprobe *rp = ri->rp;
-
-       if (rp && get_quiet() == QT_OFF) {
-               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
-               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->desc->info.rp_i.ret_type;
-
-               rp_msg_exit(regs, func_addr, ret_type, ret_addr);
-       }
-
-       return 0;
-}
-
-static void retprobe_init(struct sspt_ip *ip)
-{
-       ip->retprobe.entry_handler = retprobe_entry_handler;
-       ip->retprobe.handler = retprobe_ret_handler;
-       ip->retprobe.maxactive = 0;
-}
-
-static void retprobe_uninit(struct sspt_ip *ip)
-{
-       retprobe_cleanup(&ip->desc->info);
-}
-
-
-static struct probe_iface retprobe_iface = {
-       .init = retprobe_init,
-       .uninit = retprobe_uninit,
-       .reg = retprobe_register_probe,
-       .unreg = retprobe_unregister_probe,
-       .get_uprobe = retprobe_get_uprobe,
-       .copy = retprobe_copy,
-       .cleanup = retprobe_cleanup
-};
-
-static int __init retprobe_module_init(void)
-{
-       return swap_register_probe_type(SWAP_RETPROBE, &retprobe_iface);
-}
-
-static void __exit retprobe_module_exit(void)
-{
-       swap_unregister_probe_type(SWAP_RETPROBE);
-}
-
-module_init(retprobe_module_init);
-module_exit(retprobe_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP retprobe");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/retprobe/retprobe.h b/retprobe/retprobe.h
deleted file mode 100644 (file)
index 7a82781..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/probes/uretprobe.h
- *
- * 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, 2014
- *
- * 2014         Alexander Aksenov: Probes interface implement
- *
- */
-
-#ifndef __URETPROBE_H__
-#define __URETPROBE_H__
-
-/* Common retprobe info */
-struct retprobe_info {
-       char *args;
-       char ret_type;
-};
-
-#endif /* __URETPROBE_H__ */
diff --git a/retprobe/rp_msg.c b/retprobe/rp_msg.c
deleted file mode 100644 (file)
index 3fb4426..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <writer/swap_msg.h>
-#include <writer/kernel_operations.h>
-#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 = raw_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);
-}
-EXPORT_SYMBOL_GPL(rp_msg_entry);
-
-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 = raw_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);
-}
-EXPORT_SYMBOL_GPL(rp_msg_exit);
diff --git a/retprobe/rp_msg.h b/retprobe/rp_msg.h
deleted file mode 100644 (file)
index a2e3b28..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#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/sampler/Kbuild b/sampler/Kbuild
deleted file mode 100644 (file)
index f948655..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../writer/Module.symvers
-
-obj-m := swap_sampler.o
-swap_sampler-y := swap_sampler_module.o
-
-ifdef CONFIG_HIGH_RES_TIMERS
-    swap_sampler-y += sampler_hrtimer.o
-else
-    swap_sampler-y += sampler_timer.o
-endif
diff --git a/sampler/kernel_operations.h b/sampler/kernel_operations.h
deleted file mode 100644 (file)
index 04d8fa9..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @file sampler/kernel_operations.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Parser definitions.
- */
-
-#ifndef __KERNEL_OPERATIONS_H__
-#define __KERNEL_OPERATIONS_H__
-
-#include <linux/kernel.h>
-
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
-       printk(KERN_DEBUG "SWAP_SAMPLER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...)   \
-       printk(KERN_INFO "SWAP_SAMPLER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...)  \
-       printk(KERN_WARNING "SWAP_SAMPLER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...)   \
-       printk(KERN_ERR "SWAP_SAMPLER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...)  \
-       printk(KERN_CRIT "SWAP_SAMPLER CRITICAL : " msg, ##args)
-
-#endif /* __KERNEL_OPERATIONS_H__ */
diff --git a/sampler/sampler_hrtimer.c b/sampler/sampler_hrtimer.c
deleted file mode 100644 (file)
index b445212..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * sampler/sampler_hrtimer.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Sampler for high resolution timers.
- */
-
-
-
-#include <linux/types.h>
-#include <linux/version.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include "sampler_timers.h"
-
-
-static u64 sampler_timer_quantum;
-static DEFINE_PER_CPU(struct hrtimer, swap_hrtimer);
-static int swap_hrtimer_running;
-
-/**
- * @brief Restarts sampling.
- *
- * @param timer Pointer to hrtimer struct.
- * @return hrtimer_restart flag.
- */
-restart_ret sampler_timers_restart(swap_timer *timer)
-{
-       restart_ret ret;
-
-       hrtimer_forward_now(timer, ns_to_ktime(sampler_timer_quantum));
-       ret = HRTIMER_RESTART;
-
-       return ret;
-}
-
-/**
- * @brief Sets running flag true.
- *
- * @return Void.
- */
-void sampler_timers_set_run(void)
-{
-       swap_hrtimer_running = 1;
-}
-
-/**
- * @brief Sets running flag false.
- *
- * @return Void.
- */
-void sampler_timers_set_stop(void)
-{
-       swap_hrtimer_running = 0;
-}
-
-/**
- * @brief Starts timer sampling.
- *
- * @param restart_func Pointer to restart function.
- * @return Void.
- */
-void sampler_timers_start(void *restart_func)
-{
-       struct hrtimer *hrtimer = &__get_cpu_var(swap_hrtimer);
-
-       if (!swap_hrtimer_running)
-               return;
-
-       hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hrtimer->function = restart_func;
-       hrtimer_start(hrtimer, ns_to_ktime(sampler_timer_quantum),
-                 HRTIMER_MODE_REL_PINNED);
-}
-
-/**
- * @brief Stops timer sampling.
- *
- * @param cpu Online CPUs.
- * @return Void.
- */
-void sampler_timers_stop(int cpu)
-{
-       struct hrtimer *hrtimer = &per_cpu(swap_hrtimer, cpu);
-
-       if (!swap_hrtimer_running)
-               return;
-
-       hrtimer_cancel(hrtimer);
-}
-
-/**
- * @brief Sets timer quantum.
- *
- * @param timer_quantum Timer quantum.
- * @return Void.
- */
-void sampler_timers_set_quantum(unsigned int timer_quantum)
-{
-       u64 tmp = (u64)timer_quantum;
-       sampler_timer_quantum = tmp * 1000 * 1000;
-}
diff --git a/sampler/sampler_timer.c b/sampler/sampler_timer.c
deleted file mode 100644 (file)
index 6a86ac8..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * sampler/sampler_timer.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Sampler based on common timers.
- */
-
-
-
-#include "sampler_timers.h"
-
-
-
-static unsigned long sampler_timer_quantum;
-static DEFINE_PER_CPU(struct timer_list, swap_timer);
-static int swap_timer_running;
-
-/**
- * @brief Restarts sampling.
- *
- * @param timer Pointer to timer_list struct.
- * @return 0.
- */
-restart_ret sampler_timers_restart(swap_timer *timer)
-{
-       restart_ret ret;
-
-       mod_timer_pinned((struct timer_list *)timer,
-                    jiffies + sampler_timer_quantum);
-       ret = 0;
-
-       return ret;
-}
-
-/**
- * @brief Sets running flag true.
- *
- * @return Void.
- */
-void sampler_timers_set_run(void)
-{
-       swap_timer_running = 1;
-}
-
-/**
- * @brief Sets running flag false.
- *
- * @return Void.
- */
-void sampler_timers_set_stop(void)
-{
-       swap_timer_running = 0;
-}
-
-/**
- * @brief Starts timer sampling.
- *
- * @param restart_func Pointer to restart function.
- * @return Void.
- */
-void sampler_timers_start(void *restart_func)
-{
-       struct timer_list *timer = &__get_cpu_var(swap_timer);
-
-       if (!swap_timer_running)
-               return;
-
-       init_timer(timer);
-       timer->data = (unsigned long)timer;
-       timer->function = restart_func;
-
-       mod_timer_pinned(timer, jiffies + sampler_timer_quantum);
-}
-
-/**
- * @brief Stops timer sampling.
- *
- * @param cpu Online CPUs.
- * @return Void.
- */
-void sampler_timers_stop(int cpu)
-{
-       struct timer_list *timer = &per_cpu(swap_timer, cpu);
-
-       if (!swap_timer_running)
-               return;
-       del_timer_sync(timer);
-}
-
-/**
- * @brief Sets timer quantum.
- *
- * @param timer_quantum Timer quantum.
- * @return Void.
- */
-void sampler_timers_set_quantum(unsigned int timer_quantum)
-{
-       sampler_timer_quantum = timer_quantum;
-}
diff --git a/sampler/sampler_timers.h b/sampler/sampler_timers.h
deleted file mode 100644 (file)
index e9b83d2..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *  SWAP sampler
- *  modules/sampler/sampler_timers.h
- *
- * 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, 2013
- *
- * 2013         Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
- *
- */
-
-
-
-#ifndef __SAMPLER_TIMERS_H__
-#define __SAMPLER_TIMERS_H__
-
-
-/* ===================== INCLUDE ==================== */
-
-#if defined(CONFIG_HIGH_RES_TIMERS)
-
-#include <linux/hrtimer.h>
-
-#else /* CONFIG_HIGH_RES_TIMERS */
-
-#include <linux/timer.h>
-
-#endif /* CONFIG_HIGH_RES_TIMERS */
-
-/* ==================== TYPE DEFS =================== */
-
-#if defined(CONFIG_HIGH_RES_TIMERS)
-
-typedef struct hrtimer   swap_timer;
-typedef enum hrtimer_restart   restart_ret;
-
-#else /* CONFIG_HIGH_RES_TIMERS */
-
-typedef struct timer_list   swap_timer;
-typedef int   restart_ret;
-
-#endif /* CONFIG_HIGH_RES_TIMERS */
-
-
-/* ====================== FUNCS ===================== */
-
-restart_ret sampler_timers_restart(swap_timer *timer);
-void sampler_timers_stop(int cpu);
-void sampler_timers_start(void *unused);
-void sampler_timers_set_quantum(unsigned int timer_quantum);
-void sampler_timers_set_run(void);
-void sampler_timers_set_stop(void);
-
-#endif /* __SAMPLER_TIMERS_H__ */
diff --git a/sampler/swap_sampler_errors.h b/sampler/swap_sampler_errors.h
deleted file mode 100644 (file)
index d673b4d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @file sampler/swap_sampler_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Sampler error codes.
- */
-
-
-/**
- * @enum _swap_sampler_errors
- * @brief Sampler errors.
- */
-enum _swap_sampler_errors {
-       E_SS_SUCCESS = 0,           /**< Success. */
-       E_SS_WRONG_QUANTUM = 1      /**< Wrong timer quantum set. */
-};
diff --git a/sampler/swap_sampler_module.c b/sampler/swap_sampler_module.c
deleted file mode 100644 (file)
index 94cb506..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * sampler/swap_sampler_module.c
- * @author Andreev S.V.: SWAP Sampler implementation
- * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
- *
- * @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
- *
- * Timer-based sampling module.
- */
-
-#include <linux/ptrace.h>
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <linux/module.h>
-
-#include "swap_sampler_module.h"
-#include "swap_sampler_errors.h"
-#include "kernel_operations.h"
-#include "sampler_timers.h"
-
-
-static BLOCKING_NOTIFIER_HEAD(swap_sampler_notifier_list);
-static swap_sample_cb_t sampler_cb;
-
-static restart_ret swap_timer_restart(swap_timer *timer)
-{
-       sampler_cb(task_pt_regs(current));
-
-       return sampler_timers_restart(timer);
-}
-
-static int swap_timer_start(void)
-{
-       get_online_cpus();
-       sampler_timers_set_run();
-
-       on_each_cpu(sampler_timers_start, swap_timer_restart, 1);
-       put_online_cpus();
-
-       return E_SS_SUCCESS;
-}
-
-static void swap_timer_stop(void)
-{
-       int cpu;
-
-       get_online_cpus();
-
-       for_each_online_cpu(cpu)
-               sampler_timers_stop(cpu);
-       sampler_timers_set_stop();
-       put_online_cpus();
-}
-
-static int swap_cpu_notify(struct notifier_block *self,
-                                   unsigned long action, void *hcpu)
-{
-       long cpu = (long) hcpu;
-
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               smp_call_function_single(cpu, sampler_timers_start,
-                                swap_timer_restart, 1);
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               sampler_timers_stop(cpu);
-               break;
-       }
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata swap_cpu_notifier = {
-       .notifier_call = swap_cpu_notify,
-};
-
-static int do_swap_sampler_start(unsigned int timer_quantum)
-{
-       if (timer_quantum <= 0)
-               return -EINVAL;
-
-       sampler_timers_set_quantum(timer_quantum);
-       swap_timer_start();
-
-       return 0;
-}
-
-static void do_swap_sampler_stop(void)
-{
-       swap_timer_stop();
-}
-
-static DEFINE_MUTEX(mutex_run);
-static int sampler_run;
-
-
-/**
- * @brief Starts sampling with specified timer quantum.
- *
- * @param timer_quantum Timer quantum for sampling.
- * @return 0 on success, error code on error.
- */
-int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb)
-{
-       int ret = -EINVAL;
-
-       mutex_lock(&mutex_run);
-       if (sampler_run) {
-               printk(KERN_INFO "sampler profiling is already run!\n");
-               goto unlock;
-       }
-
-       sampler_cb = cb;
-
-       ret = do_swap_sampler_start(timer_quantum);
-       if (ret == 0)
-               sampler_run = 1;
-
-unlock:
-       mutex_unlock(&mutex_run);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_sampler_start);
-
-
-/**
- * @brief Stops sampling.
- *
- * @return 0 on success, error code on error.
- */
-int swap_sampler_stop(void)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_run);
-       if (sampler_run == 0) {
-               printk(KERN_INFO "energy profiling is not running!\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       do_swap_sampler_stop();
-
-       sampler_run = 0;
-unlock:
-       mutex_unlock(&mutex_run);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_sampler_stop);
-
-static int __init sampler_init(void)
-{
-       int retval;
-
-       retval = register_hotcpu_notifier(&swap_cpu_notifier);
-       if (retval) {
-               print_err("Error of register_hotcpu_notifier()\n");
-               return retval;
-       }
-
-       print_msg("Sample ininitialization success\n");
-
-       return E_SS_SUCCESS;
-}
-
-static void __exit sampler_exit(void)
-{
-       if (sampler_run)
-               do_swap_sampler_stop();
-
-       unregister_hotcpu_notifier(&swap_cpu_notifier);
-
-       print_msg("Sampler uninitialized\n");
-}
-
-module_init(sampler_init);
-module_exit(sampler_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP sampling module");
-MODULE_AUTHOR("Andreev S.V., Aksenov A.S.");
diff --git a/sampler/swap_sampler_module.h b/sampler/swap_sampler_module.h
deleted file mode 100644 (file)
index 7c0ef7d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @file sampler/swap_sampler_module.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Sampling module interface declaration.
- */
-
-
-/* SWAP Sampler interface */
-
-#ifndef __SWAP_SAMPLER_MODULE_H__
-#define __SWAP_SAMPLER_MODULE_H__
-
-
-typedef void (*swap_sample_cb_t)(struct pt_regs *);
-
-
-/* Starts the SWAP Sampler */
-int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb);
-
-/* Stops the SWAP Sampler */
-int swap_sampler_stop(void);
-
-#endif /* __SWAP_SAMPLER_MODULE_H__ */
diff --git a/task_ctx/Kbuild b/task_ctx/Kbuild
deleted file mode 100644 (file)
index b90f7a6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers
-
-obj-m := swap_taskctx.o
-swap_taskctx-y := task_ctx.o
diff --git a/task_ctx/task_ctx.c b/task_ctx/task_ctx.c
deleted file mode 100644 (file)
index cfd54f1..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/kconfig.h>
-#include <linux/completion.h>
-#include <ksyms/ksyms.h>
-#include <kprobe/swap_ktd.h>
-#include <master/swap_initializer.h>
-#include "task_ctx.h"
-
-
-enum { WAIT_TIMEOUT = 1500 };  /* max waiting time the signal delivery */
-
-struct call_task {
-       taskctx_t func;
-       void *data;
-
-       bool is_running;
-       struct completion comp0;
-       struct completion comp1;
-};
-
-
-static void (*swap_signal_wake_up_state)(struct task_struct *t,
-                                        unsigned int state);
-
-static struct sighand_struct *swap_lock_task_sighand(struct task_struct *tsk,
-                                                    unsigned long *flags)
-{
-       struct sighand_struct *sighand;
-
-       for (;;) {
-               local_irq_save(*flags);
-               rcu_read_lock();
-
-               sighand = rcu_dereference(tsk->sighand);
-               if (unlikely(sighand == NULL)) {
-                       rcu_read_unlock();
-                       local_irq_restore(*flags);
-                       break;
-               }
-
-               spin_lock(&sighand->siglock);
-               if (likely(sighand == tsk->sighand)) {
-                       rcu_read_unlock();
-                       break;
-               }
-               spin_unlock(&sighand->siglock);
-
-               rcu_read_unlock();
-               local_irq_restore(*flags);
-       }
-
-       return sighand;
-}
-
-static inline void swap_unlock_task_sighand(struct task_struct *tsk,
-                                           unsigned long *flags)
-{
-        spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
-}
-
-static int fake_signal_wake_up(struct task_struct *p)
-{
-       unsigned long flags;
-
-       if (swap_lock_task_sighand(p, &flags) == NULL)
-               return -ESRCH;
-
-       swap_signal_wake_up_state(p, 0);
-       swap_unlock_task_sighand(p, &flags);
-
-       return 0;
-}
-
-
-static void ktd_init(struct task_struct *task, void *data)
-{
-       struct call_task **call = (struct call_task **)data;
-
-       *call = NULL;
-}
-
-static void ktd_exit(struct task_struct *task, void *data)
-{
-       struct call_task **call = (struct call_task **)data;
-
-       WARN(*call, "call is not NULL");
-}
-
-static struct ktask_data ktd = {
-       .init = ktd_init,
-       .exit = ktd_exit,
-       .size = sizeof(struct call_task *),
-};
-
-static void call_set(struct task_struct *task, struct call_task *call)
-{
-       *(struct call_task **)swap_ktd(&ktd, task) = call;
-}
-
-static struct call_task *call_get(struct task_struct *task)
-{
-       return *(struct call_task **)swap_ktd(&ktd, task);
-}
-
-
-int taskctx_run(struct task_struct *task, taskctx_t func, void *data)
-{
-       if (IS_ENABLED(CONFIG_SWAP_KERNEL_IMMUTABLE))
-               return -ENOSYS;
-
-       if (task == current) {
-               func(data);
-       } else {
-               int ret;
-               unsigned long jiff;
-               struct call_task call = {
-                       .func = func,
-                       .data = data,
-                       .comp0 = COMPLETION_INITIALIZER(call.comp0),
-                       .comp1 = COMPLETION_INITIALIZER(call.comp1),
-                       .is_running = false,
-               };
-
-               /* check task possibility to receive signals */
-               if (task->flags & (PF_KTHREAD | PF_EXITING | PF_SIGNALED))
-                       return -EINVAL;
-
-               /* set call by task */
-               call_set(task, &call);
-
-               ret = fake_signal_wake_up(task);
-               if (ret) {
-                       /* reset call by task */
-                       call_set(task, NULL);
-                       pr_err("cannot send signal to task[%u %u %s] flags=%08x state=%08lx\n",
-                              task->tgid, task->pid, task->comm,
-                              task->flags, task->state);
-                       return ret;
-               }
-
-               jiff = msecs_to_jiffies(WAIT_TIMEOUT);
-               wait_for_completion_timeout(&call.comp0, jiff);
-
-               /* reset call by task */
-               call_set(task, NULL);
-
-               /* wait the return from sig_pre_handler() */
-               synchronize_sched();
-
-               if (call.is_running)
-                       wait_for_completion(&call.comp1);
-
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(taskctx_run);
-
-
-static void sig_handler(void)
-{
-       struct call_task *call = call_get(current);
-
-       if (call) {
-               call_set(current, NULL);
-               call->is_running = true;
-
-               complete(&call->comp0);
-               call->func(call->data);
-               complete(&call->comp1);
-       }
-}
-
-
-#ifdef CONFIG_SWAP_HOOK_SIGNAL
-# include <swap/hook_signal.h>
-void hook_handler(struct ksignal *ksig)
-{
-       sig_handler();
-}
-
-struct hook_signal hook_signal = {
-       .owner = THIS_MODULE,
-       .hook = hook_handler,
-};
-
-static int signal_reg(void)
-{
-       int ret = hook_signal_reg(&hook_signal);
-       if (ret)
-               pr_err("Cannot register hook_signal, ret=%d\n", ret);
-
-       return ret;
-}
-
-static void signal_unreg(void)
-{
-       hook_signal_unreg(&hook_signal);
-}
-
-static int signal_once(void)
-{
-       return 0;
-}
-
-#else /* !CONFIG_SWAP_HOOK_SIGNAL */
-# include <kprobe/swap_kprobes.h>
-
-static int sig_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       sig_handler();
-
-       return 0;
-}
-
-static struct kprobe sig_kprobe = {
-       .pre_handler = sig_pre_handler,
-};
-
-static int signal_reg(void)
-{
-       int ret = swap_register_kprobe(&sig_kprobe);
-       if (ret)
-               pr_err("register sig_kprobe ret=%d\n", ret);
-
-       return ret;
-}
-
-static void signal_unreg(void)
-{
-       swap_unregister_kprobe(&sig_kprobe);
-}
-
-static int signal_once(void)
-{
-       const char *sym;
-
-       sym = "signal_wake_up_state";
-       swap_signal_wake_up_state = (void *)swap_ksyms(sym);
-       if (swap_signal_wake_up_state == NULL)
-               goto not_found;
-
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
-       sym = "get_signal";
-# else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) */
-       sym = "get_signal_to_deliver";
-# endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) */
-       sig_kprobe.addr = swap_ksyms(sym);
-       if (sig_kprobe.addr == 0)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       printk("Cannot find address for '%s'!\n", sym);
-       return -ESRCH;
-}
-#endif /* CONFIG_SWAP_HOOK_SIGNAL */
-
-
-static int use_cnt = 0;
-static DEFINE_MUTEX(use_lock);
-
-int taskctx_get(void)
-{
-       int ret = 0;
-
-       mutex_lock(&use_lock);
-       if (use_cnt == 0) {
-               ret = signal_reg();
-               if (ret)
-                       goto unlock;
-       }
-
-       ++use_cnt;
-
-unlock:
-       mutex_unlock(&use_lock);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(taskctx_get);
-
-void taskctx_put(void)
-{
-       mutex_lock(&use_lock);
-       if (use_cnt == 0) {
-               WARN_ON("call put_task_context() without get_task_context");
-               goto unlock;
-       }
-
-       --use_cnt;
-       if (use_cnt == 0)
-               signal_unreg();
-
-unlock:
-       mutex_unlock(&use_lock);
-}
-EXPORT_SYMBOL_GPL(taskctx_put);
-
-
-static int taskctx_once(void)
-{
-       return signal_once();
-}
-
-static int taskctx_init(void)
-{
-       return swap_ktd_reg(&ktd);
-}
-
-static void taskctx_uninit(void)
-{
-       WARN(use_cnt, "use_cnt=%d\n", use_cnt);
-       swap_ktd_unreg(&ktd);
-}
-
-SWAP_LIGHT_INIT_MODULE(taskctx_once, taskctx_init, taskctx_uninit, NULL, NULL);
-
-MODULE_LICENSE("GPL");
diff --git a/task_ctx/task_ctx.h b/task_ctx/task_ctx.h
deleted file mode 100644 (file)
index a4c84b6..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _TASK_CTX_H
-#define _TASK_CTX_H
-
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-struct task_struct;
-
-typedef void (*taskctx_t)(void *info);
-
-
-int taskctx_run(struct task_struct *task, taskctx_t func, void *data);
-
-int taskctx_get(void);
-void taskctx_put(void);
-
-
-#endif /* _TASK_CTX_H */
diff --git a/tests/Kbuild b/tests/Kbuild
deleted file mode 100644 (file)
index 9817995..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := kprobe_tests/
diff --git a/tests/kprobe_tests/Kbuild b/tests/kprobe_tests/Kbuild
deleted file mode 100644 (file)
index 5718978..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_kp_tests.o
-swap_kp_tests-y := \
-       kp_module.o \
-       kp_tests.o \
-       krp_tests.o \
diff --git a/tests/kprobe_tests/kp_module.c b/tests/kprobe_tests/kp_module.c
deleted file mode 100644 (file)
index a0e1c80..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/uaccess.h>
-#include <linux/kallsyms.h>
-#include "kp_module.h"
-
-
-static asmlinkage long (*olog_sys_write)(unsigned int, const char __user *, size_t);
-
-static long write_to_stdout(const char *buf, size_t len)
-{
-       long ret;
-
-       mm_segment_t fs = get_fs();
-       set_fs(get_ds());
-       ret = olog_sys_write(1, buf, len);
-       set_fs(fs);
-
-       return ret;
-}
-
-static int olog_init(void)
-{
-       olog_sys_write = (void *)kallsyms_lookup_name("sys_write");
-       if (olog_sys_write == NULL) {
-               pr_err("ERR: not found 'sys_write' symbol\n");
-               return -ESRCH;
-       }
-
-       return 0;
-}
-
-void olog(const char *fmt, ...)
-{
-       char buf[256];
-       va_list args;
-
-       va_start(args, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, args);
-       va_end(args);
-
-       printk("%s", buf);
-       write_to_stdout(buf, strlen(buf));
-}
-
-
-
-
-static void print_mod_info(void)
-{
-       struct module *mod = THIS_MODULE;
-
-       printk("### MOD_INFO:\n");
-       printk("    core: %p..%p\n", mod->module_init, mod->module_init + mod->init_text_size);
-       printk("    init: %p..%p\n", mod->module_core, mod->module_core + mod->core_text_size);
-       printk("\n");
-}
-
-
-/* TODO: move declare to header */
-int kp_tests_run(void);
-int krp_tests_run(void);
-
-static int __init tests_init(void)
-{
-       int ret;
-
-       ret = olog_init();
-       if (ret)
-               return ret;
-
-       print_mod_info();
-
-       olog("### Begin tests ###\n");
-       kp_tests_run();
-       krp_tests_run();
-       olog("### End tests ###\n");
-
-       return -1;
-}
-
-static void __exit tests_exit(void)
-{
-}
-
-module_init(tests_init);
-module_exit(tests_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/tests/kprobe_tests/kp_module.h b/tests/kprobe_tests/kp_module.h
deleted file mode 100644 (file)
index e3f0b2b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _KP_MODULE_H
-#define _KP_MODULE_H
-
-
-void olog(const char *fmt, ...);
-
-
-#endif /* _KP_MODULE_H */
diff --git a/tests/kprobe_tests/kp_tests.c b/tests/kprobe_tests/kp_tests.c
deleted file mode 100644 (file)
index 6386f50..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <kprobe/swap_kprobes.h>
-#include "kp_module.h"
-
-
-static struct task_struct *cur_task;
-
-
-static struct kprobe *kp_create(char *name,
-                               int (*pre_h)(struct kprobe *, struct pt_regs *))
-{
-       struct kprobe *p;
-
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (p) {
-               p->symbol_name = name;
-               p->pre_handler = pre_h;
-       }
-
-       return p;
-}
-
-static void kp_free(struct kprobe *p)
-{
-       memset(p, 0x10, sizeof(*p));
-}
-
-#define kp_reg(ptr, name, handler) \
-       do { \
-               ptr = kp_create(name, handler); \
-               swap_register_kprobe(ptr); \
-       } while (0)
-
-#define kp_unreg(ptr) \
-       do { \
-               swap_unregister_kprobe(ptr); \
-               kp_free(ptr); \
-               ptr = NULL; \
-       } while (0)
-
-
-noinline char *my_kstrdup(const char *s, gfp_t gfp)
-{
-       return kstrdup(s, gfp);
-}
-
-noinline void my_kfree(const void *data)
-{
-       kfree(data);
-}
-
-
-
-
-/*
- ******************************************************************************
- *                                 recursion                                  *
- ******************************************************************************
- */
-static int kstrdup_cnt;
-static int kfree_cnt;
-
-static struct kprobe *kp_kstrdup;
-static int kstrdup_h(struct kprobe *kp, struct pt_regs *regs)
-{
-       char *str;
-
-       str = my_kstrdup("from_kfree_h", GFP_ATOMIC);
-       my_kfree(str);
-
-       ++kstrdup_cnt;
-
-       return 0;
-}
-
-static struct kprobe *kp_kfree;
-static int kfree_h(struct kprobe *kp, struct pt_regs *regs)
-{
-       ++kfree_cnt;
-
-       return 0;
-}
-
-static void run_test_recursion(void)
-{
-       char *str;
-
-       str = my_kstrdup("test_string_0", GFP_KERNEL);
-       my_kfree(str);
-
-       str = my_kstrdup("test_string_1", GFP_KERNEL);
-       my_kfree(str);
-}
-
-static void do_test_recursion(void)
-{
-       kp_reg(kp_kfree, "my_kfree", kfree_h);
-       kp_reg(kp_kstrdup, "my_kstrdup", kstrdup_h);
-
-       run_test_recursion();
-
-       kp_unreg(kp_kstrdup);
-       kp_unreg(kp_kfree);
-}
-
-
-static void test_recursion(void)
-{
-       olog("Recursion:\n");
-
-       kstrdup_cnt = 0;
-       kfree_cnt = 0;
-
-       do_test_recursion();
-
-       if (kstrdup_cnt == 2 && kfree_cnt == 2) {
-               olog("    OK\n");
-       } else {
-               olog("    ERROR: kstrdup_cnt=%d kfree_cnt=%d\n",
-                      kstrdup_cnt, kfree_cnt);
-       }
-}
-
-
-
-
-/*
- ******************************************************************************
- *            recursion and multiple handlers (Aggregate probe)               *
- ******************************************************************************
- */
-static int kfree2_cnt;
-
-static struct kprobe *kp_kfree2;
-static int kfree2_h(struct kprobe *kp, struct pt_regs *regs)
-{
-       if (current != cur_task || in_interrupt())
-               return 0;
-
-       ++kfree2_cnt;
-       return 0;
-}
-
-static void pre_test_recursion_and_mh(void)
-{
-       kstrdup_cnt = 0;
-       kfree_cnt = 0;
-       kfree2_cnt = 0;
-}
-
-static void post_test_recursion_and_mh(void)
-{
-       if (kstrdup_cnt == 2 && kfree_cnt == 2 && kfree2_cnt == 2) {
-               olog("    OK\n");
-       } else {
-               olog("    ERROR: kstrdup_cnt=%d kfree_cnt=%d kfree2_cnt=%d\n",
-                    kstrdup_cnt, kfree_cnt, kfree2_cnt);
-       }
-}
-
-static void test_recursion_and_multiple_handlers(void)
-{
-       olog("Recursion and multiple handlers:\n");
-
-       pre_test_recursion_and_mh();
-
-       kp_reg(kp_kfree2, "my_kfree", kfree2_h);
-       do_test_recursion();
-       kp_unreg(kp_kfree2);
-
-       post_test_recursion_and_mh();
-}
-
-static void test_recursion_and_multiple_handlers2(void)
-{
-       olog("Recursion and multiple handlers [II]:\n");
-
-       pre_test_recursion_and_mh();
-
-       kp_reg(kp_kfree, "my_kfree", kfree_h);
-       kp_reg(kp_kstrdup, "my_kstrdup", kstrdup_h);
-       kp_reg(kp_kfree2, "my_kfree", kfree2_h);
-
-       run_test_recursion();
-
-       kp_unreg(kp_kstrdup);
-       kp_unreg(kp_kfree);
-       kp_unreg(kp_kfree2);
-
-       post_test_recursion_and_mh();
-}
-
-
-
-
-/*
- ******************************************************************************
- *                        swap_unregister_kprobe(), sync                      *
- ******************************************************************************
- */
-
-static const char task_name[] = "my_task";
-
-static int is_my_task(void)
-{
-       return !strcmp(task_name, current->comm);
-}
-
-static int find_module_cnt;
-
-static struct kprobe *kp_find_module;
-static int find_module_h(struct kprobe *kp, struct pt_regs *regs)
-{
-       if (is_my_task()) {
-               might_sleep();
-               ++find_module_cnt;
-
-               /* sleep 0.5 sec */
-               msleep(500);
-               schedule();
-
-               ++find_module_cnt;
-       }
-
-       return 0;
-}
-
-static int kthread_my_fn(void *data)
-{
-       find_module("o_lo_lo");
-       find_module("o_lo_lo");
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-       }
-
-       return 0;
-}
-
-
-static void do_test_sync_unreg(unsigned int ms)
-{
-       struct task_struct *task;
-
-       kp_reg(kp_find_module, "find_module", find_module_h);
-
-       task = kthread_run(kthread_my_fn, NULL, task_name);
-       if (IS_ERR(task)) {
-               olog("ERROR: kthread_run()\n");
-               goto unreg;
-       }
-
-       /* waiting for kthread_my_fn() call */
-       msleep(ms);
-unreg:
-       kp_unreg(kp_find_module);
-       if (!IS_ERR(task))
-               kthread_stop(task);
-}
-
-static void test_sync_unreg(void)
-{
-       olog("Unreg kp:\n");
-
-       find_module_cnt = 0;
-
-       do_test_sync_unreg(200);
-
-       if (find_module_cnt == 2) {
-               olog("    OK\n");
-       } else {
-               olog("    ERROR: find_module_cnt=%d\n", find_module_cnt);
-       }
-}
-
-
-
-/*
- ******************************************************************************
- *             swap_unregister_kprobe(), sync and multiple handlers           *
- ******************************************************************************
- */
-static int find_module2_cnt;
-
-static struct kprobe *kp_find_module2;
-static int find_module2_h(struct kprobe *kp, struct pt_regs *regs)
-{
-       if (is_my_task()) {
-               ++find_module2_cnt;
-
-               /* sleep 0.5 sec */
-               msleep(500);
-
-               ++find_module2_cnt;
-       }
-
-       return 0;
-}
-
-static void pre_test_sync_unreg_and_mh(void)
-{
-       find_module_cnt = 0;
-       find_module2_cnt = 0;
-}
-
-static void post_test_sync_unreg_and_mh(int cnt, int cnt2)
-{
-       if (find_module_cnt == cnt && find_module2_cnt == cnt2) {
-               olog("    OK\n");
-       } else {
-               olog("    ERROR: find_module_cnt=%d find_module2_cnt=%d\n",
-                    find_module_cnt, find_module2_cnt);
-       }
-}
-
-static void do_test_sync_unreg_and_mh(unsigned int ms)
-{
-       struct task_struct *task;
-
-       kp_reg(kp_find_module, "find_module", find_module_h);
-       kp_reg(kp_find_module2, "find_module", find_module2_h);
-
-       task = kthread_run(kthread_my_fn, NULL, task_name);
-       if (IS_ERR(task)) {
-               olog("ERROR: kthread_run()\n");
-               goto unreg;
-       }
-
-       /* waiting for kthread_my_fn() call */
-       msleep(ms);
-unreg:
-       kp_unreg(kp_find_module2);
-       kp_unreg(kp_find_module);
-       if (!IS_ERR(task))
-               kthread_stop(task);
-}
-
-static void test_sync_unreg_and_multiple_handlers(void)
-{
-       olog("Unreg kp and multiple handlers:\n");
-
-       pre_test_sync_unreg_and_mh();
-
-       do_test_sync_unreg_and_mh(700);
-
-       post_test_sync_unreg_and_mh(2, 2);
-}
-
-static void do_test_sync_unreg_and_mh2(unsigned int ms)
-{
-       struct task_struct *task;
-
-       kp_reg(kp_find_module, "find_module", find_module_h);
-       kp_reg(kp_find_module2, "find_module", find_module2_h);
-
-       task = kthread_run(kthread_my_fn, NULL, task_name);
-       if (IS_ERR(task)) {
-               olog("ERROR: kthread_run()\n");
-               goto unreg;
-       }
-
-       /* waiting for kthread_my_fn() call */
-       msleep(ms);
-unreg:
-       kp_unreg(kp_find_module);
-       kp_unreg(kp_find_module2);
-       if (!IS_ERR(task))
-               kthread_stop(task);
-}
-
-static void test_sync_unreg_and_multiple_handlers2(void)
-{
-       olog("Unreg kp and multiple handlers [II]:\n");
-
-       pre_test_sync_unreg_and_mh();
-
-       do_test_sync_unreg_and_mh2(700);
-
-       post_test_sync_unreg_and_mh(2, 2);
-}
-
-int kp_tests_run(void)
-{
-       cur_task = current;
-
-       test_recursion();
-       test_recursion_and_multiple_handlers();
-       test_recursion_and_multiple_handlers2();
-       // add 3
-
-       test_sync_unreg();
-       test_sync_unreg_and_multiple_handlers();
-       test_sync_unreg_and_multiple_handlers2();
-
-       return 0;
-}
diff --git a/tests/kprobe_tests/krp_tests.c b/tests/kprobe_tests/krp_tests.c
deleted file mode 100644 (file)
index db59126..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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, 2016
- *
- * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <kprobe/swap_kprobes.h>
-#include "kp_module.h"
-
-
-static struct kretprobe *krp_create(char *name,
-                                   int (*eh)(struct kretprobe_instance *, struct pt_regs *),
-                                   int (*rh)(struct kretprobe_instance *, struct pt_regs *),
-                                   size_t data_size)
-{
-       struct kretprobe *rp;
-
-       rp = kzalloc(sizeof(*rp), GFP_KERNEL);
-       if (rp) {
-               rp->kp.symbol_name = name;
-               rp->entry_handler = eh;
-               rp->handler = rh;
-               rp->data_size = data_size;
-       }
-
-       return rp;
-}
-
-static void krp_free(struct kretprobe *rp)
-{
-       memset(rp, 0x10, sizeof(*rp));
-}
-
-#define krp_reg(ptr, name, eh, rh, sz) \
-       do { \
-               ptr = krp_create(name, eh, rh, sz); \
-               swap_register_kretprobe(ptr); \
-       } while (0)
-
-#define krp_unreg(ptr) \
-       do { \
-               swap_unregister_kretprobe(ptr); \
-               krp_free(ptr); \
-               ptr = NULL; \
-       } while (0)
-
-
-
-
-
-struct test_func_data {
-       long v0, v1, v2, v3, v4, v5, v6, v7;
-};
-
-static struct test_func_data tf_data_tmp;
-static unsigned long tf_data_tmp_ret;
-
-
-static long do_test_func(long v0, long v1, long v2, long v3,
-                        long v4, long v5, long v6, long v7)
-{
-       return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7;
-}
-
-static noinline long test_func(long v0, long v1, long v2, long v3,
-                              long v4, long v5, long v6, long v7)
-{
-       return do_test_func(v0, v1, v2, v3, v4, v5, v6, v7);
-}
-
-static int test_func_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct test_func_data *data = (struct test_func_data *)ri->data;
-
-       data->v0 = swap_get_karg(regs, 0);
-       data->v1 = swap_get_karg(regs, 1);
-       data->v2 = swap_get_karg(regs, 2);
-       data->v3 = swap_get_karg(regs, 3);
-       data->v4 = swap_get_karg(regs, 4);
-       data->v5 = swap_get_karg(regs, 5);
-       data->v6 = swap_get_karg(regs, 6);
-       data->v7 = swap_get_karg(regs, 7);
-
-       pr_info("E data=[%ld %ld %ld %ld %ld %ld %ld %ld]\n",
-               data->v0, data->v1, data->v2, data->v3,
-               data->v4, data->v5, data->v6, data->v7);
-
-       return 0;
-}
-
-static int test_func_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct test_func_data *data = (struct test_func_data *)ri->data;
-
-       tf_data_tmp_ret = regs_return_value(regs);
-       tf_data_tmp = *data;
-
-       pr_info("R data=[%ld %ld %ld %ld %ld %ld %ld %ld] ret=%ld\n",
-               data->v0, data->v1, data->v2, data->v3,
-               data->v4, data->v5, data->v6, data->v7,
-               tf_data_tmp_ret);
-
-       return 0;
-}
-
-struct kretprobe *test_func_krp;
-
-static struct test_func_data tf_data_gage = {
-       .v0 = 0,
-       .v1 = 1,
-       .v2 = 2,
-       .v3 = 3,
-       .v4 = 4,
-       .v5 = 5,
-       .v6 = 6,
-       .v7 = 7,
-};
-
-static void pre_test_krp(void)
-{
-       memset(&tf_data_tmp, 0, sizeof(tf_data_tmp));
-       tf_data_tmp_ret = 0;
-}
-
-static void post_test_krp(void)
-{
-       long ret;
-
-       ret = do_test_func(tf_data_gage.v0, tf_data_gage.v1, tf_data_gage.v2, tf_data_gage.v3,
-                          tf_data_gage.v4, tf_data_gage.v5, tf_data_gage.v6, tf_data_gage.v7);
-
-       if (tf_data_tmp_ret == ret &&
-           memcmp(&tf_data_gage, &tf_data_tmp, sizeof(tf_data_gage)) == 0) {
-               olog("    OK\n");
-       } else {
-               olog("    ERROR:\n"
-                    "        tf_data_gage=[%ld %ld %ld %ld %ld %ld %ld %ld] ret=%ld\n"
-                    "        tf_data_tmp =[%ld %ld %ld %ld %ld %ld %ld %ld] ret=%ld\n",
-                    tf_data_gage.v0, tf_data_gage.v1,
-                    tf_data_gage.v2, tf_data_gage.v3,
-                    tf_data_gage.v4, tf_data_gage.v5,
-                    tf_data_gage.v6, tf_data_gage.v7, ret,
-                    tf_data_tmp.v0, tf_data_tmp.v1,
-                    tf_data_tmp.v2, tf_data_tmp.v3,
-                    tf_data_tmp.v4, tf_data_tmp.v5,
-                    tf_data_tmp.v6, tf_data_tmp.v7, tf_data_tmp_ret);
-       }
-}
-
-static void do_test_krp(void)
-{
-       krp_reg(test_func_krp, "test_func",
-               test_func_eh, test_func_rh,
-               sizeof(struct test_func_data));
-
-       test_func(tf_data_gage.v0, tf_data_gage.v1, tf_data_gage.v2, tf_data_gage.v3,
-                 tf_data_gage.v4, tf_data_gage.v5, tf_data_gage.v6, tf_data_gage.v7);
-
-       krp_unreg(test_func_krp);
-}
-
-static void test_krp(void)
-{
-       olog("Kretprobe (get_args{8} and ri->data):\n");
-
-       pre_test_krp();
-
-       do_test_krp();
-
-       post_test_krp();
-}
-
-int krp_tests_run(void)
-{
-       test_krp();
-
-       return 0;
-}
diff --git a/tests/kprobe_tests/run_kp_tests.sh b/tests/kprobe_tests/run_kp_tests.sh
deleted file mode 100644 (file)
index d912090..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-cd /opt/swap/sdk
-
-insmod swap_master.ko
-echo 1 > /sys/kernel/debug/swap/enable
-insmod swap_kprobe.ko
-
-insmod swap_kp_tests.ko 2>/dev/null
-
-rmmod swap_kprobe
-rmmod swap_master
diff --git a/uihv/Kbuild b/uihv/Kbuild
deleted file mode 100644 (file)
index 9ae0694..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_uihv.o
-swap_uihv-y := uihv_module.o \
-               uihv_debugfs.o
diff --git a/uihv/uihv.h b/uihv/uihv.h
deleted file mode 100644 (file)
index 1e0b0c7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __UIHV_H__
-#define __UIHV_H__
-
-#define UIHV_PREFIX "SWAP_UIHV: "
-#define UIHV_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
-
-#endif /* __UIHV_H__ */
diff --git a/uihv/uihv_debugfs.c b/uihv/uihv_debugfs.c
deleted file mode 100644 (file)
index b02b6af..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "uihv.h"
-#include "uihv_module.h"
-
-static const char UIHV_FOLDER[] = "uihv";
-static const char UIHV_PATH[] = "path";
-static const char UIHV_APP_INFO[] = "app_info";
-static const char UIHV_ENABLE[] = "enable";
-
-static struct dentry *uihv_root;
-
-
-
-/* ===========================================================================
- * =                           UI VIEWER PATH                                =
- * ===========================================================================
- */
-
-
-static ssize_t uihv_path_write(struct file *file, const char __user *buf,
-                              size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *path;
-
-       path = kmalloc(len, GFP_KERNEL);
-       if (path == NULL) {
-               ret = -ENOMEM;
-               goto uihv_path_write_out;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto uihv_path_write_out;
-       }
-
-       path[len - 1] = '\0';
-
-       if (uihv_set_handler(path) != 0) {
-               printk(UIHV_PREFIX "Cannot set ui viewer path %s\n", path);
-               ret = -EINVAL;
-               goto uihv_path_write_out;
-       }
-
-       ret = len;
-
-       printk(UIHV_PREFIX "Set ui viewer path %s\n", path);
-
-uihv_path_write_out:
-       kfree(path);
-
-       return ret;
-}
-
-static const struct file_operations uihv_path_file_ops = {
-       .owner = THIS_MODULE,
-       .write = uihv_path_write,
-};
-
-
-/*
- * format:
- *     main:app_path
- *
- * sample:
- *     0x00000d60:/bin/app_sample
- */
-static int uihv_add_app_info(const char *buf, size_t len)
-{
-       int n, ret;
-       char *app_path;
-       unsigned long main_addr;
-       const char fmt[] = "%%lx:/%%%ds";
-       char fmt_buf[64];
-
-       n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
-       if (n <= 0)
-               return -EINVAL;
-
-       app_path = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (app_path == NULL)
-               return -ENOMEM;
-
-       n = sscanf(buf, fmt_buf, &main_addr, app_path + 1);
-       if (n != 2) {
-               ret = -EINVAL;
-               goto free_app_path;
-       }
-       app_path[0] = '/';
-
-       printk(UIHV_PREFIX "Set ui viewer app path %s, main offset 0x%lx\n", app_path, main_addr);
-
-       ret = uihv_data_set(app_path, main_addr);
-
-free_app_path:
-       kfree(app_path);
-       return ret;
-}
-
-static ssize_t write_uihv_app_info(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t len, loff_t *ppos)
-{
-       ssize_t ret = len;
-       char *buf;
-
-       buf = kmalloc(len, GFP_KERNEL);
-       if (buf == NULL) {
-               ret = -ENOMEM;
-               goto free_buf;
-       }
-
-       if (copy_from_user(buf, user_buf, len)) {
-               ret = -EINVAL;
-               goto free_buf;
-       }
-
-       buf[len - 1] = '\0';
-
-       if (uihv_add_app_info(buf, len))
-               ret = -EINVAL;
-
-free_buf:
-       kfree(buf);
-
-       return ret;
-}
-
-static const struct file_operations uihv_app_info_file_ops = {
-       .owner = THIS_MODULE,
-       .write = write_uihv_app_info,
-};
-
-static ssize_t write_uihv_enable(struct file *file,
-                                const char __user *user_buf,
-                                size_t len, loff_t *ppos)
-{
-       ssize_t ret = len;
-       char *buf;
-
-       buf = kmalloc(len, GFP_KERNEL);
-       if (!buf) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       if (copy_from_user(buf, user_buf, len)) {
-               ret = -EINVAL;
-               goto free_buf;
-       }
-
-       buf[len - 1] = '\0';
-
-       if (buf[0] == '0')
-               ret = uihv_disable();
-       else
-               ret = uihv_enable();
-
-free_buf:
-       kfree(buf);
-
-out:
-       return ret;
-}
-
-static const struct file_operations uihv_enable_file_ops = {
-       .owner = THIS_MODULE,
-       .write = write_uihv_enable,
-};
-
-int uihv_dfs_init(void)
-{
-       struct dentry *swap_dentry, *root, *path, *app_info, *uihv_enable;
-       int ret;
-
-       ret = -ENODEV;
-       if (!debugfs_initialized())
-               goto fail;
-
-       ret = -ENOENT;
-       swap_dentry = swap_debugfs_getdir();
-       if (!swap_dentry)
-               goto fail;
-
-       ret = -ENOMEM;
-       root = swap_debugfs_create_dir(UIHV_FOLDER, swap_dentry);
-       if (IS_ERR_OR_NULL(root))
-               goto fail;
-
-       uihv_root = root;
-
-       path = swap_debugfs_create_file(UIHV_PATH, UIHV_DEFAULT_PERMS, root,
-                                       NULL, &uihv_path_file_ops);
-       if (IS_ERR_OR_NULL(path)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       app_info = swap_debugfs_create_file(UIHV_APP_INFO,
-                                           UIHV_DEFAULT_PERMS, root, NULL,
-                                           &uihv_app_info_file_ops);
-       if (IS_ERR_OR_NULL(app_info)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       uihv_enable = swap_debugfs_create_file(UIHV_ENABLE,
-                                              UIHV_DEFAULT_PERMS, root, NULL,
-                                              &uihv_enable_file_ops);
-       if (IS_ERR_OR_NULL(uihv_enable)) {
-               ret = -ENOMEM;
-               goto remove;
-       }
-
-       return 0;
-
-remove:
-       debugfs_remove_recursive(root);
-
-fail:
-       printk(UIHV_PREFIX "Debugfs initialization failure: %d\n", ret);
-
-       return ret;
-}
-
-void uihv_dfs_exit(void)
-{
-       if (uihv_root)
-               debugfs_remove_recursive(uihv_root);
-
-       uihv_root = NULL;
-}
diff --git a/uihv/uihv_debugfs.h b/uihv/uihv_debugfs.h
deleted file mode 100644 (file)
index 59841c0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __UIHV_DEBUGFS_H__
-#define __UIHV_DEBUGFS_H__
-
-int uihv_dfs_init(void);
-void uihv_dfs_exit(void);
-
-#endif /* __UIHV_DEBUGFS_H__ */
diff --git a/uihv/uihv_module.c b/uihv/uihv_module.c
deleted file mode 100644 (file)
index 5d983be..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-#include <linux/namei.h>
-#include <us_manager/us_manager_common.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/callbacks.h>
-#include <us_manager/probes/probe_info_new.h>
-#include <us_manager/us_common_file.h>
-#include <writer/kernel_operations.h>
-#include <master/swap_initializer.h>
-#include <writer/swap_msg.h>
-#include <loader/loader.h>
-#include "uihv.h"
-#include "uihv_module.h"
-#include "uihv_debugfs.h"
-
-#define page_to_proc(page) ((page)->file->proc)
-#define ip_to_proc(ip) page_to_proc((ip)->page)
-#define urp_to_ip(rp) container_of(rp, struct sspt_ip, retprobe)
-
-static DEFINE_MUTEX(mutex_enable);
-
-static struct dentry *uihv_dentry = NULL;
-
-
-/* ============================================================================
- * =                               ui_viewer                                  =
- * ============================================================================
- */
-
-/* main handler for ui viewer */
-static int uihv_main_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int uihv_main_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_desc pin_main = MAKE_URPROBE(uihv_main_eh,
-                                                    uihv_main_rh, 0);
-
-struct ui_viewer_data {
-       struct dentry *app_dentry;
-       struct probe_new p_main;
-       struct pf_group *pfg;
-       bool enable;
-};
-
-static struct ui_viewer_data __ui_data;
-
-static int uihv_data_inst(void)
-{
-       struct pf_group *pfg;
-
-       pfg = get_pf_group_by_dentry(__ui_data.app_dentry,
-                                    (void *)__ui_data.app_dentry);
-       if (!pfg)
-               return -ENOMEM;
-
-       __ui_data.pfg = pfg;
-
-       return 0;
-}
-
-int uihv_data_set(const char *app_path, unsigned long main_addr)
-{
-       struct dentry *dentry;
-
-       if (__ui_data.enable) {
-               pr_err("UIHV already enabled, can't set data\n");
-               return -EBUSY;
-       }
-
-       dentry = dentry_by_path(app_path);
-       if (dentry == NULL)
-               return -ENOENT;
-
-       __ui_data.app_dentry = dentry;
-       __ui_data.p_main.desc = &pin_main;
-       __ui_data.p_main.offset = main_addr;
-
-       return uihv_data_inst();
-}
-
-int uihv_set_handler(char *path)
-{
-       struct dentry *dentry;
-       int ret;
-
-       if (uihv_dentry != NULL) {
-               swap_put_dentry(uihv_dentry);
-               uihv_dentry = NULL;
-       }
-
-       dentry = swap_get_dentry(path);
-       if (dentry == NULL) {
-               printk(KERN_WARNING UIHV_PREFIX "Error! Cannot get handler %s\n",
-                          path);
-               return -EINVAL;
-       }
-
-       ret = loader_add_handler(path);
-       if (ret != 0)
-               return ret;
-
-       uihv_dentry = dentry;
-
-       return 0;
-}
-
-
-
-/* ============================================================================
- * =                          ui viewer handlers                              =
- * ============================================================================
- */
-static int uihv_main_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-       struct hd_t *hd;
-       unsigned long old_pc = swap_get_upc(regs);
-       unsigned long vaddr = 0;
-
-       if (uihv_dentry == NULL)
-               return 0;
-
-       hd = lpd_get_hd(pd, uihv_dentry);
-       if (hd == NULL)
-               return 0;
-
-       if (lpd_get_state(hd) == NOT_LOADED)
-               vaddr = loader_not_loaded_entry(ri, regs, pd, hd);
-
-       loader_set_priv_origin(ri, vaddr);
-
-       /* PC change check */
-       return old_pc != swap_get_upc(regs);
-}
-
-static int uihv_main_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = lpd_get_by_task(current);
-       struct hd_t *hd;
-
-       if (uihv_dentry == NULL)
-               return 0;
-
-       hd = lpd_get_hd(pd, uihv_dentry);
-       if (hd == NULL)
-               return 0;
-
-       if (lpd_get_state(hd) == LOADING)
-               loader_loading_ret(ri, regs, pd, hd);
-
-       return 0;
-}
-
-int uihv_enable(void)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_enable);
-       if (__ui_data.enable) {
-               pr_err("UIHV already enabled\n");
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = pin_register(&__ui_data.p_main, __ui_data.pfg,
-                          __ui_data.app_dentry);
-       if (ret)
-               goto out;
-
-       __ui_data.enable = true;
-
-out:
-       mutex_unlock(&mutex_enable);
-       return ret;
-}
-
-int uihv_disable(void)
-{
-       int ret = 0;
-
-       mutex_lock(&mutex_enable);
-       if (!__ui_data.enable) {
-               pr_err("UIHV already disabled\n");
-               ret = -EBUSY;
-               goto out;
-       }
-
-       pin_unregister(&__ui_data.p_main, __ui_data.pfg);
-       put_pf_group(__ui_data.pfg);
-       __ui_data.pfg = NULL;
-       __ui_data.enable = false;
-
-out:
-       mutex_unlock(&mutex_enable);
-       return ret;
-}
-
-static int uihv_init(void)
-{
-       int ret;
-
-       ret = uihv_dfs_init();
-
-       return ret;
-}
-
-static void uihv_exit(void)
-{
-       if (uihv_dentry != NULL) {
-               swap_put_dentry(uihv_dentry);
-               uihv_dentry = NULL;
-       }
-
-       uihv_dfs_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, uihv_init, uihv_exit, NULL, NULL);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP UI Hierarchy Viewer");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>, Anastasia Lypa");
diff --git a/uihv/uihv_module.h b/uihv/uihv_module.h
deleted file mode 100644 (file)
index e6413a7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __UIHV_MODULE_H__
-#define __UIHV_MODULE_H__
-
-int uihv_data_set(const char *app_path, unsigned long main_addr);
-int uihv_set_handler(char *path);
-int uihv_enable(void);
-int uihv_disable(void);
-
-#endif /* __UIHV_MODULE_H__ */
diff --git a/uprobe/Kbuild b/uprobe/Kbuild
deleted file mode 100644 (file)
index ad4d051..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../kprobe/Module.symvers
-
-obj-m := swap_uprobe.o
-swap_uprobe-y := swap_uprobes.o
-
-### ARM
-swap_uprobe-$(CONFIG_ARM) += \
-       arch/arm/swap-asm/swap_uprobes.o \
-       ../arch/arm/probes/probes_thumb.o \
-       ../arch/arm/probes/decode_thumb.o \
-       ../arch/arm/probes/probes.o \
-       ../arch/arm/uprobe/swap_uprobe.o
-
-
-### ARM64
-swap_uprobe-$(CONFIG_ARM64) += \
-       arch/arm64/swap-asm/swap_uprobes.o \
-       arch/arm64/swap-asm/uprobes-arm64.o \
-       ../arch/arm/probes/probes_arm.o \
-       ../arch/arm/probes/decode_thumb.o \
-       ../arch/arm/probes/probes_thumb.o \
-       ../arch/arm/probes/probes.o \
-       ../arch/arm/uprobe/swap_uprobe.o
-
-
-### X86
-swap_uprobe-$(CONFIG_X86) += arch/x86/swap-asm/swap_uprobes.o \
-                            arch/x86/swap-asm/swap_sc_patch.o
diff --git a/uprobe/arch/arm/swap-asm/swap_uprobes.c b/uprobe/arch/arm/swap-asm/swap_uprobes.c
deleted file mode 100644 (file)
index 6da9d14..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/**
- * uprobe/arch/asm-arm/swap_uprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface implementation for ARM.
- */
-
-
-#include <linux/init.h>                        /* need for asm/traps.h */
-#include <linux/sched.h>               /* need for asm/traps.h */
-
-#include <linux/ptrace.h>              /* need for asm/traps.h */
-#include <asm/traps.h>
-
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <uprobe/swap_uprobes.h>
-#include <arch/arm/probes/probes_arm.h>
-#include <arch/arm/probes/probes_thumb.h>
-#include <swap-asm/swap_kprobes.h>
-#include "swap_uprobes.h"
-
-
-/**
- * @brief Prepares uprobe for ARM.
- *
- * @param up Pointer to the uprobe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_prepare_uprobe(struct uprobe *p)
-{
-       int ret;
-
-       ret = arch_prepare_uprobe_arm(p);
-       if (!ret) {
-               /* for uretprobe */
-               add_uprobe_table(p);
-       }
-
-       return ret;
-}
-
-/**
- * @brief Analysis opcodes.
- *
- * @param rp Pointer to the uretprobe.
- * @return Void.
- */
-void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
-{
-       /* Remove retprobe if first insn overwrites lr */
-       rp->thumb_noret = noret_thumb(rp->up.opcode);
-       rp->arm_noret = noret_arm(rp->up.opcode);
-}
-
-/**
- * @brief Prepates uretprobe for ARM.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param regs Pointer to CPU register data.
- * @return Error code.
- */
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       unsigned long thumb, bp_offset;
-
-       thumb = ri->preload.use ? ri->preload.thumb : thumb_mode(regs);
-       bp_offset = thumb ? 0x1b : sizeof(long) * PROBES_TRAMP_RET_BREAK_IDX;
-
-       /* save original return address */
-       ri->ret_addr = (uprobe_opcode_t *)regs->ARM_lr;
-
-       /* replace return address with break point adddress */
-       regs->ARM_lr = (unsigned long)(ri->rp->up.insn) + bp_offset;
-
-       /* save stack pointer address */
-       ri->sp = (uprobe_opcode_t *)regs->ARM_sp;
-
-       /* Set flag of current mode */
-       ri->sp = (uprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
-
-       return 0;
-}
-
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
-{
-       /* Understand function mode */
-       return ((unsigned long)ri->sp & 1) ?
-                       ((unsigned long)ri->rp->up.insn + 0x1b) :
-                       (unsigned long)(ri->rp->up.insn +
-                                       PROBES_TRAMP_RET_BREAK_IDX);
-}
-
-/**
- * @brief Disarms uretprobe instance.
- *
- * @param ri Pointer to the uretprobe instance
- * @param task Pointer to the task for which the uretprobe instance
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task)
-{
-       struct pt_regs *uregs = task_pt_regs(ri->task);
-       unsigned long ra = uregs->ARM_lr;
-       unsigned long *tramp = (unsigned long *)arch_tramp_by_ri(ri);
-       unsigned long *sp = (unsigned long *)((long)ri->sp & ~1);
-       unsigned long *stack = sp - URETPROBE_STACK_DEPTH + 1;
-       unsigned long *found = NULL;
-       unsigned long *buf[URETPROBE_STACK_DEPTH];
-       unsigned long vaddr = (unsigned long)ri->rp->up.addr;
-       int i, retval;
-
-       /* check stack */
-       retval = read_proc_vm_atomic(task, (unsigned long)stack,
-                                    buf, sizeof(buf));
-       if (retval != sizeof(buf)) {
-               printk(KERN_INFO "---> %s (%d/%d): failed to read "
-                      "stack from %08lx\n", task->comm, task->tgid, task->pid,
-                      (unsigned long)stack);
-               retval = -EFAULT;
-               goto check_lr;
-       }
-
-       /* search the stack from the bottom */
-       for (i = URETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
-               if (buf[i] == tramp) {
-                       found = stack + i;
-                       break;
-               }
-       }
-
-       if (!found) {
-               retval = -ESRCH;
-               goto check_lr;
-       }
-
-       printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
-              "%08lx (%08lx /%+d) - %lx, set ret_addr=%p\n",
-              task->comm, task->tgid, task->pid,
-              (unsigned long)found, (unsigned long)sp,
-              found - sp, vaddr, ri->ret_addr);
-       retval = write_proc_vm_atomic(task, (unsigned long)found,
-                                     &ri->ret_addr,
-                                     sizeof(ri->ret_addr));
-       if (retval != sizeof(ri->ret_addr)) {
-               printk(KERN_INFO "---> %s (%d/%d): "
-                      "failed to write value to %08lx",
-                      task->comm, task->tgid, task->pid, (unsigned long)found);
-               retval = -EFAULT;
-       } else {
-               retval = 0;
-       }
-
-check_lr: /* check lr anyway */
-       if (ra == (unsigned long)tramp) {
-               printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
-                      "lr = %08lx - %lx, set ret_addr=%p\n",
-                      task->comm, task->tgid, task->pid, ra, vaddr, ri->ret_addr);
-
-               swap_set_uret_addr(uregs, (unsigned long)ri->ret_addr);
-               retval = 0;
-       } else if (retval) {
-               printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at "
-                      "sp = %08lx, lr = %08lx - %lx, ret_addr=%p\n",
-                      task->comm, task->tgid, task->pid,
-                      (unsigned long)sp, ra, vaddr, ri->ret_addr);
-       }
-
-       return retval;
-}
-
-/**
- * @brief Jump pre-handler.
- *
- * @param p Pointer to the uprobe.
- * @param regs Pointer to CPU register data.
- * @return 0.
- */
-int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct ujprobe *jp = container_of(p, struct ujprobe, up);
-       entry_point_t entry = (entry_point_t)jp->entry;
-
-       if (entry) {
-               entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
-                     regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
-       } else {
-               arch_ujprobe_return();
-       }
-
-       return 0;
-}
-
-/**
- * @brief Gets trampoline address.
- *
- * @param p Pointer to the uprobe.
- * @param regs Pointer to CPU register data.
- * @return Trampoline address.
- */
-unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
-{
-       return thumb_mode(regs) ?
-                       (unsigned long)(p->insn) + 0x1b :
-                       (unsigned long)(p->insn +
-                                       PROBES_TRAMP_RET_BREAK_IDX);
-}
-
-/**
- * @brief Restores return address.
- *
- * @param orig_ret_addr Original return address.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
-{
-       regs->ARM_lr = orig_ret_addr;
-       regs->ARM_pc = orig_ret_addr & ~0x1;
-
-       if (regs->ARM_lr & 0x1)
-               regs->ARM_cpsr |= PSR_T_BIT;
-       else
-               regs->ARM_cpsr &= ~PSR_T_BIT;
-}
-
-/**
- * @brief Removes uprobe.
- *
- * @param up Pointer to the uprobe.
- * @return Void.
- */
-void arch_remove_uprobe(struct uprobe *up)
-{
-       swap_slot_free(up->sm, up->insn);
-}
-
-static int urp_handler(struct pt_regs *regs, pid_t tgid)
-{
-       struct uprobe *p;
-       unsigned long flags;
-       unsigned long vaddr = regs->ARM_pc;
-       unsigned long offset_bp = thumb_mode(regs) ?
-                                 0x1a :
-                                 4 * PROBES_TRAMP_RET_BREAK_IDX;
-       unsigned long tramp_addr = vaddr - offset_bp;
-
-       local_irq_save(flags);
-       p = get_uprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
-       if (unlikely(p == NULL)) {
-               local_irq_restore(flags);
-
-               pr_info("no_uprobe: Not one of ours: let kernel handle it %lx\n",
-                       vaddr);
-               return 1;
-       }
-
-       get_up(p);
-       local_irq_restore(flags);
-       trampoline_uprobe_handler(p, regs);
-       put_up(p);
-
-       return 0;
-}
-/**
- * @brief Prepares singlestep for current CPU.
- *
- * @param p Pointer to kprobe.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-static void arch_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
-{
-       if (p->ainsn.insn.handler) {
-               regs->ARM_pc += 4;
-               p->ainsn.insn.handler(p->opcode, &p->ainsn.insn, regs);
-       } else {
-               regs->ARM_pc = (unsigned long)p->insn;
-       }
-}
-
-/**
- * @brief Breakpoint instruction handler.
- *
- * @param regs Pointer to CPU register data.
- * @param instr Instruction.
- * @return uprobe_handler results.
- */
-static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
-{
-       int ret = 0;
-       struct uprobe *p;
-       unsigned long flags;
-       unsigned long vaddr = regs->ARM_pc | !!thumb_mode(regs);
-       pid_t tgid = current->tgid;
-
-       local_irq_save(flags);
-       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
-       if (p) {
-               get_up(p);
-               local_irq_restore(flags);
-               if (!p->pre_handler || !p->pre_handler(p, regs))
-                       arch_prepare_singlestep(p, regs);
-               put_up(p);
-       } else {
-               local_irq_restore(flags);
-               ret = urp_handler(regs, tgid);
-
-               /* check ARM/THUMB CPU mode matches installed probe mode */
-               if (ret) {
-                       vaddr ^= 1;
-
-                       local_irq_save(flags);
-                       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
-                       if (p) {
-                               get_up(p);
-                               local_irq_restore(flags);
-                               pr_err("invalid mode: thumb=%d addr=%p insn=%08x\n",
-                                      !!thumb_mode(regs), p->addr, p->opcode);
-                               ret = 0;
-
-                               disarm_uprobe(p, current);
-                               put_up(p);
-                       } else {
-                               local_irq_restore(flags);
-                       }
-               }
-       }
-
-       return ret;
-}
-
-/* userspace probes hook (arm) */
-static struct undef_hook undef_hook_for_us_arm = {
-       .instr_mask     = 0xffffffff,
-       .instr_val      = BREAK_ARM,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = USR_MODE,
-       .fn             = uprobe_trap_handler
-};
-
-/* userspace probes hook (thumb) */
-static struct undef_hook undef_hook_for_us_thumb = {
-       .instr_mask     = 0xffffffff,
-       .instr_val      = BREAK_THUMB,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = USR_MODE,
-       .fn             = uprobe_trap_handler
-};
-
-/**
- * @brief Installs breakpoint hooks.
- *
- * @return 0.
- */
-int swap_arch_init_uprobes(void)
-{
-       swap_register_undef_hook(&undef_hook_for_us_arm);
-       swap_register_undef_hook(&undef_hook_for_us_thumb);
-
-       return 0;
-}
-
-/**
- * @brief Uninstalls breakpoint hooks.
- *
- * @return Void.
- */
-void swap_arch_exit_uprobes(void)
-{
-       swap_unregister_undef_hook(&undef_hook_for_us_thumb);
-       swap_unregister_undef_hook(&undef_hook_for_us_arm);
-}
diff --git a/uprobe/arch/arm/swap-asm/swap_uprobes.h b/uprobe/arch/arm/swap-asm/swap_uprobes.h
deleted file mode 100644 (file)
index 87d8159..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * @file uprobe/arch/asm-arm/swap_uprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface declaration.
- */
-
-
-#ifndef _ARM_SWAP_UPROBES_H
-#define _ARM_SWAP_UPROBES_H
-
-
-#include <linux/uaccess.h>
-#include <arch/arm/probes/probes.h>
-#include <arch/arm/uprobe/swap_uprobe.h>
-
-
-/** Uprobes trampoline length */
-#define UPROBES_TRAMP_LEN      PROBES_TRAMP_LEN
-
-
-struct task_struct;
-struct uprobe;
-struct arch_insn;
-struct uretprobe;
-struct uretprobe_instance;
-
-typedef u32 uprobe_opcode_t;
-
-
-/**
- * @struct arch_insn
- * @brief Architecture depend copy of original instruction.
- * @var arch_insn::insn
- * Copy of the original instruction.
- */
-struct arch_insn {
-       struct arch_insn_arm insn;
-};
-
-
-static inline u32 swap_get_urp_float(struct pt_regs *regs)
-{
-       return regs->ARM_r0;
-}
-
-static inline u64 swap_get_urp_double(struct pt_regs *regs)
-{
-
-       return regs->ARM_r0 | (u64)regs->ARM_r1 << 32;
-}
-
-static inline void arch_ujprobe_return(void)
-{
-}
-
-int arch_prepare_uprobe(struct uprobe *up);
-int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
-static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
-{
-       return 0;
-}
-
-#define arch_urp_check_opcode NULL /* Arch doesn't requires special callback */
-void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task);
-
-unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
-void arch_remove_uprobe(struct uprobe *up);
-
-static inline int arch_arm_uprobe(struct uprobe *p)
-{
-       return arch_arm_uprobe_arm(p);
-}
-
-static inline void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
-{
-       arch_disarm_uprobe_arm(p, task);
-}
-
-static inline unsigned long swap_get_upc(struct pt_regs *regs)
-{
-       return swap_get_upc_arm(regs);
-}
-
-static inline void swap_set_upc(struct pt_regs *regs, unsigned long val)
-{
-       swap_set_upc_arm(regs, val);
-}
-
-static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
-{
-       return swap_get_uarg_arm(regs, n);
-}
-
-static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
-                                 unsigned long val)
-{
-       swap_put_uarg_arm(regs, n, val);
-}
-
-static inline unsigned long swap_get_uret_addr(struct pt_regs *regs)
-{
-       return swap_get_uret_addr_arm(regs);
-}
-
-static inline void swap_set_uret_addr(struct pt_regs *regs, unsigned long val)
-{
-       swap_set_uret_addr_arm(regs, val);
-}
-
-int swap_arch_init_uprobes(void);
-void swap_arch_exit_uprobes(void);
-
-#endif /* _ARM_SWAP_UPROBES_H */
diff --git a/uprobe/arch/arm64/swap-asm/swap_uprobes.c b/uprobe/arch/arm64/swap-asm/swap_uprobes.c
deleted file mode 100644 (file)
index d5e2627..0000000
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/kconfig.h>
-#include <linux/types.h>
-#include <asm/traps.h>
-#include <arch/arm/uprobe/swap_uprobe.h>
-#include <uprobe/swap_uprobes.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_td_raw.h>
-#include <kprobe/swap_kprobes_deps.h>  /* FIXME: remove it */
-#include <swap-asm/swap_probes.h>
-#include <arch/arm/uprobe/swap_uprobe.h>
-#include <swap-asm/dbg_interface.h>
-#include "uprobes-arm64.h"
-
-
-#define BRK_BP                 0x45
-#define BRK_PSEUDO_SS          0x54
-#define BRK_URP                        0x67
-#define BRK64_OPCODE_BP                MAKE_BRK(BRK_BP)
-#define BRK64_OPCODE_PSEUDO_SS MAKE_BRK(BRK_PSEUDO_SS)
-#define BRK64_OPCODE_URP       MAKE_BRK(BRK_URP)
-
-
-enum arch_mode {
-       AM_UNKNOWN,
-       AM_THUMB,
-       AM_ARM,
-       AM_ARM64
-};
-
-#define ARM64_MODE_VADDR_MASK          ((unsigned long)1 << 63)
-
-static enum arch_mode get_arch_mode(unsigned long vaddr)
-{
-       if (vaddr & 1)
-               return AM_THUMB;
-
-       if (vaddr & ARM64_MODE_VADDR_MASK)
-               return AM_ARM64;
-
-       return AM_ARM;
-}
-
-static unsigned long get_real_addr(unsigned long vaddr)
-{
-       return vaddr & ~(ARM64_MODE_VADDR_MASK | 1);
-}
-
-static unsigned long get_64bit_addr(unsigned long raddr)
-{
-       return raddr | ARM64_MODE_VADDR_MASK;
-}
-
-struct uprobe_ctlblk {
-       struct uprobe *p;
-};
-
-static struct td_raw td_raw;
-
-static struct uprobe_ctlblk *current_ctlblk(void)
-{
-       return (struct uprobe_ctlblk *)swap_td_raw(&td_raw, current);
-}
-
-static struct uprobe *get_current_uprobe(void)
-{
-       return current_ctlblk()->p;
-}
-
-static void set_current_uprobe(struct uprobe *p)
-{
-       current_ctlblk()->p = p;
-}
-
-static void reset_current_uprobe(void)
-{
-       set_current_uprobe(NULL);
-}
-
-
-static unsigned long trampoline_addr_arm64(struct uprobe *p)
-{
-       return (unsigned long)(p->insn + URP_RET_BREAK_IDX);
-}
-
-static int prepare_uretprobe_arm64(struct uretprobe_instance *ri,
-                                  struct pt_regs *regs)
-{
-       unsigned long bp_addr, ret_addr;
-
-       ret_addr = regs->regs[30] | ARM64_MODE_VADDR_MASK;
-       bp_addr = trampoline_addr_arm64(&ri->rp->up);
-
-       ri->sp = (uprobe_opcode_t *)regs->sp;
-       ri->ret_addr = (uprobe_opcode_t *)ret_addr;
-
-       /* replace the return address (regs[30] - lr) */
-       regs->regs[30] = bp_addr;
-
-       return 0;
-}
-
-int arch_prepare_uretprobe(struct uretprobe_instance *ri,
-                          struct pt_regs *regs)
-{
-       if (get_arch_mode((unsigned long)ri->rp->up.addr) == AM_ARM64)
-               return prepare_uretprobe_arm64(ri, regs);
-       else
-               return prepare_uretprobe_arm(ri, regs);
-}
-
-static void arch_opcode_analysis_uretprobe_arm64(struct uretprobe *rp)
-{
-       /* FIXME: to implement */
-}
-
-void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
-{
-       if (get_arch_mode((unsigned long)rp->up.addr) == AM_ARM64)
-               arch_opcode_analysis_uretprobe_arm64(rp);
-       else
-               arch_opcode_analysis_uretprobe_arm(rp);
-}
-
-/**
- * @brief Gets trampoline address.
- *
- * @param p Pointer to the kprobe.
- * @param regs Pointer to CPU register data.
- * @return Trampoline address.
- */
-unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
-{
-       if (get_arch_mode((unsigned long)p->addr) == AM_ARM64)
-               return trampoline_addr_arm64(p);
-       else
-               return arch_get_trampoline_addr_arm(p, regs);
-}
-
-static unsigned long arch_tramp_by_ri_arm64(struct uretprobe_instance *ri)
-{
-       return trampoline_addr_arm64(&ri->rp->up);
-}
-
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
-{
-       if (get_arch_mode((unsigned long)ri->rp->up.addr) == AM_ARM64)
-               return arch_tramp_by_ri_arm64(ri);
-       else
-               return arch_tramp_by_ri_arm(ri);
-}
-
-static int arch_disarm_urp_inst_arm64(struct uretprobe_instance *ri,
-                                     struct task_struct *task)
-{
-       struct pt_regs *uregs = task_pt_regs(ri->task);
-       u64 ra = uregs->regs[30];
-       u64 raddr, tramp, found = 0;
-       u64 sp = (u64)ri->sp;
-       u64 ret_addr = (u64)ri->ret_addr;
-       u64 stack = sp - 8 * (URETPROBE_STACK_DEPTH + 1);
-       u64 buf[URETPROBE_STACK_DEPTH];
-       int i, ret;
-
-       raddr = get_real_addr((unsigned long)ri->rp->up.addr);
-       tramp = arch_tramp_by_ri_arm64(ri);
-
-       /* check stack */
-       ret = read_proc_vm_atomic(task, stack, buf, sizeof(buf));
-       if (ret != sizeof(buf)) {
-               pr_info("---> %s (%d/%d): failed to read stack from %016llx\n",
-                       task->comm, task->tgid, task->pid, stack);
-               ret = -EFAULT;
-               goto check_lr;
-       }
-
-       /* search the stack from the bottom */
-       for (i = URETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
-               if (buf[i] == tramp) {
-                       found = stack + 8 * i;
-                       break;
-               }
-       }
-
-       if (!found) {
-               ret = -ESRCH;
-               goto check_lr;
-       }
-
-       pr_info("---> %s (%d/%d): trampoline found at "
-               "%016llx (%016llx /%+lld) - %llx, set ret_addr=%016llx\n",
-               task->comm, task->tgid, task->pid,
-               found, sp,
-               found - sp, raddr, ret_addr);
-       ret = write_proc_vm_atomic(task, found, &ret_addr, 8);
-       if (ret != 8) {
-               pr_info("---> %s (%d/%d): failed to write value to %016llx",
-                       task->comm, task->tgid, task->pid, found);
-               ret = -EFAULT;
-       } else {
-               ret = 0;
-       }
-
-check_lr: /* check lr anyway */
-       if (ra == tramp) {
-               pr_info("---> %s (%d/%d): trampoline found at "
-                       "lr = %016llx - %llx, set ret_addr=%016llx\n",
-                       task->comm, task->tgid, task->pid, ra, raddr,
-                       ret_addr);
-
-               /* set ret_addr */
-               uregs->regs[30] = ret_addr;
-               ret = 0;
-       } else if (ret) {
-               pr_info("---> %s (%d/%d): trampoline NOT found at "
-                       "sp=%016llx, lr=%016llx - %llx, ret_addr=%016llx\n",
-                       task->comm, task->tgid, task->pid,
-                       sp, ra, raddr, ret_addr);
-       }
-
-       return ret;
-}
-
-/**
- * @brief Disarms uretprobe instance.
- *
- * @param ri Pointer to the uretprobe instance
- * @param task Pointer to the task for which the uretprobe instance
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task)
-{
-       if (get_arch_mode((unsigned long)ri->rp->up.addr) == AM_ARM64)
-               return arch_disarm_urp_inst_arm64(ri, task);
-       else
-               return arch_disarm_urp_inst_arm(ri, task);
-}
-
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
-{
-       if (get_arch_mode(orig_ret_addr) == AM_ARM64) {
-               regs->pc = get_real_addr(orig_ret_addr);
-       } else {
-               set_orig_ret_addr_arm(orig_ret_addr, regs);
-       }
-}
-
-static enum dbg_code urp_handler(struct pt_regs *regs, unsigned int esr)
-{
-       struct uprobe *p;
-       unsigned long pc = regs->pc;
-       unsigned long insn_addr = pc - sizeof(u32) * URP_RET_BREAK_IDX;
-
-       p = get_uprobe_by_insn_slot((void *)insn_addr, current->tgid, regs);
-       if (p == NULL) {
-               pr_err("no_uretprobe: Not one of ours: let "
-                      "kernel handle it %lx\n", pc);
-               return DBG_ERROR;
-       }
-
-       local_irq_enable();
-       trampoline_uprobe_handler(p, regs);
-
-       return DBG_HANDLED;
-}
-
-static int arch_arm_uprobe_arm64(struct uprobe *p)
-{
-       int ret;
-       unsigned long vaddr = (unsigned long)p->addr;
-       unsigned long raddr = get_real_addr(vaddr);
-       u32 insn = BRK64_OPCODE_BP;
-
-       ret = write_proc_vm_atomic(p->task, raddr, &insn, sizeof(insn));
-       if (!ret) {
-               pr_err("failed to write memory addr=%lx\n", vaddr);
-               return -EACCES;
-       }
-
-       return 0;
-}
-
-static void arch_disarm_uprobe_arm64(struct uprobe *p,
-                                    struct task_struct *task)
-{
-       unsigned long vaddr = (unsigned long)p->addr;
-       unsigned long raddr = get_real_addr(vaddr);
-       int ret;
-
-       ret = write_proc_vm_atomic(task, raddr, &p->opcode, sizeof(p->opcode));
-       if (!ret)
-               pr_err("failed to write memory vaddr=%lx\n", vaddr);
-}
-
-int arch_arm_uprobe(struct uprobe *p)
-{
-       int ret;
-       unsigned long vaddr = (unsigned long)p->addr;
-
-       switch (get_arch_mode(vaddr)) {
-       case AM_THUMB:
-       case AM_ARM:
-               ret = arch_arm_uprobe_arm(p);
-               break;
-       case AM_ARM64:
-               ret = arch_arm_uprobe_arm64(p);
-               break;
-       default:
-               pr_err("Error: unknown mode vaddr=%lx\n", vaddr);
-               return -EINVAL;
-       }
-
-       return ret;
-}
-
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
-{
-       unsigned long vaddr = (unsigned long)p->addr;
-
-       switch (get_arch_mode(vaddr)) {
-       case AM_THUMB:
-       case AM_ARM:
-               arch_disarm_uprobe_arm(p, task);
-               break;
-       case AM_ARM64:
-               arch_disarm_uprobe_arm64(p, task);
-               break;
-       default:
-               pr_err("Error: unknown mode vaddr=%lx\n", vaddr);
-               break;
-       }
-}
-
-
-static void arch_prepare_simulate_arm64(struct uprobe *p)
-{
-       if (p->ainsn.prepare)
-               p->ainsn.prepare(p, &p->ainsn);
-}
-
-static int arch_prepare_ss_arm64(struct uprobe *p, u32 insn, u32 __user *utramp)
-{
-       u32 tramp[2];
-
-       /* prepare insn slot */
-       tramp[0] = insn;
-       tramp[1] = BRK64_OPCODE_PSEUDO_SS;
-
-       if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp, 8)) {
-               pr_err("%s: failed to write memory %p\n", __func__, utramp);
-               return -EACCES;
-       }
-
-       return 0;
-}
-
-static int arch_uretprobe_set_break_arm64(struct uprobe *p, u32 __user *utramp)
-{
-       int ret;
-       u32 urp_brk = BRK64_OPCODE_URP;
-       unsigned long brk_addr = (unsigned long)(utramp + URP_RET_BREAK_IDX);
-
-       ret = write_proc_vm_atomic(p->task, brk_addr, &urp_brk, sizeof(urp_brk));
-       if (ret != sizeof(urp_brk)) {
-               pr_err("%s failed to write memory %016lx\n",
-                      __func__, brk_addr);
-               return -EACCES;
-       }
-
-       return 0;
-}
-
-static int arch_prepare_uprobe_arm64(struct uprobe *p)
-{
-       int ret = 0;
-       struct task_struct *task = p->task;
-       unsigned long vaddr = (unsigned long)p->addr;
-       unsigned long raddr = get_real_addr(vaddr);
-       u32 insn, __user *utramp;
-
-       ret = read_proc_vm_atomic(task, raddr, &insn, sizeof(insn));
-       if (ret != sizeof(insn)) {
-               pr_err("failed to read memory %lx!\n", raddr);
-               return -EINVAL;
-       }
-
-       utramp = swap_slot_alloc(p->sm);
-       if (utramp == NULL) {
-               pr_err("ERROR: cannot allocate trampoline (%016lx)\n", vaddr);
-               return -ENOMEM;
-       }
-
-       switch (arm64_uprobe_decode_insn(insn, &p->ainsn)) {
-       case INSN_REJECTED:     /* insn not supported */
-               ret = -EINVAL;
-               break;
-
-       case INSN_GOOD_NO_SLOT: /* insn need simulation */
-               arch_prepare_simulate_arm64(p);
-               ret = 0;
-               break;
-
-       case INSN_GOOD:         /* instruction uses slot */
-               ret = arch_prepare_ss_arm64(p, insn, utramp);
-               break;
-       };
-
-       if (ret)
-               goto fail;
-
-       ret = arch_uretprobe_set_break_arm64(p, utramp);
-       if (ret)
-               goto fail;
-
-       p->insn = utramp;
-       p->opcode = insn;
-
-       return 0;
-
-fail:
-       swap_slot_free(p->sm, utramp);
-       return ret;
-}
-
-int arch_prepare_uprobe(struct uprobe *p)
-{
-       int ret;
-
-       if (get_arch_mode((unsigned long)p->addr) == AM_ARM64) {
-               ret = arch_prepare_uprobe_arm64(p);
-       } else {
-               ret = arch_prepare_uprobe_arm(p);
-       }
-
-       if (!ret) {
-               /* for uretprobe */
-               add_uprobe_table(p);
-       }
-
-       return ret;
-}
-
-void arch_remove_uprobe(struct uprobe *p)
-{
-       swap_slot_free(p->sm, p->insn);
-}
-
-static void simulate_insn_arm64(struct uprobe *p, struct pt_regs *regs)
-{
-       if (p->ainsn.handler)
-               p->ainsn.handler(p->opcode, (long)p->addr, regs);
-
-       reset_current_uprobe();
-}
-
-static void setup_ss_arm64(struct uprobe *p, struct pt_regs *regs)
-{
-       /* set trampoline */
-       regs->pc = (u64)p->insn;
-
-       set_current_uprobe(p);
-}
-
-static void setup_singlestep(struct uprobe *p, struct pt_regs *regs)
-{
-       if (p->ainsn.handler)
-               simulate_insn_arm64(p, regs);
-       else
-               setup_ss_arm64(p, regs);
-}
-
-static enum dbg_code uprobe_handler_compat(struct pt_regs *regs)
-{
-       pr_err("ARM and THUMB modes not supported\n");
-       return DBG_ERROR;
-}
-
-static enum dbg_code uprobe_handler_arm64(struct pt_regs *regs)
-{
-       struct uprobe *p;
-
-       p = get_uprobe((void *)get_64bit_addr(regs->pc), current->tgid);
-       if (p) {
-               if (!p->pre_handler || !p->pre_handler(p, regs))
-                       setup_singlestep(p, regs);
-       } else {
-               return DBG_ERROR;
-       }
-
-       return DBG_HANDLED;
-}
-
-static enum dbg_code uprobe_handler(struct pt_regs *regs, unsigned int esr)
-{
-       local_irq_enable();
-
-       return compat_user_mode(regs) ?
-                       uprobe_handler_compat(regs) :
-                       uprobe_handler_arm64(regs);
-}
-
-static enum dbg_code uprobe_ss_handler(struct pt_regs *regs, unsigned int esr)
-{
-       struct uprobe *p;
-
-       p = get_current_uprobe();
-       if (p) {
-               regs->pc = (u64)p->addr + 4;
-               reset_current_uprobe();
-       }
-
-       return DBG_HANDLED;
-}
-
-
-static struct brk_hook dbg_up_bp = {
-       .spsr_mask = PSR_MODE_MASK,
-       .spsr_val = PSR_MODE_EL0t,
-       .esr_mask = DBG_BRK_ESR_MASK,
-       .esr_val = DBG_BRK_ESR(BRK_BP),
-       .fn = uprobe_handler,
-};
-
-static struct brk_hook dbg_up_ss = {
-       .spsr_mask = PSR_MODE_MASK,
-       .spsr_val = PSR_MODE_EL0t,
-       .esr_mask = DBG_BRK_ESR_MASK,
-       .esr_val = DBG_BRK_ESR(BRK_PSEUDO_SS),
-       .fn = uprobe_ss_handler,
-};
-
-static struct brk_hook dbg_urp_bp = {
-       .spsr_mask = PSR_MODE_MASK,
-       .spsr_val = PSR_MODE_EL0t,
-       .esr_mask = DBG_BRK_ESR_MASK,
-       .esr_val = DBG_BRK_ESR(BRK_URP),
-       .fn = urp_handler,
-};
-
-
-static void arch_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
-{
-       if (p->ainsn.insn.handler) {
-               regs->pc += 4;
-               p->ainsn.insn.handler(p->opcode, &p->ainsn.insn, regs);
-       } else {
-               regs->pc = (unsigned long)p->insn;
-       }
-}
-
-static int urp_handler_aarch32(struct pt_regs *regs, pid_t tgid)
-{
-       struct uprobe *p;
-       unsigned long vaddr = regs->pc;
-       unsigned long offset_bp = compat_thumb_mode(regs) ?
-                                 0x1a :
-                                 4 * PROBES_TRAMP_RET_BREAK_IDX;
-       unsigned long tramp_addr = vaddr - offset_bp;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       p = get_uprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
-       if (unlikely(p == NULL)) {
-               local_irq_restore(flags);
-
-               pr_info("no_uprobe: Not one of ours: let kernel handle it %lx\n",
-                       vaddr);
-               return 1;
-       }
-
-       get_up(p);
-       local_irq_restore(flags);
-       trampoline_uprobe_handler(p, regs);
-       put_up(p);
-
-       return 0;
-}
-
-static int uprobe_handler_aarch32(struct pt_regs *regs, u32 instr)
-{
-       int ret = 0;
-       struct uprobe *p;
-       unsigned long flags;
-       unsigned long vaddr = regs->pc | !!compat_thumb_mode(regs);
-       pid_t tgid = current->tgid;
-
-       local_irq_enable();
-
-       local_irq_save(flags);
-       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
-       if (p) {
-               get_up(p);
-               local_irq_restore(flags);
-
-               if (!p->pre_handler || !p->pre_handler(p, regs))
-                       arch_prepare_singlestep(p, regs);
-
-               put_up(p);
-       } else {
-               local_irq_restore(flags);
-               ret = urp_handler_aarch32(regs, tgid);
-
-               /* check ARM/THUMB CPU mode matches installed probe mode */
-               if (ret == 1) {
-                       vaddr ^= 1;
-
-                       local_irq_save(flags);
-                       p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
-                       if (p) {
-                               get_up(p);
-                               local_irq_restore(flags);
-                               pr_err("invalid mode: thumb=%d addr=%p insn=%08x\n",
-                                      !!compat_thumb_mode(regs), p->addr, p->opcode);
-                               ret = 0;
-
-                               disarm_uprobe(p, current);
-                               put_up(p);
-                       } else {
-                               local_irq_restore(flags);
-                       }
-               }
-       }
-
-       return ret;
-}
-
-
-static void (*__register_undef_hook)(struct undef_hook *hook);
-static void (*__unregister_undef_hook)(struct undef_hook *hook);
-
-static int undef_hook_once(void)
-{
-       const char *sym;
-
-       sym = "register_undef_hook";
-       __register_undef_hook = (void *)swap_ksyms(sym);
-       if (__register_undef_hook == NULL)
-               goto not_found;
-
-       sym = "unregister_undef_hook";
-       __unregister_undef_hook = (void *)swap_ksyms(sym);
-       if (__unregister_undef_hook == NULL)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       pr_err("ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-
-}
-
-static struct undef_hook undef_hook_arm = {
-       .instr_mask = 0xffffffff,
-       .instr_val = BREAK_ARM,
-       .pstate_mask = COMPAT_PSR_MODE_MASK,
-       .pstate_val = COMPAT_PSR_MODE_USR,
-       .fn = uprobe_handler_aarch32,
-};
-
-static struct undef_hook undef_hook_thumb = {
-       .instr_mask = 0xffff,
-       .instr_val = BREAK_THUMB,
-       .pstate_mask = COMPAT_PSR_MODE_MASK,
-       .pstate_val = COMPAT_PSR_MODE_USR,
-       .fn = uprobe_handler_aarch32,
-};
-
-int swap_arch_init_uprobes(void)
-{
-       int ret;
-
-       ret = undef_hook_once();
-       if (ret)
-               return ret;
-
-       ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk));
-       if (ret)
-               return ret;
-
-       if (!IS_ENABLED(CONFIG_SWAP_KERNEL_IMMUTABLE)) {
-               /* for aarch64 */
-               dbg_brk_hook_reg(&dbg_up_ss);
-               dbg_brk_hook_reg(&dbg_up_bp);
-               dbg_brk_hook_reg(&dbg_urp_bp);
-       } else {
-               pr_err("64-bit uprobes doesn't supported in case of Immutable kernel\n");
-       }
-
-       /* for aarch32 */
-       __register_undef_hook(&undef_hook_arm);
-       __register_undef_hook(&undef_hook_thumb);
-
-       return 0;
-}
-
-void swap_arch_exit_uprobes(void)
-{
-       /* for aarch32 */
-       __unregister_undef_hook(&undef_hook_thumb);
-       __unregister_undef_hook(&undef_hook_arm);
-
-       if (!IS_ENABLED(CONFIG_SWAP_KERNEL_IMMUTABLE)) {
-               /* for aarch64 */
-               dbg_brk_hook_unreg(&dbg_urp_bp);
-               dbg_brk_hook_unreg(&dbg_up_bp);
-               dbg_brk_hook_unreg(&dbg_up_ss);
-       }
-
-       swap_td_raw_unreg(&td_raw);
-}
diff --git a/uprobe/arch/arm64/swap-asm/swap_uprobes.h b/uprobe/arch/arm64/swap-asm/swap_uprobes.h
deleted file mode 100644 (file)
index 2a36785..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-#ifndef _ASM_ARM64_UPROBES_H
-#define _ASM_ARM64_UPROBES_H
-
-/*
- * 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, 2014
- *
- * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <arch/arm/probes/probes.h>
-#include <arch/arm/uprobe/swap_uprobe.h>
-
-
-#define UP_TRAMP_INSN_CNT  3 /* | opcode | ss_bp | urp_bp | */
-#define UPROBES_TRAMP_LEN  (UP_TRAMP_INSN_CNT * 4) /* 4 - instruction size */
-#define URP_RET_BREAK_IDX  2
-
-
-struct uprobe;
-struct arch_insn;
-struct uretprobe;
-struct task_struct;
-struct uretprobe_instance;
-
-
-typedef unsigned long (uprobes_pstate_check_t)(unsigned long pstate);
-typedef unsigned long (uprobes_condition_check_t)(struct uprobe *p,
-                                                 struct pt_regs *regs);
-typedef void (uprobes_prepare_t)(struct uprobe *p, struct arch_insn *asi);
-typedef void (uprobes_handler_t)(u32 opcode, long addr, struct pt_regs *regs);
-
-
-struct arch_insn {
-       /* arm */
-       struct arch_insn_arm insn;
-
-       /* arm64 */
-       uprobes_pstate_check_t *pstate_cc;
-       uprobes_condition_check_t *check_condn;
-       uprobes_prepare_t *prepare;
-       uprobes_handler_t *handler;
-};
-
-
-typedef u32 uprobe_opcode_t;
-
-static inline u32 swap_get_float(struct pt_regs *regs, unsigned long n)
-{
-       u32 *ptr;
-       register unsigned long w0 asm ("w0");
-
-       switch (n) {
-       case 0:
-               asm volatile("fmov w0, s0");
-               break;
-       case 1:
-               asm volatile("fmov w0, s1");
-               break;
-       case 2:
-               asm volatile("fmov w0, s2");
-               break;
-       case 3:
-               asm volatile("fmov w0, s3");
-               break;
-       case 4:
-               asm volatile("fmov w0, s4");
-               break;
-       case 5:
-               asm volatile("fmov w0, s5");
-               break;
-       case 6:
-               asm volatile("fmov w0, s6");
-               break;
-       case 7:
-               asm volatile("fmov w0, s7");
-               break;
-       default:
-               w0 = 0;
-               ptr = (u32 *)((u64 *)regs->sp + n - 8);
-               if (get_user(w0, ptr))
-                       pr_err("failed to dereference a pointer\n");
-
-               break;
-       }
-
-       return w0;
-}
-
-static inline u64 swap_get_double(struct pt_regs *regs, unsigned long n)
-{
-       u64 *ptr;
-       register unsigned long x0 asm ("x0");
-
-       switch (n) {
-       case 0:
-               asm volatile("fmov x0, d0");
-               break;
-       case 1:
-               asm volatile("fmov x0, d1");
-               break;
-       case 2:
-               asm volatile("fmov x0, d2");
-               break;
-       case 3:
-               asm volatile("fmov x0, d3");
-               break;
-       case 4:
-               asm volatile("fmov x0, d4");
-               break;
-       case 5:
-               asm volatile("fmov x0, d5");
-               break;
-       case 6:
-               asm volatile("fmov x0, d6");
-               break;
-       case 7:
-               asm volatile("fmov x0, d7");
-               break;
-       default:
-               x0 = 0;
-               ptr = (u64 *)regs->sp + n - 8;
-               if (get_user(x0, ptr))
-                       pr_err("failed to dereference a pointer\n");
-
-               break;
-       }
-
-       return x0;
-}
-
-static inline u32 swap_get_urp_float(struct pt_regs *regs)
-{
-       return swap_get_float(regs, 0);
-}
-
-static inline u64 swap_get_urp_double(struct pt_regs *regs)
-{
-       return swap_get_double(regs, 0);
-}
-
-static inline unsigned long swap_get_upc_arm64(struct pt_regs *regs)
-{
-       return regs->pc;
-}
-
-static inline void swap_set_upc_arm64(struct pt_regs *regs, unsigned long val)
-{
-       regs->pc = val;
-}
-
-static inline unsigned long swap_get_uarg_arm64(struct pt_regs *regs,
-                                               unsigned long n)
-{
-       u64 *ptr, val;
-
-       if (n < 8)
-               return regs->regs[n];
-
-       ptr = (u64 *)regs->sp + n - 8;
-       if (get_user(val, ptr))
-               pr_err("failed to dereference a pointer, ptr=%p\n", ptr);
-
-       return val;
-}
-
-static inline void swap_put_uarg_arm64(struct pt_regs *regs, unsigned long n,
-                                      unsigned long val)
-{
-       if (n < 8) {
-               regs->regs[n] = val;
-       } else {
-               u64 *ptr = (u64 *)regs->sp + n - 8;
-               if (put_user(val, ptr))
-                       pr_err("Failed to dereference a pointer, ptr=%p\n", ptr);
-       }
-}
-
-static inline unsigned long swap_get_uret_addr_arm64(struct pt_regs *regs)
-{
-       return regs->regs[30];
-}
-
-static inline void swap_set_uret_addr_arm64(struct pt_regs *regs,
-                                           unsigned long val)
-{
-       regs->regs[30] = val;
-}
-
-static inline unsigned long swap_get_upc(struct pt_regs *regs)
-{
-       if (compat_user_mode(regs))
-               return swap_get_upc_arm(regs);
-       else
-               return swap_get_upc_arm64(regs);
-}
-
-static inline void swap_set_upc(struct pt_regs *regs, unsigned long val)
-{
-       if (compat_user_mode(regs))
-               swap_set_upc_arm(regs, val);
-       else
-               swap_set_upc_arm64(regs, val);
-}
-
-static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
-{
-       if (compat_user_mode(regs))
-               return swap_get_uarg_arm(regs, n);
-       else
-               return swap_get_uarg_arm64(regs, n);
-}
-
-static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
-                                unsigned long val)
-{
-       if (compat_user_mode(regs))
-               return swap_put_uarg_arm(regs, n, val);
-       else
-               return swap_put_uarg_arm64(regs, n, val);
-}
-
-static inline unsigned long swap_get_uret_addr(struct pt_regs *regs)
-{
-       if (compat_user_mode(regs))
-               return swap_get_uret_addr_arm(regs);
-       else
-               return swap_get_uret_addr_arm64(regs);
-}
-
-static inline void swap_set_uret_addr(struct pt_regs *regs, unsigned long val)
-{
-       if (compat_user_mode(regs))
-               swap_set_uret_addr_arm(regs, val);
-       else
-               swap_set_uret_addr_arm64(regs, val);
-}
-
-int arch_prepare_uprobe(struct uprobe *p);
-void arch_remove_uprobe(struct uprobe *p);
-
-static inline int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       WARN(1, "not implemented"); /* FIXME: to implement */
-       return 0;
-}
-
-static inline int longjmp_break_uhandler(struct uprobe *p,
-                                        struct pt_regs *regs)
-{
-       WARN(1, "not implemented"); /* FIXME: to implement */
-       return 0;
-}
-
-
-int arch_arm_uprobe(struct uprobe *p);
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
-
-
-unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
-int arch_prepare_uretprobe(struct uretprobe_instance *ri,
-                          struct pt_regs *regs);
-
-#define arch_urp_check_opcode NULL /* Arch doesn't requires special callback */
-void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task);
-
-static inline void arch_ujprobe_return(void)
-{
-       WARN(1, "not implemented"); /* FIXME: to implement */
-}
-
-int swap_arch_init_uprobes(void);
-void swap_arch_exit_uprobes(void);
-
-
-#endif /* _ASM_ARM64_UPROBES_H */
diff --git a/uprobe/arch/arm64/swap-asm/uprobes-arm64.c b/uprobe/arch/arm64/swap-asm/uprobes-arm64.c
deleted file mode 100644 (file)
index c0173bb..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/kprobes-arm64.c
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-
-#include <asm/ptrace.h>
-#include <uprobe/swap_uprobes.h>
-#include <swap-asm/simulate-insn.h>
-#include <swap-asm/condn-helpers.h>
-
-#include "uprobes-decode.h"
-#include "uprobes-arm64.h"
-
-
-/*
- * condition check functions for uprobes simulation
- */
-static unsigned long __check_pstate(struct uprobe *p, struct pt_regs *regs)
-{
-       struct arch_insn *asi = &p->ainsn;
-       unsigned long pstate = regs->pstate & 0xffffffff;
-
-       return asi->pstate_cc(pstate);
-}
-
-static unsigned long __check_cbz(struct uprobe *p, struct pt_regs *regs)
-{
-       return check_cbz((u32)p->opcode, regs);
-}
-
-static unsigned long __check_cbnz(struct uprobe *p, struct pt_regs *regs)
-{
-       return check_cbnz((u32)p->opcode, regs);
-}
-
-static unsigned long __check_tbz(struct uprobe *p, struct pt_regs *regs)
-{
-       return check_tbz((u32)p->opcode, regs);
-}
-
-static unsigned long __check_tbnz(struct uprobe *p, struct pt_regs *regs)
-{
-       return check_tbnz((u32)p->opcode, regs);
-}
-
-/*
- * prepare functions for instruction simulation
- */
-static void prepare_none(struct uprobe *p, struct arch_insn *asi)
-{
-}
-
-static void prepare_bcond(struct uprobe *p, struct arch_insn *asi)
-{
-       uprobe_opcode_t insn = p->opcode;
-
-       asi->check_condn = __check_pstate;
-       asi->pstate_cc = probe_condition_checks[insn & 0xf];
-}
-
-static void prepare_cbz_cbnz(struct uprobe *p, struct arch_insn *asi)
-{
-       uprobe_opcode_t insn = p->opcode;
-
-       asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz;
-}
-
-static void prepare_tbz_tbnz(struct uprobe *p, struct arch_insn *asi)
-{
-       uprobe_opcode_t insn = p->opcode;
-
-       asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz;
-}
-
-
-/* Load literal (PC-relative) instructions
- * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
- *
- * opcode[26]: V=0, Load GP registers, simulate them.
- * Encoding: xx01 1000 xxxx xxxx xxxx xxxx xxxx xxxx
- *     opcode[31:30]: op = 00, 01 - LDR literal
- *     opcode[31:30]: op = 10,    - LDRSW literal
- *
- * 1.   V=1 -Load FP/AdvSIMD registers
- *     Encoding: xx01 1100 xxxx xxxx xxxx xxxx xxxx xxxx
- * 2.   V=0,opc=11 -PRFM(Prefetch literal)
- *     Encoding: 1101 1000 xxxx xxxx xxxx xxxx xxxx xxxx
- *     Reject FP/AdvSIMD literal load & PRFM literal.
- */
-static const struct aarch64_decode_item load_literal_subtable[] = {
-       DECODE_REJECT(0x1C000000, 0x3F000000),
-       DECODE_REJECT(0xD8000000, 0xFF000000),
-       DECODE_LITERAL(0x18000000, 0xBF000000, prepare_none,
-                      simulate_ldr_literal),
-       DECODE_LITERAL(0x98000000, 0xFF000000, prepare_none,
-                      simulate_ldrsw_literal),
-       DECODE_END,
-};
-
-/* AArch64 instruction decode table for kprobes:
- * The instruction will fall into one of the 3 groups:
- *  1. Single stepped out-of-the-line slot.
- *     -Most instructions fall in this group, those does not
- *      depend on PC address.
- *
- *  2. Should be simulated because of PC-relative/literal access.
- *     -All branching and PC-relative insrtcutions are simulated
- *      in C code, making use of saved pt_regs
- *      Catch: SIMD/NEON register context are not saved while
- *      entering debug exception, so are rejected for now.
- *
- *  3. Cannot be probed(not safe) so are rejected.
- *     - Exception generation and exception return instructions
- *     - Exclusive monitor(LDREX/STREX family)
- *
- */
-static const struct aarch64_decode_item aarch64_decode_table[] = {
-       /*
-        * Data processing - PC relative(literal) addressing:
-        * Encoding: xxx1 0000 xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_LITERAL(0x10000000, 0x1F000000, prepare_none,
-                       simulate_adr_adrp),
-
-       /*
-        * Data processing - Add/Substract Immediate:
-        * Encoding: xxx1 0001 xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x11000000, 0x1F000000),
-
-       /*
-        * Data processing
-        * Encoding:
-        *      xxx1 0010 0xxx xxxx xxxx xxxx xxxx xxxx (Logical)
-        *      xxx1 0010 1xxx xxxx xxxx xxxx xxxx xxxx (Move wide)
-        *      xxx1 0011 0xxx xxxx xxxx xxxx xxxx xxxx (Bitfield)
-        *      xxx1 0011 1xxx xxxx xxxx xxxx xxxx xxxx (Extract)
-        */
-       DECODE_SINGLESTEP(0x12000000, 0x1E000000),
-
-       /*
-        * Data processing - SIMD/FP/AdvSIMD/Crypto-AES/SHA
-        * Encoding: xxx0 111x xxxx xxxx xxxx xxxx xxxx xxxx
-        * Encoding: xxx1 111x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x0E000000, 0x0E000000),
-
-       /*
-        * Data processing - Register
-        * Encoding: xxxx 101x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x0A000000, 0x0E000000),
-
-       /* Branching Instructions
-        *
-        * Encoding:
-        *  x001 01xx xxxx xxxx xxxx xxxx xxxx xxxx (uncondtional Branch)
-        *  x011 010x xxxx xxxx xxxx xxxx xxxx xxxx (compare & branch)
-        *  x011 011x xxxx xxxx xxxx xxxx xxxx xxxx (Test & Branch)
-        *  0101 010x xxxx xxxx xxxx xxxx xxxx xxxx (Conditional, immediate)
-        *  1101 011x xxxx xxxx xxxx xxxx xxxx xxxx (Unconditional,register)
-        */
-       DECODE_BRANCH(0x14000000, 0x7C000000, prepare_none,
-                       simulate_b_bl),
-       DECODE_BRANCH(0x34000000, 0x7E000000, prepare_cbz_cbnz,
-                     simulate_cbz_cbnz),
-       DECODE_BRANCH(0x36000000, 0x7E000000, prepare_tbz_tbnz,
-                     simulate_tbz_tbnz),
-       DECODE_BRANCH(0x54000000, 0xFE000000, prepare_bcond,
-                       simulate_b_cond),
-       DECODE_BRANCH(0xD6000000, 0xFE000000, prepare_none,
-                     simulate_br_blr_ret),
-
-       /* System insn:
-        * Encoding: 1101 0101 00xx xxxx xxxx xxxx xxxx xxxx
-        *
-        * Note: MSR immediate (update PSTATE daif) is not safe handling
-        * within kprobes, rejected.
-        *
-        * Don't re-arrange these decode table entries.
-        */
-       DECODE_REJECT(0xD500401F, 0xFFF8F01F),
-       DECODE_SINGLESTEP(0xD5000000, 0xFFC00000),
-
-       /* Exception Generation:
-        * Encoding:  1101 0100 xxxx xxxx xxxx xxxx xxxx xxxx
-        * Instructions: SVC, HVC, SMC, BRK, HLT, DCPS1, DCPS2, DCPS3
-        */
-       DECODE_REJECT(0xD4000000, 0xFF000000),
-
-       /*
-        * Load/Store - Exclusive monitor
-        * Encoding: xx00 1000 xxxx xxxx xxxx xxxx xxxx xxxx
-        *
-        * Reject exlusive monitor'ed instructions
-        */
-       DECODE_REJECT(0x08000000, 0x3F000000),
-
-       /*
-        * Load/Store - PC relative(literal):
-        * Encoding:  xx01 1x00 xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE(0x18000000, 0x3B000000, load_literal_subtable),
-
-       /*
-        * Load/Store - Register Pair
-        * Encoding:
-        *      xx10 1x00 0xxx xxxx xxxx xxxx xxxx xxxx
-        *      xx10 1x00 1xxx xxxx xxxx xxxx xxxx xxxx
-        *      xx10 1x01 0xxx xxxx xxxx xxxx xxxx xxxx
-        *      xx10 1x01 1xxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_SINGLESTEP(0x28000000, 0x3A000000),
-
-       /*
-        * Load/Store - Register
-        * Encoding:
-        *      xx11 1x00 xx0x xxxx xxxx 00xx xxxx xxxx (unscaled imm)
-        *      xx11 1x00 xx0x xxxx xxxx 01xx xxxx xxxx (imm post-indexed)
-        *      xx11 1x00 xx0x xxxx xxxx 10xx xxxx xxxx (unpriviledged)
-        *      xx11 1x00 xx0x xxxx xxxx 11xx xxxx xxxx (imm pre-indexed)
-        *
-        *      xx11 1x00 xx10 xxxx xxxx xx10 xxxx xxxx (register offset)
-        *
-        *      xx11 1x01 xxxx xxxx xxxx xxxx xxxx xxxx (unsigned imm)
-        */
-       DECODE_SINGLESTEP(0x38000000, 0x3B200000),
-       DECODE_SINGLESTEP(0x38200200, 0x38300300),
-       DECODE_SINGLESTEP(0x39000000, 0x3B000000),
-
-       /*
-        * Load/Store - AdvSIMD
-        * Encoding:
-        *  0x00 1100 0x00 0000 xxxx xxxx xxxx xxxx (Multiple-structure)
-        *  0x00 1100 1x0x xxxx xxxx xxxx xxxx xxxx (Multi-struct post-indexed)
-        *  0x00 1101 0xx0 0000 xxxx xxxx xxxx xxxx (Single-structure))
-        *  0x00 1101 1xxx xxxx xxxx xxxx xxxx xxxx (Single-struct post-index)
-        */
-       DECODE_SINGLESTEP(0x0C000000, 0xBFBF0000),
-       DECODE_SINGLESTEP(0x0C800000, 0xBFA00000),
-       DECODE_SINGLESTEP(0x0D000000, 0xBF9F0000),
-       DECODE_SINGLESTEP(0x0D800000, 0xBF800000),
-
-       /* Unallocated:         xxx0 0xxx xxxx xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT(0x00000000, 0x18000000),
-       DECODE_END,
-};
-
-static int uprobe_decode_insn(u32 insn, struct arch_insn *asi,
-                             const struct aarch64_decode_item *tbl)
-{
-       unsigned int entry, ret = INSN_REJECTED;
-
-       for (entry = 0; !decode_table_end(tbl[entry]); entry++) {
-               if (decode_table_hit(tbl[entry], insn))
-                       break;
-       }
-
-       switch (decode_get_type(tbl[entry])) {
-       case DECODE_TYPE_END:
-       case DECODE_TYPE_REJECT:
-       default:
-               ret = INSN_REJECTED;
-               break;
-
-       case DECODE_TYPE_SINGLESTEP:
-               ret = INSN_GOOD;
-               break;
-
-       case DECODE_TYPE_SIMULATE:
-               asi->prepare = decode_prepare_fn(tbl[entry]);
-               asi->handler = decode_handler_fn(tbl[entry]);
-               ret = INSN_GOOD_NO_SLOT;
-               break;
-
-       case DECODE_TYPE_TABLE:
-               /* recurse with next level decode table */
-               ret = uprobe_decode_insn(insn, asi,
-                                        decode_sub_table(tbl[entry]));
-       };
-
-       return ret;
-}
-
-/* Return:
- *   INSN_REJECTED     If instruction is one not allowed to kprobe,
- *   INSN_GOOD         If instruction is supported and uses instruction slot,
- *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
- */
-enum uprobe_insn arm64_uprobe_decode_insn(u32 insn, struct arch_insn *asi)
-{
-       return uprobe_decode_insn(insn, asi, aarch64_decode_table);
-}
diff --git a/uprobe/arch/arm64/swap-asm/uprobes-arm64.h b/uprobe/arch/arm64/swap-asm/uprobes-arm64.h
deleted file mode 100644 (file)
index 6eed2d6..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/kprobes-arm64.h
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM_UPROBES_ARM64_H
-#define _ARM_UPROBES_ARM64_H
-
-
-enum uprobe_insn {
-       INSN_REJECTED,
-       INSN_GOOD_NO_SLOT,
-       INSN_GOOD,
-};
-
-
-enum uprobe_insn arm64_uprobe_decode_insn(u32 insn, struct arch_insn *asi);
-
-
-#endif /* _ARM_UPROBES_ARM64_H */
diff --git a/uprobe/arch/arm64/swap-asm/uprobes-decode.h b/uprobe/arch/arm64/swap-asm/uprobes-decode.h
deleted file mode 100644 (file)
index 8564df2..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) Samsung Electronics, 2014
- *
- * Copied from: arch/arm64/kernel/probes-decode.h
- *
- * Copyright (C) 2013 Linaro Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM64_KERNEL_UPROBES_DECODE_H
-#define _ARM64_KERNEL_UPROBES_DECODE_H
-
-
-#include "swap_uprobes.h"
-
-
-/*
- * The following definitions and macros are used to build instruction
- * decoding tables.
- */
-enum decode_type {
-       DECODE_TYPE_END,
-       DECODE_TYPE_SINGLESTEP,
-       DECODE_TYPE_SIMULATE,
-       DECODE_TYPE_TABLE,
-       DECODE_TYPE_REJECT,
-};
-
-struct aarch64_decode_item;
-
-struct aarch64_decode_header {
-       enum decode_type type;
-       u32 mask;
-       u32 val;
-};
-
-struct aarch64_decode_actions {
-       uprobes_prepare_t *prepare;
-       uprobes_handler_t *handler;
-};
-
-struct aarch64_decode_table {
-       const struct aarch64_decode_item *tbl;
-};
-
-union aarch64_decode_handler {
-       struct aarch64_decode_actions actions;
-       struct aarch64_decode_table table;
-};
-
-struct aarch64_decode_item {
-       struct aarch64_decode_header header;
-       union aarch64_decode_handler decode;
-};
-
-#define decode_get_type(_entry)         ((_entry).header.type)
-
-#define decode_table_end(_entry)               \
-       ((_entry).header.type == DECODE_TYPE_END)
-
-#define decode_table_hit(_entry, insn)         \
-       ((insn & (_entry).header.mask) == (_entry).header.val)
-
-#define decode_prepare_fn(_entry)      ((_entry).decode.actions.prepare)
-#define decode_handler_fn(_entry)      ((_entry).decode.actions.handler)
-#define decode_sub_table(_entry)       ((_entry).decode.table.tbl)
-
-#define DECODE_ADD_HEADER(_type, _val, _mask)  \
-       .header = {                             \
-               .type = _type,                  \
-               .mask = _mask,                  \
-               .val = _val,                    \
-       }
-
-#define DECODE_ADD_ACTION(_prepare, _handler)  \
-       .decode = {                             \
-               .actions = {                    \
-                       .prepare = _prepare,    \
-                       .handler = _handler,    \
-               }                               \
-       }
-
-#define DECODE_ADD_TABLE(_table)               \
-       .decode = {                             \
-               .table = {.tbl = _table}        \
-       }
-
-#define DECODE_REJECT(_v, _m)                                  \
-       { DECODE_ADD_HEADER(DECODE_TYPE_REJECT, _v, _m) }
-
-#define DECODE_SINGLESTEP(_v, _m)                              \
-       { DECODE_ADD_HEADER(DECODE_TYPE_SINGLESTEP, _v, _m) }
-
-#define DECODE_SIMULATE(_v, _m, _p, _h)                                \
-       { DECODE_ADD_HEADER(DECODE_TYPE_SIMULATE, _v, _m),      \
-         DECODE_ADD_ACTION(_p, _h) }
-
-#define DECODE_TABLE(_v, _m, _table)                           \
-       { DECODE_ADD_HEADER(DECODE_TYPE_TABLE, _v, _m),         \
-         DECODE_ADD_TABLE(_table) }
-
-#define DECODE_LITERAL(_v, _m, _p, _h) DECODE_SIMULATE(_v, _m, _p, _h)
-#define DECODE_BRANCH(_v, _m, _p, _h)  DECODE_SIMULATE(_v, _m, _p, _h)
-
-/* should be the last element in decode structure */
-#define DECODE_END     { .header = {.type = DECODE_TYPE_END, } }
-
-#endif /* _ARM64_KERNEL_UPROBES_DECODE_H */
diff --git a/uprobe/arch/x86/swap-asm/swap_sc_patch.c b/uprobe/arch/x86/swap-asm/swap_sc_patch.c
deleted file mode 100644 (file)
index 7ffc3fa..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * swap_sc_patch.c
- * @author Dmitry Kovalenko <d.kovalenko@samsung.com>
- * @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, 2015
- *
- * @section DESCRIPTION
- *
- * Patching of sys_call_table
- */
-
-#include <ksyms/ksyms.h>
-#include "swap_sc_patch.h"
-
-static unsigned long original_syscall;
-static int patched_syscall = -1;
-
-/* disable write protection */
-#define swap_disable_wprot()           \
-       asm("pushl %eax \n"             \
-           "movl %cr0, %eax \n"        \
-           "andl $0xfffeffff, %eax \n" \
-           "movl %eax, %cr0 \n"        \
-           "popl %eax");
-
-/* enable write protection */
-#define swap_enable_wprot()           \
-       asm("push %eax \n"             \
-           "movl %cr0, %eax \n"       \
-           "orl $0x00010000, %eax \n" \
-           "movl %eax, %cr0 \n"       \
-           "popl %eax");
-
-void patch_syscall(int syscall_n, unsigned long new_syscall_addr)
-{
-       unsigned long tmp;
-       unsigned long *sc_table;
-
-       /*
-        * Search for sys_call_table (4 bytes before sysenter_after_call)
-        * sysenter_do_call function which locates before sysenter_after_call
-        * has sys_call_table address in call instruction (latest instruction)
-        */
-       tmp = swap_ksyms("sysenter_after_call");
-       sc_table = *(unsigned long **)(tmp - 4);
-
-       swap_disable_wprot();
-       original_syscall = sc_table[syscall_n];
-       sc_table[syscall_n] = new_syscall_addr;
-       patched_syscall = syscall_n;
-       swap_enable_wprot();
-}
-
-void swap_depatch_syscall(void)
-{
-       if (patched_syscall == -1) {
-               printk(KERN_WARNING
-                      "SWAP SC_PATCH: there is no patched syscalls");
-               return;
-       }
-
-       patch_syscall(patched_syscall, original_syscall);
-       patched_syscall = -1;
-}
-
-asmlinkage long sys_swap_func(void)
-{
-       /* Your code here */
-
-       return -ENOSYS;
-}
-
-#define NI_SYSCALL4SWAP 31
-void swap_patch_syscall(void)
-{
-       patch_syscall(NI_SYSCALL4SWAP, (unsigned long)&sys_swap_func);
-}
diff --git a/uprobe/arch/x86/swap-asm/swap_sc_patch.h b/uprobe/arch/x86/swap-asm/swap_sc_patch.h
deleted file mode 100644 (file)
index 9b42fac..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-void swap_depatch_syscall(void);
-void swap_patch_syscall(void);
diff --git a/uprobe/arch/x86/swap-asm/swap_uprobes.c b/uprobe/arch/x86/swap-asm/swap_uprobes.c
deleted file mode 100644 (file)
index a2d5794..0000000
+++ /dev/null
@@ -1,793 +0,0 @@
-/**
- * uprobe/arch/asm-x86/swap_uprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface implementation for x86.
- */
-
-
-#include <linux/kdebug.h>
-
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_td_raw.h>
-#include <kprobe/swap_kprobes.h>
-#include <uprobe/swap_uprobes.h>
-
-#include "swap_uprobes.h"
-
-
-struct save_context {
-       struct pt_regs save_regs;
-       struct pt_regs *ptr_regs;
-       unsigned long val;
-       int (*handler)(struct uprobe *, struct pt_regs *);
-};
-
-/**
- * @struct uprobe_ctlblk
- * @brief Uprobe control block
- */
-struct uprobe_ctlblk {
-       unsigned long flags;            /**< Flags */
-       struct uprobe *p;               /**< Pointer to the uprobe */
-
-       struct save_context ctx;
-};
-
-
-static struct td_raw td_raw;
-
-
-static unsigned long trampoline_addr(struct uprobe *up)
-{
-       return (unsigned long)(up->insn + UPROBES_TRAMP_RET_BREAK_IDX);
-}
-
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
-{
-       return trampoline_addr(&ri->rp->up);
-}
-
-static struct uprobe_ctlblk *current_ucb(void)
-{
-       return (struct uprobe_ctlblk *)swap_td_raw(&td_raw, current);
-}
-
-static struct save_context *current_ctx(void)
-{
-       return &current_ucb()->ctx;
-}
-
-static struct uprobe *get_current_probe(void)
-{
-       return current_ucb()->p;
-}
-
-static void set_current_probe(struct uprobe *p)
-{
-       current_ucb()->p = p;
-}
-
-static void save_current_flags(struct pt_regs *regs)
-{
-       current_ucb()->flags = regs->flags;
-}
-
-static void restore_current_flags(struct pt_regs *regs, unsigned long flags)
-{
-       regs->flags &= ~IF_MASK;
-       regs->flags |= flags & IF_MASK;
-}
-
-/**
- * @brief Prepares uprobe for x86.
- *
- * @param up Pointer to the uprobe.
- * @return 0 on success,\n
- * -1 on error.
- */
-int arch_prepare_uprobe(struct uprobe *p)
-{
-       struct task_struct *task = p->task;
-       u8 tramp[UPROBES_TRAMP_LEN + BP_INSN_SIZE];     /* BP for uretprobe */
-
-       if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
-                                tramp, MAX_INSN_SIZE)) {
-               printk(KERN_ERR "failed to read memory %p!\n", p->addr);
-               return -EINVAL;
-       }
-
-       if (p->check_opcode_cb) {
-               int ret;
-               ret = p->check_opcode_cb((uprobe_opcode_t *)tramp);
-               if (ret)
-                       return ret;
-       }
-
-       tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-
-       p->opcode = tramp[0];
-       p->ainsn.boostable = swap_can_boost(tramp) ? 0 : -1;
-
-       p->insn = swap_slot_alloc(p->sm);
-       if (p->insn == NULL) {
-               printk(KERN_ERR "trampoline out of memory\n");
-               return -ENOMEM;
-       }
-
-       if (!write_proc_vm_atomic(task, (unsigned long)p->insn,
-                                 tramp, sizeof(tramp))) {
-               swap_slot_free(p->sm, p->insn);
-               printk(KERN_INFO "failed to write memory %p!\n", tramp);
-               return -EINVAL;
-       }
-
-       /* for uretprobe */
-       add_uprobe_table(p);
-
-       return 0;
-}
-
-/**
- * @brief Jump pre-handler.
- *
- * @param p Pointer to the uprobe.
- * @param regs Pointer to CPU register data.
- * @return 0.
- */
-int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct ujprobe *jp = container_of(p, struct ujprobe, up);
-       entry_point_t entry = (entry_point_t)jp->entry;
-       unsigned long args[6];
-
-       /* FIXME some user space apps crash if we clean interrupt bit */
-       /* regs->EREG(flags) &= ~IF_MASK; */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
-       trace_hardirqs_off();
-#endif
-
-       /* read first 6 args from stack */
-       if (!read_proc_vm_atomic(current, regs->EREG(sp) + 4,
-                                args, sizeof(args)))
-               printk(KERN_WARNING
-                      "failed to read user space func arguments %lx!\n",
-                      regs->sp + 4);
-
-       if (entry)
-               entry(args[0], args[1], args[2], args[3], args[4], args[5]);
-       else
-               arch_ujprobe_return();
-
-       return 0;
-}
-
-/**
- * @brief Check opcode is applicable for retprobe
- *
- * @param opcode Pointer to opcode
- * @return result of checking
- */
-int arch_urp_check_opcode(uprobe_opcode_t *opcode)
-{
-       enum { call_relative_opcode = 0xe8 };
-
-       /* do not set uprobe for retprobe if insn is relative call */
-       if (opcode[0] == call_relative_opcode) {
-               pr_err("failed to set retprobe to relative call\n");
-               return -ENOEXEC;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Prepares uretprobe for x86.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       /* Replace the return addr with trampoline addr */
-       unsigned long ra = trampoline_addr(&ri->rp->up);
-       unsigned long ret_addr;
-       ri->sp = (kprobe_opcode_t *)regs->sp;
-
-       if (get_user(ret_addr, (unsigned long *)regs->sp)) {
-               pr_err("failed to read user space func ra %lx addr=%p!\n",
-                      regs->sp, ri->rp->up.addr);
-               return -EINVAL;
-       }
-
-       if (put_user(ra, (unsigned long *)regs->sp)) {
-               pr_err("failed to write user space func ra %lx!\n", regs->sp);
-               return -EINVAL;
-       }
-
-       ri->ret_addr = (uprobe_opcode_t *)ret_addr;
-
-       return 0;
-}
-
-static bool get_long(struct task_struct *task,
-                    unsigned long vaddr, unsigned long *val)
-{
-       return sizeof(*val) != read_proc_vm_atomic(task, vaddr,
-                                                  val, sizeof(*val));
-}
-
-static bool put_long(struct task_struct *task,
-                    unsigned long vaddr, unsigned long *val)
-{
-       return sizeof(*val) != write_proc_vm_atomic(task, vaddr,
-                                                   val, sizeof(*val));
-}
-
-/**
- * @brief Disarms uretprobe on x86 arch.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param task Pointer to the task for which the probe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task)
-{
-       unsigned long ret_addr;
-       unsigned long sp = (unsigned long)ri->sp;
-       unsigned long tramp_addr = trampoline_addr(&ri->rp->up);
-
-       if (get_long(task, sp, &ret_addr)) {
-               printk(KERN_INFO "---> %s (%d/%d): failed to read stack from %08lx\n",
-                      task->comm, task->tgid, task->pid, sp);
-               return -EFAULT;
-       }
-
-       if (tramp_addr == ret_addr) {
-               if (put_long(task, sp, (unsigned long *)&ri->ret_addr)) {
-                       printk(KERN_INFO "---> %s (%d/%d): failed to write "
-                              "orig_ret_addr to %08lx",
-                              task->comm, task->tgid, task->pid, sp);
-                       return -EFAULT;
-               }
-       } else {
-               printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at sp = %08lx\n",
-                      task->comm, task->tgid, task->pid, sp);
-               return -ENOENT;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Gets trampoline address.
- *
- * @param p Pointer to the uprobe.
- * @param regs Pointer to CPU register data.
- * @return Trampoline address.
- */
-unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
-{
-       return trampoline_addr(p);
-}
-
-/**
- * @brief Restores return address.
- *
- * @param orig_ret_addr Original return address.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
-{
-       regs->EREG(ip) = orig_ret_addr;
-}
-
-/**
- * @brief Removes uprobe.
- *
- * @param up Pointer to the target uprobe.
- * @return Void.
- */
-void arch_remove_uprobe(struct uprobe *p)
-{
-       swap_slot_free(p->sm, p->insn);
-}
-
-int arch_arm_uprobe(struct uprobe *p)
-{
-       int ret;
-       uprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
-       unsigned long vaddr = (unsigned long)p->addr;
-
-       ret = write_proc_vm_atomic(p->task, vaddr, &insn, sizeof(insn));
-       if (!ret) {
-               pr_err("arch_arm_uprobe: failed to write memory tgid=%u vaddr=%08lx\n",
-                      p->task->tgid, vaddr);
-
-               return -EACCES;
-       }
-
-       return 0;
-}
-
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
-{
-       int ret;
-       unsigned long vaddr = (unsigned long)p->addr;
-
-       ret = write_proc_vm_atomic(task, vaddr, &p->opcode, sizeof(p->opcode));
-       if (!ret) {
-               pr_err("arch_disarm_uprobe: failed to write memory tgid=%u, vaddr=%08lx\n",
-                      task->tgid, vaddr);
-       }
-}
-
-static void set_user_jmp_op(void *from, void *to)
-{
-       struct __arch_jmp_op {
-               char op;
-               long raddr;
-       } __packed jop;
-
-       jop.raddr = (long)(to) - ((long)(from) + 5);
-       jop.op = RELATIVEJUMP_INSTRUCTION;
-
-       if (put_user(jop.op, (char *)from) ||
-           put_user(jop.raddr, (long *)(from + 1)))
-               pr_err("failed to write jump opcode to user space %p\n", from);
-}
-
-static void resume_execution(struct uprobe *p,
-                            struct pt_regs *regs,
-                            unsigned long flags)
-{
-       unsigned long *tos, tos_dword = 0;
-       unsigned long copy_eip = (unsigned long)p->insn;
-       unsigned long orig_eip = (unsigned long)p->addr;
-       uprobe_opcode_t insns[2];
-
-       regs->EREG(flags) &= ~TF_MASK;
-
-       tos = (unsigned long *)&tos_dword;
-       if (get_user(tos_dword, (unsigned long *)regs->sp)) {
-               pr_err("failed to read from user space sp=%lx!\n", regs->sp);
-               return;
-       }
-
-       if (get_user(*(unsigned short *)insns, (unsigned short *)p->insn)) {
-               pr_err("failed to read first 2 opcodes %p!\n", p->insn);
-               return;
-       }
-
-       switch (insns[0]) {
-       case 0x9c: /* pushfl */
-               *tos &= ~(TF_MASK | IF_MASK);
-               *tos |= flags & (TF_MASK | IF_MASK);
-               break;
-       case 0xc2: /* iret/ret/lret */
-       case 0xc3:
-       case 0xca:
-       case 0xcb:
-       case 0xcf:
-       case 0xea: /* jmp absolute -- eip is correct */
-               /* eip is already adjusted, no more changes required */
-               p->ainsn.boostable = 1;
-               goto no_change;
-       case 0xe8: /* call relative - Fix return addr */
-               *tos = orig_eip + (*tos - copy_eip);
-               break;
-       case 0x9a: /* call absolute -- same as call absolute, indirect */
-               *tos = orig_eip + (*tos - copy_eip);
-
-               if (put_user(tos_dword, (unsigned long *)regs->sp)) {
-                       pr_err("failed to write dword to sp=%lx\n", regs->sp);
-                       return;
-               }
-
-               goto no_change;
-       case 0xff:
-               if ((insns[1] & 0x30) == 0x10) {
-                       /*
-                        * call absolute, indirect
-                        * Fix return addr; eip is correct.
-                        * But this is not boostable
-                        */
-                       *tos = orig_eip + (*tos - copy_eip);
-
-                       if (put_user(tos_dword, (unsigned long *)regs->sp)) {
-                               pr_err("failed to write dword to sp=%lx\n", regs->sp);
-                               return;
-                       }
-
-                       goto no_change;
-               } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
-                                                          * indirect */
-                          ((insns[1] & 0x31) == 0x21)) {
-                       /* jmp far, absolute indirect */
-                       /* eip is correct. And this is boostable */
-                       p->ainsn.boostable = 1;
-                       goto no_change;
-               }
-       case 0xf3:
-               if (insns[1] == 0xc3)
-                       /* repz ret special handling: no more changes */
-                       goto no_change;
-               break;
-       default:
-               break;
-       }
-
-       if (put_user(tos_dword, (unsigned long *)regs->sp)) {
-               pr_err("failed to write dword to sp=%lx\n", regs->sp);
-               return;
-       }
-
-       if (p->ainsn.boostable == 0) {
-               if ((regs->EREG(ip) > copy_eip) && (regs->EREG(ip) - copy_eip) +
-                   5 < MAX_INSN_SIZE) {
-                       /*
-                        * These instructions can be executed directly if it
-                        * jumps back to correct address.
-                        */
-                       set_user_jmp_op((void *) regs->EREG(ip),
-                                       (void *)orig_eip +
-                                       (regs->EREG(ip) - copy_eip));
-                       p->ainsn.boostable = 1;
-               } else {
-                       p->ainsn.boostable = -1;
-               }
-       }
-
-       regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
-
-no_change:
-       return;
-}
-
-static void prepare_tramp(struct uprobe *p, struct pt_regs *regs)
-{
-       regs->ip = (unsigned long)p->insn;
-}
-
-static void prepare_ss(struct pt_regs *regs)
-{
-       /* set single step mode */
-       regs->flags |= TF_MASK;
-       regs->flags &= ~IF_MASK;
-}
-
-
-static unsigned long resume_userspace_addr;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
-static void __rcu_nmi_enter(void) {}
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
-#error "This kernel is not support"
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */
-static void (*__rcu_nmi_enter)(void);
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */
-
-static void __used __up_handler(void)
-{
-       struct pt_regs *regs = current_ctx()->ptr_regs;
-       struct thread_info *tinfo = current_thread_info();
-       struct uprobe *p = current_ucb()->p;
-
-       /* restore KS regs */
-       *regs = current_ctx()->save_regs;
-
-       /* call handler */
-       current_ctx()->handler(p, regs);
-
-       /* resume_userspace */
-       asm volatile (
-               "movl %0, %%esp\n"
-               "movl %1, %%ebp\n"
-               "jmpl *%2\n"
-               : /* No outputs. */
-               : "r" (regs), "r" (tinfo) , "r" (resume_userspace_addr)
-       );
-}
-
-void up_handler(void);
-__asm(
-       "up_handler:\n"
-       /* skip hex tractor-driver bytes to make some free space (skip regs) */
-       "sub $0x300, %esp\n"
-       "jmp __up_handler\n"
-);
-
-static int exceptions_handler(struct pt_regs *regs,
-                             int (*handler)(struct uprobe *, struct pt_regs *))
-{
-       /* save regs */
-       current_ctx()->save_regs = *regs;
-       current_ctx()->ptr_regs = regs;
-
-       /* set handler */
-       current_ctx()->handler = handler;
-
-       /* setup regs to return to KS */
-       regs->ip = (unsigned long)up_handler;
-       regs->ds = __USER_DS;
-       regs->es = __USER_DS;
-       regs->fs = __KERNEL_PERCPU;
-       regs->cs = __KERNEL_CS | get_kernel_rpl();
-       regs->gs = 0;
-       regs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
-
-       /*
-        * Here rcu_nmi_enter() call is needed, because we change
-        * US context to KS context as a result rcu_nmi_exit() will
-        * be called on exiting exception and rcu_nmi_enter() and
-        * rcu_nmi_exit() calls must be consistent
-        */
-       __rcu_nmi_enter();
-
-       return 1;
-}
-
-static int uprobe_handler_retprobe(struct uprobe *p, struct pt_regs *regs)
-{
-       int ret;
-
-       ret = trampoline_uprobe_handler(p, regs);
-       set_current_probe(NULL);
-       put_up(p);
-
-       return ret;
-}
-
-static int uprobe_handler_part2(struct uprobe *p, struct pt_regs *regs)
-{
-       if (p->pre_handler && !p->pre_handler(p, regs)) {
-               prepare_tramp(p, regs);
-               if (p->ainsn.boostable == 1 && !p->post_handler)
-                       goto exit_and_put_up;
-
-               save_current_flags(regs);
-               set_current_probe(p);
-               prepare_ss(regs);
-
-               return 1;
-       }
-
-exit_and_put_up:
-       set_current_probe(NULL);
-       put_up(p);
-       return 1;
-}
-
-static int uprobe_handler_atomic(struct pt_regs *regs)
-{
-       pid_t tgid = current->tgid;
-       unsigned long vaddr = regs->ip - 1;
-       struct uprobe *p = get_uprobe((void *)vaddr, tgid);
-
-       if (p) {
-               get_up(p);
-               if (p->pre_handler) {
-                       set_current_probe(p);
-                       exceptions_handler(regs, uprobe_handler_part2);
-               } else {
-                       uprobe_handler_part2(p, regs);
-               }
-       } else {
-               unsigned long tramp_vaddr;
-
-               tramp_vaddr = vaddr - UPROBES_TRAMP_RET_BREAK_IDX;
-               p = get_uprobe_by_insn_slot((void *)tramp_vaddr, tgid, regs);
-               if (p == NULL) {
-                       pr_info("no_uprobe\n");
-                       return 0;
-               }
-
-               set_current_probe(p);
-               get_up(p);
-               exceptions_handler(regs, uprobe_handler_retprobe);
-       }
-
-       return 1;
-}
-
-static int post_uprobe_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       unsigned long flags = current_ucb()->flags;
-
-       resume_execution(p, regs, flags);
-       restore_current_flags(regs, flags);
-
-       /* reset current probe */
-       set_current_probe(NULL);
-       put_up(p);
-
-       return 1;
-}
-
-static int post_uprobe_handler_atomic(struct pt_regs *regs)
-{
-       struct uprobe *p = get_current_probe();
-
-       if (p) {
-               exceptions_handler(regs, post_uprobe_handler);
-       } else {
-               pr_info("task[%u %u %s] current uprobe is not found\n",
-                       current->tgid, current->pid, current->comm);
-       }
-
-       return !!p;
-}
-
-static int uprobe_exceptions_notify(struct notifier_block *self,
-                                   unsigned long val, void *data)
-{
-       struct die_args *args = (struct die_args *)data;
-       int ret = NOTIFY_DONE;
-
-       if (args->regs == NULL || !swap_user_mode(args->regs))
-               return ret;
-
-       switch (val) {
-#ifdef CONFIG_KPROBES
-       case DIE_INT3:
-#else
-       case DIE_TRAP:
-#endif
-               if (uprobe_handler_atomic(args->regs))
-                       ret = NOTIFY_STOP;
-               break;
-       case DIE_DEBUG:
-               if (post_uprobe_handler_atomic(args->regs))
-                       ret = NOTIFY_STOP;
-               break;
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-static struct notifier_block uprobe_exceptions_nb = {
-       .notifier_call = uprobe_exceptions_notify,
-       .priority = INT_MAX
-};
-
-struct up_valid_struct {
-       struct uprobe *p;
-       bool found;
-};
-
-static int __uprobe_is_valid(struct uprobe *p, void *data)
-{
-       struct up_valid_struct *valid = (struct up_valid_struct *)data;
-
-       if (valid->p == p) {
-               valid->found = true;
-               return 1;
-       }
-
-       return 0;
-}
-
-static bool uprobe_is_valid(struct uprobe *p)
-{
-       struct up_valid_struct valid = {
-               .p = p,
-               .found = false,
-       };
-
-       for_each_uprobe(__uprobe_is_valid, (void *)&valid);
-
-       return valid.found;
-}
-
-static int do_exit_handler(struct kprobe *kp, struct pt_regs *regs)
-{
-       struct uprobe *p;
-
-       p = get_current_probe();
-       if (p && uprobe_is_valid(p)) {
-               set_current_probe(NULL);
-               put_up(p);
-       }
-
-       return 0;
-}
-
-static struct kprobe kp_do_exit = {
-       .pre_handler = do_exit_handler
-};
-
-/**
- * @brief Registers notify.
- *
- * @return register_die_notifier result.
- */
-int swap_arch_init_uprobes(void)
-{
-       int ret;
-       const char *sym;
-
-       sym = "resume_userspace";
-       resume_userspace_addr = swap_ksyms(sym);
-       if (resume_userspace_addr == 0)
-               goto not_found;
-
-       sym = "do_exit";
-       kp_do_exit.addr = swap_ksyms(sym);
-       if (kp_do_exit.addr == 0)
-               goto not_found;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
-       sym = "rcu_nmi_enter";
-       __rcu_nmi_enter = (void *)swap_ksyms(sym);
-       if (__rcu_nmi_enter == NULL)
-               goto not_found;
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
-
-       ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk));
-       if (ret)
-               return ret;
-
-       ret = register_die_notifier(&uprobe_exceptions_nb);
-       if (ret)
-               goto unreg_td;
-
-       ret = swap_register_kprobe(&kp_do_exit);
-       if (ret)
-               goto unreg_exeption;
-
-       return 0;
-
-unreg_exeption:
-       unregister_die_notifier(&uprobe_exceptions_nb);
-unreg_td:
-       swap_td_raw_unreg(&td_raw);
-       return ret;
-
-not_found:
-       pr_err("symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-/**
- * @brief Unregisters notify.
- *
- * @return Void.
- */
-void swap_arch_exit_uprobes(void)
-{
-       swap_unregister_kprobe(&kp_do_exit);
-       unregister_die_notifier(&uprobe_exceptions_nb);
-       swap_td_raw_unreg(&td_raw);
-}
-
diff --git a/uprobe/arch/x86/swap-asm/swap_uprobes.h b/uprobe/arch/x86/swap-asm/swap_uprobes.h
deleted file mode 100644 (file)
index 7a153de..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * @file uprobe/arch/asm-x86/swap_uprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface declaration.
- */
-
-#ifndef _X86_SWAP_UPROBES_H
-#define _X86_SWAP_UPROBES_H
-
-
-#include <swap-asm/swap_kprobes.h>      /* FIXME: for UPROBES_TRAMP_LEN */
-
-
-struct uprobe;
-struct uretprobe;
-struct uretprobe_instance;
-
-typedef u8 uprobe_opcode_t;
-
-/**
- * @struct arch_insn
- * @brief Architecture depend copy of original instruction.
- * @var arch_insn::insn
- * Copy of the original instruction.
- * @var arch_insn::boostable
- * If this flag is not 0, this kprobe can be boost when its
- * post_handler and break_handler is not set.
- */
-struct arch_insn {
-       int boostable;
-};
-
-
-static inline u32 swap_get_urp_float(struct pt_regs *regs)
-{
-       u32 st0;
-
-       asm volatile ("fstps    %0" : "=m" (st0));
-
-       return st0;
-}
-
-static inline u64 swap_get_urp_double(struct pt_regs *regs)
-{
-       u64 st1;
-
-       asm volatile ("fstpl    %0" : "=m" (st1));
-
-       return st1;
-}
-
-static inline void arch_ujprobe_return(void)
-{
-}
-
-int arch_prepare_uprobe(struct uprobe *up);
-int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
-static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
-{
-       return 0;
-}
-
-static inline int arch_opcode_analysis_uretprobe(struct uretprobe *rp)
-{
-       return 0;
-}
-
-int arch_urp_check_opcode(uprobe_opcode_t *opcode);
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task);
-unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
-void arch_remove_uprobe(struct uprobe *up);
-int arch_arm_uprobe(struct uprobe *p);
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
-
-static inline unsigned long swap_get_upc(struct pt_regs *regs)
-{
-       return regs->ip;
-}
-
-static inline void swap_set_upc(struct pt_regs *regs, unsigned long val)
-{
-       regs->ip = val;
-}
-
-static inline unsigned long swap_get_ustack_val(struct pt_regs *regs,
-                                               unsigned long n)
-{
-       u32 *ptr, addr = 0;
-
-       ptr = (u32 *)regs->sp + n;
-       if (get_user(addr, ptr))
-               pr_err("Failed to dereference a pointer, ptr=%p\n", ptr);
-
-       return addr;
-}
-
-static inline void swap_set_ustack_val(struct pt_regs *regs, unsigned long n,
-                                      unsigned long val)
-{
-       u32 *ptr;
-
-       ptr = (u32 *)regs->sp + n;
-       if (put_user(val, ptr))
-               pr_err("Failed to dereference a pointer, ptr=%p\n", ptr);
-}
-
-static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
-{
-       /* 1 - return address saved on top of the stack */
-       return swap_get_ustack_val(regs, n + 1);
-}
-
-static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
-                                unsigned long val)
-{
-       /* 1 - return address saved on top of the stack */
-       swap_set_ustack_val(regs, n + 1, val);
-}
-
-static inline unsigned long swap_get_uret_addr(struct pt_regs *regs)
-{
-       return swap_get_ustack_val(regs, 0);
-}
-
-static inline void swap_set_uret_addr(struct pt_regs *regs, unsigned long val)
-{
-       swap_set_ustack_val(regs, 0, val);
-}
-
-
-int swap_arch_init_uprobes(void);
-void swap_arch_exit_uprobes(void);
-
-#endif /* _X86_SWAP_UPROBES_H */
diff --git a/uprobe/swap_uaccess.h b/uprobe/swap_uaccess.h
deleted file mode 100644 (file)
index 7a9215e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-
-
-static const char *strdup_from_user(const char __user *user_s, gfp_t gfp)
-{
-       enum { max_str_len = 1024 };
-       char *str;
-       int len_s, ret;
-
-       len_s = strnlen_user(user_s, max_str_len - 1);
-       str = kmalloc(len_s + 1, gfp);
-       if (str == NULL)
-               return NULL;
-
-       ret = copy_from_user(str, user_s, len_s);
-       if (ret < 0) {
-               kfree(str);
-               return NULL;
-       }
-
-       str[len_s] = '\0';
-
-       return str;
-}
diff --git a/uprobe/swap_uprobes.c b/uprobe/swap_uprobes.c
deleted file mode 100644 (file)
index d25b2d7..0000000
+++ /dev/null
@@ -1,988 +0,0 @@
-/**
- * uprobe/swap_uprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Uprobes implementation.
- */
-
-
-#include <linux/hash.h>
-#include <linux/sched.h>
-#include <linux/mempolicy.h>
-#include <linux/module.h>
-
-#include <master/swap_initializer.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kdebug.h>
-#include <kprobe/swap_kprobes_deps.h>
-
-#include <swap-asm/swap_uprobes.h>
-
-#include "swap_uprobes.h"
-
-
-enum {
-       UPROBE_HASH_BITS  = 10,
-       UPROBE_TABLE_SIZE = (1 << UPROBE_HASH_BITS)
-};
-
-static DEFINE_RWLOCK(st_lock);
-static struct hlist_head slot_table[UPROBE_TABLE_SIZE];
-static DEFINE_MUTEX(up_mtx);   /* Protects uprobe_table */
-struct hlist_head uprobe_table[UPROBE_TABLE_SIZE];
-
-static DEFINE_MUTEX(urp_mtx);  /* Protects uretprobe_inst_table */
-static struct hlist_head uretprobe_inst_table[UPROBE_TABLE_SIZE];
-
-#define DEBUG_PRINT_HASH_TABLE 0
-
-#if DEBUG_PRINT_HASH_TABLE
-void print_uprobe_hash_table(void)
-{
-       int i;
-       struct hlist_head *head;
-       struct uprobe *p;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       /* print uprobe table */
-       for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
-               head = &uprobe_insn_slot_table[i];
-               swap_hlist_for_each_entry_rcu(p, node, head, is_hlist) {
-                       printk(KERN_INFO "####### find U tgid=%u, addr=0x%lx\n",
-                                       p->task->tgid, (unsigned long)p->addr);
-               }
-       }
-}
-#endif
-
-/*
- * Keep all fields in the uprobe consistent
- */
-static inline void copy_uprobe(struct uprobe *old_p, struct uprobe *p)
-{
-       memcpy(&p->opcode, &old_p->opcode, sizeof(uprobe_opcode_t));
-       memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_insn));
-       memcpy(&p->insn, &old_p->insn, sizeof(uprobe_opcode_t *));
-}
-
-/*
- * Aggregate handlers for multiple uprobes support - these handlers
- * take care of invoking the individual uprobe handlers on p->list
- */
-static int aggr_pre_uhandler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct uprobe *up;
-       int ret;
-
-       list_for_each_entry_rcu(up, &p->list, list) {
-               if (up->pre_handler) {
-                       ret = up->pre_handler(up, regs);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       return 0;
-}
-
-static void aggr_post_uhandler(struct uprobe *p, struct pt_regs *regs,
-                              unsigned long flags)
-{
-       struct uprobe *up;
-
-       list_for_each_entry_rcu(up, &p->list, list) {
-               if (up->post_handler)
-                       up->post_handler(up, regs, flags);
-       }
-}
-
-static int aggr_fault_uhandler(struct uprobe *p,
-                              struct pt_regs *regs,
-                              int trapnr)
-{
-       return 0;
-}
-
-static int aggr_break_uhandler(struct uprobe *p, struct pt_regs *regs)
-{
-       return 0;
-}
-
-/*
- * Add the new probe to old_p->list. Fail if this is the
- * second ujprobe at the address - two ujprobes can't coexist
- */
-static int add_new_uprobe(struct uprobe *old_p, struct uprobe *p)
-{
-       if (p->break_handler) {
-               if (old_p->break_handler)
-                       return -EEXIST;
-
-               list_add_tail_rcu(&p->list, &old_p->list);
-               old_p->break_handler = aggr_break_uhandler;
-       } else {
-               list_add_rcu(&p->list, &old_p->list);
-       }
-
-       if (p->post_handler && !old_p->post_handler)
-               old_p->post_handler = aggr_post_uhandler;
-
-       return 0;
-}
-
-/*
- * Fill in the required fields of the "manager uprobe". Replace the
- * earlier uprobe in the hlist with the manager uprobe
- */
-static inline void add_aggr_uprobe(struct uprobe *ap, struct uprobe *p)
-{
-       copy_uprobe(p, ap);
-
-       ap->addr = p->addr;
-       ap->pre_handler = aggr_pre_uhandler;
-       ap->fault_handler = aggr_fault_uhandler;
-
-       if (p->post_handler)
-               ap->post_handler = aggr_post_uhandler;
-
-       if (p->break_handler)
-               ap->break_handler = aggr_break_uhandler;
-
-       INIT_LIST_HEAD(&ap->list);
-       list_add_rcu(&p->list, &ap->list);
-
-       hlist_replace_rcu(&p->hlist, &ap->hlist);
-}
-
-/*
- * This is the second or subsequent uprobe at the address - handle
- * the intricacies
- */
-static int register_aggr_uprobe(struct uprobe *old_p, struct uprobe *p)
-{
-       int ret = 0;
-
-       if (old_p->pre_handler == aggr_pre_uhandler) {
-               copy_uprobe(old_p, p);
-               ret = add_new_uprobe(old_p, p);
-       } else {
-               struct uprobe *uap = kzalloc(sizeof(*uap), GFP_KERNEL);
-               if (!uap)
-                       return -ENOMEM;
-
-               uap->task = p->task;
-               add_aggr_uprobe(uap, old_p);
-               copy_uprobe(uap, p);
-               ret = add_new_uprobe(uap, p);
-       }
-
-       return ret;
-}
-
-static int arm_uprobe(struct uprobe *p)
-{
-       return arch_arm_uprobe(p);
-}
-
-/**
- * @brief Disarms uprobe.
- *
- * @param p Pointer to the uprobe.
- * @param task Pointer to the target task.
- * @return Void.
- */
-void disarm_uprobe(struct uprobe *p, struct task_struct *task)
-{
-       arch_disarm_uprobe(p, task);
-}
-EXPORT_SYMBOL_GPL(disarm_uprobe);
-
-static void init_uprobes_insn_slots(void)
-{
-       int i;
-       for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
-               INIT_HLIST_HEAD(&slot_table[i]);
-}
-
-static void init_uprobe_table(void)
-{
-       int i;
-       for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
-               INIT_HLIST_HEAD(&uprobe_table[i]);
-}
-
-static void init_uretprobe_inst_table(void)
-{
-       int i;
-       for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
-               INIT_HLIST_HEAD(&uretprobe_inst_table[i]);
-}
-
-/**
- * @brief Gets uprobe.
- *
- * @param addr Probe's address.
- * @param tgid Probes's thread group ID.
- * @return Pointer to the uprobe on success,\n
- * NULL otherwise.
- */
-struct uprobe *get_uprobe(void *addr, pid_t tgid)
-{
-       struct hlist_head *head;
-       struct uprobe *p;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       head = &uprobe_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
-               if (p->addr == addr && p->task->tgid == tgid)
-                       return p;
-       }
-
-       return NULL;
-}
-
-/**
- * @brief Adds uprobe to hlist when trampoline have been made.
- *
- * @param p Pointer to the uprobe.
- * @return Void.
- */
-void add_uprobe_table(struct uprobe *p)
-{
-       write_lock(&st_lock);
-       hlist_add_head(&p->is_hlist,
-                      &slot_table[hash_ptr(p->insn, UPROBE_HASH_BITS)]);
-       write_unlock(&st_lock);
-}
-
-static void del_uprobe_table(struct uprobe *p)
-{
-       write_lock(&st_lock);
-       if (!hlist_unhashed(&p->is_hlist))
-               hlist_del(&p->is_hlist);
-       write_unlock(&st_lock);
-}
-
-/**
- * @brief Gets uprobe by insn slot.
- *
- * @param addr Probe's address.
- * @param tgit Probe's thread group ID.
- * @param regs Pointer to CPU registers data.
- * @return Pointer to the uprobe on success,\n
- * NULL otherwise.
- */
-struct uprobe *get_uprobe_by_insn_slot(void *addr,
-                                      pid_t tgid,
-                                      struct pt_regs *regs)
-{
-       struct hlist_head *head;
-       struct uprobe *p;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       read_lock(&st_lock);
-       head = &slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       swap_hlist_for_each_entry(p, node, head, is_hlist) {
-               if (p->insn == addr && p->task->tgid == tgid) {
-                       read_unlock(&st_lock);
-                       return p;
-               }
-       }
-       read_unlock(&st_lock);
-
-       return NULL;
-}
-
-
-static void remove_uprobe(struct uprobe *up)
-{
-       del_uprobe_table(up);
-       arch_remove_uprobe(up);
-}
-
-static struct hlist_head *uretprobe_inst_table_head(void *hash_key)
-{
-       return &uretprobe_inst_table[hash_ptr(hash_key, UPROBE_HASH_BITS)];
-}
-
-/* Called with urp_mtx held */
-static void add_urp_inst(struct uretprobe_instance *ri)
-{
-       /*
-        * Remove rp inst off the free list -
-        * Add it back when probed function returns
-        */
-       hlist_del(&ri->uflist);
-
-       /* Add rp inst onto table */
-       INIT_HLIST_NODE(&ri->hlist);
-       hlist_add_head(&ri->hlist, uretprobe_inst_table_head(ri->task->mm));
-
-       /* Also add this rp inst to the used list. */
-       INIT_HLIST_NODE(&ri->uflist);
-       hlist_add_head(&ri->uflist, &ri->rp->used_instances);
-}
-
-/* Called with urp_mtx held */
-static void recycle_urp_inst(struct uretprobe_instance *ri)
-{
-       if (ri->rp) {
-               hlist_del(&ri->hlist);
-               /* remove rp inst off the used list */
-               hlist_del(&ri->uflist);
-               /* put rp inst back onto the free list */
-               INIT_HLIST_NODE(&ri->uflist);
-               hlist_add_head(&ri->uflist, &ri->rp->free_instances);
-       }
-}
-
-/* Called with urp_mtx held */
-static struct uretprobe_instance *get_used_urp_inst(struct uretprobe *rp)
-{
-       struct uretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
-               return ri;
-       }
-
-       return NULL;
-}
-
-/**
- * @brief Gets free uretprobe instanse for the specified uretprobe without
- * allocation. Called with urp_mtx held.
- *
- * @param rp Pointer to the uretprobe.
- * @return Pointer to the uretprobe_instance on success,\n
- * NULL otherwise.
- */
-struct uretprobe_instance *get_free_urp_inst_no_alloc(struct uretprobe *rp)
-{
-       struct uretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
-               return ri;
-       }
-
-       return NULL;
-}
-
-/* Called with urp_mtx held */
-static void free_urp_inst(struct uretprobe *rp)
-{
-       struct uretprobe_instance *ri;
-       while ((ri = get_free_urp_inst_no_alloc(rp)) != NULL) {
-               hlist_del(&ri->uflist);
-               kfree(ri);
-       }
-}
-
-#define COMMON_URP_NR 10
-
-static int alloc_nodes_uretprobe(struct uretprobe *rp)
-{
-       int alloc_nodes;
-       struct uretprobe_instance *inst;
-       int i;
-
-#if 1 /* def CONFIG_PREEMPT */
-       rp->maxactive += max(COMMON_URP_NR, 2 * NR_CPUS);
-#else
-       rp->maxacpptive += NR_CPUS;
-#endif
-       alloc_nodes = COMMON_URP_NR;
-
-       for (i = 0; i < alloc_nodes; ++i) {
-               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_ATOMIC);
-               if (inst == NULL) {
-                       free_urp_inst(rp);
-                       return -ENOMEM;
-               }
-               INIT_HLIST_NODE(&inst->uflist);
-               hlist_add_head(&inst->uflist, &rp->free_instances);
-       }
-
-       return 0;
-}
-
-/* Called with urp_mtx held */
-static struct uretprobe_instance *get_free_urp_inst(struct uretprobe *rp)
-{
-       struct uretprobe_instance *ri;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
-               return ri;
-       }
-
-       if (!alloc_nodes_uretprobe(rp)) {
-               swap_hlist_for_each_entry(ri, node,
-                                         &rp->free_instances, uflist) {
-                       return ri;
-               }
-       }
-
-       return NULL;
-}
-/* =================================================================== */
-
-
-void for_each_uprobe(int (*func)(struct uprobe *, void *), void *data)
-{
-       int i;
-       struct uprobe *p;
-       struct hlist_head *head;
-       struct hlist_node *tnode;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
-               head = &uprobe_table[i];
-               swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
-                       if (func(p, data))
-                               return;
-               }
-       }
-}
-
-static int wait_up_action(atomic_t *val)
-{
-       BUG_ON(atomic_read(val));
-       schedule();
-       return 0;
-}
-
-static void wait_up(struct uprobe *p)
-{
-       wait_on_atomic_t(&p->usage, wait_up_action, TASK_UNINTERRUPTIBLE);
-}
-
-/**
- * @brief Registers uprobe.
- *
- * @param up Pointer to the uprobe to register.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int swap_register_uprobe(struct uprobe *p)
-{
-       int ret = 0;
-       struct uprobe *old_p;
-
-       if (!p->addr)
-               return -EINVAL;
-
-       p->insn = NULL;
-       INIT_LIST_HEAD(&p->list);
-       atomic_set(&p->usage, 1);
-
-       /* get the first item */
-       old_p = get_uprobe(p->addr, p->task->tgid);
-       if (old_p) {
-               ret = register_aggr_uprobe(old_p, p);
-               goto out;
-       }
-
-       INIT_HLIST_NODE(&p->is_hlist);
-
-       ret = arch_prepare_uprobe(p);
-       if (ret) {
-               DBPRINTF("goto out\n", ret);
-               goto out;
-       }
-
-       DBPRINTF("before out ret = 0x%x\n", ret);
-
-       /* TODO: add uprobe (must be in function) */
-       INIT_HLIST_NODE(&p->hlist);
-       hlist_add_head_rcu(&p->hlist,
-                          &uprobe_table[hash_ptr(p->addr, UPROBE_HASH_BITS)]);
-
-       ret = arm_uprobe(p);
-       if (ret) {
-               hlist_del_rcu(&p->hlist);
-               synchronize_rcu();
-               remove_uprobe(p);
-       }
-
-out:
-       DBPRINTF("out ret = 0x%x\n", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_uprobe);
-
-/**
- * @brief Unregisters uprobe.
- *
- * @param up Pointer to the uprobe.
- * @param disarm Disarm flag. When true uprobe is disarmed.
- * @return Void.
- */
-void __swap_unregister_uprobe(struct uprobe *p, int disarm)
-{
-       struct uprobe *old_p, *list_p;
-       int cleanup_p;
-
-       /* we MUST check probe for uncreated process  */
-       if (!p->task)
-               return;
-
-       mutex_lock(&up_mtx);
-       rcu_read_lock();
-       old_p = get_uprobe(p->addr, p->task->tgid);
-       rcu_read_unlock();
-       if (unlikely(!old_p))
-               goto out_unlock;
-
-       if (p != old_p) {
-               rcu_read_lock();
-               list_for_each_entry_rcu(list_p, &old_p->list, list) {
-                       if (list_p == p) {
-                               /* uprobe p is a valid probe */
-                               rcu_read_unlock();
-                               goto valid_p;
-                       }
-               }
-               rcu_read_unlock();
-               goto out_unlock;
-       }
-
-valid_p:
-       if ((old_p == p) || ((old_p->pre_handler == aggr_pre_uhandler) &&
-           (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
-               /* Only probe on the hash list */
-               if (disarm)
-                       disarm_uprobe(p, p->task);
-
-               hlist_del_rcu(&old_p->hlist);
-               cleanup_p = 1;
-       } else {
-               list_del_rcu(&p->list);
-               cleanup_p = 0;
-       }
-
-       if (cleanup_p) {
-               if (p != old_p) {
-                       list_del_rcu(&p->list);
-                       kfree(old_p);
-               }
-
-               if (!in_atomic()) {
-                       synchronize_sched();
-
-                       atomic_dec(&p->usage);
-                       wait_up(p);
-               }
-
-               remove_uprobe(p);
-       } else {
-               if (p->break_handler)
-                       old_p->break_handler = NULL;
-
-               if (p->post_handler) {
-                       rcu_read_lock();
-                       list_for_each_entry_rcu(list_p, &old_p->list, list) {
-                               if (list_p->post_handler) {
-                                       cleanup_p = 2;
-                                       break;
-                               }
-                       }
-                       rcu_read_unlock();
-
-                       if (cleanup_p == 0)
-                               old_p->post_handler = NULL;
-               }
-       }
-
-out_unlock:
-       mutex_unlock(&up_mtx);
-}
-EXPORT_SYMBOL_GPL(__swap_unregister_uprobe);
-
-/**
- * @brief Unregisters uprobe. Main interface function, wrapper for
- * __swap_unregister_uprobe.
- *
- * @param up Pointer to the uprobe.
- * @return Void.
- */
-void swap_unregister_uprobe(struct uprobe *up)
-{
-       __swap_unregister_uprobe(up, 1);
-}
-
-/**
- * @brief Registers ujprobe.
- *
- * @param uj Pointer to the ujprobe function.
- * @return 0 on success,\n
- * error code on error.
- */
-int swap_register_ujprobe(struct ujprobe *jp)
-{
-       int ret = 0;
-
-       /* Todo: Verify probepoint is a function entry point */
-       jp->up.pre_handler = setjmp_upre_handler;
-       jp->up.break_handler = longjmp_break_uhandler;
-
-       ret = swap_register_uprobe(&jp->up);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_ujprobe);
-
-/**
- * @brief Unregisters ujprobe.
- *
- * @param jp Pointer to the ujprobe.
- * @param disarm Disarm flag, passed to __swap_unregister_uprobe.
- * @return Void.
- */
-void __swap_unregister_ujprobe(struct ujprobe *jp, int disarm)
-{
-       __swap_unregister_uprobe(&jp->up, disarm);
-}
-EXPORT_SYMBOL_GPL(__swap_unregister_ujprobe);
-
-/**
- * @brief Unregisters ujprobe. Main interface function, wrapper for
- * __swap_unregister_ujprobe.
- *
- * @param jp Pointer to the jprobe.
- * @return Void.
- */
-void swap_unregister_ujprobe(struct ujprobe *jp)
-{
-       __swap_unregister_ujprobe(jp, 1);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_ujprobe);
-
-/**
- * @brief Trampoline uprobe handler.
- *
- * @param p Pointer to the uprobe.
- * @param regs Pointer to CPU register data.
- * @return 1
- */
-int trampoline_uprobe_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct uretprobe_instance *ri = NULL;
-       struct uprobe *up;
-       struct hlist_head *head = uretprobe_inst_table_head(current->mm);
-       unsigned long tramp_addr = arch_get_trampoline_addr(p, regs);
-       unsigned long orig_ret_addr = 0;
-       struct hlist_node *tmp;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more then one
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       uretprobe_trampoline
-        */
-       mutex_lock(&urp_mtx);
-       swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
-               if (ri->task != current) {
-                       /* another task is sharing our hash bucket */
-                       continue;
-               }
-
-               up = NULL;
-               if (ri->rp) {
-                       up = &ri->rp->up;
-
-                       if (ri->rp->handler)
-                               ri->rp->handler(ri, regs);
-               }
-
-               orig_ret_addr = (unsigned long)ri->ret_addr;
-               recycle_urp_inst(ri);
-
-               if (orig_ret_addr != tramp_addr || up == NULL) {
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-               }
-       }
-       mutex_unlock(&urp_mtx);
-
-       /* orig_ret_addr is NULL when there is no need to restore anything
-        * (all the magic is performed inside handler) */
-       if (likely(orig_ret_addr))
-               arch_set_orig_ret_addr(orig_ret_addr, regs);
-
-       return 1;
-}
-
-static int pre_handler_uretprobe(struct uprobe *p, struct pt_regs *regs)
-{
-       struct uretprobe *rp = container_of(p, struct uretprobe, up);
-       struct uretprobe_instance *ri;
-       int ret = 0;
-
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-# if defined(CONFIG_ARM64)
-#  define thumb_mode(regs)     compat_thumb_mode(regs)
-# endif /* defined(CONFIG_ARM64) */
-       int noret = thumb_mode(regs) ? rp->thumb_noret : rp->arm_noret;
-
-       if (noret)
-               return 0;
-#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-
-       /* TODO: consider to only swap the
-        * RA after the last pre_handler fired */
-
-       /* TODO: test - remove retprobe after func entry but before its exit */
-       mutex_lock(&urp_mtx);
-       ri = get_free_urp_inst(rp);
-       if (ri != NULL) {
-               int err;
-
-               ri->rp = rp;
-               ri->task = current;
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-               ri->preload.use = false;
-#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-               if (rp->entry_handler)
-                       ret = rp->entry_handler(ri, regs);
-
-               add_urp_inst(ri);
-
-               err = arch_prepare_uretprobe(ri, regs);
-               if (err) {
-                       recycle_urp_inst(ri);
-                       ++rp->nmissed;
-               }
-       } else {
-               ++rp->nmissed;
-       }
-       mutex_unlock(&urp_mtx);
-
-       return ret;
-}
-
-/**
- * @brief Registers uretprobe.
- *
- * @param rp Pointer to the uretprobe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int swap_register_uretprobe(struct uretprobe *rp)
-{
-       int i, ret = 0;
-       struct uretprobe_instance *inst;
-
-       DBPRINTF("START\n");
-
-       rp->up.pre_handler = pre_handler_uretprobe;
-       rp->up.post_handler = NULL;
-       rp->up.fault_handler = NULL;
-       rp->up.break_handler = NULL;
-       /* Set callback to check for unsupported insns */
-       rp->up.check_opcode_cb = arch_urp_check_opcode;
-
-       /* Pre-allocate memory for max kretprobe instances */
-       if (rp->maxactive <= 0) {
-#if 1 /* def CONFIG_PREEMPT */
-               rp->maxactive = max(10, 2 * NR_CPUS);
-#else
-               rp->maxactive = NR_CPUS;
-#endif
-       }
-
-       INIT_HLIST_HEAD(&rp->used_instances);
-       INIT_HLIST_HEAD(&rp->free_instances);
-
-       for (i = 0; i < rp->maxactive; i++) {
-               inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_KERNEL);
-               if (inst == NULL) {
-                       ret = -ENOMEM;
-                       goto register_err;
-               }
-
-               INIT_HLIST_NODE(&inst->uflist);
-               hlist_add_head(&inst->uflist, &rp->free_instances);
-       }
-
-       rp->nmissed = 0;
-
-       /* Establish function entry probe point */
-       ret = swap_register_uprobe(&rp->up);
-       if (ret)
-               goto register_err;
-
-       arch_opcode_analysis_uretprobe(rp);
-
-       return 0;
-
-register_err:
-       free_urp_inst(rp);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_uretprobe);
-
-/**
- * @brief Unregisters uretprobe.
- *
- * @param rp Pointer to the ureprobe.
- * @param disarm Disarm flag, passed to __swap_unregister_uprobe
- * @return Void.
- */
-void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm)
-{
-       struct uretprobe_instance *ri;
-
-       __swap_unregister_uprobe(&rp->up, disarm);
-
-       mutex_lock(&urp_mtx);
-       while ((ri = get_used_urp_inst(rp)) != NULL) {
-               /* FIXME: arch_disarm_urp_inst() for no current context */
-               if (arch_disarm_urp_inst(ri, ri->task) != 0)
-                       printk(KERN_INFO "%s (%d/%d): "
-                              "cannot disarm urp instance (%08lx)\n",
-                              ri->task->comm, ri->task->tgid, ri->task->pid,
-                              (unsigned long)rp->up.addr);
-
-               recycle_urp_inst(ri);
-       }
-
-       while ((ri = get_used_urp_inst(rp)) != NULL) {
-               ri->rp = NULL;
-               hlist_del(&ri->uflist);
-       }
-       mutex_unlock(&urp_mtx);
-
-       free_urp_inst(rp);
-}
-EXPORT_SYMBOL_GPL(__swap_unregister_uretprobe);
-
-/**
- * @brief Unregistets uretprobe. Main interface function, wrapper for
- * __swap_unregister_uretprobe.
- *
- * @param rp Pointer to the uretprobe.
- * @return Void.
- */
-void swap_unregister_uretprobe(struct uretprobe *rp)
-{
-       __swap_unregister_uretprobe(rp, 1);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_uretprobe);
-
-/**
- * @brief Unregisters all uprobes for task's thread group ID.
- *
- * @param task Pointer to the task_struct
- * @return Void.
- */
-void swap_unregister_all_uprobes(struct task_struct *task)
-{
-       struct hlist_head *head;
-       struct uprobe *p;
-       int i;
-       struct hlist_node *tnode;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
-               head = &uprobe_table[i];
-               swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
-                       if (p->task->tgid == task->tgid) {
-                               printk(KERN_INFO "%s: delete uprobe at %p[%lx]"
-                                      " for %s/%d\n", __func__, p->addr,
-                                      (unsigned long)p->opcode,
-                                      task->comm, task->pid);
-                               swap_unregister_uprobe(p);
-                       }
-               }
-       }
-}
-EXPORT_SYMBOL_GPL(swap_unregister_all_uprobes);
-
-/**
- * @brief Arch-independent wrapper for arch_ujprobe_return.
- *
- * @return Void.
- */
-void swap_ujprobe_return(void)
-{
-       arch_ujprobe_return();
-}
-EXPORT_SYMBOL_GPL(swap_ujprobe_return);
-
-void swap_uretprobe_free_task(struct task_struct *armed,
-                             struct task_struct *will_disarm, bool recycle)
-{
-       struct uretprobe_instance *ri;
-       struct hlist_head *hhead = uretprobe_inst_table_head(armed->mm);
-       struct hlist_node *n;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       mutex_lock(&urp_mtx);
-       swap_hlist_for_each_entry_safe(ri, node, n, hhead, hlist) {
-               if (armed != ri->task)
-                       continue;
-
-               if (will_disarm)
-                       arch_disarm_urp_inst(ri, will_disarm);
-
-               if (recycle)
-                       recycle_urp_inst(ri);
-       }
-       mutex_unlock(&urp_mtx);
-}
-EXPORT_SYMBOL_GPL(swap_uretprobe_free_task);
-
-
-static int once(void)
-{
-       init_uprobe_table();
-       init_uprobes_insn_slots();
-       init_uretprobe_inst_table();
-
-       return 0;
-}
-
-SWAP_LIGHT_INIT_MODULE(once, swap_arch_init_uprobes, swap_arch_exit_uprobes,
-                      NULL, NULL);
-
-MODULE_LICENSE("GPL");
diff --git a/uprobe/swap_uprobes.h b/uprobe/swap_uprobes.h
deleted file mode 100644 (file)
index e481d79..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
- * @file uprobe/swap_uprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @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, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Uprobes interface declaration.
- */
-
-#ifndef _SWAP_UPROBES_H
-#define _SWAP_UPROBES_H
-
-
-#include <master/wait.h>
-#include <swap-asm/swap_uprobes.h>
-
-
-#define URETPROBE_STACK_DEPTH 64
-
-
-/**
- * @brief Uprobe pre-handler pointer.
- */
-typedef int (*uprobe_pre_handler_t) (struct uprobe *, struct pt_regs *);
-
-/**
- * @brief Uprobe break handler pointer.
- */
-typedef int (*uprobe_break_handler_t) (struct uprobe *, struct pt_regs *);
-
-/**
- * @brief Uprobe post handler pointer.
- */
-typedef void (*uprobe_post_handler_t) (struct uprobe *,
-                                      struct pt_regs *,
-                                      unsigned long flags);
-
-/**
- * @brief Uprobe fault handler pointer.
- */
-typedef int (*uprobe_fault_handler_t) (struct uprobe *,
-                                      struct pt_regs *,
-                                      int trapnr);
-
-/**
- * @struct uprobe
- * @brief Stores uprobe data.
- */
-struct uprobe {
-       struct hlist_node hlist; /**< Hash list.*/
-       /** List of probes to search by instruction slot.*/
-       struct hlist_node is_hlist;
-       /** List of uprobes for multi-handler support.*/
-       struct list_head list;
-       /** Location of the probe point. */
-       uprobe_opcode_t *addr;
-       /** Called before addr is executed.*/
-       uprobe_pre_handler_t pre_handler;
-       /** Called after addr is executed, unless...*/
-       uprobe_post_handler_t post_handler;
-       /** ... called if executing addr causes a fault (eg. page fault).*/
-       uprobe_fault_handler_t fault_handler;
-       /** Return 1 if it handled fault, otherwise kernel will see it.*/
-       uprobe_break_handler_t break_handler;
-       /** Saved opcode (which has been replaced with breakpoint).*/
-       uprobe_opcode_t opcode;
-       atomic_t usage;
-#ifdef CONFIG_ARM
-       /** Safe/unsafe to use probe on ARM.*/
-       unsigned safe_arm:1;
-       /** Safe/unsafe to use probe on Thumb.*/
-       unsigned safe_thumb:1;
-#endif
-       uprobe_opcode_t __user *insn;
-       struct arch_insn ainsn;              /**< Copy of the original instruction.*/
-       struct task_struct *task;            /**< Pointer to the task struct */
-       struct slot_manager *sm;             /**< Pointer to slot manager */
-       int (*check_opcode_cb)(uprobe_opcode_t *opcode); /**< Callback check opcode */
-};
-
-
-void swap_uretprobe_free_task(struct task_struct *task,
-                             struct task_struct *dtask, bool recycle);
-
-
-/**
- * @brief Uprobe pre-entry handler.
- */
-typedef unsigned long (*uprobe_pre_entry_handler_t)(void *priv_arg,
-                                                   struct pt_regs *regs);
-
-/**
- * @struct ujprobe
- * @brief Stores ujprobe data, based on uprobe.
- */
-struct ujprobe {
-       struct uprobe up;       /**< Uprobe for this ujprobe */
-       void *entry;            /**< Probe handling code to jump to */
-       /** Handler which will be called before 'entry' */
-       uprobe_pre_entry_handler_t pre_entry;
-       void *priv_arg;         /**< Private args for handler */
-       char *args;             /**< Function args format string */
-};
-
-struct uretprobe_instance;
-
-/**
- * @brief Uretprobe handler.
- */
-typedef int (*uretprobe_handler_t)(struct uretprobe_instance *,
-                                  struct pt_regs *);
-
-/**
- * @strict uretprobe
- * @brief Function-return probe.
- *
- * Note:
- * User needs to provide a handler function, and initialize maxactive.
- */
-struct uretprobe {
-       struct uprobe up;                   /**< Uprobe for this uretprobe */
-       uretprobe_handler_t handler;        /**< Uretprobe handler */
-       uretprobe_handler_t entry_handler;  /**< Uretprobe entry handler */
-       /** Maximum number of instances of the probed function that can be
-        * active concurrently. */
-       int maxactive;
-       /** Tracks the number of times the probed function's return was
-        * ignored, due to maxactive being too low. */
-       int nmissed;
-       size_t data_size;                   /**< Instance data size */
-       struct hlist_head free_instances;   /**< Free instances list */
-       struct hlist_head used_instances;   /**< Used instances list */
-
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-       unsigned arm_noret:1;               /**< No-return flag for ARM */
-       unsigned thumb_noret:1;             /**< No-return flag for Thumb */
-#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
-};
-
-/**
- * @struct uretprobe_instance
- * @brief Structure for each uretprobe instance.
- */
-struct uretprobe_instance {
-       /* either on free list or used list */
-       struct hlist_node uflist;           /**< Free list */
-       struct hlist_node hlist;            /**< Used list */
-       struct uretprobe *rp;               /**< Pointer to the parent uretprobe */
-       uprobe_opcode_t *ret_addr;          /**< Return address */
-       uprobe_opcode_t *sp;                /**< Pointer to stack */
-       struct task_struct *task;           /**< Pointer to the task struct */
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-       /* FIXME Preload: if this flag is set then ignore the thumb_mode(regs)
-        * check in arch_prepare_uretprobe and use thumb trampoline. For the
-        * moment we have to explicitly force arm mode when jumping to preload
-        * handlers but we need the correct (i.e. original) retprobe tramp set
-        * anyway. */
-       struct {
-               unsigned use:1;
-               unsigned thumb:1;
-       } preload;
-#endif
-       char data[0];                       /**< Custom data */
-};
-
-
-static void inline get_up(struct uprobe *p)
-{
-       atomic_inc(&p->usage);
-}
-
-static void inline put_up(struct uprobe *p)
-{
-       if (atomic_dec_and_test(&p->usage))
-               wake_up_atomic_t(&p->usage);
-}
-
-void for_each_uprobe(int (*func)(struct uprobe *, void *), void *data);
-int swap_register_uprobe(struct uprobe *p);
-void swap_unregister_uprobe(struct uprobe *p);
-void __swap_unregister_uprobe(struct uprobe *up, int disarm);
-
-int swap_register_ujprobe(struct ujprobe *jp);
-void swap_unregister_ujprobe(struct ujprobe *jp);
-void __swap_unregister_ujprobe(struct ujprobe *jp, int disarm);
-
-int swap_register_uretprobe(struct uretprobe *rp);
-void swap_unregister_uretprobe(struct uretprobe *rp);
-void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm);
-
-void swap_unregister_all_uprobes(struct task_struct *task);
-
-void swap_ujprobe_return(void);
-struct uprobe *get_uprobe(void *addr, pid_t tgid);
-struct uprobe *get_uprobe_by_insn_slot(void *addr,
-                                       pid_t tgid,
-                                       struct pt_regs *regs);
-
-void disarm_uprobe(struct uprobe *p, struct task_struct *task);
-
-int trampoline_uprobe_handler(struct uprobe *p, struct pt_regs *regs);
-
-void add_uprobe_table(struct uprobe *p);
-
-#endif /*  _SWAP_UPROBES_H */
diff --git a/us_manager/Kbuild b/us_manager/Kbuild
deleted file mode 100644 (file)
index a3f8629..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../writer/Module.symvers \
-                       $(src)/../kprobe/Module.symvers \
-                       $(src)/../uprobe/Module.symvers
-
-obj-m := swap_us_manager.o
-swap_us_manager-y := \
-    helper.o \
-    us_manager.o \
-    us_slot_manager.o \
-    debugfs_us_manager.o \
-    sspt/sspt_ip.o \
-    sspt/sspt_page.o \
-    sspt/sspt_file.o \
-    sspt/sspt_proc.o \
-    sspt/sspt_feature.o \
-    sspt/sspt_filter.o \
-    pf/pf_group.o \
-    pf/proc_filters.o \
-    img/img_ip.o \
-    img/img_file.o \
-    img/img_proc.o \
-    probes/probes.o \
-    probes/probe_info_new.o \
-    callbacks.o \
-    usm_hook.o
diff --git a/us_manager/callbacks.c b/us_manager/callbacks.c
deleted file mode 100644 (file)
index 23a8dc8..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "callbacks.h"
-
-static LIST_HEAD(cbs_list);
-static DEFINE_MUTEX(cbs_mutex);
-static int cur_handle = 0;
-
-struct cb_item {
-       struct list_head list;
-       enum callback_t type;
-       int handle;
-       void (*func)(void);
-};
-
-static inline void __lock_cbs_list(void)
-{
-       mutex_lock(&cbs_mutex);
-}
-
-static inline void __unlock_cbs_list(void)
-{
-       mutex_unlock(&cbs_mutex);
-}
-
-static inline int __get_new_handle(void)
-{
-       return cur_handle++;
-}
-
-static inline void __free_cb(struct cb_item *cb)
-{
-       list_del(&cb->list);
-       kfree(cb);
-}
-
-static struct cb_item *__get_cb_by_handle(int handle)
-{
-       struct cb_item *cb;
-
-       list_for_each_entry(cb, &cbs_list, list)
-               if (cb->handle == handle)
-                       return cb;
-
-       return NULL;
-}
-
-
-/**
- * @brief Executes callbacks on start/stop
- *
- * @param cbt Callback type
- * @return Void
- */
-void exec_cbs(enum callback_t cbt)
-{
-       struct cb_item *cb;
-
-       __lock_cbs_list();
-
-       list_for_each_entry(cb, &cbs_list, list)
-               if (cb->type == cbt)
-                       cb->func();
-
-       __unlock_cbs_list();
-}
-
-/**
- * @brief Removes all callbacks from list
- *
- * @return Void
- */
-void remove_all_cbs(void)
-{
-       struct cb_item *cb, *n;
-
-       __lock_cbs_list();
-
-       list_for_each_entry_safe(cb, n, &cbs_list, list)
-               __free_cb(cb);
-
-       __unlock_cbs_list();
-}
-
-/**
- * @brief Registers callback on event
- *
- * @param cbt Callback type
- * @param func Callback function
- * @return Handle on succes, error code on error
- */
-int us_manager_reg_cb(enum callback_t cbt, void (*func)(void))
-{
-       struct cb_item *cb;
-       int handle;
-
-       cb = kmalloc(sizeof(*cb), GFP_KERNEL);
-       if (cb == NULL)
-               return -ENOMEM;
-
-       handle = __get_new_handle();
-
-       INIT_LIST_HEAD(&cb->list);
-       cb->type = cbt;
-       cb->handle = handle;
-       cb->func = func;
-
-       __lock_cbs_list();
-       list_add_tail(&cb->list, &cbs_list);
-       __unlock_cbs_list();
-
-       return handle;
-}
-EXPORT_SYMBOL_GPL(us_manager_reg_cb);
-
-/**
- * @brief Unegisters callback by handle
- *
- * @param handle Callback handle
- * @return Void
- */
-void us_manager_unreg_cb(int handle)
-{
-       struct cb_item *cb;
-
-       __lock_cbs_list();
-
-       cb = __get_cb_by_handle(handle);
-       if (cb == NULL)
-               goto handle_not_found;
-
-       __free_cb(cb);
-
-handle_not_found:
-       __unlock_cbs_list();
-}
-EXPORT_SYMBOL_GPL(us_manager_unreg_cb);
diff --git a/us_manager/callbacks.h b/us_manager/callbacks.h
deleted file mode 100644 (file)
index ba835d4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __CALLBACKS_H__
-#define __CALLBACKS_H__
-
-enum callback_t {
-       START_CB = 0,
-       STOP_CB,
-};
-
-/* Gets callback type (on start or on stop) and function pointer.
- * Returns positive callback's handle that is used to unregister on success,
- * negative error code otherwise.
- * Exported function. */
-int us_manager_reg_cb(enum callback_t cbt, void (*func)(void));
-
-/* Gets handle and unregisters function with this handle.
- * Exported function. */
-void us_manager_unreg_cb(int handle);
-
-/* Used to execute callbacks when start/stop is occuring. */
-void exec_cbs(enum callback_t cbt);
-
-/* Removes all callbacks */
-void remove_all_cbs(void);
-
-#endif /* __CALLBACKS_H__ */
diff --git a/us_manager/debugfs_us_manager.c b/us_manager/debugfs_us_manager.c
deleted file mode 100644 (file)
index a1305be..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#include <linux/debugfs.h>
-#include <linux/module.h>
-
-#include <master/swap_debugfs.h>
-#include <master/swap_initializer.h>
-#include <us_manager/sspt/sspt_proc.h>
-
-#include "debugfs_us_manager.h"
-
-#define MAX_APPS_COUNT  8   /* According to daemon defenitions */
-#define PID_STRING      21  /* Maximum pid string = 20 (max digits count in
-                             * unsigned int on 64-bit arch) + 1 (for \n) */
-
-/* ============================================================================
- * =                          FOPS_TASKS                                      =
- * ============================================================================
- */
-
-struct read_buf {
-       char *begin;
-       char *ptr;
-       char *end;
-};
-
-static void on_each_proc_callback(struct sspt_proc *proc, void *data)
-{
-       struct read_buf *rbuf = (struct read_buf *)data;
-       char pid_str[PID_STRING];
-       int len;
-
-       /* skip process */
-       if (!sspt_proc_is_send_event(proc))
-               return;
-
-       snprintf(pid_str, sizeof(pid_str), "%d", proc->tgid);
-
-       len = strlen(pid_str);
-
-       if (rbuf->end - rbuf->ptr < len + 2)
-               return;
-
-       memcpy(rbuf->ptr, pid_str, len);
-       rbuf->ptr += len;
-
-       *rbuf->ptr = ' ';
-       ++rbuf->ptr;
-}
-
-static ssize_t read_tasks(struct file *file, char __user *user_buf,
-                         size_t count, loff_t *ppos)
-{
-       char buf[PID_STRING * MAX_APPS_COUNT];
-       struct read_buf rbuf = {
-               .begin = buf,
-               .ptr = buf,
-               .end = buf + sizeof(buf)
-       };
-
-       on_each_proc_no_lock(on_each_proc_callback, (void *)&rbuf);
-
-       if (rbuf.ptr != rbuf.begin)
-               rbuf.ptr--;
-
-       *rbuf.ptr = '\n';
-
-       return simple_read_from_buffer(user_buf, count, ppos, rbuf.begin,
-                                  rbuf.ptr - rbuf.begin);
-}
-
-static const struct file_operations fops_tasks = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .read = read_tasks,
-       .llseek = default_llseek
-};
-
-/* ============================================================================
- * =                          INIT/EXIT                                       =
- * ============================================================================
- */
-
-static struct dentry *us_manager_dir;
-
-/**
- * @brief Destroy debugfs for us_manager
- *
- * @return Void
- */
-void exit_debugfs_us_manager(void)
-{
-       if (us_manager_dir)
-               debugfs_remove_recursive(us_manager_dir);
-
-       us_manager_dir = NULL;
-}
-
-/**
- * @brief Create debugfs for us_manager
- *
- * @return Error code
- */
-int init_debugfs_us_manager(void)
-{
-       struct dentry *swap_dir, *dentry;
-
-       swap_dir = swap_debugfs_getdir();
-       if (swap_dir == NULL)
-               return -ENOENT;
-
-       us_manager_dir = swap_debugfs_create_dir(US_MANAGER_DFS_DIR, swap_dir);
-       if (us_manager_dir == NULL)
-               return -ENOMEM;
-
-       dentry = swap_debugfs_create_file(US_MANAGER_TASKS, 0600,
-                                         us_manager_dir, NULL, &fops_tasks);
-       if (dentry == NULL)
-               goto fail;
-
-       return 0;
-
-fail:
-       exit_debugfs_us_manager();
-       return -ENOMEM;
-}
diff --git a/us_manager/debugfs_us_manager.h b/us_manager/debugfs_us_manager.h
deleted file mode 100644 (file)
index 11c281b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __DEBUGFS_US_MANAGER_H__
-#define __DEBUGFS_US_MANAGER_H__
-
-/**
- * @file us_manager/debugfs_us_manager.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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, 2014
- */
-
-/**
- * @def US_MANAGER_DFS_DIR @hideinitializer
- * Name in debugfs
- */
-#define US_MANAGER_DFS_DIR "us_manager"
-
-/**
- * @def US_MANAGER_DFS_DIR @hideinitializer
- * Name in debugfs
- */
-#define US_MANAGER_TASKS   "tasks"
-
-int init_debugfs_us_manager(void);
-void exit_debugfs_us_manager(void);
-
-#endif /* __DEBUGFS_US_MANAGER_H__ */
diff --git a/us_manager/helper.c b/us_manager/helper.c
deleted file mode 100644 (file)
index 55dfffc..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/helper.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include "sspt/sspt.h"
-#include "sspt/sspt_filter.h"
-#include "helper.h"
-#include "usm_hook.h"
-
-
-/* do_page_fault() */
-static void hh_page_fault(unsigned long addr)
-{
-       unsigned long page_addr = addr & PAGE_MASK;
-
-       call_page_fault(current, page_addr);
-}
-
-
-/* copy_process() */
-static void disarm_ip(struct sspt_ip *ip, void *data)
-{
-       struct task_struct *child = (struct task_struct *)data;
-       struct uprobe *up;
-
-       up = probe_info_get_uprobe(ip->desc->type, ip);
-       if (up)
-               disarm_uprobe(up, child);
-}
-
-static void hh_clean_task(struct task_struct *parent, struct task_struct *child)
-{
-       struct sspt_proc *proc;
-
-       proc = sspt_proc_get_by_task(parent);
-       if (proc) {
-               /* disarm up for child */
-               sspt_proc_on_each_ip(proc, disarm_ip, (void *)child);
-
-               /* disarm urp for child */
-               swap_uretprobe_free_task(parent, child, false);
-
-               sspt_proc_put(proc);
-       }
-}
-
-
-/* mm_release() */
-static void hh_mm_release(struct task_struct *task)
-{
-       struct mm_struct *mm = task->mm;
-
-       if (mm == NULL) {
-               pr_err("mm is NULL\n");
-               return;
-       }
-
-       /* TODO: this lock for synchronizing to disarm urp */
-       down_write(&mm->mmap_sem);
-       if (task != task->group_leader) {
-               struct sspt_proc *proc;
-
-               if (task != current) {
-                       pr_err("call mm_release in isn't current context\n");
-                       goto up_mmsem;
-               }
-
-               /* if the thread is killed we need to discard pending
-                * uretprobe instances which have not triggered yet */
-               proc = sspt_proc_by_task(task);
-               if (proc)
-                       swap_uretprobe_free_task(task, task, true);
-       } else {
-               call_mm_release(task);
-       }
-
-up_mmsem:
-       up_write(&mm->mmap_sem);
-}
-
-
-/* do_munmap() */
-struct msg_unmap_data {
-       unsigned long start;
-       unsigned long end;
-};
-
-static void msg_unmap(struct sspt_filter *f, void *data)
-{
-       if (f->pfg_is_inst) {
-               struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
-
-               if (cb && cb->msg_unmap) {
-                       struct msg_unmap_data *msg_data;
-
-                       msg_data = (struct msg_unmap_data *)data;
-                       cb->msg_unmap(msg_data->start, msg_data->end);
-               }
-       }
-}
-
-static void __remove_unmap_probes(struct sspt_proc *proc,
-                                 unsigned long start, unsigned long end)
-{
-       LIST_HEAD(head);
-
-       if (sspt_proc_get_files_by_region(proc, &head, start, end)) {
-               struct sspt_file *file, *n;
-               struct task_struct *task = proc->leader;
-
-               list_for_each_entry_safe(file, n, &head, list) {
-                       if (file->vm_start >= end)
-                               continue;
-
-                       if (file->vm_start >= start)
-                               sspt_file_uninstall(file, task, US_UNINSTALL);
-                       /* TODO: else: uninstall pages: * start..file->vm_end */
-               }
-
-               sspt_proc_insert_files(proc, &head);
-       }
-}
-
-static void hh_munmap(unsigned long start, unsigned long end)
-{
-       struct sspt_proc *proc;
-
-       proc = sspt_proc_get_by_task(current);
-       if (proc) {
-               struct msg_unmap_data msg_data = {
-                       .start = start,
-                       .end = end,
-               };
-
-               __remove_unmap_probes(proc, start, end);
-
-               /* send unmap region */
-               sspt_proc_on_each_filter(proc, msg_unmap, (void *)&msg_data);
-
-               sspt_proc_put(proc);
-       }
-}
-
-
-/* do_mmap_pgoff() */
-static void msg_map(struct sspt_filter *f, void *data)
-{
-       if (f->pfg_is_inst) {
-               struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
-
-               if (cb && cb->msg_map)
-                       cb->msg_map((struct vm_area_struct *)data);
-       }
-}
-
-static void hh_mmap(struct file *file, unsigned long addr)
-{
-       struct sspt_proc *proc;
-       struct task_struct *task;
-       struct vm_area_struct *vma;
-
-       task = current->group_leader;
-       if (is_kthread(task))
-               return;
-
-       if (IS_ERR_VALUE(addr))
-               return;
-
-       proc = sspt_proc_get_by_task(task);
-       if (proc == NULL)
-               return;
-
-       vma = find_vma_intersection(task->mm, addr, addr + 1);
-       if (vma && check_vma(vma)) {
-               usm_hook_mmap(proc, vma);
-               sspt_proc_on_each_filter(proc, msg_map, (void *)vma);
-       }
-
-       sspt_proc_put(proc);
-}
-
-
-/* set_task_comm() */
-static void hh_set_comm(struct task_struct *task)
-{
-       if (task == current)
-               check_task_and_install(current);
-}
-
-
-/* release_task() */
-static void hh_change_leader(struct task_struct *prev,
-                            struct task_struct *next)
-{
-       sspt_change_leader(prev, next);
-}
-
-
-#ifdef CONFIG_SWAP_HOOK_USAUX
-# include "helper_hook.c"
-#else /* CONFIG_SWAP_HOOK_USAUX */
-# include "helper_kprobe.c"
-#endif /* CONFIG_SWAP_HOOK_USAUX */
diff --git a/us_manager/helper.h b/us_manager/helper.h
deleted file mode 100644 (file)
index 242a53e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file us_manager/helper.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-#ifndef _HELPER_H
-#define _HELPER_H
-
-#include <linux/sched.h>
-
-static inline int is_kthread(struct task_struct *task)
-{
-       return !task->mm;
-}
-
-int helper_once(void);
-int helper_init(void);
-void helper_uninit(void);
-
-int helper_reg(void);
-void helper_unreg_top(void);
-void helper_unreg_bottom(void);
-
-#endif /* _HELPER_H */
diff --git a/us_manager/helper_hook.c b/us_manager/helper_hook.c
deleted file mode 100644 (file)
index 972e9db..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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, 2016
- *
- *  2016  Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- */
-
-
-#include <linux/rwsem.h>
-#include <swap/hook_usaux.h>
-#include <kprobe/swap_ktd.h>
-
-
-struct hooks_td {
-       bool in_copy_process;
-};
-
-static void hooks_td_init(struct task_struct *task, void *data)
-{
-       struct hooks_td *td = (struct hooks_td *)data;
-
-       td->in_copy_process = false;
-}
-
-static void hooks_td_exit(struct task_struct *task, void *data)
-{
-       struct hooks_td *td = (struct hooks_td *)data;
-
-       WARN(td->in_copy_process, "in_copy_process=%d", td->in_copy_process);
-}
-
-static struct ktask_data hooks_ktd = {
-       .init = hooks_td_init,
-       .exit = hooks_td_exit,
-       .size = sizeof(struct hooks_td),
-};
-
-static struct hooks_td *current_hooks_td(void)
-{
-       return (struct hooks_td *)swap_ktd(&hooks_ktd, current);
-}
-
-
-static atomic_t run_flag = ATOMIC_INIT(0);
-
-static void hook_start(void)
-{
-       atomic_set(&run_flag, 1);
-}
-
-static void hook_stop(void)
-{
-       atomic_set(&run_flag, 0);
-}
-
-static bool hook_is_running(void)
-{
-       return atomic_read(&run_flag);
-}
-
-
-static void hook_page_fault(unsigned long addr)
-{
-       if (hook_is_running())
-               hh_page_fault(addr);
-}
-
-static DECLARE_RWSEM(copy_process_sem);
-
-static void hook_copy_process_pre(void)
-{
-       if (hook_is_running()) {
-               down_read(&copy_process_sem);
-               if (hook_is_running())
-                       current_hooks_td()->in_copy_process = true;
-               else
-                       up_read(&copy_process_sem);
-       }
-}
-
-static void hook_copy_process_post(struct task_struct *task)
-{
-       struct task_struct *parent = current;
-       struct hooks_td *td = current_hooks_td();
-
-       if (!td->in_copy_process)
-               return;
-
-       if (IS_ERR(task))
-               goto out;
-
-       /* check flags CLONE_VM */
-       if (task->mm != parent->mm)
-               hh_clean_task(current, task);
-
-out:
-       up_read(&copy_process_sem);
-       td->in_copy_process = false;
-}
-
-static void hook_mm_release(struct task_struct *task)
-{
-       hh_mm_release(task);
-}
-
-static void hook_munmap(unsigned long start, unsigned long end)
-{
-       hh_munmap(start, end);
-}
-
-static void hook_mmap(struct file *file, unsigned long addr)
-{
-       hh_mmap(file, addr);
-}
-
-static void hook_set_comm(struct task_struct *task)
-{
-       if (hook_is_running())
-               hh_set_comm(task);
-}
-
-static void hook_change_leader(struct task_struct *prev,
-                               struct task_struct *next)
-{
-       hh_change_leader(prev, next);
-}
-
-static struct hook_usaux hook_usaux = {
-       .owner = THIS_MODULE,
-       .page_fault = hook_page_fault,
-       .copy_process_pre = hook_copy_process_pre,
-       .copy_process_post = hook_copy_process_post,
-       .mm_release = hook_mm_release,
-       .munmap = hook_munmap,
-       .mmap = hook_mmap,
-       .set_comm = hook_set_comm,
-       .change_leader = hook_change_leader,
-};
-
-int helper_once(void)
-{
-       return 0;
-}
-
-int helper_init(void)
-{
-       return swap_ktd_reg(&hooks_ktd);
-}
-
-void helper_uninit(void)
-{
-       swap_ktd_unreg(&hooks_ktd);
-}
-
-int helper_reg(void)
-{
-       int ret;
-
-       ret = hook_usaux_set(&hook_usaux);
-       if (ret)
-               return ret;
-
-       hook_start();
-       return ret;
-}
-
-void helper_unreg_top(void)
-{
-       hook_stop();
-}
-
-void helper_unreg_bottom(void)
-{
-       /* waiting for copy_process() finishing */
-       down_write(&copy_process_sem);
-       up_write(&copy_process_sem);
-
-       hook_usaux_reset();
-}
diff --git a/us_manager/helper_kprobe.c b/us_manager/helper_kprobe.c
deleted file mode 100644 (file)
index 0ea58cb..0000000
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * 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, 2016
- *
- *  2016    Vyacheslav Cherkashin
- */
-
-
-#include <linux/kconfig.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <ksyms/ksyms.h>
-#include <writer/kernel_operations.h>
-#include "us_slot_manager.h"
-#include "sspt/sspt.h"
-#include "sspt/sspt_filter.h"
-#include "helper.h"
-
-
-static atomic_t stop_flag = ATOMIC_INIT(0);
-
-
-/*
- ******************************************************************************
- *                               do_page_fault()                              *
- ******************************************************************************
- */
-
-struct pf_data {
-       unsigned long addr;
-
-       struct pt_regs *pf_regs;
-       unsigned long save_pc;
-};
-
-static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pf_data *data = (struct pf_data *)ri->data;
-
-#if defined(CONFIG_ARM)
-       data->addr = swap_get_karg(regs, 0);
-       data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 2);
-       data->save_pc = data->pf_regs->ARM_pc;
-#elif defined(CONFIG_X86_32)
-       data->addr = read_cr2();
-       data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 0);
-       data->save_pc = data->pf_regs->ip;
-#elif defined(CONFIG_ARM64)
-       data->addr = swap_get_karg(regs, 0);
-       data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 2);
-       data->save_pc = data->pf_regs->pc;
-       /* FIXME: to implement */
-#else
-       #error "this architecture is not supported"
-#endif /* CONFIG_arch */
-
-       if (data->addr) {
-               int ret = 0;
-               struct sspt_proc *proc;
-
-               proc = sspt_proc_get_by_task(current);
-               if (proc) {
-                       if (proc->r_state_addr == data->addr) {
-                               /* skip ret_handler_pf() for current task */
-                               ret = 1;
-                       }
-
-                       sspt_proc_put(proc);
-               }
-
-               return ret;
-       }
-
-       return 0;
-}
-
-static unsigned long cb_pf(void *data)
-{
-       unsigned long addr = *(unsigned long *)data;
-
-       hh_page_fault(addr);
-
-       return 0;
-}
-
-/* Detects when IPs are really loaded into phy mem and installs probes. */
-static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct task_struct *task = current;
-       struct pf_data *data = (struct pf_data *)ri->data;
-       unsigned long addr;
-       int ret;
-
-       if (is_kthread(task))
-               return 0;
-
-       /* skip fixup page_fault */
-#if defined(CONFIG_ARM)
-       if (data->save_pc != data->pf_regs->ARM_pc)
-               return 0;
-#elif defined(CONFIG_X86_32)
-       if (data->save_pc != data->pf_regs->ip)
-               return 0;
-#elif defined(CONFIG_ARM64)
-       if (data->save_pc != data->pf_regs->pc)
-               return 0;
-#endif /* CONFIG_arch */
-
-       /* TODO: check return value */
-       addr = data->addr;
-       ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_pf,
-                         &addr, sizeof(addr));
-
-       if (ret == 0)
-               ri->ret_addr = (unsigned long *)get_jump_addr();
-
-       return 0;
-}
-
-static struct kretprobe mf_kretprobe = {
-       .entry_handler = entry_handler_pf,
-       .handler = ret_handler_pf,
-       .data_size = sizeof(struct pf_data)
-};
-
-static int register_mf(void)
-{
-       int ret;
-
-       ret = swap_register_kretprobe(&mf_kretprobe);
-       if (ret)
-               pr_err("swap_register_kretprobe(handle_mm_fault) ret=%d!\n", ret);
-
-       return ret;
-}
-
-static void unregister_mf(void)
-{
-       swap_unregister_kretprobe(&mf_kretprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                              copy_process()                                *
- ******************************************************************************
- */
-static atomic_t rm_uprobes_child_cnt = ATOMIC_INIT(0);
-
-static unsigned long cb_clean_child(void *data)
-{
-       struct task_struct *parent = current;
-       struct task_struct *child = *(struct task_struct **)data;
-
-       hh_clean_task(parent, child);
-
-       atomic_dec(&rm_uprobes_child_cnt);
-       return 0;
-}
-
-static void rm_uprobes_child(struct kretprobe_instance *ri,
-                            struct pt_regs *regs, struct task_struct *child)
-{
-       int ret;
-
-       if (!sspt_proc_by_task(current))
-               return;
-
-       /* set jumper */
-       ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
-                         cb_clean_child, &child, sizeof(child));
-       if (ret == 0) {
-               atomic_inc(&rm_uprobes_child_cnt);
-               ri->ret_addr = (unsigned long *)get_jump_addr();
-       } else {
-               WARN_ON(1);
-       }
-}
-
-
-static int pre_handler_cp(struct kprobe *p, struct pt_regs *regs)
-{
-       if (is_kthread(current))
-               goto out;
-
-       if (atomic_read(&stop_flag))
-               call_mm_release(current);
-
-out:
-       return 0;
-}
-
-static atomic_t copy_process_cnt = ATOMIC_INIT(0);
-
-static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       atomic_inc(&copy_process_cnt);
-
-       return 0;
-}
-
-/* Delete uprobs in children at fork */
-static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct task_struct *task;
-
-       task = (struct task_struct *)regs_return_value(regs);
-       if (IS_ERR(task))
-               goto out;
-
-       if (task->mm != current->mm)    /* check flags CLONE_VM */
-               rm_uprobes_child(ri, regs, task);
-out:
-       atomic_dec(&copy_process_cnt);
-       return 0;
-}
-
-static struct kretprobe cp_kretprobe = {
-       .entry_handler = entry_handler_cp,
-       .handler = ret_handler_cp,
-};
-
-static struct kprobe cp_kprobe = {
-       .pre_handler = pre_handler_cp
-};
-
-static int register_cp(void)
-{
-       int ret;
-
-
-       ret = swap_register_kprobe(&cp_kprobe);
-       if (ret)
-               pr_err("swap_register_kprobe(copy_process) ret=%d!\n", ret);
-
-       ret = swap_register_kretprobe(&cp_kretprobe);
-       if (ret) {
-               pr_err("swap_register_kretprobe(copy_process) ret=%d!\n", ret);
-               swap_unregister_kprobe(&cp_kprobe);
-       }
-
-       return ret;
-}
-
-static void unregister_cp(void)
-{
-       swap_unregister_kretprobe_top(&cp_kretprobe, 0);
-       do {
-               synchronize_sched();
-       } while (atomic_read(&copy_process_cnt));
-       swap_unregister_kretprobe_bottom(&cp_kretprobe);
-       swap_unregister_kprobe(&cp_kprobe);
-
-       do {
-               synchronize_sched();
-       } while (atomic_read(&rm_uprobes_child_cnt));
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                                mm_release()                                *
- ******************************************************************************
- */
-
-/* Detects when target process removes IPs. */
-static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
-
-       hh_mm_release(task);
-
-       return 0;
-}
-
-static struct kprobe mr_kprobe = {
-       .pre_handler = mr_pre_handler
-};
-
-static int register_mr(void)
-{
-       int ret;
-
-       ret = swap_register_kprobe(&mr_kprobe);
-       if (ret)
-               pr_err("swap_register_kprobe(mm_release) ret=%d!\n", ret);
-
-       return ret;
-}
-
-static void unregister_mr(void)
-{
-       swap_unregister_kprobe(&mr_kprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                                 do_munmap()                                *
- ******************************************************************************
- */
-struct unmap_data {
-       unsigned long start;
-       size_t len;
-};
-
-static atomic_t unmap_cnt = ATOMIC_INIT(0);
-
-static unsigned long cb_munmap(void *data)
-{
-       struct unmap_data *umd = (struct unmap_data *)data;
-
-       hh_munmap(umd->start, umd->start + umd->len);
-
-       atomic_dec(&unmap_cnt);
-       return 0;
-}
-
-static int entry_handler_unmap(struct kretprobe_instance *ri,
-                              struct pt_regs *regs)
-{
-       struct unmap_data *data = (struct unmap_data *)ri->data;
-
-       data->start = swap_get_karg(regs, 1);
-       data->len = (size_t)PAGE_ALIGN(swap_get_karg(regs, 2));
-
-       atomic_inc(&unmap_cnt);
-       return 0;
-}
-
-static int ret_handler_unmap(struct kretprobe_instance *ri,
-                            struct pt_regs *regs)
-{
-       int ret;
-
-       if (regs_return_value(regs)) {
-               atomic_dec(&unmap_cnt);
-               return 0;
-       }
-
-       ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_munmap,
-                         (struct unmap_data *)ri->data,
-                         sizeof(struct unmap_data));
-       if (ret == 0) {
-               ri->ret_addr = (unsigned long *)get_jump_addr();
-       } else {
-               WARN_ON(1);
-               atomic_dec(&unmap_cnt);
-       }
-
-       return 0;
-}
-
-static struct kretprobe unmap_kretprobe = {
-       .entry_handler = entry_handler_unmap,
-       .handler = ret_handler_unmap,
-       .data_size = sizeof(struct unmap_data)
-};
-
-static int register_unmap(void)
-{
-       int ret;
-
-       ret = swap_register_kretprobe(&unmap_kretprobe);
-       if (ret)
-               pr_err("swap_register_kprobe(do_munmap) ret=%d!\n", ret);
-
-       return ret;
-}
-
-static void unregister_unmap(void)
-{
-       swap_unregister_kretprobe_top(&unmap_kretprobe, 0);
-       do {
-               synchronize_sched();
-       } while (atomic_read(&unmap_cnt));
-       swap_unregister_kretprobe_bottom(&unmap_kretprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                               do_mmap_pgoff()                              *
- ******************************************************************************
- */
-static int ret_handler_mmap(struct kretprobe_instance *ri,
-                           struct pt_regs *regs)
-{
-       unsigned long addr = regs_return_value(regs);
-
-       hh_mmap(NULL, addr);
-
-       return 0;
-}
-
-static struct kretprobe mmap_kretprobe = {
-       .handler = ret_handler_mmap
-};
-
-static int register_mmap(void)
-{
-       int ret;
-
-       ret = swap_register_kretprobe(&mmap_kretprobe);
-       if (ret)
-               pr_err("swap_register_kretprobe(do_mmap_pgoff) ret=%d!\n", ret);
-
-       return ret;
-}
-
-static void unregister_mmap(void)
-{
-       swap_unregister_kretprobe(&mmap_kretprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- *                               set_task_comm()                              *
- ******************************************************************************
- */
-struct comm_data {
-       struct task_struct *task;
-};
-
-static unsigned long cb_check_and_install(void *data)
-{
-       hh_set_comm(current);
-
-       return 0;
-}
-
-static int entry_handler_comm(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       struct comm_data *data = (struct comm_data *)ri->data;
-
-       data->task = (struct task_struct *)swap_get_karg(regs, 0);
-
-       return 0;
-}
-
-static int ret_handler_comm(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       int ret;
-
-       if (is_kthread(current))
-               return 0;
-
-       task = ((struct comm_data *)ri->data)->task;
-       if (task != current)
-               return 0;
-
-       ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
-                         cb_check_and_install, NULL, 0);
-       if (ret == 0)
-               ri->ret_addr = (unsigned long *)get_jump_addr();
-
-       return 0;
-}
-
-static struct kretprobe comm_kretprobe = {
-       .entry_handler = entry_handler_comm,
-       .handler = ret_handler_comm,
-       .data_size = sizeof(struct comm_data)
-};
-
-static int register_comm(void)
-{
-       int ret;
-
-       ret = swap_register_kretprobe(&comm_kretprobe);
-       if (ret)
-               pr_err("swap_register_kretprobe(set_task_comm) ret=%d!\n", ret);
-
-       return ret;
-}
-
-static void unregister_comm(void)
-{
-       swap_unregister_kretprobe(&comm_kretprobe);
-}
-
-
-
-
-/*
- ******************************************************************************
- *                               release_task()                               *
- ******************************************************************************
- */
-static int release_task_h(struct kprobe *p, struct pt_regs *regs)
-{
-       struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
-       struct task_struct *cur = current;
-
-       if (cur->flags & PF_KTHREAD)
-               return 0;
-
-       /* EXEC: change group leader */
-       if (cur != task && task->pid == cur->pid)
-               hh_change_leader(task, cur);
-
-       return 0;
-}
-
-struct kprobe release_task_kp = {
-       .pre_handler = release_task_h,
-};
-
-static int reg_release_task(void)
-{
-       return swap_register_kprobe(&release_task_kp);
-}
-
-static void unreg_release_task(void)
-{
-       swap_unregister_kprobe(&release_task_kp);
-}
-
-
-
-
-
-/**
- * @brief Registration of helper
- *
- * @return Error code
- */
-int helper_reg(void)
-{
-       int ret = 0;
-
-       atomic_set(&stop_flag, 0);
-
-       /* tracking group leader changing */
-       ret = reg_release_task();
-       if (ret)
-               return ret;
-
-       /*
-        * install probe on 'set_task_comm' to detect when field comm struct
-        * task_struct changes
-        */
-       ret = register_comm();
-       if (ret)
-               goto unreg_rel_task;
-
-       /* install probe on 'do_munmap' to detect when for remove US probes */
-       ret = register_unmap();
-       if (ret)
-               goto unreg_comm;
-
-       /* install probe on 'mm_release' to detect when for remove US probes */
-       ret = register_mr();
-       if (ret)
-               goto unreg_unmap;
-
-       /* install probe on 'copy_process' to disarm children process */
-       ret = register_cp();
-       if (ret)
-               goto unreg_mr;
-
-       /* install probe on 'do_mmap_pgoff' to detect when mapping file */
-       ret = register_mmap();
-       if (ret)
-               goto unreg_cp;
-
-       /*
-        * install probe on 'handle_mm_fault' to detect when US pages will be
-        * loaded
-        */
-       ret = register_mf();
-       if (ret)
-               goto unreg_mmap;
-
-       return ret;
-
-unreg_mmap:
-       unregister_mmap();
-
-unreg_cp:
-       unregister_cp();
-
-unreg_mr:
-       unregister_mr();
-
-unreg_unmap:
-       unregister_unmap();
-
-unreg_comm:
-       unregister_comm();
-
-unreg_rel_task:
-       unreg_release_task();
-
-       return ret;
-}
-
-/**
- * @brief Unegistration of helper bottom
- *
- * @return Void
- */
-void helper_unreg_top(void)
-{
-       unregister_mf();
-       atomic_set(&stop_flag, 1);
-}
-
-/**
- * @brief Unegistration of helper top
- *
- * @return Void
- */
-void helper_unreg_bottom(void)
-{
-       unregister_mmap();
-       unregister_cp();
-       unregister_mr();
-       unregister_unmap();
-       unregister_comm();
-       unreg_release_task();
-}
-
-/**
- * @brief Initialization of helper
- *
- * @return Error code
- */
-int helper_once(void)
-{
-       const char *sym;
-
-       sym = "do_page_fault";
-       mf_kretprobe.kp.addr = swap_ksyms(sym);
-       if (mf_kretprobe.kp.addr == 0)
-               goto not_found;
-
-       sym = "copy_process";
-       cp_kretprobe.kp.addr = swap_ksyms_substr(sym);
-       if (cp_kretprobe.kp.addr == 0)
-               goto not_found;
-       cp_kprobe.addr = cp_kretprobe.kp.addr;
-
-       sym = "mm_release";
-       mr_kprobe.addr = swap_ksyms(sym);
-       if (mr_kprobe.addr == 0)
-               goto not_found;
-
-       sym = "do_munmap";
-       unmap_kretprobe.kp.addr = swap_ksyms(sym);
-       if (unmap_kretprobe.kp.addr == 0)
-               goto not_found;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
-       sym = "do_mmap";
-#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) */
-       sym = "do_mmap_pgoff";
-#endif  /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) */
-       mmap_kretprobe.kp.addr = swap_ksyms(sym);
-       if (mmap_kretprobe.kp.addr == 0)
-               goto not_found;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
-       sym = "__set_task_comm";
-#else  /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */
-       sym = "set_task_comm";
-#endif  /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */
-       comm_kretprobe.kp.addr = swap_ksyms(sym);
-       if (comm_kretprobe.kp.addr == 0)
-               goto not_found;
-
-       sym = "release_task";
-       release_task_kp.addr = swap_ksyms(sym);
-       if (release_task_kp.addr == 0)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       pr_err("ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-int helper_init(void)
-{
-       return 0;
-}
-
-void helper_uninit(void)
-{
-}
diff --git a/us_manager/img/img_file.c b/us_manager/img/img_file.c
deleted file mode 100644 (file)
index e5165d9..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/img/img_file.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include "img_file.h"
-#include "img_ip.h"
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/dcache.h>
-#include <linux/atomic.h>
-
-
-static atomic_t file_counter = ATOMIC_INIT(0);
-
-
-static void img_del_ip_by_list(struct img_ip *ip);
-
-/**
- * @brief Create img_file struct
- *
- * @param dentry Dentry of file
- * @return Pointer to the created img_file struct
- */
-struct img_file *img_file_create(struct dentry *dentry)
-{
-       struct img_file *file;
-
-       file = kmalloc(sizeof(*file), GFP_ATOMIC);
-       if (file == NULL) {
-               pr_err("%s: failed to allocate memory\n", __func__);
-               return ERR_PTR(-ENOMEM);
-       }
-       atomic_inc(&file_counter);
-
-       file->dentry = dentry;
-       INIT_LIST_HEAD(&file->list);
-       INIT_LIST_HEAD(&file->ips.head);
-       mutex_init(&file->ips.mtx);
-       atomic_set(&file->use, 1);
-
-       return file;
-}
-
-/**
- * @brief Remove img_file struct
- *
- * @param file remove object
- * @return Void
- */
-static void img_file_free(struct img_file *file)
-{
-       struct img_ip *ip, *tmp;
-
-       list_for_each_entry_safe(ip, tmp, &file->ips.head, list) {
-               img_del_ip_by_list(ip);
-               img_ip_clean(ip);
-               img_ip_put(ip);
-       }
-
-       atomic_dec(&file_counter);
-       kfree(file);
-}
-
-/* called with mutex_[lock/unlock](&file->ips.mtx) */
-static void img_add_ip_by_list(struct img_file *file, struct img_ip *ip)
-{
-       list_add(&ip->list, &file->ips.head);
-}
-
-/* called with mutex_[lock/unlock](&file->ips.mtx) */
-static void img_del_ip_by_list(struct img_ip *ip)
-{
-       list_del(&ip->list);
-}
-
-void img_file_get(struct img_file *file)
-{
-       WARN_ON(!atomic_read(&file->use));
-       atomic_inc(&file->use);
-}
-
-void img_file_put(struct img_file *file)
-{
-       if (atomic_dec_and_test(&file->use))
-               img_file_free(file);
-}
-
-
-/**
- * @brief Add instrumentation pointer
- *
- * @param file Pointer to the img_file struct
- * @param addr Function address
- * @param probe_Pointer to a probe_info structure with an information about
- * the probe.
- * @return Error code
- */
-struct img_ip *img_file_add_ip(struct img_file *file, unsigned long addr,
-                              struct probe_desc *pd)
-{
-       struct img_ip *ip;
-
-       ip = img_ip_create(addr, pd, file);
-       if (IS_ERR(ip))
-               return ip;
-
-       mutex_lock(&file->ips.mtx);
-       img_add_ip_by_list(file, ip);
-       mutex_unlock(&file->ips.mtx);
-
-       return ip;
-}
-
-/**
- * @brief Delete img_ip struct from img_file struct
- *
- * @param file Pointer to the img_file struct
- * @param addr Function address
- * @return Error code
- */
-void img_file_del_ip(struct img_file *file, struct img_ip *ip)
-{
-       mutex_lock(&file->ips.mtx);
-       img_del_ip_by_list(ip);
-       mutex_unlock(&file->ips.mtx);
-
-       img_ip_clean(ip);
-       img_ip_put(ip);
-}
-
-/**
- * @brief Check on absence img_ip structs in img_file struct
- *
- * @param file Pointer to the img_file struct
- * @return
- *       - 0 - not empty
- *       - 1 - empty
- */
-int img_file_empty(struct img_file *file)
-{
-       return list_empty(&file->ips.head);
-}
-
-bool img_file_is_unloadable(void)
-{
-       return !(atomic_read(&file_counter) + !img_ip_is_unloadable());
-}
-
-/**
- * @brief For debug
- *
- * @param file Pointer to the img_file struct
- * @return Void
- */
-
-/* debug */
-void img_file_print(struct img_file *file)
-{
-       struct img_ip *ip;
-
-       printk(KERN_INFO "###      d_iname=%s\n", file->dentry->d_iname);
-
-       mutex_lock(&file->ips.mtx);
-       list_for_each_entry(ip, &file->ips.head, list) {
-               img_ip_print(ip);
-       }
-       mutex_unlock(&file->ips.mtx);
-}
-/* debug */
diff --git a/us_manager/img/img_file.h b/us_manager/img/img_file.h
deleted file mode 100644 (file)
index e84bcaa..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file us_manager/img/img_file.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- */
-
-
-#ifndef _IMG_FILE_H
-#define _IMG_FILE_H
-
-#include <linux/types.h>
-#include <linux/mutex.h>
-
-struct probe_desc;
-
-/**
- * @struct img_file
- * @breaf Image of file
- */
-struct img_file {
-       /* img_proc */
-       struct list_head list;          /**< List for img_proc */
-
-       /* img_ip */
-       struct {
-               struct mutex mtx;
-               struct list_head head;  /**< Head for img_ip */
-       } ips;
-
-       struct dentry *dentry;          /**< Dentry of file */
-       atomic_t use;
-};
-
-struct img_file *img_file_create(struct dentry *dentry);
-void img_file_get(struct img_file *file);
-void img_file_put(struct img_file *file);
-
-struct img_ip *img_file_add_ip(struct img_file *file, unsigned long addr,
-                              struct probe_desc *pd);
-void img_file_del_ip(struct img_file *file, struct img_ip *ip);
-
-int img_file_empty(struct img_file *file);
-bool img_file_is_unloadable(void);
-
-/* debug */
-void img_file_print(struct img_file *file);
-/* debug */
-
-#endif /* _IMG_FILE_H */
-
diff --git a/us_manager/img/img_ip.c b/us_manager/img/img_ip.c
deleted file mode 100644 (file)
index da7f6e2..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/img/img_ip.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include "img_ip.h"
-#include "img_file.h"
-#include <us_manager/probes/use_probes.h>
-#include <us_manager/sspt/sspt.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <linux/slab.h>
-#include <linux/atomic.h>
-
-
-static atomic_t ip_counter = ATOMIC_INIT(0);
-
-/**
- * @brief Create img_ip struct
- *
- * @param addr Function address
- * @param probe_i Pointer to the probe info data.
- * @return Pointer to the created img_ip struct
- */
-struct img_ip *img_ip_create(unsigned long addr, struct probe_desc *pd,
-                            struct img_file *file)
-{
-       struct img_ip *ip;
-
-       ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-       if (!ip)
-               return ERR_PTR(-ENOMEM);
-       atomic_inc(&ip_counter);
-
-       INIT_LIST_HEAD(&ip->list);
-       kref_init(&ip->ref);
-       mutex_init(&ip->sspt.mtx);
-       INIT_LIST_HEAD(&ip->sspt.head);
-       ip->addr = addr;
-       ip->desc = pd;
-       ip->file = file;
-
-       return ip;
-}
-
-static void img_ip_release(struct kref *ref)
-{
-       struct img_ip *ip = container_of(ref, struct img_ip, ref);
-
-       WARN_ON(!list_empty(&ip->sspt.head));
-
-       atomic_dec(&ip_counter);
-       kfree(ip);
-}
-
-void img_ip_clean(struct img_ip *ip)
-{
-       struct sspt_ip *p;
-
-       img_ip_lock(ip);
-       while(!list_empty(&ip->sspt.head)) {
-               p = list_first_entry(&ip->sspt.head, struct sspt_ip ,img_list);
-               sspt_ip_get(p);
-               img_ip_unlock(ip);
-
-               if (sspt_page_is_installed_ip(p->page, p))
-                       sspt_unregister_usprobe(NULL, p, US_UNREGS_PROBE);
-
-               sspt_ip_clean(p);
-
-               img_ip_lock(ip);
-               sspt_ip_put(p);
-       }
-       img_ip_unlock(ip);
-}
-
-void img_ip_get(struct img_ip *ip)
-{
-       kref_get(&ip->ref);
-}
-
-void img_ip_put(struct img_ip *ip)
-{
-       kref_put(&ip->ref, img_ip_release);
-}
-
-void img_ip_add_ip(struct img_ip *ip, struct sspt_ip *sspt_ip)
-{
-       sspt_ip->img_ip = ip;
-       list_add(&sspt_ip->img_list, &ip->sspt.head);
-}
-
-void img_ip_lock(struct img_ip *ip)
-{
-       mutex_lock(&ip->sspt.mtx);
-}
-
-void img_ip_unlock(struct img_ip *ip)
-{
-       mutex_unlock(&ip->sspt.mtx);
-}
-
-bool img_ip_is_unloadable(void)
-{
-       return !atomic_read(&ip_counter);
-}
-
-/**
- * @brief For debug
- *
- * @param ip Pointer to the img_ip struct
- * @return Void
- */
-
-/* debug */
-void img_ip_print(struct img_ip *ip)
-{
-       if (ip->desc->type == SWAP_RETPROBE)
-               printk(KERN_INFO "###            addr=8%lx, args=%s\n",
-                      ip->addr, ip->desc->info.rp_i.args);
-}
-/* debug */
diff --git a/us_manager/img/img_ip.h b/us_manager/img/img_ip.h
deleted file mode 100644 (file)
index b68c943..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @file us_manager/img/img_ip.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- */
-
-
-#ifndef _IMG_IP_H
-#define _IMG_IP_H
-
-#include <linux/types.h>
-#include <linux/kref.h>
-#include <linux/mutex.h>
-
-
-struct sspt_ip;
-struct img_file;
-struct probe_desc;
-
-/**
- * @struct img_ip
- * @breaf Image of instrumentation pointer
- */
-struct img_ip {
-       /* img_file */
-       struct list_head list;          /**< List for img_file */
-       struct img_file *file;          /**< Pointer on the file (parent) */
-
-       struct kref ref;
-
-       /* sspt_ip */
-       struct {
-               struct mutex mtx;
-               struct list_head head;
-       } sspt;
-
-       unsigned long addr;             /**< Function address */
-       struct probe_desc *desc;        /**< Probe info */
-};
-
-struct img_ip *img_ip_create(unsigned long addr, struct probe_desc *info,
-                            struct img_file *file);
-void img_ip_clean(struct img_ip *ip);
-void img_ip_get(struct img_ip *ip);
-void img_ip_put(struct img_ip *ip);
-
-void img_ip_add_ip(struct img_ip *ip, struct sspt_ip *sspt_ip);
-void img_ip_lock(struct img_ip *ip);
-void img_ip_unlock(struct img_ip *ip);
-
-bool img_ip_is_unloadable(void);
-
-/* debug */
-void img_ip_print(struct img_ip *ip);
-/* debug */
-
-#endif /* _IMG_IP_H */
diff --git a/us_manager/img/img_proc.c b/us_manager/img/img_proc.c
deleted file mode 100644 (file)
index 40f6470..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/img/img_proc.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/atomic.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_file.h>
-#include "img_ip.h"
-#include "img_proc.h"
-#include "img_file.h"
-
-
-struct img_proc {
-       /* img_file */
-       struct {
-               struct list_head head;
-               struct mutex mtx;
-       } files;
-};
-
-
-static atomic_t proc_counter = ATOMIC_INIT(0);
-
-static void img_del_file_by_list(struct img_file *file);
-
-/**
- * @brief Create img_proc struct
- *
- * @return Pointer to the created img_proc struct
- */
-struct img_proc *img_proc_create(void)
-{
-       struct img_proc *proc;
-
-       proc = kmalloc(sizeof(*proc), GFP_ATOMIC);
-       if (proc) {
-               atomic_inc(&proc_counter);
-               INIT_LIST_HEAD(&proc->files.head);
-               mutex_init(&proc->files.mtx);
-       }
-
-       return proc;
-}
-
-/**
- * @brief Remove img_proc struct
- *
- * @param file remove object
- * @return Void
- */
-void img_proc_free(struct img_proc *proc)
-{
-       struct img_file *file, *tmp;
-
-       mutex_lock(&proc->files.mtx);
-       list_for_each_entry_safe(file, tmp, &proc->files.head, list) {
-               img_del_file_by_list(file);
-               img_file_put(file);
-       }
-       mutex_unlock(&proc->files.mtx);
-
-       atomic_dec(&proc_counter);
-       kfree(proc);
-}
-
-/* called with mutex_[lock/unlock](&proc->files.mtx) */
-static void img_add_file_by_list(struct img_proc *proc, struct img_file *file)
-{
-       list_add(&file->list, &proc->files.head);
-}
-
-/* called with mutex_[lock/unlock](&proc->files.mtx) */
-static void img_del_file_by_list(struct img_file *file)
-{
-       list_del(&file->list);
-}
-
-/* called with mutex_[lock/unlock](&proc->files.mtx) */
-static struct img_file *img_file_find(struct img_proc *proc,
-                                     struct dentry *dentry)
-{
-       struct img_file *file;
-
-       list_for_each_entry(file, &proc->files.head, list) {
-               if (file->dentry == dentry)
-                       return file;
-       }
-
-       return NULL;
-}
-
-/**
- * @brief Add instrumentation pointer
- *
- * @param proc Pointer to the img_proc struct
- * @param dentry Dentry of file
- * @param addr Function address
- * @param probe_i Pointer to a probe_info struct related with the probe
- * @return Error code
- */
-struct img_ip *img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
-                              unsigned long addr, struct probe_desc *pd)
-{
-       struct img_file *file;
-
-       mutex_lock(&proc->files.mtx);
-       file = img_file_find(proc, dentry);
-       if (!file) {
-               file = img_file_create(dentry);
-               if (IS_ERR(file)) {
-                       mutex_unlock(&proc->files.mtx);
-
-                       /* handle type cast */
-                       return ERR_PTR(PTR_ERR(file));
-               }
-
-               img_add_file_by_list(proc, file);
-       }
-       mutex_unlock(&proc->files.mtx);
-
-       return img_file_add_ip(file, addr, pd);
-}
-
-/**
- * @brief Remove instrumentation pointer
- *
- * @param proc Pointer to the img_proc struct
- * @param dentry Dentry of file
- * @param args Function address
- * @return Error code
- */
-void img_proc_del_ip(struct img_proc *proc, struct img_ip *ip)
-{
-       struct img_file *file = ip->file;
-
-       mutex_lock(&proc->files.mtx);
-       img_file_del_ip(file, ip);
-       if (img_file_empty(file)) {
-               img_del_file_by_list(file);
-               img_file_put(file);
-       }
-       mutex_unlock(&proc->files.mtx);
-}
-
-void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc)
-{
-       struct sspt_file *file;
-       struct img_file *i_file;
-
-       mutex_lock(&i_proc->files.mtx);
-       list_for_each_entry(i_file, &i_proc->files.head, list) {
-               file = sspt_proc_find_file_or_new(proc, i_file->dentry);
-               if (file) {
-                       struct img_ip *i_ip;
-
-                       mutex_lock(&i_file->ips.mtx);
-                       list_for_each_entry(i_ip, &i_file->ips.head, list)
-                               sspt_file_add_ip(file, i_ip);
-                       mutex_unlock(&i_file->ips.mtx);
-               }
-       }
-       mutex_unlock(&i_proc->files.mtx);
-}
-
-bool img_proc_is_unloadable(void)
-{
-       return !(atomic_read(&proc_counter) + !img_file_is_unloadable());
-}
-
-/**
- * @brief For debug
- *
- * @param proc Pointer to the img_proc struct
- * @return Void
- */
-
-/* debug */
-void img_proc_print(struct img_proc *proc)
-{
-       struct img_file *file;
-
-       printk(KERN_INFO "### img_proc_print:\n");
-
-       mutex_lock(&proc->files.mtx);
-       list_for_each_entry(file, &proc->files.head, list) {
-               img_file_print(file);
-       }
-       mutex_unlock(&proc->files.mtx);
-}
-/* debug */
diff --git a/us_manager/img/img_proc.h b/us_manager/img/img_proc.h
deleted file mode 100644 (file)
index c9f0fc3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file us_manager/img/img_proc.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENCE
- * 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
- */
-
-
-#ifndef _IMG_PROC_H
-#define _IMG_PROC_H
-
-#include <linux/types.h>
-
-struct dentry;
-struct sspt_proc;
-struct probe_desc;
-
-
-struct img_proc *img_proc_create(void);
-void img_proc_free(struct img_proc *proc);
-
-struct img_ip *img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
-                              unsigned long addr, struct probe_desc *pd);
-void img_proc_del_ip(struct img_proc *proc, struct img_ip *ip);
-
-void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc);
-bool img_proc_is_unloadable(void);
-
-/* debug */
-void img_proc_print(struct img_proc *proc);
-/* debug */
-
-#endif /* _IMG_PROC_H */
diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c
deleted file mode 100644 (file)
index 6dfcf94..0000000
+++ /dev/null
@@ -1,875 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/pf/pf_group.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/namei.h>
-#include <linux/mman.h>
-#include <linux/atomic.h>
-#include <linux/spinlock.h>
-#include "pf_group.h"
-#include "proc_filters.h"
-#include "../sspt/sspt_filter.h"
-#include "../us_manager_common.h"
-#include <us_manager/img/img_proc.h>
-#include <us_manager/img/img_file.h>
-#include <us_manager/img/img_ip.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/helper.h>
-#include <us_manager/us_common_file.h>
-#include <task_ctx/task_ctx.h>
-
-
-struct pf_group {
-       struct list_head list;
-       struct img_proc *i_proc;
-       struct proc_filter filter;
-       struct pfg_msg_cb *msg_cb;
-       atomic_t usage;
-
-       spinlock_t pl_lock;     /* for proc_list */
-       struct list_head proc_list;
-};
-
-struct pl_struct {
-       struct list_head list;
-       struct sspt_proc *proc;
-};
-
-
-static atomic_t pfg_counter = ATOMIC_INIT(0);
-
-static LIST_HEAD(pfg_list);
-static DECLARE_RWSEM(pfg_list_sem);
-static DECLARE_RWSEM(uninstall_sem);
-
-static void pfg_list_rlock(void)
-{
-       down_read(&pfg_list_sem);
-}
-
-static void pfg_list_runlock(void)
-{
-       up_read(&pfg_list_sem);
-}
-
-static void pfg_list_wlock(void)
-{
-       down_write(&pfg_list_sem);
-}
-
-static void pfg_list_wunlock(void)
-{
-       up_write(&pfg_list_sem);
-}
-
-
-/* struct pl_struct */
-static struct pl_struct *create_pl_struct(struct sspt_proc *proc)
-{
-       struct pl_struct *pls = kmalloc(sizeof(*pls), GFP_ATOMIC);
-
-       if (pls) {
-               INIT_LIST_HEAD(&pls->list);
-               pls->proc = sspt_proc_get(proc);
-       }
-
-       return pls;
-}
-
-static void free_pl_struct(struct pl_struct *pls)
-{
-       sspt_proc_put(pls->proc);
-       kfree(pls);
-}
-/* struct pl_struct */
-
-static struct pf_group *pfg_create(void)
-{
-       struct pf_group *pfg = kmalloc(sizeof(*pfg), GFP_ATOMIC);
-
-       if (pfg == NULL)
-               return NULL;
-
-       pfg->i_proc = img_proc_create();
-       if (pfg->i_proc == NULL)
-               goto create_pfg_fail;
-
-       INIT_LIST_HEAD(&pfg->list);
-       memset(&pfg->filter, 0, sizeof(pfg->filter));
-       spin_lock_init(&pfg->pl_lock);
-       INIT_LIST_HEAD(&pfg->proc_list);
-       pfg->msg_cb = NULL;
-       atomic_set(&pfg->usage, 1);
-
-       atomic_inc(&pfg_counter);
-       return pfg;
-
-create_pfg_fail:
-
-       kfree(pfg);
-
-       return NULL;
-}
-
-static void pfg_free(struct pf_group *pfg)
-{
-       struct pl_struct *pl, *n;
-
-       img_proc_free(pfg->i_proc);
-       free_pf(&pfg->filter);
-       list_for_each_entry_safe(pl, n, &pfg->proc_list, list) {
-               sspt_proc_del_filter(pl->proc, pfg);
-               free_pl_struct(pl);
-       }
-
-       atomic_dec(&pfg_counter);
-       kfree(pfg);
-}
-
-bool pfg_is_unloadable(void)
-{
-       return !(atomic_read(&pfg_counter) + !img_proc_is_unloadable());
-}
-
-static int pfg_add_proc(struct pf_group *pfg, struct sspt_proc *proc)
-{
-       struct pl_struct *pls;
-
-       pls = create_pl_struct(proc);
-       if (pls == NULL)
-               return -ENOMEM;
-
-       spin_lock(&pfg->pl_lock);
-       list_add(&pls->list, &pfg->proc_list);
-       spin_unlock(&pfg->pl_lock);
-
-       return 0;
-}
-
-static int pfg_del_proc(struct pf_group *pfg, struct sspt_proc *proc)
-{
-       struct pl_struct *pls, *pls_free = NULL;
-
-       spin_lock(&pfg->pl_lock);
-       list_for_each_entry(pls, &pfg->proc_list, list) {
-               if (pls->proc == proc) {
-                       list_del(&pls->list);
-                       pls_free = pls;
-                       break;
-               }
-       }
-       spin_unlock(&pfg->pl_lock);
-
-       if (pls_free)
-               free_pl_struct(pls_free);
-
-       return !!pls_free;
-}
-
-
-/* called with pfg_list_lock held */
-static void pfg_add_to_list(struct pf_group *pfg)
-{
-       list_add(&pfg->list, &pfg_list);
-}
-
-/* called with pfg_list_lock held */
-static void pfg_del_from_list(struct pf_group *pfg)
-{
-       list_del(&pfg->list);
-}
-
-
-static void msg_info(struct sspt_filter *f, void *data)
-{
-       if (f->pfg_is_inst == false) {
-               struct pfg_msg_cb *cb;
-
-               f->pfg_is_inst = true;
-
-               cb = pfg_msg_cb_get(f->pfg);
-               if (cb) {
-                       struct dentry *dentry;
-
-                       dentry = (struct dentry *)f->pfg->filter.priv;
-
-                       if (cb->msg_info)
-                               cb->msg_info(f->proc->leader, dentry);
-
-                       if (cb->msg_status_info)
-                               cb->msg_status_info(f->proc->leader);
-               }
-       }
-}
-
-static void first_install(struct task_struct *task, struct sspt_proc *proc)
-{
-       down_write(&task->mm->mmap_sem);
-       sspt_proc_on_each_filter(proc, msg_info, NULL);
-       sspt_proc_install(proc);
-       up_write(&task->mm->mmap_sem);
-}
-
-static void subsequent_install(struct task_struct *task,
-                              struct sspt_proc *proc, unsigned long page_addr)
-{
-       down_write(&task->mm->mmap_sem);
-       sspt_proc_install_page(proc, page_addr);
-       up_write(&task->mm->mmap_sem);
-}
-
-
-/**
- * @brief Get dentry struct by path
- *
- * @param path Path to file
- * @return Pointer on dentry struct on NULL
- */
-struct dentry *dentry_by_path(const char *path)
-{
-       struct dentry *d;
-
-       d = swap_get_dentry(path);
-       if (d)
-               dput(d);
-
-       return d;
-}
-EXPORT_SYMBOL_GPL(dentry_by_path);
-
-
-int pfg_msg_cb_set(struct pf_group *pfg, struct pfg_msg_cb *msg_cb)
-{
-       if (pfg->msg_cb)
-               return -EBUSY;
-
-       pfg->msg_cb = msg_cb;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pfg_msg_cb_set);
-
-void pfg_msg_cb_reset(struct pf_group *pfg)
-{
-       pfg->msg_cb = NULL;
-}
-EXPORT_SYMBOL_GPL(pfg_msg_cb_reset);
-
-struct pfg_msg_cb *pfg_msg_cb_get(struct pf_group *pfg)
-{
-       return pfg->msg_cb;
-}
-
-/**
- * @brief Get pf_group struct by dentry
- *
- * @param dentry Dentry of file
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv)
-{
-       struct pf_group *pfg;
-
-       pfg_list_wlock();
-       list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_by_dentry(&pfg->filter, dentry)) {
-                       atomic_inc(&pfg->usage);
-                       goto unlock;
-               }
-       }
-
-       pfg = pfg_create();
-       if (pfg == NULL)
-               goto unlock;
-
-       set_pf_by_dentry(&pfg->filter, dentry, priv);
-
-       pfg_add_to_list(pfg);
-
-unlock:
-       pfg_list_wunlock();
-       return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_by_dentry);
-
-/**
- * @brief Get pf_group struct by TGID
- *
- * @param tgid Thread group ID
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv)
-{
-       struct pf_group *pfg;
-
-       pfg_list_wlock();
-       list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_by_tgid(&pfg->filter, tgid)) {
-                       atomic_inc(&pfg->usage);
-                       goto unlock;
-               }
-       }
-
-       pfg = pfg_create();
-       if (pfg == NULL)
-               goto unlock;
-
-       set_pf_by_tgid(&pfg->filter, tgid, priv);
-
-       pfg_add_to_list(pfg);
-
-unlock:
-       pfg_list_wunlock();
-       return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_by_tgid);
-
-/**
- * @brief Get pf_group struct by comm
- *
- * @param comm Task comm
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_by_comm(char *comm, void *priv)
-{
-       int ret;
-       struct pf_group *pfg;
-
-       pfg_list_wlock();
-       list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_by_comm(&pfg->filter, comm)) {
-                       atomic_inc(&pfg->usage);
-                       goto unlock;
-               }
-       }
-
-       pfg = pfg_create();
-       if (pfg == NULL)
-               goto unlock;
-
-       ret = set_pf_by_comm(&pfg->filter, comm, priv);
-       if (ret) {
-               printk(KERN_ERR "ERROR: set_pf_by_comm, ret=%d\n", ret);
-               pfg_free(pfg);
-               pfg = NULL;
-               goto unlock;
-       }
-
-       pfg_add_to_list(pfg);
-unlock:
-       pfg_list_wunlock();
-       return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_by_comm);
-
-/**
- * @brief Get pf_group struct for each process
- *
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_dumb(void *priv)
-{
-       struct pf_group *pfg;
-
-       pfg_list_wlock();
-       list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_pf_dumb(&pfg->filter)) {
-                       atomic_inc(&pfg->usage);
-                       goto unlock;
-               }
-       }
-
-       pfg = pfg_create();
-       if (pfg == NULL)
-               goto unlock;
-
-       set_pf_dumb(&pfg->filter, priv);
-
-       pfg_add_to_list(pfg);
-
-unlock:
-       pfg_list_wunlock();
-       return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_dumb);
-
-/**
- * @brief Put pf_group struct
- *
- * @param pfg Pointer to the pf_group struct
- * @return Void
- */
-void put_pf_group(struct pf_group *pfg)
-{
-       if (atomic_dec_and_test(&pfg->usage)) {
-               pfg_list_wlock();
-               pfg_del_from_list(pfg);
-               pfg_list_wunlock();
-
-               pfg_free(pfg);
-       }
-}
-EXPORT_SYMBOL_GPL(put_pf_group);
-
-/**
- * @brief Register prober for pf_grpup struct
- *
- * @param pfg Pointer to the pf_group struct
- * @param dentry Dentry of file
- * @param offset Function offset
- * @param probe_info Pointer to the related probe_info struct
- * @return pointer to the img_ip struct or error
- */
-struct img_ip *pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
-                                unsigned long offset, struct probe_desc *pd)
-{
-       return img_proc_add_ip(pfg->i_proc, dentry, offset, pd);
-}
-EXPORT_SYMBOL_GPL(pf_register_probe);
-
-/**
- * @brief Unregister prober from pf_grpup struct
- *
- * @param pfg Pointer to the pf_group struct
- * @param ip Pointer to the img_ip struct
- * @return Void
- */
-void pf_unregister_probe(struct pf_group *pfg, struct img_ip *ip)
-{
-       WARN(IS_ERR_OR_NULL(ip), "invalid img_ip");
-       img_proc_del_ip(pfg->i_proc, ip);
-}
-EXPORT_SYMBOL_GPL(pf_unregister_probe);
-
-static int check_task_on_filters(struct task_struct *task)
-{
-       int ret = 0;
-       struct pf_group *pfg;
-
-       pfg_list_rlock();
-       list_for_each_entry(pfg, &pfg_list, list) {
-               if (check_task_f(&pfg->filter, task)) {
-                       ret = 1;
-                       goto unlock;
-               }
-       }
-
-unlock:
-       pfg_list_runlock();
-       return ret;
-}
-
-enum pf_inst_flag {
-       PIF_NONE,
-       PIF_FIRST,
-       PIF_SECOND,
-       PIF_ADD_PFG
-};
-
-static enum pf_inst_flag pfg_check_task(struct task_struct *task)
-{
-       struct pf_group *pfg;
-       struct sspt_proc *proc = NULL;
-       enum pf_inst_flag flag = PIF_NONE;
-
-       pfg_list_rlock();
-       list_for_each_entry(pfg, &pfg_list, list) {
-               bool put_flag = false;
-
-               if (check_task_f(&pfg->filter, task) == NULL)
-                       continue;
-
-               if (proc == NULL) {
-                       proc = sspt_proc_get_by_task(task);
-                       put_flag = !!proc;
-               }
-
-               if (proc) {
-                       flag = flag == PIF_NONE ? PIF_SECOND : flag;
-               } else if (task->tgid == task->pid) {
-                       proc = sspt_proc_get_by_task_or_new(task);
-                       if (proc == NULL) {
-                               printk(KERN_ERR "cannot create sspt_proc\n");
-                               break;
-                       }
-                       put_flag = true;
-                       flag = PIF_FIRST;
-               }
-
-               if (proc) {
-                       mutex_lock(&proc->filters.mtx);
-                               if (sspt_proc_is_filter_new(proc, pfg)) {
-                                       img_proc_copy_to_sspt(pfg->i_proc, proc);
-                                       sspt_proc_add_filter(proc, pfg);
-                                       pfg_add_proc(pfg, proc);
-                                       flag = flag == PIF_FIRST ? flag : PIF_ADD_PFG;
-                       }
-                       mutex_unlock(&proc->filters.mtx);
-                       if (put_flag)
-                               sspt_proc_put(proc);
-               }
-       }
-       pfg_list_runlock();
-
-       return flag;
-}
-
-static void pfg_all_del_proc(struct sspt_proc *proc)
-{
-       struct pf_group *pfg;
-
-       pfg_list_rlock();
-       list_for_each_entry(pfg, &pfg_list, list)
-               pfg_del_proc(pfg, proc);
-       pfg_list_runlock();
-}
-
-/**
- * @brief Check task and install probes on demand
- *
- * @prarm task Pointer on the task_struct struct
- * @return Void
- */
-void check_task_and_install(struct task_struct *task)
-{
-       struct sspt_proc *proc;
-       enum pf_inst_flag flag;
-
-       flag = pfg_check_task(task);
-       switch (flag) {
-       case PIF_FIRST:
-               proc = sspt_proc_get_by_task(task);
-               if (proc) {
-                       sspt_proc_priv_create(proc);
-                       first_install(task, proc);
-                       sspt_proc_put(proc);
-               }
-               break;
-       case PIF_ADD_PFG:
-               proc = sspt_proc_get_by_task(task);
-               if (proc) {
-                       first_install(task, proc);
-                       sspt_proc_put(proc);
-               }
-               break;
-
-       case PIF_NONE:
-       case PIF_SECOND:
-               break;
-       }
-}
-
-/**
- * @brief Check task and install probes on demand
- *
- * @prarm task Pointer on the task_struct struct
- * @param page_addr Page fault address
- * @return Void
- */
-void call_page_fault(struct task_struct *task, unsigned long page_addr)
-{
-       struct sspt_proc *proc;
-       enum pf_inst_flag flag;
-
-       flag = pfg_check_task(task);
-       switch (flag) {
-       case PIF_FIRST:
-               proc = sspt_proc_get_by_task(task);
-               if (proc) {
-                       sspt_proc_priv_create(proc);
-                       first_install(task, proc);
-                       sspt_proc_put(proc);
-               }
-               break;
-       case PIF_ADD_PFG:
-               proc = sspt_proc_get_by_task(task);
-               if (proc) {
-                       first_install(task, proc);
-                       sspt_proc_put(proc);
-               }
-               break;
-
-       case PIF_SECOND:
-               proc = sspt_proc_get_by_task(task);
-               if (proc) {
-                       subsequent_install(task, proc, page_addr);
-                       sspt_proc_put(proc);
-               }
-               break;
-
-       case PIF_NONE:
-               break;
-       }
-}
-
-/**
- * @brief Uninstall probes from the sspt_proc struct
- *
- * @prarm proc Pointer on the sspt_proc struct
- * @return Void
- */
-
-/* called with sspt_proc_write_lock() */
-void uninstall_proc(struct sspt_proc *proc)
-{
-       struct task_struct *task = proc->leader;
-
-       sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
-       sspt_proc_cleanup(proc);
-}
-
-
-static void mmr_from_exit(struct sspt_proc *proc)
-{
-       BUG_ON(proc->leader != current);
-
-       sspt_proc_write_lock();
-       list_del(&proc->list);
-       sspt_proc_write_unlock();
-
-       uninstall_proc(proc);
-
-       pfg_all_del_proc(proc);
-}
-
-static void mmr_from_exec(struct sspt_proc *proc)
-{
-       BUG_ON(proc->leader != current);
-
-       if (proc->suspect.after_exec) {
-               sspt_proc_uninstall(proc, proc->leader, US_UNREGS_PROBE);
-       } else {
-               mmr_from_exit(proc);
-       }
-}
-
-/**
- * @brief Remove probes from the task on demand
- *
- * @prarm task Pointer on the task_struct struct
- * @return Void
- */
-void call_mm_release(struct task_struct *task)
-{
-       struct sspt_proc *proc;
-
-       down_read(&uninstall_sem);
-       proc = sspt_proc_get_by_task(task);
-       if (proc) {
-               if (task->flags & PF_EXITING)
-                       mmr_from_exit(proc);
-               else
-                       mmr_from_exec(proc);
-               sspt_proc_put(proc);
-       }
-       up_read(&uninstall_sem);
-}
-
-/**
- * @brief Legacy code, it is need remove
- *
- * @param addr Page address
- * @return Void
- */
-void uninstall_page(unsigned long addr)
-{
-
-}
-
-
-static void install_cb(void *unused)
-{
-       check_task_and_install(current);
-}
-
-
-
-
-struct task_item {
-       struct list_head list;
-       struct task_struct *task;
-};
-
-static void tasks_get(struct list_head *head)
-{
-       struct task_item *item;
-       struct task_struct *task;
-
-       rcu_read_lock();
-       for_each_process(task) {
-               if (task->flags & PF_KTHREAD)
-                       continue;
-
-               if (sspt_proc_by_task(task))
-                       continue;
-
-               /* TODO: get rid of GFP_ATOMIC */
-               item = kmalloc(sizeof(*item), GFP_ATOMIC);
-               if (item == NULL) {
-                       WARN(1, "out of memory\n");
-                       goto unlock;
-               }
-
-               get_task_struct(task);
-               item->task = task;
-               list_add(&item->list, head);
-       }
-
-unlock:
-       rcu_read_unlock();
-}
-
-static void tasks_install_and_put(struct list_head *head)
-{
-       struct task_item *item, *n;
-
-       list_for_each_entry_safe(item, n, head, list) {
-               int ret;
-               struct task_struct *task;
-
-               task = item->task;
-               if (!check_task_on_filters(task))
-                       goto put_task;
-
-               ret = taskctx_run(task, install_cb, NULL);
-               if (ret) {
-                       pr_err("cannot tracking task[%u %u %s] ret=%d\n",
-                              task->tgid, task->pid, task->comm, ret);
-               }
-
-put_task:
-               put_task_struct(task);
-               list_del(&item->list);
-               kfree(item);
-       }
-}
-
-static void do_install_all(void)
-{
-       LIST_HEAD(head);
-
-       tasks_get(&head);
-       tasks_install_and_put(&head);
-}
-
-/**
- * @brief Install probes on running processes
- *
- * @return Void
- */
-void install_all(void)
-{
-       int ret;
-
-       ret = taskctx_get();
-       if (!ret) {
-               do_install_all();
-               taskctx_put();
-       } else {
-               pr_err("taskctx_get ret=%d\n", ret);
-       }
-}
-
-/**
- * @brief Uninstall probes from all processes
- *
- * @return Void
- */
-void uninstall_all(void)
-{
-       struct list_head *proc_list = sspt_proc_list();
-
-       down_write(&uninstall_sem);
-       sspt_proc_write_lock();
-       while (!list_empty(proc_list)) {
-               struct sspt_proc *proc;
-               proc = list_first_entry(proc_list, struct sspt_proc, list);
-
-               list_del(&proc->list);
-
-               sspt_proc_write_unlock();
-               uninstall_proc(proc);
-               sspt_proc_write_lock();
-       }
-       sspt_proc_write_unlock();
-       up_write(&uninstall_sem);
-}
-
-static void __do_get_proc(struct sspt_proc *proc, void *data)
-{
-       struct task_struct *task = proc->leader;
-
-       get_task_struct(task);
-       proc->__task = task;
-       proc->__mm = get_task_mm(task);
-}
-
-static void __do_put_proc(struct sspt_proc *proc, void *data)
-{
-       if (proc->__mm) {
-               mmput(proc->__mm);
-               proc->__mm = NULL;
-       }
-
-       if (proc->__task) {
-               put_task_struct(proc->__task);
-               proc->__task = NULL;
-       }
-}
-
-void get_all_procs(void)
-{
-       sspt_proc_read_lock();
-       on_each_proc_no_lock(__do_get_proc, NULL);
-       sspt_proc_read_unlock();
-}
-
-void put_all_procs(void)
-{
-       sspt_proc_read_lock();
-       on_each_proc_no_lock(__do_put_proc, NULL);
-       sspt_proc_read_unlock();
-}
-
-/**
- * @brief For debug
- *
- * @param pfg Pointer to the pf_group struct
- * @return Void
- */
-
-/* debug */
-void pfg_print(struct pf_group *pfg)
-{
-       img_proc_print(pfg->i_proc);
-}
-EXPORT_SYMBOL_GPL(pfg_print);
-/* debug */
diff --git a/us_manager/pf/pf_group.h b/us_manager/pf/pf_group.h
deleted file mode 100644 (file)
index a9f74f7..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file us_manager/pf/pf_group.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-
-#ifndef _PF_GROUP_H
-#define _PF_GROUP_H
-
-#include <linux/types.h>
-
-struct img_ip;
-struct dentry;
-struct pf_group;
-struct sspt_proc;
-struct probe_desc;
-
-
-struct pfg_msg_cb {
-       void (*msg_info)(struct task_struct *task, struct dentry *dentry);
-       void (*msg_status_info)(struct task_struct *task);
-       void (*msg_term)(struct task_struct *task);
-       void (*msg_map)(struct vm_area_struct *vma);
-       void (*msg_unmap)(unsigned long start, unsigned long end);
-};
-
-
-/* FIXME: use swap_get_dentry() and swap_put_dentry() */
-struct dentry *dentry_by_path(const char *path);
-
-struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv);
-struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv);
-struct pf_group *get_pf_group_by_comm(char *comm, void *priv);
-struct pf_group *get_pf_group_dumb(void *priv);
-void put_pf_group(struct pf_group *pfg);
-bool pfg_is_unloadable(void);
-
-int pfg_msg_cb_set(struct pf_group *pfg, struct pfg_msg_cb *msg_cb);
-void pfg_msg_cb_reset(struct pf_group *pfg);
-struct pfg_msg_cb *pfg_msg_cb_get(struct pf_group *pfg);
-
-struct img_ip *pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
-                            unsigned long offset, struct probe_desc *pd);
-void pf_unregister_probe(struct pf_group *pfg, struct img_ip *ip);
-
-void install_all(void);
-void uninstall_all(void);
-
-void get_all_procs(void);
-void put_all_procs(void);
-
-void call_page_fault(struct task_struct *task, unsigned long page_addr);
-void call_mm_release(struct task_struct *task);
-void check_task_and_install(struct task_struct *task);
-void uninstall_proc(struct sspt_proc *proc);
-
-void uninstall_page(unsigned long addr);
-
-/* debug */
-void pfg_print(struct pf_group *pfg);
-/* debug */
-
-#endif /* _PF_GROUP_H */
diff --git a/us_manager/pf/proc_filters.c b/us_manager/pf/proc_filters.c
deleted file mode 100644 (file)
index d3d5d98..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/pf/proc_filters.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mm_types.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include "proc_filters.h"
-#include <us_manager/sspt/sspt.h>
-
-
-#define VOIDP2PID(x)   ((pid_t)(unsigned long)(x))
-#define PID2VOIDP(x)   ((void *)(unsigned long)(x))
-
-static int check_dentry(struct task_struct *task, struct dentry *dentry)
-{
-       struct vm_area_struct *vma;
-       struct mm_struct *mm = task->mm;
-
-       if (mm == NULL)
-               return 0;
-
-       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if (check_vma(vma) && vma->vm_file->f_path.dentry == dentry)
-                       return 1;
-       }
-
-       return 0;
-}
-
-static struct task_struct *call_by_dentry(struct proc_filter *self,
-                                        struct task_struct *task)
-{
-       struct dentry *dentry = (struct dentry *)self->data;
-
-       if (!dentry || check_dentry(task, dentry))
-               return task;
-
-       return NULL;
-}
-
-static inline void free_by_dentry(struct proc_filter *self)
-{
-       return;
-}
-
-static struct task_struct *call_by_tgid(struct proc_filter *self,
-                                      struct task_struct *task)
-{
-       pid_t tgid = VOIDP2PID(self->data);
-
-       if (task->tgid == tgid)
-               return task;
-
-       return NULL;
-}
-
-static inline void free_by_tgid(struct proc_filter *self)
-{
-       return;
-}
-
-static struct task_struct *call_by_comm(struct proc_filter *self,
-                                      struct task_struct *task)
-{
-       struct task_struct *parent;
-       char *comm = (char *)self->data;
-       size_t len = strnlen(comm, TASK_COMM_LEN);
-
-       if (!strncmp(comm, task->group_leader->comm, len))
-               return task;
-
-       parent = task->parent;
-       if (parent && !strncmp(comm, parent->comm, len))
-               return task;
-
-       return NULL;
-}
-
-static inline void free_by_comm(struct proc_filter *self)
-{
-       kfree(self->data);
-}
-
-/* Dumb call. Each task is exactly what we are looking for :) */
-static struct task_struct *call_dumb(struct proc_filter *self,
-                                    struct task_struct *task)
-{
-       return task;
-}
-
-/**
- * @brief Filling pf_group struct by dentry
- *
- * @param pf Pointer to the proc_filter struct
- * @param dentry Dentry
- * @param priv Private data
- * @return Void
- */
-void set_pf_by_dentry(struct proc_filter *pf, struct dentry *dentry, void *priv)
-{
-       pf->call = &call_by_dentry;
-       pf->data = (void *)dentry;
-       pf->priv = priv;
-}
-
-/**
- * @brief Filling pf_group struct by TGID
- *
- * @param pf Pointer to the proc_filter struct
- * @param tgid Thread group ID
- * @param priv Private data
- * @return Void
- */
-void set_pf_by_tgid(struct proc_filter *pf, pid_t tgid, void *priv)
-{
-       pf->call = &call_by_tgid;
-       pf->data = PID2VOIDP(tgid);
-       pf->priv = priv;
-}
-
-/**
- * @brief Fill proc_filter struct for given comm
- *
- * @param pf Pointer to the proc_filter struct
- * @param comm Task comm
- * @param priv Private data
- * @return 0 on suceess, error code on error.
- */
-int set_pf_by_comm(struct proc_filter *pf, char *comm, void *priv)
-{
-       size_t len = strnlen(comm, TASK_COMM_LEN);
-       char *new_comm = kmalloc(len, GFP_KERNEL);
-
-       if (new_comm == NULL)
-               return -ENOMEM;
-
-       /* copy comm */
-       memcpy(new_comm, comm, len - 1);
-       new_comm[len - 1] = '\0';
-
-       pf->call = &call_by_comm;
-       pf->data = new_comm;
-       pf->priv = priv;
-
-       return 0;
-}
-
-/**
- * @brief Filling pf_group struct for each process
- *
- * @param pf Pointer to the proc_filter struct
- * @param priv Private data
- * @return Void
- */
-void set_pf_dumb(struct proc_filter *pf, void *priv)
-{
-       pf->call = &call_dumb;
-       pf->data = NULL;
-       pf->priv = priv;
-}
-
-/**
- * @brief Free proc_filter struct
- *
- * @param filter Pointer to the proc_filter struct
- * @return Void
- */
-void free_pf(struct proc_filter *filter)
-{
-       if (filter->call == &call_by_dentry)
-               free_by_dentry(filter);
-       else if (filter->call == &call_by_tgid)
-               free_by_tgid(filter);
-       else if (filter->call == &call_by_comm)
-               free_by_comm(filter);
-}
-
-/**
- * @brief Check pf_group struct by dentry
- *
- * @param filter Pointer to the proc_filter struct
- * @param dentry Dentry
- * @return
- *       - 0 - false
- *       - 1 - true
- */
-int check_pf_by_dentry(struct proc_filter *filter, struct dentry *dentry)
-{
-       return filter->data == (void *)dentry &&
-              filter->call == &call_by_dentry;
-}
-
-/**
- * @brief Check pf_group struct by TGID
- *
- * @param filter Pointer to the proc_filter struct
- * @param tgid Thread group ID
- * @return
- *       - 0 - false
- *       - 1 - true
- */
-int check_pf_by_tgid(struct proc_filter *filter, pid_t tgid)
-{
-       return filter->data == PID2VOIDP(tgid)
-           && filter->call == &call_by_tgid;
-}
-
-/**
- * @brief Check proc_filter struct by comm
- *
- * @param filter Pointer to the proc_filter struct
- * @param comm Task comm
- * @return
- *       - 0 - false
- *       - 1 - true
- */
-int check_pf_by_comm(struct proc_filter *filter, char *comm)
-{
-       return ((filter->call == &call_by_comm) && (filter->data != NULL) &&
-               (!strncmp(filter->data, comm, TASK_COMM_LEN - 1)));
-}
-
-/**
- * @brief Dumb check always true if filter is a dumb one
- *
- * @param filter Pointer to the proc_filter struct
- * @return
- *       - 0 - false
- *       - 1 - true
- */
-int check_pf_dumb(struct proc_filter *filter)
-{
-       return filter->call == &call_dumb;
-}
-
-/**
- * @brief Get priv from pf_group struct
- *
- * @param filter Pointer to the proc_filter struct
- * @return Pointer to the priv
- */
-void *get_pf_priv(struct proc_filter *filter)
-{
-       return filter->priv;
-}
-
-/* Check function for call_page_fault() and other frequently called
-filter-check functions. It is used to call event-oriented and long-term filters
-only on specified events, but not every time memory map is changed. When
-iteraiting over the filters list, call this function on each step passing here
-pointer on filter. If it returns 1 then the filter should not be called. */
-int ignore_pf(struct proc_filter *filter)
-{
-       return filter->call == &call_by_comm;
-}
diff --git a/us_manager/pf/proc_filters.h b/us_manager/pf/proc_filters.h
deleted file mode 100644 (file)
index fe96276..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @file us_manager/pf/proc_filters.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-
-#ifndef _PROC_FILTERS_H
-#define _PROC_FILTERS_H
-
-#include <linux/types.h>
-
-struct dentry;
-struct task_struct;
-
-/**
- * @struct proc_filter
- * @breaf Filter for process
- */
-struct proc_filter {
-       /** Callback for filtering */
-       struct task_struct *(*call)(struct proc_filter *self,
-                                   struct task_struct *task);
-       void *data;             /**< Data of callback */
-       void *priv;             /**< Private data */
-};
-
-/**
- * @def check_task_f @hideinitializer
- * Call filter on the task
- *
- * @param filter Pointer to the proc_filter struct
- * @param task Pointer to the task_struct struct
- */
-#define check_task_f(filter, task) ((filter)->call(filter, task))
-
-void set_pf_by_dentry(struct proc_filter *pf, struct dentry *dentry,
-                     void *priv);
-void set_pf_by_tgid(struct proc_filter *pf, pid_t tgid, void *priv);
-int set_pf_by_comm(struct proc_filter *pf, char *comm, void *priv);
-void set_pf_dumb(struct proc_filter *pf, void *priv);
-
-
-int check_pf_by_dentry(struct proc_filter *filter, struct dentry *dentry);
-int check_pf_by_tgid(struct proc_filter *filter, pid_t tgid);
-int check_pf_by_comm(struct proc_filter *filter, char *comm);
-int check_pf_dumb(struct proc_filter *filter);
-void *get_pf_priv(struct proc_filter *filter);
-
-void free_pf(struct proc_filter *filter);
-
-int ignore_pf(struct proc_filter *filter);
-
-#endif /* _PROC_FILTERS_H */
diff --git a/us_manager/probes/probe_info_new.c b/us_manager/probes/probe_info_new.c
deleted file mode 100644 (file)
index 303f332..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include "probes.h"
-#include "probe_info_new.h"
-#include "register_probes.h"
-
-
-/*
- * handlers
- */
-static int urp_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct uretprobe *rp = ri->rp;
-
-       if (rp) {
-               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
-               struct probe_desc *pd = NULL;
-
-               pd = ip->desc;
-               if (pd && pd->u.rp.entry_handler)
-                       return pd->u.rp.entry_handler(ri, regs);
-
-       }
-
-       return 0;
-}
-
-static int urp_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct uretprobe *rp = ri->rp;
-
-       if (rp) {
-               struct sspt_ip *ip = container_of(rp, struct sspt_ip, retprobe);
-               struct probe_desc *pd = NULL;
-
-               pd = ip->desc;
-               if (pd && pd->u.rp.ret_handler)
-                       return pd->u.rp.ret_handler(ri, regs);
-       }
-
-       return 0;
-}
-
-static int uprobe_handler(struct uprobe *p, struct pt_regs *regs)
-{
-       struct sspt_ip *ip = container_of(p, struct sspt_ip, uprobe);
-       struct probe_desc *pd = NULL;
-
-       pd = ip->desc;
-       if (pd && pd->u.p.handler)
-               return pd->u.p.handler(p, regs);
-
-       return 0;
-}
-
-/*
- * register/unregister interface
- */
-int pin_register(struct probe_new *probe, struct pf_group *pfg,
-                struct dentry *dentry)
-{
-       struct img_ip *ip;
-
-       ip = pf_register_probe(pfg, dentry, probe->offset, probe->desc);
-       if (IS_ERR(ip)) {
-               pr_err("%s: register probe failed\n", __func__);
-               return PTR_ERR(ip);
-       }
-
-       probe->priv = ip;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pin_register);
-
-void pin_unregister(struct probe_new *probe, struct pf_group *pfg)
-{
-       struct img_ip *ip = probe->priv;
-
-       pf_unregister_probe(pfg, ip);
-}
-EXPORT_SYMBOL_GPL(pin_unregister);
-
-
-
-
-
-/*
- * SWAP_NEW_UP
- */
-static int up_copy(struct probe_info *dst, const struct probe_info *src)
-{
-       return 0;
-}
-
-static void up_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *up_get_uprobe(struct sspt_ip *ip)
-{
-       return &ip->uprobe;
-}
-
-static int up_register_probe(struct sspt_ip *ip)
-{
-       return swap_register_uprobe(&ip->uprobe);
-}
-
-static void up_unregister_probe(struct sspt_ip *ip, int disarm)
-{
-       __swap_unregister_uprobe(&ip->uprobe, disarm);
-}
-
-static void up_init(struct sspt_ip *ip)
-{
-       ip->uprobe.pre_handler = uprobe_handler;
-}
-
-static void up_uninit(struct sspt_ip *ip)
-{
-}
-
-static struct probe_iface up_iface = {
-       .init = up_init,
-       .uninit = up_uninit,
-       .reg = up_register_probe,
-       .unreg = up_unregister_probe,
-       .get_uprobe = up_get_uprobe,
-       .copy = up_copy,
-       .cleanup = up_cleanup
-};
-
-
-
-
-
-/*
- * SWAP_NEW_URP
- */
-static int urp_copy(struct probe_info *dst, const struct probe_info *src)
-{
-       return 0;
-}
-
-static void urp_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *urp_get_uprobe(struct sspt_ip *ip)
-{
-       return &ip->retprobe.up;
-}
-
-static int urp_register_probe(struct sspt_ip *ip)
-{
-       return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void urp_unregister_probe(struct sspt_ip *ip, int disarm)
-{
-       __swap_unregister_uretprobe(&ip->retprobe, disarm);
-}
-
-static void urp_init(struct sspt_ip *ip)
-{
-       ip->retprobe.entry_handler = urp_entry_handler;
-       ip->retprobe.handler = urp_ret_handler;
-       ip->retprobe.maxactive = 0;
-       /* FIXME: make dynamic size field 'data_size' */
-#ifdef CONFIG_ARM64
-       /*
-        * Loader module use field uretprobe_instance.data for storing
-        * 'struct us_priv'. For ARM64 it requires much more space.
-        */
-       ip->retprobe.data_size = 512 - sizeof(struct uretprobe_instance);
-#else /* CONFIG_ARM64 */
-       ip->retprobe.data_size = 128;
-#endif /* CONFIG_ARM64 */
-}
-
-static void urp_uninit(struct sspt_ip *ip)
-{
-}
-
-static struct probe_iface urp_iface = {
-       .init = urp_init,
-       .uninit = urp_uninit,
-       .reg = urp_register_probe,
-       .unreg = urp_unregister_probe,
-       .get_uprobe = urp_get_uprobe,
-       .copy = urp_copy,
-       .cleanup = urp_cleanup
-};
-
-
-
-
-/*
- * init/exit()
- */
-int pin_init(void)
-{
-       int ret;
-
-       ret = swap_register_probe_type(SWAP_NEW_UP, &up_iface);
-       if (ret)
-               return ret;
-
-       ret = swap_register_probe_type(SWAP_NEW_URP, &urp_iface);
-       if (ret)
-               swap_unregister_probe_type(SWAP_NEW_UP);
-
-       return ret;
-}
-
-void pin_exit(void)
-{
-       swap_unregister_probe_type(SWAP_NEW_URP);
-       swap_unregister_probe_type(SWAP_NEW_UP);
-}
diff --git a/us_manager/probes/probe_info_new.h b/us_manager/probes/probe_info_new.h
deleted file mode 100644 (file)
index 6c43481..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef _PROBE_INFO_NEW_H
-#define _PROBE_INFO_NEW_H
-
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <uprobe/swap_uprobes.h>
-#include "probes.h"
-
-
-struct dentry;
-struct pf_group;
-
-
-struct probe_info_new {
-       enum probe_t type;
-       union {
-               struct {
-                       uprobe_pre_handler_t handler;
-               } p;
-
-               struct {
-                       uretprobe_handler_t entry_handler;
-                       uretprobe_handler_t ret_handler;
-                       /*
-                        * FIXME: make dynamic size,
-                        *        currently data_size = sizeof(void *)
-                        */
-                       size_t data_size;
-               } rp;
-       } u;
-
-       /* private */
-       struct probe_info info;
-};
-
-struct probe_new {
-       /* reg data */
-       unsigned long offset;
-       struct probe_desc *desc;
-
-       /* unreg data */
-       void *priv;
-};
-
-
-#define MAKE_UPROBE(_handler)                          \
-       {                                               \
-               .type = SWAP_NEW_UP,                    \
-               .u.p.handler = _handler                 \
-       }
-
-#define MAKE_URPROBE(_entry, _ret, _size)              \
-       {                                               \
-               .type = SWAP_NEW_URP,                   \
-               .u.rp.entry_handler = _entry,           \
-               .u.rp.ret_handler = _ret,               \
-               .u.rp.data_size = _size                 \
-       }
-
-struct probe_info_otg {
-       struct probe_info info;
-       struct probe_info_new *data;    /* field 'data[0]' in probe_info struct */
-};
-
-int pin_register(struct probe_new *probe, struct pf_group *pfg,
-                struct dentry *dentry);
-void pin_unregister(struct probe_new *probe, struct pf_group *pfg);
-
-
-int pin_init(void);
-void pin_exit(void);
-
-
-#endif /* _PROBE_INFO_NEW_H */
diff --git a/us_manager/probes/probes.c b/us_manager/probes/probes.c
deleted file mode 100644 (file)
index 37f59f1..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/probes/probes.c
- *
- * 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, 2014
- *
- * 2014         Alexander Aksenov: Probes interface implement
- *
- */
-
-#include "probes.h"
-#include "register_probes.h"
-#include "use_probes.h"
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-
-static struct probe_iface *probes_methods[SWAP_PROBE_MAX_VAL] = { NULL };
-
-/* 1 - correct probe type
-   0 - wrong probe type
-*/
-static inline int correct_probe_type(enum probe_t probe_type)
-{
-       if (probe_type >= SWAP_PROBE_MAX_VAL)
-               return 0;
-
-       return 1;
-}
-
-static inline int methods_exist(enum probe_t probe_type)
-{
-       if (!correct_probe_type(probe_type) ||
-           (probes_methods[probe_type] == NULL)) {
-               printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-/**
- * @brief Calls specified probe type init method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return Void.
- */
-void probe_info_init(enum probe_t type, struct sspt_ip *ip)
-{
-       if (!methods_exist(type)) {
-               return;
-       }
-
-       probes_methods[type]->init(ip);
-}
-
-/**
- * @brief Calls specified probe type uninit method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return Void.
- */
-void probe_info_uninit(enum probe_t type, struct sspt_ip *ip)
-{
-       if (!methods_exist(type)) {
-               return;
-       }
-
-       probes_methods[type]->uninit(ip);
-}
-
-/**
- * @brief Calls specified probe type register method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return -EINVAL on wrong probe type, method result otherwise.
- */
-int probe_info_register(enum probe_t type, struct sspt_ip *ip)
-{
-       if (!methods_exist(type)) {
-               return -EINVAL;
-       }
-
-       return probes_methods[type]->reg(ip);
-}
-
-/**
- * @brief Calls specified probe type unregister method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @param disarm Disarm flag.
- * @return Void.
- */
-void probe_info_unregister(enum probe_t type, struct sspt_ip *ip, int disarm)
-{
-       if (!methods_exist(type)) {
-               return;
-       }
-
-       probes_methods[type]->unreg(ip, disarm);
-}
-
-/**
- * @brief Calls specified probe type get underlying uprobe method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return Pointer to the uprobe struct, NULL on error.
- */
-struct uprobe *probe_info_get_uprobe(enum probe_t type, struct sspt_ip *ip)
-{
-       if (!methods_exist(type)) {
-               return NULL;
-       }
-
-       return probes_methods[type]->get_uprobe(ip);
-}
-
-/**
- * @brief Registers probe type.
- *
- * @param probe_type Number, associated with this probe type.
- * @param pi Pointer to the probe interface structure
- * @return 0 on succes, error code on error.
- */
-int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi)
-{
-       if (!correct_probe_type(probe_type)) {
-               printk(KERN_ERR "SWAP US_MANAGER: incorrect probe type!\n");
-               return -EINVAL;
-       }
-
-       if (probes_methods[probe_type] != NULL)
-               printk(KERN_WARNING "SWAP US_MANAGER: Re-registering probe %d\n",
-                  probe_type);
-
-       probes_methods[probe_type] = pi;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_register_probe_type);
-
-/**
- * @brief Unregisters probe type.
- *
- * @param probe_type Probe type that should be unregistered.
- * @return Void.
- */
-void swap_unregister_probe_type(enum probe_t probe_type)
-{
-       if (!correct_probe_type(probe_type)) {
-               printk(KERN_ERR "SWAP US_MANAGER: incorrect probe type!\n");
-               return;
-       }
-
-       probes_methods[probe_type] = NULL;
-}
-EXPORT_SYMBOL_GPL(swap_unregister_probe_type);
diff --git a/us_manager/probes/probes.h b/us_manager/probes/probes.h
deleted file mode 100644 (file)
index 8683006..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/probes/probes.h
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @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, 2014
- *
- * 2014 Alexander Aksenov : Probes interface implement
- * 2014 Vitaliy Cherepanov: Portage
- *
- */
-
-
-#ifndef __PROBES_H__
-#define __PROBES_H__
-
-#include <linux/types.h>
-#include <uprobe/swap_uprobes.h>
-
-#include <preload/preload_probe.h>   /* TODO Remove */
-#include <retprobe/retprobe.h>       /* TODO Remove */
-#include <fbiprobe/fbiprobe.h>       /* TODO Remove */
-
-
-
-/* All probe types. Only us_manager should know about them - it is its own
- * business to install proper probes on proper places.
- */
-enum probe_t {
-       SWAP_RETPROBE = 0,          /* Retprobe */
-       SWAP_FBIPROBE = 1,          /* FBI probe */
-       SWAP_PRELOAD_PROBE = 2,     /* Preload probe */
-       SWAP_GET_CALLER = 4,        /* Get caller probe. Supports preload */
-       SWAP_GET_CALL_TYPE = 5,     /* Get call type probe. Supports preload */
-       SWAP_WRITE_MSG = 6,         /* Write messages from user space directly to 
-                                    * kernel. Supports preload */
-       SWAP_NEW_UP,
-       SWAP_NEW_URP,
-       SWAP_PROBE_MAX_VAL          /* Probes max value. */
-};
-
-/* Probe info stuct. It contains the whole information about probe. */
-struct probe_info {
-       /* Union of all SWAP supported probe types */
-       union {
-               struct retprobe_info rp_i;
-               struct fbi_info fbi_i;
-               struct preload_info pl_i;
-               struct get_caller_info gc_i;
-               struct get_call_type_info gct_i;
-               struct write_msg_info wm_i;
-       };
-};
-
-struct probe_desc {
-       enum probe_t type;
-
-       union {
-               struct {
-                       uprobe_pre_handler_t handler;
-               } p;
-
-               struct {
-                       uretprobe_handler_t entry_handler;
-                       uretprobe_handler_t ret_handler;
-                       /*
-                        * FIXME: make dynamic size,
-                        *        currently data_size = sizeof(void *)
-                        */
-                       size_t data_size;
-               } rp;
-       } u;
-
-       struct probe_info info;
-};
-
-#endif /* __PROBES_H__ */
diff --git a/us_manager/probes/register_probes.h b/us_manager/probes/register_probes.h
deleted file mode 100644 (file)
index f981056..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __REGISTER_PROBES_H__
-#define __REGISTER_PROBES_H__
-
-#include "probes.h"
-
-struct sspt_ip;
-
-struct probe_iface {
-       void (*init)(struct sspt_ip *);
-       void (*uninit)(struct sspt_ip *);
-       int (*reg)(struct sspt_ip *);
-       void (*unreg)(struct sspt_ip *, int);
-       struct uprobe *(*get_uprobe)(struct sspt_ip *);
-       int (*copy)(struct probe_info *, const struct probe_info *);
-       void (*cleanup)(struct probe_info *);
-};
-
-int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi);
-void swap_unregister_probe_type(enum probe_t probe_type);
-
-#endif /* __REGISTER_PROBES_H__ */
diff --git a/us_manager/probes/use_probes.h b/us_manager/probes/use_probes.h
deleted file mode 100644 (file)
index a925194..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __USE_PROBES_H__
-#define __USE_PROBES_H__
-
-#include "probes.h"
-
-struct sspt_ip;
-
-void probe_info_init(enum probe_t type, struct sspt_ip *ip);
-void probe_info_uninit(enum probe_t type, struct sspt_ip *ip);
-int probe_info_register(enum probe_t type, struct sspt_ip *ip);
-void probe_info_unregister(enum probe_t type, struct sspt_ip *ip, int disarm);
-struct uprobe *probe_info_get_uprobe(enum probe_t type, struct sspt_ip *ip);
-int probe_info_copy(const struct probe_info *pi, struct probe_info *dest);
-void probe_info_cleanup(struct probe_info *pi);
-
-#endif /* __USE_PROBES_H__ */
diff --git a/us_manager/sspt/sspt.h b/us_manager/sspt/sspt.h
deleted file mode 100644 (file)
index 1754acc..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef __SSPT__
-#define __SSPT__
-
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/driver/sspt/sspt.h
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt_ip.h"
-#include "sspt_page.h"
-#include "sspt_file.h"
-#include "sspt_proc.h"
-#include "sspt_debug.h"
-#include <uprobe/swap_uprobes.h>
-
-
-#include <us_manager/us_manager.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/probes/use_probes.h>
-
-
-static inline 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 inline int sspt_register_usprobe(struct sspt_ip *ip)
-{
-       int ret;
-       struct uprobe *up = NULL;
-
-       up = probe_info_get_uprobe(ip->desc->type, ip);
-
-       if (!up) {
-               printk(KERN_INFO "SWAP US_MANAGER: failed getting uprobe!\n");
-               return -EINVAL;
-       }
-
-       up->addr = (uprobe_opcode_t *)ip->orig_addr;
-       up->task = ip->page->file->proc->leader;
-       up->sm = ip->page->file->proc->sm;
-
-       ret = probe_info_register(ip->desc->type, ip);
-       if (ret) {
-               struct sspt_file *file = ip->page->file;
-               char *name = file->dentry->d_iname;
-               unsigned long addr = (unsigned long)up->addr;
-               unsigned long offset = addr - file->vm_start;
-
-               printk(KERN_ERR "probe_info_register failed %d (%s:%lx|%lx)\n",
-                               ret, name, offset,
-                               (unsigned long)ip->retprobe.up.opcode);
-       }
-
-       return ret;
-}
-
-static inline int sspt_unregister_usprobe(struct task_struct *task,
-                                         struct sspt_ip *ip,
-                                         enum US_FLAGS flag)
-{
-       struct uprobe *up = NULL;
-
-       switch (flag) {
-       case US_UNREGS_PROBE:
-               probe_info_unregister(ip->desc->type, ip, 1);
-               break;
-       case US_DISARM:
-               up = probe_info_get_uprobe(ip->desc->type, ip);
-               if (up)
-                       disarm_uprobe(up, task);
-               break;
-       case US_UNINSTALL:
-               probe_info_unregister(ip->desc->type, ip, 0);
-               break;
-       default:
-               panic("incorrect value flag=%d", flag);
-       }
-
-       return 0;
-}
-
-#endif /* __SSPT__ */
diff --git a/us_manager/sspt/sspt_debug.h b/us_manager/sspt/sspt_debug.h
deleted file mode 100644 (file)
index afd9595..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#ifndef __SSPT_DEBUG__
-#define __SSPT_DEBUG__
-
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/driver/sspt/sspt_debug.h
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include <kprobe/swap_kprobes_deps.h>
-#include <us_manager/probes/probes.h>
-
-
-static inline void print_retprobe(struct uretprobe *rp)
-{
-       printk(KERN_INFO "###         RP: handler=%lx\n",
-                       (unsigned long)rp->handler);
-}
-
-static inline void print_ip(struct sspt_ip *ip, int i)
-{
-       if (ip->desc->type == SWAP_RETPROBE) {
-               struct uretprobe *rp = &ip->retprobe;
-
-               printk(KERN_INFO "###       addr[%2d]=%lx, R_addr=%lx\n",
-                      i, (unsigned long)ip->offset,
-                      (unsigned long)rp->up.addr);
-               print_retprobe(rp);
-       }
-}
-
-static inline void print_page_probes(const struct sspt_page *page)
-{
-       int i = 0;
-       struct sspt_ip *ip;
-
-       printk(KERN_INFO "###     offset=%lx\n", page->offset);
-       printk(KERN_INFO "###     no install:\n");
-       list_for_each_entry(ip, &page->ip_list.not_inst, list) {
-               print_ip(ip, i);
-               ++i;
-       }
-
-       printk(KERN_INFO "###     install:\n");
-       list_for_each_entry(ip, &page->ip_list.inst, list) {
-               print_ip(ip, i);
-               ++i;
-       }
-}
-
-static inline void print_file_probes(struct sspt_file *file)
-{
-       int i;
-       unsigned long table_size;
-       struct sspt_page *page = NULL;
-       struct hlist_head *head = NULL;
-       static unsigned char *NA = "N/A";
-       unsigned char *name;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       if (file == NULL) {
-               printk(KERN_INFO "### file_p == NULL\n");
-               return;
-       }
-
-       table_size = (1 << file->htable.bits);
-       name = (file->dentry) ? file->dentry->d_iname : NA;
-
-       printk(KERN_INFO "### print_file_probes: path=%s, d_iname=%s, "
-              "table_size=%lu, vm_start=%lx\n",
-              file->dentry->d_iname, name, table_size, file->vm_start);
-
-       down_read(&file->htable.sem);
-       for (i = 0; i < table_size; ++i) {
-               head = &file->htable.heads[i];
-               swap_hlist_for_each_entry_rcu(page, node, head, hlist) {
-                       print_page_probes(page);
-               }
-       }
-       up_read(&file->htable.sem);
-}
-
-static inline void print_proc_probes(struct sspt_proc *proc)
-{
-       struct sspt_file *file;
-
-       printk(KERN_INFO "### print_proc_probes\n");
-       down_read(&proc->files.sem);
-       list_for_each_entry(file, &proc->files.head, list) {
-               print_file_probes(file);
-       }
-       up_read(&proc->files.sem);
-       printk(KERN_INFO "### print_proc_probes\n");
-}
-
-
-#endif /* __SSPT_DEBUG__ */
diff --git a/us_manager/sspt/sspt_feature.c b/us_manager/sspt/sspt_feature.c
deleted file mode 100644 (file)
index bc2c84d..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/us_manager/sspt/sspt_feature.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt_feature.h"
-#include "sspt_proc.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-
-struct sspt_feature {
-       struct list_head feature_list;
-};
-
-struct sspt_feature_img {
-       struct list_head list;
-
-       void *(*alloc)(void);
-       void (*free)(void *data);
-};
-
-struct sspt_feature_data {
-       struct list_head list;
-
-       struct sspt_feature_img *img;
-       void *data;
-};
-
-static DEFINE_SPINLOCK(feature_img_lock);
-static LIST_HEAD(feature_img_list);
-
-static struct sspt_feature_data *create_feature_data(
-       struct sspt_feature_img *img)
-{
-       struct sspt_feature_data *fd;
-
-       fd = kmalloc(sizeof(*fd), GFP_ATOMIC);
-       if (fd) {
-               INIT_LIST_HEAD(&fd->list);
-               fd->img = img;
-               fd->data = img->alloc();
-       }
-
-       return fd;
-}
-
-static void destroy_feature_data(struct sspt_feature_data *fd)
-{
-       fd->img->free(fd->data);
-       kfree(fd);
-}
-
-/**
- * @brief Create sspt_feature struct
- *
- * @return Pointer to the created sspt_feature struct
- */
-struct sspt_feature *sspt_create_feature(void)
-{
-       struct sspt_feature *f;
-
-       f = kmalloc(sizeof(*f), GFP_ATOMIC);
-       if (f) {
-               struct sspt_feature_data *fd;
-               struct sspt_feature_img *fi;
-               unsigned long flags;
-
-               INIT_LIST_HEAD(&f->feature_list);
-
-               spin_lock_irqsave(&feature_img_lock, flags);
-               list_for_each_entry(fi, &feature_img_list, list) {
-                       fd = create_feature_data(fi);
-                        if (fd) /* add to list */
-                               list_add(&fd->list, &f->feature_list);
-               }
-               spin_unlock_irqrestore(&feature_img_lock, flags);
-       }
-
-       return f;
-}
-
-/**
- * @brief Destroy sspt_feature struct
- *
- * @param f remove object
- * @return Void
- */
-void sspt_destroy_feature(struct sspt_feature *f)
-{
-       struct sspt_feature_data *fd, *n;
-
-       list_for_each_entry_safe(fd, n, &f->feature_list, list) {
-               /* delete from list */
-               list_del(&fd->list);
-               destroy_feature_data(fd);
-       }
-
-       kfree(f);
-}
-
-static void add_feature_img_to_list(struct sspt_feature_img *fi)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&feature_img_lock, flags);
-       list_add(&fi->list, &feature_img_list);
-       spin_unlock_irqrestore(&feature_img_lock, flags);
-}
-
-static void del_feature_img_from_list(struct sspt_feature_img *fi)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&feature_img_lock, flags);
-       list_del(&fi->list);
-       spin_unlock_irqrestore(&feature_img_lock, flags);
-}
-
-static struct sspt_feature_img *create_feature_img(void *(*alloc)(void),
-                                                  void (*free)(void *data))
-{
-       struct sspt_feature_img *fi;
-
-       fi = kmalloc(sizeof(*fi), GFP_ATOMIC);
-       if (fi) {
-               INIT_LIST_HEAD(&fi->list);
-               fi->alloc = alloc;
-               fi->free = free;
-
-               add_feature_img_to_list(fi);
-       }
-
-       return fi;
-}
-
-static void destroy_feature_img(struct sspt_feature_img *fi)
-{
-       del_feature_img_from_list(fi);
-
-       kfree(fi);
-}
-
-static void del_feature_by_img(struct sspt_feature *f,
-                              struct sspt_feature_img *img)
-{
-       struct sspt_feature_data *fd;
-
-       list_for_each_entry(fd, &f->feature_list, list) {
-               if (img == fd->img) {
-                       /* delete from list */
-                       list_del(&fd->list);
-                       destroy_feature_data(fd);
-                       break;
-               }
-       }
-}
-
-static void del_feature_from_proc(struct sspt_proc *proc, void *data)
-{
-       del_feature_by_img(proc->feature, (struct sspt_feature_img *)data);
-}
-
-/**
- * @brief Get data for feature
- *
- * @param f Pointer to the sspt_feature struct
- * @param id Feature ID
- * @return Pointer to the data
- */
-void *sspt_get_feature_data(struct sspt_feature *f, sspt_feature_id_t id)
-{
-       struct sspt_feature_img *img = (struct sspt_feature_img *)id;
-       struct sspt_feature_data *fd;
-
-       list_for_each_entry(fd, &f->feature_list, list) {
-               if (img == fd->img)
-                       return fd->data;
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(sspt_get_feature_data);
-
-/**
- * @brief Register sspt feature
- *
- * @param alloc Callback for allocating data
- * @param free Callback to release data
- * @return Feature ID
- */
-sspt_feature_id_t sspt_register_feature(void *(*alloc)(void),
-                                       void (*free)(void *data))
-{
-       struct sspt_feature_img *fi;
-
-       fi = create_feature_img(alloc, free);
-
-       /* TODO: add to already instrumentation process */
-
-       return (sspt_feature_id_t)fi;
-}
-EXPORT_SYMBOL_GPL(sspt_register_feature);
-
-/**
- * @brief Unregister sspt feature
- *
- * @param id Feature ID
- * @return Void
- */
-void sspt_unregister_feature(sspt_feature_id_t id)
-{
-       struct sspt_feature_img *fi = (struct sspt_feature_img *)id;
-
-       on_each_proc(del_feature_from_proc, (void *)fi);
-       destroy_feature_img(fi);
-}
-EXPORT_SYMBOL_GPL(sspt_unregister_feature);
diff --git a/us_manager/sspt/sspt_feature.h b/us_manager/sspt/sspt_feature.h
deleted file mode 100644 (file)
index a500bc6..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _SSPT_FEATUER_H
-#define _SSPT_FEATUER_H
-
-/**
- * @file us_manager/sspt/sspt_feature.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-struct sspt_feature;
-
-typedef void *sspt_feature_id_t;       /**< @brief sspt feature ID type */
-#define SSPT_FEATURE_ID_BAD    NULL    /**< @def SSPT_FEATURE_ID_BAD */
-
-struct sspt_feature *sspt_create_feature(void);
-void sspt_destroy_feature(struct sspt_feature *f);
-
-void *sspt_get_feature_data(struct sspt_feature *f, sspt_feature_id_t id);
-sspt_feature_id_t sspt_register_feature(void *(*alloc)(void),
-                                       void (*free)(void *data));
-void sspt_unregister_feature(sspt_feature_id_t id);
-
-#endif /* _SSPT_FEATUER_H */
diff --git a/us_manager/sspt/sspt_file.c b/us_manager/sspt/sspt_file.c
deleted file mode 100644 (file)
index 2c74b74..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/driver/sspt/sspt_file.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt.h"
-#include "sspt_file.h"
-#include "sspt_page.h"
-#include "sspt_proc.h"
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/hash.h>
-#include <linux/sched.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <us_manager/probes/probes.h>
-#include <us_manager/img/img_ip.h>
-
-static int calculation_hash_bits(int cnt)
-{
-       int bits;
-       for (bits = 1; cnt >>= 1; ++bits)
-               ;
-
-       return bits;
-}
-
-static unsigned long htable_size(const struct sspt_file *file)
-{
-       return 1 << file->htable.bits;
-}
-
-static struct hlist_head *htable_head_by_idx(const struct sspt_file *file,
-                                            unsigned long idx)
-{
-       return &file->htable.heads[idx];
-}
-
-static struct hlist_head *htable_head_by_key(const struct sspt_file *file,
-                                            unsigned long offset)
-{
-       unsigned long idx = hash_ptr((void *)offset, file->htable.bits);
-
-       return htable_head_by_idx(file, idx);
-}
-
-/**
- * @brief Create sspt_file struct
- *
- * @param dentry Dentry of file
- * @param page_cnt Size of hash-table
- * @return Pointer to the created sspt_file struct
- */
-struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt)
-{
-       int i, table_size;
-       struct hlist_head *heads;
-       struct sspt_file *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
-
-       if (obj == NULL)
-               return NULL;
-
-       INIT_LIST_HEAD(&obj->list);
-       obj->proc = NULL;
-       obj->dentry = dentry;
-       obj->loaded = 0;
-       obj->vm_start = 0;
-       obj->vm_end = 0;
-
-       obj->htable.bits = calculation_hash_bits(page_cnt);
-       table_size = htable_size(obj);
-
-       heads = kmalloc(sizeof(*obj->htable.heads) * table_size, GFP_ATOMIC);
-       if (heads == NULL)
-               goto err;
-
-       for (i = 0; i < table_size; ++i)
-               INIT_HLIST_HEAD(&heads[i]);
-
-       obj->htable.heads = heads;
-       init_rwsem(&obj->htable.sem);
-
-       return obj;
-
-err:
-       kfree(obj);
-       return NULL;
-}
-
-/**
- * @brief Remove sspt_file struct
- *
- * @param file remove object
- * @return Void
- */
-void sspt_file_free(struct sspt_file *file)
-{
-       struct hlist_head *head;
-       struct sspt_page *page;
-       int i, table_size = htable_size(file);
-       struct hlist_node *n;
-       DECLARE_NODE_PTR_FOR_HLIST(p);
-
-       down_write(&file->htable.sem);
-       for (i = 0; i < table_size; ++i) {
-               head = htable_head_by_idx(file, i);
-               swap_hlist_for_each_entry_safe(page, p, n, head, hlist) {
-                       hlist_del(&page->hlist);
-                       sspt_page_clean(page);
-                       sspt_page_put(page);
-               }
-       }
-       up_write(&file->htable.sem);
-
-       kfree(file->htable.heads);
-       kfree(file);
-}
-
-static void sspt_add_page(struct sspt_file *file, struct sspt_page *page)
-{
-       page->file = file;
-       hlist_add_head(&page->hlist, htable_head_by_key(file, page->offset));
-}
-
-static struct sspt_page *sspt_find_page(struct sspt_file *file,
-                                       unsigned long offset)
-{
-       struct hlist_head *head = htable_head_by_key(file, offset);
-       struct sspt_page *page;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       swap_hlist_for_each_entry(page, node, head, hlist) {
-               if (page->offset == offset)
-                       return page;
-       }
-
-       return NULL;
-}
-
-static struct sspt_page *sspt_find_page_or_new(struct sspt_file *file,
-                                              unsigned long offset)
-{
-       struct sspt_page *page;
-
-       down_write(&file->htable.sem);
-       page = sspt_find_page(file, offset);
-       if (page == NULL) {
-               page = sspt_page_create(offset);
-               if (page)
-                       sspt_add_page(file, page);
-       }
-       up_write(&file->htable.sem);
-
-       return page;
-}
-
-/**
- * @brief Get sspt_page from sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param page Page address
- * @return Pointer to the sspt_page struct
- */
-struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
-                                       unsigned long page)
-{
-       unsigned long offset;
-       struct sspt_page *p;
-
-       if (file->vm_start > page || file->vm_end < page) {
-               /* TODO: or panic?! */
-               printk(KERN_INFO "ERROR: file_p[vm_start..vm_end] <> page: "
-                      "file_p[vm_start=%lx, vm_end=%lx, "
-                      "d_iname=%s] page=%lx\n",
-                      file->vm_start, file->vm_end,
-                      file->dentry->d_iname, page);
-               return NULL;
-       }
-
-       offset = page - file->vm_start;
-
-       down_read(&file->htable.sem);
-       p = sspt_find_page(file, offset);
-       up_read(&file->htable.sem);
-
-       return p;
-}
-
-/**
- * @brief Add instruction pointer to sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param offset File offset
- * @param args Function arguments
- * @param ret_type Return type
- * @return Void
- */
-void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip)
-{
-       unsigned long offset = 0;
-       struct sspt_page *page = NULL;
-       struct sspt_ip *ip = NULL;
-
-       offset = img_ip->addr & PAGE_MASK;
-       page = sspt_find_page_or_new(file, offset);
-       if (!page)
-               return;
-
-       ip = sspt_ip_create(img_ip, page);
-       if (!ip)
-               return;
-
-       probe_info_init(ip->desc->type, ip);
-}
-
-void sspt_file_on_each_ip(struct sspt_file *file,
-                         void (*func)(struct sspt_ip *, void *), void *data)
-{
-       int i;
-       const int table_size = htable_size(file);
-       struct sspt_page *page;
-       struct hlist_head *head;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       down_read(&file->htable.sem);
-       for (i = 0; i < table_size; ++i) {
-               head = htable_head_by_idx(file, i);
-               swap_hlist_for_each_entry(page, node, head, hlist)
-                       sspt_page_on_each_ip(page, func, data);
-       }
-       up_read(&file->htable.sem);
-}
-
-/**
- * @brief Check install sspt_file (legacy code, it is need remove)
- *
- * @param file Pointer to the sspt_file struct
- * @return
- *       - 0 - false
- *       - 1 - true
- */
-int sspt_file_check_install_pages(struct sspt_file *file)
-{
-       int ret = 0;
-       int i, table_size;
-       struct sspt_page *page;
-       struct hlist_head *head;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       table_size = htable_size(file);
-
-       down_read(&file->htable.sem);
-       for (i = 0; i < table_size; ++i) {
-               head = htable_head_by_idx(file, i);
-               swap_hlist_for_each_entry(page, node, head, hlist) {
-                       if (sspt_page_is_installed(page)) {
-                               ret = 1;
-                               goto unlock;
-                       }
-               }
-       }
-
-unlock:
-       up_read(&file->htable.sem);
-       return ret;
-}
-
-/**
- * @brief Install sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @return Void
- */
-void sspt_file_install(struct sspt_file *file)
-{
-       struct sspt_page *page = NULL;
-       struct hlist_head *head = NULL;
-       int i, table_size = htable_size(file);
-       unsigned long page_addr;
-       struct mm_struct *mm;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       down_read(&file->htable.sem);
-       for (i = 0; i < table_size; ++i) {
-               head = htable_head_by_idx(file, i);
-               swap_hlist_for_each_entry(page, node, head, hlist) {
-                       unsigned long offset = page->offset;
-
-#ifdef CONFIG_64BIT
-                       /* Reset most significant bit for only 64-bit */
-                       offset &= (~(1UL << 63));
-#endif /* CONFIG_64BIT */
-
-                       page_addr = file->vm_start + offset;
-                       if (page_addr < file->vm_start ||
-                           page_addr >= file->vm_end)
-                               continue;
-
-                       mm = page->file->proc->leader->mm;
-                       if (page_present(mm, page_addr))
-                               sspt_register_page(page, file);
-               }
-       }
-       up_read(&file->htable.sem);
-}
-
-/**
- * @brief Uninstall sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param task Pointer to the task_stract struct
- * @param flag Action for probes
- * @return Void
- */
-int sspt_file_uninstall(struct sspt_file *file,
-                       struct task_struct *task,
-                       enum US_FLAGS flag)
-{
-       int i, err = 0;
-       int table_size = htable_size(file);
-       struct sspt_page *page;
-       struct hlist_head *head;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       down_read(&file->htable.sem);
-       for (i = 0; i < table_size; ++i) {
-               head = htable_head_by_idx(file, i);
-               swap_hlist_for_each_entry(page, node, head, hlist) {
-                       err = sspt_unregister_page(page, flag, task);
-                       if (err != 0) {
-                               printk(KERN_INFO "ERROR sspt_file_uninstall: "
-                                      "err=%d\n", err);
-                               up_read(&file->htable.sem);
-                               return err;
-                       }
-               }
-       }
-       up_read(&file->htable.sem);
-
-       if (flag != US_DISARM) {
-               file->loaded = 0;
-               file->vm_start = 0;
-               file->vm_end = 0;
-       }
-
-       return err;
-}
-
-/**
- * @brief Set mapping for sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param vma Pointer to the vm_area_struct struct
- * @return Void
- */
-void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma)
-{
-       if (file->loaded == 0) {
-               file->loaded = 1;
-               file->vm_start = vma->vm_start;
-               file->vm_end = vma->vm_end;
-       }
-}
diff --git a/us_manager/sspt/sspt_file.h b/us_manager/sspt/sspt_file.h
deleted file mode 100644 (file)
index 38d34aa..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef __SSPT_FILE__
-#define __SSPT_FILE__
-
-/**
- * @file us_manager/sspt/sspt_file.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-#include "sspt_ip.h"
-#include <linux/types.h>
-#include <linux/rwsem.h>
-
-enum US_FLAGS;
-struct vm_area_struct;
-
-/**
- * @struct sspt_file
- * @breaf Image of file for specified process
- */
-struct sspt_file {
-       /* sspt_proc */
-       struct list_head list;          /**< For sspt_proc */
-       struct sspt_proc *proc;         /**< Pointer to the proc (parent) */
-
-       /* sspt_page */
-       struct {
-               struct rw_semaphore sem;        /**< Semaphore for hash-table */
-               unsigned long bits;             /**< Hash-table size */
-               struct hlist_head *heads;       /**< Heads for pages */
-       } htable;
-
-       struct dentry *dentry;          /**< Dentry of file */
-       unsigned long vm_start;         /**< VM start */
-       unsigned long vm_end;           /**< VM end */
-       unsigned loaded:1;              /**< Flag of loading */
-};
-
-
-struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt);
-void sspt_file_free(struct sspt_file *file);
-
-struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
-                                       unsigned long page);
-void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip);
-
-void sspt_file_on_each_ip(struct sspt_file *file,
-                         void (*func)(struct sspt_ip *, void *), void *data);
-
-int sspt_file_check_install_pages(struct sspt_file *file);
-void sspt_file_install(struct sspt_file *file);
-int sspt_file_uninstall(struct sspt_file *file,
-                       struct task_struct *task,
-                       enum US_FLAGS flag);
-void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma);
-
-#endif /* __SSPT_FILE__ */
diff --git a/us_manager/sspt/sspt_filter.c b/us_manager/sspt/sspt_filter.c
deleted file mode 100644 (file)
index f7a0799..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <linux/list.h>
-#include <linux/slab.h>
-#include "sspt_filter.h"
-#include "sspt_proc.h"
-#include "../pf/pf_group.h"
-
-
-struct sspt_filter *sspt_filter_create(struct sspt_proc *proc,
-                                      struct pf_group *pfg)
-{
-       struct sspt_filter *fl;
-
-       fl = kmalloc(sizeof(*fl), GFP_ATOMIC);
-       if (fl == NULL)
-               return NULL;
-
-       INIT_LIST_HEAD(&fl->list);
-
-       fl->proc = proc;
-       fl->pfg = pfg;
-       fl->pfg_is_inst = false;
-
-       return fl;
-}
-
-void sspt_filter_free(struct sspt_filter *fl)
-{
-       if (fl->pfg_is_inst) {
-               struct pfg_msg_cb *cb = pfg_msg_cb_get(fl->pfg);
-
-               if (cb && cb->msg_term)
-                       cb->msg_term(fl->proc->leader);
-       }
-
-       kfree(fl);
-}
diff --git a/us_manager/sspt/sspt_filter.h b/us_manager/sspt/sspt_filter.h
deleted file mode 100644 (file)
index faeac80..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __SSPT_FILTER_H__
-#define __SSPT_FILTER_H__
-
-#include <linux/types.h>
-
-struct pf_group;
-struct sspt_proc;
-
-struct sspt_filter {
-       struct list_head list;
-       struct sspt_proc *proc;
-       struct pf_group *pfg;
-       bool pfg_is_inst;
-};
-
-struct sspt_filter *sspt_filter_create(struct sspt_proc *proc,
-                                      struct pf_group *pfg);
-void sspt_filter_free(struct sspt_filter *fl);
-
-#endif /* __SSPT_FILTER_H__ */
diff --git a/us_manager/sspt/sspt_ip.c b/us_manager/sspt/sspt_ip.c
deleted file mode 100644 (file)
index 0f0b4ff..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/driver/sspt/ip.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include "sspt_ip.h"
-#include "sspt_page.h"
-#include "sspt_file.h"
-#include <us_manager/probes/use_probes.h>
-#include <us_manager/img/img_ip.h>
-
-/**
- * @brief Create us_ip struct
- *
- * @param page User page
- * @param offset Function offset from the beginning of the page
- * @param probe_i Pointer to the probe data.
- * @param page Pointer to the parent sspt_page struct
- * @return Pointer to the created us_ip struct
- */
-struct sspt_ip *sspt_ip_create(struct img_ip *img_ip, struct sspt_page *page)
-{
-       struct sspt_ip *ip;
-
-       ip = kmalloc(sizeof(*ip), GFP_ATOMIC);
-       if (!ip)
-               return NULL;
-
-       memset(ip, 0, sizeof(*ip));
-       INIT_LIST_HEAD(&ip->list);
-       INIT_LIST_HEAD(&ip->img_list);
-       ip->offset = img_ip->addr & ~PAGE_MASK;
-       ip->desc = img_ip->desc;
-       atomic_set(&ip->usage, 2);      /* for 'img_ip' and 'page' */
-
-       /* add to img_ip list */
-       img_ip_get(img_ip);
-       img_ip_lock(img_ip);
-       img_ip_add_ip(img_ip, ip);
-       img_ip_unlock(img_ip);
-
-       /* add to page list */
-       sspt_page_get(page);
-       sspt_page_lock(page);
-       sspt_page_add_ip(page, ip);
-       sspt_page_unlock(page);
-
-       return ip;
-}
-
-static void sspt_ip_free(struct sspt_ip *ip)
-{
-       WARN_ON(!list_empty(&ip->list) || !list_empty(&ip->img_list));
-
-       kfree(ip);
-}
-
-void sspt_ip_get(struct sspt_ip *ip)
-{
-       atomic_inc(&ip->usage);
-}
-
-void sspt_ip_put(struct sspt_ip *ip)
-{
-       if (atomic_dec_and_test(&ip->usage))
-               sspt_ip_free(ip);
-}
-
-void sspt_ip_clean(struct sspt_ip *ip)
-{
-       bool put_page = false;
-       bool put_ip = false;
-
-       /* remove from page */
-       sspt_page_lock(ip->page);
-       if (!list_empty(&ip->list)) {
-               list_del_init(&ip->list);
-               put_page = true;
-       }
-       sspt_page_unlock(ip->page);
-       if (put_page) {
-               sspt_page_put(ip->page);
-               sspt_ip_put(ip);
-       }
-
-       /* remove from img_ip */
-       img_ip_lock(ip->img_ip);
-       if (!list_empty(&ip->img_list)) {
-               list_del_init(&ip->img_list);
-               put_ip = true;
-       }
-       img_ip_unlock(ip->img_ip);
-       if (put_ip) {
-               img_ip_put(ip->img_ip);
-               sspt_ip_put(ip);
-       }
-}
diff --git a/us_manager/sspt/sspt_ip.h b/us_manager/sspt/sspt_ip.h
deleted file mode 100644 (file)
index 226173e..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef _SSPT_IP
-#define _SSPT_IP
-
-/**
- * @file us_manager/sspt/ip.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-#include <linux/list.h>
-#include <linux/atomic.h>
-#include <uprobe/swap_uprobes.h>
-#include <us_manager/probes/probes.h>
-
-struct sspt_page;
-
-/**
- * @struct sspt_ip
- * @breaf Image of instrumentation pointer for specified process
- */
-struct sspt_ip {
-       /* sspt_page */
-       struct list_head list;      /**< For sspt_page */
-       struct sspt_page *page;     /**< Pointer on the page (parent) */
-
-       /* img_ip */
-       struct img_ip *img_ip;      /**< Pointer on the img_ip (parent) */
-       struct list_head img_list;  /**< For img_ip */
-
-       atomic_t usage;
-
-       unsigned long orig_addr;    /**< Function address */
-       unsigned long offset;       /**< Page offset */
-
-       struct probe_desc *desc;    /**< Probe's data */
-
-       union {
-               struct uretprobe retprobe;
-               struct uprobe uprobe;
-       };
-};
-
-
-struct sspt_ip *sspt_ip_create(struct img_ip *img_ip, struct sspt_page *page);
-void sspt_ip_clean(struct sspt_ip *ip);
-void sspt_ip_get(struct sspt_ip *ip);
-void sspt_ip_put(struct sspt_ip *ip);
-
-
-#endif /* _SSPT_IP */
diff --git a/us_manager/sspt/sspt_page.c b/us_manager/sspt/sspt_page.c
deleted file mode 100644 (file)
index 6fa19a2..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/driver/sspt/sspt_page.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt.h"
-#include "sspt_page.h"
-#include "sspt_file.h"
-#include "sspt_ip.h"
-#include <us_manager/probes/use_probes.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-
-/**
- * @brief Create sspt_page struct
- *
- * @param offset File ofset
- * @return Pointer to the created sspt_page struct
- */
-struct sspt_page *sspt_page_create(unsigned long offset)
-{
-       struct sspt_page *obj = kmalloc(sizeof(*obj), GFP_KERNEL);
-       if (obj) {
-               INIT_HLIST_NODE(&obj->hlist);
-               mutex_init(&obj->ip_list.mtx);
-               INIT_LIST_HEAD(&obj->ip_list.inst);
-               INIT_LIST_HEAD(&obj->ip_list.not_inst);
-               obj->offset = offset;
-               obj->file = NULL;
-               kref_init(&obj->ref);
-       }
-
-       return obj;
-}
-
-void sspt_page_clean(struct sspt_page *page)
-{
-       struct sspt_ip *ip, *n;
-       LIST_HEAD(head);
-
-       sspt_page_lock(page);
-       WARN_ON(!list_empty(&page->ip_list.inst));
-       list_for_each_entry_safe(ip, n, &page->ip_list.inst, list) {
-               sspt_ip_get(ip);
-               list_move(&ip->list, &head);
-       }
-
-       list_for_each_entry_safe(ip, n, &page->ip_list.not_inst, list) {
-               sspt_ip_get(ip);
-               list_move(&ip->list, &head);
-       }
-
-       while (!list_empty(&head)) {
-               ip = list_first_entry(&head, struct sspt_ip ,list);
-               sspt_page_unlock(page);
-
-               sspt_ip_clean(ip);
-
-               sspt_page_lock(page);
-               sspt_ip_put(ip);
-       }
-       sspt_page_unlock(page);
-}
-
-static void sspt_page_release(struct kref *ref)
-{
-       struct sspt_page *page = container_of(ref, struct sspt_page, ref);
-
-       WARN_ON(!list_empty(&page->ip_list.inst) ||
-               !list_empty(&page->ip_list.not_inst));
-
-       kfree(page);
-}
-
-void sspt_page_get(struct sspt_page *page)
-{
-       kref_get(&page->ref);
-}
-
-void sspt_page_put(struct sspt_page *page)
-{
-       kref_put(&page->ref, sspt_page_release);
-}
-
-/**
- * @brief Add instruction pointer to sspt_page
- *
- * @param page Pointer to the sspt_page struct
- * @param ip Pointer to the us_ip struct
- * @return Void
- */
-void sspt_page_add_ip(struct sspt_page *page, struct sspt_ip *ip)
-{
-       ip->page = page;
-       list_add(&ip->list, &page->ip_list.not_inst);
-}
-
-void sspt_page_lock(struct sspt_page *page)
-{
-       mutex_lock(&page->ip_list.mtx);
-}
-
-void sspt_page_unlock(struct sspt_page *page)
-{
-       mutex_unlock(&page->ip_list.mtx);
-}
-
-/**
- * @brief Check if probes are set on the page
- *
- * @param page Pointer to the sspt_page struct
- * @return Boolean
- */
-bool sspt_page_is_installed(struct sspt_page *page)
-{
-       return !list_empty(&page->ip_list.inst);
-}
-
-bool sspt_page_is_installed_ip(struct sspt_page *page, struct sspt_ip *ip)
-{
-       bool result = false; /* not installed by default */
-       struct sspt_ip *p;
-
-       sspt_page_lock(page);
-       list_for_each_entry(p, &page->ip_list.inst, list) {
-               if (p == ip) {
-                       result = true;
-                       goto unlock;
-               }
-       }
-
-unlock:
-       sspt_page_unlock(page);
-
-       return result;
-}
-
-/**
- * @brief Install probes on the page
- *
- * @param page Pointer to the sspt_page struct
- * @param file Pointer to the sspt_file struct
- * @return Error code
- */
-int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
-{
-       int err = 0;
-       struct sspt_ip *ip, *n;
-       LIST_HEAD(not_inst_head);
-
-       mutex_lock(&page->ip_list.mtx);
-       if (list_empty(&page->ip_list.not_inst))
-               goto unlock;
-
-       list_for_each_entry_safe(ip, n, &page->ip_list.not_inst, list) {
-               /* set virtual address */
-               ip->orig_addr = file->vm_start + page->offset + ip->offset;
-
-               err = sspt_register_usprobe(ip);
-               if (err) {
-                       sspt_ip_get(ip);
-                       list_move(&ip->list, &not_inst_head);
-                       continue;
-               }
-       }
-
-       list_splice_init(&page->ip_list.not_inst, &page->ip_list.inst);
-
-unlock:
-       mutex_unlock(&page->ip_list.mtx);
-
-       list_for_each_entry_safe(ip, n, &not_inst_head, list) {
-               sspt_ip_clean(ip);
-               sspt_ip_put(ip);
-       }
-
-       return 0;
-}
-
-/**
- * @brief Uninstall probes on the page
- *
- * @param page Pointer to the sspt_page struct
- * @param flag Action for probes
- * @param task Pointer to the task_struct struct
- * @return Error code
- */
-int sspt_unregister_page(struct sspt_page *page,
-                        enum US_FLAGS flag,
-                        struct task_struct *task)
-{
-       int err = 0;
-       struct sspt_ip *ip;
-
-       mutex_lock(&page->ip_list.mtx);
-       if (list_empty(&page->ip_list.inst))
-               goto unlock;
-
-       list_for_each_entry(ip, &page->ip_list.inst, list) {
-               err = sspt_unregister_usprobe(task, ip, flag);
-               if (err != 0) {
-                       WARN_ON(1);
-                       break;
-               }
-       }
-
-       if (flag != US_DISARM)
-               list_splice_init(&page->ip_list.inst, &page->ip_list.not_inst);
-
-unlock:
-       mutex_unlock(&page->ip_list.mtx);
-       return err;
-}
-
-void sspt_page_on_each_ip(struct sspt_page *page,
-                         void (*func)(struct sspt_ip *, void *), void *data)
-{
-       struct sspt_ip *ip;
-
-       mutex_lock(&page->ip_list.mtx);
-       list_for_each_entry(ip, &page->ip_list.inst, list)
-               func(ip, data);
-       mutex_unlock(&page->ip_list.mtx);
-}
diff --git a/us_manager/sspt/sspt_page.h b/us_manager/sspt/sspt_page.h
deleted file mode 100644 (file)
index bf7fa89..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef __SSPT_PAGE__
-#define __SSPT_PAGE__
-
-/**
- * @file us_manager/sspt/sspt_page.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/kref.h>
-
-struct sspt_ip;
-struct sspt_file;
-struct task_struct;
-enum US_FLAGS;
-
-/**
- * @struct sspt_page
- * @breaf Image of page for specified process
- */
-struct sspt_page {
-       /* sspt_file */
-       struct hlist_node hlist;                /**< For sspt_file */
-       struct sspt_file *file;                 /**< Ptr to the file (parent) */
-
-       /* sspt_ip */
-       struct {
-               struct mutex mtx;               /**< Lock page */
-               struct list_head inst;          /**< For installed ip */
-               struct list_head not_inst;      /**< For don'tinstalled ip */
-       } ip_list;
-
-       unsigned long offset;                   /**< File offset */
-
-       struct kref ref;
-};
-
-struct sspt_page *sspt_page_create(unsigned long offset);
-void sspt_page_clean(struct sspt_page *page);
-void sspt_page_get(struct sspt_page *page);
-void sspt_page_put(struct sspt_page *page);
-
-bool sspt_page_is_installed_ip(struct sspt_page *page, struct sspt_ip *ip);
-void sspt_page_add_ip(struct sspt_page *page, struct sspt_ip *ip);
-void sspt_page_lock(struct sspt_page *page);
-void sspt_page_unlock(struct sspt_page *page);
-
-bool sspt_page_is_installed(struct sspt_page *page);
-
-int sspt_register_page(struct sspt_page *page, struct sspt_file *file);
-
-int sspt_unregister_page(struct sspt_page *page,
-                        enum US_FLAGS flag,
-                        struct task_struct *task);
-
-void sspt_page_on_each_ip(struct sspt_page *page,
-                         void (*func)(struct sspt_ip *, void *), void *data);
-
-#endif /* __SSPT_PAGE__ */
diff --git a/us_manager/sspt/sspt_proc.c b/us_manager/sspt/sspt_proc.c
deleted file mode 100644 (file)
index bf6a2e6..0000000
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- *  Dynamic Binary Instrumentation Module based on KProbes
- *  modules/driver/sspt/sspt_proc.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt.h"
-#include "sspt_proc.h"
-#include "sspt_page.h"
-#include "sspt_feature.h"
-#include "sspt_filter.h"
-#include "../pf/proc_filters.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <kprobe/swap_ktd.h>
-#include <us_manager/us_slot_manager.h>
-
-static LIST_HEAD(proc_probes_list);
-static DEFINE_RWLOCK(sspt_proc_rwlock);
-
-
-struct list_head *sspt_proc_list()
-{
-       return &proc_probes_list;
-}
-
-/**
- * @brief Global read lock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_read_lock(void)
-{
-       read_lock(&sspt_proc_rwlock);
-}
-
-/**
- * @brief Global read unlock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_read_unlock(void)
-{
-       read_unlock(&sspt_proc_rwlock);
-}
-
-/**
- * @brief Global write lock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_write_lock(void)
-{
-       write_lock(&sspt_proc_rwlock);
-}
-
-/**
- * @brief Global write unlock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_write_unlock(void)
-{
-       write_unlock(&sspt_proc_rwlock);
-}
-
-struct ktd_proc {
-       struct sspt_proc *proc;
-       spinlock_t lock;
-};
-
-static void ktd_init(struct task_struct *task, void *data)
-{
-       struct ktd_proc *kproc = (struct ktd_proc *)data;
-
-       kproc->proc = NULL;
-       spin_lock_init(&kproc->lock);
-}
-
-static void ktd_exit(struct task_struct *task, void *data)
-{
-       struct ktd_proc *kproc = (struct ktd_proc *)data;
-
-       WARN_ON(kproc->proc);
-}
-
-static struct ktask_data ktd = {
-       .init = ktd_init,
-       .exit = ktd_exit,
-       .size = sizeof(struct ktd_proc),
-};
-
-static struct ktd_proc *kproc_by_task(struct task_struct *task)
-{
-       return (struct ktd_proc *)swap_ktd(&ktd, task);
-}
-
-int sspt_proc_init(void)
-{
-       return swap_ktd_reg(&ktd);
-}
-
-void sspt_proc_uninit(void)
-{
-       swap_ktd_unreg(&ktd);
-}
-
-void sspt_change_leader(struct task_struct *prev, struct task_struct *next)
-{
-       struct ktd_proc *prev_kproc;
-
-       prev_kproc = kproc_by_task(prev);
-       spin_lock(&prev_kproc->lock);
-       if (prev_kproc->proc) {
-               struct ktd_proc *next_kproc;
-
-               next_kproc = kproc_by_task(next);
-               get_task_struct(next);
-
-               /* Change the keeper sspt_proc */
-               BUG_ON(next_kproc->proc);
-
-               spin_lock(&next_kproc->lock);
-               next_kproc->proc = prev_kproc->proc;
-               prev_kproc->proc = NULL;
-               spin_unlock(&next_kproc->lock);
-
-               /* Set new the task leader to sspt_proc */
-               next_kproc->proc->leader = next;
-
-               put_task_struct(prev);
-       }
-       spin_unlock(&prev_kproc->lock);
-}
-
-static void sspt_reset_proc(struct task_struct *task)
-{
-       struct ktd_proc *kproc;
-
-       kproc = kproc_by_task(task->group_leader);
-       spin_lock(&kproc->lock);
-       kproc->proc = NULL;
-       spin_unlock(&kproc->lock);
-}
-
-
-
-
-
-static struct sspt_proc *sspt_proc_create(struct task_struct *leader)
-{
-       struct sspt_proc *proc = kzalloc(sizeof(*proc), GFP_KERNEL);
-
-       if (proc) {
-               proc->feature = sspt_create_feature();
-               if (proc->feature == NULL) {
-                       kfree(proc);
-                       return NULL;
-               }
-
-               INIT_LIST_HEAD(&proc->list);
-               INIT_LIST_HEAD(&proc->files.head);
-               init_rwsem(&proc->files.sem);
-               proc->tgid = leader->tgid;
-               proc->leader = leader;
-               /* FIXME: change the task leader */
-               proc->sm = create_sm_us(leader);
-               mutex_init(&proc->filters.mtx);
-               INIT_LIST_HEAD(&proc->filters.head);
-               atomic_set(&proc->usage, 1);
-
-               get_task_struct(proc->leader);
-
-               proc->suspect.after_exec = 1;
-               proc->suspect.after_fork = 0;
-       }
-
-       return proc;
-}
-
-static void sspt_proc_free(struct sspt_proc *proc)
-{
-       put_task_struct(proc->leader);
-       free_sm_us(proc->sm);
-       sspt_destroy_feature(proc->feature);
-       kfree(proc);
-}
-
-/**
- * @brief Remove sspt_proc struct
- *
- * @param proc remove object
- * @return Void
- */
-
-/* called with sspt_proc_write_lock() */
-void sspt_proc_cleanup(struct sspt_proc *proc)
-{
-       struct sspt_file *file, *n;
-
-       sspt_proc_del_all_filters(proc);
-
-       down_write(&proc->files.sem);
-       list_for_each_entry_safe(file, n, &proc->files.head, list) {
-               list_del(&file->list);
-               sspt_file_free(file);
-       }
-       up_write(&proc->files.sem);
-
-       sspt_destroy_feature(proc->feature);
-
-       free_sm_us(proc->sm);
-       sspt_reset_proc(proc->leader);
-       sspt_proc_put(proc);
-}
-
-struct sspt_proc *sspt_proc_get(struct sspt_proc *proc)
-{
-       atomic_inc(&proc->usage);
-
-       return proc;
-}
-
-void sspt_proc_put(struct sspt_proc *proc)
-{
-       if (atomic_dec_and_test(&proc->usage)) {
-               if (proc->__mm) {
-                       mmput(proc->__mm);
-                       proc->__mm = NULL;
-               }
-               if (proc->__task) {
-                       put_task_struct(proc->__task);
-                       proc->__task = NULL;
-               }
-
-               WARN_ON(kproc_by_task(proc->leader)->proc);
-
-               put_task_struct(proc->leader);
-               kfree(proc);
-       }
-}
-EXPORT_SYMBOL_GPL(sspt_proc_put);
-
-struct sspt_proc *sspt_proc_by_task(struct task_struct *task)
-{
-       return kproc_by_task(task->group_leader)->proc;
-}
-EXPORT_SYMBOL_GPL(sspt_proc_by_task);
-
-struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task)
-{
-       struct ktd_proc *kproc = kproc_by_task(task->group_leader);
-       struct sspt_proc *proc;
-
-       spin_lock(&kproc->lock);
-       proc = kproc->proc;
-       if (proc)
-               sspt_proc_get(proc);
-       spin_unlock(&kproc->lock);
-
-       return proc;
-}
-EXPORT_SYMBOL_GPL(sspt_proc_get_by_task);
-
-/**
- * @brief Call func() on each proc (no lock)
- *
- * @param func Callback
- * @param data Data for callback
- * @return Void
- */
-void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *), void *data)
-{
-       struct sspt_proc *proc, *tmp;
-
-       list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) {
-               func(proc, data);
-       }
-}
-
-/**
- * @brief Call func() on each proc
- *
- * @param func Callback
- * @param data Data for callback
- * @return Void
- */
-void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data)
-{
-       sspt_proc_read_lock();
-       on_each_proc_no_lock(func, data);
-       sspt_proc_read_unlock();
-}
-EXPORT_SYMBOL_GPL(on_each_proc);
-
-/**
- * @brief Get sspt_proc by task or create sspt_proc
- *
- * @param task Pointer on the task_struct struct
- * @param priv Private data
- * @return Pointer on the sspt_proc struct
- */
-struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task)
-{
-       static DEFINE_MUTEX(local_mutex);
-       struct ktd_proc *kproc;
-       struct sspt_proc *proc;
-       struct task_struct *leader = task->group_leader;
-
-       kproc = kproc_by_task(leader);
-       if (kproc->proc)
-               goto out;
-
-       proc = sspt_proc_create(leader);
-
-       spin_lock(&kproc->lock);
-       if (kproc->proc == NULL) {
-               sspt_proc_get(proc);
-               kproc->proc = proc;
-               proc = NULL;
-
-               sspt_proc_write_lock();
-               list_add(&kproc->proc->list, &proc_probes_list);
-               sspt_proc_write_unlock();
-       }
-       spin_unlock(&kproc->lock);
-
-       if (proc)
-               sspt_proc_free(proc);
-
-out:
-       return kproc->proc;
-}
-
-/**
- * @brief Check sspt_proc on empty
- *
- * @return Pointer on the sspt_proc struct
- */
-void sspt_proc_check_empty(void)
-{
-       WARN_ON(!list_empty(&proc_probes_list));
-}
-
-static void sspt_proc_add_file(struct sspt_proc *proc, struct sspt_file *file)
-{
-       down_write(&proc->files.sem);
-       list_add(&file->list, &proc->files.head);
-       file->proc = proc;
-       up_write(&proc->files.sem);
-}
-
-/**
- * @brief Get sspt_file from sspt_proc by dentry or new
- *
- * @param proc Pointer on the sspt_proc struct
- * @param dentry Dentry of file
- * @return Pointer on the sspt_file struct
- */
-struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
-                                            struct dentry *dentry)
-{
-       struct sspt_file *file;
-
-       file = sspt_proc_find_file(proc, dentry);
-       if (file == NULL) {
-               file = sspt_file_create(dentry, 10);
-               if (file)
-                       sspt_proc_add_file(proc, file);
-       }
-
-       return file;
-}
-
-/**
- * @brief Get sspt_file from sspt_proc by dentry
- *
- * @param proc Pointer on the sspt_proc struct
- * @param dentry Dentry of file
- * @return Pointer on the sspt_file struct
- */
-struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
-                                     struct dentry *dentry)
-{
-       struct sspt_file *file;
-
-       down_read(&proc->files.sem);
-       list_for_each_entry(file, &proc->files.head, list) {
-               if (dentry == file->dentry)
-                       goto unlock;
-       }
-       file = NULL;
-
-unlock:
-       up_read(&proc->files.sem);
-
-       return file;
-}
-
-/**
- * @brief Install probes on the page to monitored process
- *
- * @param proc Pointer on the sspt_proc struct
- * @param page_addr Page address
- * @return Void
- */
-void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr)
-{
-       struct mm_struct *mm = proc->leader->mm;
-       struct vm_area_struct *vma;
-
-       vma = find_vma_intersection(mm, page_addr, page_addr + 1);
-       if (vma && check_vma(vma)) {
-               struct dentry *dentry = vma->vm_file->f_path.dentry;
-               struct sspt_file *file = sspt_proc_find_file(proc, dentry);
-               if (file) {
-                       sspt_file_set_mapping(file, vma);
-                       sspt_file_install(file);
-               }
-       }
-}
-
-/**
- * @brief Install probes to monitored process
- *
- * @param proc Pointer on the sspt_proc struct
- * @return Void
- */
-void sspt_proc_install(struct sspt_proc *proc)
-{
-       struct vm_area_struct *vma;
-       struct mm_struct *mm = proc->leader->mm;
-
-       proc->first_install = 1;
-
-       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if (check_vma(vma)) {
-                       struct dentry *dentry = vma->vm_file->f_path.dentry;
-                       struct sspt_file *file =
-                               sspt_proc_find_file(proc, dentry);
-                       if (file) {
-                               sspt_file_set_mapping(file, vma);
-                               sspt_file_install(file);
-                       }
-               }
-       }
-}
-
-/**
- * @brief Uninstall probes to monitored process
- *
- * @param proc Pointer on the sspt_proc struct
- * @param task Pointer on the task_struct struct
- * @param flag Action for probes
- * @return Error code
- */
-int sspt_proc_uninstall(struct sspt_proc *proc,
-                       struct task_struct *task,
-                       enum US_FLAGS flag)
-{
-       int err = 0;
-       struct sspt_file *file;
-
-       down_read(&proc->files.sem);
-       list_for_each_entry(file, &proc->files.head, list) {
-               err = sspt_file_uninstall(file, task, flag);
-               if (err != 0) {
-                       printk(KERN_INFO "ERROR sspt_proc_uninstall: err=%d\n",
-                              err);
-                       break;
-               }
-       }
-       up_read(&proc->files.sem);
-
-       return err;
-}
-
-static int intersection(unsigned long start_a, unsigned long end_a,
-                       unsigned long start_b, unsigned long end_b)
-{
-       return start_a < start_b ?
-                       end_a > start_b :
-                       start_a < end_b;
-}
-
-/**
- * @brief Get sspt_file list by region (remove sspt_file from sspt_proc list)
- *
- * @param proc Pointer on the sspt_proc struct
- * @param head[out] Pointer on the head list
- * @param start Region start
- * @param len Region length
- * @return Error code
- */
-int sspt_proc_get_files_by_region(struct sspt_proc *proc,
-                                 struct list_head *head,
-                                 unsigned long start, unsigned long end)
-{
-       int ret = 0;
-       struct sspt_file *file, *n;
-
-       down_write(&proc->files.sem);
-       list_for_each_entry_safe(file, n, &proc->files.head, list) {
-               if (intersection(file->vm_start, file->vm_end, start, end)) {
-                       ret = 1;
-                       list_move(&file->list, head);
-               }
-       }
-       up_write(&proc->files.sem);
-
-       return ret;
-}
-
-/**
- * @brief Insert sspt_file to sspt_proc list
- *
- * @param proc Pointer on the sspt_proc struct
- * @param head Pointer on the head list
- * @return Void
- */
-void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head)
-{
-       down_write(&proc->files.sem);
-       list_splice(head, &proc->files.head);
-       up_write(&proc->files.sem);
-}
-
-/**
- * @brief Add sspt_filter to sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @param pfg Pointer to pf_group struct
- * @return Void
- */
-void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg)
-{
-       struct sspt_filter *f;
-
-       f = sspt_filter_create(proc, pfg);
-       if (f)
-               list_add(&f->list, &proc->filters.head);
-}
-
-/**
- * @brief Remove sspt_filter from sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @param pfg Pointer to pf_group struct
- * @return Void
- */
-void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg)
-{
-       struct sspt_filter *fl, *tmp;
-
-       mutex_lock(&proc->filters.mtx);
-       list_for_each_entry_safe(fl, tmp, &proc->filters.head, list) {
-               if (fl->pfg == pfg) {
-                       list_del(&fl->list);
-                       sspt_filter_free(fl);
-               }
-       }
-       mutex_unlock(&proc->filters.mtx);
-}
-
-/**
- * @brief Remove all sspt_filters from sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @return Void
- */
-void sspt_proc_del_all_filters(struct sspt_proc *proc)
-{
-       struct sspt_filter *fl, *tmp;
-
-       mutex_lock(&proc->filters.mtx);
-       list_for_each_entry_safe(fl, tmp, &proc->filters.head, list) {
-               list_del(&fl->list);
-               sspt_filter_free(fl);
-       }
-       mutex_unlock(&proc->filters.mtx);
-}
-
-/**
- * @brief Check if sspt_filter is already in sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @param pfg Pointer to pf_group struct
- * @return Boolean
- */
-bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg)
-{
-       struct sspt_filter *fl;
-
-       list_for_each_entry(fl, &proc->filters.head, list)
-               if (fl->pfg == pfg)
-                       return false;
-
-       return true;
-}
-
-void sspt_proc_on_each_filter(struct sspt_proc *proc,
-                             void (*func)(struct sspt_filter *, void *),
-                             void *data)
-{
-       struct sspt_filter *fl;
-
-       list_for_each_entry(fl, &proc->filters.head, list)
-               func(fl, data);
-}
-
-void sspt_proc_on_each_ip(struct sspt_proc *proc,
-                         void (*func)(struct sspt_ip *, void *), void *data)
-{
-       struct sspt_file *file;
-
-       down_read(&proc->files.sem);
-       list_for_each_entry(file, &proc->files.head, list)
-               sspt_file_on_each_ip(file, func, data);
-       up_read(&proc->files.sem);
-}
-
-static void is_send_event(struct sspt_filter *f, void *data)
-{
-       bool *is_send = (bool *)data;
-
-       if (!*is_send && f->pfg_is_inst)
-               *is_send = !!pfg_msg_cb_get(f->pfg);
-}
-
-bool sspt_proc_is_send_event(struct sspt_proc *proc)
-{
-       bool is_send = false;
-
-       /* FIXME: add read lock (deadlock in sampler) */
-       sspt_proc_on_each_filter(proc, is_send_event, (void *)&is_send);
-
-       return is_send;
-}
-
-
-static struct sspt_proc_cb *proc_cb;
-
-int sspt_proc_cb_set(struct sspt_proc_cb *cb)
-{
-       if (cb && proc_cb)
-               return -EBUSY;
-
-       proc_cb = cb;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sspt_proc_cb_set);
-
-void sspt_proc_priv_create(struct sspt_proc *proc)
-{
-       if (proc_cb && proc_cb->priv_create)
-               proc->private_data = proc_cb->priv_create(proc);
-}
-
-void sspt_proc_priv_destroy(struct sspt_proc *proc)
-{
-       if (proc->first_install && proc_cb && proc_cb->priv_destroy)
-               proc_cb->priv_destroy(proc, proc->private_data);
-}
diff --git a/us_manager/sspt/sspt_proc.h b/us_manager/sspt/sspt_proc.h
deleted file mode 100644 (file)
index aaaa469..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-#ifndef __SSPT_PROC__
-#define __SSPT_PROC__
-
-/**
- * @file us_manager/sspt/sspt_proc.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include "sspt_file.h"
-
-struct slot_manager;
-struct task_struct;
-struct pf_group;
-struct sspt_filter;
-struct sspt_ip;
-
-/** Flags for sspt_*_uninstall() */
-enum US_FLAGS {
-       US_UNREGS_PROBE,        /**< probes remove and disarm */
-       US_DISARM,              /**< probes disarm */
-       US_UNINSTALL            /**< probes remove from list install */
-};
-
-/**
- * @struct sspt_proc
- * @breaf Image of process for specified process
- */
-struct sspt_proc {
-       struct list_head list;          /**< For global process list */
-
-       /* sspt_file */
-       struct {
-               struct rw_semaphore sem;/**< Semaphore for files list */
-               struct list_head head;  /**< For sspt_file */
-       } files;
-
-       pid_t tgid;                     /**< Thread group ID */
-       struct task_struct *leader;     /**< Ptr to the task leader */
-       struct mm_struct *__mm;
-       struct task_struct *__task;
-       struct slot_manager *sm;        /**< Ptr to the manager slot */
-
-       struct {
-               unsigned after_exec:1;
-               unsigned after_fork:1;
-       } suspect;
-
-       struct {
-               struct mutex mtx;       /**< Mutex for filter list */
-               struct list_head head;  /**< Filter head */
-       } filters;
-
-       unsigned first_install:1;       /**< Install flag */
-       struct sspt_feature *feature;   /**< Ptr to the feature */
-       atomic_t usage;
-
-       /* FIXME: for preload (remove those fields) */
-       unsigned long r_state_addr;     /**< address of r_state */
-       void *private_data;             /**< Process private data */
-};
-
-struct sspt_proc_cb {
-       void *(*priv_create)(struct sspt_proc *);
-       void (*priv_destroy)(struct sspt_proc *, void *);
-};
-
-
-struct list_head *sspt_proc_list(void);
-
-struct sspt_proc *sspt_proc_by_task(struct task_struct *task);
-struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task);
-struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task);
-struct sspt_proc *sspt_proc_get(struct sspt_proc *proc);
-void sspt_proc_put(struct sspt_proc *proc);
-void sspt_proc_cleanup(struct sspt_proc *proc);
-
-void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *),
-                         void *data);
-void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data);
-
-void sspt_proc_check_empty(void);
-
-struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
-                                     struct dentry *dentry);
-struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
-                                            struct dentry *dentry);
-void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr);
-void sspt_proc_install(struct sspt_proc *proc);
-int sspt_proc_uninstall(struct sspt_proc *proc,
-                       struct task_struct *task,
-                       enum US_FLAGS flag);
-
-int sspt_proc_get_files_by_region(struct sspt_proc *proc,
-                                 struct list_head *head,
-                                 unsigned long start, unsigned long end);
-void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head);
-
-void sspt_proc_read_lock(void);
-void sspt_proc_read_unlock(void);
-void sspt_proc_write_lock(void);
-void sspt_proc_write_unlock(void);
-
-void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg);
-void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg);
-void sspt_proc_del_all_filters(struct sspt_proc *proc);
-bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg);
-
-void sspt_proc_on_each_filter(struct sspt_proc *proc,
-                             void (*func)(struct sspt_filter *, void *),
-                             void *data);
-
-void sspt_proc_on_each_ip(struct sspt_proc *proc,
-                         void (*func)(struct sspt_ip *, void *), void *data);
-
-bool sspt_proc_is_send_event(struct sspt_proc *proc);
-
-int sspt_proc_cb_set(struct sspt_proc_cb *cb);
-void sspt_proc_priv_create(struct sspt_proc *proc);
-void sspt_proc_priv_destroy(struct sspt_proc *proc);
-
-void sspt_change_leader(struct task_struct *prev, struct task_struct *next);
-int sspt_proc_init(void);
-void sspt_proc_uninit(void);
-
-
-#endif /* __SSPT_PROC__ */
diff --git a/us_manager/us_common_file.h b/us_manager/us_common_file.h
deleted file mode 100644 (file)
index f18b6ce..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/us_manager_common_file.h
- *
- * 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, 2017
- *
- * 2017         Alexander Aksenov: SWAP us_manager implement
- *
- */
-
-#ifndef __US_MANAGER_COMMON_FILE_H__
-#define __US_MANAGER_COMMON_FILE_H__
-
-#include <linux/dcache.h>
-#include <linux/namei.h>
-
-static inline struct dentry *swap_get_dentry(const char *filepath)
-{
-       struct path path;
-       struct dentry *dentry = NULL;
-
-       if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) {
-               dentry = dget(path.dentry);
-               path_put(&path);
-       }
-
-       return dentry;
-}
-
-static inline void swap_put_dentry(struct dentry *dentry)
-{
-       dput(dentry);
-}
-
-#endif /* __US_MANAGER_COMMON_FILE_H__ */
diff --git a/us_manager/us_manager.c b/us_manager/us_manager.c
deleted file mode 100644 (file)
index e6101b9..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/us_manager.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/stop_machine.h>
-#include "pf/pf_group.h"
-#include "sspt/sspt_proc.h"
-#include "probes/probe_info_new.h"
-#include "helper.h"
-#include "us_manager.h"
-#include "debugfs_us_manager.h"
-#include "callbacks.h"
-#include <writer/event_filter.h>
-#include <master/swap_initializer.h>
-
-
-static DEFINE_MUTEX(mutex_inst);
-static enum status_type status = ST_OFF;
-
-
-static int __do_usm_stop(void *data)
-{
-       get_all_procs();
-
-       return 0;
-}
-
-static void do_usm_stop(void)
-{
-       int ret;
-
-       exec_cbs(STOP_CB);
-       helper_unreg_top();
-
-       ret = stop_machine(__do_usm_stop, NULL, NULL);
-       if (ret)
-               printk("do_usm_stop failed: %d\n", ret);
-
-       uninstall_all();
-       helper_unreg_bottom();
-       sspt_proc_check_empty();
-}
-
-static int do_usm_start(void)
-{
-       int ret;
-
-       ret = helper_reg();
-       if (ret)
-               return ret;
-
-       install_all();
-
-       exec_cbs(START_CB);
-
-       return 0;
-}
-
-/**
- * @brief Get instrumentation status
- *
- * @return Instrumentation status
- */
-enum status_type usm_get_status(void)
-{
-       mutex_lock(&mutex_inst);
-       return status;
-}
-EXPORT_SYMBOL_GPL(usm_get_status);
-
-/**
- * @brief Put instrumentation status
- *
- * @param st Instrumentation status
- * @return Void
- */
-void usm_put_status(enum status_type st)
-{
-       status = st;
-       mutex_unlock(&mutex_inst);
-}
-EXPORT_SYMBOL_GPL(usm_put_status);
-
-/**
- * @brief Stop instrumentation
- *
- * @return Error code
- */
-int usm_stop(void)
-{
-       int ret = 0;
-
-       if (usm_get_status() == ST_OFF) {
-               printk(KERN_INFO "US instrumentation is not running!\n");
-               ret = -EINVAL;
-               goto put;
-       }
-
-       do_usm_stop();
-
-put:
-       usm_put_status(ST_OFF);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usm_stop);
-
-/**
- * @brief Start instrumentation
- *
- * @return Error code
- */
-int usm_start(void)
-{
-       int ret = -EINVAL;
-       enum status_type st;
-
-       st = usm_get_status();
-       if (st == ST_ON) {
-               printk(KERN_INFO "US instrumentation is already run!\n");
-               goto put;
-       }
-
-       ret = do_usm_start();
-       if (ret == 0)
-               st = ST_ON;
-
-put:
-       usm_put_status(st);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usm_start);
-
-
-
-
-
-/* ============================================================================
- * ===                                QUIET                                 ===
- * ============================================================================
- */
-static enum quiet_type quiet = QT_ON;
-
-/**
- * @brief Set quiet mode
- *
- * @param q Quiet mode
- * @return Void
- */
-void set_quiet(enum quiet_type q)
-{
-       quiet = q;
-}
-EXPORT_SYMBOL_GPL(set_quiet);
-
-/**
- * @brief Get quiet mode
- *
- * @return Quiet mode
- */
-enum quiet_type get_quiet(void)
-{
-       return quiet;
-}
-EXPORT_SYMBOL_GPL(get_quiet);
-
-
-
-
-
-/* ============================================================================
- * ===                              US_FILTER                               ===
- * ============================================================================
- */
-static int us_filter(struct task_struct *task)
-{
-       struct sspt_proc *proc;
-
-       /* FIXME: add read lock (deadlock in sampler) */
-       proc = sspt_proc_by_task(task);
-       if (proc)
-               return sspt_proc_is_send_event(proc);
-
-       return 0;
-}
-
-static struct ev_filter ev_us_filter = {
-       .name = "traced_process_only",
-       .filter = us_filter
-};
-
-static int init_us_filter(void)
-{
-       int ret;
-
-       ret = event_filter_register(&ev_us_filter);
-       if (ret)
-               return ret;
-
-       return event_filter_set(ev_us_filter.name);
-}
-
-static void exit_us_filter(void)
-{
-       event_filter_unregister(&ev_us_filter);
-}
-
-
-
-
-
-static int usm_once(void)
-{
-       int ret;
-
-       ret = helper_once();
-
-       return ret;
-}
-
-static int init_us_manager(void)
-{
-       int ret;
-
-       ret = helper_init();
-       if (ret)
-               return ret;
-
-       ret = sspt_proc_init();
-       if (ret)
-               goto uninit_helper;
-
-       ret = pin_init();
-       if (ret)
-               goto uninit_proc;
-
-       ret = init_us_filter();
-       if (ret)
-               goto uninit_pin;
-
-       return 0;
-
-uninit_pin:
-       pin_exit();
-uninit_proc:
-       sspt_proc_uninit();
-uninit_helper:
-       helper_uninit();
-
-       return ret;
-}
-
-static void exit_us_manager(void)
-{
-       if (status == ST_ON)
-               BUG_ON(usm_stop());
-
-       remove_all_cbs();
-
-       exit_us_filter();
-       pin_exit();
-       sspt_proc_uninit();
-       helper_uninit();
-
-       WARN_ON(!pfg_is_unloadable());
-}
-
-SWAP_LIGHT_INIT_MODULE(usm_once, init_us_manager, exit_us_manager,
-                      init_debugfs_us_manager, exit_debugfs_us_manager);
-
-MODULE_LICENSE("GPL");
diff --git a/us_manager/us_manager.h b/us_manager/us_manager.h
deleted file mode 100644 (file)
index f1bf081..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file us_manager/us_manager.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-#ifndef _US_MANAGER_H
-#define _US_MANAGER_H
-
-
-/** Quiet mode */
-enum quiet_type {
-       QT_ON,          /**< Quiet mode - on */
-       QT_OFF          /**< Quiet mode - off */
-};
-
-/** Instrumentation status */
-enum status_type {
-       ST_OFF,         /**< Instrumentation status - off */
-       ST_ON           /**< Instrumentation status - on */
-};
-
-void set_quiet(enum quiet_type q);
-enum quiet_type get_quiet(void);
-
-enum status_type usm_get_status(void);
-void usm_put_status(enum status_type st);
-
-int usm_start(void);
-int usm_stop(void);
-
-#endif /* _US_MANAGER_H */
diff --git a/us_manager/us_manager_common.h b/us_manager/us_manager_common.h
deleted file mode 100644 (file)
index 4400e31..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/us_slot_manager.c
- *
- * 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, 2013
- *
- * 2013         Alexander Aksenov: SWAP us_manager implement
- *
- */
-
-
-#include <linux/mm.h>
-#include <linux/version.h>
-
-/*
- * TODO: move declaration and definition swap_do_mmap_pgoff()
- *       from swap_kprobe.ko to swap_us_manager.ko
- */
-#include <kprobe/swap_kprobes_deps.h>
-
-
-static inline unsigned long __swap_do_mmap(struct file *filp,
-                                          unsigned long addr,
-                                          unsigned long len,
-                                          unsigned long prot,
-                                          unsigned long flag,
-                                          unsigned long offset)
-{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 3, 0)
-       unsigned long populate;
-
-       return swap_do_mmap(filp, addr, len, prot,
-                                 flag, 0, offset, &populate);
-
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
-       unsigned long populate;
-
-       return swap_do_mmap_pgoff(filp, addr, len, prot,
-                                 flag, offset, &populate);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-       return swap_do_mmap_pgoff(filp, addr, len, prot, flag, offset);
-#else
-       return do_mmap(filp, addr, len, prot, flag, offset);
-#endif
-}
diff --git a/us_manager/us_slot_manager.c b/us_manager/us_slot_manager.c
deleted file mode 100644 (file)
index 56e8f28..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *  SWAP uprobe manager
- *  modules/us_manager/us_slot_manager.c
- *
- * 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, 2013
- *
- * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/hardirq.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/list.h>
-
-#include <kprobe/swap_slots.h>
-#include <swap-asm/swap_kprobes.h>
-#include <swap-asm/swap_uprobes.h>
-#include "us_manager_common.h"
-
-
-static void *sm_alloc_us(struct slot_manager *sm)
-{
-       unsigned long addr;
-
-       addr = __swap_do_mmap(NULL, 0, PAGE_SIZE,
-                             PROT_EXEC | PROT_READ | PROT_WRITE,
-                             MAP_ANONYMOUS | MAP_PRIVATE, 0);
-       return (void *)addr;
-}
-
-static void sm_free_us(struct slot_manager *sm, void *ptr)
-{
-       /*
-        * E. G.: This code provides kernel dump because of rescheduling while
-        * atomic. As workaround, this code was commented. In this case we will
-        * have memory leaks for instrumented process, but instrumentation
-        * process should functionate correctly. Planned that good solution for
-        * this problem will be done during redesigning KProbe for improving
-        * supportability and performance.
-        */
-#if 0
-       struct task_struct *task = sm->data;
-
-       mm = get_task_mm(task);
-       if (mm) {
-               down_write(&mm->mmap_sem);
-               do_munmap(mm, (unsigned long)(ptr), PAGE_SIZE);
-               up_write(&mm->mmap_sem);
-               mmput(mm);
-       }
-#endif
-       /* FIXME: implement the removal of memory for task */
-}
-
-/**
- * @brief Create slot_manager struct for US
- *
- * @param task Pointer to the task_struct struct
- * @return Pointer to the created slot_manager struct
- */
-struct slot_manager *create_sm_us(struct task_struct *task)
-{
-       struct slot_manager *sm = kmalloc(sizeof(*sm), GFP_ATOMIC);
-
-       if (sm == NULL)
-               return NULL;
-
-       sm->slot_size = UPROBES_TRAMP_LEN;
-       sm->alloc = sm_alloc_us;
-       sm->free = sm_free_us;
-       INIT_HLIST_HEAD(&sm->page_list);
-       sm->data = task;
-
-       return sm;
-}
-
-/**
- * @brief Remove slot_manager struct for US
- *
- * @param sm remove object
- * @return Void
- */
-void free_sm_us(struct slot_manager *sm)
-{
-       if (sm == NULL)
-               return;
-
-       if (!hlist_empty(&sm->page_list)) {
-               printk(KERN_WARNING "SWAP US_MANAGER: Error! Slot manager is "
-                                   "not empty!\n");
-               return;
-       }
-
-       kfree(sm);
-}
diff --git a/us_manager/us_slot_manager.h b/us_manager/us_slot_manager.h
deleted file mode 100644 (file)
index 144d4a4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @file us_manager/us_slot_manager.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- */
-
-
-#ifndef _US_SLOT_MANAGER_H
-#define _US_SLOT_MANAGER_H
-
-struct task_struct;
-struct slot_manager;
-
-struct slot_manager *create_sm_us(struct task_struct *task);
-void free_sm_us(struct slot_manager *sm);
-
-#endif /* _US_SLOT_MANAGER_H */
diff --git a/us_manager/usm_hook.c b/us_manager/usm_hook.c
deleted file mode 100644 (file)
index c41fd94..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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, 2017
- *
- * 2017         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/rwsem.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <kprobe/swap_kprobes_deps.h> // for swap_hlist_for_each_entry
-#include "usm_hook.h"
-
-
-static HLIST_HEAD(hook_head);
-static DECLARE_RWSEM(hook_sem);
-
-
-int usm_hook_reg(struct usm_hook *hook)
-{
-       if (!try_module_get(hook->owner))
-               return -ENODEV;
-
-       INIT_HLIST_NODE(&hook->node);
-
-       down_write(&hook_sem);
-       hlist_add_head(&hook->node, &hook_head);
-       up_write(&hook_sem);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(usm_hook_reg);
-
-void usm_hook_unreg(struct usm_hook *hook)
-{
-       down_write(&hook_sem);
-       hlist_del(&hook->node);
-       up_write(&hook_sem);
-
-       module_put(hook->owner);
-}
-EXPORT_SYMBOL_GPL(usm_hook_unreg);
-
-void usm_hook_mmap(struct sspt_proc *proc, struct vm_area_struct *vma)
-{
-       struct usm_hook *hook;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       down_read(&hook_sem);
-       swap_hlist_for_each_entry(hook, node, &hook_head, node) {
-               if (hook->mmap)
-                       hook->mmap(proc, vma);
-       }
-       up_read(&hook_sem);
-}
diff --git a/us_manager/usm_hook.h b/us_manager/usm_hook.h
deleted file mode 100644 (file)
index 132b337..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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, 2017
- *
- * 2017         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_USM_HOOK_H
-#define _SWAP_USM_HOOK_H
-
-
-#include <linux/list.h>
-
-
-struct module;
-struct sspt_proc;
-struct vm_area_struct;
-
-
-struct usm_hook {
-       struct hlist_node node;
-       struct module *owner;
-
-       /*
-        * mmap hook called only for vma which we can instrument
-        * (e.g. vma->vm_file is already validate)
-        */
-       void (*mmap)(struct sspt_proc *proc, struct vm_area_struct *vma);
-};
-
-
-int usm_hook_reg(struct usm_hook *hook);
-void usm_hook_unreg(struct usm_hook *hook);
-
-
-/* private interface */
-void usm_hook_mmap(struct sspt_proc *proc, struct vm_area_struct *vma);
-
-
-#endif /* _SWAP_USM_HOOK_H */
-
diff --git a/writer/Kbuild b/writer/Kbuild
deleted file mode 100644 (file)
index 1c938cf..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-KBUILD_EXTRA_SYMBOLS = $(src)/../buffer/Module.symvers \
-                       $(src)/../driver/Module.symvers
-
-obj-m := swap_writer.o
-swap_writer-y := swap_writer_module.o \
-                 debugfs_writer.o \
-                 event_filter.o \
-                 swap_msg.o
-
diff --git a/writer/debugfs_writer.c b/writer/debugfs_writer.c
deleted file mode 100644 (file)
index a79e9b6..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/**
- * writer/debugfs_writer.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- * Writer debugfs implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <master/swap_debugfs.h>
-#include <master/swap_initializer.h>
-#include "swap_msg.h"
-#include "event_filter.h"
-
-
-/* ============================================================================
- * ===                               BUFFER                                 ===
- * ============================================================================
- */
-static char *common_buf;
-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();
-}
-
-
-
-
-
-/* ============================================================================
- * ===                             FOPS_RAW                                 ===
- * ============================================================================
- */
-static ssize_t write_raw(struct file *file, const char __user *user_buf,
-                        size_t count, loff_t *ppos)
-{
-       int ret;
-       void *buf;
-
-       if (count > subbuf_size)
-               return -EINVAL;
-
-       buf = get_current_buf();
-       if (copy_from_user(buf, user_buf, count)) {
-               ret = -EFAULT;
-               goto put_buf;
-       }
-
-       ret = swap_msg_raw(buf, count);
-
-put_buf:
-       put_current_buf();
-       return ret;
-}
-
-static const struct file_operations fops_raw = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .write =        write_raw,
-       .llseek =       default_llseek
-};
-
-
-
-
-
-/* ============================================================================
- * ===                        FOPS_AVAILABLE_FILTERS                        ===
- * ============================================================================
- */
-struct read_buf {
-       char *begin;
-       char *ptr;
-       char *end;
-};
-
-static void func_for_read(struct ev_filter *f, void *data)
-{
-       struct read_buf *rbuf = (struct read_buf *)data;
-       int len = strlen(f->name);
-
-       if (rbuf->end - rbuf->ptr < len + 2)
-               return;
-
-       if (rbuf->ptr != rbuf->begin) {
-               *rbuf->ptr = ' ';
-               ++rbuf->ptr;
-       }
-
-       memcpy(rbuf->ptr, f->name, len);
-       rbuf->ptr += len;
-}
-
-static ssize_t read_af(struct file *file, char __user *user_buf,
-                      size_t count, loff_t *ppos)
-{
-       char buf[512];
-       struct read_buf rbuf = {
-               .begin = buf,
-               .ptr = buf,
-               .end = buf + sizeof(buf)
-       };
-
-       event_filter_on_each(func_for_read, (void *)&rbuf);
-
-       *rbuf.ptr = '\n';
-       ++rbuf.ptr;
-
-       return simple_read_from_buffer(user_buf, count, ppos,
-                                      rbuf.begin, rbuf.ptr - rbuf.begin);
-}
-
-static const struct file_operations fops_available_filters = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .read =         read_af,
-       .llseek =       default_llseek
-};
-
-
-
-
-
-/* ============================================================================
- * ===                              FOPS_FILTER                             ===
- * ============================================================================
- */
-static ssize_t read_filter(struct file *file, char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       const char *name = event_filter_get();
-       int len = strlen(name);
-       char *buf;
-       ssize_t ret;
-
-       buf = kmalloc(len + 2, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
-
-       memcpy(buf, name, len);
-       buf[len] = '\0';
-       buf[len + 1] = '\n';
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, len + 2);
-       kfree(buf);
-
-       return ret;
-}
-
-static ssize_t write_filter(struct file *file, const char __user *user_buf,
-                       size_t count, loff_t *ppos)
-{
-       enum { len = 32 };
-       char buf[len], name[len];
-       size_t buf_size;
-       ssize_t ret;
-
-       buf_size = min(count, (size_t)(len - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       buf[len - 1] = '\0';
-       ret = sscanf(buf, "%31s", name);
-       if (ret != 1)
-               return -EINVAL;
-
-       ret = event_filter_set(name);
-       if (ret)
-               return -EINVAL;
-
-       return count;
-}
-
-static const struct file_operations fops_filter = {
-       .owner = THIS_MODULE,
-       .open = swap_init_simple_open,
-       .release = swap_init_simple_release,
-       .read =         read_filter,
-       .write =        write_filter,
-       .llseek =       default_llseek
-};
-
-
-
-
-
-/* ============================================================================
- * ===                              INIT/EXIT                               ===
- * ============================================================================
- */
-static struct dentry *writer_dir;
-
-/**
- * @brief Removes writer debugfs.
- *
- * @return Void.
- */
-void exit_debugfs_writer(void)
-{
-       if (writer_dir)
-               debugfs_remove_recursive(writer_dir);
-
-       writer_dir = NULL;
-
-       exit_buffer();
-}
-
-/**
- * @brief Initializes writer debugfs.
- *
- * @return 0 on success, error code on error.
- */
-int init_debugfs_writer(void)
-{
-       int ret;
-       struct dentry *swap_dir, *dentry;
-
-       ret = init_buffer();
-       if (ret)
-               return ret;
-
-       swap_dir = swap_debugfs_getdir();
-       if (swap_dir == NULL)
-               return -ENOENT;
-
-       writer_dir = swap_debugfs_create_dir("writer", swap_dir);
-       if (writer_dir == NULL)
-               return -ENOMEM;
-
-       dentry = swap_debugfs_create_file("raw", 0600, writer_dir,
-                                         NULL, &fops_raw);
-       if (dentry == NULL)
-               goto fail;
-
-       dentry = swap_debugfs_create_file("available_filters", 0600, writer_dir,
-                                         NULL, &fops_available_filters);
-       if (dentry == NULL)
-               goto fail;
-
-       dentry = swap_debugfs_create_file("filter", 0600, writer_dir,
-                                         NULL, &fops_filter);
-       if (dentry == NULL)
-               goto fail;
-
-       return 0;
-
-fail:
-       exit_debugfs_writer();
-       return -ENOMEM;
-}
diff --git a/writer/debugfs_writer.h b/writer/debugfs_writer.h
deleted file mode 100644 (file)
index d5e1fc3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @file writer/debugfs_writer.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- * Writer debugfs interface declaration.
- */
-
-#ifndef _DEBUGFS_WRITER_H
-#define _DEBUGFS_WRITER_H
-
-int init_debugfs_writer(void);
-void exit_debugfs_writer(void);
-
-#endif /* _DEBUGFS_WRITER_H */
diff --git a/writer/event_filter.c b/writer/event_filter.c
deleted file mode 100644 (file)
index 2496110..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * writer/event_filter.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- * Events filter.
- */
-
-
-#include <linux/module.h>
-#include <linux/list.h>
-#include "event_filter.h"
-
-
-static LIST_HEAD(filter_list);
-
-static int func_none(struct task_struct *task)
-{
-       return 1;
-}
-
-static struct ev_filter filter_none = {
-       .name = "all",
-       .filter = func_none
-};
-
-static struct ev_filter *filter_current = &filter_none;
-
-int check_event(struct task_struct *task)
-{
-       return filter_current->filter(task);
-}
-EXPORT_SYMBOL_GPL(check_event);
-
-static struct ev_filter *event_filter_find(const char *name)
-{
-       struct ev_filter *f, *tmp;
-
-       list_for_each_entry_safe(f, tmp, &filter_list, list) {
-               if (strcmp(f->name, name) == 0)
-                       return f;
-       }
-
-       return NULL;
-}
-
-/**
- * @brief Registers event filter.
- *
- * @param f Pointer to the event filter.
- * @return 0 on success, error code on error.
- */
-int event_filter_register(struct ev_filter *f)
-{
-       if (event_filter_find(f->name))
-               return -EINVAL;
-
-       INIT_LIST_HEAD(&f->list);
-       list_add(&f->list, &filter_list);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(event_filter_register);
-
-/**
- * @brief Unregisters event filter.
- *
- * @param f Pointer to the event filter.
- * @return Void.
- */
-void event_filter_unregister(struct ev_filter *f)
-{
-       struct ev_filter *filter, *tmp;
-
-       if (filter_current == f)
-               filter_current = &filter_none;
-
-       list_for_each_entry_safe(filter, tmp, &filter_list, list) {
-               if (filter == f) {
-                       list_del(&filter->list);
-                       break;
-               }
-       }
-}
-EXPORT_SYMBOL_GPL(event_filter_unregister);
-
-/**
- * @brief Sets event filter by its name.
- *
- * @param name Filter name.
- * @return 0 on success, error code on error.
- */
-int event_filter_set(const char *name)
-{
-       struct ev_filter *f;
-
-       f = event_filter_find(name);
-       if (f == NULL)
-               return -EINVAL;
-
-       filter_current = f;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(event_filter_set);
-
-/**
- * @brief Gets filter name.
- *
- * @return Pointer to the filter name string.
- */
-const char *event_filter_get(void)
-{
-       return filter_current->name;
-}
-
-/**
- * @brief Runs specified callback for each filter in list.
- *
- * @param func Specified callback.
- * @param data Pointer to the data passed to the callback.
- * @return Void.
- */
-void event_filter_on_each(void (*func)(struct ev_filter *, void *),
-                         void *data)
-{
-       struct ev_filter *f, *tmp;
-
-       list_for_each_entry_safe(f, tmp, &filter_list, list)
-               func(f, data);
-}
-
-/**
- * @brief Initializes event filter.
- *
- * @return Initialization result.
- */
-int event_filter_init(void)
-{
-       return event_filter_register(&filter_none);
-}
-
-/**
- * @brief Uninitializes event filter.
- *
- * @return Void.
- */
-void event_filter_exit(void)
-{
-       event_filter_unregister(&filter_none);
-}
diff --git a/writer/event_filter.h b/writer/event_filter.h
deleted file mode 100644 (file)
index 1b420eb..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * @file writer/event_filter.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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
- *
- * Event filter interface declaration.
- */
-
-
-#ifndef _EVENT_FILTER_H
-#define _EVENT_FILTER_H
-
-
-#include <linux/list.h>
-
-struct task_struct;
-
-/**
- * @struct ev_filter
- * @bref Event filter structure.
- */
-struct ev_filter {
-       struct list_head list;                  /**< Filter list head. */
-       char *name;                             /**< Filter name. */
-       int (*filter)(struct task_struct *);    /**< Filter function. */
-};
-
-
-int check_event(struct task_struct *task);
-
-int event_filter_register(struct ev_filter *f);
-void event_filter_unregister(struct ev_filter *f);
-int event_filter_set(const char *name);
-const char *event_filter_get(void);
-
-void event_filter_on_each(void (*func)(struct ev_filter *, void *),
-                         void *data);
-
-int event_filter_init(void);
-void event_filter_exit(void);
-
-#endif /* _EVENT_FILTER_H */
diff --git a/writer/kernel_operations.h b/writer/kernel_operations.h
deleted file mode 100644 (file)
index b2bf043..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * @file writer/kernel_operations.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Writer kernel operations.
- */
-
-/* Kernel functions wrap */
-
-#ifndef __KERNEL_OPERATIONS_H__
-#define __KERNEL_OPERATIONS_H__
-
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
-#include <asm/ptrace.h>
-
-
-/* ARCH-DEPENDED OPERATIONS */
-
-
-/* Regs manipulations */
-#if defined(CONFIG_ARM)
-
-#define get_regs_ret_func(regs)     (regs->ARM_lr)    /**< Get lr reg. */
-#define get_regs_ret_val(regs)      (regs->ARM_r0)    /**< Get ret val. */
-#define get_regs_stack_ptr(regs)    (regs->ARM_sp)    /**< Get stack pointer. */
-
-#elif defined(CONFIG_X86_32)
-
-#define get_regs_ret_val(regs)      (regs->ax)        /**< Get ret val. */
-#define get_regs_stack_ptr(regs)    (regs->sp)        /**< Get stack pointer. */
-
-static inline u32 get_regs_ret_func(struct pt_regs *regs)
-{
-       u32 *sp, addr = 0;
-
-       if (user_mode(regs)) {
-               sp = (u32 *)regs->sp;
-               if (get_user(addr, sp))
-                       pr_info("failed to dereference a pointer, sp=%p, "
-                               "pc=%lx\n", sp, regs->ip - 1);
-       } else {
-               sp = (u32 *)kernel_stack_pointer(regs);
-               addr = *sp;
-       }
-
-       return addr;
-}
-
-#elif defined(CONFIG_ARM64)
-
-static inline u64 get_regs_ret_func(struct pt_regs *regs)
-{
-       if (compat_user_mode(regs))
-               return regs->compat_lr;
-       else
-               return regs->regs[30];
-}
-
-#endif /* CONFIG_arch */
-
-#endif /* __KERNEL_OPERATIONS_H__ */
diff --git a/writer/swap_msg.c b/writer/swap_msg.c
deleted file mode 100644 (file)
index cf20fd6..0000000
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/ctype.h>
-#include <linux/errno.h>
-#include <linux/atomic.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/spinlock.h>
-#include <buffer/swap_buffer_module.h>
-#include <swap-asm/swap_kprobes.h>
-#include <swap-asm/swap_uprobes.h>
-#include "swap_msg.h"
-
-
-#define MSG_PREFIX     "[SWAP_MSG] "
-
-
-/* simple buffer */
-struct sb_struct {
-       size_t subbuf_size;
-
-       size_t count;
-       void *data;
-};
-
-static int sb_init(struct sb_struct *sb, size_t count, size_t subbuf_size)
-{
-       sb->data = vmalloc(count * subbuf_size);
-       if (!sb->data)
-               return -ENOMEM;
-
-       sb->count = count;
-       sb->subbuf_size = subbuf_size;
-
-       return 0;
-}
-
-static void sb_uninit(struct sb_struct *sb)
-{
-       vfree(sb->data);
-}
-
-static void *sb_data(struct sb_struct *sb, size_t idx)
-{
-       return sb->data + sb->subbuf_size * idx;
-}
-
-static size_t sb_idx(struct sb_struct *sb, void *data)
-{
-       return (data - sb->data) / sb->subbuf_size;
-}
-
-static bool sb_contains(struct sb_struct *sb, void *data)
-{
-       void *begin = sb->data;
-       void *end = sb->data + sb->count * sb->subbuf_size;
-
-       return data >= begin && data < end;
-}
-
-static size_t sb_count(struct sb_struct *sb)
-{
-       return sb->count;
-}
-
-
-/* pool buffer */
-struct pb_struct {
-       spinlock_t lock;
-       size_t free_first;
-       size_t free_count;
-
-       struct sb_struct buf;
-};
-
-static void *pb_data(struct pb_struct *pb, size_t idx)
-{
-       return sb_data(&pb->buf, idx);
-}
-
-static size_t pb_idx(struct pb_struct *pb, void *data)
-{
-       return sb_idx(&pb->buf, data);
-}
-
-static void pb_val_set(struct pb_struct *pb, size_t idx, size_t val)
-{
-       *(size_t *)pb_data(pb, idx) = val;
-}
-
-static size_t pb_val_get(struct pb_struct *pb, size_t idx)
-{
-       return *(size_t *)pb_data(pb, idx);
-}
-
-static int pb_init(struct pb_struct *pb, size_t count, size_t subbuf_size)
-{
-       int ret;
-       size_t idx;
-
-       ret = sb_init(&pb->buf, count, subbuf_size);
-       if (ret)
-               return ret;
-
-       spin_lock_init(&pb->lock);
-       pb->free_first = 0;
-       pb->free_count = count;
-
-       for (idx = 0; idx < count; ++idx)
-               pb_val_set(pb, idx, idx + 1);
-
-       return 0;
-}
-
-static void pb_uninit(struct pb_struct *pb)
-{
-       WARN(sb_count(&pb->buf) != pb->free_count,
-            "count=%zu free_conut=%zu\n", sb_count(&pb->buf), pb->free_count);
-
-       sb_uninit(&pb->buf);
-}
-
-static void *pb_buf_get(struct pb_struct *pb)
-{
-       void *data;
-       unsigned long flags;
-
-       if (!pb->free_count)
-               return NULL;
-
-       spin_lock_irqsave(&pb->lock, flags);
-       data = pb_data(pb, pb->free_first);
-       pb->free_first = pb_val_get(pb, pb->free_first);
-       --pb->free_count;
-       spin_unlock_irqrestore(&pb->lock, flags);
-
-       return data;
-}
-
-static void pb_buf_put(struct pb_struct *pb, void *data)
-{
-       unsigned long flags;
-       size_t idx = pb_idx(pb, data);
-
-       spin_lock_irqsave(&pb->lock, flags);
-       pb_val_set(pb, idx, pb->free_first);
-       pb->free_first = idx;
-       ++pb->free_count;
-       spin_unlock_irqrestore(&pb->lock, flags);
-}
-
-
-struct swap_msg {
-       u32 msg_id;
-       u32 seq_num;
-       u64 time;
-       u32 len;
-       char payload[0];
-} __packed;
-
-
-static struct sb_struct cpu_buf;
-static struct pb_struct pool_buffer;
-static atomic_t seq_num = ATOMIC_INIT(-1);
-static atomic_t discarded = ATOMIC_INIT(0);
-
-
-int swap_msg_init(void)
-{
-       int ret;
-
-       ret = sb_init(&cpu_buf, NR_CPUS, SWAP_MSG_BUF_SIZE);
-       if (ret) {
-               pr_err(MSG_PREFIX "Cannot init cpu_buf, ret=%d\n", ret);
-               return ret;
-       }
-
-       ret = pb_init(&pool_buffer, NR_CPUS * 32, SWAP_MSG_BUF_SIZE);
-       if (ret) {
-               sb_uninit(&cpu_buf);
-               pr_err(MSG_PREFIX "Cannot init ring_buffer, ret=%d\n", ret);
-       }
-
-       return ret;
-}
-
-void swap_msg_exit(void)
-{
-       pb_uninit(&pool_buffer);
-       sb_uninit(&cpu_buf);
-}
-
-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 swap_msg *m;
-
-       m = pb_buf_get(&pool_buffer);
-       if (!m)
-               m = sb_data(&cpu_buf, get_cpu());
-
-       m->msg_id = (u32)id;
-       m->seq_num = atomic_inc_return(&seq_num);
-       m->time = swap_msg_current_time();
-
-       return m;
-}
-EXPORT_SYMBOL_GPL(swap_msg_get);
-
-static int __swap_msg_flush(struct swap_msg *m, size_t size, bool wakeup)
-{
-       if (unlikely(size >= SWAP_MSG_PAYLOAD_SIZE))
-               return -ENOMEM;
-
-       m->len = size;
-
-       if (swap_buffer_write(m, SWAP_MSG_PRIV_DATA + size, wakeup) !=
-           (SWAP_MSG_PRIV_DATA + size)) {
-               atomic_inc(&discarded);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int swap_msg_flush(struct swap_msg *m, size_t size)
-{
-       return __swap_msg_flush(m, size, true);
-}
-EXPORT_SYMBOL_GPL(swap_msg_flush);
-
-int swap_msg_flush_wakeupoff(struct swap_msg *m, size_t size)
-{
-       return __swap_msg_flush(m, size, false);
-}
-EXPORT_SYMBOL_GPL(swap_msg_flush_wakeupoff);
-
-void swap_msg_put(struct swap_msg *m)
-{
-       if (unlikely(sb_contains(&cpu_buf, m)))
-               put_cpu();
-       else
-               pb_buf_put(&pool_buffer, m);
-}
-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) */
-                       *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) */
-#ifdef CONFIG_ARM64
-                       if (len < 4)
-                               return -ENOMEM;
-
-                       tmp_u32 = (u32 *)buf;
-                       *tmp_u32 = swap_get_float(regs, i);
-                       buf += 4;
-                       len -= 4;
-                       break;
-#endif /* CONFIG_ARM64 */
-                       /* For others case f == d */
-               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;
-#ifdef CONFIG_ARM64
-                       *tmp_u64 = swap_get_double(regs, i);
-#else /* CONFIG_ARM64 */
-                       *tmp_u64 = get_arg(regs, i);
-                       ++i;
-                       *tmp_u64 |= (u64)get_arg(regs, i) << 32;
-#endif /* CONFIG_ARM64 */
-                       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) {
-               pr_err(MSG_PREFIX "ERROR: message RAW small size=%zu\n", size);
-               return -EINVAL;
-       }
-
-       if (m->len + sizeof(*m) != size) {
-               pr_err(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, true) != 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) {
-               pr_err(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
deleted file mode 100644 (file)
index 5d86f95..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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 <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_MSG_H
-#define _SWAP_MSG_H
-
-#include <linux/version.h>
-#include <linux/types.h>
-
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0)
-
-#include <linux/ktime.h>       /* Needed by timekeeping.h */
-#include <linux/timekeeping.h> /* Now getnstimeofday() is here */
-
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
-
-#include <linux/time.h>
-
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */
-
-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_PROCESS_STATUS_INFO         = 0x000e,
-       MSG_CONTEXT_SWITCH_ENTRY        = 0x0010,
-       MSG_CONTEXT_SWITCH_EXIT         = 0x0011,
-       MSG_PROC_MAP                    = 0x0012,
-       MSG_PROC_UNMAP                  = 0x0013,
-       MSG_PROC_COMM                   = 0x0014,
-       MSG_WEB_PROFILING               = 0x0015,
-       MSG_NSP                         = 0x0019,
-       MSG_WSP                         = 0x001a,
-       MSG_FBI                         = 0x0020
-};
-
-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;
-}
-
-static inline u64 swap_msg_current_time(void)
-{
-       struct timespec ts;
-       getnstimeofday(&ts);
-       return swap_msg_spec2time(&ts);
-}
-
-struct swap_msg *swap_msg_get(enum swap_msg_id id);
-int swap_msg_flush(struct swap_msg *m, size_t size);
-int swap_msg_flush_wakeupoff(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_errors.h b/writer/swap_writer_errors.h
deleted file mode 100644 (file)
index def1f47..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @file writer/swap_writer_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @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
- *
- * Writer module error codes.
- */
-
-#ifndef __SWAP_WRITER_ERRORS_H__
-#define __SWAP_WRITER_ERRORS_H__
-
-/**
- * @enum _swap_writer_errors
- * Error codes.
- */
-enum _swap_writer_errors {
-       E_SW_SUCCESS = 0                /**< Success. */
-};
-
-#endif /* __SWAP_WRITER_ERRORS_H__ */
diff --git a/writer/swap_writer_module.c b/writer/swap_writer_module.c
deleted file mode 100644 (file)
index f945a81..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * writer/swap_writer_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- * @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
- *
- * Packing and writing data.
- */
-
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "swap_msg.h"
-#include "event_filter.h"
-#include "debugfs_writer.h"
-
-
-static int core_init(void)
-{
-       int ret;
-
-       ret = swap_msg_init();
-       if (ret)
-               return ret;
-
-       ret = event_filter_init();
-       if (ret)
-               swap_msg_exit();
-
-       return ret;
-}
-
-static void core_exit(void)
-{
-       event_filter_exit();
-       swap_msg_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, core_init, core_exit,
-                      init_debugfs_writer, exit_debugfs_writer);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP Writer module");
-MODULE_AUTHOR("Cherkashin V., Aksenov A.S.");
diff --git a/wsp/Kbuild b/wsp/Kbuild
deleted file mode 100644 (file)
index 580bb29..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
-obj-m := swap_wsp.o
-swap_wsp-y := wsp_module.o \
-              wsp_msg.o \
-              wsp_debugfs.o \
-              wsp.o \
-              wsp_res.o
diff --git a/wsp/wsp.c b/wsp/wsp.c
deleted file mode 100644 (file)
index 66b8cbe..0000000
--- a/wsp/wsp.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <linux/string.h>
-#include <us_manager/sspt/sspt.h>
-#include <us_manager/probes/probe_info_new.h>
-#include "wsp.h"
-#include "wsp_res.h"
-#include "wsp_msg.h"
-
-struct wsp_probe {
-       const char *name;
-       struct probe_new probe;
-};
-
-struct wsp_bin {
-       const char *name;
-       unsigned long cnt;
-       struct wsp_probe *probe_array;
-};
-
-static char *webapp_path;
-static char *chromium_path;
-
-#define WSP_PROBE_MAKE(_name_, _offset_,  _desc_)      \
-{                                                      \
-       .name = (_name_),                               \
-       .probe.offset = (_offset_),                     \
-       .probe.desc = (_desc_)                          \
-}
-
-/*
- * res_request
- */
-/* blink::ResourceLoader.m_request.m_url */
-#define URL_OFFSET             84
-/* base::String.m_impl.m_ptr */
-#define URL_LEN_OFFSET         4
-#define URL_DATA_OFFSET                12
-
-static char *path_get_from_object(unsigned long ptr)
-{
-       char *path;
-       unsigned long url, len, ret;
-
-       get_user(url, (unsigned long __user *)(ptr + URL_OFFSET));
-       get_user(len, (unsigned long __user *)(url + URL_LEN_OFFSET));
-       path = kzalloc(len + 1, GFP_KERNEL);
-       if (!path)
-               return NULL;
-
-       ret = copy_from_user(path,
-                            (const void __user *)(url + URL_DATA_OFFSET),
-                            len);
-       if (ret) {
-               kfree(path);
-               path = NULL;
-       } else {
-               path[len] = '\0';
-       }
-
-       return path;
-}
-
-static int res_request_handle(struct uprobe *p, struct pt_regs *regs)
-{
-       unsigned long ptr;
-       char *path;
-
-       ptr = (unsigned long)swap_get_uarg(regs, 0);
-       path = path_get_from_object(ptr);
-       if (path) {
-               int id = wsp_resource_data_add(ptr, path);
-               if (id >= 0)
-                       wsp_msg(WSP_RES_LOAD_BEGIN, id, path);
-       }
-
-       return 0;
-}
-
-static struct probe_desc res_request = MAKE_UPROBE(res_request_handle);
-
-/*
- * res_finish
- */
-static int res_finish_ehandle(struct uretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       int id;
-       unsigned long ptr = (unsigned long)swap_get_uarg(regs, 0);
-
-       id = wsp_resource_data_id(ptr);
-       if (id >= 0) {
-               *(unsigned long *)ri->data = ptr;
-               wsp_msg(WSP_RES_PROC_BEGIN, id, NULL);
-       }
-
-       return 0;
-}
-
-static int res_finish_rhandle(struct uretprobe_instance *ri,
-                             struct pt_regs *regs)
-{
-       int id;
-       unsigned long ptr;
-
-       ptr = *(unsigned long *)ri->data;
-       id = wsp_resource_data_id(ptr);
-       if (id >= 0) {
-               wsp_msg(WSP_RES_PROC_END, id, NULL);
-               wsp_msg(WSP_RES_LOAD_END, id, NULL);
-               wsp_resource_data_del(ptr);
-       }
-
-       return 0;
-}
-
-static struct probe_desc res_finish =
-               MAKE_URPROBE(res_finish_ehandle, res_finish_rhandle,
-                            sizeof(unsigned long));
-
-/*
- * redraw
- */
-static int redraw_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       wsp_msg(WSP_DRAW_BEGIN, 0, NULL);
-
-       return 0;
-}
-
-static int redraw_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       wsp_msg(WSP_DRAW_END, 0, NULL);
-
-       return 0;
-}
-
-static struct probe_desc redraw = MAKE_URPROBE(redraw_eh, redraw_rh, 0);
-
-/* blink::ResourceLoader::start() */
-#define RES_REQ "_ZN5blink14ResourceLoader5startEv"
-/* blink::ResourceLoader::didFinishLoading(WebURLLoader*, double , int64_t) */
-#define RES_FINISH "_ZN5blink14ResourceLoader16didFinishLoadingEPNS_12WebURLLoaderEdx"
-
-/* content::RenderWidget::DidCommitAndDrawCompositorFrame */
-#define REDRAW "_ZN7content23CompositorOutputSurface11SwapBuffersEPN2cc15CompositorFrameE"
-
-static struct wsp_probe __probe_array[] = {
-       /* res */
-       WSP_PROBE_MAKE(RES_REQ, 0, &res_request),
-       WSP_PROBE_MAKE(RES_FINISH, 0, &res_finish),
-
-       /* redraw */
-       WSP_PROBE_MAKE(REDRAW, 0, &redraw),
-};
-
-static struct wsp_bin chromium_bin = {
-       .name = NULL,
-       .probe_array = __probe_array,
-       .cnt = ARRAY_SIZE(__probe_array)
-};
-
-/* check chromium_bin array on init address */
-static bool wsp_is_addr_init(void)
-{
-       int i;
-
-       for (i = 0; i < chromium_bin.cnt; ++i)
-               if (chromium_bin.probe_array[i].probe.offset == 0)
-                       return false;
-
-       return true;
-}
-
-static int wsp_bin_register(struct pf_group *pfg, struct wsp_bin *bin)
-{
-       int i, ret;
-       struct dentry *dentry;
-
-       dentry = dentry_by_path(bin->name);
-       if (!dentry) {
-               pr_err("dentry not found (path='%s'\n", bin->name);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < bin->cnt; ++i) {
-               struct wsp_probe *p = &bin->probe_array[i];
-
-               ret = pin_register(&p->probe, pfg, dentry);
-               if (ret) {
-                       pr_err("failed to register WSP probe (%lx:%d)\n",
-                              p->probe.offset, ret);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static void wsp_bin_unregister(struct pf_group *pfg, struct wsp_bin *bin)
-{
-       int i;
-       struct dentry *dentry;
-
-       dentry = dentry_by_path(bin->name);
-       if (!dentry) {
-               pr_err("dentry not found (path='%s'\n", bin->name);
-               return;
-       }
-
-       for (i = 0; i < bin->cnt; ++i) {
-               struct wsp_probe *p = &bin->probe_array[i];
-
-               pin_unregister(&p->probe, pfg);
-       }
-}
-
-static char *do_set_path(char *path, size_t len)
-{
-       char *p;
-
-       p = kmalloc(len, GFP_KERNEL);
-       if (!p)
-               return NULL;
-
-       strncpy(p, path, len);
-       return p;
-}
-
-static void do_free_path(char **dest)
-{
-       kfree(*dest);
-       *dest = NULL;
-}
-
-static struct pf_group *g_pfg;
-
-static int wsp_app_register(void)
-{
-       struct dentry *dentry;
-
-       if (!webapp_path || !chromium_path) {
-               pr_err("WSP: some required paths are not set!\n");
-               return -EINVAL;
-       }
-
-       chromium_bin.name = chromium_path;
-
-       dentry = dentry_by_path(webapp_path);
-       if (!dentry) {
-               pr_err("dentry not found (path='%s'\n", webapp_path);
-               return -EINVAL;
-       }
-
-       g_pfg = get_pf_group_by_dentry(dentry, (void *)dentry);
-       if (!g_pfg) {
-               pr_err("WSP: g_pfg is NULL (by dentry=%p)\n", dentry);
-               return -ENOMEM;
-       }
-
-       return wsp_bin_register(g_pfg, &chromium_bin);
-}
-
-static void wsp_app_unregister(void)
-{
-       if (!chromium_bin.name) {
-               pr_err("WSP: chromium path is not initialized\n");
-               return;
-       }
-
-       wsp_bin_unregister(g_pfg, &chromium_bin);
-       put_pf_group(g_pfg);
-}
-
-static int do_wsp_on(void)
-{
-       int ret;
-
-       ret = wsp_res_init();
-       if (ret)
-               return ret;
-
-       ret = wsp_app_register();
-       if (ret)
-               wsp_res_exit();
-
-       return ret;
-}
-
-static int do_wsp_off(void)
-{
-       wsp_app_unregister();
-       wsp_res_exit();
-
-       return 0;
-}
-
-static enum wsp_mode g_mode = WSP_OFF;
-static DEFINE_MUTEX(g_mode_mutex);
-
-int wsp_set_addr(const char *name, unsigned long offset)
-{
-       int i, ret = 0;
-
-       if (mutex_trylock(&g_mode_mutex) == 0)
-               return -EBUSY;
-
-       for (i = 0; i < chromium_bin.cnt; ++i) {
-               if (!strcmp(name, chromium_bin.probe_array[i].name)) {
-                       chromium_bin.probe_array[i].probe.offset = offset;
-                       goto unlock;
-               }
-       }
-
-       ret = -EINVAL;
-
-unlock:
-       mutex_unlock(&g_mode_mutex);
-       return ret;
-}
-
-int wsp_set_mode(enum wsp_mode mode)
-{
-       int ret = -EINVAL;
-
-       if (g_mode == mode)
-               return -EBUSY;
-
-       mutex_lock(&g_mode_mutex);
-       switch (mode) {
-       case WSP_ON:
-               ret = wsp_is_addr_init() ? do_wsp_on() : -EPERM;
-               break;
-       case WSP_OFF:
-               ret = do_wsp_off();
-               break;
-       }
-
-       if (!ret)
-               g_mode = mode;
-
-       mutex_unlock(&g_mode_mutex);
-       return ret;
-}
-
-enum wsp_mode wsp_get_mode(void)
-{
-       return g_mode;
-}
-
-void wsp_set_webapp_path(char *path, size_t len)
-{
-       do_free_path(&webapp_path);
-       webapp_path = do_set_path(path, len);
-}
-
-void wsp_set_chromium_path(char *path, size_t len)
-{
-       do_free_path(&chromium_path);
-       chromium_path = do_set_path(path, len);
-}
-
-int wsp_init(void)
-{
-       return 0;
-}
-
-void wsp_exit(void)
-{
-       wsp_set_mode(WSP_OFF);
-       do_free_path(&webapp_path);
-       do_free_path(&chromium_path);
-}
diff --git a/wsp/wsp.h b/wsp/wsp.h
deleted file mode 100644 (file)
index 8b45e1d..0000000
--- a/wsp/wsp.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef _WSP_H
-#define _WSP_H
-
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-enum wsp_mode {
-       WSP_ON,
-       WSP_OFF
-};
-
-int wsp_set_addr(const char *name, unsigned long offset);
-
-int wsp_set_mode(enum wsp_mode mode);
-enum wsp_mode wsp_get_mode(void);
-
-void wsp_set_webapp_path(char *path, size_t len);
-void wsp_set_chromium_path(char *path, size_t len);
-
-int wsp_init(void);
-void wsp_exit(void);
-
-#endif /* _WSP_H */
diff --git a/wsp/wsp_debugfs.c b/wsp/wsp_debugfs.c
deleted file mode 100644 (file)
index c117f75..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "wsp.h"
-#include "wsp_debugfs.h"
-
-static int do_write_cmd(const char *buf, size_t count)
-{
-       int n, ret = 0;
-       char *name;
-       unsigned long offset;
-
-       name = kmalloc(count, GFP_KERNEL);
-       if (!name)
-               return -ENOMEM;
-
-       n = sscanf(buf, "%lx %1024s", &offset, name);
-       if (n != 2) {
-               ret = -EINVAL;
-               goto free_name;
-       }
-
-       ret = wsp_set_addr(name, offset);
-
-free_name:
-       kfree(name);
-       return ret;
-}
-
-/* ============================================================================
- * ===                          DEBUGFS FOR CMD                             ===
- * ============================================================================
- */
-static ssize_t write_cmd(struct file *file, const char __user *user_buf,
-                        size_t count, loff_t *ppos)
-{
-       enum { max_count = 1024 };
-       int ret;
-       char *buf;
-
-       if (count > max_count)
-               return -ENOMEM;
-
-       buf = kmalloc(count + 1, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       if (copy_from_user(buf, user_buf, count)) {
-               ret = -EFAULT;
-               goto free_buf;
-       }
-
-       buf[count] = '\0';
-       ret = do_write_cmd(buf, count);
-
-free_buf:
-       kfree(buf);
-       return ret ? ret : count;
-}
-
-static const struct file_operations fops_cmd = {
-       .write =        write_cmd,
-       .llseek =       default_llseek,
-};
-
-/* ============================================================================
- * ===                         DEBUGFS FOR ENABLE                           ===
- * ============================================================================
- */
-static ssize_t read_enabled(struct file *file, char __user *user_buf,
-                           size_t count, loff_t *ppos)
-{
-       char buf[2];
-
-       buf[0] = wsp_get_mode() == WSP_OFF ? '0' : '1';
-       buf[1] = '\n';
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static ssize_t write_enabled(struct file *file, const char __user *user_buf,
-                            size_t count, loff_t *ppos)
-{
-       int ret = 0;
-       char buf[32];
-       size_t buf_size;
-
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       buf[buf_size] = '\0';
-       switch (buf[0]) {
-       case '1':
-               ret = wsp_set_mode(WSP_ON);
-               break;
-       case '0':
-               ret = wsp_set_mode(WSP_OFF);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static const struct file_operations fops_enabled = {
-       .read =         read_enabled,
-       .write =        write_enabled,
-       .llseek =       default_llseek,
-};
-
-/* ============================================================================
- * ===                       DEBUGFS FOR WEBAPP_PATH                        ===
- * ============================================================================
- */
-static ssize_t write_webapp_path(struct file *file,
-                                const char __user *user_buf,
-                                size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *path;
-
-       path = kmalloc(len, GFP_KERNEL);
-       if (!path) {
-               ret = -ENOMEM;
-               goto write_webapp_path_failed;
-       }
-
-       if (copy_from_user(path, user_buf, len)) {
-               ret = -EINVAL;
-               goto write_webapp_path_failed;
-       }
-
-       path[len - 1] = '\0';
-       wsp_set_webapp_path(path, len);
-
-       ret = len;
-
-write_webapp_path_failed:
-       kfree(path);
-
-       return ret;
-}
-
-static const struct file_operations fops_webapp_path = {
-       .write = write_webapp_path
-};
-
-/* ============================================================================
- * ===                      DEBUGFS FOR EWEBKIT_PATH                        ===
- * ============================================================================
- */
-static ssize_t write_ewebkit_path(struct file *file,
-                                 const char __user *user_buf,
-                                 size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-       char *path;
-
-       path = kmalloc(len, GFP_KERNEL);
-       if (!path) {
-               ret = -ENOMEM;
-               goto write_ewebkit_path_failed;
-       }
-
-       if (copy_from_user(path, user_buf, len)) {
-               ret = -EINVAL;
-               goto write_ewebkit_path_failed;
-       }
-
-       path[len - 1] = '\0';
-
-       wsp_set_chromium_path(path, len);
-
-       ret = len;
-
-write_ewebkit_path_failed:
-       kfree(path);
-
-       return ret;
-}
-
-static const struct file_operations fops_ewebkit_path = {
-       .write = write_ewebkit_path
-};
-
-static struct dentry *wsp_dir;
-
-void wsp_debugfs_exit(void)
-{
-       debugfs_remove_recursive(wsp_dir);
-       wsp_dir = NULL;
-}
-
-int wsp_debugfs_init(void)
-{
-       struct dentry *dentry;
-
-       dentry = swap_debugfs_getdir();
-       if (!dentry)
-               return -ENOENT;
-
-       wsp_dir = swap_debugfs_create_dir("wsp", dentry);
-       if (!wsp_dir)
-               return -ENOMEM;
-
-       dentry = swap_debugfs_create_file("enabled", 0600, wsp_dir, NULL,
-                                         &fops_enabled);
-       if (!dentry)
-               goto fail;
-
-       dentry = swap_debugfs_create_file("cmd", 0600, wsp_dir, NULL,
-                                         &fops_cmd);
-       if (!dentry)
-               goto fail;
-
-       dentry = swap_debugfs_create_file("webapp_path", 0600, wsp_dir, NULL,
-                                         &fops_webapp_path);
-       if (!dentry)
-               goto fail;
-
-       dentry = swap_debugfs_create_file("ewebkit_path", 0600, wsp_dir, NULL,
-                                         &fops_ewebkit_path);
-       if (!dentry)
-               goto fail;
-
-       return 0;
-
-fail:
-       wsp_debugfs_exit();
-       return -ENOMEM;
-}
diff --git a/wsp/wsp_debugfs.h b/wsp/wsp_debugfs.h
deleted file mode 100644 (file)
index db3ea17..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _WSP_DEBUGFS_H
-#define _WSP_DEBUGFS_H
-
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-int wsp_debugfs_init(void);
-void wsp_debugfs_exit(void);
-
-#endif /* _WSP_DEBUGFS_H */
diff --git a/wsp/wsp_module.c b/wsp/wsp_module.c
deleted file mode 100644 (file)
index 2c5d490..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <master/swap_initializer.h>
-#include "wsp.h"
-#include "wsp_debugfs.h"
-
-SWAP_LIGHT_INIT_MODULE(NULL, wsp_init, wsp_exit,
-                      wsp_debugfs_init, wsp_debugfs_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/wsp/wsp_msg.c b/wsp/wsp_msg.c
deleted file mode 100644 (file)
index a0532cd..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * wsp/wsp_msg.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <writer/swap_msg.h>
-#include "wsp_msg.h"
-
-/*
- * MSG_WSP (payload):
- * +-------------+----------+----------+
- * | name        | type     | length   |
- * +-------------+----------+----------+
- * | PID         | int      |      4   |
- * | wsp_id      | int      |      4   |
- * | wsp_payload | variable | variable |
- * +-------------+----------+----------+
-
- * wsp_id:
- *   - WSP_RES_LOAD_BEGIN = 0x0001
- *   - WSP_RES_LOAD_END   = 0x0002
- *   - WSP_RES_PROC_BEGIN = 0x0003
- *   - WSP_RES_PROC_END   = 0x0004
- *   - WSP_DRAW_BEGIN     = 0x0005
- *   - WSP_DRAW_END       = 0x0006
- *
- * wsp_payload:
- *
- * 1. WSP_RES_LOAD_BEGIN:
- *         +--------+--------+----------+
- *         | name   | type   |  length  |
- *         +--------+--------+----------+
- *         | res_id | int    |     4    |
- *         | path   | string | variable |
- *         +--------+--------+----------+
- *
- * 2. WSP_RES_LOAD_END, WSP_RES_PROC_BEGIN, WSP_RES_PROC_END:
- *         +--------+--------+----------+
- *         | name   | type   |  length  |
- *         +--------+--------+----------+
- *         | res_id | int    |     4    |
- *         +--------+--------+----------+
- *
- * 3. WSP_DRAW_BEGIN, WSP_DRAW_END:
- *         no wsp_payload
- */
-
-static int pack_wsp_msg(void *data, size_t size, enum wsp_id id,
-                       u32 res_id, const char *path)
-{
-       size_t len;
-       const size_t old_size = size;
-
-       /* write PID */
-       *(u32 *)data = (u32)current->tgid;
-       data += 4;
-       size -= 4;
-
-       /* write wsp_id */
-       *(u32 *)data = (u32)id;
-       data += 4;
-       size -= 4;
-
-       /* pack wsp_payload */
-       switch (id) {
-       case WSP_RES_LOAD_BEGIN:
-               len = strlen(path) + 1;
-               if (size < len + 4)
-                       return -ENOMEM;
-
-               /* '+ 4' - skip space for res_id */
-               memcpy(data + 4, path, len);
-               size -= len;
-       case WSP_RES_LOAD_END:
-       case WSP_RES_PROC_BEGIN:
-       case WSP_RES_PROC_END:
-               /* write res_id */
-               *(u32 *)data = res_id;
-               size -= 4;
-               break;
-
-       case WSP_DRAW_BEGIN:
-       case WSP_DRAW_END:
-               break;
-
-       default:
-               pr_err("unknown wsp_id: id=%u\n", (unsigned int)id);
-               return -EINVAL;
-       }
-
-       return old_size - size;
-}
-
-void wsp_msg(enum wsp_id id, u32 res_id, const char *path)
-{
-       int ret;
-       void *data;
-       size_t size;
-       struct swap_msg *m;
-
-       m = swap_msg_get(MSG_WSP);
-       data = swap_msg_payload(m);
-       size = swap_msg_size(m);
-       ret = pack_wsp_msg(data, size, id, res_id, path);
-       if (ret < 0) {
-               pr_err("error MSG_WSP packing, ret=%d\n", ret);
-               goto put_msg;
-       }
-
-       swap_msg_flush(m, ret);
-
-put_msg:
-       swap_msg_put(m);
-}
diff --git a/wsp/wsp_msg.h b/wsp/wsp_msg.h
deleted file mode 100644 (file)
index fc02009..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _WSP_MSG_H
-#define _WSP_MSG_H
-
-/*
- * wsp/wsp_msg.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <linux/types.h>
-
-enum wsp_id {
-       WSP_RES_LOAD_BEGIN = 0x0001,
-       WSP_RES_LOAD_END   = 0x0002,
-       WSP_RES_PROC_BEGIN = 0x0003,
-       WSP_RES_PROC_END   = 0x0004,
-       WSP_DRAW_BEGIN     = 0x0005,
-       WSP_DRAW_END       = 0x0006
-};
-
-void wsp_msg(enum wsp_id id, u32 res_id, const char *path);
-
-#endif /* _WSP_MSG_H */
diff --git a/wsp/wsp_res.c b/wsp/wsp_res.c
deleted file mode 100644 (file)
index 2ad640f..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <linux/slab.h>
-#include <linux/atomic.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include "wsp_res.h"
-
-static atomic_t __resource_id = ATOMIC_INIT(0);
-
-static inline int __wsp_resource_id(void)
-{
-       return atomic_inc_return(&__resource_id);
-}
-
-struct wsp_resource_data {
-       struct list_head list;
-       int id;
-       unsigned long addr;
-       char *path;
-};
-
-static LIST_HEAD(__resources_list);
-static DEFINE_MUTEX(__resources_mutex);
-
-static struct wsp_resource_data *wsp_resource_data_alloc(void)
-{
-       struct wsp_resource_data *p;
-
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return NULL;
-
-       INIT_LIST_HEAD(&p->list);
-
-       return p;
-}
-
-static void wsp_resource_data_free(struct wsp_resource_data *p)
-{
-       if (!p)
-               return;
-
-       kfree(p->path);
-       kfree(p);
-}
-
-static struct wsp_resource_data *wsp_resource_data_find(unsigned long addr)
-{
-       struct wsp_resource_data *p;
-
-       list_for_each_entry(p, &__resources_list, list)
-               if (p->addr == addr)
-                       return p;
-
-       return NULL;
-}
-
-int wsp_resource_data_id(unsigned long addr)
-{
-       int ret = -1;
-       struct wsp_resource_data *p;
-
-       mutex_lock(&__resources_mutex);
-       p = wsp_resource_data_find(addr);
-       if (p)
-               ret = p->id;
-       mutex_unlock(&__resources_mutex);
-
-       return ret;
-}
-
-int wsp_resource_data_add(unsigned long addr, char *path)
-{
-       int ret = -1;
-       struct wsp_resource_data *p;
-
-       mutex_lock(&__resources_mutex);
-       p = wsp_resource_data_find(addr);
-       if (p) {
-               ret = p->id;
-               goto out;
-       }
-       p = wsp_resource_data_alloc();
-       if (p) {
-               p->id = __wsp_resource_id();
-               p->addr = addr;
-               p->path = path;
-               list_add_tail(&p->list, &__resources_list);
-               ret = p->id;
-       }
-
-out:
-       mutex_unlock(&__resources_mutex);
-
-       return ret;
-}
-
-void wsp_resource_data_del(unsigned long addr)
-{
-       struct wsp_resource_data *p;
-
-       mutex_lock(&__resources_mutex);
-       p = wsp_resource_data_find(addr);
-       if (p) {
-               list_del(&p->list);
-               wsp_resource_data_free(p);
-       }
-
-       mutex_unlock(&__resources_mutex);
-}
-
-/* ============================================================================
- * =                                init/exit()                               =
- * ============================================================================
- */
-int wsp_res_init(void)
-{
-       return 0;
-}
-
-void wsp_res_exit(void)
-{
-       struct wsp_resource_data *p, *tmp;
-
-       mutex_lock(&__resources_mutex);
-       list_for_each_entry_safe(p, tmp, &__resources_list, list) {
-               list_del(&p->list);
-               wsp_resource_data_free(p);
-       }
-       mutex_unlock(&__resources_mutex);
-}
diff --git a/wsp/wsp_res.h b/wsp/wsp_res.h
deleted file mode 100644 (file)
index 9c13478..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _WSP_TDATA_H
-#define _WSP_TDATA_H
-
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @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, see <http://www.gnu.org/licenses/>.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Web startup profiling
- */
-
-#include <linux/types.h>
-
-int wsp_resource_data_add(unsigned long addr, char *path);
-void wsp_resource_data_del(unsigned long addr);
-int wsp_resource_data_id(unsigned long addr);
-
-int wsp_res_init(void);
-void wsp_res_exit(void);
-
-#endif /* _WSP_TDATA_H */