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 Bob Montgomery
98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Will Cohen
108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon
118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie
128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/sched.h>
158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/unistd.h>
168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/mman.h>
178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/file.h>
188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprofile.h"
208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_dcache.h"
218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_util.h"
228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodduint dname_top;
248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct qstr **dname_stack;
258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddchar * pool_pos;
268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddchar * pool_start;
278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddchar * pool_end;
288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid oprof_put_note(struct op_note * samp);
308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* ------------ system calls --------------- */
328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct mmap_arg_struct {
348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unsigned long addr;
358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long len;
368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long prot;
378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long flags;
388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long fd;
398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd        unsigned long offset;
408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd};
418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* --------- IA64 versions of system calls ------ */
438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_clone)(long, long);
448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_clone2)(long, long, long);
458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static int (*old_sys_execve)(char *, char **, char **);
468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static unsigned long (*old_sys_mmap)(unsigned long,
478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				unsigned long, int, int, int, long);
488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static unsigned long (*old_sys_mmap2)(unsigned long,
498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				unsigned long, int, int, int, long);
508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static long (*old_sys_init_module)(char const *, struct module *);
518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage static long (*old_sys_exit)(int);
528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* --------- declarations of interception stubs for IA64  ------ */
548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long post_stub_clone(long, long);
558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long post_stub_clone2(long, long, long);
568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long my_ia64_execve(char *, char **, char **);
578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage unsigned long post_stub_mmap(unsigned long,
588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					unsigned long, int, int, int, long);
598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage unsigned long post_stub_mmap2(unsigned long,
608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					unsigned long, int, int, int, long);
618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long post_stub_init_module(char const *, struct module *);
628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long pre_stub_exit(int);
638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* IA64 system call table doesn't use function pointers, it uses
658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * pointers to code (not the same thing).  Basically it can violate the
668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * procedure calling rules because these "procedure calls" are made by
678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * the assembly language BREAK handler in ivt.S.
688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc {
718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	void * ip;
728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	void * gp;
738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd};
748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_clone;
768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_clone2;
778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_execve;
788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_mmap;
798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_mmap2;
808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_init_module;
818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct fdesc fdesc_exit;
828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* ----------- End of IA64 weirdness for now -------------- */
838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddspinlock_t map_lock = SPIN_LOCK_UNLOCKED;
858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* called with map_lock held */
878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void oprof_output_map(ulong addr, ulong len,
888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ulong offset, struct file * file, int is_execve)
898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct op_note note;
918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* don't bother with /dev/zero mappings etc. */
938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!len)
948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.pid = current->pid;
978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.tgid = op_get_tgid();
988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.addr = addr;
998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.len = len;
1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.offset = offset;
1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.type = is_execve ? OP_EXEC : OP_MAP;
1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.hash = hash_path(file);
1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (note.hash == -1)
1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_put_note(&note);
1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_output_maps(struct task_struct * task)
1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int size=0;
1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct mm_struct * mm;
1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct vm_area_struct * map;
1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* we don't need to worry about mm_users here, since there is at
1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   least one user (current), and if there's other code using this
1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   mm, then mm_users must be at least 2; we should never have to
1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   mmput() here. */
1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!(mm = task->mm))
1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		goto out;
1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	lock_mmap(mm);
1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_lock(&map_lock);
1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* We need two pass, daemon assume than the first mmap notification
1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * is for the executable but some process doesn't follow this model.
1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (map = mm->mmap; map; map = map->vm_next) {
1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(map->vm_flags & VM_EXEC) || !map->vm_file)
1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(map->vm_flags & VM_EXECUTABLE))
1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_output_map(map->vm_start, map->vm_end-map->vm_start,
1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			GET_VM_OFFSET(map), map->vm_file, 1);
1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (map = mm->mmap; map; map = map->vm_next) {
1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(map->vm_flags & VM_EXEC) || !map->vm_file)
1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (map->vm_flags & VM_EXECUTABLE)
1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_output_map(map->vm_start, map->vm_end-map->vm_start,
1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			GET_VM_OFFSET(map), map->vm_file, 0);
1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_unlock(&map_lock);
1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unlock_mmap(mm);
1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return size;
1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* execve is a special case on IA64.  The others get the result and
1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * arguments after the system call has been made from the ASM stub. */
1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage long
1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddmy_sys_execve (char * filename, char **argv, char **envp, struct pt_regs * regs)
1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int error;
1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	filename = getname(filename);
1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	error = PTR_ERR(filename);
1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (IS_ERR(filename))
1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		goto out;
1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	error = do_execve(filename, argv, envp, regs);
1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!error) {
1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		PTRACE_OFF(current);
1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_output_maps(current);
1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	putname(filename);
1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unlock_execve();
1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return error;
1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void out_mmap(ulong addr, ulong len, ulong prot, ulong flags,
1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ulong fd, ulong offset)
1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct file * file;
1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	lock_out_mmap();
1888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	file = fget(fd);
1908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!file)
1918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		goto out;
1928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_lock(&map_lock);
1948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_output_map(addr, len, offset, file, 0);
1958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_unlock(&map_lock);
1968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fput(file);
1988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
2008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unlock_out_mmap();
2018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/*
2058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * IA64 mmap routines:
2068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * The post_sys_* routines are called after the syscall has been made.
2078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * The first argument is the return value from the system call.
2088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
2098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage void post_sys_mmap2(ulong ret, ulong addr, ulong len,
2108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ulong prot, ulong flags, ulong fd, ulong pgoff)
2118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* FIXME: This should be done in the ASM stub. */
2138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if ((prot & PROT_EXEC) && ret >= 0)
2168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		out_mmap(ret, len, prot, flags, fd, pgoff << PAGE_SHIFT);
2178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	goto out;
2188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
2198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage void post_sys_mmap(ulong ret, ulong addr, ulong len,
2238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ulong prot, ulong flags, ulong fd, ulong off)
2248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* FIXME: This should be done in the ASM stub. */
2268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if ((prot & PROT_EXEC) && ret >= 0)
2298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		out_mmap(ret, len, prot, flags, fd, off);
2308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	goto out;
2318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout:
2328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static void oprof_report_fork(u32 old_pid, u32 new_pid, u32 old_tgid, u32 new_tgid)
2378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct op_note note;
2398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.type = OP_FORK;
2418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.pid = old_pid;
2428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.tgid = old_tgid;
2438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.addr = new_pid;
2448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.len = new_tgid;
2458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_put_note(&note);
2468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage void post_sys_clone(long ret, long arg0, long arg1)
2508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 pid = current->pid;
2528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 tgid = op_get_tgid();
2538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* FIXME: This should be done in the ASM stub. */
2558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret)
2588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		/* FIXME: my libc show clone() is not implemented in ia64
2598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		 * but used only by fork() with a SIGCHILD first parameter
2608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		 * so we assume it's a fork */
2618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_report_fork(pid, ret, pid, tgid);
2628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage void post_sys_clone2(long ret, long arg0, long arg1, long arg2)
2668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 pid = current->pid;
2688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	u32 tgid = op_get_tgid();
2698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	long clone_flags = arg0;
2708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* FIXME: This should be done in the ASM stub. */
2728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret) {
2758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (clone_flags & CLONE_THREAD)
2768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			oprof_report_fork(pid, ret, tgid, tgid);
2778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		else
2788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			oprof_report_fork(pid, ret, tgid, ret);
2798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage void
2848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddpost_sys_init_module(long ret, char const * name_user,
2858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd                     struct module * mod_user)
2868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* FIXME: This should be done in the ASM stub. */
2888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
2898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret >= 0) {
2918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		struct op_note note;
2928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		note.type = OP_DROP_MODULES;
2948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		oprof_put_note(&note);
2958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
2978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* Exit must use a pre-call intercept stub.  There is no post exit. */
3008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddasmlinkage void pre_sys_exit(int error_code)
3018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct op_note note;
3038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_INC_USE_COUNT;
3058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.addr = current->times.tms_utime;
3078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.len = current->times.tms_stime;
3088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.offset = current->start_time;
3098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.type = OP_EXIT;
3108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.pid = current->pid;
3118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	note.tgid = op_get_tgid();
3128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	oprof_put_note(&note);
3138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* this looks UP-dangerous, as the exit sleeps and we don't
3158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * have a use count, but in fact its ok as sys_exit is noreturn,
3168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * so we can never come back to this non-existent exec page
3178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
3188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	MOD_DEC_USE_COUNT;
3198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddextern void * sys_call_table[];
3228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* FIXME:  Now that I'm never trying to do a C-level call through these
3248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * pointers, I should just save, intercept, and restore with void *
3258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * instead of the void * part of the function descriptor, I think.
3268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
3278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_save_syscalls(void)
3298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_clone.ip = sys_call_table[__NR_clone - __NR_ni_syscall];
3318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_clone = (void *)&fdesc_clone;
3328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_clone2.ip = sys_call_table[__NR_clone2 - __NR_ni_syscall];
3338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_clone2 = (void *)&fdesc_clone2;
3348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_execve.ip = sys_call_table[__NR_execve - __NR_ni_syscall];
3358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_execve = (void *)&fdesc_execve;
3368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_mmap.ip = sys_call_table[__NR_mmap - __NR_ni_syscall];
3378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_mmap = (void *)&fdesc_mmap;
3388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_mmap2.ip = sys_call_table[__NR_mmap2 - __NR_ni_syscall];
3398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_mmap2 = (void *)&fdesc_mmap2;
3408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_init_module.ip = sys_call_table[__NR_init_module - __NR_ni_syscall];
3418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_init_module = (void *)&fdesc_init_module;
3428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fdesc_exit.ip = sys_call_table[__NR_exit - __NR_ni_syscall];
3438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	old_sys_exit = (void *)&fdesc_exit;
3448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_intercept_syscalls(void)
3478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* Must extract the function address from the stub function
3498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * descriptors.
3508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
3518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_clone - __NR_ni_syscall] =
3528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)post_stub_clone)->ip;
3538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_clone2 - __NR_ni_syscall] =
3548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)post_stub_clone2)->ip;
3558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_execve - __NR_ni_syscall] =
3568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)my_ia64_execve)->ip;
3578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap - __NR_ni_syscall] =
3588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)post_stub_mmap)->ip;
3598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap2 - __NR_ni_syscall] =
3608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)post_stub_mmap2)->ip;
3618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_init_module - __NR_ni_syscall] =
3628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)post_stub_init_module)->ip;
3638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_exit - __NR_ni_syscall] =
3648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)pre_stub_exit)->ip;
3658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_restore_syscalls(void)
3688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_clone - __NR_ni_syscall] =
3708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_clone)->ip;
3718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_clone2 - __NR_ni_syscall] =
3728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_clone2)->ip;
3738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_execve - __NR_ni_syscall] =
3748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_execve)->ip;
3758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap - __NR_ni_syscall] =
3768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_mmap)->ip;
3778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_mmap2 - __NR_ni_syscall] =
3788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_mmap2)->ip;
3798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_init_module - __NR_ni_syscall] =
3808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_init_module)->ip;
3818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	sys_call_table[__NR_exit - __NR_ni_syscall] =
3828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		((struct fdesc *)old_sys_exit)->ip;
3838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
384