home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
MAGAZINE
/
DDJMAG
/
DDJCSPEC.ZIP
/
EDGAR.LST
< prev
next >
Wrap
File List
|
1989-11-21
|
7KB
|
290 lines
_DEBUGGING C PROGRAMS_
by Bob Edgar
[LISTING ONE]
short tlevel = 0;
main(argc, argv, envp)
char *argv[];
char **envp;
{
int n;
for (n = 0; n < argc; n++)
{
if (argv[n][0] == '-' && argv[n][1] == 'L')
{
int i;
char digit;
/* Found -L argument - process it */
digit = argv[n][2];
if (digit < '0' || digit > '9')
{
printf("Bad -L option\n");
exit(1);
}
tlevel = digit - '0';
/* Delete this element from argv[]. */
/* We assume that argv[] has argc+1 */
/* elements (most systems set argv[argc] */
/* to zero). */
argc--;
for (i = n; i < argc; i++)
argv[i] = argv[i+1];
}
}
mymain(argc, argv, envp);
}
[LISTING TWO]
/* showstack: Show layout of host machine's stack */
#define STACKLOW 1
int *stacktop, *ip;
int f(), g();
main(argc, argv)
char **argv;
{
stacktop = (int *) &argv;
printf("&argc=%08lx &argv=%08lx\n", &argc, &argv);
printf("&main=%08lx &f=%08lx &g=%08lx\n", main, f, g);
f(0x11112222, 0x33334444);
}
f(arg_1, arg_2)
{
g(0x55556666);
}
g(arg_2)
{
int local;
local = 0x77778888;
#ifdef STACKLOW /* Stack grows towards LOWER addresses */
for (ip = stacktop; ip >= &local; ip--)
#else /* Stack grows towards HIGHER addresses */
for (ip = stacktop; ip <= &local; ip++)
#endif
printf("%08lx\t%08x\n", ip, *ip);
}
[LISTING THREE]
calltrace(arg_1) /* Trace calling sequence */
{
int *bp, *newbp;
bp = (int *) (&arg_1 - 2);
while (bp < stacktop) /* "<" because STACKLOW */
{
newbp = (int *) *bp; /* next link in list */
printf("BP=%08lx RET. ADDR=%08lx\n", bp, *(bp + 1));
bp = newbp;
}
}
[LISTING FOUR]
struct func
{
int (*addr)();
char *name;
};
int main(), f(), g();
struct func funcs[] = /* symbol table */
{
main, "main",
f, "f",
g, "g",
};
int nfuncs = sizeof(funcs)/sizeof(funcs[0]);
char *atoname(a) /* convert address to function name */
int (*a)(); /* address */
{
char *s;
int (*maxa)();
int n;
maxa = 0;
s = "?";
for (n = 0; n < nfuncs; n++)
if (funcs[n].addr < a && funcs[n].addr > maxa)
s = funcs[n].name, maxa = funcs[n].addr;
return s;
}
Example 1: Defining the NDEBUG macro
#ifndef NDEBUG
#define assert(cond) {if (!(cond)) \
printf("ASSERT cond, file %s line %d\n", \
__FILE__, __LINE__); exit(1);}
#else
#define assert(cond) {;} /* Empty block */
#endif
Example 2: Using an assertion
do_str(s)
char *s;
{
assert(s != NULL)
/* rest of do_str... */
Example 3: using parentheses so that the entire arugment list to
printf is a single argument
#define assertp(cond, args) {if (!(cond)) \
printf("ASSERT cond, file %s, line %d\n", \
__FILE__, __LINE__); \
printf args; exit(1);}
Example 4: A typical use of assert
assertp(n > 3, ("Surprise! n > 3, is %d\n", n))
Example 5: A macro which unconditionally prints when the trace
level is high enough
#define assertl(level, args) {if (tlevel >= (level)) \
printf("file %s, line %d\n", \
__FILE__, __LINE__); \
printf args; exit(1);}
Example 6: A typical use of Example 5
assertl(2, ("i=%d j=%d\n", i, j))
Example 7: An assert.h header file
#ifndef NDEBUG
extern short tlevel;
#define main mymain
#endif
Example 8: Typical bit definitions
#define TBIT_LEXER 0x0001 /* Lexical analysis functions */
#define TBIT_PARSER 0x0002 /* Parser */
#define TBIT_EXPTREE 0x0004 /* Expression tree */
#define TBIT_CODEGEN 0x0008 /* Code generator */
#define TBIT_OPTIM 0x0010 /* Optimizer */
Example 9: Defining assert-like macros
#define assertb(bits, args) {if ((bits) & tbits) \
printf args;}
which can be used in this way:
assertb(TBITS_PARSER | TBITS_EXPTREE,
("Nodes in expression tree = %d\n", nnode))
Example 10: Adding a statement to trap an error
do_str(s)
char *s;
{
if (s == NULL)
printf("do_str(NULL)!\n");
Example 11: A function for a calling function
do_str(s)
char *s;
{
char *caller();
if (s == NULL)
printf("%s() calls do_str(NULL)\n", caller());
}
Example 12: Calling a function
push n'th argument
...
push 2nd argument
push 1st argument
push current instruction pointer (ie. return address)
jump to start of function
copy stack pointer (SP) to base pointer (BP)
push BP
Example 13: The top of the stack after functions have been called
2nd arg
1st arg
Return addr.
BP--> Caller's BP
Example 14: Modifying showstack so that g() calls only ctrace()
results in this output
&main=00000094 &f=000000db &g=000000f9
BP=0187ed20 RET. ADDR=0000010a
BP=0187ed38 RET. ADDR=000000f1
BP=0187ed50 RET. ADDR=000000d3
BP=0187ed6c RET. ADDR=0000057d
Example 15: The function atoname() finds the function closest to,
but starting before, the address given as its argument.
printf("BP=%08lx FUNCTION=%s\n", bp, atoname(*(bp + 1)));
then the output looks like this:
&main=00000094 &f=000000db &g=000000f9
BP=0187ed28 FUNCTION=g
BP=0187ed40 FUNCTION=f
BP=0187ed58 FUNCTION=main
BP=0187ed74 FUNCTION=g
Example 16: Changing ctrace() again
printf("%s(%x, %x)\n", atoname(*(bp + 1)), *(newbp + 2), *(newbp + 3));
After this change, the output of the test program became:
&main=00000094 &f=000000db &g=000000f9
g(55556666, 187eda8)
f(11112222, 33334444)
main(1, 187eda8)
g(1, 187ee20)