Using dbx with a core File


In this section, you will debug a version of blankstrip that 
produces a fatal error and a core dump when it executes.  Programs generate 
fatal errors when they attempt operations that violate the rules of the 
operating system.  This happens when a program tries to divide by zero, or 
access memory that doesn't belong to it.


Before you work through this tutorial, you need to activate core dumps on your 
workstation.  Use the quota -v command to determine the amount 
of free space you have in your file system, then use the limit 
command to set the upper limit size of the core dumps.  For instance, if you 
want to limit the size of your core files to 100 kbytes of disk space, use the 
limit command as follows:


coke-23: limit coredumpsize 100


You will recompile blankstrip using a different version of 
main.c, maincore.c. This new version of 
main() differs from the old in one respect; the declararation 
of the instring variable.  This variable receives the input 
string when main() calls the gets() 
function.  The original main.c file declared 
instring like this:


char instring[MAXLEN];


maincore.c declares it like this:


char *instring;


According to the laws of C, both declarations are valid.  In fact, if you look 
at the manual page for gets() (type man 3 gets 
at the coke-50: prompt), the documentation suggests that you 
declare the gets() argument as a pointer to 
char:


char *gets(s)

char *s;}


The manual page does not suggest that you declare the argument as a character 
array:


char s[VALUE];


Unfortunately the documentation assumes that you understand that 
*s has to point to allocated space.  If you don't understand 
this, and you declare a char pointer variable for 
gets() in the wrong context, you create what can be an ugly 
bug.


Compile and run the program as follows:


coke-51: cc -g maincore.c preblank.c adjstring.c 
tblank.c}

maincore.c:

preblank.c:

adjstring.c:

tblank.c:

coke-52: a.out

Enter a string with leading and trailing blanks:

    asdf

Bus error (core dumped)


The program generates a fatal error by attempting something contrary to the 
rules of the operating system.  When a program errs in this manner, UNIX takes 
a snapshot of the program in memory, and dumps the results into a core file.


You can use dbx to examine core files, as the following will 
illustrate:


coke-53: dbx a.out

dbx version 3.12 of 12/6/85 8:35 (paris).

Type 'help' for help.

reading symbolic information ...

[using memory image in core]	<-- dbx loads the core file.


The dbx where command tells you what procedures 
and functions are active.  When used to debug core files, where 
tells you what procedures were active when the program generated the fatal 
error:


(dbx) where

gets(0x0) at 0x1f3

main(0x1, 0x7fffe45c, 0x7fffe464), line 10 in "maincore.c"


The numbers that dbx displays refer to addresses in memory. 
 They won't be of much use to you unless you know something about core images.


In addition to giving you memory addresses, the message indicates that 
gets() was active when the program produced the fatal error, 
and that the error happened at line 10 of maincore.c.  Set a 
breakpoint there and run the program:


(dbx) stop at 10

[1] stop at "maincore.c":10

(dbx) run

Enter a string with leading and trailing blanks:

[1] stopped in main at line 10 in file "maincore.c"

   10     if (gets(instring))}


At this point gets() has not supplied a value for 
instring.  Examine the instring variable:


(dbx) print instring

(nil)

(dbx) print instring[0]

reference through nil pointer


The messages show that instring is an uninitialized pointer, 
a pointer that points to an arbitrary space.  If you try to assign data to 
instring, you ask the operating system to store the data at 
whatever address that instring addresses.


In this instance, instring addresses an invalid space, so the 
operating system responds by terminating the program and producing the core 
file.  Luck was on your side this time.  Many times uninitialized pointers 
point to valid memory locations.  When that happens, the program continues 
running.  If the program tries to use the value stored at the address, you may 
end up with a very obscure runtime error.


Compare the two instring declarations again:


char instring[MAXLEN];


char *instring;}


The first declaration says "create an array of type char, of 
size MAXLEN-1" (MAXLEN-1 because C arrays 
are indexed starting from 0).  The second declaration says "create a pointer 
that points to type char, but don't bother assigning it any 
space just yet."


Before you can use a char pointer in a program, you must make 
it point to an array that has already been allocated.  Before you use a 
*s, make sure it references something like 
instring[MAXLEN].


When you have finished debugging the program, don't forget to remove the core 
file.