GDB调试C++工程非ROS
1.通过运行可执行程序来进入gdb
CMakeLists中的修改:
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")#用于进行gdb调试
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
gdb调试指令
-
(gdb) gdb ./Examples/RGB-D/rgbd_tum //运行可执行文件
(gdb) set args /home/ubuntu/Documents/03.Semantic_Mapping_on_ORBSLAM2-master/Vocabulary/ORBvoc.txt /home/ubuntu/Documents/03.Semantic_Mapping_on_ORBSLAM2-master/Examples/RGB-D/TUM1.yaml /home/ubuntu/shard_read/rgbd_dataset_freiburg1_xyz /home/ubuntu/shard_read/rgbd_dataset_freiburg1_xyz/associate.txt //给出参数
//打断点 注意此时程序还未运行
(gdb) b rgbd_tum.cc:106 //在会编译成可执行文件的源文件cpp中加断点
(gdb) b Global.cc:25 //会提示未来编译成shared library的源文件cpp中加断点
No source file named Global.cc.
Make breakpoint pending on future shared library load? (y or [n]) y
(gdb) run //程序开始运行
Breakpoint 2, ORB_SLAM2::Global::init (this=0x7fffffffd526,
strSettingsFile=...)
at /home/ubuntu/Documents/03.Semantic_Mapping_on_ORBSLAM2-master/src/Global.cc:26
warning: Source file is more recent than executable.
26 }
(gdb) print Global::PORT //打印变量
$1 = 8080
(gdb) c //直接运行到下一个断点
Continuing.
Connect successfully! client iP: 127.0.0.1, port: 8080
[New Thread 0x7fffb2902700 (LWP 4336)]
[New Thread 0x7fffb2101700 (LWP 4337)]
gdb基础功能使用
c/continue # 向下运行到下一个断点处
n/next # 执行下一行代码,不进入调用的函数,直接返回结果
s/step # 执行下一行代码,进入调用的函数
finish # 跳出函数体
until # 跳出当前循环 在执行完循环体内的最后一条语句之后执行 until,才可以跳出循环
info breakpoints
info threads
2.通过运行core文件来进入gdb
CMake的时候增加生成core的编译选项
在文件 CMakeLists.txt添加下面一条语句
set(CMAKE_CXX_FLAGS_DEBUG "-O3 -Wall -g") //以debug形式编译,可以生成core文件
ulimit -a //查询core文件大小
![](https://img-blog.csdnimg.cn/d3780386dd8f47998b4cbb82a3d094a1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAc2xhbeiuqeaIkeWktOeWvA==,size_20,color_FFFFFF,t_70,g_se,x_16)
这里的size的单位是blocks,一般1block=512bytes,
ulimit –c 4 (注意,这里的size如果太小,则可能不会产生对应的core文件,笔者设置过ulimit –c 1的时候,系统并不生成core文件,并尝试了1,2,3均无法产生core,至少需要4才生成core文件)。
我的ubuntu系统改完大小以后直接在打开终端的目录下生成core文件。
但根据百度出来的结果,很可能会在其他路径下生成相关文件。
但当前设置的ulimit只对当前会话有效,若想系统均有效,则需要进行如下设置:
Ø 在/etc/profile中加入以下一行,这将允许生成coredump文件
ulimit-c unlimited //会在当前的文件目录下生成core文件
Ø 在rc.local中加入以下一行,这将使程序崩溃时生成的coredump文件位于/data/coredump/目录下:
echo /data/coredump/core.%e.%p> /proc/sys/kernel/core_pattern
注意rc.local在不同的环境,存储的目录可能不同,susu下可能在/etc/rc.d/rc.local
ROS 配置gdb进行调试查看最后一行出错的代码
rosrun --prefix 'gdb -ex run --args' [package_name] [node_name]
VINS-FUSION中
rosrun --prefix 'gdb -ex run --args' vins vins_node /home/zhou/1130_vinsfusion/src/VINS-Fusion-master/config/kitti_stereo/kitti_mono_imu_config.yaml
修改ROS launch文件,在node标签中添加一句话
launch-prefix="xterm -e gdb -ex run --args "
<node pkg="waypoint_follower" type="pure_persuit" name="pure_pursuit" output="screen" launch-prefix="xterm -e gdb -ex run --args">
</node>
附:roslaunch node前缀
The launch-prefix attribute of the tag that, among other things, makes it easy to debug a ROS node process. Here are some example launch-prefixes you might find useful:
launch-prefix=“xterm -e gdb --args” : run your node in a gdb in a separate xterm window, manually type run to start it
launch-prefix=“gdb -ex run --args” : run your node in gdb in the same xterm as your launch without having to type run to start it
launch-prefix=“stterm -g 200x60 -e gdb -ex run --args” : run your node in gdb in a new stterm window without having to type run to start it
launch-prefix=“valgrind” : run your node in valgrind
这个valgrind工具可以用于检测内存泄露,并执行性能分析
launch-prefix=“xterm -e” : run your node in a separate xterm window
launch-prefix=“nice” : nice your process to lower its CPU usage
launch-prefix=“screen -d -m gdb --args” : useful if the node is being run on another machine; you can then ssh to that machine and do screen -D -R to see the gdb session
launch-prefix=“xterm -e python -m pdb” : run your python node a separate xterm window in pdb for debugging; manually type run to start it
说明:launch-prefix后面的内容可以如rosrun --prefix 'gdb -ex run --args' 放到引号里进行使用
参考链接:ROS在线调试(使用GDB)_lovely_yoshino的博客-CSDN博客_roslaunch 调试
roslaunch/Tutorials/Roslaunch Nodes in Valgrind or GDB - ROS Wiki
C++ 基础:
override只是C++保留字,不是关键字,这意味着只有在正确的使用位置,oerride才启“关键字”的作用,其他地方可以作为标志符
class Base {
virtual void f();
};
class Derived : public Base {
void f() override; // 表示派生类重写基类虚函数f
void F() override;//错误:函数F没有重写基类任何虚函数
};