Throw/Raise Exception From Probes

From OC Systems Wiki!
Revision as of 02:08, 18 August 2019 by Swn (talk | contribs) (C/C++ Example)
Jump to: navigation, search

You can raise and Ada exception or throw a C++ exception from a probe.

In Ada you will need to know the name of the exception you want to raise. This can be as simple as constraint_error or a more complex fully-qualified name pkg.child.my_exception.

In C++ you will have to provide: the exception object (usually referenced in the application program using a target expression, for example $MyExceptionObject), the exception typeinfo, a constructor, and a destructor. Below are some prototype macros which make this a little bit easier.

If you raise/throw and exception in an on_entry action of a probe, the function call will be stubbed and the exception will be raised/thrown when the probed function exits.

If you raise/throw and exception in an on_line/offset action of a probe, the exception will be raised/thrown at that point.

If you raise/throw and exception in an on_exit action of a probe, the exception will be raised/thrown when the function returns.


Ada Example

The Ada example demonstrates how to raise an Ada exception from a probe on_entry/on_line/on_exit action. Note that #ifdef's are used to condition the Aprobe macro used to raise the exception depending on the target compiler (PowerAda or Gnat).

#ifdef _AIX
#define RAISE ap_RaisePowerAdaException
#else
#define RAISE ap_RaiseGnatException
#endif

probe thread
{
   probe "tmain.x1" 
   {
      on_entry 
      {
         RAISE("constraint_error");
      }
   }

   probe "tmain.x2" 
   {
      on_exit 
      {
         RAISE("ada.io_exceptions.status_error");
      }
   }

   probe "tmain.x3" 
   {
      on_line(27) 
      {
         RAISE("my_exception");
      }
   }
}

C/C++ Example

Throwing C++ exceptions is more complicated. This example demonstrates some prototype macros to make the process simpler. Eventually, these macros may be migrated to the aprobe.h as they prove their worth. If the macros fail, you will have to extract the proper information yourself and call ap_ThrowGccException() directly.

// This macro can be used to throw a C++ exception.  
//
// You must provide the exception name, the exception object, and a module id.  
//
// The macro will generate code to lookup the exception typeinfo and a constructor and destructor.  This is base on
// C++ mangled symbols and Aprobe detangled symbols and works for simple examples.  If your exception is defined in 
// your application module, pass <code>ap_ApplicationModuleId()</code> as the model parameter.  If your exception is defined in a
// shared library, you must provide the module id (ap_ModuleIdT) using <code>ap_ModuleNameToId()</code>.
//
#define THROW(exname, exobj, modid) \
{ \
   int len = ap_Strlen(exname); \
   ap_SymbolIdT tiSym; \
   ap_SymbolIdT ctorSym; \
   ap_SymbolIdT dtorSym; \
   char *tiptr = alloca(len + 5); \
   char *ctorptr = alloca(len * 2 + 5); \
   char *dtorptr = alloca(len * 2 + 5); \
 \
   sprintf(tiptr, "_ZTI%d%s", len, exname); \
   sprintf(ctorptr, "%s::%s", exname, exname); \
   sprintf(dtorptr, "%s::~%s", exname, exname); \
 \
   tiSym = \
         ap_SymbolNameToId( \
            modid, \
            tiptr, \
            ap_ExternSymbol, \
            ap_DataSymbol); \
   ctorSym = \
         ap_SymbolNameToId( \
            modid, \
            ctorptr, \
            ap_ExternSymbol, \
            ap_FunctionSymbol); \
   dtorSym = \
         ap_SymbolNameToId( \
            modid, \
            dtorptr, \
            ap_ExternSymbol, \
            ap_FunctionSymbol); \
 \
   ap_ThrowCppException(exobj, sizeof(exobj), ap_SymbolAddress(tiSym), ap_SymbolAddress(ctorSym), ap_SymbolAddress(dtorSym)); \
}

// This macro can be used to throw a simple string object.  Just provide a string literal or a target-expression
// for the string object.
//
#define THROW_STRING(exobj) \
{ \
   ap_SymbolIdT tiSym = \
         ap_SymbolNameToId( \
            ap_ModuleNameToId("libstdc++.so"), \
            "_ZTIPKc", \
            ap_ExternSymbol, \
            ap_DataSymbol); \
   ap_ThrowCppException(exobj, sizeof(exobj), ap_SymbolAddress(tiSym), NULL, NULL); \
}

//
// The example probe which uses the above macros.
//
probe thread
{
   int count = 0;

   probe "service(int, int)"
   {
      on_entry
      {
         count++;
         if (count == 1)
         {
            // throw E;
            // E is the exception class and $e1 is the exception object declared in the application.
            THROW("E", $e1, ap_ApplicationModuleId());
         }
         else if (count == 2)
         {
            // throw myexception;
            // my exception is the exception class and $e2 is the exception object declared in the application.
            THROW("myexception", $e2, ap_ApplicationModuleId());
         }
         else
         {
            // throw "Exception";
            // throw a local string object.
            THROW_STRING("Exception");
         }
      }
   }
}