Commit 54a69e55 authored by Mathieu Desnoyers's avatar Mathieu Desnoyers Committed by Greg Kroah-Hartman

lttng: syscall instrumentation

x86-32 and x86-64 system call instrumentation, along with the
lttng-syscalls-generate-headers.sh script that generates the headers
from the system call list. See README for details.
Signed-off-by: default avatarMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 763be8c0
LTTng system call tracing
1) lttng-syscall-extractor
You need to build a kernel with CONFIG_FTRACE_SYSCALLS=y and
CONFIG_KALLSYMS_ALL=y for extraction. Apply the linker patch to get your
kernel to keep the system call metadata after boot. Then build and load
the LTTng syscall extractor module. The module will fail to load (this
is expected). See the dmesg output for system call metadata.
2) Generate system call TRACE_EVENT().
Take the dmesg metadata and feed it to lttng-syscalls-generate-headers.sh, e.g.,
from the instrumentation/syscalls directory. See the script header for
usage example.
After these are created, we just need to follow the new system call additions,
no need to regenerate the whole thing, since system calls are only appended to.
#ifdef CONFIG_X86_64
#include "x86-32-syscalls-3.1.0-rc6_integers.h"
#endif
#ifdef CONFIG_X86_64
#include "x86-32-syscalls-3.1.0-rc6_pointers.h"
#endif
#ifdef CONFIG_X86_64
#include "x86-64-syscalls-3.0.4_integers.h"
#endif
#ifdef CONFIG_X86_32
#include "x86-32-syscalls-3.1.0-rc6_integers.h"
#endif
#define OVERRIDE_32_sys_mmap
#define OVERRIDE_64_sys_mmap
#ifndef CREATE_SYSCALL_TABLE
SC_TRACE_EVENT(sys_mmap,
TP_PROTO(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off),
TP_ARGS(addr, len, prot, flags, fd, off),
TP_STRUCT__entry(__field_hex(unsigned long, addr) __field(size_t, len) __field(int, prot) __field(int, flags) __field(int, fd) __field(off_t, offset)),
TP_fast_assign(tp_assign(addr, addr) tp_assign(len, len) tp_assign(prot, prot) tp_assign(flags, flags) tp_assign(fd, fd) tp_assign(offset, off)),
TP_printk()
)
#endif /* CREATE_SYSCALL_TABLE */
#ifdef CONFIG_X86_64
#include "x86-64-syscalls-3.0.4_pointers.h"
#endif
#ifdef CONFIG_X86_32
#include "x86-32-syscalls-3.1.0-rc6_pointers.h"
#endif
/*
* This is a place-holder for override defines for system calls with
* pointers (all architectures).
*/
#if !defined(_TRACE_SYSCALLS_UNKNOWN_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SYSCALLS_UNKNOWN_H
#include <linux/tracepoint.h>
#include <linux/syscalls.h>
#define UNKNOWN_SYSCALL_NRARGS 6
TRACE_EVENT(sys_unknown,
TP_PROTO(unsigned int id, unsigned long *args),
TP_ARGS(id, args),
TP_STRUCT__entry(
__field(unsigned int, id)
__array(unsigned long, args, UNKNOWN_SYSCALL_NRARGS)
),
TP_fast_assign(
tp_assign(id, id)
tp_memcpy(args, args, UNKNOWN_SYSCALL_NRARGS * sizeof(*args))
),
TP_printk()
)
TRACE_EVENT(compat_sys_unknown,
TP_PROTO(unsigned int id, unsigned long *args),
TP_ARGS(id, args),
TP_STRUCT__entry(
__field(unsigned int, id)
__array(unsigned long, args, UNKNOWN_SYSCALL_NRARGS)
),
TP_fast_assign(
tp_assign(id, id)
tp_memcpy(args, args, UNKNOWN_SYSCALL_NRARGS * sizeof(*args))
),
TP_printk()
)
/*
* This is going to hook on sys_exit in the kernel.
* We change the name so we don't clash with the sys_exit syscall entry
* event.
*/
TRACE_EVENT(exit_syscall,
TP_PROTO(struct pt_regs *regs, long ret),
TP_ARGS(regs, ret),
TP_STRUCT__entry(
__field(long, ret)
),
TP_fast_assign(
tp_assign(ret, ret)
),
TP_printk()
)
#endif /* _TRACE_SYSCALLS_UNKNOWN_H */
/* This part must be outside protection */
#include "../../../probes/define_trace.h"
#ifndef CONFIG_UID16
#define OVERRIDE_32_sys_getuid16
#define OVERRIDE_32_sys_getgid16
#define OVERRIDE_32_sys_geteuid16
#define OVERRIDE_32_sys_getegid16
#define OVERRIDE_32_sys_setuid16
#define OVERRIDE_32_sys_setgid16
#define OVERRIDE_32_sys_setfsuid16
#define OVERRIDE_32_sys_setfsgid16
#define OVERRIDE_32_sys_setreuid16
#define OVERRIDE_32_sys_setregid16
#define OVERRIDE_32_sys_fchown16
#define OVERRIDE_32_sys_setresuid16
#define OVERRIDE_32_sys_setresgid16
#define OVERRIDE_TABLE_32_sys_getuid16
#define OVERRIDE_TABLE_32_sys_getgid16
#define OVERRIDE_TABLE_32_sys_geteuid16
#define OVERRIDE_TABLE_32_sys_getegid16
#define OVERRIDE_TABLE_32_sys_setuid16
#define OVERRIDE_TABLE_32_sys_setgid16
#define OVERRIDE_TABLE_32_sys_setreuid16
#define OVERRIDE_TABLE_32_sys_setregid16
#define OVERRIDE_TABLE_32_sys_fchown16
#define OVERRIDE_TABLE_32_sys_setfsuid16
#define OVERRIDE_TABLE_32_sys_setfsgid16
#define OVERRIDE_TABLE_32_sys_setresuid16
#define OVERRIDE_TABLE_32_sys_setresgid16
#endif
#ifdef CREATE_SYSCALL_TABLE
#define OVERRIDE_TABLE_32_sys_mmap
TRACE_SYSCALL_TABLE(sys_mmap, sys_mmap, 90, 6)
#endif
#ifndef CONFIG_UID16
#define OVERRIDE_32_sys_getgroups16
#define OVERRIDE_32_sys_setgroups16
#define OVERRIDE_32_sys_lchown16
#define OVERRIDE_32_sys_getresuid16
#define OVERRIDE_32_sys_getresgid16
#define OVERRIDE_32_sys_chown16
#define OVERRIDE_TABLE_32_sys_getgroups16
#define OVERRIDE_TABLE_32_sys_setgroups16
#define OVERRIDE_TABLE_32_sys_lchown16
#define OVERRIDE_TABLE_32_sys_getresuid16
#define OVERRIDE_TABLE_32_sys_getresgid16
#define OVERRIDE_TABLE_32_sys_chown16
#endif
/*
* this is a place-holder for x86_64 interger syscall definition override.
*/
#ifndef CREATE_SYSCALL_TABLE
#else /* CREATE_SYSCALL_TABLE */
#endif /* CREATE_SYSCALL_TABLE */
/*
* Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
* Copyright 2011 - Julien Desfossez <julien.desfossez@polymtl.ca>
*
* Dump syscall metadata to console.
*
* GPLv2 license.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/kallsyms.h>
#include <linux/dcache.h>
#include <linux/ftrace_event.h>
#include <trace/syscall.h>
#ifndef CONFIG_FTRACE_SYSCALLS
#error "You need to set CONFIG_FTRACE_SYSCALLS=y"
#endif
#ifndef CONFIG_KALLSYMS_ALL
#error "You need to set CONFIG_KALLSYMS_ALL=y"
#endif
static struct syscall_metadata **__start_syscalls_metadata;
static struct syscall_metadata **__stop_syscalls_metadata;
static __init
struct syscall_metadata *find_syscall_meta(unsigned long syscall)
{
struct syscall_metadata **iter;
for (iter = __start_syscalls_metadata;
iter < __stop_syscalls_metadata; iter++) {
if ((*iter)->syscall_nr == syscall)
return (*iter);
}
return NULL;
}
int init_module(void)
{
struct syscall_metadata *meta;
int i;
__start_syscalls_metadata = (void *) kallsyms_lookup_name("__start_syscalls_metadata");
__stop_syscalls_metadata = (void *) kallsyms_lookup_name("__stop_syscalls_metadata");
for (i = 0; i < NR_syscalls; i++) {
int j;
meta = find_syscall_meta(i);
if (!meta)
continue;
printk("syscall %s nr %d nbargs %d ",
meta->name, meta->syscall_nr, meta->nb_args);
printk("types: (");
for (j = 0; j < meta->nb_args; j++) {
if (j > 0)
printk(", ");
printk("%s", meta->types[j]);
}
printk(") ");
printk("args: (");
for (j = 0; j < meta->nb_args; j++) {
if (j > 0)
printk(", ");
printk("%s", meta->args[j]);
}
printk(")\n");
}
printk("SUCCESS\n");
return -1;
}
void cleanup_module(void)
{
}
MODULE_LICENSE("GPL");
#!/bin/sh
# Generate system call probe description macros from syscall metadata dump file.
# example usage:
#
# lttng-syscalls-generate-headers.sh integers 3.0.4 x86-64-syscalls-3.0.4 64
# lttng-syscalls-generate-headers.sh pointers 3.0.4 x86-64-syscalls-3.0.4 64
CLASS=$1
INPUTDIR=$2
INPUTFILE=$3
BITNESS=$4
INPUT=${INPUTDIR}/${INPUTFILE}
SRCFILE=gen.tmp.0
TMPFILE=gen.tmp.1
HEADER=headers/${INPUTFILE}_${CLASS}.h
cp ${INPUT} ${SRCFILE}
#Cleanup
perl -p -e 's/^\[.*\] //g' ${SRCFILE} > ${TMPFILE}
mv ${TMPFILE} ${SRCFILE}
perl -p -e 's/^syscall sys_([^ ]*)/syscall $1/g' ${SRCFILE} > ${TMPFILE}
mv ${TMPFILE} ${SRCFILE}
#Filter
if [ "$CLASS" = integers ]; then
#select integers and no-args.
CLASSCAP=INTEGERS
grep -v "\\*\|cap_user_header_t" ${SRCFILE} > ${TMPFILE}
mv ${TMPFILE} ${SRCFILE}
fi
if [ "$CLASS" = pointers ]; then
#select system calls using pointers.
CLASSCAP=POINTERS
grep "\\*\|cap_#user_header_t" ${SRCFILE} > ${TMPFILE}
mv ${TMPFILE} ${SRCFILE}
fi
echo "/* THIS FILE IS AUTO-GENERATED. DO NOT EDIT */" > ${HEADER}
echo \
"#ifndef CREATE_SYSCALL_TABLE
#if !defined(_TRACE_SYSCALLS_${CLASSCAP}_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SYSCALLS_${CLASSCAP}_H
#include <linux/tracepoint.h>
#include <linux/syscalls.h>
#include \"${INPUTFILE}_${CLASS}_override.h\"
#include \"syscalls_${CLASS}_override.h\"
" >> ${HEADER}
if [ "$CLASS" = integers ]; then
NRARGS=0
echo \
'SC_DECLARE_EVENT_CLASS_NOARGS(syscalls_noargs,\n'\
' TP_STRUCT__entry(),\n'\
' TP_fast_assign(),\n'\
' TP_printk()\n'\
')'\
>> ${HEADER}
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^)]*)\) '\
'args: \(([^)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_DEFINE_EVENT_NOARGS(syscalls_noargs, sys_$1)\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
fi
# types: 4
# args 5
NRARGS=1
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^)]*)\) '\
'args: \(([^)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_TRACE_EVENT(sys_$1,\n'\
' TP_PROTO($4 $5),\n'\
' TP_ARGS($5),\n'\
' TP_STRUCT__entry(__field($4, $5)),\n'\
' TP_fast_assign(tp_assign($4, $5, $5)),\n'\
' TP_printk()\n'\
')\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
# types: 4 5
# args 6 7
NRARGS=2
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^,]*), ([^)]*)\) '\
'args: \(([^,]*), ([^)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_TRACE_EVENT(sys_$1,\n'\
' TP_PROTO($4 $6, $5 $7),\n'\
' TP_ARGS($6, $7),\n'\
' TP_STRUCT__entry(__field($4, $6) __field($5, $7)),\n'\
' TP_fast_assign(tp_assign($4, $6, $6) tp_assign($5, $7, $7)),\n'\
' TP_printk()\n'\
')\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
# types: 4 5 6
# args 7 8 9
NRARGS=3
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^,]*), ([^,]*), ([^)]*)\) '\
'args: \(([^,]*), ([^,]*), ([^)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_TRACE_EVENT(sys_$1,\n'\
' TP_PROTO($4 $7, $5 $8, $6 $9),\n'\
' TP_ARGS($7, $8, $9),\n'\
' TP_STRUCT__entry(__field($4, $7) __field($5, $8) __field($6, $9)),\n'\
' TP_fast_assign(tp_assign($4, $7, $7) tp_assign($5, $8, $8) tp_assign($6, $9, $9)),\n'\
' TP_printk()\n'\
')\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
# types: 4 5 6 7
# args 8 9 10 11
NRARGS=4
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^,]*), ([^,]*), ([^,]*), ([^)]*)\) '\
'args: \(([^,]*), ([^,]*), ([^,]*), ([^)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_TRACE_EVENT(sys_$1,\n'\
' TP_PROTO($4 $8, $5 $9, $6 $10, $7 $11),\n'\
' TP_ARGS($8, $9, $10, $11),\n'\
' TP_STRUCT__entry(__field($4, $8) __field($5, $9) __field($6, $10) __field($7, $11)),\n'\
' TP_fast_assign(tp_assign($4, $8, $8) tp_assign($5, $9, $9) tp_assign($6, $10, $10) tp_assign($7, $11, $11)),\n'\
' TP_printk()\n'\
')\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
# types: 4 5 6 7 8
# args 9 10 11 12 13
NRARGS=5
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^)]*)\) '\
'args: \(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_TRACE_EVENT(sys_$1,\n'\
' TP_PROTO($4 $9, $5 $10, $6 $11, $7 $12, $8 $13),\n'\
' TP_ARGS($9, $10, $11, $12, $13),\n'\
' TP_STRUCT__entry(__field($4, $9) __field($5, $10) __field($6, $11) __field($7, $12) __field($8, $13)),\n'\
' TP_fast_assign(tp_assign($4, $9, $9) tp_assign($5, $10, $10) tp_assign($6, $11, $11) tp_assign($7, $12, $12) tp_assign($8, $13, $13)),\n'\
' TP_printk()\n'\
')\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
# types: 4 5 6 7 8 9
# args 10 11 12 13 14 15
NRARGS=6
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) '\
'types: \(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^\)]*)\) '\
'args: \(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^\)]*)\)/'\
'#ifndef OVERRIDE_'"${BITNESS}"'_sys_$1\n'\
'SC_TRACE_EVENT(sys_$1,\n'\
' TP_PROTO($4 $10, $5 $11, $6 $12, $7 $13, $8 $14, $9 $15),\n'\
' TP_ARGS($10, $11, $12, $13, $14, $15),\n'\
' TP_STRUCT__entry(__field($4, $10) __field($5, $11) __field($6, $12) __field($7, $13) __field($8, $14) __field($9, $15)),\n'\
' TP_fast_assign(tp_assign($4, $10, $10) tp_assign($5, $11, $11) tp_assign($6, $12, $12) tp_assign($7, $13, $13) tp_assign($8, $14, $14) tp_assign($9, $15, $15)),\n'\
' TP_printk()\n'\
')\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
# Macro for tracing syscall table
rm -f ${TMPFILE}
for NRARGS in $(seq 0 6); do
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} >> ${TMPFILE}
done
echo \
"
#endif /* _TRACE_SYSCALLS_${CLASSCAP}_H */
/* This part must be outside protection */
#include \"../../../probes/define_trace.h\"
#else /* CREATE_SYSCALL_TABLE */
#include \"${INPUTFILE}_${CLASS}_override.h\"
#include \"syscalls_${CLASS}_override.h\"
" >> ${HEADER}
NRARGS=0
if [ "$CLASS" = integers ]; then
#noargs
grep "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) .*$/'\
'#ifndef OVERRIDE_TABLE_'"${BITNESS}"'_sys_$1\n'\
'TRACE_SYSCALL_TABLE\(syscalls_noargs, sys_$1, $2, $3\)\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
fi
#others.
grep -v "^syscall [^ ]* nr [^ ]* nbargs ${NRARGS} " ${SRCFILE} > ${TMPFILE}
perl -p -e 's/^syscall ([^ ]*) nr ([^ ]*) nbargs ([^ ]*) .*$/'\
'#ifndef OVERRIDE_TABLE_'"${BITNESS}"'_sys_$1\n'\
'TRACE_SYSCALL_TABLE(sys_$1, sys_$1, $2, $3)\n'\
'#endif/g'\
${TMPFILE} >> ${HEADER}
echo -n \
"
#endif /* CREATE_SYSCALL_TABLE */
" >> ${HEADER}
#fields names: ...char * type with *name* or *file* or *path* or *root*
# or *put_old* or *type*
cp -f ${HEADER} ${TMPFILE}
rm -f ${HEADER}
perl -p -e 's/__field\(([^,)]*char \*), ([^\)]*)(name|file|path|root|put_old|type)([^\)]*)\)/__string_from_user($2$3$4, $2$3$4)/g'\
${TMPFILE} >> ${HEADER}
cp -f ${HEADER} ${TMPFILE}
rm -f ${HEADER}
perl -p -e 's/tp_assign\(([^,)]*char \*), ([^,]*)(name|file|path|root|put_old|type)([^,]*), ([^\)]*)\)/tp_copy_string_from_user($2$3$4, $5)/g'\
${TMPFILE} >> ${HEADER}
#prettify addresses heuristics.
#field names with addr or ptr
cp -f ${HEADER} ${TMPFILE}
rm -f ${HEADER}
perl -p -e 's/__field\(([^,)]*), ([^,)]*addr|[^,)]*ptr)([^),]*)\)/__field_hex($1, $2$3)/g'\
${TMPFILE} >> ${HEADER}
#field types ending with '*'
cp -f ${HEADER} ${TMPFILE}
rm -f ${HEADER}
perl -p -e 's/__field\(([^,)]*\*), ([^),]*)\)/__field_hex($1, $2)/g'\
${TMPFILE} >> ${HEADER}
#strip the extra type information from tp_assign.
cp -f ${HEADER} ${TMPFILE}
rm -f ${HEADER}
perl -p -e 's/tp_assign\(([^,)]*), ([^,]*), ([^\)]*)\)/tp_assign($2, $3)/g'\
${TMPFILE} >> ${HEADER}
rm -f ${INPUTFILE}.tmp
rm -f ${TMPFILE}
rm -f ${SRCFILE}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment