home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / callmon / src / callmon$intercept.c < prev    next >
C/C++ Source or Header  |  1996-08-06  |  16KB  |  426 lines

  1. /*  CALLMON - A Call Monitor for OpenVMS Alpha
  2.  *
  3.  *  File:     CALLMON$INTERCEPT.C
  4.  *  Author:   Thierry Lelegard
  5.  *  Version:  1.0
  6.  *  Date:     24-JUL-1996
  7.  *
  8.  *  Abstract: This module contains the routines which intercept routines
  9.  *            in shareable images.
  10.  */
  11.  
  12.  
  13. #include "callmon$private.h"
  14.  
  15.  
  16. /*******************************************************************************
  17.  *
  18.  *  The following structure is a context block for LIB$TRAVERSE_TREE
  19.  *  when all routines of a image are being intercepted.
  20.  */
  21.  
  22. typedef struct {
  23.     image_t* image;        /* Shareable image to intercept */
  24.     pdsc_t*  pre_routine;  /* Pre-routine descriptor */
  25.     pdsc_t*  post_routine; /* Post-routine descriptor */
  26.     int      override;     /* Boolean: override already intercepted routines */
  27.     int      use_desc;     /* Boolean: use string descriptor */
  28. } intercept_ctx_t;
  29.  
  30.  
  31. /*******************************************************************************
  32.  *
  33.  *  Jacket routines.
  34.  *
  35.  *  When a routine is intercepted, it is replaced by a jacket routine
  36.  *  which receives its arguments. Module CALLMON$JACKET.M64 contains
  37.  *  one jacket routine. Each time a new jacket routine is needed,
  38.  *  we clone the linkage section of this routine, thus creating a
  39.  *  new instance of the jacket routine. The cloned linkage section
  40.  *  is filled with the routine-specific data.
  41.  */
  42.  
  43. /*
  44.  *  The following symbols are defined in file CALLMON$JACKET.M64.
  45.  *  They define the various points inside the template linkage section.
  46.  *  The char type is dummy and used to be able to compute offsets.
  47.  */
  48.  
  49. #pragma extern_model save
  50. #pragma extern_model strict_refdef
  51.  
  52. extern char callmon$$jacket;           /* Start of template linkage section */
  53. extern char callmon$$clone_routine;    /* PDSC of original routine */
  54. extern char callmon$$clone_pre;        /* PDSC of pre-processing routine */
  55. extern char callmon$$clone_post;       /* PDSC of post-processing routine */
  56. extern char callmon$$clone_name;       /* Name of original routine */
  57. extern char callmon$$jacket_link_end;  /* End of template linkage section */
  58.  
  59. #pragma extern_model restore
  60.  
  61. /*
  62.  *  When a jacket routine is cloned, we allocate a new linkage section.
  63.  *  The original content of the template linkage section must be first
  64.  *  copied into the cloned linkage section.
  65.  */
  66.  
  67. #define CLONE_LINKAGE_SECTION_SIZE \
  68.     ((char*) &callmon$$jacket_link_end - (char*) &callmon$$jacket)
  69.  
  70. /*
  71.  *  Then, the routine-specific data are modified inside the clone
  72.  *  linkage section. This includes the addresses of the original
  73.  *  routine, the pre- and post-processing routines and the routine
  74.  *  name.
  75.  */
  76.  
  77. #define CLONE_LINKAGE_ADDR(routine,symbol) \
  78.     ((int64*) ((char*) ((routine)->jacket) + \
  79.     ((char*) &(callmon$$clone_##symbol) - (char*) &callmon$$jacket)))
  80.  
  81. #define CLONE_ROUTINE(routine) (*CLONE_LINKAGE_ADDR (routine, routine))
  82. #define CLONE_PRE(routine)     (*CLONE_LINKAGE_ADDR (routine, pre))
  83. #define CLONE_POST(routine)    (*CLONE_LINKAGE_ADDR (routine, post))
  84. #define CLONE_NAME(routine)    (*CLONE_LINKAGE_ADDR (routine, name))
  85.  
  86.  
  87. /*******************************************************************************
  88.  *
  89.  *  This routine modifies one image. It hooks one jacket routine.
  90.  *  It is an action routine for LIB$TRAVERSE_TREE on the tree of images.
  91.  *  The user_data is the routine_t structure.
  92.  */
  93.  
  94. static uint32 hook_image (image_t* image, routine_t* routine)
  95. {
  96.     if (image != routine->image)
  97.         callmon$$process_fixups (image, routine);
  98.     else {
  99.         callmon$$remove_bsr (image);
  100.         callmon$$process_relocations (routine);
  101.     }
  102.  
  103.     return SS$_NORMAL;
  104. }
  105.  
  106.  
  107. /*******************************************************************************
  108.  *
  109.  *  This routine intercepts one specific routine.
  110.  */
  111.  
  112. static uint32 intercept_routine (
  113.     routine_t* routine,
  114.     pdsc_t*    pre_routine,
  115.     pdsc_t*    post_routine,
  116.     int        use_desc)
  117. {
  118.     uint32 status;
  119.     void** res;
  120.     routine_t* dup;
  121.  
  122.     /* If the routine is not interceptable, give up */
  123.  
  124.     if (routine->uninterceptable)
  125.         return CALLMON$_RESROUT;
  126.  
  127.     /* If the routine has already a jacket routine, simply modify pre/post */
  128.  
  129.     if (routine->jacket != NULL) {
  130.         CLONE_PRE (routine) = (int64) pre_routine;
  131.         CLONE_POST (routine) = (int64) post_routine;
  132.         CLONE_NAME (routine) = use_desc ?
  133.             (int64) &routine->name_d : (int64) routine->name;
  134.         return SS$_NORMAL;
  135.     }
  136.  
  137.     /* Allocate one jacket routine. Note that the PDSC must be aligned on a
  138.      * quadword boundary. Here, we rely on the fact that LIBVM's default
  139.      * zone alignment attribute is also quadword. */
  140.  
  141.     routine->jacket = callmon$$alloc (CLONE_LINKAGE_SECTION_SIZE);
  142.  
  143.     /* The initial content of the clone linkage section is a copy
  144.      * of the template linkage section. */
  145.  
  146.     memcpy (routine->jacket, &callmon$$jacket, CLONE_LINKAGE_SECTION_SIZE);
  147.  
  148.     /* Now fill the new clone linkage section with specific data */
  149.  
  150.     CLONE_ROUTINE (routine) = routine->lkp.lkp$q_proc_value;
  151.     CLONE_PRE (routine) = (int64) pre_routine;
  152.     CLONE_POST (routine) = (int64) post_routine;
  153.     CLONE_NAME (routine) = use_desc ?
  154.         (int64) &routine->name_d : (int64) routine->name;
  155.  
  156.     /* All routine_t for this procedure must point to the same jacket */
  157.  
  158.     for (dup = routine->master_by_value; dup; dup = dup->next_by_value)
  159.         dup->jacket = routine->jacket;
  160.  
  161.     /* In all images, modify all references to the routine */
  162.  
  163.     return lib$traverse_tree (&callmon$$own.image_tree, hook_image, routine);
  164. }
  165.  
  166.  
  167. /*******************************************************************************
  168.  *
  169.  *  This public routine intercepts one specific routine.
  170.  */
  171.  
  172. uint32 callmon$intercept (
  173.     char*               routine_name,
  174.     callmon$intercept_t pre_routine,
  175.     callmon$intercept_t post_routine)
  176. {
  177.     uint32 status;
  178.     uint32 final_status;
  179.     routine_t* routine;
  180.     thread_state_t thread_state;
  181.  
  182.     /* Initialize CALLMON if not yet done */
  183.  
  184.     callmon$initialize ();
  185.  
  186.     if (callmon$$own.trace_flags & TRACE_API)
  187.         callmon$$putmsg (CALLMON$_INTERCEPT, 3, 
  188.             routine_name, pre_routine, post_routine);
  189.  
  190.     callmon$$disable_threading (&thread_state);
  191.  
  192.     /* Find the description of the routine */
  193.  
  194.     if ((routine = callmon$$get_routine_by_name (routine_name)) == NULL)
  195.         final_status = CALLMON$_RNF;
  196.  
  197.     else {
  198.  
  199.         /* Hook all routines with that name */
  200.  
  201.         final_status = SS$_NORMAL;
  202.  
  203.         for (routine = routine->master_by_name;
  204.              routine != NULL;
  205.              routine = routine->next_by_name) {
  206.  
  207.             status = intercept_routine (routine, (pdsc_t*) pre_routine,
  208.                 (pdsc_t*) post_routine, 0);
  209.  
  210.             if (!$VMS_STATUS_SUCCESS (status))
  211.                 final_status = status;
  212.         }
  213.     }
  214.  
  215.     callmon$$restore_threading (&thread_state);
  216.  
  217.     return final_status;
  218. }
  219.  
  220.  
  221. /*******************************************************************************
  222.  *
  223.  *  This public routine intercepts one specific routine.
  224.  *  Use string descriptors (for non-C application).
  225.  */
  226.  
  227. uint32 callmon$intercept_dsc (
  228.     struct dsc$descriptor_s* routine_name,
  229.     callmon$intercept_t      pre_routine,
  230.     callmon$intercept_t      post_routine)
  231. {
  232.     uint32 status;
  233.     uint32 final_status;
  234.     char* routine_name_z;
  235.     routine_t* routine;
  236.     thread_state_t thread_state;
  237.  
  238.     /* Allocate a nul-terminated string on stack */
  239.  
  240.     routine_name_z = __ALLOCA (routine_name->dsc$w_length + 1);
  241.     memcpy (routine_name_z, routine_name->dsc$a_pointer,
  242.         routine_name->dsc$w_length);
  243.     routine_name_z [routine_name->dsc$w_length] = '\0';
  244.  
  245.     /* Initialize CALLMON if not yet done */
  246.  
  247.     callmon$initialize ();
  248.  
  249.     if (callmon$$own.trace_flags & TRACE_API)
  250.         callmon$$putmsg (CALLMON$_INTERCEPT, 3, 
  251.             routine_name_z, pre_routine, post_routine);
  252.  
  253.     callmon$$disable_threading (&thread_state);
  254.  
  255.     /* Find the description of the routine */
  256.  
  257.     if ((routine = callmon$$get_routine_by_name (routine_name_z)) == NULL)
  258.         final_status = CALLMON$_RNF;
  259.  
  260.     else {
  261.  
  262.         /* Hook all routines with that name */
  263.  
  264.         final_status = SS$_NORMAL;
  265.  
  266.         for (routine = routine->master_by_name;
  267.              routine != NULL;
  268.              routine = routine->next_by_name) {
  269.  
  270.             status = intercept_routine (routine, (pdsc_t*) pre_routine,
  271.                 (pdsc_t*) post_routine, 1);
  272.  
  273.             if (!$VMS_STATUS_SUCCESS (status))
  274.                 final_status = status;
  275.         }
  276.     }
  277.  
  278.     callmon$$restore_threading (&thread_state);
  279.  
  280.     return final_status;
  281. }
  282.  
  283.  
  284. /*******************************************************************************
  285.  *
  286.  *  Intercept one image.
  287.  *  Action routine for LIB$TRAVERSE_TREE on the tree of routines by value.
  288.  */
  289.  
  290. static uint32 intercept_all (libtree_t* node, intercept_ctx_t* ctx)
  291. {
  292.     routine_t* routine = BASE (routine_t, by_value, node);
  293.     uint32 status;
  294.  
  295.     /* If no routine at this address belong to this image, don't interested */
  296.  
  297.     for (routine = routine->master_by_value;
  298.          routine != NULL && routine->image != ctx->image;
  299.          routine = routine->next_by_value);
  300.  
  301.     if (routine == NULL)
  302.         return SS$_NORMAL;
  303.  
  304.     /* If routine already intercepted, override only on demand */
  305.  
  306.     if (!ctx->override && routine->jacket != NULL &&
  307.         (CLONE_PRE (routine) != 0 || CLONE_POST (routine) != 0))
  308.         return SS$_NORMAL;
  309.  
  310.     /* Hook the routine. Note that we must skip reserved routines
  311.      * without reporting an error. */
  312.  
  313.     status = intercept_routine (routine, ctx->pre_routine, ctx->post_routine,
  314.         ctx->use_desc);
  315.  
  316.     return status == CALLMON$_RESROUT ? SS$_NORMAL : status;
  317. }
  318.  
  319.  
  320. /*******************************************************************************
  321.  *
  322.  *  This public routine intercepts all routines in an image.
  323.  */
  324.  
  325. uint32 callmon$intercept_all (
  326.     char*               image_name,
  327.     callmon$intercept_t pre_routine,
  328.     callmon$intercept_t post_routine,
  329.     callmon$boolean_t   override)
  330. {
  331.     uint32 status;
  332.     intercept_ctx_t ctx;
  333.     thread_state_t thread_state;
  334.  
  335.     /* Initialize CALLMON if not yet done */
  336.  
  337.     callmon$initialize ();
  338.  
  339.     if (callmon$$own.trace_flags & TRACE_API)
  340.         callmon$$putmsg (CALLMON$_INTCPTALL, 4, 
  341.             image_name, pre_routine, post_routine,
  342.             override ? "TRUE" : "FALSE");
  343.  
  344.     callmon$$disable_threading (&thread_state);
  345.  
  346.     /* Find the description of the image */
  347.  
  348.     if ((ctx.image = callmon$$get_image (image_name)) == NULL)
  349.         status = CALLMON$_INF;
  350.  
  351.     else {
  352.  
  353.         /* Intercept all routines in this image */
  354.  
  355.         ctx.pre_routine = (pdsc_t*) pre_routine;
  356.         ctx.post_routine = (pdsc_t*) post_routine;
  357.         ctx.override = override;
  358.         ctx.use_desc = 0;
  359.  
  360.         status = lib$traverse_tree (&callmon$$own.routine_tree_by_value,
  361.             intercept_all, &ctx);
  362.     }
  363.  
  364.     callmon$$restore_threading (&thread_state);
  365.  
  366.     return status;
  367. }
  368.  
  369.  
  370. /*******************************************************************************
  371.  *
  372.  *  This public routine intercepts all routines in an image.
  373.  *  Use string descriptors (for non-C application).
  374.  */
  375.  
  376. uint32 callmon$intercept_all_dsc (
  377.     struct dsc$descriptor_s* image_name,
  378.     callmon$intercept_t      pre_routine,
  379.     callmon$intercept_t      post_routine,
  380.     callmon$boolean_t        override)
  381. {
  382.     uint32 status;
  383.     intercept_ctx_t ctx;
  384.     char* image_name_z;
  385.     thread_state_t thread_state;
  386.  
  387.     /* Allocate a nul-terminated string on stack */
  388.  
  389.     image_name_z = __ALLOCA (image_name->dsc$w_length + 1);
  390.     memcpy (image_name_z, image_name->dsc$a_pointer, image_name->dsc$w_length);
  391.     image_name_z [image_name->dsc$w_length] = '\0';
  392.  
  393.     /* Initialize CALLMON if not yet done */
  394.  
  395.     callmon$initialize ();
  396.  
  397.     if (callmon$$own.trace_flags & TRACE_API)
  398.         callmon$$putmsg (CALLMON$_INTCPTALL, 4, 
  399.             image_name_z, pre_routine, post_routine,
  400.             override ? "TRUE" : "FALSE");
  401.  
  402.     callmon$$disable_threading (&thread_state);
  403.  
  404.     /* Find the description of the image */
  405.  
  406.     if ((ctx.image = callmon$$get_image (image_name_z)) == NULL)
  407.         status = CALLMON$_INF;
  408.  
  409.     else {
  410.  
  411.         /* Intercept all routines in this image */
  412.  
  413.         ctx.pre_routine = (pdsc_t*) pre_routine;
  414.         ctx.post_routine = (pdsc_t*) post_routine;
  415.         ctx.override = override;
  416.         ctx.use_desc = 1;
  417.  
  418.         status = lib$traverse_tree (&callmon$$own.routine_tree_by_value,
  419.             intercept_all, &ctx);
  420.     }
  421.  
  422.     callmon$$restore_threading (&thread_state);
  423.  
  424.     return status;
  425. }
  426. n