cvsuser 02/08/25 16:39:16
Modified: . debug.c
include/parrot debug.h
config/gen/makefiles root.in
Log:
Added conditional breakpoints.
Fixed dependecies.
More documentation.
Revision Changes Path
1.29 +252 -19 parrot/debug.c
Index: debug.c
===================================================================
RCS file: /cvs/public/parrot/debug.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -w -r1.28 -r1.29
--- debug.c 22 Aug 2002 15:17:31 -0000 1.28
+++ debug.c 25 Aug 2002 23:38:13 -0000 1.29
@@ -2,7 +2,7 @@
* debug.c
*
* CVS Info
- * $Id: debug.c,v 1.28 2002/08/22 15:17:31 grunblatt Exp $
+ * $Id: debug.c,v 1.29 2002/08/25 23:38:13 grunblatt Exp $
* Overview:
* Parrot debugger
* History:
@@ -19,14 +19,28 @@
#include <stdio.h>
#include <stdlib.h>
+/* na(c) [Next Argument (Char pointer)]
+ *
+ * Moves the pointer to the next argument in the user input.
+ */
#define na(c) { \
while(*c && !isspace((int) *c)) \
c++; \
while(*c && isspace((int) *c)) \
c++; }
-/* PDB_get_command
- * get a command from stdin to execute
+/* PDB_get_command(struct Parrot_Interp *interpreter)
+ *
+ * Get a command from the user input to execute.
+ *
+ * It saves the last command executed (in pdb->last_command), so it first
+ * frees the old one and updates it with the current one.
+ *
+ * Also prints the next line to run if the program is still active.
+ *
+ * The user input can't be longer than 255 characters.
+ *
+ * The input is saved in pdb->cur_command.
*/
void
PDB_get_command(struct Parrot_Interp *interpreter)
@@ -40,7 +54,7 @@
fflush(stdout);
/* not used any more */
- if (pdb->last_command && *pdb->cur_command)
+ if (pdb->last_command && *pdb->last_command)
mem_sys_free(pdb->last_command);
/* update the last command */
@@ -77,8 +91,11 @@
pdb->cur_command = c;
}
-/* PDB_run_command
- * run a command
+/* PDB_run_command(struct Parrot_Interp *interpreter, const char *command)
+ *
+ * Run a command.
+ *
+ * Hash the command to make a simple switch calling the correct handler.
*/
void
PDB_run_command(struct Parrot_Interp *interpreter, const char *command)
@@ -177,29 +194,36 @@
}
}
-/* PDB_next
- * execute the next instruction
+/* PDB_next(struct Parrot_Interp *interpreter, const char *command)
+ *
+ * Execute the next N operation(s).
+ *
+ * Inits the program if needed, runs the next N >= 1 operations and
+ * stops.
+ *
*/
void
-PDB_next(struct Parrot_Interp *interpreter,
- const char *command)
+PDB_next(struct Parrot_Interp *interpreter, const char *command)
{
PDB_t *pdb = interpreter->pdb;
unsigned long n = 1;
+ /* Init the program if it's not running */
if (!(pdb->state & PDB_RUNNING))
- {
PDB_init(interpreter,command);
- }
+ /* Get the number of operations to execute if any */
if (command && isdigit((int) *command))
n = atol(command);
+ /* Erase the stopped flag */
pdb->state &= ~PDB_STOPPED;
+ /* Execute */
for ( ; n && pdb->cur_opcode; n--)
DO_OP(pdb->cur_opcode,interpreter);
+ /* Set the stopped flag */
pdb->state |= PDB_STOPPED;
/* If program ended */
@@ -243,12 +267,143 @@
PDB_program_end(interpreter);
}
+/* PDB_cond
+ *
+ * Analyzes a condition from the user input.
+ */
+PDB_condition_t *
+PDB_cond(struct Parrot_Interp *interpreter, const char *command)
+{
+ PDB_t *pdb = interpreter->pdb;
+ PDB_breakpoint_t *newbreak,*sbreak;
+ PDB_condition_t *condition;
+ int i;
+ char str[255];
+
+ /* Allocate new condition */
+ condition = (PDB_condition_t *)mem_sys_allocate(sizeof(PDB_condition_t));
+ /* The first argument after the 'if' MUST be a register of any type. */
+ na(command);
+
+ /* return if no more arguments */
+ if (!(command && *command))
+ return NULL;
+
+ switch (*command) {
+ case 'i':
+ case 'I':
+ condition->type = PDB_cond_int;
+ break;
+ case 'n':
+ case 'N':
+ condition->type = PDB_cond_num;
+ break;
+ case 's':
+ case 'S':
+ condition->type = PDB_cond_str;
+ break;
+ case 'p':
+ case 'P':
+ condition->type = PDB_cond_pmc;
+ break;
+ default:
+ fprintf(stderr, "First argument must be a register\n");
+ return NULL;
+ }
+
+ /* get the register number */
+ condition->reg = atoi(++command);
+
+ /* the next argument might have no spaces between the register and the
+ * condition. */
+ command++;
+
+ if (condition->reg > 9)
+ command++;
+
+ if (*command == ' ')
+ na(command);
+
+ /* Now the condition */
+ switch (*command) {
+ case '>':
+ if (*(command + 1) == '=')
+ condition->type |= PDB_cond_ge;
+ else if (*(command + 1) == ' ')
+ condition->type |= PDB_cond_gt;
+ else
+ goto INV_COND;
+ break;
+ case '<':
+ if (*(command + 1) == '=')
+ condition->type |= PDB_cond_le;
+ else if (*(command + 1) == ' ')
+ condition->type |= PDB_cond_lt;
+ else
+ goto INV_COND;
+ break;
+ case '=':
+ if (*(command + 1) == '=')
+ condition->type |= PDB_cond_eq;
+ else
+ goto INV_COND;
+ break;
+ case '!':
+ if (*(command + 1) == '=')
+ condition->type |= PDB_cond_ne;
+ else
+ goto INV_COND;
+ break;
+ default:
+INV_COND: fprintf(stderr, "Invalid condition\n");
+ return NULL;
+ }
+
+ if (*(command + 1) == '=')
+ command += 2;
+ else
+ command ++;
+
+ if (*command == ' ')
+ na(command);
+
+ /* return if no more arguments */
+ if (!(command && *command))
+ return NULL;
+
+ if (!((isdigit((int)*command)) || (*command == '"'))) {
+ condition->value = (void *)mem_sys_allocate(sizeof(int));
+ *(int *)condition->value = (int)atoi(++command);
+ }
+ /* If the first argument was an integer */
+ else if (condition->type & PDB_cond_int) {
+ /* This must be either an integer constant or register */
+ condition->value = (void *)mem_sys_allocate(sizeof(INTVAL));
+ *(INTVAL *)condition->value = (INTVAL)atoi(command);
+ condition->type |= PDB_cond_const;
+ }
+ else if (condition->type & PDB_cond_num) {
+ condition->value = (void *)mem_sys_allocate(sizeof(FLOATVAL));
+ *(FLOATVAL *)condition->value = (FLOATVAL)atof(command);
+ condition->type |= PDB_cond_const;
+ }
+ else if (condition->type & PDB_cond_str) {
+ for (i = 1; ((command[i] != '"') && (i < 255)); i++)
+ str[i - 1] = command[i];
+ str[i - 1] = '\0';
+ (STRING *)condition->value = string_make(interpreter,
+ str, i - 1, NULL, BUFFER_external_FLAG, NULL);
+ condition->type |= PDB_cond_const;
+ }
+
+ return condition;
+}
+
/* PDB_set_break
* set a break point, the source code file must be loaded.
*/
void
-PDB_set_break(struct Parrot_Interp *interpreter,
- const char *command)
+PDB_set_break(struct Parrot_Interp *interpreter, const char *command)
{
PDB_t *pdb = interpreter->pdb;
PDB_breakpoint_t *newbreak,*sbreak;
@@ -304,6 +459,14 @@
/* Allocate the new break point */
newbreak = (PDB_breakpoint_t *)mem_sys_allocate(sizeof(PDB_breakpoint_t));
+ na(command);
+
+ /* if there is another argument to break, besides the line number,
+ * it should be an 'if', so we call another handler. */
+ if (command && *command &&
+ !(newbreak->condition = PDB_cond(interpreter, command)))
+ return;
+
/* Set the address where to stop */
newbreak->pc = line->opcode;
/* No next breakpoint */
@@ -448,6 +611,72 @@
return 1;
}
+/* PDB_check_condition
+ *
+ * Returns TRUE if the condition was met.
+ */
+char
+PDB_check_condition(struct Parrot_Interp *interpreter,
+ PDB_condition_t *condition)
+{
+ INTVAL i,j;
+ FLOATVAL k, l;
+ STRING *m, *n;
+
+ if (condition->type & PDB_cond_int) {
+ i = interpreter->ctx.int_reg.registers[condition->reg];
+ if (condition->type & PDB_cond_const)
+ j = *(INTVAL *)condition->value;
+ else
+ j = interpreter->ctx.int_reg.registers[*(int *)condition->value];
+ if (((condition->type & PDB_cond_gt) && (i > j)) ||
+ ((condition->type & PDB_cond_ge) && (i >= j)) ||
+ ((condition->type & PDB_cond_eq) && (i == j)) ||
+ ((condition->type & PDB_cond_ne) && (i != j)) ||
+ ((condition->type & PDB_cond_le) && (i <= j)) ||
+ ((condition->type & PDB_cond_lt) && (i < j)))
+ return 1;
+ return 0;
+ }
+ else if (condition->type & PDB_cond_num) {
+ k = interpreter->ctx.num_reg.registers[condition->reg];
+ if (condition->type & PDB_cond_const)
+ l = *(FLOATVAL *)condition->value;
+ else
+ l = interpreter->ctx.num_reg.registers[*(int *)condition->value];
+ if (((condition->type & PDB_cond_gt) && (k > l)) ||
+ ((condition->type & PDB_cond_ge) && (k >= l)) ||
+ ((condition->type & PDB_cond_eq) && (k == l)) ||
+ ((condition->type & PDB_cond_ne) && (k != l)) ||
+ ((condition->type & PDB_cond_le) && (k <= l)) ||
+ ((condition->type & PDB_cond_lt) && (k < l)))
+ return 1;
+ return 0;
+ }
+ else if (condition->type & PDB_cond_str) {
+ m = interpreter->ctx.string_reg.registers[condition->reg];
+ if (condition->type & PDB_cond_const)
+ n = (STRING *)condition->value;
+ else
+ n = interpreter->ctx.string_reg.registers[*(int *)condition->value];
+ if (((condition->type & PDB_cond_gt) &&
+ (string_compare(interpreter, m, n) > 0)) ||
+ ((condition->type & PDB_cond_ge) &&
+ (string_compare(interpreter, m, n) >= 0)) ||
+ ((condition->type & PDB_cond_eq) &&
+ (string_compare(interpreter, m, n) == 0)) ||
+ ((condition->type & PDB_cond_ne) &&
+ (string_compare(interpreter, m, n) != 0)) ||
+ ((condition->type & PDB_cond_le) &&
+ (string_compare(interpreter, m, n) <= 0)) ||
+ ((condition->type & PDB_cond_lt) &&
+ (string_compare(interpreter, m, n) < 0)))
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
/* PDB_break
* return true if we have to stop running
*/
@@ -479,6 +708,11 @@
if (breakpoint->skip < 0)
return 0;
+ /* Check if there is a condition for this breakpoint */
+ if ((breakpoint->condition) &&
+ (!PDB_check_condition(interpreter, breakpoint->condition)))
+ return 0;
+
/* Add the STOPPED state and stop */
pdb->state |= PDB_STOPPED;
return 1;
@@ -691,8 +925,7 @@
constants[pc[j]]->string->strstart,
interpreter->code->const_table->
constants[pc[j]]->string->strlen);
- if (escaped)
- {
+ if (escaped) {
strcpy(&pfile->source[pfile->size],escaped);
pfile->size += strlen(escaped);
mem_sys_free(escaped);
@@ -1086,7 +1319,7 @@
char s[1], *c = buf;
op_info_t *op_info;
/* Opcodes can't have more that 10 arguments */
- opcode_t eval[11],*run;
+ opcode_t eval[10],*run;
int op_number,i,k,l,j = 0;
/* find_op needs a string with only the opcode name */
1.12 +96 -14 parrot/include/parrot/debug.h
Index: debug.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/debug.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -w -r1.11 -r1.12
--- debug.h 23 Jul 2002 14:33:53 -0000 1.11
+++ debug.h 25 Aug 2002 23:38:44 -0000 1.12
@@ -2,7 +2,7 @@
* debug.h
*
* CVS Info
- * $Id: debug.h,v 1.11 2002/07/23 14:33:53 grunblatt Exp $
+ * $Id: debug.h,v 1.12 2002/08/25 23:38:44 grunblatt Exp $
* Overview:
* Parrot debugger header files
* History:
@@ -23,6 +23,41 @@
PDB_EXIT = 1 << 5
};
+enum {
+ PDB_cond_int = 1 << 0,
+ PDB_cond_num = 1 << 1,
+ PDB_cond_str = 1 << 2,
+ PDB_cond_pmc = 1 << 3,
+ PDB_cond_gt = 1 << 4,
+ PDB_cond_ge = 1 << 5,
+ PDB_cond_eq = 1 << 6,
+ PDB_cond_ne = 1 << 7,
+ PDB_cond_le = 1 << 8,
+ PDB_cond_lt = 1 << 9,
+ PDB_cond_const = 1 << 10
+};
+
+/* PDB_condition_t
+ * Conditions for breakpoint or watchpoints.
+ *
+ * type: The type of condition and the way to use arguments.
+ * reg: The register involved, there must be at least one.
+ * value: A pointer to the second argument.
+ */
+
+typedef struct PDB_condition {
+ unsigned short type;
+ unsigned char reg;
+ void *value;
+} PDB_condition_t;
+
+/* PDB_label_t
+ * A label in the source file.
+ *
+ * opcode: The pointer to the bytecode where the label is.
+ * number: Number label.
+ */
+
typedef struct PDB_label *PDB_label_ptr;
typedef struct PDB_label {
@@ -31,6 +66,15 @@
PDB_label_ptr next;
} PDB_label_t;
+/* PDB_line_t
+ * A line in the source file.
+ *
+ * opcode: A pointer to the opcode in the bytecode correspoinding to
+ * this line.
+ * source_offset: Offset from the source file start.
+ * number: Line number.
+ * label: The label if any.
+ */
typedef struct PDB_line *PDB_line_ptr;
typedef struct PDB_line {
@@ -41,6 +85,16 @@
PDB_line_ptr next;
} PDB_line_t;
+/* PDB_file_t
+ * A source code file.
+ *
+ * sourcefilename: The source code file name.
+ * source: The file it self.
+ * size: The size of the file.
+ * list_line: The next line to list.
+ * line: The first line of the source code.
+ * label: The first label.
+ */
typedef struct PDB_file *PDB_file_ptr;
typedef struct PDB_file {
@@ -53,17 +107,38 @@
PDB_file_ptr next;
} PDB_file_t;
+/* PDB_breakpoint_t
+ * List of breakpoints.
+ *
+ * pc: Where the breakpoint is.
+ * skip: The number of times to skip this breakpoint.
+ */
+
typedef struct PDB_breakpoint *PDB_breakpoint_ptr;
typedef struct PDB_breakpoint {
opcode_t * pc;
long skip;
+ PDB_condition_t *condition;
PDB_breakpoint_ptr next;
} PDB_breakpoint_t;
+/* PDB_t
+ * The debugger.
+ *
+ * file: Source code file.
+ * breakpoint: The first breakpoint.
+ * breakpoint_skip: Number of breakpoints to skip.
+ * cur_command: The command being executed.
+ * last_command: Last command executed.
+ * cur_opcode: Current opcode.
+ * state: The status of the program being debugged.
+ */
+
typedef struct PDB {
PDB_file_t * file;
PDB_breakpoint_t * breakpoint;
+ PDB_condition_t *watchpoint;
long breakpoint_skip;
char * cur_command;
char * last_command;
@@ -123,6 +198,11 @@
void PDB_set_break(struct Parrot_Interp *, const char *);
+PDB_condition_t *PDB_cond(struct Parrot_Interp *, const char *);
+
+char PDB_check_condition(struct Parrot_Interp *interpreter,
+ PDB_condition_t *condition);
+
char PDB_program_end(struct Parrot_Interp *);
char PDB_hasinstruction(char *);
@@ -168,6 +248,7 @@
#define c_r 29325
#define c_s 29580
#define c_t 29835
+#define c_w 30600
#define c_int 175185
#define c_run 176460
#define c_num 174675
@@ -184,6 +265,7 @@
#define c_print 441150
#define c_stack 414120
#define c_trace 405705
+#define c_watch 416160
#define c_delete 588285
#define c_continue 1053405
#define c_disassemble 1903830
1.24 +3 -3 parrot/config/gen/makefiles/root.in
Index: root.in
===================================================================
RCS file: /cvs/public/parrot/config/gen/makefiles/root.in,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -w -r1.23 -r1.24
--- root.in 22 Aug 2002 21:55:09 -0000 1.23
+++ root.in 25 Aug 2002 23:39:15 -0000 1.24
@@ -67,7 +67,7 @@
$(INC)/oplib/core_ops_prederef.h $(INC)/runops_cores.h $(INC)/trace.h \
$(INC)/pmc.h $(INC)/key.h $(INC)/hash.h $(INC)/resources.h $(INC)/platform.h
${cg_h} \
$(INC)/interp_guts.h $(INC)/rx.h $(INC)/rxstacks.h \
-$(INC)/embed.h $(INC)/warnings.h $(INC)/misc.h $(INC)/debug.h $(INC)/pmc.h \
+$(INC)/embed.h $(INC)/warnings.h $(INC)/misc.h $(INC)/pmc.h \
$(INC)/key.h $(INC)/hash.h $(INC)/smallobject.h $(INC)/headers.h $(INC)/dod.h \
$(INC)/method_util.h
@@ -332,7 +332,7 @@
platform$(O) : $(GENERAL_H_FILES)
-debug$(O) : $(GENERAL_H_FILES)
+debug$(O) : $(GENERAL_H_FILES) $(INC)/debug.h
method_util$(O) : $(GENERAL_H_FILES)
@@ -384,7 +384,7 @@
stacks$(O) : $(GENERAL_H_FILES)
-embed$(O) : $(GENERAL_H_FILES)
+embed$(O) : $(GENERAL_H_FILES) $(INC)/debug.h
core_ops$(O) : $(GENERAL_H_FILES) core_ops.c