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 >
File List  |  1989-11-21  |  7KB  |  290 lines

  1. _DEBUGGING C PROGRAMS_
  2. by Bob Edgar
  3.  
  4. [LISTING ONE]
  5.  
  6. short tlevel = 0;
  7.  
  8. main(argc, argv, envp)
  9. char *argv[];
  10. char **envp;
  11.     {
  12.     int n;
  13.  
  14.     for (n = 0; n < argc; n++)
  15.         {
  16.         if (argv[n][0] == '-' && argv[n][1] == 'L')
  17.             {
  18.             int i;
  19.             char digit;
  20.  
  21.             /*  Found -L argument - process it  */
  22.  
  23.             digit = argv[n][2];
  24.             if (digit < '0' || digit > '9')
  25.                     {
  26.                     printf("Bad -L option\n");
  27.                     exit(1);
  28.                     }
  29.             tlevel = digit - '0';
  30.  
  31.             /*  Delete this element from argv[].  */
  32.             /*  We assume that argv[] has argc+1  */
  33.             /*  elements (most systems set argv[argc]  */
  34.             /*  to zero).  */
  35.  
  36.             argc--;
  37.             for (i = n; i < argc; i++)
  38.                     argv[i] = argv[i+1];
  39.             }
  40.         }
  41.     mymain(argc, argv, envp);
  42.     }
  43.  
  44.  
  45. [LISTING TWO]
  46.  
  47. /* showstack:  Show layout of host machine's stack */
  48.  
  49. #define STACKLOW        1
  50. int *stacktop, *ip;
  51. int f(), g();
  52.  
  53. main(argc, argv)
  54. char **argv;
  55.     {
  56.     stacktop = (int *) &argv;
  57.     printf("&argc=%08lx  &argv=%08lx\n", &argc, &argv);
  58.     printf("&main=%08lx  &f=%08lx  &g=%08lx\n", main, f, g);
  59.     f(0x11112222, 0x33334444);
  60.     }
  61.  
  62. f(arg_1, arg_2)
  63.     {
  64.     g(0x55556666);
  65.     }
  66.  
  67. g(arg_2)
  68.     {
  69.     int local;
  70.  
  71.     local = 0x77778888;
  72. #ifdef  STACKLOW        /*  Stack grows towards LOWER addresses  */
  73.     for (ip = stacktop; ip >= &local; ip--)
  74. #else                   /*  Stack grows towards HIGHER addresses  */
  75.     for (ip = stacktop; ip <= &local; ip++)
  76. #endif
  77.          printf("%08lx\t%08x\n", ip, *ip);
  78.     }
  79.  
  80.  
  81.  
  82. [LISTING THREE]
  83.  
  84. calltrace(arg_1)                /*  Trace calling sequence  */
  85.     {
  86.     int *bp, *newbp;
  87.  
  88.     bp = (int *) (&arg_1 - 2);
  89.  
  90.     while (bp < stacktop)   /*  "<" because STACKLOW  */
  91.         {
  92.         newbp = (int *) *bp;    /*  next link in list  */
  93.         printf("BP=%08lx  RET. ADDR=%08lx\n", bp, *(bp + 1));
  94.         bp = newbp;
  95.         }
  96.     }
  97.  
  98.  
  99.  
  100. [LISTING FOUR]
  101.  
  102.  
  103. struct func
  104.     {
  105.     int (*addr)();
  106.     char *name;
  107.     };
  108.  
  109. int main(), f(), g();
  110.  
  111. struct func funcs[] =           /*  symbol table  */
  112.     {
  113.     main, "main",
  114.     f, "f",
  115.     g, "g",
  116.     };
  117.  
  118. int nfuncs = sizeof(funcs)/sizeof(funcs[0]);
  119.  
  120. char *atoname(a)        /*  convert address to function name  */
  121. int (*a)();             /*  address  */
  122.     {
  123.     char *s;
  124.     int (*maxa)();
  125.     int n;
  126.  
  127.     maxa = 0;
  128.     s = "?";
  129.     for (n = 0; n < nfuncs; n++)
  130.             if (funcs[n].addr < a && funcs[n].addr > maxa)
  131.                     s = funcs[n].name, maxa = funcs[n].addr;
  132.     return s;
  133.     }
  134.  
  135.  
  136. Example 1: Defining the NDEBUG macro
  137.  
  138.         #ifndef NDEBUG
  139.         #define assert(cond) {if (!(cond)) \
  140.             printf("ASSERT cond,  file %s line %d\n", \
  141.             __FILE__, __LINE__); exit(1);}
  142.         #else
  143.         #define assert(cond) {;}  /*  Empty block  */
  144.         #endif
  145.  
  146.  
  147. Example 2: Using an assertion 
  148.  
  149.         do_str(s)
  150.         char *s;
  151.             {
  152.             assert(s != NULL)
  153.             /*  rest of do_str...  */
  154.  
  155.  
  156.  
  157. Example 3: using parentheses so that the entire arugment list to 
  158. printf is a single argument
  159.  
  160.         #define assertp(cond, args)     {if (!(cond)) \
  161.             printf("ASSERT cond, file %s, line %d\n", \
  162.             __FILE__, __LINE__); \
  163.             printf args; exit(1);}
  164.  
  165.  
  166. Example 4: A typical use of assert
  167.  
  168.         assertp(n > 3, ("Surprise! n > 3, is %d\n", n))
  169.  
  170.  
  171. Example 5: A macro which unconditionally prints when the trace 
  172. level is high enough
  173.  
  174.         #define assertl(level, args)    {if (tlevel >= (level)) \
  175.             printf("file %s, line %d\n", \
  176.             __FILE__, __LINE__); \
  177.             printf args; exit(1);}
  178.  
  179.  
  180. Example 6: A typical use of Example 5
  181.  
  182.         assertl(2, ("i=%d j=%d\n", i, j))
  183.  
  184.  
  185. Example 7: An assert.h header file
  186.  
  187.         #ifndef NDEBUG
  188.         extern short tlevel;
  189.         #define main    mymain
  190.         #endif
  191.  
  192.  
  193. Example 8: Typical bit definitions 
  194.  
  195.         #define TBIT_LEXER   0x0001 /* Lexical analysis functions  */
  196.         #define TBIT_PARSER  0x0002 /* Parser  */
  197.         #define TBIT_EXPTREE 0x0004 /* Expression tree  */
  198.         #define TBIT_CODEGEN 0x0008 /* Code generator  */
  199.         #define TBIT_OPTIM   0x0010 /* Optimizer  */
  200.  
  201.  
  202. Example 9: Defining assert-like macros
  203.  
  204.             #define assertb(bits, args)     {if ((bits) & tbits) \
  205.                     printf args;}
  206.  
  207. which can be used in this way:
  208.  
  209.         assertb(TBITS_PARSER | TBITS_EXPTREE,
  210.             ("Nodes in expression tree = %d\n", nnode))
  211.  
  212.  
  213. Example 10: Adding a statement to trap an error
  214.  
  215.         do_str(s)
  216.         char *s;
  217.             {
  218.             if (s == NULL)
  219.                  printf("do_str(NULL)!\n");
  220.  
  221.  
  222. Example 11: A function for a calling function 
  223.  
  224.         do_str(s)
  225.         char *s;
  226.             {
  227.             char *caller();
  228.             if (s == NULL)
  229.                 printf("%s() calls do_str(NULL)\n", caller());
  230.             }
  231.  
  232.  
  233. Example 12: Calling a function
  234.  
  235.  
  236.         push n'th argument
  237.         ...
  238.         push 2nd argument
  239.         push 1st argument
  240.         push current instruction pointer (ie. return address)
  241.         jump to start of function
  242.         copy stack pointer (SP) to base pointer (BP)
  243.         push BP
  244.  
  245.  
  246. Example 13: The top of the stack after functions have been called
  247.     
  248.               2nd arg
  249.               1st arg
  250.               Return addr.
  251.         BP--> Caller's BP
  252.    
  253.  
  254. Example 14: Modifying showstack so that g() calls only ctrace() 
  255. results in this output
  256.  
  257.     &main=00000094  &f=000000db  &g=000000f9
  258.     BP=0187ed20  RET. ADDR=0000010a
  259.     BP=0187ed38  RET. ADDR=000000f1
  260.     BP=0187ed50  RET. ADDR=000000d3
  261.     BP=0187ed6c  RET. ADDR=0000057d
  262.  
  263.  
  264. Example 15: The function atoname() finds the function closest to, 
  265. but starting before, the address given as its argument. 
  266.  
  267.         printf("BP=%08lx  FUNCTION=%s\n", bp, atoname(*(bp + 1)));
  268.  
  269. then the output looks like this:
  270.  
  271.         &main=00000094  &f=000000db  &g=000000f9
  272.         BP=0187ed28  FUNCTION=g
  273.         BP=0187ed40  FUNCTION=f
  274.         BP=0187ed58  FUNCTION=main
  275.         BP=0187ed74  FUNCTION=g
  276.  
  277.  
  278. Example 16: Changing ctrace() again
  279.  
  280.         printf("%s(%x, %x)\n", atoname(*(bp + 1)), *(newbp + 2), *(newbp + 3));
  281.  
  282. After this change, the output of the test program became:
  283.  
  284.         &main=00000094  &f=000000db  &g=000000f9
  285.         g(55556666, 187eda8)
  286.         f(11112222, 33334444)
  287.         main(1, 187eda8)
  288.         g(1, 187ee20)
  289.  
  290.