forked from Archive/PX4-Autopilot
749 lines
21 KiB
C
749 lines
21 KiB
C
/**********************************************************************
|
|
* pdbg.c
|
|
* P-Code Debugger
|
|
*
|
|
* Copyright (C) 2008-2009 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 <stdint.h>
|
|
#include <stdbool.h>
|
|
#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"
|
|
|
|
/**********************************************************************
|
|
* Pre-processor 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
|
|
{
|
|
paddr_t pc;
|
|
paddr_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_t g_lastvalue;
|
|
|
|
/**********************************************************************
|
|
* Private Function Prototypes
|
|
**********************************************************************/
|
|
|
|
static void pdbg_showcommands(void);
|
|
static void pdbg_execcommand(struct pexec_s *st, enum command_e cmd, uint32_t value);
|
|
static int32_t pdbg_readdecimal(char *ptr);
|
|
static int32_t pdbg_readhex(char *ptr, int32_t defaultvalue);
|
|
static void pdbg_programstatus(struct pexec_s *st);
|
|
static paddr_t pdbg_printpcode(struct pexec_s *st, paddr_t pc, int16_t nitems);
|
|
static paddr_t pdbg_printstack(struct pexec_s *st, paddr_t sp, int16_t nitems);
|
|
static void pdbg_printregisters(struct pexec_s *st);
|
|
static void pdbg_printtracearray(struct pexec_s *st);
|
|
static void pdbg_addbreakpoint(paddr_t pc);
|
|
static void pdbg_deletebreakpoint(int16_t 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_t g_tracendx;
|
|
/* This is the index into the circular g_tracearray */
|
|
static uint16_t g_ntracepoints;
|
|
/* This is the number of valid enties in g_tracearray */
|
|
static paddr_t g_breakpoint[MAX_BREAK_POINTS];
|
|
/* Contains address associated with all active */
|
|
/* break points. */
|
|
static paddr_t g_untilpoint;
|
|
/* The 'g_untilpoint' is a temporary breakpoint */
|
|
static uint16_t g_nbreakpoints;
|
|
/* Number of items in breakPoints[] */
|
|
static paddr_t g_displayloc;
|
|
/* P-code display location display */
|
|
static bool 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)
|
|
{
|
|
paddr_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_t 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 int32_t pdbg_readdecimal(char *ptr)
|
|
{
|
|
int32_t decimal = 0;
|
|
|
|
while (!isspace(*ptr)) ptr++;
|
|
while (isspace(*ptr)) ptr++;
|
|
for (; ((*ptr >= '0') && (*ptr <= '9')); ptr++)
|
|
decimal = 10*decimal + (int32_t)*ptr - (int32_t)'0';
|
|
|
|
return decimal;
|
|
|
|
} /* end pdbg_readdecimal */
|
|
/***********************************************************************/
|
|
/* Read a hexadecimal value from the input string */
|
|
|
|
static int32_t pdbg_readhex(char *ptr, int32_t defaultvalue)
|
|
{
|
|
char c;
|
|
int32_t hex = 0;
|
|
bool found = false;
|
|
|
|
while (!isspace(*ptr)) ptr++;
|
|
while (isspace(*ptr)) ptr++;
|
|
while (true) {
|
|
|
|
c = toupper(*ptr);
|
|
if ((c >= '0') && (c <= '9')) {
|
|
hex = ((hex << 4) | ((int32_t)c - (int32_t)'0'));
|
|
found = true;
|
|
} /* end if */
|
|
else if ((c >= 'A') && (c <= 'F')) {
|
|
hex = ((hex << 4) | ((int32_t)c - (int32_t)'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 paddr_t pdbg_printpcode(struct pexec_s *st, paddr_t pc, int16_t nitems)
|
|
{
|
|
OPTYPE op;
|
|
paddr_t opsize;
|
|
uint8_t *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 paddr_t pdbg_printstack(struct pexec_s *st, paddr_t sp, int16_t nitems)
|
|
{
|
|
int32_t 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(paddr_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(int16_t 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_t 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_t 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 */
|