How to debug a portion of FreeBSD code using gdb from a shell? (Using Sysinstall code as an example)
Well, in my last FreeBSD Friday post, I talked about How to compile a portion of FreeBSD code with debugging? (Sysinstall for this example). The next step is to learn to step through the code. There is a debugging tool included with FreeBSD called gdb
.
A good start for gdb is to read this document from the FreeBSD Developers’ Handbook.
http://www.freebsd.org/doc/en/books/developers-handbook/debugging.html
To really get good at gdb though, you should read the gdb documenation here:
http://sourceware.org/gdb/current/onlinedocs/gdb/
Well, lets get started.
Step 1 – Compile a portion of FreeBSD code with debugging enabled
How to compile a portion of FreeBSD code with debugging? (Sysinstall for this example)
Step 2 – Start gdb
As a user (not root) launch gdb with the name of the executable as the only parameter.
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “amd64-marcel-freebsd”…
(gdb)
Step 3 – Set a break point
At the gdb prompt, type break main.
Breakpoint 1 at 0x416b00: file main.c, line 55.
(gdb)
Step 4 – Start the program
To start the program type run and hit enter.
Starting program: /usr/home/jared/Devel/FreeBSD/head/usr.sbin/sysinstall/sysinstall
Breakpoint 1, main (argc=1, argv=0x7fffffffe998) at main.c:55
55 {
(gdb)
Step 5 – Step through the code
Ok, to step through the code you simply type ‘s’.
Breakpoint 1 at 0x416b00: file main.c, line 55.
(gdb)
Once you have typed ‘s’ once, you can just hit enter and it will keep stepping through. You could keep typing ‘s’ but you don’t need to.
Step through the code until it terminates because you are not root.
Here is the entire run through in one screen.
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “amd64-marcel-freebsd”…
(gdb) break main
Breakpoint 1 at 0x416b00: file main.c, line 55.
(gdb) run
Starting program: /usr/home/jared/Devel/FreeBSD/head/usr.sbin/sysinstall/sysinstall
Breakpoint 1, main (argc=1, argv=0x7fffffffe998) at main.c:55
55 {
(gdb) s
61 StartName = argv[0];
(gdb)
64 if (getpid() == 1) {
(gdb)
68 signal(SIGPIPE, SIG_IGN);
(gdb)
71 if (geteuid() != 0) {
(gdb)
72 fprintf(stderr, “Error: This utility should only be run as root.\n”);
(gdb)
Error: This utility should only be run as root.
204 }
(gdb)
0x0000000000404d9e in _start ()
(gdb)
Single stepping until exit from function _start,
which has no line number information.
Program exited with code 01.
(gdb)
Ok, you now have done some basic debugging with gdb and you have learned that you cannot run sysinstall as root.
Step 6 – Debug as root
Ok, this shouldn’t be hard for you by now. Sudo to root and repeat the above steps only this time the program will continue past the check for whether it is running as root because it will be. Stop just after you pass the line that checks if you are root.
One you get so far, you will actually get to the sysinstall gui and you can choose to exit.
Step 7 – Set a break point based on line number
Type the following to set a break point based on line number.
Breakpoint 2 at 0x416bd6: file main.c, line 103.
(gdb)
Step 8 – Continuing to the next break point
So now instead of stepping to line 110, we will just continue the program with the command “continue”. By the way, the following three commands will continue and all are really the exact same command. You might ask, “Why are there three ways to do the same thing?” I have to answer, “I don’t know, I didn’t write gdb.” But hey, I am not complaining.
- continue
- c
- fg
So yes to continue you can type any of the three commands at the gdb prompt and your program will continue until the next break point or until the program terminates.
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffe8c8) at main.c:103
103 systemInitialize(argc, argv);
(gdb)
Note on finding development code or development features
Often while developing, a developer adds code to help them develop. This is development code, development features, debug code, or whatever you want to call it. This code is not really meant to be used in production, but it sure helps the developer write and test and debug the production code. Most large applications have such hidden development features. When stepping through code, you should look for these.
As I was looking through the sysinstall code, I noticed a section of code starting at line 110 (obviously this is subject to change but you should be able to find the line number in the same area) that checks for a parameter called -fake.
if (argc > 1 && !strcmp(argv[1], "-fake")) { variable_set2(VAR_DEBUG, "YES", 0); Fake = TRUE; msgConfirm("I'll be just faking it from here on out, OK?"); }
This hidden switch is never mentioned in the man page. It appears to be one of those development only features that we can take advantage of to help us code Sysinstall. It also suggests that you can step through Sysinstall without having anything actually happen, which might be useful in debugging.
Making our first code change
Ok, so if I am going to use the -fake switch, I would assume that I could do so without running as root. Since we are “faking it” anyway, we might as well not be running as root at all.
So here is a code change I have made that will allow me to run as a normal user if I pass the -fake parameter. I am going to change line 73 (again this may not be the exact line for you as this is subject to change) where sysinstall checks if it is running as root and add an additional check to see if a parameter was passed and if so see if the parameter was -fake and if so, continue even though it is not root.
Here is what the code was originally.
if (geteuid() != 0) { fprintf(stderr, "Error: This utility should only be run as root.\n"); return 1; }
Here is what I changed the code to. Notice that I didn’t delete or add to the existing line just yet. Instead, I commented it out and added a new line because that makes it easier to switch back and forth when testing this new code out.
//if (geteuid() != 0) {
if (geteuid() != 0 && (argc < 2 || strcmp(argv[1], "-fake"))) {
fprintf(stderr, "Error: This utility should only be run as root.\n");
return 1;
}
[/sourcecode]
Ok, so save and exit. No go ahead and exit your root shell so you are just logged in as your user again.
Recompile to apply your changes. In case you forgot, you recompile with this command:
Go ahead and debug again. Repeat the steps above again, however, this time, in the gdb prompt, before you execute the command “run”, go ahead and set the arguments to pass to your application so that the -fake argument is passed.
(gdb)
Just to make sure, lets show the arguments to make sure that we properly set them.
Argument list to give program being debugged when it is started is “-fake”.
(gdb)
Now you can run your program in gdb and continue debugging sysinstall as a regular user. I think I am going to send this change in because maybe it should be a permanent change. What do you think?
Copyright ® Rhyous.com – Linking to this article is allowed without permission and as many as ten lines of this article can be used along with this link. Any other use of this article is allowed only by permission of Rhyous.com.