- Table of Contents
- Copyright
- About the Author
- Acknowledgments
- Tell Us What You Think!
- Introduction
- Part I: Introduction to Mac OS X
- Chapter 1. Mac OS X Component Architecture
- Chapter 2. Installing Mac OS X
- Chapter 3. Mac OS X Basics
- Chapter 4. The Finder: Working with Files and Applications
- Chapter 5. Running Classic Mac OS Applications
- Part II: Inside Mac OS X
- Chapter 6. Native Utilities and Applications
- Chapter 7. Internet Communications
- Chapter 8. Installing Third-Party Applications
- Part III: User-Level OS X Configuration
- Chapter 9. Network Setup
- Chapter 10. Printer and Font Management
- Chapter 11. Additional System Components
- Part IV: Introduction to BSD Applications
- Chapter 12. Introducing the BSD Subsystem
- Chapter 13. Common Unix Shell Commands: File Operations
- Part V: Advanced Command-Line Concepts
- Chapter 14. Advanced Shell Concepts and Commands
- Chapter 15. Command-Line Applications and Application Suites
- Chapter 16. Command-Line Software Installation
- Chapter 17. Troubleshooting Software Installs, and Compiling and Debugging Manually
- Chapter 18. Advanced Unix Shell Use: Configuration and Programming (Shell Scripting)
- Part VI: Server/Network Administration
- Chapter 19. X Window System Applications
- Chapter 20. Command-Line Configuration and Administration
- Chapter 21. AppleScript
- Chapter 22. Perl Scripting and SQL Connectivity
- Chapter 23. File and Resource Sharing with NetInfo
- Chapter 24. User Management and Machine Clustering
- Chapter 25. FTP Serving
- Chapter 26. Remote Access and Administration
- Chapter 27. Web Serving
- Part VII: Server Health
- Chapter 28. Web Programming
- Chapter 29. Creating a Mail Server
- Chapter 30. Accessing and Serving a Windows Network
- Chapter 31. Server Security and Advanced Network Configuration
- Chapter 32. System Maintenance
- Appendix A. Command-Line Reference
- Appendix B. Administration Reference
Using the gdb Debugger
If thinking about the problem, trying to do things as correctly as possible, and examining all the debugging information yields only an application that doesn't run correctly, you still have the option of digging around in the code. Thankfully, Apple has provided the GNU debugger, gdb, as part of the development tools. The GNU debugger is to the Unix debugging world what the GNU compiler is to the Unix programming world—a flexible, community-supported, de facto standard for programmer productivity.
The easiest way to explain how to use gdb is to demonstrate its use. The program has copious online help, as well as man pages, and an INFO section available through the emacs M-x info command. Before the demonstration however, Table 17.1 contains a summary of command-line options and common internal commands.
Table 17.1. The Command Documentation Table for the gdb Debugger
| gdb | GNU debugger |
gdb [-help] [-nx] [-q] [-batch] [-cd=<dir>] [-f] [-b <bps>] [-tty=<dev>] [-s <symfile>] [-e <prog>] [-se <prog>] [-c <core>] [-x <cmds>] [-d <dir>] [<prog> [<core> | <procID>] |
|
| gdb can be used to debug programs written in C, C++, and Modula-2. | |
| Arguments other than options specify an executable file and a core file or process ID. The fist argument encountered with no associated option flag is equivalent to the -se option; the second, if any, is equivalent to the -c option, if it is a file. Options and command-line arguments are processed in sequential order. The order makes a difference when the -x option is specified. | |
| -help | |
| -h | Lists all options with brief explanations. |
| -symbols=< file > | |
| -s < file > | Reads symbol table from file < file >. |
| -write | Enables writing into executable and core files. |
| -exec=< file > | |
| -e < file > | ses < file > as the executable file to execute when appropriate, and for examining pure data in conjunction with a core dump. |
| -se=< file > | Reads symbol table from < file > and uses it as the executable file. |
| -core=< file > | |
| -c < file > | Uses < file > as a core dump to examine. |
| -command=< file > | |
| -x < file > | Executes gdb commands from < file >. |
| -directory=< directory > | |
| -d < directory > | Adds < directory > to the path to search for source files. |
| -nx | |
| -n | Does not execute commands from any .gdbinit files. Normally, commands in these files are executed after all the command options and arguments have been processed. |
| -quiet | |
| -q | Quiet mode. Does not print the introductory and copyright messages. Also suppresses them in batch mode. |
| -batch | Batch mode. Exits with status 0 after processing all the command files associated with the -x option (and .gdbinit, if not inhibited). Exits with nonzero status if an error occurs in executing the gdb commands in the command files. |
| -cd=< directory > | Runs gdb using < directory > as the working directory rather than using the current directory as the working directory. |
| -fullname | |
| -f | Outputs information used by emacs-gdb interface. |
| -b < bps > | Sets the line speed (baud rate or bits per second) of any serial interface used by gdb for remote debugging. |
| -tty=< device > | Runs using < device > for your program's standard input and output. |
| These are some of the more frequently needed gdb commands: | |
| break [< file >]< function > | Sets a breakpoint at < function > (in < file >). |
| run [< arglist >] | Starts your program (with < arglist >, if specified). |
| bt | Backtrace. Displays the program stack. |
| print < expr > | Displays the value of an expression. |
| c | Continues running your program (after stopping, such as at a breakpoint). |
| next | Executes the next program line (after stopping); steps over any function calls in the line. |
| step | Executes the next program line (after stopping); steps into any function calls in the line. |
| help [< name >] | Sows information about gdb command < name >, or general information about using gdb. |
| quit | Exits gdb. |
To use gdb, you first need something on which to use it. Type in the little program shown in Listing 17.1, just as it appears here. Name the file addme.c.
Example 17.1. The Source for the addme.c Demo C Program/* addme.c
A really silly C demo program */
/* 990325 WCR */
/* Usage is <progname> <filename> */
#include <stdio.h>
int addem(a,b)
int a, b;
{
return a+b;
}
void main(argc,argv)
int argc;
char *argv[];
{
int i;
char infilename[8];
int j;
FILE *infile;
char number[100];
char *infilename2=infilename;
strcpy(infilename2,argv[1]);
i=0; j=0;
infile = fopen(infilename2,"r");
if(infile==NULL)
{
printf("couldn't open file %s please try again\n",infilename2);
exit(1);
}
i=0;
while (fgets(number,90,infile) != '\0')
{
sscanf(number,"%d",&j);
i=addem(i,j);
}
printf("Your total is %d\n",i);
exit(0);
}
This simple little C program will take a list of integers from a file, one per line, and add them together. So that you'll have a file to work from, create a file named numbers with the following contents:
1 2 13 15
Make sure that there are no blank lines above or below the data.
Also create a file with a very long name, such as supercalifradgilisti c zowie, and put the same data in it.
Note there's a bit of trickery involved in the way this code is written that's specifically there to generate an error. Even though there are a few errors in this code, some systems are sloppy enough with memory management that the program might run intermittently. Also, if you rearrange the definition of the variables i and j, you decrease the likelihood of a crash. Weird, huh?
So, let's see what we have. Time to compile the program. We don't have a makefile, so we'll have to do it by hand. Issue the command:
cc -g -o addemup addme.c
After a few seconds, your machine should return you to a command line. The compiler should respond with a warning similar to the following:
addme.c: In function `main': addme.c:14: warning: return type of `main' is not `int'
It should return you to the command line. If it does anything else, for instance outputs
addme.c: In function `main': addme.c:15: parse error before `char' addme.c:23: subscripted value is neither array nor pointer
that means you've typed the program in incorrectly. Specifically, if you got this error, in all likelihood you forgot the semicolon after the line that says int argc;. The warning is just that: a warning, not an error. The most recent revision of the C programming language has a preference for a particular return type for the main program, and the compiler is just being pedantic.
After you get the program to compile cleanly with no errors you're ready for the next step—trying it out. Issue the command ./addemup and see what happens. Note that the command is addemup, not something related to addme. I could actually have named it anything I wanted, simply by changing the -o addemup part of the cc command. If you don't specify any output filename, cc will name the output file a.out by default. Also, just so you know, the -g flag tells the compiler to turn on the debugging output. This slows the program, but it gives the debugger important information.
/addemup Bus Error
Well, that doesn't sound good. What could be wrong? You can probably figure it out just by looking at the code at this point, but on a more complicated program that would be impossible. Instead, let's start the gdb debugger and take a look.
racer-x testaddme 274% gdb ./addemup GNU gdb 5.0-20001113 (Apple version gdb-186.1) (Sun Feb 18 01:18:32 GMT 2001) (UI_OUT) Copyright 2000 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 "powerpc-apple-macos10". Reading symbols for shared libraries .. done (gdb)
Okay, we're at a prompt. What do we do? The gdb debugger actually has a rather complete selection of online help available. To access the help system, simply enter the command help.
(gdb) help List of classes of commands: running — Running the program stack — Examining the stack data — Examining data breakpoints — Making program stop at certain points files — Specifying and examining files status — Status inquiries support — Support facilities user-defined — User-defined commands aliases — Aliases of other commands obscure — Obscure features internals — Maintenance commands Type "help" followed by a class name for a list of commands in that class. Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (gdb)
I'll leave some of the interesting items here for you to explore, rather than walk you through them. Right now, let's get back to debugging our program. To start the program, simply issue the command r.
(gdb) r Starting program: /priv/home/ray/testaddme/./addemup [Switching to thread 1 (process 390 thread 0x1903)] Program received signal EXC_BAD_ACCESS, Could not access memory. 0x700047d4 in strcpy () (gdb)
So, gdb knows something. Not a very intelligible something at this point, but something none the less. Let's see whether it can be a bit more informative.
(gdb) where #0 0x700047d4 in strcpy () #1 0x00001d18 in main (argc=1, argv=0xbffffb00) at addme.c:23 #2 0x00001bf4 in _start () #3 0x00001a34 in start () #4 0x00000000 in ?? () (gdb)
gdb says the program broke in a procedure named strcpy, which was called from a procedure named main, in line 23 of our file addme.c. The start(), and ??() calls are OS X and gdb initializing and starting the program. Let's take a look at this region of the code.
(gdb) l 23 18 char infilename[8]; 19 int j; 20 FILE *infile; 21 char number[100]; 22 char *infilename2=&infilename; 23 strcpy(infilename2,argv[1]); 24 i=0; j=0; 25 infile = fopen(infilename2,"r"); 26 27 if(infile==NULL) (gdb)
Line 23 has a function strcpy on it. The debugger seems to be on to something here. Let's set a breakpoint (a place we want the program to stop running and wait for us) at line 23 and see what happens.
(gdb) b 23 Breakpoint 1 at 0x2320: file addme.c, line 23. (gdb)
So far, so good. Now let's run the program again and see where this takes us.
(gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /priv/home/ray/testaddme/./addemup [Switching to thread 1 (process 395 thread 0x1a07)] Breakpoint 1, main (argc=1, argv=0xf7fff744) at addme.c:23 23 strcpy(infilename2,argv[1]); (gdb)
Note that gdb asked me whether I wanted to restart from the beginning and I told it to go ahead. Now it has run up to our breakpoint and is waiting for me to do something. Even if I don't know quite what strcpy does, there's still something obviously wrong with this line. I know I've got a variable named infilename2 and a funny variable named argv[1]. Let's see what gdb has to say about them.
(gdb) p infilename2 $1 = 0xbffff99c "L\000\000@" (gdb)
The $1 indicates that it's telling us about the first variable we asked about. The 0xbfff99c is the memory location where it's stored—don't be surprised if yours is different. The L\000\000@ is the current contents of that memory, which currently isn't too informative. (Don't be surprised if yours has something else in whatever memory location shows up on your machine.) What can we tell about this argv[1]?
(gdb) p argv[1] $2 = 0xbffffba9 0x0 (gdb)
Hmmm… 0x0 is a hexadecimal 0, or NULL in the C world. Examining the code again certainly suggests that something useful should be happening here. It looks like infilename2 gets used to open a file in just a few lines, and neither L\000\000@ nor NULL looks promising as a filename. Nulls get used in C, but frequently they're signs of a problem, so let's think about this.
The program is trying to do something with a variable named argv[1]. The only other place this variable (argv) appears is in the main statement, the statement that starts off the actual program execution. It certainly looks like there should be something other than a NULL here. Wait a minute, what did it say in the comments at the top? It said I needed to give it a filename! I didn't give it a filename, and it's trying to copy something that doesn't exist to get one. Aren't programmers supposed to check for that?
Let's see if I'm right. I'll rerun the program with a filename this time.
(gdb) r numbers The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /priv/home/ray/testaddme/./addemup numbers [Switching to thread 1 (process 405 thread 0x250b)] Breakpoint 1, main (argc=2, argv=0xf7fff73c) at addme.c:23 23 strcpy(infilename2,argv[1]); (gdb)
I started it over, but I forgot to turn off my breakpoint. Still, this is a good opportunity for me to check to see whether I was right.
(gdb) p infilename2 $3 = 0xf7fff200 "\000\000\200\000\000\000 " (gdb)
That's just as useless as before.
(gdb) p argv[1] $4 = 0xf7fff80f "numbers" (gdb)
Now we're getting somewhere! If we remember to give it a filename, it actually gets one! To continue past the breakpoint, I can enter c.
(gdb) c Continuing. Your total is 31 Program exited normally. (gdb)
The program now does exactly what it should. If I'd like to test it again without stopping at the breakpoint, I can delete the breakpoint and run it again.
(gdb) d 1 (gdb) r Starting program: /priv/home/ray/testaddme/./addemup numbers [Switching to thread 1 (process 445 thread 0x2721)] Your total is 31 Program exited normally. (gdb)
The command d 1 deletes breakpoint 1 (you can have multiples if you need them). Note that I didn't have to give it the command-line argument numbers this time when I hit r because it conveniently remembered command-line arguments between runs. As you can see, it runs properly to completion.
Quitting gdb with the quit command and trying it on the command line produces the same results.
racer-x testaddme 286% ./addemup numbers Your total is 31 racer-x testaddme 287%
Now let's see whether we can demonstrate another type of error. Do you still remember what your very long filename is? Try using that filename instead of numbers and see what happens.
racer-x testaddme 287% ./addemup supercalifragilisticzowie couldn't open file supercalifra please try again racer-x testaddme 288%
Huh? I didn't call it supercalifra. Something happened to my filename. Time to break out gdb again and have another look.
gdb ./addemup GNU gdb 5.0-20001113 (Apple version gdb-186.1) (Sun Feb 18 01:18:32 GMT 2001) (UI_OUT) Copyright 2000 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 "powerpc-apple-macos10". Reading symbols for shared libraries .. done (gdb) r supercalifragilisticzowie Starting program: /priv/home/ray/testaddme/./addemup supercalifragilisticzowie [Switching to thread 1 (process 551 thread 0x351b)] couldn't open file supercalifra please try again Program exited with code 01. (gdb)
Basically, it says the same thing. There must be something more we can find out, though. Let's look at the code and see if we can figure out where that weird truncation came from.
(gdb) l
14 int argc;
15 char *argv[];
16 {
17 int i;
18 char infilename[8];
19 int j;
20 FILE *infile;
21 char number[100];
22 char *infilename2=infilename;
23 strcpy(infilename2,argv[1]);
(gdb)
24 i=0; j=0;
25 infile = fopen(infilename2,"r");
26
27 if(infile==NULL)
28 {
29 printf("couldn't open file %s please try again\n",infilename2);
30 exit(1);
31 }
32
33 i=0;
(gdb)
Line 29 seems to be where the error message is coming from. Let's set a breakpoint there and see what happens.
(gdb) b 29
Breakpoint 1 at 0x2374: file addme.c, line 29.
(gdb) r
Starting program: /priv/home/ray/testaddme/./addemup supercalifragilisticzowie
[Switching to thread 1 (process 583 thread 0x291b)]
Breakpoint 1, main (argc=2, argv=0xf7fff72c) at addme.c:29
29 printf("couldn't open file %s please try again\n",infilename2);
(gdb)
We're at our breakpoint. infilename2 is supposed to be supercalifragilisti c zowie, and it is
(gdb) p infilename2 $1 = 0xbffff99c "supercalifra" (gdb)
Something's very wrong here! Time to back up to our trusty breakpoint at line 23 and watch what happens from the top down.
(gdb) r Starting program: /priv/home/ray/testaddme/./addemup supercalifragilisticzowie Breakpoint 1, main (argc=2, argv=0xf7fff72c) at addme.c:23 23 strcpy(infilename2,argv[1]); (gdb) p argv[1] $1 = 0xf7fff7ff "supercalifragilisticzowie" (gdb)
So, the previous culprit isn't a problem here.
(gdb) p infilename2 $2 = 0xbffff99c "\000\000\200\000\000\000 " (gdb)
There's nothing interesting there. Let's see what happens on the next line—use the gdb command n to step to the next line. When you step to the next line, this line executes, so you should expect to see the results of that strcpy after stepping forward.
(gdb) n 24 i=0; j=0; (gdb) p infilename2 $1 = 0xf7fff6b0 "supercalifragilisticzowie" (gdb)
As expected, infilename2 contains our atrociously long filename. Nothing wrong here, but by the time it hit line 29, it was broken, so let's step forward again and see what happens.
(gdb) n 25 infile = fopen(infilename2,"r"); (gdb) p $3 = 0xf7fff6b0 "supercalifra" (gdb)
Wait a minute! Now it's wrong! What happened? All that the program did was assign both the variables i and j to be zero, and somehow it affected infilename2. You wouldn't think this could happen, variables just changing their values willy-nilly.
In fact, if the program were written properly, this wouldn't happen. As a non-programmer, this is where you usually give up. That isn't to say that the exercise has been useless. With this information, you can more easily explain to the author or online support community what problems you've observed, so they can fix it more easily and quickly. Program authors hate it when they get bug reports that say, "it didn't work." This doesn't mean anything to them because if they could duplicate the problem on their end, they'd probably have found and fixed it already.
By taking these extra steps, the information you can provide about the program's problems can mean the difference between a fix that takes a few minutes to appear and a fix that never appears.
Recommended Command-Line Software Installations | Next Section

Account Sign In
View your cart