[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::debug

Title:DEBUG
Notice:Updated locations for reporting QARs -- see note 834.1
Moderator:LOWFAT::DIETER
Created:Fri Jan 24 1986
Last Modified:Wed Jun 04 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1868
Total number of notes:8200

1830.0. "Subroutine actual parameter debugger stepping" by SZAJBA::VOUTERS (Philippe VOUTERS, Evry (France)) Thu Jan 30 1997 09:11

Hello,

It looks like it is a common AXP compilers policy in Digital to step with the
debugger on each parameter of a multi-line subroutine call. This brings a
problem for a customer here in France. Can a multi-line subroutine call
be stepped entirely at once without setting a new breakpoint ? Is there
some option inside the debugger ? I do not know of any workaround.

Thank in advance you for any hints.
Best regards,
Philippe Vouters (MCS France)
PS: Tested on OpenVMS AXP V6.2
    
Fortran Program linked with C code in next reply:

	PROGRAM TEST

	PARAMETER LONG_LENGTH = 0
	PARAMETER WORD_LENGTH = 1
	PARAMETER BYTE_LENGTH = 2
	PARAMETER OCTAL = 0
	PARAMETER DECIMAL = 1
	PARAMETER HEXADECIMAL = 2
	PARAMETER BINARY = 3
        CHARACTER*40 BUFFER

        BUFFER(1:25) = 'Hello from Digital France'
        CALL DUMP_BUFFER(%DESCR(BUFFER),
     1			 %VAL(%LOC (BUFFER)),
     2			 %VAL(OCTAL),
     3			 %VAL(BYTE_LENGTH))
	END

Result of debugger log file :

Step
!stepped to TEST\%LINE 12
!    12:         BUFFER(1:25) = 'Hello from Digital France'
Step
!stepped to TEST\%LINE 14
!    14:      1                   %VAL(%LOC (BUFFER)),
Step
!stepped to TEST\%LINE 13
!    13:         CALL DUMP_BUFFER(%DESCR(BUFFER),
Step
!stepped to TEST\%LINE 15
!    15:      2                   %VAL(OCTAL),
Step
!stepped to TEST\%LINE 16
!    16:      3                   %VAL(BYTE_LENGTH))
Step
!stepped to TEST\%LINE 13
!    13:         CALL DUMP_BUFFER(%DESCR(BUFFER),
Step
!stepped to TEST\%LINE 17
!    17:         END
exit

T.RTitleUserPersonal
Name
DateLines
1830.1DBGDMP.C needed for Fortran programSZAJBA::VOUTERSPhilippe VOUTERS, Evry (France)Thu Jan 30 1997 09:13415
/*
                             COPYRIGHT (C) 1994 BY
                       DIGITAL EQUIPMENT CORPORATION, MAYNARD
                        MASSACHUSETTS.  ALL RIGHTS RESERVED.

     THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
     ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION
     OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY OTHER COPIES
     THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER
     PERSON.  NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.

     THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
     SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.

     DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
     SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.

     NO RESPONSIBILITY IS ASSUMED FOR THE USE OR RELIABILITY OF SOFTWARE
     ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL EQUIPMENT CORPORATION.

     SUPPORT FOR THIS SOFTWARE IS NOT COVERED UNDER ANY DIGITAL SOFTWARE
     PRODUCT SUPPORT CONTRACT, BUT MAY BE PROVIDED UNDER THE TERMS OF THE
     CONSULTING AGREEMENT UNDER WHICH THIS SOFTWARE WAS DEVELOPED.

*/
#pragma module dbgdmp "V1.0-00"

#include <starlet.h>   		/* defines system services */
#include <lib$routines>		/* defines the lib$ rtl routines */
#include <descrip.h>            /* defines the various descriptors offsets */
#include <string.h>		/* for the memcpy call */
#include <stdlib.h>		/* for the malloc, free, exit calls */
#include <stdio.h>              /* for the printf call */

struct ascic {
   unsigned char len;
   char faostr[3];
};

/* Define length of data to be dumped */
typedef enum {LONG_LENGTH,WORD_LENGTH,BYTE_LENGTH} length;

/* Define radices */
typedef enum {OCTAL,DECIMAL,HEXADECIMAL,BINARY} radices;

#define dump$c_maxlisiz 80	/* Maximum screen's output size */
#define max_fao_size 40		/* Size of largest of faotables' expanded fao strings */
#define screenwidth 80		/* Width of one full dump listing line */
#define maxlines 20

#define CH$COPY(bytesleft,buffer,a,bytesperline,tempbuffer)     \
	lib$movc5 (&(bytesleft),(buffer),&(a),&(bytesperline),(tempbuffer));

#define CH$MOVE(length,pointer1,pointer2)			\
	memcpy ((pointer2),(pointer1),(length));                 		

#define CH$FILL(bytefill,padlength,pointer)                     \
{ char *src; 							\
   for (src=(pointer);src<(pointer)+(padlength);src++)		\
	 *src=(bytefill);}

#define cstring(data,string)					\
{ char *src,*start,*dst = (data).faostr;			\
   for (src=start=(string); *src !='\0';src++)			\
        *dst++ = *src;                                          \
   (data).len = src - start;					\
}


void dump$fao_line(char *buff,int numentperline,int size,
		   int byte_offset,int num_entries,int format,
		   struct dsc$descriptor_s *fao,
		   struct dsc$descriptor_s *outbuff,
		   unsigned char binary_dump)
{
  int i,j;
  unsigned char *cp;
  unsigned short *cp1;
  unsigned long *cp2 ;
  unsigned long *ptr;
  unsigned long *ptr1;
  unsigned char *ptr2;
  int min;
  int bit_length;
  unsigned char *start_of_ptr2;

  /* get the minimum of numentperline and num_entries */
  min = (numentperline < num_entries ? numentperline : num_entries);

  /* allocate a dynamic buffer which hold the values to be converted by the
   * sys$faol routine.
   */
  if (binary_dump)
      ptr = (unsigned long *) malloc ((3+2*numentperline)*sizeof(unsigned long));
  else
      ptr = (unsigned long *) malloc ((3+numentperline*size)*sizeof(unsigned long));

  /* intialize the buffer to all zero's. */
  for (i=0; i < 3 + numentperline*size; i++) ptr[i] = 0;

  /* For binary format dumping set up the bit length
   * and allocates a buffer that will hold the bit value to ASCII
   * representation '0' or '1'. Do not forget the space separator (+1)
   */
  if (binary_dump){
       switch (format) {
	case 0 : bit_length = 32;
		 break;
	case 1 : bit_length = 16;
		 break;
	case 2 : bit_length = 8;
	}
      ptr2= (unsigned char *)malloc(numentperline*(bit_length+1));
      start_of_ptr2 = ptr2;
  }
  /*
   * ptr value will be modified by increments. For the sys$faol and the free
   * calls save ptr. Copy each byte to a longword, each word to a longword
   * and each longword to a longword depending on the format. In order to
   * to display data from right to left like the dump command setup the
   * pointer to the last data and decrement it. When displayed this will
   * give a reading a dumped data from rigth to left. For a binary dump,
   * the highest bit must be displayed first and lower bit last.
   */
  ptr1 = ptr;
  if (!(binary_dump)){
      switch (format) {
	case 0 : cp2 = (unsigned long *)buff+ min -1;
		 for (i=0;i<min;i++)
			*ptr++ = *cp2--;
		 break;
	case 1 : cp1 = ((unsigned short *)buff)+ min -1;
		 for (i=0;i<min;i++){
			*ptr = (unsigned long)(*cp1--);
			ptr++;
			}
                 break;
	case 2 : cp = (unsigned char *)buff+min-1;
		 for (i=0;i<min;i++) {
			*ptr = (unsigned long) (*cp--);
			ptr++;
		}
      }/* end switch */
   }
  else {
      switch (format) {
	case 0 : cp2 = (unsigned long *)buff+ min -1;
  		 for (i=0;i<min;i++){
			for (j=0;j<bit_length;j++)
				*ptr2++ = (((*cp2<<j) & (1<<(bit_length-1)))
						>>(bit_length-1)) + '0';
			cp2--;
                        *ptr2++ = ' ';
			}
  		 break;
	case 1 : cp1 = ((unsigned short *)buff)+ min -1;
		 for (i=0;i<min;i++){
			for (j=0;j<bit_length;j++)
				*ptr2++ = (((*cp1<<j) & (1<<bit_length))
						>>(bit_length-1)) + '0';
			cp1--;
                        *ptr2++ = ' ';
			}
                 break;
	case 2 : cp = (unsigned char *)buff+min-1;
		 for (i=0;i<min;i++) {
			for (j=0;j<bit_length;j++)
				*ptr2++ = (((*cp<<j) & (1<<(bit_length-1)))
						>>(bit_length-1)) + '0';
			cp--;
                        *ptr2++ = ' ';
			}
      }/* end switch */
      for (i=0;i<min;i++){
        *ptr++ = bit_length+1;
	*ptr++ = (unsigned long)(start_of_ptr2 + (bit_length+1)*i);
	}
  }

  /*
   * This last three arguments are expected by the FAO directive. Include them
   */
  *ptr++ = (unsigned long)byte_offset;
  *ptr++ = (unsigned long)numentperline*size;
  *ptr++ = (unsigned long)(buff);
  ptr = ptr1;

  /*
   * The fao directive is contained in the variable fao (passed by descriptor)
   * The output buffer when sys$faol will store the result is contained in
   * outbuff and ptr is a buffer containing data to be converted to ASCII.
   */
  sys$faol (fao,outbuff,outbuff,ptr);
  if (binary_dump)
      free (start_of_ptr2);
  free (ptr1);
}

void dump_buffer (struct dsc$descriptor_s *bufdesc, unsigned int mem_address,
		    int radix,int length)
{
     struct ascic offtable[4] ;
     struct ascic *faotable;
     $DESCRIPTOR(descr0,"!!!ZL(!AC) |!!!AC| !!!ZLAF");
     $DESCRIPTOR(descr1,"!!!!!!ZL(!AC) |!!!!!AC| !!!!!ZLAF");
     struct dsc$descriptor_s dump$gl_outdesc = {
	0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
     char dump$ab_outbuf [dump$c_maxlisiz];
     struct dsc$descriptor_s buffer_desc ;
     char tempbuffer [512]; 
     struct dsc$descriptor_s tempdesc ;
     char tempfaobuf [max_fao_size];
     int additional;
     int padbytes;
     char *buffer;
     char *bufferpointer;
     struct dsc$descriptor_s *faopointer;
     int buffer_length;
     unsigned short bytesperline;
     unsigned short bytesleft;
     int dumpmode;
     int dumpwidth;
     int mempointer = mem_address;
     int modeindex;			/* Index into faotable  */
     int number;
     unsigned int entry;
     int entrysize;			/* Size of one entry */
     int entsinbuf;
     int entsperline;			/* Number of entries on one line */
     char plinfaostring [max_fao_size];	/* FAO string for partial lines  */
     struct dsc$descriptor_s plinfaodesc = {    	/* Desciptor for partial line fao control string */
	0,DSC$K_DTYPE_T, DSC$K_CLASS_S,0};
     char faoctrstring [max_fao_size]; 	/* FAO control string */
     struct dsc$descriptor_s faoctrdesc =	{	/* FAO control string descriptor */
	0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; 
   int sizetbl[12] = {9,5,3,11,6,4,12,7,4,33,17,9};
   int charsperbyte[4] = {2,3,3,8}; /* Number of ascii chars/byte based on radix */
   int sizetable[11] = {
                        1,                      /* Table to round entry's per */
			2,                      /* line to nearest lower power*/
			4,                      /* of two.  Max length is 32. */
			8,
			16,
			32,
			64,
			128,
			256,
			512,
			1024};

   /* ! FAO control to print buffer offsets */
   cstring(offtable[0],"9XL");
   cstring(offtable[1],"SL");
   cstring(offtable[2],"9OL");
   cstring(offtable[3],"9AF");

   /*
    * The faotable contains in the order an longword, word and byte format
    * for the hexadecimal, decimal, octal, binary radices.
    */
   faotable = (struct ascic *) malloc (12*sizeof(struct ascic));
   cstring(faotable[0],"9XL"); /* Longword hexadecimal */
   cstring(faotable[1],"5XW"); /* Word hexadecimal */
   cstring(faotable[2],"3XB"); /* Byte hexadecimal */
   cstring(faotable[3],"11SL");/* longword decimal */
   cstring(faotable[4],"6SW"); /* word decimal */
   cstring(faotable[5],"4SB"); /* byte decimal */
   cstring(faotable[6],"12OL");/* Longword octal */
   cstring(faotable[7],"7OW"); /* word octal */
   cstring(faotable[8],"4OB"); /* byte octal */
   cstring(faotable[9],"AD");  /* Longword binary */
   cstring(faotable[10],"AD"); /* word binary */
   cstring(faotable[11],"AD"); /* byte binary */

  plinfaodesc.dsc$w_length =  max_fao_size;
  plinfaodesc.dsc$a_pointer = (char *)plinfaostring;
  faoctrdesc.dsc$w_length = max_fao_size;
  faoctrdesc.dsc$a_pointer = (char *)faoctrstring; 
  entry = 0;			/* used for entry size calc.*/
  if (radix == DECIMAL)
      modeindex = 3;            /* modeindex index of faotable */
  else if (radix == OCTAL)
      modeindex = 6;
  else if (radix == BINARY)
      modeindex = 9;
  else
      modeindex = 0;		/* Default to hex dump */

  if  (length == LONG_LENGTH) {
      dumpmode = 0;  /* Dumpmode is the format in dump$fao_line */
      entrysize = 4; /* A longword is 4 bytes */
      }
  else if (length == WORD_LENGTH){
      entrysize = 2;
      dumpmode = 1;
      modeindex = modeindex + 1;
      }
  else if (length == BYTE_LENGTH){
      entrysize = 1;
      dumpmode = 2;
      modeindex = modeindex + 2;
      }

  /* Find entries per line and make it the nearest lower power of 2.
  */
  entsperline = ((screenwidth - 7)/(sizetbl[modeindex]+entrysize))& (~1);

  if (entsperline > 64 )	/* Make sure entsperline is reasonable */
  {
      printf ("DBGDMP\\DUMP_BUFFER\\ entsperline greater than 64\n");
      return;
  }
  if (entsperline == 0)
      entry = 1;

  while (entsperline >= sizetable[entry]) 	/* Find nearest largest power of 2 */
       entry = entry + 1;			/* from entsperline. */

  entsperline = sizetable[entry-1];	 	/* Make entsperline nearest lower */
						/* power of two. */
  dumpwidth = entsperline*(sizetbl[modeindex] + entrysize) + 8 + 5; 

  faoctrdesc.dsc$w_length = max_fao_size;

  /*
   * convert the fao directive contained in descr0 to a simpler fao directive
   * that contains the correct number of entries and the radix.
   * This is for plain lines (i.e. lines not completed by spaces)
   */
  sys$fao(&descr0,
          &faoctrdesc,
          &faoctrdesc,
          entsperline,
      	  &faotable[modeindex],
          &offtable[0],
          entsperline * entrysize);

  /* Set up FAO control string to be used for partial lines.
  */
  sys$fao(&descr1,
	  &plinfaodesc,
          &plinfaodesc,
          &faotable[modeindex],
          &offtable[0],
          entsperline * entrysize);

  number = 0;
  buffer = bufdesc->dsc$a_pointer;
  dump$gl_outdesc.dsc$a_pointer = dump$ab_outbuf;
  dump$gl_outdesc.dsc$w_length = dump$c_maxlisiz;
  faopointer = &faoctrdesc;
  bytesperline = entsperline*entrysize;
  entsinbuf = ((bufdesc->dsc$w_length + entrysize - 1)
			& (~(entrysize-1)))/entrysize;
  bytesleft = bufdesc->dsc$w_length;
  while (entsinbuf > 0) {
      if (bytesleft < bytesperline) {
          /* Copy partial line, zero fill to end */
	  CH$COPY(bytesleft,buffer +number,0,bytesperline,tempbuffer); 
	  /* Set up work area for partial lines  */
          tempdesc.dsc$w_length = max_fao_size;                           
	  tempdesc.dsc$a_pointer = tempfaobuf;
          /* Set up fao with # of entries for partial line */ 
	  sys$fao(&plinfaodesc,&tempdesc,&tempdesc,entsinbuf);      	  
	  /* Use this fao control string instead  */
	  faopointer = &tempdesc;                                          
	  bufferpointer = tempbuffer;
	  /* Set output length to default value  */ 
	  dump$gl_outdesc.dsc$w_length = screenwidth;	               
	  /* Format the output line */
          dump$fao_line(bufferpointer,entsperline,entrysize,           
		mempointer+number,entsinbuf,dumpmode,faopointer,
		&dump$gl_outdesc,(radix==BINARY));
          additional = 0;
          /* Calculate padding (word offset)*/ 
	  padbytes = dumpwidth - dump$gl_outdesc.dsc$w_length;         
          if (!(radix == DECIMAL)){
	      /* Find additional offset */ 
              if ((additional = bytesleft % entrysize) > 0)          
                    {
		     /* Customize it to type of dump */
	             additional = (entrysize - additional) *           
                                 charsperbyte[modeindex/3] + 1;
                     padbytes = padbytes + additional;
                    }
          }
          CH$MOVE(dump$gl_outdesc.dsc$w_length - additional,
                  dump$gl_outdesc.dsc$a_pointer + additional,
                  dump$gl_outdesc.dsc$a_pointer + padbytes);
	  /* Move blanks to pad areas */
          CH$FILL(' ',padbytes,dump$gl_outdesc.dsc$a_pointer);       
          /* Set output length to  */
	  dump$gl_outdesc.dsc$w_length = dumpwidth;                  
          }                                                           
      else
	  {
	  /* Dump full line */
	  bufferpointer = &buffer[number];                             
	  /* Set output length to default value */
	  dump$gl_outdesc.dsc$w_length = screenwidth ;                 
          /* Format the output line */
	  dump$fao_line(bufferpointer,entsperline,entrysize,           
                  mempointer+number,entsinbuf,dumpmode,faopointer,
		  &dump$gl_outdesc,(radix == BINARY));
          }
      printf ("\n%.*s",dump$gl_outdesc.dsc$w_length,dump$gl_outdesc.dsc$a_pointer);
      /* Calculate next index */
      number = number + bytesperline;				       
      /* Update # of entry's in buffer */
      entsinbuf = entsinbuf - entsperline;			       
      /* Calculate how many bytes left in buffer */
      bytesleft = bytesleft - (entsperline*entrysize);                 
      }
   free (faotable);
}
1830.2LOWFAT::DIETERFri Jan 31 1997 09:1952
Hi Philippe -

How about STEP/CALL?

  STEP

    Qualifiers

      /CALL

         Executes the program to the next call or return instruction. STEP
         /CALL has the same effect as SET BREAK/TEMPORARY/CALL;GO.



for example:

DBG> rerun
%DEBUG-I-INITIAL, Language: FORTRAN, Module: TEST
DBG> s
stepped to TEST\%LINE 12
    12:         BUFFER(1:25) = 'Hello from Digital France'
DBG> s
stepped to TEST\%LINE 14
    14:      1                   %VAL(%LOC (BUFFER)),
DBG> step/call
stepped to TEST\%LINE 13+12:    BSR             R26,#X0001E0
    13:         CALL DUMP_BUFFER(%DESCR(BUFFER),


They would probably have to use it selectively.  That is, they STEP/LINE
until they get to the line which loads the first parameter (in this case, 
line 14) and then, once they are there, they can STEP/CALL to skip over
the loading of the remainder of the parameters.

Of course, they could STEP/CALL all the time, but this would 'skip' some
lines -- that is, you would only be breaking at call instructions, for 
example:

DBG> rerun
%DEBUG-I-INITIAL, Language: FORTRAN, Module: TEST
DBG> step/instru/call
stepped to TEST\%LINE 12+16:    JSR             R26,(R26)
    12:         BUFFER(1:25) = 'Hello from Digital France'
DBG> step/instru/call
stepped to TEST\%LINE 13+12:    BSR             R26,#X0001E0
    13:         CALL DUMP_BUFFER(%DESCR(BUFFER),



Mary
1830.3Multi-line statement stepping ?AUBER::VOUTERSPhilippe VOUTERS, Evry (France)Tue Feb 04 1997 09:0631
Hello Mary,

The STEP/CALL then STEP/OVER made the trick. Many thanks for this. I have
another problem on AXP. I do not know how many steps (STEP n) to compute SUM
without SETting a BREAKPOINT on line containing the RETURN. Do not use
STEP/RETURN. On VAX you arrive on the RETURN in two keypad 0 keypress.
Do you have a solution for this one.

Many thanks in advance for an hint.
Very best regards,
Philippe

        PROGRAM TEST
        REAL*4 X,Y

	X = 5.0
	Y = 2.0**2
        Y  = SUM(2.0*Y,
     1		 4*x,
     2		- 5,
     3           x*y,
     4           2*x)
	END
	FUNCTION SUM (a,b,c,d,e)
        SUM=a
     1	  + b
     2    + c
     3    + d
     4    +e
        RETURN
        END
1830.4huh?SSPADE::SSPADE::HILDEMon Feb 10 1997 10:2751
Why not use STEP/RET?  Why do they need to know how many steps?  The number
of steps could easily vary with compiler version.  Note that with RISC
machine like AXP, the compilers have many more choices to make on how to
"package" machine instructions (many more instructions per line) into lines.
This is good for performance optimizations...and some optimization seems
to creep through even with the /NOOPT switch.  Look at the .LIS file created
by the compiler with /LIST/MACHINE switchs...that should show you how the
compiler has organized the instructions and lines.  Also, from the debugger
source and instruction view:


    12:         FUNCTION SUM (a,b,c,d,e)
    13:         SUM=a
    14:      1    + b
    15:      2    + c
    16:      3    + d
    17:      4    +e
->  18:         RETURN
    19:         END

    Line    12:         BIS             R31,FP,R24
              :         BIS             R31,R27,FP
              :         BIS             R31,R16,R23
              :         BIS             R31,R17,R22
              :         BIS             R31,R18,R21
              :         BIS             R31,R19,R1
              :         BIS             R31,R20,R0
    Line    13:         LDF             F0,(R23)
    Line    14:         LDF             F10,(R22)
    Line    13:         ADDF            F0,F10,F0
    Line    15:         LDF             F11,(R21)
    Line    13:         ADDF            F0,F11,F0
    Line    16:         LDF             F10,(R1)
    Line    13:         ADDF            F0,F10,F0
    Line    17:         LDF             F11,(R0)
    Line    13:         ADDF            F0,F11,F1
->  Line    18:         CPYS            F1,F1,F0
              :         BIS             R31,R24,FP
              :         RET             R31,(R26)


You can see that the compiler has organized the first LDF and all the ADDFs
into line 13 and all the remaining LDFs into separte lines.  The point is,
that you're issue needs to be taken to the compiler folks.  The debugger is
merely stepping the lines that the compiler generated.  I nonetheless feel
that this is just one of the "things" to get used to with this newer RISCer
archetecture.

Lon