从零开始学Linux_16_gdb入门(下)

欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢微笑



一、查看运行时数据
1、 print- 查看变量值
2、 ptype - 查看类型
3、 printarray - 查看数组
4、 print* array@len - 查看动态内存
5、printx=5- 改变运行时数据


二、程序错误
1、 编译错误:编写程序的时候没有符合语言规范导致编译错误。
2、 运行时错误:编译器检查不出这种错误,但在运行的时候可能会导致程序崩溃。
3、 逻辑错误:编译和运行都很顺利,但是程序没有干它该干的事情。


三、gdb调试逻辑错误

#include<stdio.h>
int main(void)
{
        inti; 
        char str[6]= "hello";
        char reverse_str[6]= "";
        printf("%s\n", str);
        for (i=0; i<5; i++)
                reverse_str[5-i]= str[i];
        printf("%s\n", reverse_str);
        return 0;
}

这个程序要实现逆序输出字符串hello,但是却没有任何输出。



四、gdb调试段错误
1、 段错误是由于访问非法地址而产生的错误。
(1) 访问系统数据区,尤其是往系统保护的内存地址写数据。最常见就是给一个指针以 0 地址
(2) 内存越界 ( 数组越界,变量类型不一致等 ) 访问到不属于你的内存区域


五、core文件调试段错误
1 core 文件
     在程序崩溃时,一般会生成一个文件叫 core 文件。 core文件记录的是程序崩溃时的内存映像 ,并加入调试信息。core 文件生成的过程叫做 core dump

2 、设置生成 core 文件
(1) ulimit -c  查看 core-dump 状态 (ulimit -a 查看当前块大小)
(2) ulimit -c 数字 (如: ulimit -c 1024 ) (设置每一块的大小为1024)
(3) ulimit -c unlimited  (每一块的大小,没有限制)

3 gdb 利用 core 文件调试
(1)gdb 文件名 core文件  (若用bugging的例子, # gdb bugging core.9351
(2) bt  (查看堆栈)


六、示例
1、第一个示例
//main.c
#include <stdio.h>
#include <stdlib.h>
long func(int n);
int main(int argc, char *argv[])
{
    int i;
    int x =5;
    double z = 2.5;
    char ch = 'q';
     int arr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
     int *arr2 = (int *)malloc(sizeof(int) * 10);
     for (i=0; i<10; ++i)
     {
          arr2[i] = i;
     }
     printf("Entering main ...\n");
     for (i=0; i<argc; ++i)
     {
          printf("%s ", argv[i]);
     }
     printf("\n");
     long result = 0;
     for (i=1; i<=100; ++i)
     {
          result += i;
     }
     printf("result[1-100] = %ld\n", result);
     printf("result[1-10] = %ld\n", func(10));
     printf("Exiting main ...\n");
     return 0;
}
long func(int n)
{
     long sum = 0;
     int i;
     for (i=1; i<=n; ++i)
     {
          sum += i;
     }
     return sum;
} 
#  gcc -Wall -g main.c -o main
#  gdb main
#  l
#  b 13
#  r
#  ptype x
#  ptype z
#  p arr1  (打印出数组的值)
#  p arr1[2]  (打印出数组的值)
#  p &arr1[0]  (打印出首地址)
#  p &arr1  (打印出首地址)
#  n
#  n
#  until
#  l
#  p *arr2@10  (查看arr2开始10个数组内容)
#  p *arr2@15  (查看arr2开始15个数组内容,包括未定义的)
#  p arr1@2  (查看arr1开始20个数组内容,包括未定义的;即arr1为整体,两倍长度的内容,因此为20个)
#  p *arr1@2  (查看arr1开始2个数组内容,即{0,1}
#  p *arr1[2]@2  (查看arr1[2]开始2个数组内容,即{2,3}

2、第二个示例,逻辑错误gdb调试
//error.c
#include <stdio.h>
int main(void)
{
    int i;
    char str[6] = "hello";
    char reverse_str[6] = "";
    printf("%s\n", str);
    for (i=0; i<5; i++)
        reverse_str[5-i] = str[i];
    printf("%s\n", reverse_str);
    return 0;
} 
#  gcc -Wall -g error.c -o error
#  gdb error
#  b 10
#  s
#  p str[i]
#  s
#  p reverse_str[5-i]
#  until
#  p i (此时i=5,即循环5次退出了)
#  p reverse_str  (打印出了"\000olleh")
解释:由于打印出第一位是“\0”,因此肯定不会打印出后续的值。
    因此我们可以做一个简单的修改,把第11句修改:reverse_str[4-i] = str[i];程序就正常输出了。

3、第三个示例,gdb调试段错误
(1) 访问系统数据区,尤其是往系统保护的内存地址写数据。最常见就是给一个指针以 0 地址
//bugging.c
#include <stdio.h>
#include <stdlib.h>
void segfault()
{
    int *p = NULL;
    *p = 100;  //向空指针赋值,产生段错误
}
int main(void)
{
    segfault();
    /*
    char buf[1] = "a";
    buf[10003] = 'A';
    printf("%c\n",buf[10003]);
    */
    return 0;
} 
#  gcc -Wall -g bugging.c -o bugging
#  gdb bugging
#  r    (如果程序很长,直接运行,会给出段错误的位置)
#  bt  (栈回朔)
#  l 7  (打印出第7行)

(2)内存越界(数组越界,变量类型不一致等) 访问到不属于你的内存区域
修改bugging.c程序
//bugging.c
#include <stdio.h>
#include <stdlib.h>
void segfault()
{
    int *p = NULL;
    *p = 100;  //向空指针赋值,产生段错误
}
int main(void)
{
    //segfault();
    char buf[1] = "a";
    buf[10003] = 'A';
    printf("%c\n",buf[10003]);
    return 0;
}
#  gcc -Wall -g bugging.c -o bugging
#  gdb bugging
#  r  (如果程序很长,直接运行,会给出段错误的位置:第14行,buf[10003] = 'A'



你可能感兴趣的:(linux,gdb)