1.什么是系统调用?为什么要有系统调用?
系统调用是操作系统提供给用户的一些列特殊接口,用于访问系统资源,可以方便用户的使用,也可以约束用户的行为。
或由于能力 ,或由于意图,不能完全信任应用程序及其编写者,不允许用户直接控制硬件资源,硬件资源必须由操作系统统一管理,而不允许应用程序直接访问硬件(网络设备也在其列)。
操作系统只允许应用程序调用操作系统中封装的一系列命令,来间接使用硬件资源,这就是系统调用。
2.本次实验说明
1.实验平台和工具:本次实验基于WSL环境和xfce4,VcXsrvt产生的图形界面,通过gdb工具设置断点并进行调试
2.前置环境:在前一次实验中搭建的menuOS https://www.cnblogs.com/Miliapus/p/12031824.html(前一次实验使用实验楼虚拟环境,这次在WSL上重复了前一次实验的步骤
3.简述:带参数启动menuOs,打开gdb监听端口并设置断点,执行replyhi命令后分析执行情况
3.详细流程:
1.修改Makefile文件,加入参数-s -S -apend nokaslr用于调试
2.启用gdb并设置断点
先设置start_kernel以检查 断点是否工作
可见 断点确实起效
设置断点 break sys_socketcall
允许menuos完成启动
输入命令replyhi
到达断点
继续运行
可以观察到这个断点总计到达了两次
说明replyhi命令中 sys_socketcall运行了两次
我们猜测这两次应该是socket、bind
我们研究这个函数:
SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) { unsigned long a[AUDITSC_ARGS]; unsigned long a0, a1; int err; unsigned int len; if (call < 1 || call > SYS_SENDMMSG) return -EINVAL; call = array_index_nospec(call, SYS_SENDMMSG + 1); len = nargs[call]; if (len > sizeof(a)) return -EINVAL; /* copy_from_user should be SMP safe. */ if (copy_from_user(a, args, len)) return -EFAULT; err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); if (err) return err; a0 = a[0]; a1 = a[1]; switch (call) { case SYS_SOCKET: err = __sys_socket(a0, a1, a[2]); break; case SYS_BIND: err = __sys_bind(a0, (struct sockaddr __user *)a1, a[2]); break; case SYS_CONNECT: err = __sys_connect(a0, (struct sockaddr __user *)a1, a[2]); break; case SYS_LISTEN: err = __sys_listen(a0, a1); break; case SYS_ACCEPT: err = __sys_accept4(a0, (struct sockaddr __user *)a1, (int __user *)a[2], 0); break; case SYS_GETSOCKNAME: err = __sys_getsockname(a0, (struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_GETPEERNAME: err = __sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_SOCKETPAIR: err = __sys_socketpair(a0, a1, a[2], (int __user *)a[3]); break; case SYS_SEND: err = __sys_sendto(a0, (void __user *)a1, a[2], a[3], NULL, 0); break; case SYS_SENDTO: err = __sys_sendto(a0, (void __user *)a1, a[2], a[3], (struct sockaddr __user *)a[4], a[5]); break; case SYS_RECV: err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3], NULL, NULL); break; case SYS_RECVFROM: err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3], (struct sockaddr __user *)a[4], (int __user *)a[5]); break; case SYS_SHUTDOWN: err = __sys_shutdown(a0, a1); break; case SYS_SETSOCKOPT: err = __sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); break; case SYS_GETSOCKOPT: err = __sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]); break; case SYS_SENDMSG: err = __sys_sendmsg(a0, (struct user_msghdr __user *)a1, a[2], true); break; case SYS_SENDMMSG: err = __sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], true); break; case SYS_RECVMSG: err = __sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2], true); break; case SYS_RECVMMSG: if (IS_ENABLED(CONFIG_64BIT) || !IS_ENABLED(CONFIG_64BIT_TIME)) err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], (struct __kernel_timespec __user *)a[4], NULL); else err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], NULL, (struct old_timespec32 __user *)a[4]); break; case SYS_ACCEPT4: err = __sys_accept4(a0, (struct sockaddr __user *)a1, (int __user *)a[2], a[3]); break; default: err = -EINVAL; break; } return err; }
可以观察到 这两个过程分别是由如下两个函数执行的
__sys_socket
__sys_bind
我们不妨来验证这点:
第一个函数被调用了
我们打上更多断点来检查(12345是区分和上一次内容的分界线):
可以看到确实是
__sys_socket
__sys_bind
各一次
原文:https://www.cnblogs.com/Miliapus/p/12070635.html