160 likes | 351 Views
Linux 程序调试. GNU 编译器 gcc 程序调试器 gdb. GNU 基础知识. GNU 是由“ GNU’s Not Unix” 所递归定义出的首字母缩写语,它的发音为“ guh-NEW” GNU 汇编器 as ,编译器 gcc ,链接器 ld gcc ( GNU Compiler Collection ),是多种 GNU 编译器的集合,包含一系列针对不同语言和不同目标平台,以及可运行在不同主机系统上的编译器 其中的 C 编译器并不完全符合 ANSI C 标准 gcc 先将高级语言代码转化为一种内部语言,再将其优化后生成可执行代码,使其便于移植以及新语言的添加.
E N D
Linux程序调试 GNU编译器gcc 程序调试器gdb
GNU基础知识 • GNU是由“GNU’s Not Unix”所递归定义出的首字母缩写语,它的发音为“guh-NEW” • GNU汇编器as,编译器gcc,链接器ld • gcc(GNU Compiler Collection),是多种GNU编译器的集合,包含一系列针对不同语言和不同目标平台,以及可运行在不同主机系统上的编译器 • 其中的C编译器并不完全符合ANSI C标准 • gcc先将高级语言代码转化为一种内部语言,再将其优化后生成可执行代码,使其便于移植以及新语言的添加
gcc起步 • $ cat >hello.c #include <stdio.h>int main(void){printf (“Hello world, Linux programming!\n”);return 0;}然后执行下面的命令编译和运行这段程序: $ gcc hello.c -o hello$ ./helloHello world, Linux programming!
gcc程序编译四阶段 • 预处理(Pre-Processing) • 编译(Compiling) • 汇编(Assembling) • 链接(Linking)
gcc常用参数 • -c:只预处理,编译和汇编生产obj文件,而不连接成为可执行文件,通常用于编译不包含主程序的子程序文件。 • -o:指定输出文件名,如果不给出这个选项,gcc就给出预设的可执行文件a.out。 • -g:在可执行文件中输出调试信息,通常是为调试器gdb所用,要想对源代码进行调试,我们就必须加入这个选项。 • -O:对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。 • -O2:比-O更好的优化编译、连接,当然整个编译、连接过程会更慢 • -Wall:打开警报信息开关,在编译的过程中如果gcc遇到一些它认为可能会发生错误的地方就会提出一些相应的警告和提示信息。提示我们注意这个地方是不是有什么失误导致的错误。 • -ldirname :指定头文件搜索目录。 • gcc foo.c –I/home/chen/include –o foo • -Ldirname:指定在目录中需要搜索的库(动态库.so和静态库.a) • gcc foo.c –L/home/chen/lib –lfoo –o foo
程序调试工具gdb • gdb可完成单步运行,设置断点,监视变量,显示堆栈以及反汇编等功能。 • 若要全面的调试,则需要在编译源代码时,加-g 即 gcc -g • 使用过程为 • 编辑test.c • gcc –o test –g test.c • gdb test • 启动了gdb,可在其下输入命令实现调试
gdb下的命令(1) • Run运行 • c继续运行 • next单步运行,不进入函数体 • step单步运行,进入函数体 • kill终止当前进程 • 文件操作 • list显示源代码 • file装入可执行体 • 断点设置 • break function • break line • clear function
gdb下的命令(2) • 监视 • print expr显示表达式的值 • watch 变量 • disassemble function 反汇编 • disassemble addr1 addr2 • 状态显示 • info target • info functions • info break • info registers
常用进程控制系统调用 • fork——进程创建 • exec——进程执行 • exit——进程终止 • wait——进程同步 • sleep——进程挂起 • system——执行shell命令 • getpid——返回进程PID • getppid——返回父进程PID
进程的建立——fork系统调用 • 一个现存进程调用fork()函数是Linux创建一个新进程的唯一手段 • fork()调用执行后,两个代码相同的父、子进程并发执行 • 即子进程也是从fork()调用后的语句开始执行的 • 如果调用成功,对父进程返回子进程的PID,对子进程返回0 • 如果调用失败,返回-1 • 失败主要原因:超出系统或者用户最大进程数的限制 • 头文件unistd.h或者sys/types.h • 返回值类型pid_t / int
fork()的用处 • 一般来说fork()有两种用处: • 一个父进程希望复制自己,使父、子进程同时执行不同的代码段 • 这在网络服务进程中是最常见的——父进程等待委托者的服务请求 • 请求到达时,fork一个子进程处理请求,父进程继续等待下一个服务请求 • 一个进程要执行一个不同的程序 • 子进程从fork()返回后立即调用exec()
执行新程序——exec系统调用 • exec在这里指所有exec()一族的函数 • execve()、 execl() 、execlp()、execle() 、execv()、execvp()等各种此类系统调用 • exec()系列负责读取可执行文件并将其载入执行——免于共享资源的复制(写时拷贝机制) • 默认可执行文件路径为/usr/bin以及/bin • 当exec系统调用成功时,不会将控制权返回给调用进程;失败时返回-1 • 头文件unistd.h • 其参数等请查看man
进程的同步——wait系统调用 • 一个进程可以通过系统调用wait,使之与执行的子进程终止实现同步 • wait系统调用将调用进程挂起,直到其任一个子进程暂停或退出,或者收到一个不能忽略的信号为止。 • 头文件sys/wait.h或者sys/types.h • 常用函数: • pid_t wait(0); • pid_t wait(int *status); • pid_t waitpid(pid_t pid, int *status, int options); • 其中status是接收子进程结束时返回的状态信息的地址
解释退出状态 • 子进程的结束状态返回后存于status,下面几个宏可判别结束情况: • WIFEXITED(status):如果子进程正常结束则为非0值。 • WEXITSTATUS(status):取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。 • WIFSIGNALED(status):如果子进程是因为信号而结束则此宏值为真。 • WTERMSIG(status):取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。 • WIFSTOPPED(status):如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。 • WSTOPSIG(status):取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED 来判断后才使用此宏。