linux下常见的调试方法

文章转自 https://blog.csdn.net/delphiwcdj/article/details/6603910

 

(一) 有漏洞的程序
(二) 代码检查
(三) 取样法
(四) 使用gdb进行调试

 

(一) 有漏洞的程序

  1. /* debug1.c */
  2. typedef struct {
  3. char *data;
  4. int key;
  5. }item;
  6. item array[] = {
  7. { "bill", 3},
  8. { "neil", 4},
  9. { "john", 2},
  10. { "rick", 5},
  11. { "alex", 1},
  12. };
  13. void sort(item *a, int n)
  14. {
  15. int i = 0, j = 0;
  16. int s = 1;
  17. for(; i < n && s != 0; i++) {
  18. s = 0;
  19. for(j = 0; j < n; j++) {
  20. if (a[j].key > a[j+ 1].key) {
  21. item t = a[j];
  22. a[j] = a[j+ 1];
  23. a[j+ 1] = t;
  24. s++;
  25. }
  26. }
  27. n--;
  28. }
  29. }
  30. #include <stdio.h>
  31. main()
  32. {
  33. int i;
  34. sort( array, 5);
  35. for (i = 0; i < 5; i++) {
  36. printf( "array[%d] = {%s, %d}\n",
  37. i, array[i].data, array[i].key);
  38. }
  39. }

pic

注意:输出的结果取决于所使用的Linux(或UNIX)版本及其具体设置情况。

(二) 代码检查

使用编译器的报警选项对代码进行检查。

pic

(三) 取样法

取样法:是指在程序中添加一些代码以收集更多与程序运行时的行为相关的信息的方法。

技巧1:用C语言的预处理器有选择地包括取样代码,这样只需重新编译程序就可以包含或去除调试代码。在编译程序时可以加上编译器标志 -DDEBUG。如果加上这个标志,就定义了DEBUG符号,从而可以在程序中包含额外的调试代码;如果未加上该标志,这些调试代码将被删除。

  1. typedef struct {
  2. char *data;
  3. int key;
  4. }item;
  5. item array[] = {
  6. { "bill", 3},
  7. { "neil", 4},
  8. { "john", 2},
  9. { "rick", 5},
  10. { "alex", 1},
  11. };
  12. void sort(item *a, int n)
  13. {
  14. int i = 0, j = 0;
  15. int s = 1;
  16. for(; i < n && s != 0; i++) {
  17. s = 0;
  18. for(j = 0; j < n; j++) {
  19. if (a[j].key > a[j+ 1].key) {
  20. item t = a[j];
  21. a[j] = a[j+ 1];
  22. a[j+ 1] = t;
  23. s++;
  24. }
  25. }
  26. n--;
  27. }
  28. }
  29. #include <stdio.h>
  30. main()
  31. {
  32. #ifdef DEBUG
  33. printf( "debug mode\n");
  34. #endif
  35. int i;
  36. sort( array, 5);
  37. for (i = 0; i < 5; i++) {
  38. printf( "array[%d] = {%s, %d}\n",
  39. i, array[i].data, array[i].key);
  40. }
  41. }

pic

 

技巧2:还可以用数值调试宏来完成更复杂的调试应用。
在这种情况下,我们必须总是定义DEBUG宏,但我们可以设置它为代表一组调试信息或代表一个调试级别。比如,编译器标志 -DDEBUG=5 将启用 BASIC_DEBUG 和 SUPER_DEBUG,但不包括 EXTRA_DEBUG。标志 -DDEBUG=0 将禁用所有的调试信息。

  1. typedef struct {
  2. char *data;
  3. int key;
  4. }item;
  5. item array[] = {
  6. { "bill", 3},
  7. { "neil", 4},
  8. { "john", 2},
  9. { "rick", 5},
  10. { "alex", 1},
  11. };
  12. void sort(item *a, int n)
  13. {
  14. int i = 0, j = 0;
  15. int s = 1;
  16. for(; i < n && s != 0; i++) {
  17. s = 0;
  18. for(j = 0; j < n; j++) {
  19. if (a[j].key > a[j+ 1].key) {
  20. item t = a[j];
  21. a[j] = a[j+ 1];
  22. a[j+ 1] = t;
  23. s++;
  24. }
  25. }
  26. n--;
  27. }
  28. }
  29. #include <stdio.h>
  30. #define BASIC_DEBUG 1
  31. #define EXTRA_DEBUG 2
  32. #define SUPER_DEBUG 4
  33. main()
  34. {
  35. #ifdef DEBUG
  36. printf( "debug mode\n");
  37. #endif
  38. #if (DEBUG & EXTRA_DEBUG)
  39. printf( "debug mode 2\n");
  40. #endif
  41. int i;
  42. sort( array, 5);
  43. for (i = 0; i < 5; i++) {
  44. printf( "array[%d] = {%s, %d}\n",
  45. i, array[i].data, array[i].key);
  46. }
  47. }

pic

 

技巧3:C语言预处理器定义的一些宏可以帮助我们进行调试。这些宏在扩展后会提供当前编译操作的相关信息。

__LINE__ 代表当前行号的十进制常数
__FILE__ 代表当前文件名的字符串
__DATE__ mmm dd yyyy格式的字符串,代表当前日期
__TIME__ hh:mm:ss格式的字符串,代表当前时间

注意:
(1) 这些符号的前后各有两个下划线,这是标准的预处理器符号通常的做法,你应该注意避免选择可能会与它们冲突的符号。
(2) “当前”指的是预处理操作正在执行的那一时刻,即正在运行编译器对文件进行处理时的时间和日期。 

  1. typedef struct {
  2. char *data;
  3. int key;
  4. }item;
  5. item array[] = {
  6. { "bill", 3},
  7. { "neil", 4},
  8. { "john", 2},
  9. { "rick", 5},
  10. { "alex", 1},
  11. };
  12. void sort(item *a, int n)
  13. {
  14. int i = 0, j = 0;
  15. int s = 1;
  16. for(; i < n && s != 0; i++) {
  17. s = 0;
  18. for(j = 0; j < n; j++) {
  19. if (a[j].key > a[j+ 1].key) {
  20. item t = a[j];
  21. a[j] = a[j+ 1];
  22. a[j+ 1] = t;
  23. s++;
  24. }
  25. }
  26. n--;
  27. }
  28. }
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #define BASIC_DEBUG 1
  32. #define EXTRA_DEBUG 2
  33. #define SUPER_DEBUG 4
  34. main()
  35. {
  36. #ifdef DEBUG
  37. printf( "debug mode\n");
  38. printf( "Compiled: "__DATE__ " at "__TIME__ "\n");
  39. printf( "This is line %d of file %s\n", __LINE__, __FILE__);
  40. #endif
  41. #if (DEBUG & EXTRA_DEBUG)
  42. printf( "debug mode 2\n");
  43. #endif
  44. int i;
  45. sort( array, 5);
  46. for (i = 0; i < 5; i++) {
  47. printf( "array[%d] = {%s, %d}\n",
  48. i, array[i].data, array[i].key);
  49. }
  50. exit( 0);
  51. }

pic 

注意:ANSI C 标准定义相邻的字符串可以被看作为一个字符串。

 

(四) 使用gdb进行调试

pic

注意:可以使用命令 strip <file> 将可执行文件中的调试信息删除而不需要重新编译程序。

gdb本身是一个基于文本的应用程序,但它为一些重复性的任务准备了一些快捷键。
(1) gdb的许多版本都具备带历史记录的命令行编辑功能,用户可以(尝试用方向键)回卷并再次执行以前输入过的命令。
(2) gdb的所有版本都支持“空命令”,即直接按下回车键再次执行最近执行过的那条命令。在用step或next命令单步执行程序时,空命令非常有用。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值