2

How can i check if a function is part of the kernel or user space? (or could be both too) Is there any overview over all kernel libs/functions?

Working with C in Unix environment.

e.g. rand() is pure user space, malloc() is user and kernel space etc..

The manual pages doesn't contain any information.

Leviathan
  • 928
  • 1
  • 6
  • 15
  • 1
    Why do you need to know? – Ed Heal Jan 25 '15 at 14:05
  • I would like to have an overview, because its important to know where functions have their roots. That's necessary for effective programming. – Leviathan Jan 25 '15 at 14:08
  • All functions called from user space are "user mode" functions. They *might* however invoke the kernel. To turn this around: You cannot invoke kernel-functionality from user space directly. – alk Jan 25 '15 at 14:09
  • Also you seem to mix up user-mode and user-space. Or should I have totally misunderstood the question? – alk Jan 25 '15 at 14:12
  • That's my mistake, i am talking about the "space". – Leviathan Jan 25 '15 at 14:18
  • 1
    All functions are user mode in user mode programs and kernel mode in kernels. A user mode programa can call the kernel by means of a system call. It should be intuitively clear which functions require OS services to work and which do not. Roughly, anything that has to do with I/O or memory allocation potentially needs the OS. – n. m. could be an AI Jan 25 '15 at 14:19
  • 1
    "necessary for effective programming" — dubious. Why? – n. m. could be an AI Jan 25 '15 at 14:22
  • If you gotta use the kernel you gotta use the kernel - not a lot you can do about it – Ed Heal Jan 25 '15 at 14:27
  • @n.m. Because when you writing system software you should know where the functions relate to. Many kernel-function-calls can reduce your performance. Kernel-mode function calls are more "expensive" then User-mode functions. – Leviathan Jan 25 '15 at 14:30
  • Of course that is true - but you need the kernel to write to disk,. You cannot get away without using the kernel. – Ed Heal Jan 25 '15 at 14:36
  • 1
    @EdHeal, _but you need the kernel to write to disk_. That's true, but knowing that disk access is slow, you may choose to minimize it and hold data in memory whenever possible. Similarly, if you know that `malloc` requires a system call, which involves an "expensive" context switch, you might choose to store the data on stack or in global variable. These are micro optimizations we are talking about here, but still... – Super-intelligent Shade Jan 25 '15 at 15:16
  • That is true - but those libraries have already been written stdio/malloc does this for you. You can avoid dynamic memory altogether kif you wish. – Ed Heal Jan 25 '15 at 15:18
  • Agreed. I was just trying to say there are valid use cases, where these things need to be thought of. I had worked on an embedded project once, where I literally had to count CPU clocks for each instruction trying to optimize the code :) – Super-intelligent Shade Jan 25 '15 at 15:23
  • Knowing whether your function calls the kernel or not can only give you a very vague idea about its real-world performance. Not nearly enough to assess efficiency of a program that uses it. You need far more specific knowledge about each function. – n. m. could be an AI Jan 25 '15 at 17:11

3 Answers3

1

This article should give you some info on system calls (into kernel space). Now you can use this rough (and not very accurate) guideline:

  1. All man pages from section 2 are system calls.

  2. If a man page is from section 3, look in the SEE ALSO part at the bottom to see if it uses any commands from section 2. (Might also need to read through the man page itself.)

Again, this is not very accurate, but short of reading the source code, it should give you an idea.

0

Throughout it's run-time, a process computes a lot of system calls starting even before it's actually run.

You've got some options to debug those:

  • Compile your own glibc with debugging information
  • strace
  • gdb

The third option is probably the best one, especially if you're just interested in one function rather than a set of functions (where strace would be better). Indeed, gdb allows you to catch the system calls made by the attached process or some specific ones; you can obtain this with catch syscall number or catch syscall to catch them all.

You might also want to avoid the calls made by the dynamic linker at runtime by compiling the code with -static.

edmz
  • 8,220
  • 2
  • 26
  • 45
0

Depends on what you call "kernel mode" function. If I understood you correct, you mean that some C functions ask to do something, like malloc() calls brk() so kernel would increase process heap size.

So everything you need is detect which functions ask something from kernel which usually done in by calling a System Call such as brk().

Now it's time to determine which functions call which system calls. There are two ways to do that:

  • Static code analys. Just build a callgraph of a glibc, then plot graphs where root is a syscall. The only problem is complexity of glibc, so it would be hard to build entire callgraph.
  • Dynamic code analysis. Attach a debugger/tracer to your process, and when process calls a syscall, print its stack. This approach doesn't cover all functions and cases, but easy to implement.

I.e. using gdb:

myaut@panther:~> gdb /bin/cat
...
(gdb) b brk
Function "brk" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
(gdb) commands 1
> bt
> cont
> end
(gdb) r
Starting program: /bin/cat 

...

Breakpoint 1, __brk (addr=0x62d000) at ../sysdeps/unix/sysv/linux/x86_64/brk.c:28
28      in ../sysdeps/unix/sysv/linux/x86_64/brk.c
#0  __brk (addr=0x62d000) at ../sysdeps/unix/sysv/linux/x86_64/brk.c:28
#1  0x00007ffff7b0eea5 in __GI___sbrk (increment=135168) at sbrk.c:53
#2  0x00007ffff7aaeda9 in __GI___default_morecore (increment=<optimized out>) at morecore.c:48
#3  0x00007ffff7aaaa37 in sysmalloc (av=0x7ffff7dd5640 <main_arena>, nb=32) at malloc.c:2454
#4  _int_malloc (av=0x7ffff7dd5640 <main_arena>, bytes=5) at malloc.c:3718
#5  0x00007ffff7aac263 in __GI___libc_malloc (bytes=5) at malloc.c:2859
...
#10 0x0000000000401d8a in main (argc=1, argv=0x7fffffffdd08) at cat.c:563

Or some dynamic tracing engine such as SystemTap (Linux):

# stap -e '
        probe syscall.brk { 
            if(pid() == target()) 
                print_ubacktrace(); 
        } ' -c /bin/cat -d /lib/x86_64-linux-gnu/libc.so.6
...
0x7f5edb427ffa : brk+0xa/0x70 [/lib/x86_64-linux-gnu/libc-2.13.so]
0x7f5edb4280ad : sbrk+0x4d/0xb0 [/lib/x86_64-linux-gnu/libc-2.13.so]
0x7f5edb3d0ae9 : __default_morecore+0x9/0xb0 [/lib/x86_64-linux-gnu/libc-2.13.so]
0x7f5edb3cd1e6 : malloc_trim+0x15e6/0x23c0 [/lib/x86_64-linux-gnu/libc-2.13.so]
0x7f5edb3cec00 : malloc+0x70/0x340 [/lib/x86_64-linux-gnu/libc-2.13.so]
...
0x401bea [/bin/cat+0x1bea/0xc000]

Or DTrace:

root@sol11:~# dtrace -n '
            syscall::brk:entry 
            /pid == $target/ { 
                ustack() 
            }' -c '/bin/cat'
CPU     ID                    FUNCTION:NAME
0     58                        brk:entry 
            libc.so.1`_brk_unlocked+0x15
            libc.so.1`sbrk+0x38
            ...
            libc.so.1`malloc+0x38
            libc.so.1`strdup+0x29
            libc.so.1`expand_locale_name+0x333
            libc.so.1`setlocale+0x89c
            cat`main+0x23
            cat`_start+0x7d
myaut
  • 11,174
  • 2
  • 30
  • 62