home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Utilities / Except.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  13.2 KB  |  611 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Except.cpp
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Owned by:    Ted Jucevic
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>      3/3/96    TJ        Added global gVolatile to help make
  13.                                     ODVolatile realy volatile.
  14.  
  15.     To Do:
  16. */
  17.  
  18. /*
  19.     File:        Except.cpp
  20.  
  21.     Contains:    Exception-handling utility
  22.  
  23.     Owned by:    Jens Alfke
  24.  
  25.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  26.  
  27.     
  28.     In Progress:
  29.         
  30. */
  31.  
  32. #ifndef _PLATFORM_MACINTOSH_
  33. #define DONT_USE_STACKCRAWL
  34. #endif
  35.  
  36. #ifndef __EXCEPT__
  37. #include "Except.h"
  38. #endif
  39.  
  40. #ifndef _ODDEBUG_
  41. #include "ODDebug.h"
  42. #endif
  43.  
  44. #ifndef SOM_Module_OpenDoc_Errors_defined
  45. #include "ErrorDef.xh"
  46. #endif
  47.  
  48. #ifndef _PLFMDEF_
  49. #include "PlfmDef.h"
  50. #endif
  51.  
  52. #ifndef _UTILERRS_
  53. #include "UtilErrs.h"
  54. #endif
  55.  
  56. #ifndef DONT_USE_STACKCRAWL
  57. #ifndef _CRAWL_
  58. #include <Crawl.h>
  59. #endif
  60. #endif
  61.  
  62. #ifndef __SOM__
  63. #include <som.xh>
  64. #endif
  65.  
  66. #ifndef __RESOURCES__
  67. #include <Resources.h>
  68. #endif
  69.  
  70. #ifndef __STRINGS__
  71. #include <Strings.h>
  72. #endif
  73.  
  74. #ifndef _ODMEMORY_
  75. #include "ODMemory.h"
  76. #endif
  77.  
  78. #include <stdio.h>
  79. #include <stdarg.h>
  80. #include <string.h>
  81.  
  82.  
  83. extern void BREAK( const char[] );
  84.  
  85.  
  86. static ODBoolean gBreakOnThrow = kODFalse;    // Set to true to break on exceptions
  87.  
  88. void* gVolatile = kODNULL;
  89.  
  90. const ODSize kSpareMemSize = 512;
  91. static void* gSpareMem = kODNULL;
  92. // gSpareMem is a block of memory we keep around to make sure that in an emergency
  93. // we always have enough memory to allocate a SOM exception, by releasing the spare
  94. // block if we have to.
  95.  
  96.  
  97. #pragma segment ODExceptions
  98.  
  99.  
  100. //=====================================================================================
  101. // Setting BreakOnThrow
  102. //=====================================================================================
  103.  
  104.  
  105. ODBoolean
  106. BreakOnThrow( ODBoolean brk )
  107. {
  108.     ODBoolean oldBrk = gBreakOnThrow;
  109.     gBreakOnThrow = brk;
  110.     return oldBrk;
  111. }
  112.  
  113.  
  114. //=====================================================================================
  115. // Initializing ODException Structures
  116. //=====================================================================================
  117.  
  118.  
  119. static void
  120. InitODException( ODException *x, ODError error, const char *message, ODSLong msgsize )
  121. {
  122.     x->error = error;
  123.     if( message ) {
  124.         ODBlockMove(message,x->message,msgsize);
  125.         x->message[msgsize-1] = '\0';
  126.     } else
  127.         x->message[0] = 0;
  128. }
  129.  
  130.  
  131. static ODException*
  132. NewODException( ODError error, const char *message )
  133. {
  134.     SOMFree(gSpareMem);                            // Get some slack
  135.     
  136.     ODULong size = message ?(strlen(message)+1) :1;
  137.     if( size>256 ) size=256;
  138.     ODException *x = (ODException*) SOMMalloc( sizeof(ODError) + size );
  139.     
  140.     if( x )
  141.         InitODException(x,error,message,size);
  142.     
  143.     gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up again
  144.     
  145.     return x;
  146. }
  147.  
  148.  
  149. #ifndef _NATIVE_EXCEPTIONS_
  150.  
  151. //=====================================================================================
  152. // Stack Maintenance
  153. //=====================================================================================
  154.  
  155.  
  156. static ODExceptionFrame *gTopHandler = kODNULL;
  157.  
  158. inline ODExceptionFrame* GetTopHandler( )
  159. { return gTopHandler; }
  160.  
  161.  
  162. //=====================================================================================
  163. // ODExceptionFrame
  164. //=====================================================================================
  165.  
  166.  
  167. #define kAlreadyPoppedHandler ((ODExceptionFrame*)0xDEADBEEF)
  168.  
  169.  
  170. #ifndef _ASM_XTRY_
  171. jmp_buf* _xTryEv( ODExceptionFrame *x, Environment *ev )
  172. {
  173.     if( ! gSpareMem )
  174.         gSpareMem = SOMMalloc(kSpareMemSize);
  175.         
  176.     x->fError = kODNoError;
  177.     x->fODException = kODNULL;
  178.     x->fEv = ev;
  179.     x->fDestructoList = kODNULL;
  180.     x->fPrev = GetTopHandler();
  181.     gTopHandler = x;
  182.     return &x->fBuffer;
  183. }
  184.  
  185. jmp_buf* _xTry( ODExceptionFrame *x )
  186. {
  187.     if( ! gSpareMem )
  188.         gSpareMem = SOMMalloc(kSpareMemSize);
  189.         
  190.     x->fError = kODNoError;
  191.     x->fODException = kODNULL;
  192.     x->fEv = kODNULL;
  193.     x->fDestructoList = kODNULL;
  194.     x->fPrev = GetTopHandler();
  195.     gTopHandler = x;
  196.     return &x->fBuffer;
  197. }
  198. #endif /*_ASM_XTRY_*/
  199.  
  200.  
  201. void _xPop( ODExceptionFrame *x )
  202. {
  203.     if( GetTopHandler() == x )
  204.         // Remove myself from the stack if (a) I'm at ENDTRY and no exception was thrown,
  205.         // or (b) someone exited (probably via 'return') from within the TRY block:
  206.         gTopHandler = x->fPrev;
  207.         
  208.     else {
  209.         if( x->fPrev == kAlreadyPoppedHandler )
  210.             // Do nothing if I was already popped by a THROW.
  211.             ;
  212.         else {
  213.             /*  At this point the astute reader will be wondering how a non-top
  214.                 exception handler could be destructed first. Given correct inside-
  215.                 out destruction of stack-based objects, this should never happen;
  216.                 however, some compilers will mix up the order in certain cases.
  217.                 Therefore we roll up our sleeves and prepare to destruct any
  218.                 intervening handlers on the stack: */
  219.                 
  220.             WARN("Destructing non-top excpt frame %p",x);
  221.             
  222.             ODExceptionFrame *e;
  223.             for( e=gTopHandler; e && e->fPrev!=x; e=e->fPrev )
  224.                 ;
  225.             if( e==kODNULL )
  226.                 WARN("Excpt frame %p not found on stack!",x);
  227.             else
  228.                 e->fPrev = x->fPrev;
  229.         }
  230.         
  231.         /*    If exiting a SOM_TRY handler with an error, store it in the Environment: */
  232.         if( x->fEv ) {
  233.             if( x->fODException ) {
  234.                 somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
  235.                 x->fODException = kODNULL;
  236.             } else if( x->fError )
  237.                 ODSetSOMException(x->fEv,x->fError);
  238.         }
  239.     }
  240.     
  241.     if( x->fODException ) {
  242.         SOMFree(x->fODException);
  243.         if( ! gSpareMem )
  244.             gSpareMem = SOMMalloc(kSpareMemSize);
  245.     }
  246. }
  247.  
  248.  
  249. void
  250. ODExceptionFrame::Throw( ODError err, const char* msg, ODException *x )
  251. {
  252.     if( err == kODNoError ) {
  253.         WARN("Do not call THROW(0)!");
  254.         return;
  255.     }
  256.         
  257.     WASSERT(this==GetTopHandler());
  258.  
  259.     // Call the destructor of each of my destructos:
  260.     for( Destructo *d=fDestructoList; d; d=d->EmergencyDestruct() )
  261.         ;
  262.     
  263.     gTopHandler = fPrev;                // Pop the exception handler
  264.     fPrev = kAlreadyPoppedHandler;
  265.     
  266.     // Store error info in this handler. If there's a message, need to copy
  267.     // it into an ODException structure if possible:
  268.     fError = err;
  269.     if( x )
  270.         fODException = x;
  271.     else if( msg && msg[0]!='\0' )
  272.         fODException = NewODException(err,msg);
  273.     else
  274.         fODException = kODNULL;
  275.     
  276.     longjmp(fBuffer,1);                    // SHAZAM!
  277. }
  278.  
  279.  
  280. void
  281. _xReraise( ODExceptionFrame *xf )
  282. {
  283. #if ODDebug
  284.     if( GetTopHandler()==xf )
  285.         BREAK("Reraise called on active exception handler!");
  286.     // Not fatal but probably a mistaken usage of RERAISE.
  287. #endif
  288.  
  289.     if( xf->fEv ) {
  290.         WARN("RERAISE in SOM_CATCH_ALL block is illegal");
  291.         return;
  292.     }
  293.     
  294.     WASSERTM(xf->fError!=kODNoError,"RERAISE called with no exception");
  295.     
  296.     // Throw the exception, re-using the ODException if possible:
  297.     if( GetTopHandler() ==kODNULL )
  298.         BREAK("No handler to CATCH exception!!");
  299.     else {
  300.         ODException *x = xf->fODException;
  301.         xf->fODException = kODNULL;
  302.         GetTopHandler()->Throw(xf->fError,kODNULL,x);
  303.     }
  304. }
  305.  
  306.  
  307. void
  308. _xSetErrorCode( ODExceptionFrame *xf, ODError err )
  309. {
  310.     xf->fError = err;
  311.     if( err ) {
  312.         if( xf->fODException )
  313.             xf->fODException->error = err;
  314.     } else {
  315.         SOMFree(xf->fODException);
  316.         xf->fODException = kODNULL;
  317.     }
  318. }
  319.  
  320.  
  321. void
  322. _xSetErrorMessage( ODExceptionFrame *xf, const char *message )
  323. {
  324.     if( message && message[0]!='\0' ) {
  325.         ODException *x = NewODException(xf->fError,message);
  326.         if( x ) {
  327.             SOMFree(xf->fODException);
  328.             xf->fODException = x;
  329.         }
  330.     } else {
  331.         SOMFree(xf->fODException);
  332.         xf->fODException = kODNULL;
  333.     }
  334. }
  335.  
  336.  
  337. //=================================================================================== 
  338. // Destructo class
  339. //=================================================================================== 
  340.  
  341.  
  342. #define kIWuzDestructed ((Destructo*)0xDEADBEEF)
  343. #define kEmergencyDestructing    ((Destructo*)0xFADEBABE)
  344.  
  345.  
  346. Destructo::Destructo( )
  347. {
  348.     /* Constructor adds me to the current exception frame's destructo list. */
  349.     if( GetTopHandler() ) {
  350.         fPrevDestructo = gTopHandler->fDestructoList;
  351.         gTopHandler->fDestructoList = this;
  352.     } else
  353.         fPrevDestructo = kODNULL;
  354. }
  355.  
  356.  
  357. Destructo::~Destructo( )
  358. {
  359.     /*    Destructor removes me from the owner's destructo list, except during
  360.         an emergency destruct while an exception is being thrown; in that case
  361.         the exception handler takes care of that bit itself. */
  362.         
  363.     if( fPrevDestructo != kEmergencyDestructing ) {
  364. #if ODDebug
  365.     if( fPrevDestructo==kIWuzDestructed ) {
  366.         WARN("Destructo %p being destructed twice!",this);
  367.         return;
  368.     }
  369. #endif
  370.     if( GetTopHandler() ) {
  371.         if( gTopHandler->fDestructoList == this )
  372.             gTopHandler->fDestructoList = fPrevDestructo;
  373.         else
  374.             WARN("Destructo %p being destructed is not top of list",this);
  375.     }
  376.     }
  377.     
  378. #if ODDebug
  379.     fPrevDestructo = kIWuzDestructed;
  380. #endif
  381. }
  382.  
  383.  
  384. Destructo*
  385. Destructo::EmergencyDestruct( )
  386. {
  387.     /*    My owner is _not_ the top handler right now, because it's destructing me in
  388.         a nested TRY block. Jam a special marker into fPrevDestructo to tell my
  389.         destructor not to mess with the Destructo chain; then return the next
  390.         destructo in the chain to help the handler walk it. */
  391.     
  392.     Destructo *prev = fPrevDestructo;
  393. #if ODDebug
  394.     if( prev==kIWuzDestructed ) {
  395.         WARN("Destructo %p being emergency-destructed twice!",this);
  396.         return kODNULL;
  397.     }
  398. #endif
  399.  
  400.     fPrevDestructo = kEmergencyDestructing;
  401.     TRY{
  402.         this->~Destructo();
  403.     }CATCH_ALL{
  404.         // Ignore the nested exception.
  405.     }ENDTRY
  406.     return prev;
  407. }
  408.  
  409.  
  410. #endif /*not _NATIVE_EXCEPTIONS_*/
  411.  
  412.  
  413. //=================================================================================== 
  414. // THROW, et al
  415. //=================================================================================== 
  416.  
  417.  
  418. static void
  419. DoThrow( ODError err, const char* msg, ODException *x = kODNULL )
  420. {
  421.     if( err == kODNoError ) {
  422.         WARN("Do not call THROW(0)!");
  423.         return;
  424.     }
  425.             
  426. #if ODDebug
  427.     // Dump useful into to stdout or MacsBug. Ignore AE coercion-failure error
  428.     // (-1700 == errAECoercionFail) since it happens as part of normal operation.
  429.     
  430.     if( (GetOutputMode() != kNoOutput || gBreakOnThrow)
  431.                 && err!=-1700 && err!=-1708 ) {                // Skip noise AE errors
  432.         char caller[256];
  433.         #ifndef DONT_USE_STACKCRAWL
  434.             if( ! ODHaveFreeSpace(1024,1024) )
  435.                 strcpy(caller,"??(low mem)??");
  436.             else {
  437.                 StackCrawl *sc = StackCrawl::New(2,2);
  438.                 sc->GetFrameName(0,caller);
  439.                 delete sc;
  440.             }
  441.         
  442.             if( GetOutputMode() != kNoOutput ) {
  443.                 if( msg )
  444.                     somPrintf("** THROW(%d) called by %s\n", err,caller);
  445.                 else
  446.                     somPrintf("** THROW(%d,%s) called by %s\n", err,msg,caller);
  447.                 if( ODHaveFreeSpace(1024,1024) ) {
  448.                     StackCrawl *s = StackCrawl::New(2,-5);
  449.                     if( s ) {
  450.                         for( long i=0; i<s->CountFrames(); i++ ) {
  451.                             char name[256];
  452.                             s->GetFrameName(i,name);
  453.                             somPrintf("        %s\n",name);
  454.                         }
  455.                         delete s;
  456.                     }
  457.                 }
  458.             }
  459.         #else
  460.             strcpy(caller,"????");
  461.         #endif
  462.         
  463.         if( gBreakOnThrow )
  464.             if( msg )
  465.                 WARN("THROW(%ld,%s) called by %s", err,msg,caller);
  466.             else
  467.                 WARN("THROW(%ld) called by %s", err,caller);
  468.     }
  469. #endif
  470.  
  471. #ifdef _NATIVE_EXCEPTIONS_
  472.     ODException x;
  473.     InitODException(&x, err,msg,256);
  474.     throw(x);
  475. #else
  476.     if( GetTopHandler() ==kODNULL )
  477.         BREAK("No handler to CATCH exception!!");
  478.     else
  479.         GetTopHandler()->Throw(err,msg,x);
  480. #endif
  481. }
  482.  
  483.  
  484.  
  485. void
  486. THROW( ODError err )
  487. {
  488.     DoThrow(err,kODNULL);
  489. }
  490.  
  491.  
  492. void
  493. THROW_IF_ERROR( ODError err )
  494. {
  495.     if( err != 0 )
  496.         DoThrow(err,kODNULL);
  497. }
  498.  
  499.  
  500. void
  501. THROW_IF_NULL( void* value )
  502. {
  503.     if( value == kODNULL )
  504.         DoThrow(kODErrOutOfMemory,kODNULL);
  505. }
  506.  
  507.  
  508. #if ODDebug
  509. void
  510. THROW_IF_ERROR_M( ODError err, const char *msg )
  511. {
  512.     if( err != 0 )
  513.         DoThrow(err,msg);
  514. }
  515.  
  516. void
  517. THROW_M( ODError err, const char* msg )
  518. {
  519.     DoThrow(err,msg);
  520. }
  521.  
  522. void
  523. THROW_IF_NULL_M( void* value, const char* msg )
  524. {
  525.     if( value == kODNULL )
  526.         DoThrow(kODErrOutOfMemory,msg);
  527. }
  528. #endif /*ODDebug*/
  529.  
  530.  
  531. //=================================================================================== 
  532. // SOM EXCEPTIONS
  533. //===================================================================================
  534.  
  535.  
  536. void
  537. ODSetSOMException( Environment *ev, ODError error, const char *message /*=NULL*/ )
  538. {
  539.     if( error ) {
  540.         ODException *x = NewODException(error,message);
  541.             SOMFree(gSpareMem);                            // Get some slack
  542.             somSetException(ev,USER_EXCEPTION,ex_ODException,x);
  543.             gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up
  544.     } else {
  545.         somExceptionFree(ev);
  546.         ev->_major = NO_EXCEPTION;
  547.     }
  548. }
  549.  
  550.  
  551. #ifdef _NATIVE_EXCEPTIONS_
  552. void
  553. ODSetSOMException( Environment *ev, ODException &except )
  554. {
  555.     ODSetSOMException(ev,except.error,except.message);
  556. }
  557.  
  558. #else
  559.  
  560. void
  561. _xSetSOMException( Environment *ev, ODExceptionFrame *x )
  562. {
  563.     if( !x->fEv ) {                        // Ignore this in a SOM_TRY block
  564.         if( x->fODException ) {
  565.             SOMFree(gSpareMem);                            // Get some slack
  566.             somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
  567.             gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up
  568.             x->fODException = kODNULL;
  569.         } else if( x->fError )
  570.             ODSetSOMException(x->fEv,x->fError);
  571.     }
  572. }
  573.  
  574. #endif
  575.  
  576.  
  577. ODError
  578. ODGetSOMException( Environment *ev )
  579. {
  580.     if( ev->_major ) {
  581.         const char *excpName = somExceptionId(ev);
  582.         if( strcmp(excpName,ex_ODException) == 0 ) {
  583.             ODException *x = (ODException*)somExceptionValue(ev);
  584.             return x->error;
  585.         } else {
  586.             WARN("Env has non-OpenDoc err: %s",excpName);
  587.             return kODErrSOMException;
  588.         }
  589.     } else
  590.         return kODNoError;
  591. }
  592.  
  593.  
  594. void
  595. CHECK_ENV( Environment *ev )
  596. {
  597.     if( ev->_major ) {
  598.         const char *excpName = somExceptionId(ev);
  599.         if( strcmp(excpName,ex_ODException) == 0 ) {
  600.             ODException x = *(ODException*)somExceptionValue(ev);
  601.             somExceptionFree(ev);
  602.             ev->_major = NO_EXCEPTION;
  603.             DoThrow(x.error, x.message);
  604.         } else {
  605.             WARN("Env has non-OpenDoc err: %s",excpName);
  606.             somExceptionFree(ev);
  607.             ev->_major = NO_EXCEPTION;
  608.             DoThrow(kODErrSOMException,kODNULL);
  609.         }
  610.     }
  611. }