【GDB】手把手教你用gdb调试程序(超清晰流程)
实例
我以自己曾经写的一段实际代码为例,来讲解究竟该怎么进行GDB
调试。
实例地址:
GitHub:https://github.com/yngzMiao/protobuf-parser-tool
实例的功能是生成和解析proto
文件,分为C++
和python
版本。其中,C++
版本采用的是CMakeLists.txt
进行编译,按照以下命令可以生成可执行文件:
mkdir build && cd build
cmake ..
make
最终可执行文件example_person
是在build
文件夹下。
如果不太了解CMakeLists.txt的,可以阅读博文:【CMake】CMakeLists.txt的超傻瓜手把手教程(附实例源码)
前提
一般情况下,GDB
主要调试的是C/C++
的程序。要调试C/C++
的程序,首先在编译时,必须要把符号表信息加到可执行文件中。使用编译器的-g
参数可以做到这一点。比如:
g++ -g hello.cpp -o hello
当然,本实例中,在最顶层的CMakeLists.txt
添加以下语句:
add_definitions("-Wall -g")
代码内容
接下来看一下主代码的内容,即example_person.cpp
:
#include <iostream>
#include "General_buf_read.h"
#include "General_buf_write.h"
#include "Person.pb.h" namespace PersonProto {class Person;
};namespace GeneralBuf {template <typename T>class GeneralProtoWriter;typedef GeneralProtoWriter<PersonProto::Person> PersonProtoWriter;template <typename T>class GeneralProtoReader;typedef GeneralProtoReader<PersonProto::Person> PersonProtoReader;
};int main(int argc, char const *argv[])
{GeneralBuf::PersonProtoWriter writer;std::string filename = "Person_test.proto";int64_t version = 20191001;writer.startWriter(filename, version);PersonProto::Person *person1 = new PersonProto::Person();person1->set_id(100000);person1->set_name("zhangsan");person1->set_age(20);person1->add_email("123456@qq.com");person1->add_email("234567@qq.com");PersonProto::PhoneNumber *phone1 = person1->add_phone();PersonProto::PhoneNumber *phone2 = person1->add_phone();phone1->set_number("987654");phone1->set_type(PersonProto::PhoneType::MOBILE);phone2->set_number("876543");phone2->set_type(PersonProto::PhoneType::HOME);PersonProto::Address *addr = person1->mutable_address();addr->set_country("china");addr->set_detail("beijing");writer.write(person1);writer.stopWriter();GeneralBuf::PersonProtoReader reader;reader.startReader(filename);std::cout << "version : " << reader.getVersion() << "\n";std::cout << "cnt : " << reader.getFrameCount() << "\n";reader.setFrameIndex(0);PersonProto::Person *person = new PersonProto::Person();reader.read(person);person->PrintDebugString();return 0;
}
使用GDB调试
下面使用GDB
来对生成的可执行文件进行调试,调试命令如下,解释在后面进行了标注:
yngzmiao@yngzmiao-virtual-machine:~/github/protobuf-parser-tool/c++/build$ gdb example_person <--------启动GDB
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from example_person...done.
(gdb) l <---------------list,查看源码
6 namespace PersonProto {
7 class Person;
8 };
9
10 namespace GeneralBuf {
11 template <typename T>
12 class GeneralProtoWriter;
13 typedef GeneralProtoWriter<PersonProto::Person> PersonProtoWriter;
14 template <typename T>
15 class GeneralProtoReader;
(gdb) <---------------直接回车,重复上一条命令
16 typedef GeneralProtoReader<PersonProto::Person> PersonProtoReader;
17 };
18
19 int main(int argc, char const *argv[])
20 {
21 GeneralBuf::PersonProtoWriter writer;
22 std::string filename = "Person_test.proto";
23 int64_t version = 20191001;
24 writer.startWriter(filename, version);
25
(gdb) <---------------直接回车,重复上一条命令
26 PersonProto::Person *person1 = new PersonProto::Person();
27 person1->set_id(100000);
28 person1->set_name("zhangsan");
29 person1->set_age(20);
30
31 person1->add_email("123456@qq.com");
32 person1->add_email("234567@qq.com");
33 PersonProto::PhoneNumber *phone1 = person1->add_phone();
34 PersonProto::PhoneNumber *phone2 = person1->add_phone();
35 phone1->set_number("987654");
(gdb) <---------------直接回车,重复上一条命令
36 phone1->set_type(PersonProto::PhoneType::MOBILE);
37 phone2->set_number("876543");
38 phone2->set_type(PersonProto::PhoneType::HOME);
39
40 PersonProto::Address *addr = person1->mutable_address();
41 addr->set_country("china");
42 addr->set_detail("beijing");
43
44 writer.write(person1);
45 writer.stopWriter();
(gdb) <---------------直接回车,重复上一条命令
46
47 GeneralBuf::PersonProtoReader reader;
48 reader.startReader(filename);
49
50 std::cout << "version : " << reader.getVersion() << "\n";
51 std::cout << "cnt : " << reader.getFrameCount() << "\n";
52 reader.setFrameIndex(0);
53 PersonProto::Person *person = new PersonProto::Person();
54 reader.read(person);
55 person->PrintDebugString();
(gdb) <---------------直接回车,重复上一条命令
56
57 return 0;
58 }
(gdb) b 44 <---------------break,设置断点
Breakpoint 1 at 0x40dd2d: file /home/yngzmiao/github/protobuf-parser-tool/c++/example_person.cpp, line 44.
(gdb) b 55 <---------------break,设置断点
Breakpoint 2 at 0x40de34: file /home/yngzmiao/github/protobuf-parser-tool/c++/example_person.cpp, line 55.
(gdb) i b <---------------info break,查看断点信息
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040dd2d in main(int, char const**) at /home/yngzmiao/github/protobuf-parser-tool/c++/example_person.cpp:44
2 breakpoint keep y 0x000000000040de34 in main(int, char const**) at /home/yngzmiao/github/protobuf-parser-tool/c++/example_person.cpp:55
(gdb) r <---------------run,运行程序,在断点处停止
Starting program: /home/yngzmiao/github/protobuf-parser-tool/c++/build/example_person
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".Breakpoint 1, main (argc=1, argv=0x7fffffffdc88) at /home/yngzmiao/github/protobuf-parser-tool/c++/example_person.cpp:44
44 writer.write(person1);
(gdb) p person1 <---------------print,打印
$1 = (PersonProto::Person *) 0x6375d0
(gdb) p *person1 <---------------print,打印
$2 = {<google::protobuf::Message> = {<No data fields>}, static kIdFieldNumber = 1, static kNameFieldNumber = 2, static kAgeFieldNumber = 3, static kEmailFieldNumber = 4, static kPhoneFieldNumber = 5, static kAddressFieldNumber = 6, _unknown_fields_ = {fields_ = 0x0}, _has_bits_ = {39}, _cached_size_ = 0, name_ = 0x636fd0, id_ = 100000, age_ = 20, email_ = {<google::protobuf::internal::RepeatedPtrFieldBase> = {static kInitialSize = 0, elements_ = 0x636830, current_size_ = 2, allocated_size_ = 2, total_size_ = 4}, <No data fields>}, phone_ = {<google::protobuf::internal::RepeatedPtrFieldBase> = {static kInitialSize = 0, elements_ = 0x634180, current_size_ = 2, allocated_size_ = 2, total_size_ = 4}, <No data fields>}, address_ = 0x631f60, static default_instance_ = 0x6324c0}
(gdb) p *(PersonProto::Person *) 0x6375d0 <---------------print,打印
$3 = {<google::protobuf::Message> = {<No data fields>}, static kIdFieldNumber = 1, static kNameFieldNumber = 2, static kAgeFieldNumber = 3, static kEmailFieldNumber = 4, static kPhoneFieldNumber = 5, static kAddressFieldNumber = 6, _unknown_fields_ = {fields_ = 0x0}, _has_bits_ = {39}, _cached_size_ = 0, name_ = 0x636fd0, id_ = 100000, age_ = 20, email_ = {<google::protobuf::internal::RepeatedPtrFieldBase> = {static kInitialSize = 0, elements_ = 0x636830, current_size_ = 2, allocated_size_ = 2, total_size_ = 4}, <No data fields>}, phone_ = {<google::protobuf::internal::RepeatedPtrFieldBase> = {static kInitialSize = 0, elements_ = 0x634180, current_size_ = 2, allocated_size_ = 2, total_size_ = 4}, <No data fields>}, address_ = 0x631f60, static default_instance_ = 0x6324c0}
(gdb) p person1-> <---------------tab tab,两次tab,代码补全功能
ByteSize SharedCtor clear_email has_address mutable_name set_email
Clear SharedDtor clear_has_address has_age mutable_phone set_has_address
CopyFrom Swap clear_has_age has_id mutable_unknown_fields set_has_age
GetCachedSize _cached_size_ clear_has_id has_name name set_has_id
GetMetadata _has_bits_ clear_has_name id name_ set_has_name
InitAsDefaultInstance _unknown_fields_ clear_id id_ operator= set_id
IsInitialized add_email clear_name kAddressFieldNumber phone set_name
MergeFrom add_phone clear_phone kAgeFieldNumber phone_ unknown_fields
MergePartialFromCodedStream address default_instance kEmailFieldNumber phone_size ~Person
New address_ default_instance_ kIdFieldNumber release_address
Person age descriptor kNameFieldNumber release_name
SerializeWithCachedSizes age_ email kPhoneFieldNumber set_age
SerializeWithCachedSizesToArray clear_address email_ mutable_address set_allocated_address
SetCachedSize clear_age email_size mutable_email set_allocated_name
(gdb) p person1->ByteSize() <---------------print,打印
$4 = 88
(gdb) n <---------------next,单条语句执行
45 writer.stopWriter();
(gdb) n <---------------next,单条语句执行
47 GeneralBuf::PersonProtoReader reader;
(gdb) n <---------------next,单条语句执行
48 reader.startReader(filename);
(gdb) c <---------------continue,继续运行程序,下一个断点处停止
Continuing.
version : 20191001
cnt : 1Breakpoint 2, main (argc=1, argv=0x7fffffffdc88) at /home/yngzmiao/github/protobuf-parser-tool/c++/example_person.cpp:55
55 person->PrintDebugString();
(gdb) c <---------------continue,继续运行程序,下一个断点处停止
Continuing.
id: 100000
name: "zhangsan"
age: 20
email: "123456@qq.com"
email: "234567@qq.com"
phone {number: "987654"type: MOBILE
}
phone {number: "876543"type: HOME
}
address {country: "china"detail: "beijing"
}
[Inferior 1 (process 3734) exited normally]
(gdb) q <---------------quit,退出GDB
yngzmiao@yngzmiao-virtual-machine:~/github/protobuf-parser-tool/c++/build$
最基本的GDB命令
上文使用的是最基本的GDB
命令,下面进行总结:
命令 | 全称 | 解释 |
---|---|---|
l | list | 查看源码 |
b | break | 设置断点 |
r | run | 运行程序,在断点处停止 |
n | next | 单条语句执行 |
c | continue | 继续运行程序,下一个断点处停止 |
p | 打印 | |
q | quit | 退出GDB |
其他的GDB命令,会在后面的博文中进行介绍。
【GDB】手把手教你用gdb调试程序(超清晰流程)相关推荐
- 华为语音解锁设置_华为手机免费语音转文字功能如何开启?手把手教你如何设置,超赞...
原标题:华为手机免费语音转文字功能如何开启?手把手教你如何设置,超赞 关于华为手机免费语音转文字功能,相信你也有所了解,但还有很大部份华为手机用户表示:我的手机为什么没有语音转文字的功能. 如果你是华 ...
- 手把手教你做第一个RPA机器人流程
手把手教你做第一个RPA机器人流程 第一步:下载&安装RPA工具 第二步:新建第一个自动化流程 第三步:开始详细配置流程 简单介绍一下艺赛旗RPA界面 开始流程配置 第四步:总结 第一步:下载 ...
- 小羊手把手教你gcc gdb makefile
1. vim编辑hello.c 2. 分别查看下面gcc指令的结果 GCC交叉编译器简介: 最早为GNU C Compiler是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作之一; 支 ...
- 手把手教你运行YOLOv6(超详细)
YOLOv6 是美团视觉智能部研发的一款目标检测框架,致力于工业应用.本框架同时专注于检测的精度和推理效率,在工业界常用的尺寸模型中:YOLOv6-nano 在 COCO 上精度可达 35.0% AP ...
- 实战案例,手把手教你使用 Tableau 绘制超炫酷可视化图表
有一种美叫数据的美,Tableau可以让你看到这种数据美,以及探索数据美的可能,如下图表均是由强大的tableau可视化而成的. 喜欢点赞.收藏 使用tableau的优势就在于不需要懂技术,更不需要写 ...
- 手把手教你下载VS2022(超详细)
目录 一.下载 二.安装配置 一.下载 来到下载网址后,我们如下图所示点击Community 2022下载即可,是社区免费版. VS2022下载链接 (去官网下载即可哦,不需要去某些需要收费的网站,就 ...
- 【换脸详细教程】手把手教你进行AI换脸:换脸流程及源码详解
目录 1. 换脸基本原理 2 人脸检测及可视化 3. 人脸轮廓点检测及可视化 4. 人脸图像变换--仿射变换 5. 生成遮罩并直接替换人脸 6. 人脸颜色校正 最近AI换脸貌似比较火爆,就稍微研究了一 ...
- 手把手教你用dlv和gdb调试GoLang
码字不易,转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加QQ群:909211071 无论哪种方式,都要配置证书相关,参考这篇文章:在Mac安装最新gdb的详细教程,含可能遇到的所有坑(网上最新教程 ...
- python numpy安装教程_手把手教你搭建机器学习开发环境—Python与NumPy的超简安装教程...
手把手教你搭建机器学习开发环境Python语言是机器学习的基础,所以,想要入门机器学习,配置好Python的开发环境是第一步.本文就手把手的教你配置好基于Python的机器学习开发环境.超简单!第一步 ...
最新文章
- 主成分分析(PCA)Python代码实现
- 排序算法 时间复杂度+空间复杂度 总结
- 结构风险和经验风险是什么?怎么去平衡它们?
- mysql 开仓函数_MySQL函数大全 及用法示例
- mysql源码添加一个命令,MySQL ALTER命令
- Python selenium巧用Javascript脚本注入解决按钮点选问题
- ArcGIS Desktop 10.5 安装实录
- idea中mapper.xml的头文件配置
- 国内外大数据经典案例研究
- 洛谷P2757 [国家集训队]等差子序列
- 常用大数据核心技术有哪些?
- SCP不会覆盖已有文件
- mysql lob字段_数据库的LOB大字段的一些总结
- 全球与中国网络连接视频门铃对讲机系统市场深度研究分析报告势
- 用Python实现表白代码 抖音最火的整蛊表白小程序如何做出来的
- 2009年经典语录雷人总汇
- 【SLAM】视觉SLAM:一直在入门,从未到精通
- 2016中国IT用户满意度总体保持平稳
- [NOTE in progress] Simulation Optimization
- Android Native程序crash的一些定位方法简介
热门文章
- 共享移动智能办公入口 钉钉10亿加速企业数字化和智能化
- 最新ie图标变灰css,网站变灰的CSS代码(兼容火狐、Chrome、IE系浏览器)——w3cdream|前端学习-开发...
- python新手怎么兼职-学完python怎么找兼职呢?
- 网页添加Live2D,背景线条动漫人物
- 聊聊大数据(一)——大数据的存储
- 弹性盒子模型属性之flex-grow
- UML-----uml建模的分类
- CF1369D TediousLee 翻译
- linux探测路由器重启,openwrt命令实现网络不通,自动重启路由器,重新拨号或者重启wifi...
- QQ聊天 QQ流应该注意的问题