1

I've been given source code in C and want to see which parts (functions, system calls) of POSIX is used in it.

Is there a test suite or other program, which can give me an overview?

Minix
  • 5,855

2 Answers2

3

If you can compile and run the code, and if seeing what sys calls it makes is adequate (i.e. you can exercise everything you need to know about) then

strace myapp

will run myapp and list all the system calls (POSIX and other) it makes.

0

strace traces system calls. POSIX includes both system calls and functions. Some platforms support an analogous ltrace (tracing library calls).

For example, the date command-line utility with ltrace would show something like this:

__libc_start_main(0x401a50, 1, 0x7ffe41310418, 0x40a100, 0x40a0f0 <unfinished ...>
strrchr("date", '/')                             = NULL
setlocale(6, "")                                 = "en_US.UTF-8"
bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
textdomain("coreutils")                          = "coreutils"
__cxa_atexit(0x402b60, 0, 0, 0x736c6974756572, 0x7f8c29d9bea8) = 0
getenv("POSIXLY_CORRECT")                        = NULL
nl_langinfo(131180, 0x40b6b9, 0, 0, 0)           = 0x7f8c23e98955
clock_gettime(0, 0x7ffe41310260, 0x20ef440, 0, 0) = 0
localtime(0x7ffe413101d0)                        = 0x7f8c29d9f380
strftime("", 140239874654731, NULL, 0x7ffe4130fd63) = 4
fwrite("Mon", 3, 1, 0x7f8c29d9a7a0)              = 1
fputc(' ', 0x7f8c29d9a7a0)                       = 32
strftime("", 140239874654844, NULL, 0x7ffe4130fd63) = 4
fwrite("Sep", 3, 1, 0x7f8c29d9a7a0)              = 1
fputc(' ', 0x7f8c29d9a7a0)                       = 32
fwrite("12\004\200\0011A\376\177", 2, 1, 0x7f8c29d9a7a0) = 1
fputc(' ', 0x7f8c29d9a7a0)                       = 32
fwrite("17\004\200\0011A\376\177", 2, 1, 0x7f8c29d9a7a0) = 1
fputc(':', 0x7f8c29d9a7a0)                       = 58
fwrite("43\004\200\0011A\376\177", 2, 1, 0x7f8c29d9a7a0) = 1
fputc(':', 0x7f8c29d9a7a0)                       = 58
fwrite("52\004\200\0011A\376\177", 2, 1, 0x7f8c29d9a7a0) = 1
fputc(' ', 0x7f8c29d9a7a0)                       = 32
strlen("EDT")                                    = 3
fwrite("EDT", 3, 1, 0x7f8c29d9a7a0)              = 1
fputc(' ', 0x7f8c29d9a7a0)                       = 32
fwrite("2016\004\200\0011A\376\177", 4, 1, 0x7f8c29d9a7a0) = 1
__overflow(0x7f8c29d9a7a0, 10, 4, 54, 0x7f8c2a1c401c) = 10
exit(0 <unfinished ...>
...

while strace shows something different:

execve("/bin/date", ["date"], [/* 60 vars */]) = 0
brk(0)                                  = 0x1ac9000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff3eed91000
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=132177, ...}) = 0
mmap(NULL, 132177, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff3eed70000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/librt.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\220!\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=31744, ...}) = 0
mmap(NULL, 2128856, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff3ee96c000
mprotect(0x7ff3ee973000, 2093056, PROT_NONE) = 0
mmap(0x7ff3eeb72000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7ff3eeb72000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", 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\300\357\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1607696, ...}) = 0
mmap(NULL, 3721272, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff3ee5df000
mprotect(0x7ff3ee763000, 2093056, PROT_NONE) = 0
mmap(0x7ff3ee962000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183000) = 0x7ff3ee962000
mmap(0x7ff3ee967000, 18488, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff3ee967000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libpthread.so.0", 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@\\\0\0\0\0\0\0"..., 832) = 832
...

For both cases, I've only given a sample. But if you were to compare the two complete traces you would not see much correlation between the two. This is not always true: functions which do I/O can be matched fairly closely between the two. But only the very end of the strace log shows any I/O which can be matched against the ltrace log. All of those fwrite and fputc calls become in-memory work until the write system call at the end:

open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=110939968, ...}) = 0
mmap(NULL, 110939968, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff3e79f6000
close(3)
open("/etc/localtime", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3519, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=3519, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff3eed90000
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\0"..., 4096) = 3519
lseek(3, -2252, SEEK_CUR)               = 1267
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0\5\0\0\0\0"..., 4096) = 2252
close(3)                                = 0
munmap(0x7ff3eed90000, 4096)            = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff3eed90000
write(1, "Mon Sep 12 17:43:41 EDT 2016\n", 29) = 29
close(1)                                = 0
munmap(0x7ff3eed90000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?

In both traces, the names beginning with underscores are definitely non-POSIX. Some others also are implementation-specific such as the exit_group call.

If you have no source-code for the application and can only observe a binary, there is no plausible way to improve this approach. POSIX is based on a variety of features which use the source-code of an application. For instance, some of the features depend on the system header files against which the application is compiled, while other features depend on the behavior of command-line utilities. The POSIX certification tests use the observable behavior of an application given its source code, using the standard interfaces. Internal details may differ, and those are what strace/ltrace show you, as noted in the example with exit_group.

Further reading:

Thomas Dickey
  • 76,765
  • These are not good tools to discover what interfaces an application are using because they work at a too low level. For example a POSIX interface may be declared as a macro or as a function that's optimized by the compiler so that ltrace only sees a system-specific internal library call. – Gilles 'SO- stop being evil' Sep 13 '16 at 06:14