• Linux下常用调试技巧


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

     

    (一) 有漏洞的程序

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

    pic

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

    (二) 代码检查

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

    pic

    (三) 取样法

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

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

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

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

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

    pic 

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

    (四) 使用gdb进行调试

    pic

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

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

    转载:http://blog.csdn.net/delphiwcdj/article/details/6603910

  • 相关阅读:
    变形方块
    Vim编辑器设置字体高亮显示
    从命令行终端获取数值作为函数参数
    Vi编辑器的使用技巧
    iOS开发常用shell命令
    include使用技巧
    交换2个整型变量的值
    C语言位运算实现函数体
    React Native 之文件内数据操作(var、let、const、static、Props、State、this)
    React Native 城市选择(四)获取城市名称
  • 原文地址:https://www.cnblogs.com/doctorqbw/p/2248608.html
Copyright © 2020-2023  润新知