关于GDB

基本使用不会贴在这里。只是放自己的使用心得。
基本使用可以看这个
http://fanqiang.chinaunix.net/program/other/2006-07-14/4834.shtml
1.为什么没有调试信息?
多模块的时候,我明明debug编译了,相应的.so文件也拷贝到安装目录中了,加断点的时候,找不到文件提示:No source file namedXXXXX。
原来要运行的时候才加载对应的文件。
比如说你要给一个对话框创建的时候的代码加断点。先把这个对话框运行起来,然后加断点就可以了。
网上搜了下,说可以在.gdbinit里加
"set breakpoint pending on"
解决。我没试过。

2.调用堆栈
命令:bt //列出调用堆栈
命令:frame id //栈顶ID号为0,往后依次类推。
用frame命令不会让程序的执行跳转到对应位置,但是你可以查看变量及各种状态。程序的下一条指令不会随frame而边。它会给你造成程序好像从后面重新执行的错觉。

3.打印内存。
X命令。可以用help x来查看。
x/<n/f/u> <addr>

n、f、u是可选的参数。
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
u表示单位的大小:如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。
例子:
假设t是int型变量
(gdb) x/t &t
0xbffff3ac: 00000000001010000011111111111101
(gdb) x/4bt &t
0xbffff3ac: 11111101 00111111 00101000 00000000



4.打印数组
例如,你的程序中有这样的语句:
int *array = (int *) malloc (len * sizeof (int));
于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:
p *array@len

5.core dump
http://my.oschina.net/kaixindewo/blog/28526
http://www.cnblogs.com/lbsx/archive/2010/10/09/1846535.html
http://cs.baylor.edu/~donahoo/tools/gdb/tutorial.html
http://www.linuxsir.org/bbs/thread344797.html
<think>我们被要求使用GDB调试多线程和多进程程序,并提供示例和调试指导。根据引用内容,我们可以总结出以下步骤和示例。 首先,GDB是一个功能强大的调试工具,可以用于调试多线程和多进程程序。主要功能包括: 1. 启动程序,并按照自定义要求运行。 2. 设置断点(包括条件表达式)让程序停住。 3. 检查程序停住时的状态。 4. 动态改变程序执行环境。 ### 调试多线程程序 多线程调试的关键是能够查看和切换线程,设置断点,以及观察线程间的交互(如死锁)。 #### 示例代码(多线程死锁问题) 以下是一个简单的多线程死锁示例(根据引用[2]和[3]的启示编写): ```cpp #include <iostream> #include <thread> #include <mutex> std::mutex mtx1; std::mutex mtx2; void thread1() { mtx1.lock(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟一些操作 mtx2.lock(); // 等待mtx2 std::cout << "Thread1 is running" << std::endl; mtx2.unlock(); mtx1.unlock(); } void thread2() { mtx2.lock(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); mtx1.lock(); // 等待mtx1 std::cout << "Thread2 is running" << std::endl; mtx1.unlock(); mtx2.unlock(); } int main() { std::thread t1(thread1); std::thread t2(thread2); t1.join(); t2.join(); return 0; } ``` 这个程序可能会发生死锁,因为两个线程以不同的顺序请求互斥锁。 #### 调试步骤 1. **编译程序**:使用`-g`选项编译,以便调试。 ```bash g++ -g -std=c++11 -o deadlock deadlock.cpp -pthread ``` 2. **启动GDB**: ```bash gdb ./deadlock ``` 3. **运行程序**:在GDB中运行程序,直到发生死锁(程序可能挂起)。 ```bash (gdb) run ``` 4. **查看线程状态**:使用`info threads`命令查看所有线程的状态。 ```bash (gdb) info threads ``` 输出可能显示每个线程正在执行的函数,以及它们阻塞的位置。 5. **切换线程并查看堆栈**:例如,切换到线程1,并查看其堆栈跟踪。 ```bash (gdb) thread 1 (gdb) bt ``` 类似地,切换到线程2,查看堆栈。 6. **检查死锁位置**:通过堆栈跟踪,可以确定线程在等待哪个互斥锁。例如,线程1可能卡在`mtx2.lock()`,而线程2卡在`mtx1.lock()`。 7. **设置断点**:可以在关键位置(如锁操作前)设置断点,以便在死锁发生前暂停程序。 ```bash (gdb) break thread1.cpp:10 # 在thread1函数中请求mtx2之前设置断点 (gdb) break thread2.cpp:10 # 在thread2函数中请求mtx1之前设置断点 ``` 8. **重新运行并调试**:重新运行程序,当程序在断点处停止时,可以单步执行(`step`或`next`)并观察。 ### 调试多进程程序 GDB在调试多进程程序时,默认只跟踪父进程。要调试子进程,需要设置`follow-fork-mode`。 #### 示例代码(多进程) ```c #include <stdio.h> #include <unistd.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程 printf("Child process\n"); int x = 5 / 0; // 制造一个除零错误 } else { // 父进程 printf("Parent process\n"); wait(NULL); } return 0; } ``` #### 调试步骤 1. **编译**: ```bash gcc -g -o multiprocess multiprocess.c ``` 2. **启动GDB**: ```bash gdb ./multiprocess ``` 3. **设置跟踪子进程**:在运行前设置`follow-fork-mode`为`child`(默认为`parent`)。 ```bash (gdb) set follow-fork-mode child ``` 4. **运行程序**:运行程序,GDB会跟踪进入子进程。 ```bash (gdb) run ``` 当子进程发生除零错误时,GDB会暂停并报告错误。 5. **查看错误位置**:使用`bt`查看堆栈,定位错误代码。 6. **调试父进程**:如果需要切换回父进程,可以在fork之后设置: ```bash (gdb) set follow-fork-mode parent ``` 然后重新运行。 ### 总结 - **多线程调试**:使用`info threads`, `thread <id>`, `bt`等命令查看和切换线程,并分析死锁或竞争条件。 - **多进程调试**:使用`set follow-fork-mode`选择跟踪的进程,并注意子进程的调试。 ### 注意事项 - 在多线程调试中,可以使用`thread apply all bt`查看所有线程的堆栈。 - 对于核心转储文件(core dump),可以使用`gdb <program> <core>`来调试。 以上示例和步骤可以帮助你开始使用GDB调试多线程和多进程程序。 §§相关问题§§ 1. 如何用GDB调试程序中的死锁问题? 2. GDB调试多进程程序时,如何切换跟踪的进程? 3. 如何利用GDB调试程序崩溃产生的core文件?</think>### GDB调试多线程与多进程程序指南 #### 一、基础调试流程 1. **编译带调试信息** 使用 `-g` 选项编译程序(以C++为例): ```bash g++ -g -std=c++11 -o program program.cpp -pthread ``` 2. **启动GDB调试** ```bash gdb ./program ``` 3. **核心调试命令** - `run`:启动程序 - `break [位置]`:设置断点(如 `break main` 或 `break 行号`) - `next`/`n`:单步跳过 - `step`/`s`:单步进入 - `print [变量]`:查看变量值 - `backtrace`/`bt`:查看调用堆栈 #### 二、多线程调试技巧 **示例代码(引用[3]修改版)**: ```cpp #include <thread> #include <mutex> #include <chrono> std::mutex mtx; // 互斥锁 void worker(int id) { while (true) { mtx.lock(); std::cout << "Thread " << id << " working\n"; mtx.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } int main() { std::thread t1(worker, 1); std::thread t2(worker, 2); t1.join(); t2.join(); return 0; } ``` **关键调试命令**: 1. 查看所有线程: ```gdb (gdb) info threads ``` ``` Id Target Id Frame * 1 Thread 0x7ffff7feb740 (LWP 1234) main () at main.cpp:20 2 Thread 0x7ffff77f6700 (LWP 1235) worker (id=1) at main.cpp:10 3 Thread 0x7ffff6ff5700 (LWP 1236) worker (id=2) at main.cpp:10 ``` 2. 切换线程上下文: ```gdb (gdb) thread 2 # 切换到ID为2的线程 ``` 3. 设置线程特定断点: ```gdb (gdb) break worker thread 2 # 仅在线程2触发 ``` 4. 检测死锁(当线程卡在锁操作时): - 使用 `bt` 查看堆栈 - 检查 `p mtx` 查看锁状态 #### 三、多进程调试技巧 **示例代码(fork示例)**: ```c #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程 execl("./child_program", "./child_program", NULL); } else { // 父进程 wait(NULL); } return 0; } ``` **关键调试命令**: 1. 跟踪子进程: ```gdb (gdb) set follow-fork-mode child ``` 2. 同时调试父子进程: ```gdb (gdb) set detach-on-fork off # 同时保留控制权 (gdb) info inferiors # 查看所有进程 (gdb) inferior 2 # 切换到子进程 ``` 3. 添加子进程断点: ```gdb (gdb) catch exec # 捕获exec事件 (gdb) break child_function # 在子进程函数设断点 ``` #### 、Core文件调试 当程序崩溃时(如段错误): ```bash ulimit -c unlimited # 启用core dump ./program # 触发崩溃 gdb ./program core # 调试core文件 ``` 在GDB中使用: ```gdb (gdb) bt # 查看崩溃时的调用栈 (gdb) frame [栈帧编号] # 检查具体栈帧 (gdb) print [变量] # 查看崩溃时变量值 ``` #### 五、高级调试场景 1. **条件断点**(引用[1]): ```gdb (gdb) break main.cpp:20 if id == 2 && count > 100 ``` 2. **观察点**: ```gdb (gdb) watch global_var # 当变量被修改时暂停 ``` 3. **修改运行状态**(引用[1]): ```gdb (gdb) set var count = 0 # 动态修改变量值 ``` > **调试建议**:多线程问题常出现在锁竞争和共享数据访问,使用 `thread apply all bt` 可一次性查看所有线程堆栈;多进程调试需注意进程间同步点[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值