1.Gdb的基本调试

示例代码

//e.c
#include <stdio.h>
void debug(char *str)
{
printf("debug info :%s\n",str );
} int main(int argc,char *argv[]){
int i,j;
j=0;
for(i=0;i<10;i++){
j+=5;
printf("now a=%d\n", j);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

gcc -g -o e e.c
调试gdb e
或者输入gdb
然后 file e

1. list 命令用法

list命令显示多行源代码,从上次的位置开始显示,默认情况下,一次显示10行,第一次使用时,从代码其实位置显示。

list n显示已第n行未中心的10行代码
list functionname显示以functionname的函数为中心的10行代码
  • 1
  • 2

2. 断点命令break
break location:在location位置设置断点,改位置可以为某一行,某函数名或者其它结构的地址。gdb会在执行该位置的代码之前停下来.

使用delete breakpoints 断点号 删除断点
这里的断点号表示的是第几个断点,刚才执行break 10返回
reakpoint 1 at 0x40050a: file e.c, line 10.
中的1表示该断点的标号,因此使用 delete breakpoints 1表示删除第10行所定义的断点 clear n表示清除第n行的断点,因此clear 10等同于delete breakpoints 1
disable/enable n表示使得编号为n的断点暂时失效或有效
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可使用info查看断点相关的信息
info breakpoints

c(continue),继续程序运行直到下一个断点

3.display命令
查看参数的值

4.step及next命令
step可使得程序逐条执行,即执行完一条语句然后在下一跳语句前停下来,等待用户的命令。一般使用step命令是,可使用display或者watch命令查看变量的变化,从而判断程序行为是否符合要求。当下一条指令为函数时,s进入函数内部,在其第一条语句前停下来。next单步执行,但不进入函数内部。
step n,next n 表示连续但不执行n条指令,如果期间遇到断点,则停下来
5.print打印内部变量值
6.bt 查看堆栈信息
7.watch 监视变量值的变化

watch通常需要和break,run,continue联合使用。

下面举例说明:

代码如下:
#include <stdio.h>

int main()
{
int a=0;
for(int i=0; i<10; i++)
a+=i;
}
调试的时候过程如下:

(gdb) l
1 #include <stdio.h>
2
3 int main()
4 {
5 int a=0;
6 for(int i=0; i<10; i++)
7 a+=i;
8 }
(gdb) b 5 -------在第5行设置断电
Breakpoint 1 at 0x80483ba: file a.cpp, line 5.
(gdb) r -------执行到断点处停止
Starting program: /a.o

Breakpoint 1, main () at a.cpp:5
5 int a=0;
(gdb) watch a -------观察a的值,当有变化时,停止
Hardware watchpoint 2: a
(gdb) c -------继续执行,当a的值变化时停止
Continuing.
Hardware watchpoint 2: a

Old value = 0
New value = 1
main () at a.cpp:6
6 for(int i=0; i<10; i++)
(gdb)
Continuing.
Hardware watchpoint 2: a

Old value = 1
New value = 3
main () at a.cpp:6
6 for(int i=0; i<10; i++)
(gdb)
Continuing.
Hardware watchpoint 2: a

即,在使用watch时步骤如下:

  1. 使用break在要观察的变量所在处设置断点;

  2. 使用run执行,直到断点;

  3. 使用watch设置观察点;

  4. 使用continue观察设置的观察点是否有变化。

8.set variable value=x 动态改变变量值
1,调试中需要修改临时变量的值时,可以使用set命令
语法:

set variable key = value
set var key = value
示例:
(gdb) set variable array[1] = 12

2,另一种更简单的方式,使用print命令修改
语法:
print key=value

2.多线程调试

1. 线程的查看
首先创建两个线程:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h> void* pthread_run1(void* arg)
{
(void)arg; while(1)
{
printf("I am thread1,ID: %d\n",pthread_self());
sleep(1);
}
} void* pthread_run2(void* arg)
{
(void)arg; while(1)
{
printf("I am thread2,ID: %d\n",pthread_self());
sleep(1);
}
} int main()
{ pthread_t tid1;
pthread_t tid2; pthread_create(&tid1,NULL,pthread_run1,NULL);
pthread_create(&tid2,NULL,pthread_run2,NULL); printf("I am main thread\n"); pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

分析:上面程序中创建了两个线程,程序执行起来,main函数所在程序为主线程,在这个主线程中有两个新线程运行。
命令行查看:

//查看当前运行的进程
ps aux|grep a.out
//查看当前运行的轻量级进程
ps -aL|grep a.out
//查看主线程和新线程的关系
pstree -p 主线程id
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6


2. 线程栈结构的查看

  1. 获取线程ID
  2. 通过命令查看栈结构 ps stack 线程ID

    3. 利用gdb查看线程信息
    将进程附加到gdb调试器当中,查看是否创建了新线程:gdb attach 主线程ID

查看线程的一些信息

//1.查看进程:info inferiors
//2.查看线程:info threads
//3.查看线程栈结构:bt
//4.切换线程:thread n(n代表第几个线程)

4. 利用gdb调试多线程
  当程序没有启动,线程还没有执行,此时利用gdb调试多线程和调试普通程序一样,通过设置断点,运行,查看信息等等,在这里不在演示,最后会加上调试线程的命令

设置断点

//1. 设置断点:break 行号/函数名
//2. 查看断点:info b
  • 1
  • 2


执行线程2的函数,指行完毕继续运行到断点处

1. 继续使某一线程运行:thread apply 1-n(第几个线程) n
2. 重新启动程序运行到断点处:r
  • 1
  • 2


3.只运行当前线程

. 设置:set scheduler-locking on 2
. 运行:n
  • 1
  • 2


4.所有线程并发执行

    1. 设置:set scheduler-locking off
2. 运行:n
  • 1
  • 2

注意点:
ctrl+c ctrl+d ctrl+z 的区别和使用场景

Ctrl+C :强制中断程序,程序无论运行哪里都停止。

Ctrl+D :发送一个 exit 的信号,退出当前的用户或者是客户端。

Ctrl+Z :暂停程序,在进程中维持挂起状态。

引用别人的说法:

1、Ctrl+C比较暴力,就是发送Terminal到当前的程序,比如你正在运行一个查找功能,文件正在查找中,Ctrl+C就会强制结束当前的这个进程。
2、Ctrl+Z 是把当前的程序挂起,暂停执行这个程序,比如你正在mysql终端中,需要出来搞点其他的文件操作,又不想退出mysql终端(因为下次还得输入用户名密码进入,挺麻烦),于是可以ctrl+z将mysql挂起,然后进行其他操作,然后输入 fg 回车后就可以回来,当然可以挂起好多进程到后台,然后 fg 加编号就能把挂起的进程返回到前台。当然,配合bg(后台)和fg命令进行前后台切换会非常方便。
3、Ctrl+D 是发送一个exit信号,没有那么强烈,类似ctrl+C的操作,比如你从管理员root退回到你的普通用户就可以这么用。

Linux学习——Gdb基本调试方法&&多线程调试的更多相关文章

  1. GDB:从单线程调试到多线程调试(MFiX单步调试)

    GDB:从单线程调试到多线程调试 1. 裸跑GDB 1.1 安装GDB sudo apt-get install gdb 1.2 编译程序 由于需要调试,因此编译的时候需要添加-g编译参数: 1.3 ...

  2. 2019-2-14-VisualStudio-通过外部调试方法快速调试库代码

    title author date CreateTime categories VisualStudio 通过外部调试方法快速调试库代码 lindexi 2019-2-14 22:1:37 +0800 ...

  3. Linux学习--gdb调试

    一.gdb常用命令: 命令 描述 backtrace(或bt) 查看各级函数调用及参数 finish 连续运行到当前函数返回为止,然后停下来等待命令 frame(或f) 帧编号 选择栈帧 info(或 ...

  4. Linux学习----gdb调试(指针的指针)

    昨天遇到一个很奇怪的问题,如下: 按照理论,最后*p的值应该是99,不知为什么是15了,所以今天记录用gdb调试的过程,并熟悉gdb的使用. (调试过程参考:http://www.cnblogs.co ...

  5. Linux学习笔记(16)-多线程

    什么是多线程?或者说,什么是线程? 按照书本上的描述,所谓线程,便是包含在进程内部的顺序执行流,是进程中实际运作的单位,也是操作系统能够进行调度的最小单位. 一个进程中可以并发多条线程,每条线程并行执 ...

  6. Linux学习笔记20——第一个多线程程序

    一 什么是线程 线程:是一个进程内部的一个控制序列. 二 使用POSIX的注意点 1 为了使用线程函数库,必须定义宏_REENTRANT,通过定义_REENTRANT来告诉编译器我们需要可重入功能,可 ...

  7. GDB多线程调试

    一.多线程调试1. 多线程调试,最重要的几个命令:info threads                        查看当前进程的线程.                              ...

  8. GDB调试方法精粹

    http://blog.chinaunix.net/uid-26922071-id-3756018.html 一.多线程调试 1. 多线程调试,最重要的几个命令: info threads       ...

  9. GDB多线程调试分析

    0x00: 在Linux系统上Gdb提供了一组多线程调试命令,如表所示: 多线程调试的主要任务是准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的结 ...

随机推荐

  1. 混合开发框架Flutter

    Flutter开发简介与其他的混合开发的对比 为什么要使用Flutter? 跨平台技术简介 Hybrid技术简介 QT简介 Flutter简介 为什么要使用Flutter? Flutter有什么优势? ...

  2. 神经网络 感知机 Perceptron python实现

    import numpy as np import matplotlib.pyplot as plt import math def create_data(w1=3,w2=-7,b=4,seed=1 ...

  3. 有向路径检查 牛客网 程序员面试金典 C++ Python

    有向路径检查 牛客网 程序员面试金典 C++ Python 题目描述 对于一个有向图,请实现一个算法,找出两点之间是否存在一条路径. 给定图中的两个结点的指针DirectedGraphNode* a, ...

  4. popStar机机对战数据生成器代码(C#)

    代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...

  5. 第01课 OpenGL窗口(1)

    教程的这一节在2000年一月彻底重写了一遍.将会教您如何设置一个 OpenGL窗口.它可以只是一个窗口或是全屏幕的.可以任意 大小.任意色彩深度.此处的代码很稳定且很强大,您可以在您所有的OpenGL ...

  6. java容器之HashMap

    HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的. 解决哈希冲突的三个方法: a.开放 ...

  7. (二)lamp环境搭建之编译安装mysql

    mysql 编译安装1,在网站上下载: wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.15.tar.gz 2,安装cmake ...

  8. offsetX各种值总结

    pageX: 页面X坐标位置 pageY: 页面Y坐标位置 screenX: 屏幕X坐标位置 screenY: 屏幕Y坐标位置 clientX: 鼠标的坐标到页面左侧的距离 clientY: 鼠标的坐 ...

  9. 一个疏忽损失惨重!就因为把int改成Integer,第2天被辞了

    1 故事背景 一个程序员就因为改了生产环境上的一个方法参数,把int型改成了Integer类型,因为涉及到钱,结果上线之后公司损失惨重,程序员被辞退了.信不信继续往下看.先来看一段代码: public ...

  10. redis-sentinel "DENIED Redis is running in protected mode"

    protected-mode no in sentinel.conf https://github.com/antirez/redis/issues/3106