summaryrefslogblamecommitdiff
path: root/misc/pascal/insn16/prun/pdbg.c
blob: c617359c726411462769354f0ad397e44faf8249 (plain) (tree)


















































                                                                         


















                                                                         
               

















                 
               
  




                                








                                                                         

                                             




                                                                         














                                                                                      










                                                                         
                                                
                                                     




                                                                                 

                                                                          


                                                                           
                                                               
                              
                                                              
                                  

                                                                   

                    
                                       







                                                                         
             








                          

                                                

                   
                                          





















                                                 
                                          
                                           

                                                     

                                             
                                                 








                                                
                                          






                                                   

                                                     

                                                 

                                                     

                                                
                                               







                                                
                                               






                                              
                                                        



































                                                                          
                                                                                   


                                                              

                       








                                       
                             







                                              
                               





                                               

                                     


           
                                   

                           
                        


                               
                                



                                           
                                              

                                            
                                 



                                                      
                                 







                                             
                                                     





                                                 
                                 












                                                   
                                 


           
                                                                        





                                                   
                                 


           
                                                                       











                                                
                             






















                                                                          
                                                           





















                                                              
                                 




















                                                                          
                                                                            

             
                 

                  
                                                       
      
                                 
 




                                          




                                   
                    








                                          
                       










                                               
                    


                    
             





                                                                          
                                                                            
  
              
 
                                                  
      

                                                        
 



                                                                   


                   
                                    

                     
             














                                                                          
                             


                                                     
                 

              
                                                           


                                  
                                                               

                                
                                                                

                                                                  
                                                              











                                                                          
                                          




                                              
                                         


                                                        
                                           
          
                                     








                                                                      
                                           






                                                                          
                                               
  
                                                  
 

                                                    
  
                        










                                                                          
 
                                      
                                        

                                 
                                                      














                                                                          
                                                            

                  
                                           

                                                                        
                                   










                                                                          



                             












                                                                          

                                             
                                  
                                                                         
           
                                           
 



                                             












                                                                          
                                   



                                                 
                             



                                                                         
                                     


                                                 

                                                                   


                                                                       
                                       


                                      
                                

                            
/**********************************************************************
 * pdbg.c
 * P-Code Debugger
 *
 *   Copyright (C) 2008 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 **********************************************************************/

/**********************************************************************
 * Included Files
 **********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>

#include "keywords.h"
#include "pdefs.h"
#include "podefs.h"
#include "pinsn16.h"
#include "pxdefs.h"
#include "pedefs.h"

#include "paslib.h"
#include "pinsn.h"
#include "pexec.h"
#include "pdbg.h"

/**********************************************************************
 * Definitions
 **********************************************************************/

#define TRACE_ARRAY_SIZE       16
#define MAX_BREAK_POINTS        8
#define DISPLAY_STACK_SIZE     16
#define DISPLAY_INST_SIZE      16

/**********************************************************************
 * Private Type Definitions
 **********************************************************************/

enum command_e
{
  eCMD_NONE = 0,
  eCMD_RESET,
  eCMD_RUN,
  eCMD_STEP,
  eCMD_NEXT,
  eCMD_GO,
  eCMD_BS,
  eCMD_BC,
  eCMD_DP,
  eCMD_DT,
  eCMD_DS,
  eCMD_DI,
  eCMD_DB,
  eCMD_HELP,
  eCMD_QUIT
};

struct trace_s
{
  addr_t   pc;
  addr_t   sp;
  ustack_t tos;
};
typedef struct trace_s trace_t;

/**********************************************************************
 * Private Constant Data
 **********************************************************************/

/**********************************************************************
 * Private Data
 **********************************************************************/

static enum command_e g_lastcmd = eCMD_NONE;
static uint32           g_lastvalue;

/**********************************************************************
 * Private Function Prototypes
 **********************************************************************/

static void   pdbg_showcommands(void);
static void   pdbg_execcommand(struct pexec_s *st, enum command_e cmd, uint32 value);
static sint32 pdbg_readdecimal(char *ptr);
static sint32 pdbg_readhex(char *ptr, sint32 defaultvalue);
static void   pdbg_programstatus(struct pexec_s *st);
static addr_t pdbg_printpcode(struct pexec_s *st, addr_t pc, sint16 nitems);
static addr_t pdbg_printstack(struct pexec_s *st, addr_t sp, sint16 nitems);
static void   pdbg_printregisters(struct pexec_s *st);
static void   pdbg_printtracearray(struct pexec_s *st);
static void   pdbg_addbreakpoint(addr_t pc);
static void   pdbg_deletebreakpoint(sint16 bpno);
static void   pdbg_printbreakpoints(struct pexec_s *st);
static void   pdbg_checkbreakpoint(struct pexec_s *st);
static void   pdbg_initdebugger(void);
static void   pdbg_debugpcode(struct pexec_s *st);

/**********************************************************************
 * Global Variables
 **********************************************************************/

/**********************************************************************
 * Private Variables
 **********************************************************************/

/* Debugging variables */

static trace_t  g_tracearray[TRACE_ARRAY_SIZE];
			/* Holds execution histor */
static uint16   g_tracendx;
			/* This is the index into the circular g_tracearray */
static uint16   g_ntracepoints;
			/* This is the number of valid enties in g_tracearray */
static addr_t   g_breakpoint[MAX_BREAK_POINTS];
			/* Contains address associated with all active */
                        /* break points. */
static addr_t   g_untilpoint;
                        /* The 'g_untilpoint' is a temporary breakpoint */
static uint16   g_nbreakpoints;
			/* Number of items in breakPoints[] */
static addr_t   g_displayloc;
			/* P-code display location display */
static boolean  g_bstopexecution;
			/* TRUE means to stop program execution */

/* I/O variables */

static char     g_inline[LINE_SIZE+1];
			/* Command line buffer */

/**********************************************************************
 * Public Functions
 **********************************************************************/

void dbg_run(struct pexec_s *st)
{
  addr_t pc;
  int i;

  pdbg_showcommands();
  pdbg_initdebugger();
  pdbg_programstatus(st);

  while (TRUE)
    {
      printf("CMD: ");
      (void) fgets(g_inline, LINE_SIZE, stdin);
      switch (toupper(g_inline[0]))
	{
	case 'R' :
	  switch (toupper(g_inline[1])) {
	  case 'E' :  /* Reset */
	    pdbg_execcommand(st, eCMD_RESET, 0);
	    break;
	  case 'U' :  /* Run */
	    pdbg_execcommand(st, eCMD_RUN, 0);
	    break;
	  default :
	    printf("Unrecognized Command\n");
	    pdbg_execcommand(st, eCMD_HELP, 0);
	    break;
	  } /* end switch */
	  break;
	case 'S' :  /* Single Step (into) */
	  pdbg_execcommand(st, eCMD_STEP, 0);
	  break;
	case 'N' :  /* Single Step (over) */
	  pdbg_execcommand(st, eCMD_NEXT, 0);
	  break;
	case 'G' :  /* Go */
	  pdbg_execcommand(st, eCMD_GO, 0);
	  break;
	case 'B' :
	  switch (toupper(g_inline[1])) {
	  case 'S' :  /* Set Breakpoint */
	    pc = pdbg_readhex(&g_inline[2], st->pc);
	    pdbg_execcommand(st, eCMD_BS, pc);
	    break;
	  case 'C' :  /* Clear Breakpoint */
	    i =  pdbg_readdecimal(&g_inline[2]);
	    pdbg_execcommand(st, eCMD_BC, i);
	    break;
	  default :
	    printf("Unrecognized Command\n");
	    pdbg_execcommand(st, eCMD_HELP, 0);
	    break;
	  } /* end switch */
	  break;
	case 'D' :
	  switch (toupper(g_inline[1])) {
	  case 'P' :  /* Display Program Status */
	    pdbg_execcommand(st, eCMD_DP, 0);
	    break;
	  case 'T' :  /* Display Program Trace */
	    pdbg_execcommand(st, eCMD_DT, 0);
	    break;
	  case 'S' :  /* Display Stack */
	    pc = pdbg_readhex(&g_inline[2], st->sp);
	    pdbg_execcommand(st, eCMD_DS, pc);
	    break;
	  case 'I' :  /* Display Instructions */
	    pc = pdbg_readhex(&g_inline[2], st->pc);
	    pdbg_execcommand(st, eCMD_DI, pc);
	    break;
	  case 'B' :  /* Display Breakpoints */
	    pdbg_execcommand(st, eCMD_DB, pc);
	    break;
	  default :
	    printf("Unrecognized Command\n");
	    pdbg_execcommand(st, eCMD_HELP, 0);
	    break;
	  } /* end switch */
	  break;
	case 'Q' :  /* Quit */
	  pdbg_execcommand(st, eCMD_QUIT, pc);
	  break;
	case 'H' :  /* Help */
	case '?' :
	  pdbg_execcommand(st, eCMD_HELP, 0);
	  break;
	case '\0' : /* Repeat last command */
	case '\n' : /* Repeat last command */
	  pdbg_execcommand(st, g_lastcmd, g_lastvalue);
	  break;
	default :
	  printf("Unrecognized Command\n");
	  pdbg_execcommand(st, eCMD_HELP, 0);
	  break;
	} /* end switch */
    } /* end while */

} /* end pdbg_debugpcodeProgram */

/**********************************************************************
 * Private Functions
 **********************************************************************/
/* Show command characters */

static void pdbg_showcommands(void)
{
   printf("Commands:\n");
   printf("  RE[set]   - Reset\n");
   printf("  RU[n]     - Run\n");
   printf("  S[tep]    - Single Step (Into)\n");
   printf("  N[ext]    - Single Step (Over)\n");
   printf("  G[o]      - Go\n");
   printf("  BS xxxx   - Set Breakpoint\n");
   printf("  BC n      - Clear Breakpoint\n");
   printf("  DP        - Display Program Status\n");
   printf("  DT        - Display Program Trace\n");
   printf("  DS [xxxx] - Display Stack\n");
   printf("  DI [xxxx] - Display Instructions\n");
   printf("  DB        - Display Breakpoints\n");
   printf("  H or ?    - Shows this list\n");
   printf("  Q[uit]    - Quit\n");

} /* end pdbg_showcommands */

/***********************************************************************/
static void pdbg_execcommand(struct pexec_s *st, enum command_e cmd, uint32 value)
{
  /* Save the command to resuse if the user enters nothing */

  g_lastcmd   = cmd;
  g_lastvalue = value;

  switch (cmd)
    {
    case eCMD_NONE:   /* Do nothing */
      break;
    case eCMD_RESET:  /* Reset */
      pexec_reset(st);
      pdbg_initdebugger();
      pdbg_programstatus(st);
      g_lastcmd = eCMD_NONE;
      break;
    case eCMD_RUN:    /* Run */
      pexec_reset(st);
      pdbg_initdebugger();
      pdbg_debugpcode(st);
      pdbg_programstatus(st);
      break;
    case eCMD_STEP:   /* Single Step (into)*/
      g_bstopexecution = TRUE;
      pdbg_debugpcode(st);
      pdbg_programstatus(st);
      break;
    case eCMD_NEXT:   /* Single Step (over) */
      if (st->ispace[st->pc] == oPCAL)
	{
	  g_bstopexecution = FALSE;
	  g_untilpoint = st->pc + 4;
	}
      else
	{
	  g_bstopexecution = TRUE;
	}
      pdbg_debugpcode(st);
      g_untilpoint = 0;
      pdbg_programstatus(st);
      break;
    case eCMD_GO:     /* Go */
      g_bstopexecution = FALSE;
      pdbg_debugpcode(st);
      pdbg_programstatus(st);
      break;
    case eCMD_BS:     /* Set Breakpoint */
      if (g_nbreakpoints >= MAX_BREAK_POINTS)
	{
	  printf("Too many breakpoints\n");
	  g_lastcmd = eCMD_NONE;
	}
      else if (value >= st->maxpc)
	{
	  printf("Invalid address for breakpoint\n");
	  g_lastcmd = eCMD_NONE;
	}
      else
	{
	  pdbg_addbreakpoint(value);
	  pdbg_printbreakpoints(st);
	} /* end else */
      break;
    case eCMD_BC:     /* Clear Breakpoint */
      if ((value >= 1) && (value <= g_nbreakpoints))
	{
	  pdbg_deletebreakpoint(value);
	}
      else
	{
	  printf("Invalid breakpoint number\n");
	  g_lastcmd = eCMD_NONE;
	}
      pdbg_printbreakpoints(st);
      break;
    case eCMD_DP:     /* Display Program Status */
      pdbg_programstatus(st);
      break;
    case eCMD_DT:     /* Display Program Trace */
      pdbg_printtracearray(st);
      break;
    case eCMD_DS:     /* Display Stack */
      if (value > st->sp)
	{
	  printf("Invalid stack address\n");
	  g_lastcmd = eCMD_NONE;
	}
      else
	{
	  g_lastvalue = pdbg_printstack(st, value, DISPLAY_STACK_SIZE);
	} /* end else */
      break;
    case eCMD_DI:     /* Display Instructions */
      if (value >= st->maxpc)
	{
	  printf("Invalid instruction address\n");
	  g_lastcmd = eCMD_NONE;
	}
      else
	{
	  g_lastvalue = pdbg_printpcode(st, value, DISPLAY_INST_SIZE);
	} /* end else */
      break;
    case eCMD_DB:     /* Display Breakpoints */
      pdbg_printbreakpoints(st);
      break;
    case eCMD_QUIT:   /* Quit */
      printf("Goodbye\n");
      exit(0);
      break;
    case eCMD_HELP:   /* Help */
    default:          /* Internal error */
      pdbg_showcommands();
      g_lastcmd = eCMD_NONE;
      break;
    } /* end switch */

} /* end pdbg_execcommand */

/***********************************************************************/
/* Read a decimal value from the  input string */

static sint32 pdbg_readdecimal(char *ptr)
{
   sint32 decimal = 0;

   while (!isspace(*ptr)) ptr++;
   while (isspace(*ptr))  ptr++;
   for (; ((*ptr >= '0') && (*ptr <= '9')); ptr++)
      decimal = 10*decimal + (sint32)*ptr - (sint32)'0';
 
   return decimal;

} /* end pdbg_readdecimal */
/***********************************************************************/
/* Read a hexadecimal value from the  input string */

static sint32 pdbg_readhex(char *ptr, sint32 defaultvalue)
{
   char    c;
   sint32  hex = 0;
   boolean found = FALSE;

   while (!isspace(*ptr)) ptr++;
   while (isspace(*ptr))  ptr++;
   while (TRUE) {

      c = toupper(*ptr);
      if ((c >= '0') && (c <= '9')) {
	 hex = ((hex << 4) | ((sint32)c - (sint32)'0'));
	 found = TRUE;
      } /* end if */
      else if ((c >= 'A') && (c <= 'F')) {
	 hex = ((hex << 4) | ((sint32)c - (sint32)'A' + 10));
	 found = TRUE;
      } /* end else if */
      else {
         if (found)
	    return hex;
	 else
            return defaultvalue;
      } /* end else */
      ptr++;

   } /* end while */

} /* end pdbg_readhex */

/***********************************************************************/
/* Print the disassembled P-Code at PC */

static void pdbg_programstatus(struct pexec_s *st)
{
   (void)pdbg_printpcode(st, st->pc, 1);
   (void)pdbg_printstack(st, st->sp, 2);
   pdbg_printregisters(st);

} /* end pdbg_programstatus */

/***********************************************************************/
/* Print the disassembled P-Code at PC */

static addr_t pdbg_printpcode(struct pexec_s *st, addr_t pc, sint16 nitems)
{
  OPTYPE op;
  addr_t opsize;
  ubyte *address;

  for (; ((pc < st->maxpc) && (nitems > 0)); nitems--)
    {
      address = &st->ispace[pc];

      op.op    = *address++;
      op.arg1  = 0;
      op.arg2  = 0;
      opsize   = 1;
      printf("PC:%04x  %02x", pc, op.op);

      if ((op.op & o8) != 0)
	{
	  op.arg1 = *address++;
	  printf("%02x", op.arg1);
	  opsize++;
	} /* end if */
      else 
	printf("..");

      if ((op.op & o16) != 0)
	{
	  op.arg2  = ((*address++) << 8);
	  op.arg2 |= *address++;
	  printf("%04x", op.arg2);
	  opsize += 2;
	} /* end if */
      else
	printf("....");

      /* The disassemble it to stdout */

      printf("  ");
      insn_DisassemblePCode(stdout, &op);

      /* Get the address of the next P-Code */

      pc += opsize;

    } /* end for */

  return pc;

} /* end pdbg_printpcode */

/***********************************************************************/
/* Print the stack value at SP */

static addr_t pdbg_printstack(struct pexec_s *st, addr_t sp, sint16 nitems)
{
  sint32 isp;

  if ((st->sp < st->stacksize) && (sp <= st->sp))
    {
      isp = BTOISTACK(sp);
      printf("SP:%04x  %04x\n", sp, st->dstack.i[isp]);

      for (isp--, sp -= BPERI, nitems--;
	   ((isp >= 0) && (nitems > 0));
	   isp--, sp -= BPERI, nitems--)
	printf("   %04x  %04x\n", sp, st->dstack.i[isp] & 0xffff);
    } /* end if */
  else
    {
      printf("SP:%04x  BAD\n", sp);
    } /* end else */

  return sp;
} /* end pdbg_printstack */

/***********************************************************************/
/* Print the base register */

static void pdbg_printregisters(struct pexec_s *st)
{
   if (st->fp <= st->sp)
      printf("FP:%04x ", st->fp);

   printf("CSP:%04x\n", st->csp);

} /* end pdbg_printregisters */

/***********************************************************************/
/* Print the g_tracearray */

static void pdbg_printtracearray(struct pexec_s *st)
{
   int nprinted;
   int index;

   index = g_tracendx + TRACE_ARRAY_SIZE - g_ntracepoints;
   if (index >= TRACE_ARRAY_SIZE)
     index -= TRACE_ARRAY_SIZE;

   for (nprinted = 0; nprinted < g_ntracepoints; nprinted++) {

      printf("SP:%04x  %04x  ",
         g_tracearray[ index ].sp, g_tracearray[ index ].tos); 

      /* Print the instruction executed at this traced address */
      (void)pdbg_printpcode(st, g_tracearray[ index ].pc, 1);

      /* Index to the next trace entry */
      if (++index >= TRACE_ARRAY_SIZE)
	 index = 0;

   } /* end for */

} /* end pdbg_printtracearray */

/***********************************************************************/
/* Add a breakpoint to the breakpoint array */

static void pdbg_addbreakpoint(addr_t pc)
{
  int i;

  /* Is there room for another breakpoint? */

  if (g_nbreakpoints < MAX_BREAK_POINTS)
    {
      /* Yes..Check if the breakpoint already exists */

      for (i = 0; i < g_nbreakpoints; i++)
	{
	  if (g_breakpoint[i] == pc)
	    {
	      /* It is already set.  Return without doing anything */

	      return;
	    }
	}

      /* The breakpoint is not already set -- set it */

      g_breakpoint[g_nbreakpoints++] = pc;
    } /* end if */

} /* end pdbg_addbreakpoint */

/***********************************************************************/
/* Remove a breakpoint from the breakpoint array */

static void pdbg_deletebreakpoint(sint16 bpno)
{
   if ((bpno >= 1) && (bpno <= g_nbreakpoints)) {

      for (; (bpno < g_nbreakpoints); bpno++)
         g_breakpoint[bpno-1] = g_breakpoint[bpno];
 
      g_nbreakpoints--;

   } /* end if */

} /* end pdbg_deletebreakpoint */

/***********************************************************************/
/* Print the breakpoint array */

static void pdbg_printbreakpoints(struct pexec_s *st)
{
   int i;

   printf("BP:#  Address  P-Code\n");
   for (i = 0; i < g_nbreakpoints; i++)
     {
       printf("BP:%d  ", (i+1));
       (void)pdbg_printpcode(st, g_breakpoint[i], 1);
     } /* end for */

} /* end pdbg_printbreakpoints */

/***********************************************************************/
/* Check if a breakpoint is set at the current value of program counter.
 * If so, print the instruction and stop execution. */

static void pdbg_checkbreakpoint(struct pexec_s *st)
{
  uint16 bpIndex;

  /* Check for a user breakpoint */

  for (bpIndex = 0;
       ((bpIndex < g_nbreakpoints) && (!g_bstopexecution));
       bpIndex++)
    {
      if (g_breakpoint[bpIndex] == st->pc)
	{
	  printf("Breakpoint #%d -- Execution Stopped\n", (bpIndex+1));
	  g_bstopexecution = TRUE;
	  return;
	} /* end if */
    } /* end for */

} /* end pdbg_checkbreakpoint */

/***********************************************************************/
/* Initialize Debugger variables */

static void pdbg_initdebugger(void)
{
   g_bstopexecution = FALSE;
   g_displayloc     = 0;
   g_tracendx       = 0;
   g_ntracepoints   = 0;
}

/***********************************************************************/
/* This function executes the P-Code program until a stopping condition
 * is encountered. */

static void pdbg_debugpcode(struct pexec_s *st)
{
   uint16 errno;

   do {
      /* Trace the next instruction execution */

      g_tracearray[g_tracendx].pc  = st->pc;
      g_tracearray[g_tracendx].sp  = st->sp;
      if (st->sp < st->stacksize)
	 g_tracearray[g_tracendx].tos = st->dstack.i[BTOISTACK(st->sp)];
      else
	 g_tracearray[g_tracendx].tos = 0;

      if (++g_tracendx >= TRACE_ARRAY_SIZE)
	 g_tracendx = 0;
      if (g_ntracepoints < TRACE_ARRAY_SIZE)
         g_ntracepoints++;

      /* Execute the instruction */

      errno = pexec(st);

      /* Check for exceptional stopping conditions */

      if (errno != eNOERROR)
	{
	  if (errno == eEXIT)
	    printf("Normal Termination\n");
	  else
	    printf("Runtime error 0x%02x -- Execution Stopped\n", errno);
	  g_bstopexecution = TRUE;
	} /* end if */

      /* Check for normal stopping conditions */

      if (!g_bstopexecution)
	{
	  /* Check for attempt to execute code outside of legal range */

	  if (st->pc >= st->maxpc)
	    g_bstopexecution = TRUE;

	  /* Check for a temporary breakpoint */

	  else if ((g_untilpoint > 0) && (g_untilpoint == st->pc))
	    g_bstopexecution = TRUE;

	  /* Check if there is a breakpoint at the next instruction */

	  else if (g_nbreakpoints > 0)
	    pdbg_checkbreakpoint(st);
	}

   } while (!g_bstopexecution);

} /* end pdbg_debugpcode */