0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Ubuntu 16.04系统中调试Apollo项目核心转储文件的方法

电子工程师 来源:未知 作者:李倩 2018-03-23 09:30 次阅读

Linux系统中,若程序异常终止,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为叫做Core Dump(中文一般译为“核心转储”)。实际上,除内存信息之外,核心转储还会记录程序的一些关键运行状态,例如寄存器信息(包括程序指针、栈指针等)、内存管理信息等。核心转储对于程序员调试程序非常有益,因为有些程序错误是很难重现的,例如指针异常,而核心转储文件可以重现程序出错时的情景。

1

Ubuntu 16.04系统中打开核心转储功能

Ubuntu 16.04系统默认关闭了核心转储功能,需重新设置打开。

1检查核心转储是否打开

按快捷键“Ctrl+Alt+T”打开命令终端,输入命令:

ulimit -c

若输出的结果为 0,则说明默认是关闭核心转储功能的,即当程序异常终止时,不会生成核心转储文件。

2在当前命令终端中打开核心转储

使用命令:

ulimit -c unlimited

可开启当前命令终端的核心转储功能,并且不限制核心转储文件大小; 若需限制文件大小,将unlimited修改为你所需文件的大小,注意单位为KB。

3永久打开核心转储

若想永久打开核心转储功能,则使用命令:

sudo vi /etc/security/limits.conf

修改配置文件(我这里是使用vi编辑器修改,你可以换成自己熟悉的编辑器,但建议修改配置文件还是采用vi较好,因为它是所有Unix/Linux系统标配的编辑器,并且简单的操作并不困难),增加如下所示的一行内容:

#Each line describes a limit for a user in the form:## * soft core unlimited

4配置核心转储文件名是否添加PID号

默认的核心转储文件名称为core。通过修改/proc/sys/kernel/core_uses_pid文件可以让生成的core文件名是否自动加上pid号。使用命令:

sudo vi /proc/sys/kernel/core_uses_pid

将/proc/sys/kernel/core_uses_pid文件里的“0”修改为“1”,然后保存退出,这样生成的core文件名将会变成core.pid,其中pid表示该进程的PID。

5配置核心转储文件的生成位置及文件名格式

默认的核心转储文件保存在可执行文件所在的目录下,可以通过修改/proc/sys/kernel/core_pattern文件来控制core文件的生成位置以及文件名格式。使用命令:

sudo vi /proc/sys/kernel/core_pattern

可对core文件的生成位置以及文件名格式进行配置,以下是几种配置示例:

# 示例1:将生成的core文件保存在/apollo/data/core目录下,# 文件名格式:“core_进程名.进程PID”/apollo/data/core/core_%e.%p# 示例2:将生成的core文件保存在/tmp/core目录下,# 文件名格式:“core_进程名_进程PID.时间戳”/tmp/core/core_%e_%p.%t# 示例3:这是Ubuntu默认的core文件生成方式。# “apport”是一个用python写的脚本程序,# 其作用是在可执行文件目录下生成core文件,# %p %s %c %d %P分别表示: # [global pid]/usr/share/apport/apport %p %s %c %d %P

注意:以上示例只能使用其中一个,关于core文件的详细命名格式,可以通过man core命令查看。

2

Ubuntu 16.04系统中调试核心转储文件的一个示例

1生成核心转储文件

首先撰写一个C++测试程序,代码如下:

#include int main(){ // Attention! // The following code will cause a core dump file. double *pointer; *pointer = 10; return 0;}

Linux系统中使用GCC编译器的编译命令如下:

g++ -g -Wall -std=c++11 *.cpp -o test

注意,上述命令一定要加“-g”选项,生成调试信息,否则后面使用GDB调试核心转储文件时,仍然无法定位程序崩溃点。

运行该程序:

./test

输出结果为:

段错误 (核心已转储)

ls -l的结果如下(我使用示例3所示的core文件生成方式):

总用量 584-rw------- 1 davidhopper davidhopper 565248 Mar 19 17:49 core-rw-rw-r-- 1 davidhopper davidhopper 163 Mar 19 16:27 main.cpp-rwxrwxr-x 1 davidhopper davidhopper 25968 Mar 19 17:49 test

可见,已经在当前可执行文件目录中生成了一个核心转储文件:core

2使用GDB调试器调试core文件

借助GDB调试器,使用如下命令,可调试core文件:

gdb ./test core

输出信息如下:

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1Copyright (C) 2016 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:.Find the GDB manual and other documentation resources online at:.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from ./test...done.[New LWP 4340]Core was generated by `./test'.Program terminated with signal SIGSEGV, Segmentation fault.#0 0x00000000004006c6 in main () at main.cpp:88 *pointer = 10;(gdb)

可见,GDB调试器根据生成的core文件,已经找到了程序崩溃点为原程序的第8行。看到这里,是不是感觉到了GDB调试核心转储文件的威力?

3

Ubuntu 16.04系统中调试Apollo项目核心转储文件的方法

由于Apollo项目是在Docker中运行,因此不能直接在Ubuntu 16.04系统中直接生成核心转储文件并使用GDB对其进行调试,所有的工作必须在Docker中完成。具体操作步骤如下:

1启动并进入Apollo项目的Docker

# 进入Apollo项目根目录(我的路径为:~/code/apollo,你需要修改为自己的路径)cd ~/code/apollo# 启动Apollo项目的Docker(注意:2.0以上版本在后面加上一个“-C”选项,# 表示从中国服务器拉取镜像文件,以加快下载速度)bash docker/scripts/dev_start.sh# 进入Dockerbash docker/scripts/dev_into.sh

2在Docker内部检查并设置核心转储功能

在Docker内部,使用本文第一部分内容检查并设置核心转储功能。在我的机器上,使用ulimit -c命令检查的结果为:unlimited,表明已打开核心转储功能。假如在你的Docker内部发现未开启核心转储功能,该怎么办?那就按照本文第一部分内容重新打开呗。

同样在我的Docker内部,使用命令:cat /proc/sys/kernel/core_pattern查看核心转储文件的生成位置及文件名格式,得到的结果为:/apollo/data/core/core_%e.%p,表明Docker内部的核心转储文件被保存在/apollo/data/core目录下,文件名格式:core_进程名.进程PID。当然,你也可以按照本文第一部分内容对核心转储文件的保存位置及文件名格式进行定制。

3在Docker内部调试各功能模块生成的核心转储文件的方法

在Apollo项目Docker内部,所有功能模块的可执行文件均被放置于/apollo/bazel-bin/modules。下面以规划(Planning)模块为例进行说明。

最近,我修改了规划模块内部的RTKReplayPlanner类。在通过Dreamview调试规划模块时,经常发现该模块莫名其妙地退出,看日志文件没有任何可用信息,根据我的编程经验,这一定是我在某处的指针使用存在问题,要么是引用了空指针,要么是指针越界,如此等等,不一而足。是时候让核心转储文件发挥作用了。

我打开/apollo/data/core目录,果然找到了规划模块崩溃时生成的核心转储文件:core_planning.695,于是立刻在Docker内部(即使用bash docker/scripts/dev_into.sh命令进入Docker后的命令行终端内操作)借助GDB调试该文件,命令如下所示。注意:若需定位程序崩溃位置,必须在构建Apollo项目时,添加调试信息。也就是说,构建命令不能使用“build_opt”或“build_opt_gpu”等优化选项,而应使用“build”或“build_gpu”等带调试信息的选项。

gdb /apollo/bazel-bin/modules/planning/planning /apollo/data/core/core_planning.695

调试结果如下:

GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1Copyright (C) 2014 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:.Find the GDB manual and other documentation resources online at:.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from /apollo/bazel-bin/modules/planning/planning...done.[New LWP 747][New LWP 697][New LWP 695][New LWP 698][New LWP 709][New LWP 699][New LWP 714][New LWP 700][New LWP 746][New LWP 750][New LWP 749][New LWP 711][New LWP 702][New LWP 703][New LWP 704][New LWP 705][New LWP 706][New LWP 707][New LWP 708][New LWP 712][New LWP 745][New LWP 748][Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".Core was generated by `/apollo/bazel-bin/modules/planning/planning --flagfile=modules/planning/conf/pl'.Program terminated with signal SIGSEGV, Segmentation fault.#0 0x000000000042f476 in apollo::common::TrajectoryPoint::relative_time (this=0x0) at bazel-out/local-dbg/genfiles/modules/common/proto/pnc_point.pb.h:15141514 return relative_time_;(gdb)

上述结果表明,在bazel-out/local-dbg/genfiles/modules/common/proto/pnc_point.pb.h文件的1514行返回relative_time_时,this指针为空,即引用了一个空指针。显然,这里只是错误暴露处,而非错误产生处。联想到我修改了RTKReplayPlanner类,于是我立即在modules/planning/planner/rtk/rtk_replay_planner.cc中查找关键字:relative_time,找到相关代码处(注意:下面的代码是我修改后的内容,并非Apollo项目原有代码):

// reset relative time double zero_time = current_trajectory[matched_index].relative_time(); for (auto& trajectory_point : trajectory_points) { // davidhopper // We shoud add the "planning_init_point.relative_time()" to // maintain the correct time sequence. trajectory_point.set_relative_time(trajectory_point.relative_time() - zero_time + planning_init_point.relative_time());

最终结果水落石出,原来是double zero_time = current_trajectory[matched_index].relative_time();作了越界引用。找到了错误产生原因,代码修改方法也就比较容易了,对matched_index的范围作出限制即可解决问题。

自Apollo平台开放已来,我们收到了大量开发者的咨询和反馈,越来越多开发者基于Apollo擦出了更多的火花,并愿意将自己的成果贡献出来,这充分体现了Apollo『贡献越多,获得越多』的开源精神。为此我们开设了『开发者说』板块,希望开发者们能够踊跃投稿,更好地为广大自动驾驶开发者营造一个共享交流的平台!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11222

    浏览量

    208891
  • Ubuntu
    +关注

    关注

    5

    文章

    560

    浏览量

    29553
  • 编辑器
    +关注

    关注

    1

    文章

    800

    浏览量

    31112
  • Apollo
    +关注

    关注

    5

    文章

    340

    浏览量

    18403

原文标题:开发者说 | 在Docker内使用GDB调试Apollo项目的核心转储(Core Dump)文件

文章出处:【微信号:Apollo_Developers,微信公众号:Apollo开发者社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Ubuntu 16.04 MATE树莓派3版本开始支持板载Wi-Fi和蓝牙

     Ubuntu的MATE项目负责人Martin Wimpress昨天宣布推出Ubuntu 16.04 MATE第二个Beta版本,Ubuntu
    发表于 04-06 10:20 4578次阅读

    【BPI-M64试用体验】第一篇 烧写ubuntu16.04 mate系统

    是没有系统的,需要自己烧写系统,本人烧写了ubuntu16.04mate与android6.0系统。需要准备的工具有:220V5V电源,一
    发表于 04-17 08:51

    如何在VMware安装ubuntu 16.04

    如何在VMware安装ubuntu 16.04如何安装Vitis AI几个常见的docker指令
    发表于 02-24 06:24

    如何对Apollo2.5 CANBUS进行全面调试

    前言:CANBUS是Apollo需要根据你的底盘写代码的地方,感觉也是Apollo最难调试的部分。这部分首先要选好CAN卡,因为不是Apollo推荐的CAN卡,驱动程序和对应接口,可能
    发表于 08-30 06:02

    Ubuntu16.04配置开发编译环境的过程是怎样的?

    如何获取Ubuntu16.04镜像文件Ubuntu16.04配置开发编译环境的过程是怎样的?
    发表于 03-04 07:06

    Ubuntu 16.04系统环境下Ubuntu固件的编译流程是怎样的

    Ubuntu 16.04系统环境下Ubuntu固件的编译流程是怎样的?如何在Ubuntu 16.04
    发表于 03-04 07:18

    如何使用Ubuntu 16.04编译根文件系统

    如何使用Ubuntu 16.04编译根文件系统
    发表于 03-09 07:57

    移植Ubuntu16.04系统到ROC-RK3308-CC板子上记录

    文件系统方法,最核心的地方就是通过交叉模拟器qemu-user-static,对文件系统进行定制,这个大家按自己需求来就好,这里就不再赘述了,这里移植的是
    发表于 06-09 16:58

    有什么方法可以追溯地将加密标志应用于现有加密设备上的核心分区?

    我有一个生产固件的设备。我们启用了闪存加密,并启用了核心。不幸的是,我们没有在文档的任何地方看到核心
    发表于 03-02 08:01

    ubuntu隐藏/显示文件文件

    ubuntu 16.04 LTS - 隐藏/显示文件文件夹 1. GUI hot key Ctrl H: 隐藏/显示文件
    发表于 11-25 12:52 5067次阅读

    Ubuntu 16.04 MATE树莓派3版本开始支持板载Wi-Fi和蓝牙

    Ubuntu的MATE项目负责人Martin Wimpress今天宣布推出Ubuntu 16.04 MATE第二个Beta版本,Ub
    发表于 04-02 14:51 358次阅读

    fireflyAIO-3288J主板编译Ubuntu16.04固件简介

    编译 Ubuntu16.04 固件(GPT) 前言 本 SDK 开发环境是在 Ubuntu 上开发测试的。我们推荐使用 Ubuntu 16.04
    的头像 发表于 12-26 14:54 3231次阅读
    fireflyAIO-3288J主板编译<b class='flag-5'>Ubuntu16.04</b>固件简介

    嵌入式Linux移植3. NFS根文件系统挂载(从Ubuntu启动内核,文件系统

    :通过tftp使用Ubuntu的/tftpboot的uImage启动rootfs根文件系统:通过NFS使用Ubuntu
    发表于 11-02 12:51 7次下载
    嵌入式Linux移植3. NFS根<b class='flag-5'>文件系统</b>挂载(从<b class='flag-5'>Ubuntu</b>启动内核,<b class='flag-5'>文件系统</b>)

    ubuntu与windows之间的文件互传方法

    。因此在开发的过程中会经常在 Windows和 Ubuntu两者间切换,同时还需要频繁的进行文件互传。一般情况下,ubuntu 与 windows 之间的文件互传有如下三种
    的头像 发表于 04-17 15:03 1.1w次阅读
    <b class='flag-5'>ubuntu</b>与windows之间的<b class='flag-5'>文件</b>互传<b class='flag-5'>方法</b>

    ubuntu删除的文件怎么恢复

    Ubuntu系统,删除的文件可以通过多种方法进行恢复。本文将详细介绍Ubuntu
    的头像 发表于 08-30 15:10 1142次阅读