0%

使用GDB调试ROS2程序

我们使用backward_ros功能包来快速实现用GDB调试ROS2程序。

backward_ros功能包介绍

backward_ros功能包是对backward-cpp包的ROS2封装,以便可以简单快速地使用GDB工具。

backward-cpp包的介绍可以查看其仓库:

https://github.com/bombela/backward-cpp

使用backward_ros功能包实现GDB调试ROS2程序只需下面三个步骤:

  1. 添加backward_rospackage.xml 文件。
1
<depend>backward_ros</depend>
  1. 添加backward_rosCMakeLists.txt文件中。
1
find_package(backward_ros REQUIRED)
  1. 使用Debug 或者 RelWithDebInfo选项编译程序。
1
colcon build --cmake-args '-DCMAKE_BUILD_TYPE=RelWithDebInfo'

backward_ros功能包的github地址(ROS2程序使用foxy-devel分支):

https://github.com/pal-robotics/backward_ros.git

运行示例程序

获取示例程序:

1
git clone https://github.com/shoufei403/gdb_test.git

编译时选择RelWithDebInfoDebug编译类型时可以看到是代码的哪一行出了问题

1
colcon build --cmake-args '-DCMAKE_BUILD_TYPE=RelWithDebInfo'

运行测试程序

1
2
source install/setup.bash
ros2 run gdb_test gdb_test

可以看到下面的堆栈信息

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Stack trace (most recent call last):
#4 Object "", at 0xffffffffffffffff, in
#3 Source "/home/kevin/gdb_test/src/gdb_test/gdb_test.cpp", line 50, in _start [0x56060876e91d]
47: rclcpp::spin(std::make_shared<MinimalSubscriber>());
48: rclcpp::shutdown();
49: return 0;
> 50: }
#2 Source "../csu/libc-start.c", line 308, in __libc_start_main [0x7f1b2f271082]
#1 | Source "/home/kevin/gdb_test/src/gdb_test/gdb_test.cpp", line 47, in make_shared<MinimalSubscriber>
| 45: {
| 46: rclcpp::init(argc, argv);
| > 47: rclcpp::spin(std::make_shared<MinimalSubscriber>());
| 48: rclcpp::shutdown();
| 49: return 0;
| Source "/usr/include/c++/9/bits/shared_ptr.h", line 718, in allocate_shared<MinimalSubscriber, std::allocator<MinimalSubscriber> >
| 716: typedef typename std::remove_cv<_Tp>::type _Tp_nc;
| 717: return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
| > 718: std::forward<_Args>(__args)...);
| 719: }
| Source "/usr/include/c++/9/bits/shared_ptr.h", line 702, in shared_ptr<std::allocator<MinimalSubscriber> >
| 700: {
| 701: return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a},
| > 702: std::forward<_Args>(__args)...);
| 703: }
| Source "/usr/include/c++/9/bits/shared_ptr.h", line 359, in __shared_ptr<std::allocator<MinimalSubscriber> >
| 357: template<typename _Alloc, typename... _Args>
| 358: shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)
| > 359: : __shared_ptr<_Tp>(__tag, std::forward<_Args>(__args)...)
| 360: { }
| Source "/usr/include/c++/9/bits/shared_ptr_base.h", line 1344, in __shared_count<MinimalSubscriber, std::allocator<MinimalSubscriber> >
| 1342: template<typename _Alloc, typename... _Args>
| 1343: __shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)
| >1344: : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...)
| 1345: { _M_enable_shared_from_this_with(_M_ptr); }
| Source "/usr/include/c++/9/bits/shared_ptr_base.h", line 679, in _Sp_counted_ptr_inplace<>
| 677: auto __guard = std::__allocate_guarded(__a2);
| 678: _Sp_cp_type* __mem = __guard.get();
| > 679: auto __pi = ::new (__mem)
| 680: _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...);
| 681: __guard = nullptr;
| Source "/usr/include/c++/9/bits/shared_ptr_base.h", line 548, in construct<MinimalSubscriber>
| 546: // _GLIBCXX_RESOLVE_LIB_DEFECTS
| 547: // 2070. allocate_shared should use allocator_traits<A>::construct
| > 548: allocator_traits<_Alloc>::construct(__a, _M_ptr(),
| 549: std::forward<_Args>(__args)...); // might throw
| 550: }
| Source "/usr/include/c++/9/bits/alloc_traits.h", line 483, in construct<MinimalSubscriber>
| 481: construct(allocator_type& __a, _Up* __p, _Args&&... __args)
| 482: noexcept(std::is_nothrow_constructible<_Up, _Args...>::value)
| > 483: { __a.construct(__p, std::forward<_Args>(__args)...); }
| 484:
| 485: /**
Source "/usr/include/c++/9/new", line 174, in main [0x56060876e7b1]
172: // Default placement versions of operator new.
173: _GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
> 174: { return __p; }
175: _GLIBCXX_NODISCARD inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
176: { return __p; }
#0 Source "/home/kevin/gdb_test/src/gdb_test/gdb_test.cpp", line 33, in MinimalSubscriber [0x56060878c1a8]
30: "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
31:
32: int * p = nullptr;
> 33: *p = 1;//制造断错误
34: }
35:
36: private:
Segmentation fault (Address not mapped to object [(nil)])

其他使用GDB的方法可以参考此文档

https://navigation.ros.org/tutorials/docs/get_backtrace.html#preliminaries


觉得有用就点赞吧!

我是首飞,一个帮大家填坑的机器人开发攻城狮。

另外在公众号《首飞》内回复“机器人”获取精心推荐的C/C++,Python,Docker,Qt,ROS1/2等机器人行业常用技术资料。

公众号