On Sat, 28 Sep 2013 15:47:10 +0300
Pauli Nieminen <[email protected]> wrote:

> Some kernel packagers like to disable syscalls ftrace events claiming it
> would be runtime overhead. But those kernels still can have raw_syscalls
> events enabled. To be able to use stock kernels for tracing system
> behavior I decided to write simple translation plugin for trace-cmd.
> 
> Translation tables are automatically generated from asm/unistd*.h files
> during compilation. Those translation tables are then used to find
> possible matches from all supported syscall ids for the running system.
> 
> Possible improvements to build on top of this:
> * Is it possible to figure out the architecture for sure from trace data?
> * UI communication to allow user to select process architecture
> * Heuristics to guess the process architecture from syscall patterns
> 
> Is this idea worth of cleaning to be good enough to apply?
> Is auto generated or manual syscall tables better idea?
> 

Sorry for the very late reply, but do you have any plans on extending
this? This looks very useful.

This got lost in my INBOX, and I just recently discovered it.

-- Steve


> Signed-off-by: Pauli Nieminen <[email protected]>
> ---
>  .gitignore            |   1 +
>  Makefile              |  40 +++++++++++++++--
>  plugin_raw_syscalls.c | 121 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  plugin_raw_syscalls.h |  12 +++++
>  unistd.c.in           |   7 +++
>  5 files changed, 178 insertions(+), 3 deletions(-)
>  create mode 100644 plugin_raw_syscalls.c
>  create mode 100644 plugin_raw_syscalls.h
>  create mode 100644 unistd.c.in
> 
> diff --git a/.gitignore b/.gitignore
> index b7b405f..870c4f3 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -20,3 +20,4 @@ TAGS
>  cscope*
>  trace_plugin_dir
>  trace_python_dir
> +plugin_raw_syscall_unistd*.c
> diff --git a/Makefile b/Makefile
> index 1964949..b2584e4 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -248,6 +248,7 @@ ifeq ($(VERBOSE),1)
>    print_plugin_obj_compile =
>    print_plugin_build =
>    print_install =
> +  print_unistd_source_gen =
>  else
>    Q = @
>    print_compile =            echo '  $(GUI)COMPILE            '$(GOBJ);
> @@ -258,6 +259,7 @@ else
>    print_plugin_build =               echo '  $(GUI)BUILD PLUGIN       
> '$(GOBJ);
>    print_static_lib_build =   echo '  $(GUI)BUILD STATIC LIB   '$(GOBJ);
>    print_install =            echo '  $(GUI)INSTALL     '$(GSPACE)$1' to      
> $(DESTDIR_SQ)$2';
> +  print_unistd_source_gen =  echo '  $(GUI)GEN                '$(GOBJ);
>  endif
>  
>  do_fpic_compile =                                    \
> @@ -276,9 +278,30 @@ do_compile_plugin_obj =                          \
>       ($(print_plugin_obj_compile)            \
>       $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
>  
> +do_gen_unistd_source =                                                       
>         \
> +     ($(print_unistd_source_gen)                                             
> \
> +     ARCH_UNISTD=$<;                                                         
> \
> +     ARCH=`echo $$ARCH_UNISTD | sed 's/^.*d_\(.*\).h$$/\1/'` || exit $$?;    
> \
> +     ARCH_UNISTD_INCL=`echo $$ARCH_UNISTD | sed 's/^.*asm/asm/'`;            
> \
> +     PREFIX=raw_syscalls_$$ARCH;                                             
> \
> +     echo "const char $${PREFIX}_arch[] = \"$$ARCH\";" > $@;                 
> \
> +     echo "/* $(UNISTD_H_PATH) defines */" >> $@;                            
> \
> +     grep "\#\s*define\s\+[A-Za-z_0-9]\+\s\+[A-Za-z_0-9(]\+" 
> $(UNISTD_H_PATH) >> $@; \
> +                                                                             
> \
> +     echo "/* $(ARCH_UNISTD) defines */" >> $@;                              
> \
> +     echo "\#include <$$ARCH_UNISTD_INCL>" >> $@;                            
> \
> +                                                                             
> \
> +     echo "/* syscall table */" >> $@;                                       
> \
> +     echo "\#include \"plugin_raw_syscalls.h\"" >> $@;                       
>         \
> +     echo "static const struct raw_syscalls_entry $${PREFIX}_syscalls[] = {" 
> >> $@; \
> +     sed -n 
> "s/^.*\#\s*define\s\+__NR_\([A-Za-z_0-9]\+\)\s\+\(.*\)\s*$$/{\"\1\", \2},/p" 
> < $$ARCH_UNISTD >> $@; \
> +     echo "};" >> $@;                                                        
> \
> +                                                                             
> \
> +     sed "s/PREFIX/$$PREFIX/g" < $(UNISTD_TEMPLATE) >> $@)
> +
>  do_plugin_build =                            \
>       ($(print_plugin_build)                  \
> -     $(CC) $(CFLAGS) $(LDFLAGS) -shared -nostartfiles -o $@ $<)
> +     $(CC) $(CFLAGS) $(LDFLAGS) -shared -nostartfiles -o $@ $^)
>  
>  do_build_static_lib =                                \
>       ($(print_static_lib_build)              \
> @@ -318,7 +341,7 @@ TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o 
> trace-input.o trace-ftrace.o \
>  
>  PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \
>       plugin_mac80211.o plugin_jbd2.o plugin_function.o plugin_kvm.o \
> -     plugin_blk.o
> +     plugin_blk.o plugin_raw_syscalls.o
>  
>  PLUGINS := $(PLUGIN_OBJS:.o=.so)
>  
> @@ -332,6 +355,11 @@ GUI_TARGETS = ks_version.h trace-graph trace-view 
> kernelshark
>  
>  TARGETS = $(CMD_TARGETS) $(GUI_TARGETS)
>  
> +ARCH_INCL_PATH ?= /usr/include/$(shell $(CC) $(CFLAGS) -print-multiarch)/asm
> +UNISTD_H_PATH ?= $(ARCH_INCL_PATH)/unistd.h
> +UNISTD_ARCH_HEADERS = $(notdir $(shell sed -n 
> 's/^\s*\#\s*include\s\+<\(.*\)>\s*$$/\1/p' $(UNISTD_H_PATH)))
> +UNISTD_OBJS = $(patsubst %.h,plugin_raw_syscalls_%.o, $(UNISTD_ARCH_HEADERS))
> +UNISTD_TEMPLATE = unistd.c.in
>  
>  #    cpp $(INCLUDES)
>  
> @@ -388,12 +416,17 @@ libtracecmd.a: $(TCMD_LIB_OBJS)
>  
>  trace-util.o: trace_plugin_dir
>  
> -$(PLUGIN_OBJS): %.o : $(src)/%.c
> +$(PLUGIN_OBJS) $(UNISTD_OBJS): %.o : $(src)/%.c
>       $(Q)$(do_compile_plugin_obj)
>  
> +$(CURDIR)/plugin_raw_syscalls_%.c: $(ARCH_INCL_PATH)/%.h Makefile
> +     $(Q)$(do_gen_unistd_source)
> +
>  $(PLUGINS): %.so: %.o
>       $(Q)$(do_plugin_build)
>  
> +plugin_raw_syscalls.so: $(UNISTD_OBJS)
> +
>  define make_version.h
>       (echo '/* This file is automatically generated. Do not modify. */';     
>         \
>       echo \#define VERSION_CODE $(shell                                      
>         \
> @@ -546,6 +579,7 @@ install_doc:
>  clean:
>       $(RM) *.o *~ $(TARGETS) *.a *.so ctracecmd_wrap.c .*.d
>       $(RM) tags TAGS cscope*
> +     $(RM) plugin_raw_syscalls_unistd*.c
>  
>  
>  ##### PYTHON STUFF #####
> diff --git a/plugin_raw_syscalls.c b/plugin_raw_syscalls.c
> new file mode 100644
> index 0000000..e6270c0
> --- /dev/null
> +++ b/plugin_raw_syscalls.c
> @@ -0,0 +1,121 @@
> +/*
> + * Copyright (C) 2013 Pauli Nieminen <[email protected]
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation;
> + * version 2.1 of the License (not later!)
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this program; if not,  see 
> <http://www.gnu.org/licenses>
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +
> +#include <limits.h>
> +#include <search.h>
> +
> +#include "trace-cmd.h"
> +#include "plugin_raw_syscalls.h"
> +
> +static struct raw_syscalls_tables {
> +     const char *name;
> +     size_t nr_calls;
> +     const struct raw_syscalls_entry *table;
> +     int in_order;
> +     struct raw_syscalls_tables *next;
> +} *raw_syscalls_tables = NULL;
> +
> +static int syscalls_cmp(const void *va, const void *vb)
> +{
> +     const struct raw_syscalls_entry *a = va, *b = vb;
> +     return (int)(a->id - b->id);
> +}
> +
> +static int raw_syscalls_handler(struct trace_seq *s, struct pevent_record 
> *record,
> +                             struct event_format *event, void *context)
> +{
> +     unsigned long long val;
> +     long id;
> +     struct raw_syscalls_tables *table = raw_syscalls_tables;
> +
> +     if (pevent_get_field_val(s, event, "id", record, &val, 1))
> +             return trace_seq_putc(s, '!');
> +
> +     id = val;
> +
> +     while (table) {
> +             struct raw_syscalls_entry key = { .id = id };
> +             const struct raw_syscalls_entry *syscalls;
> +             if (table->in_order) {
> +                     syscalls = bsearch(&key, table->table,
> +                                        table->nr_calls,
> +                                        sizeof(table->table[0]),
> +                                        syscalls_cmp);
> +             } else {
> +                     syscalls = lfind(&key, table->table,
> +                                      &table->nr_calls,
> +                                      sizeof(table->table[0]),
> +                                      syscalls_cmp);
> +             }
> +
> +             if (syscalls) {
> +                     trace_seq_printf(s, "%s(%s) ",
> +                                      syscalls->name, table->name);
> +             }
> +             table = table->next;
> +     }
> +
> +     return 1;
> +}
> +
> +void raw_syscalls_register_table(const char *arch,
> +                              size_t nr_calls,
> +                              const struct raw_syscalls_entry *table)
> +{
> +     int i;
> +     long current_id = LONG_MIN;
> +     struct raw_syscalls_tables *lookup = malloc_or_die(sizeof(*lookup));
> +
> +     lookup->next = raw_syscalls_tables;
> +     raw_syscalls_tables = lookup;
> +
> +     lookup->name = arch;
> +     lookup->nr_calls = nr_calls;
> +     lookup->table = table;
> +     lookup->in_order = 1;
> +
> +     for (i = 0; i < nr_calls; i++) {
> +             if (table[i].id < current_id) {
> +                     lookup->in_order = 0;
> +                     break;
> +             }
> +             current_id = table[i].id;
> +     }
> +}
> +
> +int PEVENT_PLUGIN_UNLOADER(void)
> +{
> +     struct raw_syscalls_tables *next = raw_syscalls_tables;
> +     while (next) {
> +             struct raw_syscalls_tables *cur = next;
> +             next = cur->next;
> +             free(cur);
> +     }
> +     return 0;
> +}
> +
> +int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
> +{
> +     pevent_register_event_handler(pevent, -1, "raw_syscalls", "sys_enter",
> +                     raw_syscalls_handler, NULL);
> +     pevent_register_event_handler(pevent, -1, "raw_syscalls", "sys_exit",
> +                     raw_syscalls_handler, NULL);
> +     return 0;
> +}
> diff --git a/plugin_raw_syscalls.h b/plugin_raw_syscalls.h
> new file mode 100644
> index 0000000..daf968f
> --- /dev/null
> +++ b/plugin_raw_syscalls.h
> @@ -0,0 +1,12 @@
> +#pragma once
> +
> +#include <stddef.h>
> +
> +struct raw_syscalls_entry {
> +     const char *name;
> +     long id;
> +};
> +
> +void raw_syscalls_register_table(const char *arch,
> +                              size_t nr_calls,
> +                              const struct raw_syscalls_entry *table);
> diff --git a/unistd.c.in b/unistd.c.in
> new file mode 100644
> index 0000000..377dd27
> --- /dev/null
> +++ b/unistd.c.in
> @@ -0,0 +1,7 @@
> +
> +static __attribute__((constructor)) void PREFIX_init(void)
> +{
> +     raw_syscalls_register_table(PREFIX_arch,
> +                                 sizeof PREFIX_syscalls/sizeof 
> PREFIX_syscalls[0],
> +                                 PREFIX_syscalls);
> +};

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to