如何在C程序中执行strace日志里字符串形式的系统调用并获取返回值?
问题
我有一份strace日志,希望在C程序中逐行执行其中以字符串形式呈现的系统调用。例如日志中的某一行内容为:openat(AT_FDCWD, "filename", O_RDONLY|O_CLOEXEC) = 4,请问是否存在可行的方法来执行这类系统调用,同时获取它们的返回值?
可行的实现方案
1. 解析strace日志行
首先要把日志字符串拆解为可执行的关键信息:
- 提取系统调用名称(如
openat) - 解析括号内的参数列表(如
AT_FDCWD、"filename"、O_RDONLY|O_CLOEXEC) - 区分参数类型:处理整数常量、字符串、位掩码(需将
|连接的宏转换为对应数值)
解析可借助正则表达式,比如匹配这类日志行的正则:
^(\w+)\((.*)\) = (-?\d+)$
通过捕获分组分别提取调用名、参数串、原进程返回值。
2. 执行系统调用的两种方式
方式一:调用C标准库封装函数
多数系统调用都有对应的C库函数(比如openat()直接可用),步骤如下:
- 建立系统调用名到函数指针的映射表(例如
{"openat", (void*)openat}) - 将解析后的参数转换为对应类型:字符串直接使用,位掩码需拆分宏并计算数值(如
O_RDONLY为0,O_CLOEXEC为0x80000,按位或得到最终flags值) - 调用函数并获取返回值
示例代码(openat为例):
#include <fcntl.h> #include <stdio.h> int main() { int dirfd = AT_FDCWD; const char* path = "filename"; int flags = O_RDONLY | O_CLOEXEC; int ret = openat(dirfd, path, flags); printf("openat执行返回值:%d\n", ret); return 0; }
方式二:用syscall()直接调用底层系统调用
若遇到无C库封装的系统调用,或需要更底层控制,可使用syscall()函数,需传入系统调用号和对应参数:
- 查找目标架构的系统调用号(比如x86_64架构下
openat的调用号是SYS_openat) - 将所有参数转换为
long类型(syscall()的参数统一为long) - 调用后获取返回值
示例代码:
#include <sys/syscall.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> int main() { long ret = syscall(SYS_openat, AT_FDCWD, "filename", O_RDONLY | O_CLOEXEC); printf("openat执行返回值:%ld\n", ret); return 0; }
3. 处理参数转换的难点
- 字符串参数:提取引号内内容,注意转义字符(如
\"需转为") - 宏常量:提前定义或通过预编译获取宏的实际数值(比如
AT_FDCWD的值是-100) - 位掩码:拆分
|连接的宏,分别取值后按位或计算最终值 - 指针参数:若遇到
write(fd, buf, len)这类带指针的调用,日志仅显示指针地址,无法直接获取缓冲区内容,需从上下文或其他日志行补充信息
4. 关键注意事项
- 系统调用会改变当前进程状态(如打开的文件描述符),执行后需妥善清理资源
- 需严格遵循日志行的执行顺序,保证系统调用的依赖关系(如先
open再read) - 当前进程权限可能与原进程不同,可能导致调用失败
- 执行后的返回值可能与日志中原进程的返回值不一致(比如文件描述符编号)
内容的提问来源于stack exchange,提问作者raffayatiq
相关产品推荐
相关产品推荐

