Debugging Using GDB PDF
Debugging Using GDB PDF
Page 1 of 5
[LUPG Home] [Tutorials] [Related Material] [Essays] [Project Ideas] [Send Comments]
Note that we run the program from the same directory it was compiled in, otherwise gdb won't find the source file, and thus won't be able to show us where in the code we are at a given point. It is possible to ask gdb to search for extra source files in some directory after launching it, but for now, it's easier to just invoke it from the correct directory.
http://users.actcom.co.il/~choo/lupg/tutorials/debugging/debugging-with-gdb.html
10/26/2013
Page 2 of 5
Note that we used quotation marks to denote that "hello, world" is a single parameter, and not to separate parameters (the debugger assumes white-space separates the parameters).
Setting Breakpoints
The problem with just running the code is that it keeps on running until the program exits, which is usually too late. For this, breakpoints are introduced. A break point is a command for the debugger to stop the execution of the program before executing a specific source line.We can set break points using two methods: 1. Specifying a specific line of code to stop in:
break debug_me.c:9
Will insert a break point right before checking the command line arguments in our program (see the file supplied with this tutorial). 2. Specifying a function name, to break every time it is being called:
break main
this will set a break point right when starting the program (as the function "main" gets executed automatically on the beginning of any C or C++ program).
Breakpoint 1, main (argc=1, argv=0xbffffba4) at debug_me.c:9 9 if (argc < 2) { /* 2 - 1 for program name (argv[0]) and one for a param. */ (gdb)
Note that you won't always get the warnings i got - it just goes to show you how lousy my system setup is. In any case, these warnings are not relevant to our code, as we do not intend to debug any shared libraries.
http://users.actcom.co.il/~choo/lupg/tutorials/debugging/debugging-with-gdb.html
10/26/2013
Page 3 of 5
Now we want to start running the program slowly, step by step. There are two options for that: 1. "next" - causes the debugger to execute the current command, and stop again, showing the next command in the code to be executed. 2. "step" - causes the debugger to execute the current command, and if it is a function call - break at the beginning of that function. This is useful for debugging nested code. Now is your time to experiment with these options with our debug program, and see how they work. It is also useful to read the debuggers help, using the command "help break" and "help breakpoints" to learn how to set several breakpoints, how to see what breakpoints are set, how to delete breakpoints, and how to apply conditions to breakpoints (i.e. make them stop the program only if a certain expression evaluates to "true" when the breakpoint is reached).
which means that "i" contains the number "0". Note that this requires "i" to be in scope, or you'll get a message such as:
No symbol "i" in current context.
For example, if you break inside the "print_string" function and try to print the value of "i", you'll get this message. You may also try to print more complex expressions, like "i*2", or "argv[3]", or "argv[argc]", and so on. In fact, you may also use type casts, call functions found in the program, and whatever your sick mind could imagine (well, almost). Again, this is a good time to try this out.
This means the currently executing function is "print_string", at file "debug_me.c", line 7. The function that called it is "main". We also see which arguments each function had received. If there were more functions in the call chain, we'd see them listed in order. This list is also called "a stack trace", since it shows us the structure of the execution stack at this point in the program's life. Just as we can see contents of variables in the current function, we can see contents of variables local to the calling function, or to any other function on the stack. For example, if we want to see the contents of variable "i" in function "main", we can type the following two commands:
http://users.actcom.co.il/~choo/lupg/tutorials/debugging/debugging-with-gdb.html
10/26/2013
Page 4 of 5
frame 1 print i
The "frame" command tells the debugger to switch to the given stack frame ('0' is the frame of the currently executing function). At that stage, any print command invoked will use the context of that stack frame. Ofcourse, if we issue a "step" or "next" command, the program will continue at the top frame, not at the frame we requested to see. After all, the debugger cannot "undo" all the calls and continue from there.
Here we assume that "debug_me" is the name of the program executed, and that 9561 is the process id (PID) of the process we want to debug. What happens is that gdb first tries looking for a "core" file named "9561" (we'll see what core files are in the next section), and when it won't find it, it'll assume the supplied number is a process ID, and try to attach to it. If there process executes exactly the same program whose path we gave to gdb (not a copy of the file. it must be the exact same file that the process runs), it'll attach to the program, pause its execution, and will let us continue debugging it as if we started the program from inside the debugger. Doing a "where" right when we get gdb's prompt will show us the stack trace of the process, and we can continue from there. Once we exit the debugger, It will detach itself from the process, and the process will continue execution from where we left it.
This assumes the program was launched using this path, and the core file is in the current directory. If it is not, we can give the path to the core file. When we get the debugger's prompt (assuming the core file was successfully read), we can issue commands such as "print", "where" or "frame X". We can not issue commands that imply execution (such as "next", or the invocation of function calls). In some situations, we will be able to see what caused the crash.
http://users.actcom.co.il/~choo/lupg/tutorials/debugging/debugging-with-gdb.html
10/26/2013
Page 5 of 5
One should note that if the program crashed due to invalid memory address access, this will imply that the memory of the program was corrupt, and thus that the core file is corrupt as well, and thus contains bad memory contents, invalid stack frames, etc. Thus, we should see the core file's contents as one possible past, out of many probable pasts (this makes core file analysis rather similar to quantum theory. almost).
[LUPG Home] [Tutorials] [Related Material] [Essays] [Project Ideas] [Send Comments] This document is copyright (c) 1998-2002 by guy keren. The material in this document is provided AS IS, without any expressed or implied warranty, or claim of fitness for a particular purpose. Neither the author nor any contributers shell be liable for any damages incured directly or indirectly by using the material contained in this document. permission to copy this document (electronically or on paper, for personal or organization internal use) or publish it on-line is hereby granted, provided that the document is copied as-is, this copyright notice is preserved, and a link to the original document is written in the document's body, or in the page linking to the copy of this document. Permission to make translations of this document is also granted, under these terms - assuming the translation preserves the meaning of the text, the copyright notice is preserved as-is, and a link to the original document is written in the document's body, or in the page linking to the copy of this document. For any questions about the document and its license, please contact the author.
http://users.actcom.co.il/~choo/lupg/tutorials/debugging/debugging-with-gdb.html
10/26/2013