18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file op_syscalls.c
38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Tracing of system calls
48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors
68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING
78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon
98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie
108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/sched.h>
138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/unistd.h>
148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/mman.h>
158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/file.h>
168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprofile.h"
188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid oprof_put_note(struct op_note * samp);
208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid __oprof_put_note(struct op_note * samp);
218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddextern spinlock_t note_lock;
238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* ------------ system calls --------------- */
258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct mmap_arg_struct {
278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unsigned long addr;
288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long len;
298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long prot;
308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long flags;
318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long fd;
328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long offset;
338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd};
348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_fork)(struct pt_regs);
368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_vfork)(struct pt_regs);
378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_clone)(struct pt_regs);
388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_execve)(struct pt_regs);
398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_old_mmap)(struct mmap_arg_struct *);
408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_MMAP2
418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static long (*old_sys_mmap2)(ulong, ulong, ulong, ulong, ulong, ulong);
428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static long (*old_sys_init_module)(char const *, struct module *);
448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static long (*old_sys_exit)(int);
458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* called with note_lock held */
478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void oprof_output_map(ulong addr, ulong len, ulong offset,
488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			     struct file * file, int is_execve)
498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct op_note note;
518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* don't bother with /dev/zero mappings etc. */
538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!len)
548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.pid = current->pid;
578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.tgid = op_get_tgid();
588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.addr = addr;
598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.len = len;
608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.offset = offset;
618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.type = is_execve ? OP_EXEC : OP_MAP;
628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.hash = hash_path(file);
638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (note.hash == -1)
648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* holding note lock */
668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	__oprof_put_note(&note);
678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_output_maps(struct task_struct * task)
708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int size=0;
728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct mm_struct * mm;
738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct vm_area_struct * map;
748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* we don't need to worry about mm_users here, since there is at
768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   least one user (current), and if there's other code using this
778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   mm, then mm_users must be at least 2; we should never have to
788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   mmput() here. */
798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!(mm = task->mm))
818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		goto out;
828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	lock_mmap(mm);
848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_lock(&note_lock);
858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* We need two pass, daemon assume than the first mmap notification
878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * is for the executable but some process doesn't follow this model.
888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (map = mm->mmap; map; map = map->vm_next) {
908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(map->vm_flags & VM_EXEC) || !map->vm_file)
918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(map->vm_flags & VM_EXECUTABLE))
938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_output_map(map->vm_start, map->vm_end-map->vm_start,
968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			GET_VM_OFFSET(map), map->vm_file, 1);
978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (map = mm->mmap; map; map = map->vm_next) {
998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(map->vm_flags & VM_EXEC) || !map->vm_file)
1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (map->vm_flags & VM_EXECUTABLE)
1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_output_map(map->vm_start, map->vm_end-map->vm_start,
1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			GET_VM_OFFSET(map), map->vm_file, 0);
1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_unlock(&note_lock);
1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unlock_mmap(mm);
1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return size;
1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int my_sys_execve(struct pt_regs regs)
1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	char * filename;
1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret;
1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	lock_execve();
1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	filename = getname((char *)regs.ebx);
1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (IS_ERR(filename)) {
1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ret = PTR_ERR(filename);
1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		goto out;
1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = do_execve(filename, (char **)regs.ecx, (char **)regs.edx, &regs);
1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!ret) {
1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		PTRACE_OFF(current);
1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_output_maps(current);
1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	putname(filename);
1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unlock_execve();
1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        return ret;
1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void out_mmap(ulong addr, ulong len, ulong prot, ulong flags, ulong fd,
1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		     ulong offset)
1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct file * file;
1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	lock_out_mmap();
1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	file = fget(fd);
1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!file)
1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		goto out;
1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_lock(&note_lock);
1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_output_map(addr, len, offset, file, 0);
1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_unlock(&note_lock);
1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fput(file);
1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unlock_out_mmap();
1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_MMAP2
1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int my_sys_mmap2(ulong addr, ulong len,
1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ulong prot, ulong flags, ulong fd, ulong pgoff)
1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret;
1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = old_sys_mmap2(addr, len, prot, flags, fd, pgoff);
1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if ((prot & PROT_EXEC) && ret >= 0)
1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		out_mmap(ret, len, prot, flags, fd, pgoff << PAGE_SHIFT);
1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int my_old_mmap(struct mmap_arg_struct * arg)
1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret;
1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
1888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = old_old_mmap(arg);
1908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret >= 0) {
1928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		struct mmap_arg_struct a;
1938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (copy_from_user(&a, arg, sizeof(a))) {
1958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			ret = -EFAULT;
1968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			goto out;
1978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
1988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (a.prot&PROT_EXEC)
2008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			out_mmap(ret, a.len, a.prot, a.flags, a.fd, a.offset);
2018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
2048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static void oprof_report_fork(u32 old_pid, u32 new_pid, u32 old_tgid, u32 new_tgid)
2098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct op_note note;
2118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.type = OP_FORK;
2138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.pid = old_pid;
2148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.tgid = old_tgid;
2158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.addr = new_pid;
2168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.len = new_tgid;
2178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_put_note(&note);
2188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int my_sys_fork(struct pt_regs regs)
2218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 pid = current->pid;
2238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 tgid = op_get_tgid();
2248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret;
2258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = old_sys_fork(regs);
2298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret)
2308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_report_fork(pid, ret, tgid, ret);
2318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int my_sys_vfork(struct pt_regs regs)
2368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 pid = current->pid;
2388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 tgid = op_get_tgid();
2398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret;
2408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = old_sys_vfork(regs);
2438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret)
2448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_report_fork(pid, ret, tgid, ret);
2458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int my_sys_clone(struct pt_regs regs)
2508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 pid = current->pid;
2528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 tgid = op_get_tgid();
2538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if V_AT_LEAST(2, 4, 0)
2548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 clone_flags = regs.ebx;
2558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
2568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret;
2578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = old_sys_clone(regs);
2608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret) {
2618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if V_AT_LEAST(2, 4, 0)
2628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (clone_flags & CLONE_THREAD)
2638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			oprof_report_fork(pid, ret, tgid, tgid);
2648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		else
2658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
2668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			oprof_report_fork(pid, ret, tgid, ret);
2678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static long my_sys_init_module(char const * name_user, struct module * mod_user)
2738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	long ret;
2758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ret = old_sys_init_module(name_user, mod_user);
2798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret >= 0) {
2818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		struct op_note note;
2828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		note.type = OP_DROP_MODULES;
2848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_put_note(&note);
2858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* used from do_nmi */
2918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long my_sys_exit(int error_code)
2928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct op_note note;
2948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.type = OP_EXIT;
2988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.pid = current->pid;
2998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.tgid = op_get_tgid();
3008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_put_note(&note);
3018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* this looks UP-dangerous, as the exit sleeps and we don't
3038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * have a use count, but in fact its ok as sys_exit is noreturn,
3048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * so we can never come back to this non-existent exec page
3058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
3068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
3078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return old_sys_exit(error_code);
3088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddextern void * sys_call_table[];
3118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_save_syscalls(void)
3138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_fork = sys_call_table[__NR_fork];
3158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_vfork = sys_call_table[__NR_vfork];
3168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_clone = sys_call_table[__NR_clone];
3178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_execve = sys_call_table[__NR_execve];
3188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_old_mmap = sys_call_table[__NR_mmap];
3198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_MMAP2
3208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_mmap2 = sys_call_table[__NR_mmap2];
3218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
3228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_init_module = sys_call_table[__NR_init_module];
3238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_exit = sys_call_table[__NR_exit];
3248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_intercept_syscalls(void)
3278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_fork] = my_sys_fork;
3298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_vfork] = my_sys_vfork;
3308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_clone] = my_sys_clone;
3318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_execve] = my_sys_execve;
3328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap] = my_old_mmap;
3338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_MMAP2
3348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap2] = my_sys_mmap2;
3358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
3368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_init_module] = my_sys_init_module;
3378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_exit] = my_sys_exit;
3388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_restore_syscalls(void)
3418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_fork] = old_sys_fork;
3438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_vfork] = old_sys_vfork;
3448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_clone] = old_sys_clone;
3458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_execve] = old_sys_execve;
3468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap] = old_old_mmap;
3478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_MMAP2
3488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap2] = old_sys_mmap2;
3498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
3508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_init_module] = old_sys_init_module;
3518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_exit] = old_sys_exit;
3528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
353