今天gdb a pid调试发现了一个问题
执行程序崩溃段错误
gdb GFS.test core 定位到了崩溃点
原因vector点erase方法返回会使迭代器+1操作,当erase后再将迭代器+1将会导致 地址越界以至于段错误
list与vector中的erase用法相同,它们的 erase 函数会返回指向下一个元素的迭代器,因此在遍历时,只需要 it = c.erase(it); 即可
for (std::vector<GFSgwInfo>::iterator itorCh = children.begin(); itorCh != children.end(); /* ++itorCh */) { if (m_realPort == itorCh->port && 0 == strcmp(m_realIp.c_str(), itorCh->ip.c_str())) itorCh = children.erase(itorCh); else ++itorCH; }
std::map::erase方法返回void,会使删除的迭代器失效,需用erase(itor++)得到删除迭代器的下一个迭代器,与vector有很大不同
参考
map<int, int> m; m[2] = 2; m[4] = 4; m[6] = 6; //map迭代器为中序遍历,那么插入的节点成为m.begin()的左子节点不会被当前遍历到, //因为中序为有序遍历,比m.begin()小的节点不会被当前迭代器包含 map<int, int>::iterator itor = m.begin(); int add = 1; for ( ; itor != m.end() ) { if (add == 1) { m[1] = 1; m[3] = 3; m[5] = 5; } add = 0; if (itor->second = 6) m.erase(itor++); else { std::cout << itor->second << std::endl; ++itor; } } // run result: 2 3 4 5
然后通过gdb调试
ps -ef |grep GFS.test 找到pid
gdb a pid调试
(gdb)list AppClient.cpp:750
查看代码
(gdb)stop --先暂停那个子进程,然后设置一些断点和一些Watch
(gdb)b AppClient.cpp:758 --设置断点
奇怪的是通过b AppClient.cpp: AppClient::getGFSgwServer设置断点时,是通过动态加载方式:
Function " AppClient::getGFSgwServer" not defined in "AppClient.cpp".
Make breakpoint pending on future shared library load? (y or [n])
但是运行的时候停不到断点,gdb也会有错误提示:Missing separate debuginfo for /lib64/libnss_files.so.2 等...;用b AppClient.cpp:758 却可以
(gdb)c --继续运行
然后GFS.test执行程序输入选项执行,执行停到断点,接下来就是常规调试
参考
cmake支持gdb的实现, 首先在CMakeLists.txt下加入 SET(CMAKE_BUILD_TYPE "Debug") 在下面加入: SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 原因是CMake 中有一个变量 CMAKE_BUILD_TYPE ,可以的取值是 Debug Release RelWithDebInfo >和 MinSizeRel。 当这个变量值为 Debug 的时候,CMake 会使用变量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_C_FLAGS_DEBUG 中的字符串作为编译选项生成 Makefile;
gdb中命令:
回车键:重复上一命令
(gdb)help:查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h
(gdb)run:重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r
(gdb)start:单步执行,运行程序,停在第一执行语句
(gdb)list:查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l
(gdb)set:设置变量的值;set args
(gdb)next:单步调试(逐过程,函数直接执行),简写n
(gdb)step:单步调试(逐语句:跳入自定义函数内部执行),简写s
(gdb)backtrace:查看函数的调用的栈帧和层级关系,简写bt
(gdb)frame:切换函数的栈帧,简写f
(gdb)info:查看函数内部局部变量的数值,简写i
(gdb)finish:结束当前函数,返回到函数调用点
(gdb)continue:继续运行,简写c
(gdb)print:打印值及地址,简写p
(gdb)quit:退出gdb,简写q
(gdb)search keywork 在当前文件搜索关键字,配合break使用;切换文件可以list filename:linenum
(gdb)break+num:在第num行设置断点,简写b
(gdb)info breakpoints:查看当前设置的所有断点
(gdb)delete breakpoints num:删除第num个断点,简写d
(gdb)display:追踪查看具体变量值
(gdb)undisplay:取消追踪观察变量
(gdb)watch:被设置观察点的变量发生修改时,打印显示
(gdb)i watch:显示观察点
(gdb)enable breakpoints:启用断点
(gdb)disable breakpoints:禁用断点
(gdb)whatis i即可知道i是什么类型的变量
(gdb)x:查看内存x/20xw 显示20个单元,16进制,4字节每单元
(gdb)run argv[1] argv[2]:调试时命令行传参
(gdb) set args help就能加上可执行文件需要的参数,如果要看argc[1]到argc[N]的参数,只需要 (gdb) show args
(gdb)set follow-fork-mode child#Makefile项目管理:选择跟踪父子进程(fork())
core文件:先用$ ulimit -c 1024 开启core,当程序出错会自动生成core文件。调试时 gdb a.out core
 
gdb a pid 调试(vector erase与map erase):等您坐沙发呢!