前言
本文描述一个问题的常用定位方法以及如何解决。运行的环境为在linux4.19内核版本下运行一个app代码发现系统调用报错。特用此文记录该问题的解决思路。
问题描述
简单写一个epoll相关的测试代码
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/epoll.h>
int main(void)
{
int fd = -1;
fd = epoll_create1 (EPOLL_CLOEXEC);
if(fd < 0) {
printf("ret:%d,%d[%s]\n", fd, errno, strerror(errno));
perror("abd2233");
}
printf("ret:%d\n", fd);
while(1)
{
sleep(1);
}
return 0;
}
1.编译生成epoll的可执行程序
2.运行如下报错,表示函数不可达。
/mnt/nfs #
/mnt/nfs # ./epoll
ret:-1,38[Function not implemented]
abd2233: Function not implemented
ret:-1
分析
1.由于该函数是系统调用函数,那么其调用一定是通过c库调用。那么首先就要看c库里面是否有其代码的实现
/mnt/nfs # grep -rn “epoll_create1” /lib/libc.so.1
25108:epoll_create1
/mnt/nfs #
2.假如c库没有实现那么就需要更换更高版本的c库或者工具链
3.明明c库有实现,却提示函数为实现,那么有可能是系统调用出了问题,继续往下挖掘
4.既然怀疑系统调用出了问题,那么就需要大致了解下系统调用的过程。
系统调用
系统调用表
1.可以尝试在编译工具链目录下寻找下系统调用表如下图所示。
arm-ca9-linux-uclibcgnueabihf-8.4.01\share\gdb\syscalls
2.也可以在内核目录下./arch/arm/目录下搜索系统调用函数 也能收到表
grep -Rn ‘epoll_create1’ ./arch/arm/
3.我们知道系统调用是通过系统调用号来进行匹配对应执行的(由app切入内核)。发现epoll_create1的系统调用号 357 号码对上没看到实体定义,同时定义了宏__NR_epoll_create1
4.系统调用相关的函数在./include/uapi/ 一定有线索,再次搜索grep -Rn ‘__NR_epoll_create1’ ./include/uapi/
SYSCALL_DEFINE1(epoll_create1, int, flags)
5.发现有一个__SYSCALL就是系统调用的定义,参数前面是号码后面是实现实体
到这个文件里面去看 它的实体是sys_epoll_create1 且有提示在/* fs/eventpoll.c */中实现
6.去eventpoll.c文件下查看,但是在 fs/eventpoll.c中并没有发现sys_epoll_create1函数实现
去kernel目录下搜索实体
grep -Rn ‘sys_epoll_create1’ ./kernel/
发现只有.o有,说明很有可能是宏拼接的
7.查看该文件果然,同时也有提示我们去fs/eventpoll.c查看,说明
sys_epoll_create1的实现在fs/eventpoll.c 的epoll_create1函数。
同时在eventpoll.c中,这个SYSCALL_DEFINE1展开就是定义
sys_epoll_create1
编译
1.查看是否编译进内核,去fs/eventpoll.c 目录查看发现没有相对应的.o文件,发现没有编译
2.查看makefile,该文件编译需要这个宏CONFIG_EPOLL
3.查看.config 确实没有定义
4.打开内核配置将相对应的内核配置上即可
结论
系统调用报错无非在两个地方有可能出错,那便是c库没有实现该系统调用以及内核不支持该系统调用
解决方法:1.确定c库有该系统调用的实体,2.修改内核配置文件从新编译该内核使其支持该系统调用。