gdb a pid 调试(vector erase与map erase)

今天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有很大不同

参考

vector、list、map、set中的erase用法

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 a pid 调试(vector erase与map erase)

(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执行程序输入选项执行,执行停到断点,接下来就是常规调试

 

参考

gdb中list用法

GDB 调试 一些命令good

gdb如何调试动态链接库问题

gdb调试命令

GDB 命令详细解释

 

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

 
喜欢 0
分享