一、实验环境准备
uname -a
在本机编译linux 5.0.1 X86-64内核,重新按照64位方式编译,步骤同上一篇博客。
make x86_64_defconfig make menuconfig make #编译内核
二、Socket与系统调用
1.socket
- Socket API编程接口之上可以编写基于不同网络协议的应用程序;
- Socket接口在用户态通过系统调用机制进入内核;
- 内核中将系统调用作为一个特殊的中断来处理,以socket相关系统调用为例进行分析;
- socket相关系统调用的内核处理函数内部通过“多态机制”对不同的网络协议进行的封装方法。
2.系统调用
- 系统调用就是为了让应用程序可以访问系统资源,每个操作系统都会提供一套接口供应用程序使用。这些接口通常通过中断来实现,linux使用0x80号中断作为系统的调用的入口。
- 系统调用的弊端:各个操作系统的系统调用不兼容,使用不方便,系统调用比较原始。运行库解决这两个问题,它的使用统一不会随着操作系统或编译器的变化而变化。
- 系统调用的原理:系统调用是运行在内核态的,而用户程序一般是运行在用户态的,操作系统一般通过中断从用户态切换到内核态。中断具有两个属性一个是中断号,一个是中断向量表,是一个数组,包含中断处理程序。一个中断号对应一个中断处理程序。中断分为硬件中断和软件中断,软件中断通常是一条指令,带有一个参数代表中断号。在linux中使用0x80来触发所有的系统调用。和中断一样系统调用都有一个系统调用号,系统调用号代表在系统调用表中的位置。
3.系统调用表
vi linux-5.0.1/arch/sh/include/uapi/asm/unistd_64.h
从中可以看到与socket相关的调用号。
三、GDB调试
1.启用gdb调试系统启动
vi LinuxKernel/menu/Makefile cd menu make rootfs
在图形化界面启动menu后,用终端打开gdb:
查找资料得知,我本机是32位linux,gdb为32位,无法调试64位程序。因此,下面为基于32位linux内核的调试。
在系统启动后,可以看到,内核的初始化完成了以下的函数调用过程:start_kernel > trap_init > idt_setup_traps, 其中start_kernal是内核启动的入口函数。
2.gdb调试socket
这一次我们在__sys_listen加入断点
可以看到,当我在Qemu中输入replyhi后,进入断点
在sys_socketcall加入断点,输入了replyhi后,可以看到该方法被调用了4次
Socket本质上是一个glibc中的函数,执行实际上是是调用sys_socketcall()系统调用。sys_socketcall()是几乎所有socket相关函数的入口,即是说,bind,connect等等函数都需要sys_socketcall()作为入口。省略号省略掉的是各种网络编程用得到的函数,全部都在这个系统调用中,socketcall是系统所有socket相关函数打大门。
SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) { unsigned long a[6]; unsigned long a0, a1; int err; unsigned int len; if (call < 1 || call > SYS_SENDMMSG) return -EINVAL; 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; audit_socketcall(nargs[call] / sizeof(unsigned long), a); 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; //... default: err = -EINVAL; break; } return err; }
原文地址:https://www.cnblogs.com/tanhao1410/p/12066356.html
时间: 2024-10-05 04:04:40