Monday, August 19, 2013

Trouble Shoot : Using Strace

When ever we run a command or a program in linux , there are 2 types of calls that are being made.

1.library calls – These are the calls that are done to a external library module.Most of the library functions are in the standard C library, libc.

2.System Calls – These are the very important calls that are implemented inside the linux Kernel.
When a program makes a system call, the arguments are packaged and sent to the kernel, which takes over execution of the program until the call completes. A system call is not just an ordinary function call, and a special procedure is required to transfer control to the kernel.

The system calls are the layer between the programs and kernel. Some system calls can be very dangerious like shutdown the system , passing resources to process . These have restrictions on who invokes these. Only a root user can has the access to invoke them but as a part of working some non-user started process also can invoke these calls.

Strace is a command available in linux which helps in debugging and troubleshooting the execution of a executable ( command or a process).Strace also tells you what is going with a program at this point. It can tell you what system calls the program is using and whether they pass or fail.
Lets use the Strace command and analyze the output. In the below example we will use the hostname command along with strace and see how it calls the kernel layer
Just invoke the strace with hostname like

[root@vx111a ~]# strace hostname
execve("/bin/hostname", ["hostname"], [/* 47 vars */]) = 0
brk(0) = 0x2190000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e18479000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=61740, ...}) = 0
mmap(NULL, 61740, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4e18469000
close(3) = 0
open("/lib64/libselinux.so.1", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 X\240@?\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=124624, ...}) = 0
mmap(0x3f40a00000, 2221912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3f40a00000
mprotect(0x3f40a1d000, 2093056, PROT_NONE) = 0
mmap(0x3f40c1c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c000) = 0x3f40c1c000
mmap(0x3f40c1e000, 1880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3f40c1e000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\355a??\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1912928, ...}) = 0
mmap(0x3f3f600000, 3737768, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3f3f600000
mprotect(0x3f3f787000, 2097152, PROT_NONE) = 0
mmap(0x3f3f987000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x187000) = 0x3f3f987000
mmap(0x3f3f98c000, 18600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3f3f98c000
close(3) = 0
open("/lib64/libdl.so.2", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\r ??\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=22536, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e18468000
mmap(0x3f3f200000, 2109696, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3f3f200000
mprotect(0x3f3f202000, 2097152, PROT_NONE) = 0
mmap(0x3f3f402000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x3f3f402000
close(3) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e18466000
arch_prctl(ARCH_SET_FS, 0x7f4e184667a0) = 0
mprotect(0x3f40c1c000, 4096, PROT_READ) = 0
mprotect(0x3f3f987000, 16384, PROT_READ) = 0
mprotect(0x3f3f402000, 4096, PROT_READ) = 0
mprotect(0x3f3f01f000, 4096, PROT_READ) = 0
munmap(0x7f4e18469000, 61740) = 0
statfs("/selinux", {f_type=0xf97cff8c, f_bsize=4096, f_blocks=0, f_bfree=0, f_bavail=0, f_files=0, f_ffree=0, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0
brk(0) = 0x2190000
brk(0x21b1000) = 0x21b1000
open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=99158752, ...}) = 0
mmap(NULL, 99158752, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4e125d5000
close(3) = 0
uname({sys="Linux", node="vx111a.jas.com", ...}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e18478000
write(1, "vx111a.jas.com\n", 15vx111a.jas.com) = 15
exit_group(0) = ?

We will see a couple of Screens as an Output.each line in the output is a System call. For each call, the system call’s name is listed, followed by its arguments (or abbreviated arguments, if they are very long) and its return value

execve("/bin/hostname", ["hostname"], [/* 47 vars */]) = 0

The first call is the execve call in which the first argument is the name of the program to run; the second is its argument list, consisting of only a single element; and the third is its environment list.

The next lines are part of loading the standard C library for obtaining the hostname.

The uname system call is used to obtain the system’s hostname from the kernel,
uname({sys="Linux", node="vx111a.jas.com", ...}) = 0

In the above uname call the strace helpfully labels the fields (sys and node) of the structure argument. This structure is filled in by the system call—Linux sets the sys field to the operating system name and the node field to the system’s hostname like

write(1, "vx111a.jas.com\n", 15) = 15

Finally, the write system call produces output. Recall that file descriptor 1 corresponds to standard output. The third argument is the number of characters to write, and the return value is the number of characters that were actually written.


We can analyze various system calls using the strace command available in linux.