我已经获得了 C 语言的源代码,并且想看看其中使用了 POSIX 的哪些部分(函数、系统调用)。
是否有测试套件或其他程序可以让我有一个概述?
答案1
如果您可以编译并运行代码,并且如果查看它所做的 sys 调用就足够了(即您可以练习您需要了解的所有内容),那么
strace myapp
将运行myapp
并列出它进行的所有系统调用(POSIX 和其他)。
答案2
strace
痕迹系统来电。 POSIX 包括两者系统来电和功能。一些平台支持类似的ltrace
(跟踪图书馆来电)。
例如,date
命令行实用程序 withltrace
将显示如下内容:
__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 ...>
...
whilestrace
显示不同的东西:
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
...
对于这两种情况,我只给出了一个示例。但如果您要比较两个完整的轨迹,您将不会发现两者之间有太多相关性。这并不总是正确的:执行 I/O 的函数在两者之间可以相当接近地匹配。但只有日志的最后部分strace
显示可以与日志匹配的任何 I/O ltrace
。所有这些fwrite
和fputc
调用都变成内存中的工作,直到write
最后的系统调用:
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) = ?
在这两个跟踪中,以下划线开头的名称肯定是非 POSIX 的。其他一些也是特定于实现的,例如exit_group
调用。
如果您没有应用程序的源代码并且只能观察二进制文件,则没有可行的方法来改进这种方法。 POSIX 基于使用应用程序源代码的各种功能。例如,某些功能取决于编译应用程序所依据的系统头文件,而其他功能则取决于命令行实用程序的行为。 POSIX 认证测试使用标准接口在给定源代码的情况下应用程序的可观察行为。内部细节可能有所不同,这些是 strace/ltrace 向您展示的内容,如 示例中所述exit_group
。
进一步阅读: