Linux下的gcc与gdb

打印 上一主题 下一主题

主题 1592|帖子 1592|积分 4776

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
目次
   Linux下的gcc与gdb
   代码编译与链接
   函数库
   gdb介绍和安装
   gdb基本使用指令
   示例代码
   debug模式和release模式
   基本指令
   进入gdb调试与显示调试代码
   创建断点与删除断点
   启用和禁用断点
   执行代码
   逐语句和逐过程调试
   断点跳转
   显示指定变量以及对应内容
   打印变量的值
   执行到指定行
   执行完当前作用域的代码
   监视变量
   运行时临时修改变量内容
   条件断点
   退出gdb调试
   cgdb增夸大试过程
   
   
   Linux下的gcc与gdb

   
在前面C语言的编译与链接章节中学到了C语言的可执行程序是怎样从代码一步一步天生的,下面是前面用到的指令

   代码编译与链接

   
代码编译预处理

  
  1. gcc -E test.c -o test.i
复制代码
  

  • 选项-E,该选项的作用是让gcc在预处理结束后制止编译过程
  • 选项-o是指目标文件,.i文件为已经过预处理的C原始程序
   
预处理天生汇编

  
  1. gcc -S test.c -o test.s
复制代码
      如果已经在前面执行了编译预处理天生了    test.i文件,则可以直接用    test.i文件而不是    test.c文件      

  • 用户可以使用-S选项来举行检察,该选项只举行编译而不举行汇编,天生汇编代码
   
汇编天生二进制文件

  
  1. gcc -c test.c -o test.o
复制代码
      如果已经在前面执行了编译预处理天生了    test.s文件,则可以直接用    test.s文件而不是    test.c文件      

  • 使用选项-c就可看到汇编代码已转化为.o的二进制目标代码,.o文件也被称为可重定位目标文件
   
二进制文件链接天生可执行程序

  
  1. gcc test.c -o test
复制代码
      如果已经在前面执行了编译预处理天生了    test.o文件,则可以直接用    test.o文件而不是    test.c文件      函数库

   
函数库一般分为静态库和动态库两种

   

  • 静态库:编译链接时把库文件的代码全部加入到可执行文件中,因今天生的文件比力大,在运行时不再必要库文件了。厥后缀名一般为.a
  • 动态库:在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,如许可以节流系统的开销。动态库一般后缀名为.so。gcc在编译时默认使用动态库。完成了链接之后,gcc就可以天生可执行文件
   
直接编译时选择动态库:gcc test.c -o test

   
使用静态编译选项-static时选择静态库:gcc -o test test.c -static

   gdb介绍和安装

   
gdb(GNU调试器)是GNU项目的一部分,用于调试C、C++、Pascal、Objective-C、Ada以及其他语言编写的程序。它允许开发者执行一系列的调试操作,如启动程序、设置断点、监视变量、单步执行代码、改变程序状态等,以便于找出并修正程序中的错误

   
在CentOS安装gdb可以使用下面的指令:

  
  1. sudo yum install -y gdb
复制代码
  
必要检察gdb版本时可以使用下面的下令:

  
  1. gdb --version
复制代码
  gdb基本使用指令

   示例代码

   
以下面的代码作为本次的调试用例:

  
  1. #include <stdio.h>
  2. int add(int start, int end) {
  3.     int sum = 0;
  4.     for(int i = start; i <= end; i++) {
  5.         sum += i;
  6.     }
  7.     return sum;
  8. }
  9. int main() {
  10.     printf("Start programme\n");
  11.     int start = 0;
  12.     int end = 20;
  13.     int result = add(start, end);
  14.     printf("result = %d\n", result);
  15.     printf("End programme\n");
  16.     return 0;
  17. }
复制代码
  
对应的Makefile文件内容如下:

  
  1. TARGET=test
  2. SRC=test.c
  3. $(TARGET):$(SRC)
  4.     $(CC) -o $@ $^ -std=gnu99
  5. .PHONY:clean
  6. clean:
  7.     rm -rf test
复制代码
  debug模式和release模式

   
默认情况下,直接使用gcc编译天生的可执行程序是release模式下的程序,不包含任何debug调试信息,而且release模式下无法举行调试。如果必要使用gcc编译天生的可执行程序是debug模式下的程序,就必要带上-g选项,天生的可执行文件包含debug信息,而且debug模式可以对代码举行调试

   
在CentOS下可以使用下面的指令判断一个文件是否使用debug模式编译天生

  
  1. readelf -S test | grep -i debug
复制代码
  
在Ubuntu下直接使用file+可执行程序文件即可检察到是否带有debug的字段即可判断是否使用debug模式编译天生

   
使用初始的Makefile举行编译时,天生的是release模式下的可执行程序,以是不带有任何debug信息:

   

   

   
而将Makefile中的内容修改为如下:

  
  1. # ...
  2. $(TARGET):$(SRC)
  3.     $(CC) -o $@ $^ -std=gnu99 -g
  4. # ...
复制代码
  
此时就会显示debug相关字段的信息

   

   

   基本指令

   进入gdb调试与显示调试代码

   
在创建出debug模式下的可执行程序test后,在终端输入gdb test,即可进入调试模式

   
在调试中,输入l+对应数字显示指定行以及之前的代码,默认一共显示10行代码,而l后方的数字对应行的代码一般会出如今展示的10行代码中央

       如果输入    l 0则默认从第一行代码展示,一共展示10行,结果同    l 1。另外,    gdb中存在指令影象,不输入任何指令会默认执行上一条指令      
本事:在gdb调试过程中,如果想要看到文件中的完整代码,可以输入l 0大概l 1,在展示完10行代码后接着按回车即可继续展示后10行代码,以此类推直到抵达文件内容末端。

   
也可以使用l+文件:数字显示指定文件中的对应行相应代码,其余结果与l+数字相同

   创建断点与删除断点

   
在gdb中,使用b/break+必要添加断点的行号即可在指定行添加断点

   
必要检察已经添加断点可以使用info + b,显示的表格即为已经添加的断点信息

   
在gdb中的断点都拥有本身的编号,删除断点时使用del + 断点编号

       必要留意,编号的巨细依次递增,而且其编号生命周期随着    gdb结束而结束,以是尽管删除断点,删除断点的编号仍旧不会被新的断点使用      
比方,在代码的16行和20行创建断点,展示断点信息,再删除20行的断点,再在第5行添加断点

   

  • 创建断点
   

   

   

  • 删除断点和添加新断点
   

   

   
同样,也可以使用break 文件:行号指定文件名中的行位置创建断点,还可以指定函数名b+函数名添加断点,函数名断点会默认跳到函数的第一条语句

   启用和禁用断点

   
在gdb中,使用enable+断点编号启动对应行的断点,使用disable+断点编号禁用断点

   

  • 对于启用的断点来说,使用info b检察断点信息可以在Enb列看到其值为y(代表yes)
  • 对于禁用的断点来说,使用info b检察断点信息可以在Enb列看到其值为n(代表no)
   
比方,禁用第5行的断点,再启用

   

  • 初始状态
   

   

   

  • 禁用状态
   

   

   

  • 启用状态
   

   

   执行代码

   
使用r指令运行代码

   
默认情况下,使用r指令运行代码会直接显示代码运行结果

   
如果添加了断点,使用r指令运行代码时,会直接运行到断点所在行然后等候(前面的代码会执行,但是断点所在行不会执行),此时会显示当前运行所在行

   
如果代码已经处于运行状态,再使用r指令会收到提示是否重新运行,按照需求选择即可

   
比方,在第17行添加断点,执行代码

   

   

   逐语句和逐过程调试

   
在gdb中,使用n指令举行逐过程调试,在逐过程中,不会执行函数细节,即遇到函数不会进入函数;使用s指令举行逐语句调试,与逐过程相反,在逐语句中,会执行函数细节,但是不会执行库中的函数

   
逐语句和逐过程调试过程中,显示的行是下一步必要执行的行,而不是已经执行之后的行

       逐语句和逐过程不会在多个断点间跳转      断点跳转

   
在gdb中,如果创建了多个断点必要直接从一个断点跳到下一个断点位置并执行两个断点间的代码,可以使用c指令

   
比方,在第17行和第5行创建两个断点,使用指令从第17行的断点跳转到第5行的断点

   

   

   显示指定变量以及对应内容

   
在gdb中,使用display + 变量名可以显示指定变量的值,显示的变量会在每一次调试语句中显示对应的内容,显示的变量会一直连续显示除非脱离变量所在作用域、显式取消显示大概退出gdb

       显示变量必须在对应变量所在作用域,否则会报错为:    No symbol "xxx" in current context   
必要检察变量的地址,也可以使用    display+&变量名      
每一个变量也存在变量,而且变量编号不受作用域的限制,而且也满意线性递增,以是取消显示已经显示的变量,使用undisplay + 变量编号

   打印变量的值

   
使用p+变量名指令可以打印对应变量的值

   执行到指定行

   
在gdb中,可以使用until+行号直接跳转到对应行,而且执行起始位置和指定行位置之前的代码。如果until中指定行的代码执行完毕之后没有遇到断点,程序就会直接运行到当前作用域结束,否则跳转到下一个断点处

   执行完当前作用域的代码

   
如果必要快速执行完当前函数作用域(非最外层函数作用域,本示例代码中最外层函数作用域为main函数所在作用域,非最外层函数作用域为add函数所在作用域)的代码,则可以使用finish指令

       对长的代码块举行区间调试本事:将断点打在多个函数所在行,使用断点+finish/until+c依次查抄函数是否出现问题      监视变量

   
所谓监视变量,与前面打印变量的值基本一样,但是差别的是,监视变量在gdb中本质是打一个断点,而且只有在变量的值发生变化时,才会再次主动打印变量以及对应的值

   
监视变量使用watch+变量名,删除监视变量与删除断点的方式相同,也可以在断点列表中检察到对应的监视变量断点

   

   

   运行时临时修改变量内容

   
部分情况下问题已经暴露而且必要改变一下变量内容临时检察是否修改对应变量的内容可以办理问题,此时就可以使用set 变量名=值在调试代码时临时改变指定变量的值

   条件断点

   
在gdb中,一共有两种添加条件断点的方式:

   

  • 在指定位置新增条件断点:使用b/break+断点行号+if 条件
  • 在已有断点位置添加条件:使用condition+已有断点编号+条件
       条件断点在新增后,会在断点列表显示断点跳转条件      

   

   退出gdb调试

   
使用quit指令退出调试,如果调试的代码还在运行,会询问用户是否结束并退出调试,根据必要选择即可

   cgdb增夸大试过程

   
直接使用gdb调试必要一直使用指令检察代码以及断点,为了使调试更加方便,可以使用cgdb代替gdb,但是基本使用方式与gdb完全相同,只是cgdb视觉上更加直观

   
在CentOS下,使用下面的指令安装cgdb

  
  1. sudo yum install -y cgdb
复制代码
  
使用cgdb调试代码就可以看到下面的界面:

   

   

   
代码行号处的箭头表现下一步必要执行的代码,刚开始并未没有断点或未开始情况下,会指向main函数的第一条语句

   
如果添加了断点,则断点所在行号会酿成赤色,比方下面的结果:

   

   

       尽量不要使用鼠标滚轮拖动代码窗口,防止出现问题      


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表