Black God

System Call tracing in Linux (strace)

strace:

When there is a definitive guide to learn Linux system programming, it is heaven to read and practice those examples. Some times we may need to implement some function which is available in the well known tools (or commercial tools), but we may not know which system call to use to accomplish some of the tasks. I too faced such problems. Then I found that strace is handy command for this purpose. This is very much useful for debugging purpose.

How to use it?

strace -o <trace file name> <your command> <arguments of command if any>

For example if I want to trace what system calls are used by fdisk while I am listing all partitions in my system (fdisk -l), here is the command with strace feature:

# strace -o fdisk-trace.log fdisk -l

Here is the output on console:

Disk /dev/hda: 20.5 GB, 20547841536 bytes
255 heads, 63 sectors/track, 2498 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/hda1 * 1 13 104391 83 Linux
/dev/hda2 14 2368 18916537+ 83 Linux
/dev/hda3 2369 2498 1044225 82 Linux swap

Here is the fdisk-trace.log file which lists all system calls called by fdisk with argument and return values.:

execve(“/sbin/fdisk”, ["/sbin/fdisk", "-l"], [/* 26 vars */]) = 0
uname({sys=”Linux”, node=”pr000.hcl.cp.net”, …}) = 0
brk(0) = 0x805ff48
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0×40016000
open(“/etc/ld.so.preload”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/etc/ld.so.cache”, O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=75477, …}) = 0
old_mmap(NULL, 75477, PROT_READ, MAP_PRIVATE, 3, 0) = 0×40017000
close(3) = 0
open(“/lib/tls/libc.so.6″, O_RDONLY) = 3
read(3, “\177ELF\1\1\1\3\3\1`V\1B4″…, 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1531064, …}) = 0
old_mmap(0×42000000, 1257224, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0×42000000
old_mmap(0x4212e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12e000) = 0x4212e000
old_mmap(0×42131000, 7944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0×42131000
close(3) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0x40016a20, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0×40017000, 75477) = 0
brk(0) = 0x805ff48
brk(0x8060f48) = 0x8060f48
brk(0) = 0x8060f48
brk(0×8061000) = 0×8061000
open(“/usr/lib/locale/locale-archive”, O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=30301680, …}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0×40017000
close(3) = 0
open(“/proc/partitions”, O_RDONLY|O_LARGEFILE) = 3

:-) It accesses /proc/partitions pseudo file for partition information.

read(3, “major minor #blocks name r”…, 32768) = 412
open(“/proc/ide/hda/media”, O_RDONLY|O_LARGEFILE) = 4

:-) It accesses /proc/ide/hda/media for type of storage device. This /proc/ide/hda has more harddisk related description and settings details.

fstat64(4, {st_mode=S_IFREG|0444, st_size=0, …}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0×40217000
read(4, “disk\n”, 4096) = 5
close(4) = 0
munmap(0×40217000, 4096) = 0
open(“/dev/hda”, O_RDONLY|O_LARGEFILE) = 4
open(“/dev/hda”, O_RDONLY|O_LARGEFILE) = 5

:-) It opens /dev/hda and gets the handle.

read(5, “\353H\220lbaLILO\1\25\4Z\vW4=\3640\300\1″…, 512) = 512
uname({sys=”Linux”, node=”pr000.hcl.cp.net”, …}) = 0
ioctl(5, BLKSSZGET, 0xbfff73e4) = 0
fstat64(5, {st_mode=S_IFBLK|0660, st_rdev=makedev(3, 0), …}) = 0
ioctl(5, 0×301, 0xbfff73e0) = 0
ioctl(5, BLKGETSIZE, 0xbfff7408) = 0

:-) Handle of /dev/hda used to call ioctl implemented by /dev/hda driver. The IOCTL code BLKSSZGET gets the size of a block

_llseek(5, 0, [0], SEEK_SET) = 0
read(5, “\353H\220lbaLILO\1\25\4Z\vW4=\3640\300\1″…, 8192) = 8192
close(5) = 0
open(“/usr/share/locale/locale.alias”, O_RDONLY) = 5
fstat64(5, {st_mode=S_IFREG|0644, st_size=2601, …}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0×40217000
read(5, “# Locale name alias data base.\n#”…, 4096) = 2601
brk(0) = 0×8061000
brk(0×8062000) = 0×8062000
read(5, “”, 4096) = 0
close(5) = 0
munmap(0×40217000, 4096) = 0
open(“/usr/share/locale/en_US.UTF-8/LC_MESSAGES/util-linux.mo”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/usr/share/locale/en_US.utf8/LC_MESSAGES/util-linux.mo”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/usr/share/locale/en_US/LC_MESSAGES/util-linux.mo”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/usr/share/locale/en.UTF-8/LC_MESSAGES/util-linux.mo”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/usr/share/locale/en.utf8/LC_MESSAGES/util-linux.mo”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/usr/share/locale/en/LC_MESSAGES/util-linux.mo”, O_RDONLY) = -1 ENOENT (No such file or directory)
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), …}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0×40217000
write(1, “\n”, 1) = 1
write(1, “Disk /dev/hda: 20.5 GB, 20547841″…, 42) = 42
write(1, “255 heads, 63 sectors/track, 249″…, 44) = 44
write(1, “Units = cylinders of 16065 * 512″…, 50) = 50
write(1, ” Device Boot Start En”…, 57) = 57
open(“/usr/lib/gconv/gconv-modules.cache”, O_RDONLY) = 5
fstat64(5, {st_mode=S_IFREG|0644, st_size=21040, …}) = 0
mmap2(NULL, 21040, PROT_READ, MAP_SHARED, 5, 0) = 0×40218000
close(5) = 0
write(1, “/dev/hda1 * 1 1″…, 56) = 56
write(1, “/dev/hda2 14 236″…, 56) = 56
write(1, “/dev/hda3 2369 249″…, 61) = 61
read(3, “”, 32768) = 0
close(3) = 0
munmap(0×40217000, 4096) = 0
exit_group(0) = ?

Conclusion:

I hope this information will sure be helpful to those who don’t know such a nice feature exists in Linux command line.

2 comments for “System Call tracing in Linux (strace)

  1. November 23, 2008 at 4:25 pm

    Thanx any way…

  2. October 30, 2008 at 12:06 am

    old article ;)

Leave a Reply

Your email address will not be published. Required fields are marked *