gdb调试core文件:
# gdb program core
注意,不要直接 gdb core 或者gdb -c core 这样你将看不到调用栈的
问题:
1. gdb program core时 ,先做了什么使得能看到调用栈的?
2. core文件的格式是什么?core能为gdb提供什么有用的信息呢?
DevOps
gdb调试core文件:
# gdb program core
注意,不要直接 gdb core 或者gdb -c core 这样你将看不到调用栈的
问题:
1. gdb program core时 ,先做了什么使得能看到调用栈的?
2. core文件的格式是什么?core能为gdb提供什么有用的信息呢?
1. 使用getline从文件初始化一个数组
2. 使用 key in arr 的方式来匹配
[root@login test]# cat uid
123
456
789
[root@login test]# echo -e "123 man\n456 b\nc"|awk -v file=uid ‘BEGIN{i=0;while(getline uid <file) arr[uid]=true;} {if($1 in arr) print $0;}’
123 man
456 b
tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854
0x4745 为"GET"前两个字母"GE"
0x4854 为"HTTP"前两个字母"HT"
glibc read(可能通过宏来实现) -> system_call(这里也可能是一个宏) -> int 0x80(or sysenter) -> sys_read
Linux 内核完全剖析——基于0.12内核
http://product.dangdang.com/product.aspx?product_id=20365956&ref=search-1-pub
http://lxr.linux.no/#linux+v3.1.1/
您可以很方便地在这里看代码,你也可以直接修改版本号,查看不同版本的代码
【这里只研究 x86 平台下的】
1. 相关文件:
系统调用号的定义:
arch/x86/include/asm/unistd_32.h
这里对每个系统调用都分配了一个系统调用号。
系统调用表的定义:
arch/x86/kernel/syscall_table_32.S
这里是用汇编语言定义的系统调用表,系统启动时会加载到指定的内存区域
那么,这些sys_* 系统调用例程怎么定义的呢? 在某个版本以前,我们可以直接通过sys_* 找到该函数的定义,但是,在linux-3.1.1中,我们只能看到使用该函数的地方,却找不到定义该函数的地方了,因为可能通过宏来定义了,如: SYSCALL_DEFINE0, SYSCALL_DEFINE1,SYSCALL_DEFINE2,…
参考文件 include/linux/syscalls.h:
当然,也可能没有通过宏来定义,我们不妨还按照sys_ 来搜索。
让我们来找找sys_fork 吧:
grep SYSCALL_DEFINE -r * | grep fork
没有结果, 在试试sys_fork
grep sys_fork -r *
结果太多了,我只关心x86平台下的实现,如下:
grep sys_fork -r * | grep x86
大概在文件:./arch/x86/kernel/process.casm/syscalls.h 中
再看看./arch/x86/kernel/process.c :
我们知道,系统调用也是通过一个系统中断来实现的,linux上,所有的系统调用都是通过一个中断号为 0x80的中断来实现的,参考文件:
arch/x86/include/asm/irq_vectors.h
那么,中断向量表又是在什么时候初始化的呢?
arch/x86/kernel/traps.c 中初始化了中断向量表,里面也指定了 0x80 的中断处理例程是 system_call
那么, system_call 又是怎么定义的呢?
arch/x86/kernel/entry_32.S
这里我们还发现系统调用被跟踪的逻辑,就是 syscall_trace_entry, 同样出现在文件: arch/x86/kernel/entry_32.S中;
ptrace 函数就是利用这个功能来实现的。
那么, syscall_trace_enter 的实现又是在哪里的呢?
arch/x86/kernel/ptrace.c
ptrace是不是很强大? 记住: ptrace本身可不是系统调用,如果是的话就死循环了。
问题: ptrace.c 中没有定义ptrace这个函数,但是 man ptrace 时,却又如下定义:
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
那么这个函数又是怎么来的呢?
====================================================================
现在,我要执行一个fork系统调用时,是怎么通过fork符号来找到系统调用表中的指定的例程的呢???????????????
下面的就不要看了,只是猜测。。。。。。。。。。。。。。。。。。
系统调用都到这里来执行:
arch/x86/kernel/sys_i386_32.c
对于较新的cpu来讲,系统调用是通过: ./vdso/vdso32/sysenter.S 中的__kernel_vsyscall来实现的,其中使用了一个新的cpu指令: sysenter
1. 关于动态链接的文件依赖的共享库:
链接时使用-l指定的库文件都会记录到elf文件里面的,程序加载前的动态链接一定会加载的,不管你的程序是否会用到;如:
======= phpor.c ============
======= phpor_test.c =============
———————————-
# gcc -shared -o libphpor.so phpor.c
# gcc -o phpor_test -l phpor -L. phpor_test.c
# LD_LIBRARY_PATH=. ./phpor_test
no dependent
# LD_LIBRARY_PATH=. ldd ./phpor_test
libphpor.so => ./libphpor.so (0x00e4f000)
libc.so.6 => /lib/tls/libc.so.6 (0x00865000)
/lib/ld-linux.so.2 (0x00846000)
你可以把libphpor.so 删掉,执行的时候就报错了
2. 关于共享库的版本号:
我创建了一个so文件 libphpor.so.1 ,现在我要编译一个phpor_test的文件,该文件依赖libphpor.so.1,于是有如下命令:
gcc -o phpor_test -l phpor -L. phpor_test.c
我的libphpor.so.1 是在当前目录下的,所以 -L.
如果我不创建软连接 libphpor.so => libphpor.so.1 的话,则是无法连接的。 为什么不能直接使用 libphpor.so.1 呢? 关键是:
# ldd /bin/ls
librt.so.1 => /lib/tls/librt.so.1 (0x00ce9000)
libacl.so.1 => /lib/libacl.so.1 (0x00f7f000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00a22000)
libc.so.6 => /lib/tls/libc.so.6 (0x00865000)
libpthread.so.0 => /lib/tls/libpthread.so.0 (0x009f5000)
/lib/ld-linux.so.2 (0x00846000)
libattr.so.1 => /lib/libattr.so.1 (0x00502000)
为什么ls这个命令就能依赖一个带有主版本号的库,而我就不能依赖指定的主版本号?
我只好创建一个软连接 libphpor.so => libphpor.so.1 ,因为该so文件没有在LD_LIBRARY_PATH 下,所以,这里测试时临时指定一下:
LD_LIBRARY_PATH=. ./phpor_test
3. 关于共享库、静态库和动态链接、静态链接的概念
共享库、静态库
强调的是:
我能否被其它程序动态加载
特点:
- 静态库(不是静态链接的可执行程序)可能(也可能不)依赖别的未定义的符号,但是,自己不知道(也不会说明)这些符号在那里可以找到,即: 不描述依赖关系
- 共享库可能(也可能不)依赖别的未定义的符号,但是,如果有未定义符号,则自己会说明需要动态加载哪些共享库,即:描述依赖关系
- 其实,静态库实际是没有经过链接的,只是一些目标文件的打包;共享库是经过了链接这个步骤了的
动态链接、静态链接:
强调的是:
我(就是链接的结果文件,可能是一个可执行文件,也可能是一个共享库so文件,注意,so文件有的也可以直接执行,但一定不是静态库文件)在运行的时候,是否依赖别的动态库文件。
特点:
- 动态链接的文件一定依赖其他的so文件,至少要依赖 ld.so
- 静态链接的文件一定不依赖其他的so文件
库类型与链接类型之间的关系:
4. 我们说,共享库也可以是静态链接的,下面我们做一个实验,把上面的phpor.c 编译成一个静态链接的共享库文件:
因为linux几乎所有程序都依赖libc.so, 现在要静态链接,就需要指定需要的.a 文件 libc.a, 在/usr/lib下; 一般默认是动态链接的,如果要静态连接,就需要使用 -static 选项指定,命令如下:
gcc -shared -static -o libphpor.so.2 /usr/lib/libc.a phpor.c
但是,这样编译的结果还是动态链接的,为什么? -static 没有起作用吗?
使用如下命令:
# gcc -shared -nodefaultlibs -o libphpor.so.2 /usr/lib/libc.a phpor.c
# ldd libphpor.so.2
statically linked
当然,您可以同时使用 -nodefaultlibs和 -static ; 不明白的是: 难道static不是用来屏蔽其它的动态库文件的吗?
先生成目标文件,自己使用ld命令来做静态连接:
# gcc -o phpor.o -c phpor.c
# ld -shared -dn -o libphpor.so.3 phpor.o
# ldd libphpor.so.3
statically linked
# ln -s libphpor.so.3 libphpor.so
# LD_LIBRARY_PATH=. ./phpor_test
hello
又有问题了,为什么我没有指定/usr/lib/libc.a , 这里却能链接完成,而且还能用了呢?难道ld帮我做了?
动态库不仅能节省磁盘空间,也能节省内存空间。
1. 执行如下命令:
aVar=theValue
echo $aVar
不会输出theValue
2. 执行如下命令:
export aVar=theValue
echo $aVar
输出: theValue
说明:
如果没有export, 则,只作用于当前的命令; 如果export了,则相当于修改了当前shell的环境
3. 比较如下两个命令
第一个命令中的aVar是当前shell中的环境变量,因为没有使用export,所以只为空;
第二个命令(注意:使用的是单引号)中的$aVar是eval进程中的环境变量,而前面没有使用export,所以,只作用于eval进程,所以aVar就有值了
PHP中使用sysvsem模块实现锁机制
http://hk2.php.net/manual/en/function.sem-get.php