Chinaunix首页 | 论坛 | 博客
  • 博客访问: 351504
  • 博文数量: 83
  • 博客积分: 5322
  • 博客等级: 中校
  • 技术积分: 1057
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-11 11:27
个人简介

爱生活,爱阅读

文章分类

全部博文(83)

文章存档

2015年(1)

2013年(1)

2012年(80)

2011年(1)

分类:

2012-09-14 16:21:18

Using GNU's GDB Debugger

Debugging A Running Process

By Peter Jay Salzman

Previous: 

Next: Debugging Ncurses Programs

调试运行中的进程

So far, we've debugged executables, with and without core files. However, we can debug processes too. Think about that -- we can debug a process that has already been started outside the debugger. There are two ways of doing this: Using command line arguments and using the attach command.

到目前为止,我们已经调试了带有或者未带有核文件(core file)的可执行程序。然而,我们也可以调试进程。考虑一下这种情况----我们调试一个在调试器外部已经被启动的进程。有两种方式可以做到:使用命令行参数以及使用attach命令。

Download and read  and its . Compile it, and run it as a background job in one console (or xterm). It'll simply print out the number of bottles of beer on the wall:

下载并阅读beer-process.c和其makefile文件。编译之,在控制台上以后台作业的方式运行之。它将简单的打印出墙上的啤酒数:

   $ ./beer-process &

   [1] 17399

   p@satan$ 100000 bottles of beer on the wall.

   99999 bottles of beer on the wall.

   99998 bottles of beer on the wall.

   99997 bottles of beer on the wall.

使用命令行参数

With the beer process running one console, start GDB in another console with an argument list of the executable and the process ID. The process ID should've been printed when you started the background process:

当啤酒进程在控制台运行时,在另一个控制台上启动GDB,并指定其参数列表:可执行程序名及进程ID。进程ID就是当你启动后台进程时打印出来的ID:

   $ gdb beer-process 17399

   Attaching to program: code/running_process/beer-process, process 17399

   0x410c64fb in nanosleep () from /lib/tls/libc.so.6

   (gdb)

Chances are overwhelmingly good that the process is in GoToSleep(). Print out a backtrace and take a look at the stack:

机会非常好,因为该进程正处于GoToSleep()中。输入backtrace并查看栈的内容:

   (gdb) bt

   #0  0x410c64fb in nanosleep () from /lib/tls/libc.so.6

   #1  0x410c6358 in sleep () from /lib/tls/libc.so.6

   #2  0x0804841f in GoToSleep () at beer-process.c:32

   #3  0x080483e0 in main () at beer-process.c:14

Aside: Note that GoToSleep() calls the C library function sleep(), and sleep(), in turn, calls the system call nanosleep(). As you know, all library functions (glibc on Linux) do their job by calling system calls. I'm a little surprised to see the library and system functions listed in the call stack since I'm not using a debugging version of glibc. Weird.

题外话:注意GoToSleep()函数调用C库函数sleep(),而sleep()依次调用系统调用nanosleep()。正如你知道的那样,所有的库函数是通过调用系统调用工作的。在调用栈上,我惊讶地看到了库与系统函数列表。而我并没有采用调试版本的glibc。奇怪。

At this point, the backtrace should be very familiar to you. But there's an important distinction. We didn't run this program from within GDB. We ran it from the command line, and then had GDB attach to an already running process.

此时,你对backtrace应该非常熟悉。但是这里有一个重要的区别。我们并不是通过GDB调用该进程的,我们是通过命令行的方式将GDB同已经运行的进程连接起来。

Look at the output of the beer process: you should notice that the process has stopped! Whenever GDB attaches to a running process, the process is paused so you can get a handle on what the call stack looks like. Let's do some interesting things.

查看“啤酒进程(beer process)”的输出:你应该发现该进程已经停止了!无论何时,当GDB连接到了运行的进程,进程将停止,这样你就可以查看调用栈的样子。让我们做一些有趣的事情吧。

In my output above, i=9997. Yours is probably different, but nevertheless, you should be able to follow along with me. Let's verify the value of i by selecting the stack frame for main() and looking at its value:

在我上面的输出中,i=9997。你的可能不同,但是没有关系,你应该能够跟上我。让我们通过选择main()的栈帧来确认并查看i的值:

   (gdb) frame 3

   #3  0x080483eb in main () at beer-process.c:15

   15                      GoToSleep();

   (gdb) print i

   $1 = 99997

No surprises here. As you'd expect, we can use next and step (which takes us out of nanosleep() and sleep() respectively, putting us into GoToSleep()):

没有什么奇怪的。正如你所期待的,我们可以使用next step命令(这将使我们分别跳出nanosleep()和sleep()并进入到GoToSleep()中):

   (gdb) next

   Single stepping until exit from function nanosleep,

   which has no line number information.

   0x410c6358 in sleep () from /lib/tls/libc.so.6

   (gdb) step

   Single stepping until exit from function sleep,

   which has no line number information.

   GoToSleep () at beer-process.c:34

   34      }

   (gdb) bt

   #0  GoToSleep () at beer-process.c:34

   #1  0x080483eb in main () at beer-process.c:15

Looking at the code, the next things to happen are that i will be decremented and then will print bottles of beer on the wall. However, suppose we wanted more beer? Let's change to the stack frame for main() (where i lives) and change the number of beers on the wall.

查看代码,下一步将要发生的事情是i将减少,之后,函数PrintMessage()将打印“99996 bottles of beer on the wall”。然而,假设我们想要更多的啤酒呢?让我们改变main()的栈帧,并改变墙上啤酒的数目。

 (gdb) frame 3  

#3  0x080483eb in main () at beer-process.c:15

   15                      GoToSleep();

   (gdb) set var i = 99999999

Now quit GDB. When GDB detaches from the process, the process will continue along its merry way. We could also use the detach command to detach from the process without quiting GDB; I'll explain detach in the next session.

现在退出GDB。当GDB退出进程,则进程将继续愉快的执行。我们也可以不用退出GDB,只要执行detach命令即可;我将在下面的部分中解释detach命令。

   (gdb) quit

   The program is running.  Quit anyway (and detach it)? (y or n) y

   Detaching from program: code/running_process/beer-process,

   process 17399

but with the new value for i:

但是i的值已经是新的值了:

   $ ./beer-process &

   [1] 17399

   p@satan$ 100000 bottles of beer on the wall.

   99999 bottles of beer on the wall.

   99998 bottles of beer on the wall.

   99997 bottles of beer on the wall.

   99999998 bottles of beer on the wall.

   99999997 bottles of beer on the wall.

   99999996 bottles of beer on the wall.

   99999995 bottles of beer on the wall.

   99999994 bottles of beer on the wall.

I hope you're impressed by this! We attached GDB to a process that was already running. The process halted and we were able to do everything that we would've been able to do had we started the process from within GDB. Now that's power!

我希望你能对此印象深刻!我们将GDB连接上一个正在运行的进程。进程暂停,我们可以做任何就像通过GDB启动该进程时我们能做的事情。这就是其强大功能!

One non-debugging use I've had for this in the past is with scientific programming. I had PDE solvers and Monte Carlo applications that would run for a very long time. Whenever I wanted to take a look at how my simulation was doing or what some of the intermediary answers looked like, I'd attach to the process using GDB and inspect my variables. This was a much better option than simply printing everything of interest out, which could've possibly have taken hundreds of megs of disk space!

在过去,我曾经对一个科学进程使用了GDB的非调试功能(non-debugging use)。我有PED solversMonte Carlo软件,它们需要运行很长时间。无论何时,每当我想查看我的模拟执行了多少,或者中间的结果是什么时,我使用GDB连接该进程,并查看我的变量。这比简单的打印出所有你感兴趣的东西更好的方式,因为这可能会占用你很多磁盘空间。

使用attack命令

We can also debug an already running process using GDB's attach command to attach to a running process. Again, once attached, we can use the detach command to detach from the process.

我们亦可以通过GDBattach命令来调试一个已经运行的进程。一旦连接后,我们可以使用detach命令断开对该进程的连接。

If you quit the running background process from the previous section, restart beer-process in the background. Start GDB with no command line arguments. But use the attach command to attach to the running process.

如果你从前一部分的后台运行进程中退了出来,那么重新在后台运行啤酒进程。不带任何参数启动GDB,使用attach命令连接运行中的进程。

   $ gdb

   (gdb) attach 17399

   Attaching to process 17399

   Reading symbols from code/running_process/beer-process...done.

   0x410c64fb in nanosleep () from /lib/tls/libc.so.6

   (gdb)

As before, the process should halt. This is when you do whatever it is you want to do with the process: debug, snoop, spy, modify, etc. When you're done futzing around, quit GDB:

同之前一样,该进程暂停。之后,你就可以做任何想对该进程做的事情:调试,探听,spy,更改等。当你完成时,退出GDB

   The program is running.  Quit anyway (and detach it)? (y or n) y

   Detaching from program: code/running_process/beer-process,

   process 17399

As before, once you detach from the process, it'll continue running.

和之前一样,一旦你从该进程断开连接,它将继续运行。

没有调试符号的进程

As with debugging executables and corefiles, it's only convenient to debug processes that were started from executables with debugging information compiled into them. To see this in action, strip the executable and run it in the background again:

说到调试可执行程序与核文件(core file),只有当调试进程中被编译进调试信息时,调试才会很方便。让我们实际看一看从可执行程序中剥离符号表之后,在后台再次运行它:

   $ strip beer-process

   $ ./beer-process  &

   [1] 32262

   p@satan$ 100000 bottles of beer on the wall.

   99999 bottles of beer on the wall.

   99998 bottles of beer on the wall.

Debug the process and look at the call stack:

调试该进程并查看调用栈:

   $ gdb

   (gdb) attach 32262

   Attaching to process 32262

   Reading symbols from code/running_process/beer-process...(no debugging symbols found)...done.

   (gdb) bt

   #0  0x410c64fb in nanosleep () from /lib/tls/libc.so.6

   #1  0x410c6358 in sleep () from /lib/tls/libc.so.6

   #2  0x0804841f in ?? ()

   #3  0x00000003 in ?? ()

   #4  0x0001869d in ?? ()

   #5  0xbffff7b8 in ?? ()

   #6  0x080483eb in ?? ()

   #7  0x0001869d in ?? ()

   #8  0x0001869d in ?? ()

   #9  0xbffff844 in ?? ()

   #10 0x4102e7f8 in __libc_start_main () from /lib/tls/libc.so.6

   #11 0x41150fcc in ?? () from /lib/tls/libc.so.6

Exercises

练习

1.   Suppose you're playing a game that you have source code for, like Doom, Nethack, or Duke Nukem 3D. How can you use GDB to cheat, like giving yourself extra health? If you wrote your own game, can you protect the integrity of networked games from people who would cheat like this? What kinds of things could you do?

假设你正在玩一个游戏,而你有这部游戏的源代码。例如Doom, Nethack,或者Duke Nuken 3D。你怎样利用GDB来进行欺诈呢,比如给你自己很高的健康度?如果你在写你自己的游戏,你能够保护网络游戏的完整度而不让人们作弊么?你可以做些什么事情?

2.   Now suppose you're playing a game for which you do not have the source code. Can you still cheat in this manner? If so, how would you go about it?

现在,假设你在玩一款没有源码的游戏,你还能按那种方式作弊么?如果可以,你应该怎么做?

3.   Do a Google search on an application called "kcheat". Read the documentation. This person, in effect, wrote a debugger. If you have spare time, download the source and try to learn how it works. Browse the man page for the function ptrace().

Google上搜索一款叫做“kcheat”的软件。读取该文档。这个人写了一个高效的调试器。如果你有空闲时间。下载其源代码,并学习它是如何工作的。阅读ptrace函数手册。

4.   From the previous exercise, GDB could be considered as a "front end" to ptrace() system call. Look at ps aux. Do you see any processes that, if attached to with GDB, would be a security issue? Could cause a system to go down? Cause filesystem corruption? You probably have a process called "init" that has a process id of 1. Try to attach to it. Now become root and try to attach to it. There are some things that even root can't do!

在前面的练习中,GDB可以被认为是系统调用ptrace()的“前端(front end)”。查看ps aux。你是否看到了任何用GDB连接的进程了?这是安全的么?能否导致系统停止?使得文件系统损坏?你可能有一个进程id1,名字为init的进程。尝试连接该进程。现在成为root并试图连接它。有些事情root也是无法做到的!

 

 

阅读(1046) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~