home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / DDJ0190.ZIP / SCHULMAN.LST < prev    next >
File List  |  1989-12-26  |  10KB  |  369 lines

  1. _STALKING GENERAL PROTECTION FAULTS: PART I_
  2. by Andrew Schulman
  3.  
  4. [LISTING ONE]
  5.  
  6. /* FFFF.C
  7.     -- causes GP fault in real mode on 286/386, and in Virtual 86 mode
  8.     -- catch it in real mode
  9.     -- can't catch it in Virtual 86 mode
  10.  
  11. Turbo C: tcc ffff.c
  12. Microsoft C: cl ffff.c
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <dos.h>
  17. #include "gpfault.h"
  18.  
  19. void (interrupt far *old)();
  20.  
  21. void fini(char *msg, int exit_code)
  22. {
  23.     puts(msg);
  24.     _dos_setvect(INT_GPFAULT, old);
  25.     exit(exit_code);
  26. }
  27.  
  28. void far my_exit(void) { fini("Bye!", 1); }
  29.  
  30. void interrupt far handler(REG_PARAMS r)
  31. {
  32.     printf("\nProtection violation at %04X:%04X\n", r.cs, r.ip);
  33.     /* change CS:IP on stack so control is "returned" to my_exit */
  34.     /* this is an alternative to using longjmp() */
  35.     r.cs = FP_SEG(my_exit);
  36.     r.ip = FP_OFF(my_exit);
  37. }   
  38.  
  39. main()
  40. {
  41.     int *p = (int *) -1;
  42.     old = _dos_getvect(INT_GPFAULT);
  43. #ifndef CRASH_AT
  44.     _dos_setvect(INT_GPFAULT, handler);
  45. #endif
  46.     printf("int at %p is ", p);
  47.     printf("%04X\n", *p);
  48.     /*NOTREACHED on 286/386 */
  49.     fini("Done!", 0);
  50. }
  51.  
  52.  
  53.  
  54. [LISTING TWO]
  55.  
  56. /* GPFAULT.H
  57.     -- REG_PARAM structure represents stack at entry to interrupt handler
  58.     -- CPU pushes flags, CS:IP, and, for protected-mode INT 08-0D,
  59.        an error code
  60.     -- Compiler pushes all other registers at entry to interrupt function
  61.     -- Turbo C pushes registers in a strange order
  62.     -- Watcom C 386 7.0 also pushes FS and GS registers (unfortunately
  63.        MetaWare High C for MS-DOS 386 1.5 does not)
  64.  
  65.     -- replace Microsoft C 5.1 FP_SEG, FP_OFF macros with ones that don't
  66.        requires lvalues
  67.     -- keep Watcom C 386 7.0 FP_SEG, etc. -- these work for 48-bit pointers
  68.     -- for MetaWare High C for 386 MS-DOS, need our own 48-bit FP_SEG, etc.
  69. */
  70.  
  71. #ifdef InstantC_16M
  72. /* Rational Systems Instant-C/16M protected-mode C interpreter */
  73. #define DOS16M
  74. #define PROT_MODE
  75. #endif
  76.  
  77. typedef struct {
  78. #if defined(__WATCOMC__) && defined(__386__)
  79.     unsigned gs,fs;
  80. #endif
  81. #ifdef __TURBOC__
  82.     unsigned bp,di,si,ds,es,dx,cx,bx,ax;
  83. #else
  84.     unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax;     /* same as PUSHA */
  85. #endif
  86. #ifdef PROT_MODE
  87.     unsigned err_code;                          /* for pmode INT 08-0D */
  88. #endif
  89.     unsigned ip,cs,flags;
  90.     } REG_PARAMS;
  91.  
  92. #ifdef __TURBOC__
  93. #define _dos_setvect(x,y)   setvect(x,y)
  94. #define _dos_getvect(x)     getvect(x)
  95. #endif
  96.  
  97. #define INT_GPFAULT         0x0D
  98.  
  99. /* 386 protected-mode: far pointer is 48 bits; near pointer is 32 bits */
  100. /* thus, 386 pmode near pointer can hold a real-mode far pointer */
  101. #ifdef __HIGHC__
  102. #define real_far            _near
  103. #define prot_far            _far
  104. #define far                 _far
  105. #else
  106. #if defined(__WATCOMC__) && defined(__386__)
  107. #define real_far            near
  108. #define prot_far            far
  109. #endif
  110. #endif
  111.  
  112. #ifdef __HIGHC__
  113. /* use overlay struct: no High C support for 48-bit immediate values */
  114. /* remember that unsigned is 32 bits, short is 16 bits */
  115. typedef struct { unsigned off; short seg; } overlay;
  116.  
  117. #define FP_SEG(fp)          ((overlay prot_far *) &(fp))->seg
  118. #define FP_OFF(fp)          ((overlay prot_far *) &(fp))->off
  119. #else
  120. #if (!(defined(__WATCOMC__) && defined(__386__)))
  121. /* Microsoft C FP_SEG() and FP_OFF() require an lvalue:  yuk! */
  122. #ifdef FP_SEG
  123. #undef FP_SEG
  124. #undef MK_FP
  125. #undef FP_OFF
  126. #endif
  127. #define FP_SEG(fp)          (((UL)(fp)) >> 16)
  128. #define MK_FP(seg,off)      ((FP)(UL)(((UL)(seg) << 16) | (off)))
  129. #define FP_OFF(fp)          ((unsigned)(fp))
  130. #endif
  131. #endif
  132.  
  133. typedef unsigned long UL;
  134. typedef void far *FP;
  135. typedef enum { FALSE, TRUE } BOOL;
  136.  
  137. #ifdef __HIGHC__
  138. #pragma Calling_convention(C_interrupt | _FAR_CALL);
  139. typedef void (*IPROC)();
  140. #pragma Calling_convention();
  141. #else
  142. typedef void (interrupt far *IPROC)();
  143. #endif
  144.  
  145.  
  146.  
  147. [LISTING THREE]
  148.  
  149. /* GPFAULT.C -- for AI Architects OS/286 or Rational Systems DOS/16M
  150.  
  151. for AI Architects:
  152.     cl -AL -Ox -Gs2 -c -DPROT_MODE gpfault.c
  153.     link gpfault,gpfault,gpfault/map,\os286\llibce;
  154.     \os286\express gpfault
  155.     cp gpfault
  156.  
  157. for DOS16M:
  158.     if not exist dos16lib.obj cl -AL -Ox -Gs2 -c source\dos16lib.c
  159.     cl -AL -Ox -Gs2 -c -DPROT_MODE -DDOS16M -Zi gpfault.c
  160.     link /co preload crt0_16m pml gpfault dos16lib /noe,gpfault;
  161.     makepm gpfault
  162.     splice gpfault gpfault
  163.     d gpfault
  164. */
  165.  
  166. #include <stdio.h>
  167. #include <stdlib.h>
  168. #include <setjmp.h>
  169. #include <string.h>
  170. #include <dos.h>
  171. #ifdef DOS16M
  172. #include "dos16.h"
  173. #endif
  174. #include "gpfault.h"
  175.  
  176. #define IN_MY_CODE          11593
  177. #define IN_USER_CODE        16843
  178. #define IN_HANDLER          40311
  179.  
  180. unsigned whereami = IN_MY_CODE;     /* need our own protection for this */
  181. jmp_buf toplevel;
  182. jmp_buf toplevel_copy = {0};        /* initialized, in a different segment */
  183. unsigned legal = 0;                 /* just a legal address to bang on */
  184. void (interrupt far *old_int13handler)();
  185.  
  186. void interrupt far int13handler(REG_PARAMS r);  /* GP fault handler */
  187. void goto_toplevel(void);       /* longjump out of handler */
  188. void revert(void);              /* restore default handler */
  189. void fail(char *msg, FP fp);    /* fail by calling default handler */
  190.  
  191. main(int argc, char *argv[])
  192. {
  193.     char buf[255];
  194.     unsigned far *fp;
  195.     unsigned data;
  196.  
  197.     old_int13handler = _dos_getvect(INT_GPFAULT);
  198.     _dos_setvect(INT_GPFAULT, int13handler);
  199.  
  200.     printf("'Q' to quit, '!' to reinstall default GP Fault handler\n");
  201.     printf("%Fp is a legal address to poke\n", &legal);
  202.     /* next line helps illustrate limitations of protection */
  203.     printf("%Fp is not a legal address to poke\n", &legal-1);
  204.     
  205.     setjmp(toplevel);
  206.     whereami = IN_MY_CODE;
  207.     memcpy(toplevel_copy, toplevel, sizeof(jmp_buf));
  208.     
  209.     for (;;)
  210.     {
  211.         printf("$ ");
  212.         *buf = '\0';
  213.         gets(buf);
  214.         
  215.         if (toupper(*buf) == 'Q')
  216.             break;
  217.         else if (*buf == '!')
  218.         {
  219.             revert();
  220.             continue;
  221.         }
  222.     
  223.         sscanf(buf, "%Fp %u", &fp, &data);
  224.         whereami = IN_USER_CODE;
  225.         *fp = data;     /* the crucial line of code */
  226.         printf("poked %Fp with %u\n", fp, *fp);
  227.         whereami = IN_MY_CODE;
  228.     }
  229.  
  230.     revert();
  231.     puts("Bye");
  232.     return 0;
  233. }
  234.  
  235. void revert(void)
  236. {
  237.     _dos_setvect(INT_GPFAULT, old_int13handler);
  238. }
  239.  
  240. void fail(char *msg, FP fp)
  241. {
  242.     (fp) ? printf(msg, fp) : puts(msg);
  243.     revert();
  244.     _chain_intr(old_int13handler);
  245. }
  246.  
  247. void goto_toplevel(void)
  248. {
  249.     if (memcmp(toplevel, toplevel_copy, sizeof(jmp_buf)) == 0)
  250.         longjmp(toplevel, -1);
  251.     else
  252.         fail("Toplevel context has been trompled", 0);
  253. }
  254.             
  255. void interrupt far int13handler(REG_PARAMS r)
  256. {
  257.     switch (whereami)
  258.     {
  259.         case IN_HANDLER:
  260.             fail("\nDouble fault at %Fp\n", MK_FP(r.cs, r.ip));
  261.             /*NOTREACHED*/
  262.         case IN_MY_CODE:
  263.             fail("\nInternal error at %Fp\n", MK_FP(r.cs, r.ip));
  264.             /*NOTREACHED*/
  265.         case IN_USER_CODE:
  266.             whereami = IN_HANDLER;
  267.             _enable();  /* reenable interrupts */
  268.             /* we could use Intel LAR and LSL instructions here to
  269.             figure out why GP fault took place:  did we try to write
  270.             into code?  or did offset overrun segment limit? */
  271.             printf("\nProtection violation at %04X:%04X\n", r.cs, r.ip);
  272.             if (r.err_code)
  273.                 printf("Error code %04X\n", r.err_code);
  274.             printf("<ES %04X> <DS %04X> <DI %04X> <SI %04X>\n", 
  275.                 r.es, r.ds, r.di, r.si);
  276.             printf("<AX %04X> <BX %04X> <CX %04X> <DX %04X>\n", 
  277.                 r.ax, r.bx, r.cx, r.dx);
  278.             goto_toplevel();
  279.             /*NOTREACHED*/
  280.         default:
  281.             whereami = IN_HANDLER;
  282.             _enable();
  283.             puts("whereami flag got trompled");
  284.             goto_toplevel();
  285.             /*NOTREACHED*/
  286.     }
  287. }
  288.  
  289. #ifdef DOS16M
  290. void _dos_setvect(unsigned intno, IPROC isr)
  291. {
  292.     D16pmInstall(intno, FP_SEG(isr), FP_OFF(isr), NULL);
  293. }
  294.  
  295. IPROC _dos_getvect(unsigned intno)
  296. {
  297.     IPROC isr;
  298.     D16pmGetVector(intno, (INTVECT *) &isr);
  299.     return isr;
  300. }
  301. #endif
  302.  
  303.  
  304. Example 1: This code will cause a GP fault in protected mode 
  305.  
  306.         main()
  307.         {
  308.             int far *fp = (int far *) main;
  309.             *fp = rand();
  310.             main();
  311.         }
  312.  
  313. Example 2: If this program GP faults, it's because of an error by 
  314. the user, not by the application itself.
  315.  
  316.         main(int argc, char *argv[])
  317.         {
  318.             int far *fp = (int far *) atol(argv[1]);
  319.             *fp = atoi(argv[2]);
  320.         }
  321.  
  322.  
  323. Figure 1: A GP fault dump
  324.  
  325.         Session Title: UR/Forth
  326.             SYS1943: A program caused a protection violation.
  327.             TRAP 000D
  328.             AX=2092 BX=0000 CX=FFFF DX=3FC2 BP=FFFA
  329.             SI=05EA DI=05E4 DS=00C7 ES=0000 FLG=2206
  330.             CS=0227 IP=2093 SS=00C7 SP=FBFC MSW=FFED
  331.             CSLIM=FFFE SSLIM=FFFF DSLIM=FFFF ESLIM=****
  332.             CSACC=DF SSACC=F3 DSACC=F3 ESACC=**
  333.             ERRCD=0000 ERLIM=**** ERACC=**
  334.                 End the program
  335.  
  336. Figure 2: A GPFAULT.EXP session
  337.  
  338.  
  339.         C:\DOS16M>gpfault
  340.         DOS/16M Protected Mode Run-Time     Version 3.25
  341.         Copyright (C) 1987,1988,1989 by Rational Systems, Inc.
  342.         'Q' to quit, '!' to reinstall default GP fault handler
  343.         00A0:04C6 is a legal address to poke
  344.         00A0:04C4 is not a legal address to poke
  345.         $ 1234:5678 666
  346.         Protection violation at 0088:00C5!
  347.         Error code 1234
  348.         <ES 00A0> <DS 00A0> <DI 1AC0> <SI 0082>
  349.         <AX 0015> <BX 0BF8> <CX 0015> <DX 0000>
  350.         $ 00A0:04C4 666
  351.         poked 00A0:04C4 with 666
  352.         $ 00A0:04C2 1
  353.         poked 00A0:04C2 with 1
  354.         $ 0088:00C5 666
  355.         Protection violation at 0088:00CB!
  356.         <ES 0088> <DS 00A0> <DI 1AC0> <SI 0082>
  357.         <AX 029A> <BX 00CB> <CX 0015> <DX 0000>
  358.         $ 0:0 0
  359.         Protection violation at 0088:00CB!
  360.         <ES 0000> <DS 00A0> <DI 1AC0> <SI 0082>
  361.         <AX 0000> <BX 0000> <CX 0015> <DX 0000>
  362.         $ !
  363.         $ 0:0 0
  364.         DOS/16M: Unexpected Interrupt=000D  at 0088:00CB
  365.         code=0000 ss=00A0 ds=00A0 es=0000 
  366.         ax=0000 bx=0000 cx=0015 dx=0000 sp=1982 bp=1A92 si=0082 di=1AC0 
  367.         C:\DOS16M>
  368.  
  369.