[an error occurred while processing this directive]

HP OpenVMS Systems

HP Digital Continuous Profiling Infrastructure
Content starts here

Example of HP DCPI and dynamic code

The following is an example of the interaction between
an application that executes code dynamically and HP DCPI.
When you install DCPI, this example is installed on the system as 
SYS$EXAMPLES:DCPI$DYN_EXAMPLE.C
 
/*
 *
 *                         OpenVMS Alpha DCPI V2.0
 *
 *                    D C P I $ D Y N _ E X A M P L E . C
 *
 *  Copyright 2004 Hewlett-Packard Company
 *
 *  HP Registered in U.S. Patent and Trademark Office.  All other product
 *  names mentioned herein may be trademarks or registered trademarks of their
 *  respective companies.
 *
 *  Permission is granted to use or copy any part of this example program
 *  with the inclusion of the above copyright notice.
 *
 *  HP shall not be liable for technical or editorial errors or omissions
 *  contained herein.
 *
 *  The information in this publication is subject to change without notice
 *  and is provided "AS IS" WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
 *  ARISING OUT OF THE USE OF THIS INFORMATION REMAINS WITH RECIPIENT. IN NO
 *  EVENT SHALL HP BE LIABLE FOR ANY DIRECT, CONSEQUENTIAL, INCIDENTAL,
 *  SPECIAL, PUNITIVE OR OTHER DAMAGES WHATSOEVER (INCLUDING WITHOUT
 *  LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION
 *  OR LOSS OF BUSINESS INFORMATION), EVEN IF HP HAS BEEN ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
 * 
 *  The limited warranties for HP products are exclusively set forth in
 *  the documentation accompanying such products. Nothing herein should be      
 *  construed as constituting a further or additional warranty.                 
 *
 *******************************************************************************
 *
 *  Abstract:    This module provides an example of the interaction between
 *               an application that executes code "dynamically", and DCPI.
 *
 *  To Build:    The usual method for building this example is simple:
 *                   $ cc dcpi$dyn_example.c
 *                   $ link dcpi$dyn_example,sys$input/opt
 *                   dbg$dyn/shareable [^Z]
 *               where dbg$dyn points to the dbg$dyn.exe shareable image
 *
 *  Author:      HP OpenVMS Engineering
 *
 *  Creation date: 14-Dec-2001
 */

#include "dbg$dyn.h"
#include <descrip>
#include <pdscdef>
#include <ssdef>
#include <starlet>
#include <stdio>
#include <string>

#define BLOCKS     8    /* Total blocks allocated for dsts and code           */
#define BLOCKSIZE  512  /* Size in bytes of a block                           */
#define CODE_BLOCK 0    /* The starting block for the code section            */
#define DST_BLOCK  4    /* The starting block for the dst section             */

/* Macro to set a counted ascii string */
#define ASSIGN_ASCIIC(destination,source)                         \
  (destination)[0] = strlen(source);                              \
  for(int i = 0; i < strlen(source) && (source)[i] != '\0'; i++)  \
    (destination)[i + 1] = (source)[i]

/* Macro to determine a code section's length */
/* NOTE: This macro assumes zero terminated code sections because the */
/*       code sections used here are not really dynamically generated */
#define GET_CODE_SECTION_LENGTH(section, length)                       \
  for(length = 0; section[length] != 0; length++);                     \
  length *= sizeof(section[0])

/* Status checking macro */
#define check(status) if(!((status)&1)) sys$exit(status)

/* A couple useful typedefs */
typedef unsigned long instr_t;
typedef (*function_pointer)();

int
main(void)
{
  char    section_1[BLOCKS][BLOCKSIZE]; /* Some 512 byte blocks               */
  char    section_2[BLOCKS][BLOCKSIZE]; /* Some more 512 byte blocks          */
  struct pdscdef pdsc;                  /* A procedure descriptor             */
  dst$module_begin  *dst_modbeg;        /* Module Begin DST record            */
  dst$mb_trlr       *dst_mbtrlr;        /* Module Begin trailer               */
  dst$module_end    *dst_modend;        /* Module End DST record              */
  dst$routine_begin *dst_rtnbeg;        /* Routine Begin DST record           */
  dst$routine_end   *dst_rtnend;        /* Routine End DST record             */
  function_pointer ExampleRoutine1;     /* Pointer to a routine               */
  instr_t *code_section;                /* Pointer to a code section          */
  void    *dst_section;                 /* Pointer to a DST section           */
  char    *buf;                         /* General purpose pointer            */
  __int64 context;                      /* The context quadword               */
  int     code_section_length   = 1;    /* Code section length in blocks      */
  int     dst_section_length    = 1;    /* DST section length in blocks       */
  int     bytes_in_code_section = 0;    /* Size in bytes of the code section  */
  int     bytes_in_dst_section  = 0;    /* Size in bytes of the dst section   */
  int     status;                       /* Return status                      */
  int     dcpid;                        /* Is the dcpi daemon running?        */
  int     i;                            /* Loop counter                       */
  $DESCRIPTOR(facility_desc, "dyn_example"); /* Facility id string            */

  /* Fill in procedure descriptor */
  memset((void *)&pdsc, '\0', sizeof(struct pdscdef));
  pdsc.pdsc$w_flags = 0x300A;
  pdsc.pdsc$b_save_fp = 0x10;
  pdsc.pdsc$b_save_ra = 0x1A;
  pdsc.pdsc$v_func_return = 0x00;
  pdsc.pdsc$v_exception_mode = 0x02;
  pdsc.pdsc$w_signature_offset = 0x00;
  pdsc.pdsc$l_entry = (int)&section_1[CODE_BLOCK];
  pdsc.pdsc$l_size = 0x00;

  /* Setup our function pointer for later */
  ExampleRoutine1 = (function_pointer) &pdsc;

  /* This is where we write the instructions */
  memset((void *)section_1[CODE_BLOCK], '\0', BLOCKSIZE);
  code_section = (instr_t *)section_1[CODE_BLOCK];
  code_section[0]  = 0x23DEFFD0;
  code_section[1]  = 0xB77E0000;
  code_section[2]  = 0xB75E0008;
  code_section[3]  = 0xB45E0010;
  code_section[4]  = 0xB47E0018;
  code_section[5]  = 0xB7BE0020;
  code_section[6]  = 0x47FE041D;
  code_section[7]  = 0x47FF0402;
  code_section[8]  = 0x40403002;
  code_section[9]  = 0x405FF5A3;
  code_section[10] = 0xF47FFFFD;
  code_section[11] = 0x47FF0402;
  code_section[12] = 0xC3FFFFFB;
  code_section[13] = 0x47FD041E;
  code_section[14] = 0xA79E0008;
  code_section[15] = 0xA45E0010;
  code_section[16] = 0xA47E0018;
  code_section[17] = 0xA7BE0020;
  code_section[18] = 0x23DE0030;
  code_section[19] = 0x6BFC8001;
  code_section[20] = 0x00000000;

  printf("Code segment:\n");
  printf("  Starting Address: %p\n", code_section);
  printf("       End Address: %p\n", (code_section + (code_section_length * BLOCKSIZE)));

  printf("Generating DST information...");

  /* Create DST block(s)...  First, Module Begin. */
  memset((void *)section_1[DST_BLOCK], 0x00, BLOCKSIZE);
  dst_section = (void *)section_1[DST_BLOCK];
  dst_modbeg = (dst$module_begin *)dst_section;              /* Setup pointer to module begin DST record */
  dst_modbeg->dst$a_modbeg_header.dst$w_type = DST$K_MODBEG; /* Define the DST record type */
  dst_modbeg->dst$a_modbeg_header.dst$w_length = 0;          /* We don't know what the length is yet... */
  dst_modbeg->dst$v_modbeg_hide     = 0x00;                  /* Hide this module from the SHOW MODULE command */
  dst_modbeg->dst$v_modbeg_version  = 0x01;                  /* This record contains the DST$L_VERSION field */
  dst_modbeg->dst$v_modbeg_unused   = 0x00;                  /* This is unused */
  dst_modbeg->dst$b_modbeg_unused   = 0x00;                  /* This is unused */
  dst_modbeg->dst$l_modbeg_language = DST$K_C;               /* This module was written in C */
  dst_modbeg->dst$w_version_major   = DST$K_VERSION_MAJOR;   /* Major ID      */
  dst_modbeg->dst$w_version_minor   = DST$K_VERSION_MINOR;   /* Minor ID      */
  buf = (char *)&dst_modbeg->dst$b_modbeg_name;
  ASSIGN_ASCIIC(buf, "ExampleModule1");           /* The name of the module   */

  /* Setup the Module Begin record's "trailer" */
  dst_mbtrlr = (dst$mb_trlr *)((__int64)&section_1[DST_BLOCK] + sizeof(dst$module_begin) + dst_modbeg->dst$b_modbeg_name);
  buf = (char *)&dst_mbtrlr->dst$b_compiler;
  ASSIGN_ASCIIC(buf, "Compaq C V6.2-003");        /* The name of the compiler */

  /* Now that we know what the record looks like we can define its size in the Module Begin header */
  dst_modbeg->dst$a_modbeg_header.dst$w_length = sizeof(dst$module_begin) + dst_modbeg->dst$b_modbeg_name +
                                                 sizeof(dst$mb_trlr) + dst_mbtrlr->dst$b_compiler - 1;
  bytes_in_dst_section += sizeof(dst$module_begin) + sizeof(dst$mb_trlr) +
                          dst_modbeg->dst$b_modbeg_name + dst_mbtrlr->dst$b_compiler;

  /* Routine Begin */
  dst_rtnbeg = (dst$routine_begin *)((__int64)dst_modbeg + dst_modbeg->dst$a_modbeg_header.dst$w_length + 1);
  dst_rtnbeg->dst$a_rtnbeg_header.dst$w_type = DST$K_RTNBEG; /* Define the DST record type */
  dst_rtnbeg->dst$a_rtnbeg_header.dst$w_length = 0;          /* We don't know what the length is yet... */
  dst_rtnbeg->dst$b_rtnbeg_flags = 0x80;                     /* Some flags */
  dst_rtnbeg->dst$l_rtnbeg_address = (int *)code_section;    /* Start address of routine */
  dst_rtnbeg->dst$l_rtnbeg_pd_address = 0x00000000;          /* Address of routine's procedure descriptor */
  buf = (char *)&dst_rtnbeg->dst$b_rtnbeg_name;
  ASSIGN_ASCIIC(buf, "ExampleRoutine1");                     /* The name of the routine */
  dst_rtnbeg->dst$a_rtnbeg_header.dst$w_length = sizeof(dst$routine_begin) + dst_rtnbeg->dst$b_rtnbeg_name - 1;
  bytes_in_dst_section += sizeof(dst$routine_begin) + dst_rtnbeg->dst$b_rtnbeg_name;

  /* Routine End */
  dst_rtnend = (dst$routine_end *)((__int64)dst_rtnbeg + dst_rtnbeg->dst$a_rtnbeg_header.dst$w_length + 1);
  dst_rtnend->dst$a_rtnend_header.dst$w_type   = DST$K_RTNEND;
  dst_rtnend->dst$a_rtnend_header.dst$w_length = sizeof(dst$routine_end) - 1;
  dst_rtnend->dst$b_rtnend_unused = 0x00;
  GET_CODE_SECTION_LENGTH(code_section, dst_rtnend->dst$l_rtnend_size);
  bytes_in_dst_section += sizeof(dst$routine_end);

  /* Module End */
  dst_modend = (dst$module_end *)((__int64)dst_rtnend + dst_rtnend->dst$a_rtnend_header.dst$w_length + 1);
  dst_modend->dst$a_modend_header.dst$w_type   = DST$K_MODEND;
  dst_modend->dst$a_modend_header.dst$w_length = sizeof(dst$module_end) - 1;
  bytes_in_dst_section += sizeof(dst$module_end);

  printf("...Done\n");

  bytes_in_code_section = code_section_length * BLOCKSIZE;

  printf("Making first dbg$dyn_begin call\n");

  status = dbg$dyn_begin(&facility_desc, bytes_in_code_section, code_section,
                bytes_in_dst_section, dst_section, &context);

  /* Continue execution if the dcpi daemon isn't around */
  if(status != SS$_NOLOGNAM)
    check(status);

  printf("Creating new code section\n");

  /* Now we create a new code section */
  memset((void *)section_2[CODE_BLOCK], '\0', BLOCKSIZE);
  code_section = (instr_t *)section_2[CODE_BLOCK];
  code_section[0]  = 0x23DEFFA0;
  code_section[1]  = 0xB7FE0008;
  code_section[2]  = 0xB77E0000;
  code_section[3]  = 0xB75E0048;
  code_section[4]  = 0xB45E0050;
  code_section[5]  = 0xB7BE0058;
  code_section[6]  = 0x63FF0000;
  code_section[7]  = 0x47FE041D;
  code_section[8]  = 0x23DEFFE0;
  code_section[9]  = 0xB7FE0000;
  code_section[10] = 0x47FB0402;
  code_section[11] = 0xB21D0044;
  code_section[12] = 0xB23D0040;
  code_section[13] = 0xB25D003C;
  code_section[14] = 0xB27D0038;
  code_section[15] = 0xB29D0034;
  code_section[16] = 0xB2BD0030;
  code_section[17] = 0x203F2000;
  code_section[18] = 0xB43D0008;
  code_section[19] = 0x22FD0028;
  code_section[20] = 0x231D0024;
  code_section[21] = 0x233D0020;
  code_section[22] = 0xB6FE0000;
  code_section[23] = 0xB71E0008;
  code_section[24] = 0xB73E0010;
  code_section[25] = 0xA21D0044;
  code_section[26] = 0xA23D0040;
  code_section[27] = 0xA25D003C;
  code_section[28] = 0xA27D0038;
  code_section[29] = 0xA29D0034;
  code_section[30] = 0xA2BD0030;
  code_section[31] = 0x47E13419;
  code_section[32] = 0xA7420048;
  code_section[33] = 0xA7620050;
  code_section[34] = 0x6B5A6AF1;
  code_section[35] = 0x2362FFE8;
  code_section[36] = 0xD340000C;
  code_section[37] = 0x47E00410;
  code_section[38] = 0x47E03419;
  code_section[39] = 0xA7420038;
  code_section[40] = 0xA7620040;
  code_section[41] = 0x6B5A501E;
  code_section[42] = 0x63FF0000;
  code_section[43] = 0x47FD041E;
  code_section[44] = 0xA75D0048;
  code_section[45] = 0xA45D0050;
  code_section[46] = 0xA7BD0058;
  code_section[47] = 0x23DE0060;
  code_section[48] = 0x6BFA8001;
  code_section[49] = 0x47FD0410;
  code_section[50] = 0x47FB041D;
  code_section[51] = 0x47FF0400;
  code_section[52] = 0x40003000;
  code_section[53] = 0x20208597;
  code_section[54] = 0xF43FFFFD;
  code_section[55] = 0x47FF0400;
  code_section[56] = 0xC3FFFFFB;
  code_section[57] = 0x00000000;

  printf("Code segment:\n");
  printf("  Starting Address: %p\n", code_section);
  printf("       End Address: %p\n", (code_section + (code_section_length * BLOCKSIZE)));

  printf("Calling dyn_add with new code segment information\n");

  bytes_in_code_section = code_section_length * BLOCKSIZE;
  status = dbg$dyn_add(DBG$K_DYNCODESEC, bytes_in_code_section, code_section, &context);

  /* Continue execution if the dcpi daemon isn't around */
  if(status != SS$_NOLOGNAM)
    check(status);

  printf("Generating new DST information...");

  /* Create DST block(s)...  First, Module Begin. */
  memset((void *)section_2[DST_BLOCK], 0x00, BLOCKSIZE);
  dst_section = (void *)section_2[DST_BLOCK];
  dst_modbeg = (dst$module_begin *)dst_section;              /* Setup pointer to module begin DST record */
  dst_modbeg->dst$a_modbeg_header.dst$w_type = DST$K_MODBEG; /* Define the DST record type */
  dst_modbeg->dst$a_modbeg_header.dst$w_length = 0;          /* We don't know what the length is yet... */
  dst_modbeg->dst$v_modbeg_hide     = 0x00;                  /* Hide this module from the SHOW MODULE command */
  dst_modbeg->dst$v_modbeg_version  = 0x01;                  /* This record contains the DST$L_VERSION field */
  dst_modbeg->dst$v_modbeg_unused   = 0x00;                  /* This is unused */
  dst_modbeg->dst$b_modbeg_unused   = 0x00;                  /* This is unused */
  dst_modbeg->dst$l_modbeg_language = DST$K_C;               /* This module was written in C */
  dst_modbeg->dst$w_version_major   = DST$K_VERSION_MAJOR;   /* Major ID      */
  dst_modbeg->dst$w_version_minor   = DST$K_VERSION_MINOR;   /* Minor ID      */
  buf = (char *)&dst_modbeg->dst$b_modbeg_name;
  ASSIGN_ASCIIC(buf, "ExampleModule2");           /* The name of the module   */

  /* Setup the Module Begin record's "trailer" */
  dst_mbtrlr = (dst$mb_trlr *)((__int64)&section_2[DST_BLOCK] + sizeof(dst$module_begin) + dst_modbeg->dst$b_modbeg_name);
  buf = (char *)&dst_mbtrlr->dst$b_compiler;
  ASSIGN_ASCIIC(buf, "Compaq C V6.2-003");        /* The name of the compiler */

  /* Now that we know what the record looks like we can define its size in the Module Begin header */
  dst_modbeg->dst$a_modbeg_header.dst$w_length = sizeof(dst$module_begin) + dst_modbeg->dst$b_modbeg_name +
                                                 sizeof(dst$mb_trlr) + dst_mbtrlr->dst$b_compiler - 1;
  bytes_in_dst_section += sizeof(dst$module_begin) + sizeof(dst$mb_trlr) +
                          dst_modbeg->dst$b_modbeg_name + dst_mbtrlr->dst$b_compiler;


  /* Routine Begin */
  dst_rtnbeg = (dst$routine_begin *)((__int64)dst_modbeg + dst_modbeg->dst$a_modbeg_header.dst$w_length + 1);
  dst_rtnbeg->dst$a_rtnbeg_header.dst$w_type = DST$K_RTNBEG; /* Define the DST record type */
  dst_rtnbeg->dst$a_rtnbeg_header.dst$w_length = 0;          /* We don't know what the length is yet... */
  dst_rtnbeg->dst$b_rtnbeg_flags = 0x80;                     /* Some flags */
  dst_rtnbeg->dst$l_rtnbeg_address = (int *)code_section;    /* Start address of routine */
  dst_rtnbeg->dst$l_rtnbeg_pd_address = 0x00000000;          /* Address of routine's procedure descriptor */
  buf = (char *)&dst_rtnbeg->dst$b_rtnbeg_name;
  ASSIGN_ASCIIC(buf, "ExampleRoutine2");                     /* The name of the routine */
  dst_rtnbeg->dst$a_rtnbeg_header.dst$w_length = sizeof(dst$routine_begin) + dst_rtnbeg->dst$b_rtnbeg_name - 1;
  bytes_in_dst_section += sizeof(dst$routine_begin) + dst_rtnbeg->dst$b_rtnbeg_name;

  /* Routine End */
  dst_rtnend = (dst$routine_end *)((__int64)dst_rtnbeg + dst_rtnbeg->dst$a_rtnbeg_header.dst$w_length + 1);
  dst_rtnend->dst$a_rtnend_header.dst$w_type   = DST$K_RTNEND;
  dst_rtnend->dst$a_rtnend_header.dst$w_length = sizeof(dst$routine_end) - 1;
  dst_rtnend->dst$b_rtnend_unused = 0x00;
  GET_CODE_SECTION_LENGTH(code_section, dst_rtnend->dst$l_rtnend_size);
  bytes_in_dst_section += sizeof(dst$routine_end);

  /* Module End */
  dst_modend = (dst$module_end *)((__int64)dst_rtnend + dst_rtnend->dst$a_rtnend_header.dst$w_length + 1);
  dst_modend->dst$a_modend_header.dst$w_type   = DST$K_MODEND;
  dst_modend->dst$a_modend_header.dst$w_length = sizeof(dst$module_end) - 1;
  bytes_in_dst_section += sizeof(dst$module_end);

  printf("...Done\n");

  printf("Calling dyn_add with new DST information\n");
  status = dbg$dyn_add(DBG$K_DYNDSTSEC, bytes_in_dst_section, dst_section, &context);

  /* Continue execution if the dcpi daemom is not around */
  if(status != SS$_NOLOGNAM)
    check(status);

  /* When we're finished do the following */
  printf("Ending (dbg$dyn_end)\n");
  status = dbg$dyn_end(&context);

  /* Continue execution if the dcpi daemon is not around */
  if(status != SS$_NOLOGNAM)
    check(status);

  printf("Calling ExampleRoutine1...\n");
  ExampleRoutine1();

  return(SS$_NORMAL);
}

 

 



Comments
Last modified: April 8, 2004