GDB调试学习

C语言HelloWorld

编辑源程序

#include <stdio.h>

int main(int argc,char **argv){
	printf("Hello World\n");
	return 0;
}

gcc编译,链接

gcc -o helloworld helloworld.c
./helloworld

g++ 编译,链接

gcc -o helloworld helloworld.c
./helloworld

C++语言HelloWorld程序

编辑源程序

#include <iostream>
using namespace std;

int main(int argc,char **argv)
{
    cout<<"Hello World C++"<<endl;
    return 0;
}

g++编译,链接

g++ -o helloworldplus helloworldplus.cpp
./helloworldplus

gcc编译,链接

#提示错误
gcc -o helloworldplus helloworldplus.cpp
gcc -o helloworldplus helloworldplus.cpp -lstdc++
./helloworldplus

通用Makefile

#定义了一个变量 EXECUTABLE,它的值是 chapter_3。这个变量表示最终生成的可执行文件的名称。
EXECUTABLE:= chapter_3
#定义了一个变量 LIBDIR,它没有赋值,因此为空。这个变量通常用来指定库文件的目录。
LIBDIR:= 
#定义了一个变量 LIBS,它没有赋值,因此为空。这个变量通常用来指定需要链接的库文件。
LIBS:= 
#定义了一个变量 INCLUDES,它的值是 .。这个变量通常用来指定包含头文件的目录。
INCLUDES:=. 
#定义了一个变量 SRCDIR,它没有赋值,因此为空。这个变量通常用来指定源代码文件的目录。
SRCDIR:= 

#定义了一个变量 CC,它的值是 g++。这个变量表示用于编译C++代码的编译器。
CC:=g++
#定义了一个变量 CFLAGS,它包含了一些编译器选项,如 -g(生成调试信息)、-Wall(启用警告信息)、-O0(不进行优化)以及一些静态链接选项。
CFLAGS:= -g -Wall -O0 -static -static-libgcc -static-libstdc++
#定义了一个变量 CPPFLAGS,它的值等于 CFLAGS 的值。这个变量通常用来存放C++编译器的选项。
CPPFLAGS:= $(CFLAGS)
#将 -I 选项加入到 CPPFLAGS 变量中,用于指定头文件的搜索路径。
CPPFLAGS+= $(addprefix -I,$(INCLUDES)) 
#将当前目录(.)也加入到 CPPFLAGS 变量中,用于头文件的搜索路径。
CPPFLAGS+=-I.
#将 -MMD 选项加入到 CPPFLAGS 变量中,这个选项告诉编译器生成依赖关系文件(.d 文件)。
CPPFLAGS+=-MMD 

#定义了一个变量 RM-F,它的值是 rm -f。这个变量通常用来删除文件,-f 选项表示强制删除而不提示。
RM-F:=rm -f 

#使用 wildcard 函数查找当前目录下所有的 .cpp 文件,并将它们赋值给变量 SRCS。同时,也查找 SRCDIR 目录下的所有 .cpp 文件。
SRCS:=$(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
#使用 patsubst 函数将 SRCS 中的每个 .cpp 文件替换为对应的 .o 文件,并将结果赋值给变量 OBJS。这些 .o 文件是编译后的目标文件。
OBJS:= $(patsubst %.cpp,%.o, $(SRCS))
#使用 patsubst 函数将 OBJS 中的每个 .o 文件替换为对应的 .d 文件,并将结果赋值给变量 DEPS。这些 .d 文件包含了依赖关系信息。
DEPS:= $(patsubst %.o,%.d,$(OBJS)) 
#使用 wildcard 函数查找所有 .d 文件,然后使用 filter-out 函数找出缺失的依赖关系文件,并将结果赋值给变量 MISSING_DEPS。
MISSING_DEPS:= $(filter-out $(wildcard $(DEPS)), $(DEPS)) 
#使用 patsubst 函数将 MISSING_DEPS 中的每个 .d 文件替换为对应的 .cpp 文件,并使用 wildcard 函数查找这些缺失的源代码文件,并将结果赋值给变量 MISSING_DEPS_SOURCES。
MISSING_DEPS_SOURCES:= $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS))) )

#声明了四个伪目标,它们不代表实际的文件,而是用于执行特定任务的标记。这些目标分别是 all、deps、objs、clean。
.PHONY: all deps objs clean 
#定义了一个 all 目标,它依赖于 $(EXECUTABLE),表示要构建 $(EXECUTABLE) 这个可执行文件。
all:$(EXECUTABLE)
#定义了一个 deps 目标,它依赖于 $(DEPS),表示要生成依赖关系文件。
deps:$(DEPS) 
#定义了一个 objs 目标,它依赖于 $(OBJS),表示要编译生成目标文件。
objs:$(OBJS) 
#定义了一个 clean 目标,用于删除生成的 .o 文件和 .d 文件。
clean: 
    @$(RM-F)  *.c
    @$(RM-F)    *.d

#这是一个条件判断,如果 MISSING_DEPS 不为空(即存在缺失的依赖关系文件),则执行下面的命令。
ifneq ($(MISSING_DEPS),) 
#这个规则用于删除缺失的依赖关系文件对应的 .o 文件。
$(MISSING_DEPS): 
		@$(RM-F) $(patsubst %.d,%.o,$e) 
endif
#使用 -include 命令包含所有的 .d 文件,这些文件包含了源文件的依赖关系。
-include $(DEPS) 
$(EXECUTABLE):$(OBJS) 
	$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$ (LIBS)) 

gdb使用

chapter_3.3.cpp

#include <malloc.h>
#include <string.h>
#include <thread>
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
struct NODE
{
	int  ID;
	char Name[40];
	int age;
	NODE* prev;
	NODE *next;
};
struct NODE *node_head = NULL;
int member_id = 0;
void add_member()
{
	struct NODE *new_node = (NODE*)malloc(sizeof(NODE));
	new_node->next = NULL;
	NODE* prev_node = node_head->prev;
	if(prev_node)
	{
		prev_node->next = new_node;
		new_node->prev = prev_node;
		node_head->prev = new_node;

	}
	else
	{
		node_head->next = new_node;
		new_node->prev = node_head;
		node_head->prev = new_node;
	}
	new_node->ID = member_id++;
	printf("请输入会员姓名,然后按回车\n");
	scanf("%s",new_node->Name);
	printf("请输入会员年龄,然后按回车\n");
	scanf("%d",&new_node->age);

	printf("添加新会员成功\n");

}
class test_1
{
public:
	test_1(){x=10;y=100;}
	virtual ~test_1(){}
	virtual void test_fun()
	{
		printf("test_1 test_fun\n");
	}
private:
	int x;
	int y;
	
};
class test_2:public test_1
{
public:
	test_2(){}
	virtual ~test_2(){}
	virtual void test_fun2()
	{
		printf("test_fun2\n");
	}
	virtual void test_fun()
	{
		printf("test_2 test_fun\n");
	}

};
void test_fun(int i)
{
	printf("i is %d\n",i);
}
void test_fun(const char* str)
{
	printf("str is %s\n",str);
}
void test_fun_x()
{
	printf("test fun x\n");
}
void test_loop()
{
	for(int i=0;i<1000;i++)
	{
		printf("i is %d\n",i);
	}
	printf("exit the loop\n");
}

void cond_fun_test(int a,const char *str)
{
	int x = a * a;
	printf("a is %d,x is %d,str is %s\n",a,x,str);
	x *=2;
	printf("quit fun\n");
}
void print_arr_test()
{
	int iarr[]={0,1,2,3,4,5,6,7,8,9};
	const char *strarr[]={"this","is","a","test","string"};
	for(unsigned long i=0;i<sizeof(iarr)/sizeof(int);i++)
	{
		printf("%d ",iarr[i]);
	}
	for(int i=0;i<5;i++)
	{
		printf("%s ",strarr[i]);
	}
	printf("arr test done\n");
}
class test_3
{
	int x;
	int y;
	void test()
	{
	}
};
struct TEST_NODE
{
	char gender[3];
	int ID;
	char name[7];

};
void test_memory()
{
	const char* str = "test";
	int number = 0x12345678;
	TEST_NODE *node = new TEST_NODE;
	node->ID = 100;
	strcpy(node->gender,"男");
	strcpy(node->name,"海洋");
	
	printf("str is %s,number is %d,node id is %d,test end\n",str,number,node->ID);
	delete node;
}
int call_fun_test_2(int level,const char* str)
{
	int number = 102;
	const char *name = "call_fun_test_2";
	printf("level is %d,str is %s,name is %s\n",level,str,name);
	return 2;

}
int call_fun_test_1(int level,const char* str)
{
	int number = 101;
	const char* name = "call_fun_test_1";
	printf("level is %d,str is %s,name is %s\n",level,str,name);
	call_fun_test_2(level + 1,"call_fun_test_2");
	return 1;
}
int count = 0;
void do_work(void *arg)
{
    std::cout << "线程函数开始"<< std::endl;
    //模拟做一些事情
    int local_data = count;
    count++;
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout << "线程函数结束" << std::endl;
}
int start_threads(int thread_num)
{
    std::vector<std::thread> threads;
    //启动10个线程
    for (int i = 0; i < thread_num; ++i)
    {
        threads.push_back(std::thread(do_work,&i));
        std::cout << "启动新线程:" << i << std::endl;
    }
    //等待所有线程结束
    for (auto& thread : threads)
    {
        thread.join();
    }
}
void test_throw(int number)
{
        int local_data = number;
        const char* name = "test throw";
        printf("name is %s,%d\n",name,local_data);
        throw "test exception";
}
void test_try_catch(int number)
{
        int local_data = number;
        const char* name = "test_try_catch";
        printf("name is %s,%d\n",name,local_data);
        try
        {
		int throw_num = 50;
		printf("throw\n");
                throw 10;
        }
        catch(...)
        {
		int catch_num = 100;
                printf("catch ...\n");
        }

}

int main(int argc,char* argv[])
{
	test_1 *t1 = NULL;
	test_3 t3;
	test_try_catch(10);
	start_threads(10);
	int number = 100;
	const char* name ="main";
	call_fun_test_1(1,"call_fun_test_1");
	test_memory();
	print_arr_test();
	//assert(t1 != NULL);
	cond_fun_test(10,"test");
	//test_loop();
	
	
	for(int i=0;i<10;i++)
	{
		printf("execute test_fun_x\n");
		test_fun_x();
	}
	
	test_fun(10);
	test_fun("test");
	test_1 *test = new test_1();
	test->test_fun();
	test_1 *test2 = new test_2();
	test2->test_fun();
	test_2 test3;
	printf("传入的参数信息为:\n");
	for(int i=0;i<argc;i++)
	{
		printf("参数 %d=%s\n",i,argv[i]);
	}
	node_head = (struct NODE*)malloc(sizeof(NODE));
	node_head->next = node_head->prev= NULL;
	printf("会员管理系统\n1:录入会员信息\nq:退出\n");
	while(true)
	{
		switch(getchar())
		{
		case '1':
			add_member();
			break;
		case 'q':
			return 0;
		default:
			break;
		}
	}	
	return 0;
}

Makefile

EXECUTABLE:= chapter_3.3
LIBDIR:=
LIBS:=pthread
INCLUDES:=.
SRCDIR:=

CC:=g++
CFLAGS:= -g -Wall -O0 -static -static-libgcc -static-libstdc++ 
CPPFLAGS:= $(CFLAGS)
CPPFLAGS+= $(addprefix -I,$(INCLUDES))
CPPFLAGS+= -I.
CPPFLAGS+= -MMD

RM-F:= rm -f

SRCS:= $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS:= $(patsubst %.cpp,%.o,$(SRCS))
DEPS:= $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS:= $(filter-out $(wildcard $(DEPS)),$(DEPS))
#MISSING_DEPS_SOURCES:= $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))


.PHONY : all deps objs clean
all:$(EXECUTABLE)
deps:$(DEPS)

objs:$(OBJS)
clean:
	@$(RM-F) *.o
	@$(RM-F) *.d

ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS):
	@$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
	$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))

启动gdb

make
gdb chapter_3.3
root@hecs-270451192.168.0.179 16:37:50 [pwd:~/test]# gdb test
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-16.el8
Copyright (C) 2018 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-redhat-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 test...done.
#成功加载
(gdb) list
198                     int throw_num = 50;
199                     printf("throw\n");
200                     throw 10;
201             }
202             catch(...)
203             {
204                     int catch_num = 100;
205                     printf("catch ...\n");
206             }
207
(gdb) quit
r #启动程序
q #退出程序
q #退出gdby

启动调试并添加参数

gdb dmserver 
set args /home/dmdba/dmdbms/data/DMDB/dm.ini
r
(gdb) r
Starting program: /home/dmdba/dmdbms/bin/dmserver /home/dmdba/dmdbms/data/DMDB/dm.ini
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-164.el8.x86_64
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
file dm.key not found, use default license!
[Detaching after fork from child process 2515887]
version info: develop
[New Thread 0x7fffe757a700 (LWP 2515888)]
[Detaching after fork from child process 2515889]
DM Database Server 64 V8 03134284058-20230621-193718-20046 startup...
Normal of FAST
Normal of DEFAULT
Normal of RECYCLE
Normal of KEEP
Normal of ROLL
[New Thread 0x7fffa4703700 (LWP 2515890)]
[New Thread 0x7fffa161f700 (LWP 2515891)]
[New Thread 0x7fffa151e700 (LWP 2515892)]
[New Thread 0x7fffa141d700 (LWP 2515893)]
[New Thread 0x7fffa131c700 (LWP 2515894)]
Database mode = 0, oguid = 15324133
[New Thread 0x7fffa121b700 (LWP 2515895)]
License will expire on 2024-06-21
[New Thread 0x7fff9819e700 (LWP 2515896)]
[New Thread 0x7fff881e0700 (LWP 2515897)]
[New Thread 0x7fff78aee700 (LWP 2515898)]
[New Thread 0x7fff789ed700 (LWP 2515899)]

附加到进程

ps -ef|grep dms
gdb attach pid

常用命令

#查看源码 
list
#显示调用栈信息
backtrace
#查看信息
info threads

#设置日志
set logging on
set logging off
show logging
set logging file coredump.c