大家好,欢迎来到IT知识分享网。
实例
我以自己曾经写的一段实际代码为例,来讲解究竟该怎么进行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 : 1
Breakpoint 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命令,会在后面的博文中进行介绍。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/14833.html