MyGdb(一) — 加载被调试程序

/ 0评 / 0

调试器加载被调试程序

1 程序可调试状态

从调试器的视角来看,正在运行的程序可以分为两类,一类是正常运行的,不受调试器干扰的程序。另一类是处于调试状态的程序,它的每一步运行都在调试器的掌控之下。

让程序处于调试状态大有2种方式,一种是静态加载,即由调试器来启动程序,告知系统,这个程序将要被调试。
第二种是动态加载,即程序正在运行,调试器通过一些系统调用来迫使使得程序处于调试状态。

1.2 gdb 加载被调试程序操作

1) 静态加载,由gdb来启动被调试程序,这种方式常常用在程序还在开发的过程中。

1
#gdb ./a.out

2) 动态加载,使用gdb attach子命令 + 调试程序的进程号(每个正在运行的程序在系统中都有一个唯一的标号标识)
假设要调试程序的进程号为 2333 ,则可以使用如下命令进行操作.

1
2
#gdb
(gdb) attach 2333

2 MyGdb 实现应用程序代码

Ptrace 暂时就不在这里介绍了,大家可以去看下本博客转载的”玩转ptrace“系列文章。
玩转ptrace(一)“,”玩转ptrace(二)“.

2.1 MyGdb静态加载应用程序

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/* inferior.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ptrace.h>
 
int mygdb_inferior(char *program, char **allargs)
{
	int pid = fork();
 
	if (pid < 0)
		return pid;
 
	if (pid == 0) {
		ptrace(PTRACE_TRACEME, 0, 0, 0);
 
		setpgid(0, 0);
 
		execv(program, allargs);
		if (errno == ENOENT)
			execvp(program, allargs);
 
		fprintf(stderr, "Cannot exec %s: %s.\n", program,
				strerror(errno));
		fflush(stderr);
		exit(0177);
	}
 
	return pid;
}
 
int mygdb_attach(unsigned long pid)
{
	if (ptrace(PTRACE_ATTACH, pid, 0, 0) != 0) {
		/* If we fail to attach to a process, report an error. */
		error("Cannot attach to process %ld: %s (%d)\n", pid,
				strerror(errno), errno);
		return -1;
	}
 
	return 0;
}
 
int mygdb_continue(unsigned long pid)
{
	if (ptrace(PTRACE_CONT, pid, NULL, NULL) != 0) {
		/* If we fail to continue to a process, report an error. */
		error("Cannot continue process %ld: %s (%d)\n", pid,
				strerror(errno), errno);
		return -1;
	}
 
	return 0;
}
 
int main(int argc, char *argv[])
{
	pid_t child;
	if (argc <= 1) {
		printf("Usage: ./inferior your_programme\r\n");
		printf("Example: ./inferior ./a.out\r\n");
		exit(0);
	}
 
	child = mygdb_inferior(argv[1], NULL);
 
	if (child < 0) {
		error("mygdb_inferior: fork error.\r\n");
		exit(0);
	}
 
	printf("inferior process success.\r\n");
 
	printf("will run process after sleep 10s.\r\n");
	sleep(10);
 
	if (mygdb_continue(child) != -1)
		printf("run process.\r\n");
 
	return 0;
}

将上诉代码保存到本地文件,并取名为inferior.c,使用如下命令编译程序:

1
gcc inferior.c  -o inferior

2.2 MyGdb动态加载应用程序

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
/* attach.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ptrace.h>
 
int mygdb_attach(unsigned long pid)
{
	if (ptrace(PTRACE_ATTACH, pid, 0, 0) != 0) {
		/* If we fail to attach to a process, report an error. */
		error("Cannot attach to process %ld: %s (%d)\n", pid,
				strerror(errno), errno);
		return -1;
	}
 
	return 0;
}
 
int mygdb_continue(unsigned long pid)
{
	if (ptrace(PTRACE_CONT, pid, NULL, NULL) != 0) {
		/* If we fail to continue to a process, report an error. */
		error("Cannot continue process %ld: %s (%d)\n", pid,
				strerror(errno), errno);
		return -1;
	}
 
	return 0;
}
 
int main(int argc, char *argv[])
{
	int pid = 0;
 
	if (argc <= 1) {
		printf("Usage: ./attach pid_number\r\n");
		printf("Example: ./attach 1111\r\n");
		exit(0);
	}
 
	/* get the pid number from arg2 */
	pid = strtoul(argv[1], NULL, 0);
 
	if (pid <= 0) {
		printf("please input the valid pid number.\r\n");
		exit(0);
	}
 
	if (mygdb_attach(pid) == -1)
		exit(0);
 
	printf("attach process success.\r\n");
 
	printf("will reusme process after sleep 10s.\r\n");
	sleep(10);
 
	if (mygdb_continue(pid) != -1)
		printf("reusme process.\r\n");
 
	return 0;
}

将上诉代码保存到本地文件,并取名为attach.c,使用如下命令编译程序:

1
gcc attach.c  -o attach

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据