[t][tools] Allow assigning to lowercase register names in parrot_debugger, since...
[parrot.git] / src / debug.c
blobe250045596643880ea3e190ac74a043373cd29db
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/debug.c - Parrot debugging
9 =head1 DESCRIPTION
11 This file implements Parrot debugging and is used by C<parrot_debugger>,
12 the Parrot debugger, and the C<debug> ops.
14 =head2 Functions
16 =over 4
18 =cut
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "parrot/parrot.h"
25 #include "parrot/extend.h"
26 #include "parrot/embed.h"
27 #include "parrot/oplib.h"
28 #include "parrot/debugger.h"
29 #include "parrot/oplib/ops.h"
30 #include "pmc/pmc_key.h"
31 #include "parrot/runcore_api.h"
32 #include "parrot/runcore_trace.h"
33 #include "debug.str"
34 #include "pmc/pmc_continuation.h"
36 /* Hand switched debugger tracing
37 * Set to 1 to enable tracing to stderr
38 * Set to 0 to disable
40 #define TRACE_DEBUGGER 0
42 #if TRACE_DEBUGGER
43 # define TRACEDEB_MSG(msg) fprintf(stderr, "%s\n", (msg))
44 #else
45 # define TRACEDEB_MSG(msg)
46 #endif
48 /* Length of command line buffers */
49 #define DEBUG_CMD_BUFFER_LENGTH 255
51 /* Easier register access */
52 #define IREG(i) REG_INT(interp, (i))
53 #define NREG(i) REG_NUM(interp, (i))
54 #define SREG(i) REG_STR(interp, (i))
55 #define PREG(i) REG_PMC(interp, (i))
57 typedef struct DebuggerCmd DebuggerCmd;
58 typedef struct DebuggerCmdList DebuggerCmdList;
61 /* HEADERIZER HFILE: include/parrot/debugger.h */
63 /* HEADERIZER BEGIN: static */
64 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
66 static void chop_newline(ARGMOD(char * buf))
67 __attribute__nonnull__(1)
68 FUNC_MODIFIES(* buf);
70 static void close_script_file(PARROT_INTERP)
71 __attribute__nonnull__(1);
73 static unsigned short condition_regtype(ARGIN(const char *cmd))
74 __attribute__nonnull__(1);
76 PARROT_CAN_RETURN_NULL
77 static PDB_breakpoint_t * current_breakpoint(ARGIN(PDB_t * pdb))
78 __attribute__nonnull__(1);
80 static void debugger_cmdline(PARROT_INTERP)
81 __attribute__nonnull__(1);
83 static void dump_string(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
84 __attribute__nonnull__(1);
86 PARROT_WARN_UNUSED_RESULT
87 PARROT_CANNOT_RETURN_NULL
88 PARROT_OBSERVER
89 static STRING * GDB_P(PARROT_INTERP, ARGIN(const char *s))
90 __attribute__nonnull__(1)
91 __attribute__nonnull__(2);
93 PARROT_WARN_UNUSED_RESULT
94 PARROT_CANNOT_RETURN_NULL
95 PARROT_OBSERVER
96 static STRING * GDB_print_reg(PARROT_INTERP, int t, int n)
97 __attribute__nonnull__(1);
99 PARROT_WARN_UNUSED_RESULT
100 PARROT_CAN_RETURN_NULL
101 static const DebuggerCmd * get_cmd(ARGIN_NULLOK(const char **cmd));
103 PARROT_WARN_UNUSED_RESULT
104 static unsigned long get_uint(ARGMOD(const char **cmd), unsigned int def)
105 __attribute__nonnull__(1)
106 FUNC_MODIFIES(*cmd);
108 PARROT_WARN_UNUSED_RESULT
109 static unsigned long get_ulong(ARGMOD(const char **cmd), unsigned long def)
110 __attribute__nonnull__(1)
111 FUNC_MODIFIES(*cmd);
113 static void list_breakpoints(ARGIN(PDB_t *pdb))
114 __attribute__nonnull__(1);
116 PARROT_CAN_RETURN_NULL
117 PARROT_WARN_UNUSED_RESULT
118 static const char * nextarg(ARGIN_NULLOK(const char *command));
120 static void no_such_register(PARROT_INTERP,
121 char register_type,
122 UINTVAL register_num)
123 __attribute__nonnull__(1);
125 PARROT_CANNOT_RETURN_NULL
126 PARROT_WARN_UNUSED_RESULT
127 static const char * parse_int(ARGIN(const char *str), ARGOUT(int *intP))
128 __attribute__nonnull__(1)
129 __attribute__nonnull__(2)
130 FUNC_MODIFIES(*intP);
132 PARROT_CAN_RETURN_NULL
133 PARROT_WARN_UNUSED_RESULT
134 static const char* parse_key(PARROT_INTERP,
135 ARGIN(const char *str),
136 ARGOUT(PMC **keyP))
137 __attribute__nonnull__(1)
138 __attribute__nonnull__(2)
139 __attribute__nonnull__(3)
140 FUNC_MODIFIES(*keyP);
142 PARROT_CAN_RETURN_NULL
143 PARROT_WARN_UNUSED_RESULT
144 static const char * parse_string(PARROT_INTERP,
145 ARGIN(const char *str),
146 ARGOUT(STRING **strP))
147 __attribute__nonnull__(1)
148 __attribute__nonnull__(2)
149 __attribute__nonnull__(3)
150 FUNC_MODIFIES(*strP);
152 PARROT_CANNOT_RETURN_NULL
153 static const char * skip_command(ARGIN(const char *str))
154 __attribute__nonnull__(1);
156 PARROT_WARN_UNUSED_RESULT
157 PARROT_CANNOT_RETURN_NULL
158 static const char * skip_whitespace(ARGIN(const char *cmd))
159 __attribute__nonnull__(1);
161 #define ASSERT_ARGS_chop_newline __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
162 PARROT_ASSERT_ARG(buf))
163 #define ASSERT_ARGS_close_script_file __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
164 PARROT_ASSERT_ARG(interp))
165 #define ASSERT_ARGS_condition_regtype __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
166 PARROT_ASSERT_ARG(cmd))
167 #define ASSERT_ARGS_current_breakpoint __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
168 PARROT_ASSERT_ARG(pdb))
169 #define ASSERT_ARGS_debugger_cmdline __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
170 PARROT_ASSERT_ARG(interp))
171 #define ASSERT_ARGS_dump_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
172 PARROT_ASSERT_ARG(interp))
173 #define ASSERT_ARGS_GDB_P __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
174 PARROT_ASSERT_ARG(interp) \
175 , PARROT_ASSERT_ARG(s))
176 #define ASSERT_ARGS_GDB_print_reg __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
177 PARROT_ASSERT_ARG(interp))
178 #define ASSERT_ARGS_get_cmd __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
179 #define ASSERT_ARGS_get_uint __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
180 PARROT_ASSERT_ARG(cmd))
181 #define ASSERT_ARGS_get_ulong __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
182 PARROT_ASSERT_ARG(cmd))
183 #define ASSERT_ARGS_list_breakpoints __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
184 PARROT_ASSERT_ARG(pdb))
185 #define ASSERT_ARGS_nextarg __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
186 #define ASSERT_ARGS_no_such_register __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
187 PARROT_ASSERT_ARG(interp))
188 #define ASSERT_ARGS_parse_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
189 PARROT_ASSERT_ARG(str) \
190 , PARROT_ASSERT_ARG(intP))
191 #define ASSERT_ARGS_parse_key __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
192 PARROT_ASSERT_ARG(interp) \
193 , PARROT_ASSERT_ARG(str) \
194 , PARROT_ASSERT_ARG(keyP))
195 #define ASSERT_ARGS_parse_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
196 PARROT_ASSERT_ARG(interp) \
197 , PARROT_ASSERT_ARG(str) \
198 , PARROT_ASSERT_ARG(strP))
199 #define ASSERT_ARGS_skip_command __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
200 PARROT_ASSERT_ARG(str))
201 #define ASSERT_ARGS_skip_whitespace __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
202 PARROT_ASSERT_ARG(cmd))
203 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
204 /* HEADERIZER END: static */
207 * Command functions and help dispatch
210 typedef void (* debugger_func_t)(PDB_t * pdb, const char * cmd);
212 static int nomoreargs(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
214 if (*skip_whitespace(cmd) == '\0')
215 return 1;
216 else {
217 Parrot_io_eprintf(pdb->debugger, "Spurious arg\n");
218 return 0;
222 static void dbg_assign(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
224 TRACEDEB_MSG("dbg_assign");
226 PDB_assign(pdb->debugee, cmd);
229 static void dbg_break(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
231 TRACEDEB_MSG("dbg_break");
233 PDB_set_break(pdb->debugee, cmd);
236 static void dbg_continue(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
238 TRACEDEB_MSG("dbg_continue");
240 PDB_continue(pdb->debugee, cmd);
243 static void dbg_delete(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
245 TRACEDEB_MSG("dbg_delete");
247 PDB_delete_breakpoint(pdb->debugee, cmd);
250 static void dbg_disable(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
252 TRACEDEB_MSG("dbg_disable");
254 PDB_disable_breakpoint(pdb->debugee, cmd);
257 static void dbg_disassemble(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
259 TRACEDEB_MSG("dbg_disassemble");
261 PDB_disassemble(pdb->debugee, cmd);
264 static void dbg_echo(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
266 TRACEDEB_MSG("dbg_echo");
268 if (! nomoreargs(pdb, cmd))
269 return;
271 if (pdb->state & PDB_ECHO) {
272 TRACEDEB_MSG("Disabling echo");
273 pdb->state &= ~PDB_ECHO;
275 else {
276 TRACEDEB_MSG("Enabling echo");
277 pdb->state |= PDB_ECHO;
281 static void dbg_enable(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
283 PDB_enable_breakpoint(pdb->debugee, cmd);
286 static void dbg_eval(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
288 PDB_eval(pdb->debugee, cmd);
291 static void dbg_gcdebug(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
293 TRACEDEB_MSG("dbg_gcdebug");
295 if (! nomoreargs(pdb, cmd))
296 return;
298 if (pdb->state & PDB_GCDEBUG) {
299 TRACEDEB_MSG("Disabling gcdebug mode");
300 pdb->state &= ~PDB_GCDEBUG;
302 else {
303 TRACEDEB_MSG("Enabling gcdebug mode");
304 pdb->state |= PDB_GCDEBUG;
308 static void dbg_help(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
310 TRACEDEB_MSG("dbg_help");
312 PDB_help(pdb->debugee, cmd);
315 static void dbg_info(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
317 TRACEDEB_MSG("dbg_info");
319 if (! nomoreargs(pdb, cmd))
320 return;
322 PDB_info(pdb->debugger);
325 static void dbg_list(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
327 TRACEDEB_MSG("dbg_list");
329 PDB_list(pdb->debugee, cmd);
332 static void dbg_listbreakpoints(PDB_t * pdb, SHIM(const char * cmd)) /* HEADERIZER SKIP */
334 TRACEDEB_MSG("dbg_list");
336 list_breakpoints(pdb);
339 static void dbg_load(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
341 TRACEDEB_MSG("dbg_load");
343 PDB_load_source(pdb->debugee, cmd);
346 static void dbg_next(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
348 TRACEDEB_MSG("dbg_next");
350 PDB_next(pdb->debugee, cmd);
353 static void dbg_print(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
355 TRACEDEB_MSG("dbg_print");
357 PDB_print(pdb->debugee, cmd);
360 static void dbg_quit(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
362 TRACEDEB_MSG("dbg_quit");
364 if (! nomoreargs(pdb, cmd))
365 return;
367 pdb->state |= PDB_EXIT;
368 pdb->state &= ~PDB_STOPPED;
371 static void dbg_run(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
373 TRACEDEB_MSG("dbg_run");
375 PDB_init(pdb->debugee, cmd);
376 PDB_continue(pdb->debugee, NULL);
379 static void dbg_script(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
381 TRACEDEB_MSG("dbg_script");
383 PDB_script_file(pdb->debugee, cmd);
386 static void dbg_stack(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
388 TRACEDEB_MSG("dbg_stack");
390 if (! nomoreargs(pdb, cmd))
391 return;
393 PDB_backtrace(pdb->debugee);
396 static void dbg_trace(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
398 TRACEDEB_MSG("dbg_trace");
400 PDB_trace(pdb->debugee, cmd);
403 static void dbg_watch(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
405 TRACEDEB_MSG("dbg_watch");
407 PDB_watchpoint(pdb->debugee, cmd);
410 struct DebuggerCmd {
411 debugger_func_t func;
412 PARROT_OBSERVER const char * const shorthelp;
413 PARROT_OBSERVER const char * const help;
416 static const DebuggerCmd
417 cmd_assign = {
418 & dbg_assign,
419 "assign to a register",
420 "Assign a value to a register. For example:\n\
421 a I0 42\n\
422 a N1 3.14\n\
423 The first command sets I0 to 42 and the second sets N1 to 3.14."
425 cmd_break = {
426 & dbg_break,
427 "add a breakpoint",
428 "Set a breakpoint at a given line number (which must be specified).\n\n\
429 Optionally, specify a condition, in which case the breakpoint will only\n\
430 activate if the condition is met. Conditions take the form:\n\n\
431 if [REGISTER] [COMPARISON] [REGISTER or CONSTANT]\n\n\
433 For example:\n\n\
434 break 10 if I4 > I3\n\n\
435 break 45 if S1 == \"foo\"\n\n\
436 The command returns a number which is the breakpoint identifier."
438 cmd_continue = {
439 & dbg_continue,
440 "continue the program execution",
441 "Continue the program execution.\n\n\
442 Without arguments, the program runs until a breakpoint is found\n\
443 (or until the program terminates for some other reason).\n\n\
444 If a number is specified, then skip that many breakpoints.\n\n\
445 If the program has terminated, then \"continue\" will do nothing;\n\
446 use \"run\" to re-run the program."
448 cmd_delete = {
449 & dbg_delete,
450 "delete a breakpoint",
451 "Delete a breakpoint.\n\n\
452 The breakpoint to delete must be specified by its breakpoint number.\n\
453 Deleted breakpoints are gone completely. If instead you want to\n\
454 temporarily disable a breakpoint, use \"disable\"."
456 cmd_disable = {
457 & dbg_disable,
458 "disable a breakpoint",
459 "Disable a breakpoint.\n\n\
460 The breakpoint to disable must be specified by its breakpoint number.\n\
461 Disabled breakpoints are not forgotten, but have no effect until re-enabled\n\
462 with the \"enable\" command."
464 cmd_disassemble = {
465 & dbg_disassemble,
466 "disassemble the bytecode",
467 "Disassemble code"
469 cmd_echo = {
470 & dbg_echo,
471 "toggle echo of script commands",
472 "Toggle echo mode.\n\n\
473 In echo mode the script commands are written to stderr before executing."
475 cmd_enable = {
476 & dbg_enable,
477 "reenable a disabled breakpoint",
478 "Re-enable a disabled breakpoint."
480 cmd_eval = {
481 & dbg_eval,
482 "run an instruction",
483 "No documentation yet"
485 cmd_gcdebug = {
486 & dbg_gcdebug,
487 "toggle gcdebug mode",
488 "Toggle gcdebug mode.\n\n\
489 In gcdebug mode a garbage collection cycle is run before each opcocde,\n\
490 same as using the gcdebug core."
492 cmd_help = {
493 & dbg_help,
494 "print this help",
495 "Print a list of available commands."
497 cmd_info = {
498 & dbg_info,
499 "print interpreter information",
500 "Print information about the current interpreter"
502 cmd_list = {
503 & dbg_list,
504 "list the source code file",
505 "List the source code.\n\n\
506 Optionally specify the line number to begin the listing from and the number\n\
507 of lines to display."
509 cmd_listbreakpoints = {
510 & dbg_listbreakpoints,
511 "list breakpoints",
512 "List breakpoints."
514 cmd_load = {
515 & dbg_load,
516 "load a source code file",
517 "Load a source code file."
519 cmd_next = {
520 & dbg_next,
521 "run the next instruction",
522 "Execute a specified number of instructions.\n\n\
523 If a number is specified with the command (e.g. \"next 5\"), then\n\
524 execute that number of instructions, unless the program reaches a\n\
525 breakpoint, or stops for some other reason.\n\n\
526 If no number is specified, it defaults to 1."
528 cmd_print = {
529 & dbg_print,
530 "print the interpreter registers",
531 "Print register: e.g. \"p i2\"\n\
532 Note that the register type is case-insensitive. If no digits appear\n\
533 after the register type, all registers of that type are printed."
535 cmd_quit = {
536 & dbg_quit,
537 "exit the debugger",
538 "Exit the debugger"
540 cmd_run = {
541 & dbg_run,
542 "run the program",
543 "Run (or restart) the program being debugged.\n\n\
544 Arguments specified after \"run\" are passed as command line arguments to\n\
545 the program.\n"
547 cmd_script = {
548 & dbg_script,
549 "interprets a file as user commands",
550 "Interprets a file s user commands.\n\
551 Usage:\n\
552 (pdb) script file.script"
554 cmd_stack = {
555 & dbg_stack,
556 "examine the stack",
557 "Print a stack trace of the parrot VM"
559 cmd_trace = {
560 & dbg_trace,
561 "trace the next instruction",
562 "Similar to \"next\", but prints additional trace information.\n\
563 This is the same as the information you get when running Parrot with\n\
564 the -t option.\n"
566 cmd_watch = {
567 & dbg_watch,
568 "add a watchpoint",
569 "Add a watchpoint"
572 struct DebuggerCmdList {
573 PARROT_OBSERVER const char * const name;
574 char shortname;
575 PARROT_OBSERVER const DebuggerCmd * const cmd;
578 DebuggerCmdList DebCmdList [] = {
579 { "assign", 'a', &cmd_assign },
580 { "break", '\0', &cmd_break },
581 { "continue", '\0', &cmd_continue },
582 { "delete", 'd', &cmd_delete },
583 { "disable", '\0', &cmd_disable },
584 { "disassemble", '\0', &cmd_disassemble },
585 { "e", '\0', &cmd_eval },
586 { "echo", '\0', &cmd_echo },
587 { "enable", '\0', &cmd_enable },
588 { "eval", '\0', &cmd_eval },
589 { "f", '\0', &cmd_script },
590 { "gcdebug", '\0', &cmd_gcdebug },
591 { "help", '\0', &cmd_help },
592 { "info", '\0', &cmd_info },
593 { "L", '\0', &cmd_listbreakpoints },
594 { "list", 'l', &cmd_list },
595 { "load", '\0', &cmd_load },
596 { "next", '\0', &cmd_next },
597 { "print", '\0', &cmd_print },
598 { "quit", '\0', &cmd_quit },
599 { "run", '\0', &cmd_run },
600 { "script", '\0', &cmd_script },
601 { "stack", 's', &cmd_stack },
602 { "trace", '\0', &cmd_trace },
603 { "watch", '\0', &cmd_watch }
608 =item C<static const DebuggerCmd * get_cmd(const char **cmd)>
610 =cut
614 PARROT_WARN_UNUSED_RESULT
615 PARROT_CAN_RETURN_NULL
616 static const DebuggerCmd *
617 get_cmd(ARGIN_NULLOK(const char **cmd))
619 ASSERT_ARGS(get_cmd)
620 if (cmd && *cmd) {
621 const char * const start = skip_whitespace(*cmd);
622 const char *next = start;
623 char c;
624 unsigned int i, l;
625 int found = -1;
626 int hits = 0;
628 *cmd = start;
629 for (; (c= *next) != '\0' && !isspace((unsigned char)c); ++next)
630 continue;
631 l = next - start;
632 if (l == 0)
633 return NULL;
634 for (i= 0; i < sizeof (DebCmdList) / sizeof (DebuggerCmdList); ++i) {
635 const DebuggerCmdList * const cmdlist = DebCmdList + i;
636 if (l == 1 && cmdlist->shortname == (*cmd)[0]) {
637 hits = 1;
638 found = i;
639 break;
641 if (strncmp(*cmd, cmdlist->name, l) == 0) {
642 if (strlen(cmdlist->name) == l) {
643 hits = 1;
644 found = i;
645 break;
647 else {
648 ++hits;
649 found = i;
653 if (hits == 1) {
654 *cmd = skip_whitespace(next);
655 return DebCmdList[found].cmd;
658 return NULL;
663 =item C<static const char * skip_whitespace(const char *cmd)>
665 =cut
669 PARROT_WARN_UNUSED_RESULT
670 PARROT_CANNOT_RETURN_NULL
671 static const char *
672 skip_whitespace(ARGIN(const char *cmd))
674 ASSERT_ARGS(skip_whitespace)
675 while (*cmd && isspace((unsigned char)*cmd))
676 ++cmd;
677 return cmd;
682 =item C<static unsigned long get_uint(const char **cmd, unsigned int def)>
684 =cut
689 PARROT_WARN_UNUSED_RESULT
690 static unsigned long
691 get_uint(ARGMOD(const char **cmd), unsigned int def)
693 ASSERT_ARGS(get_uint)
694 char *cmdnext;
695 unsigned int result = strtoul(skip_whitespace(* cmd), & cmdnext, 0);
696 if (cmdnext != *cmd)
697 *cmd = cmdnext;
698 else
699 result = def;
700 return result;
705 =item C<static unsigned long get_ulong(const char **cmd, unsigned long def)>
707 =cut
712 PARROT_WARN_UNUSED_RESULT
713 static unsigned long
714 get_ulong(ARGMOD(const char **cmd), unsigned long def)
716 ASSERT_ARGS(get_ulong)
717 char *cmdnext;
718 unsigned long result = strtoul(skip_whitespace(* cmd), & cmdnext, 0);
719 if (cmdnext != * cmd)
720 * cmd = cmdnext;
721 else
722 result = def;
723 return result;
728 =item C<static void chop_newline(char * buf)>
730 If the C string argument end with a newline, delete it.
732 =cut
736 static void
737 chop_newline(ARGMOD(char * buf))
739 ASSERT_ARGS(chop_newline)
740 const size_t l = strlen(buf);
742 if (l > 0 && buf [l - 1] == '\n')
743 buf [l - 1] = '\0';
748 =item C<static const char * nextarg(const char *command)>
750 Returns the position just past the current argument in the PASM instruction
751 C<command>. This is not the same as C<skip_command()>, which is intended for
752 debugger commands. This function is used for C<eval>.
754 =cut
758 PARROT_CAN_RETURN_NULL
759 PARROT_WARN_UNUSED_RESULT
760 static const char *
761 nextarg(ARGIN_NULLOK(const char *command))
763 ASSERT_ARGS(nextarg)
764 /* as long as the character pointed to by command is not NULL,
765 * and it is either alphanumeric, a comma or a closing bracket,
766 * continue looking for the next argument.
768 if (command) {
769 while (isalnum((unsigned char) *command) || *command == ',' || *command == ']')
770 command++;
772 /* eat as much space as possible */
773 command = skip_whitespace(command);
776 return command;
781 =item C<static const char * skip_command(const char *str)>
783 Returns the pointer past the current debugger command. (This is an
784 alternative to the C<skip_command()> macro above.)
786 =cut
790 PARROT_CANNOT_RETURN_NULL
791 static const char *
792 skip_command(ARGIN(const char *str))
794 ASSERT_ARGS(skip_command)
795 /* while str is not null and it contains a command (no spaces),
796 * skip the character
798 while (*str && !isspace((unsigned char) *str))
799 str++;
801 /* eat all space after that */
802 return skip_whitespace(str);
807 =item C<static const char * parse_int(const char *str, int *intP)>
809 Parse an C<int> out of a string and return a pointer to just after the C<int>.
810 The output parameter C<intP> contains the parsed value.
812 =cut
816 PARROT_CANNOT_RETURN_NULL
817 PARROT_WARN_UNUSED_RESULT
818 static const char *
819 parse_int(ARGIN(const char *str), ARGOUT(int *intP))
821 ASSERT_ARGS(parse_int)
822 char *end;
824 *intP = strtol(str, &end, 0);
826 return end;
831 =item C<static const char * parse_string(PARROT_INTERP, const char *str, STRING
832 **strP)>
834 Parse a double-quoted string out of a C string and return a pointer to
835 just after the string. The parsed string is converted to a Parrot
836 C<STRING> and placed in the output parameter C<strP>.
838 =cut
842 PARROT_CAN_RETURN_NULL
843 PARROT_WARN_UNUSED_RESULT
844 static const char *
845 parse_string(PARROT_INTERP, ARGIN(const char *str), ARGOUT(STRING **strP))
847 ASSERT_ARGS(parse_string)
848 const char *string_start;
850 /* if this is not a quoted string, there's nothing to parse */
851 if (*str != '"')
852 return NULL;
854 /* skip the quote */
855 str++;
857 string_start = str;
859 /* parse while there's no closing quote */
860 while (*str && *str != '"') {
861 /* skip any potentially escaped quotes */
862 if (*str == '\\' && str[1])
863 str += 2;
864 else
865 str++;
868 /* create the output STRING */
869 *strP = string_make(interp, string_start, (UINTVAL)(str - string_start),
870 NULL, 0);
872 /* skip the closing quote */
873 if (*str)
874 str++;
876 return str;
881 =item C<static const char* parse_key(PARROT_INTERP, const char *str, PMC
882 **keyP)>
884 Parse an aggregate key out of a string and return a pointer to just
885 after the key. Currently only string and integer keys are allowed.
887 =cut
891 PARROT_CAN_RETURN_NULL
892 PARROT_WARN_UNUSED_RESULT
893 static const char*
894 parse_key(PARROT_INTERP, ARGIN(const char *str), ARGOUT(PMC **keyP))
896 ASSERT_ARGS(parse_key)
897 /* clear output parameter */
898 *keyP = NULL;
900 /* make sure it's a key */
901 if (*str != '[')
902 return NULL;
904 /* Skip [ */
905 str++;
907 /* if this is a string key, create a Parrot STRING */
908 if (*str == '"') {
909 STRING *parrot_string;
910 str = parse_string(interp, str, &parrot_string);
911 *keyP = key_new_string(interp, parrot_string);
913 /* if this is a numeric key */
914 else if (isdigit((unsigned char) *str)) {
915 int value;
916 str = parse_int(str, &value);
917 *keyP = key_new_integer(interp, (INTVAL) value);
919 /* unsupported case; neither a string nor a numeric key */
920 else {
921 return NULL;
924 /* hm, but if this doesn't match, it's probably an error */
925 /* XXX str can be NULL from parse_string() */
926 if (*str != ']')
927 return NULL;
929 /* skip the closing brace on the key */
930 return ++str;
935 =item C<static void debugger_cmdline(PARROT_INTERP)>
937 Debugger command line.
939 Gets and executes commands, looping until the debugger state
940 is changed, either to exit or to start executing code.
942 =cut
946 static void
947 debugger_cmdline(PARROT_INTERP)
949 ASSERT_ARGS(debugger_cmdline)
950 TRACEDEB_MSG("debugger_cmdline");
952 /*while (!(interp->pdb->state & PDB_EXIT)) {*/
953 while (interp->pdb->state & PDB_STOPPED) {
954 const char * command;
955 interp->pdb->state &= ~PDB_TRACING;
956 PDB_get_command(interp);
957 command = interp->pdb->cur_command;
958 if (command[0] == '\0')
959 command = interp->pdb->last_command;
961 PDB_run_command(interp, command);
963 TRACEDEB_MSG("debugger_cmdline finished");
968 =item C<static void close_script_file(PARROT_INTERP)>
970 Close the script file, returning to command prompt mode.
972 =cut
976 static void
977 close_script_file(PARROT_INTERP)
979 ASSERT_ARGS(close_script_file)
980 TRACEDEB_MSG("Closing debugger script file");
981 if (interp->pdb->script_file) {
982 fclose(interp->pdb->script_file);
983 interp->pdb->script_file = NULL;
984 interp->pdb->state|= PDB_STOPPED;
985 interp->pdb->last_command[0] = '\0';
986 interp->pdb->cur_command[0] = '\0';
992 =item C<void Parrot_debugger_init(PARROT_INTERP)>
994 Initializes the Parrot debugger, if it's not already initialized.
996 =cut
1000 PARROT_EXPORT
1001 void
1002 Parrot_debugger_init(PARROT_INTERP)
1004 ASSERT_ARGS(Parrot_debugger_init)
1005 TRACEDEB_MSG("Parrot_debugger_init");
1007 if (! interp->pdb) {
1008 PDB_t *pdb = mem_allocate_zeroed_typed(PDB_t);
1009 Parrot_Interp debugger = Parrot_new(interp);
1010 interp->pdb = pdb;
1011 debugger->pdb = pdb;
1012 pdb->debugee = interp;
1013 pdb->debugger = debugger;
1015 /* Allocate space for command line buffers, NUL terminated c strings */
1016 pdb->cur_command = (char *)mem_sys_allocate_zeroed(DEBUG_CMD_BUFFER_LENGTH + 1);
1017 pdb->last_command = (char *)mem_sys_allocate_zeroed(DEBUG_CMD_BUFFER_LENGTH + 1);
1018 pdb->file = mem_allocate_zeroed_typed(PDB_file_t);
1021 /* PDB_disassemble(interp, NULL); */
1023 interp->pdb->state |= PDB_RUNNING;
1028 =item C<void Parrot_debugger_destroy(PARROT_INTERP)>
1030 Destroy the current Parrot debugger instance.
1032 =cut
1036 PARROT_EXPORT
1037 void
1038 Parrot_debugger_destroy(PARROT_INTERP)
1040 ASSERT_ARGS(Parrot_debugger_destroy)
1041 /* Unfinished.
1042 Free all debugger allocated resources.
1044 PDB_t *pdb = interp->pdb;
1046 TRACEDEB_MSG("Parrot_debugger_destroy");
1048 PARROT_ASSERT(pdb);
1049 PARROT_ASSERT(pdb->debugee == interp);
1051 mem_sys_free(pdb->last_command);
1052 mem_sys_free(pdb->cur_command);
1054 mem_sys_free(pdb);
1055 interp->pdb = NULL;
1060 =item C<void Parrot_debugger_load(PARROT_INTERP, STRING *filename)>
1062 Loads a Parrot source file for the current program.
1064 =cut
1068 PARROT_EXPORT
1069 void
1070 Parrot_debugger_load(PARROT_INTERP, ARGIN_NULLOK(STRING *filename))
1072 ASSERT_ARGS(Parrot_debugger_load)
1073 char *file;
1075 TRACEDEB_MSG("Parrot_debugger_load");
1077 if (!interp->pdb)
1078 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1080 file = Parrot_str_to_cstring(interp, filename);
1081 PDB_load_source(interp, file);
1082 Parrot_str_free_cstring(file);
1087 =item C<void Parrot_debugger_start(PARROT_INTERP, opcode_t * cur_opcode)>
1089 Start debugger.
1091 =cut
1095 PARROT_EXPORT
1096 void
1097 Parrot_debugger_start(PARROT_INTERP, ARGIN(opcode_t * cur_opcode))
1099 ASSERT_ARGS(Parrot_debugger_start)
1100 TRACEDEB_MSG("Parrot_debugger_start");
1102 if (!interp->pdb)
1103 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1105 interp->pdb->cur_opcode = interp->code->base.data;
1107 if (interp->pdb->state & PDB_ENTER) {
1108 if (!interp->pdb->file) {
1109 /* PDB_disassemble(interp, NULL); */
1111 interp->pdb->state &= ~PDB_ENTER;
1114 interp->pdb->cur_opcode = cur_opcode;
1116 interp->pdb->state |= PDB_STOPPED;
1118 debugger_cmdline(interp);
1120 if (interp->pdb->state & PDB_EXIT) {
1121 TRACEDEB_MSG("Parrot_debugger_start Parrot_exit");
1122 Parrot_exit(interp, 0);
1124 TRACEDEB_MSG("Parrot_debugger_start ends");
1129 =item C<void Parrot_debugger_break(PARROT_INTERP, opcode_t * cur_opcode)>
1131 Breaks execution and drops into the debugger. If we are already into the
1132 debugger and it is the first call, set a breakpoint.
1134 When you re run/continue the program being debugged it will pay no attention to
1135 the debug ops.
1137 =cut
1141 PARROT_EXPORT
1142 void
1143 Parrot_debugger_break(PARROT_INTERP, ARGIN(opcode_t * cur_opcode))
1145 ASSERT_ARGS(Parrot_debugger_break)
1146 TRACEDEB_MSG("Parrot_debugger_break");
1148 if (!interp->pdb)
1149 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1151 if (!interp->pdb->file)
1152 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No file loaded to debug");
1154 if (!(interp->pdb->state & PDB_BREAK)) {
1155 TRACEDEB_MSG("Parrot_debugger_break - in BREAK state");
1156 new_runloop_jump_point(interp);
1157 if (setjmp(interp->current_runloop->resume)) {
1158 fprintf(stderr, "Unhandled exception in debugger\n");
1159 return;
1162 interp->pdb->state |= PDB_BREAK;
1163 interp->pdb->state |= PDB_STOPPED;
1164 interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
1166 /*PDB_set_break(interp, NULL);*/
1168 debugger_cmdline(interp);
1170 /* RT #42378 this is not ok */
1171 /* exit(EXIT_SUCCESS); */
1173 else {
1174 interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
1175 /*PDB_set_break(interp, NULL);*/
1177 TRACEDEB_MSG("Parrot_debugger_break done");
1182 =item C<void PDB_get_command(PARROT_INTERP)>
1184 Get a command from the user input to execute.
1186 It saves the last command executed (in C<< pdb->last_command >>), so it
1187 first frees the old one and updates it with the current one.
1189 Also prints the next line to run if the program is still active.
1191 The user input can't be longer than DEBUG_CMD_BUFFER_LENGTH characters.
1193 The input is saved in C<< pdb->cur_command >>.
1195 =cut
1199 void
1200 PDB_get_command(PARROT_INTERP)
1202 ASSERT_ARGS(PDB_get_command)
1203 unsigned int i;
1204 int ch;
1205 char *c;
1206 PDB_t * const pdb = interp->pdb;
1208 /***********************************
1209 **** Testing ****
1210 Do not delete yet
1211 the commented out
1212 parts
1213 ***********************************/
1215 /* flush the buffered data */
1216 fflush(stdout);
1218 TRACEDEB_MSG("PDB_get_command");
1220 PARROT_ASSERT(pdb->last_command);
1221 PARROT_ASSERT(pdb->cur_command);
1223 if (interp->pdb->script_file) {
1224 FILE *fd = interp->pdb->script_file;
1225 char buf[DEBUG_CMD_BUFFER_LENGTH+1];
1226 const char *ptr;
1228 do {
1229 if (fgets(buf, DEBUG_CMD_BUFFER_LENGTH, fd) == NULL) {
1230 close_script_file(interp);
1231 return;
1233 ++pdb->script_line;
1234 chop_newline(buf);
1235 #if TRACE_DEBUGGER
1236 fprintf(stderr, "script (%lu): '%s'\n", pdb->script_line, buf);
1237 #endif
1239 /* skip spaces */
1240 ptr = skip_whitespace(buf);
1242 /* skip blank and commented lines */
1243 } while (*ptr == '\0' || *ptr == '#');
1245 if (pdb->state & PDB_ECHO)
1246 Parrot_io_eprintf(pdb->debugger, "[%lu %s]\n", pdb->script_line, buf);
1248 #if TRACE_DEBUGGER
1249 fprintf(stderr, "(script) %s\n", buf);
1250 #endif
1252 strcpy(pdb->cur_command, buf);
1254 else {
1256 /* update the last command */
1257 if (pdb->cur_command[0] != '\0')
1258 strcpy(pdb->last_command, pdb->cur_command);
1260 i = 0;
1262 c = pdb->cur_command;
1264 /*Parrot_io_eprintf(pdb->debugger, "\n(pdb) ");*/
1265 Parrot_io_eprintf(pdb->debugger, "\n");
1267 /* skip leading whitespace */
1269 do {
1270 ch = fgetc(stdin);
1271 } while (isspace((unsigned char)ch) && ch != '\n');
1274 Interp * interpdeb = interp->pdb->debugger;
1275 STRING * readline = CONST_STRING(interpdeb, "readline_interactive");
1276 STRING * prompt = CONST_STRING(interpdeb, "(pdb) ");
1277 STRING *s= Parrot_str_new(interpdeb, NULL, 0);
1278 PMC *tmp_stdin = Parrot_io_stdhandle(interpdeb, 0, NULL);
1280 Parrot_PCCINVOKE(interpdeb,
1281 tmp_stdin, readline,
1282 "S->S", prompt, & s);
1284 char * aux = Parrot_str_to_cstring(interpdeb, s);
1285 strcpy(c, aux);
1286 Parrot_str_free_cstring(aux);
1288 ch = '\n';
1291 /* generate string (no more than buffer length) */
1293 while (ch != EOF && ch != '\n' && (i < DEBUG_CMD_BUFFER_LENGTH)) {
1294 c[i++] = (char)ch;
1295 ch = fgetc(tmp_stdin);
1298 c[i] = '\0';
1300 if (ch == -1)
1301 strcpy(c, "quit");
1307 =item C<void PDB_script_file(PARROT_INTERP, const char *command)>
1309 Interprets the contents of a file as user input commands
1311 =cut
1315 PARROT_EXPORT
1316 void
1317 PDB_script_file(PARROT_INTERP, ARGIN(const char *command))
1319 ASSERT_ARGS(PDB_script_file)
1320 FILE *fd;
1322 TRACEDEB_MSG("PDB_script_file");
1324 /* If already executing a script, close it */
1325 close_script_file(interp);
1327 TRACEDEB_MSG("Opening debugger script file");
1329 fd = fopen(command, "r");
1330 if (!fd) {
1331 Parrot_io_eprintf(interp->pdb->debugger,
1332 "Error reading script file %s.\n",
1333 command);
1334 return;
1336 interp->pdb->script_file = fd;
1337 interp->pdb->script_line = 0;
1338 TRACEDEB_MSG("PDB_script_file finished");
1343 =item C<int PDB_run_command(PARROT_INTERP, const char *command)>
1345 Run a command.
1347 Hash the command to make a simple switch calling the correct handler.
1349 =cut
1353 PARROT_IGNORABLE_RESULT
1355 PDB_run_command(PARROT_INTERP, ARGIN(const char *command))
1357 ASSERT_ARGS(PDB_run_command)
1358 PDB_t * const pdb = interp->pdb;
1359 const DebuggerCmd *cmd;
1361 /* keep a pointer to the command, in case we need to report an error */
1363 const char * cmdline = command;
1365 TRACEDEB_MSG("PDB_run_command");
1366 cmd = get_cmd(& cmdline);
1368 if (cmd) {
1369 (* cmd->func)(pdb, cmdline);
1370 return 0;
1372 else {
1373 if (*cmdline == '\0') {
1374 return 0;
1376 else {
1377 Parrot_io_eprintf(pdb->debugger,
1378 "Undefined command: \"%s\"", command);
1379 if (pdb->script_file)
1380 Parrot_io_eprintf(pdb->debugger, " in line %lu", pdb->script_line);
1381 Parrot_io_eprintf(pdb->debugger, ". Try \"help\".");
1382 close_script_file(interp);
1383 return 1;
1390 =item C<void PDB_next(PARROT_INTERP, const char *command)>
1392 Execute the next N operation(s).
1394 Inits the program if needed, runs the next N >= 1 operations and stops.
1396 =cut
1400 void
1401 PDB_next(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1403 ASSERT_ARGS(PDB_next)
1404 PDB_t * const pdb = interp->pdb;
1405 Interp *debugee;
1407 TRACEDEB_MSG("PDB_next");
1409 /* Init the program if it's not running */
1410 if (!(pdb->state & PDB_RUNNING))
1411 PDB_init(interp, command);
1413 /* Get the number of operations to execute if any */
1414 pdb->tracing = get_ulong(& command, 1);
1416 /* Erase the stopped flag */
1417 pdb->state &= ~PDB_STOPPED;
1419 /* Testing use of the debugger runloop */
1420 #if 0
1422 /* Execute */
1423 for (; n && pdb->cur_opcode; n--)
1424 DO_OP(pdb->cur_opcode, pdb->debugee);
1426 /* Set the stopped flag */
1427 pdb->state |= PDB_STOPPED;
1429 /* If program ended */
1432 * RT #46119 this doesn't handle resume opcodes
1434 if (!pdb->cur_opcode)
1435 (void)PDB_program_end(interp);
1436 #endif
1438 debugee = pdb->debugee;
1440 new_runloop_jump_point(debugee);
1441 if (setjmp(debugee->current_runloop->resume)) {
1442 Parrot_io_eprintf(pdb->debugger, "Unhandled exception while tracing\n");
1443 pdb->state |= PDB_STOPPED;
1444 return;
1447 Parrot_runcore_switch(pdb->debugee, CONST_STRING(interp, "debugger"));
1449 TRACEDEB_MSG("PDB_next finished");
1454 =item C<void PDB_trace(PARROT_INTERP, const char *command)>
1456 Execute the next N operations; if no number is specified, it defaults to 1.
1458 =cut
1462 void
1463 PDB_trace(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1465 ASSERT_ARGS(PDB_trace)
1466 PDB_t * const pdb = interp->pdb;
1467 Interp *debugee;
1469 TRACEDEB_MSG("PDB_trace");
1471 /* if debugger is not running yet, initialize */
1473 if (!(pdb->state & PDB_RUNNING))
1474 PDB_init(interp, command);
1477 /* get the number of ops to run, if specified */
1478 pdb->tracing = get_ulong(& command, 1);
1480 /* clear the PDB_STOPPED flag, we'll be running n ops now */
1481 pdb->state &= ~PDB_STOPPED;
1482 debugee = pdb->debugee;
1484 /* execute n ops */
1485 new_runloop_jump_point(debugee);
1486 if (setjmp(debugee->current_runloop->resume)) {
1487 Parrot_io_eprintf(pdb->debugger, "Unhandled exception while tracing\n");
1488 pdb->state |= PDB_STOPPED;
1489 return;
1492 pdb->state |= PDB_TRACING;
1493 Parrot_runcore_switch(pdb->debugee, CONST_STRING(interp, "debugger"));
1495 /* Clear the following when done some testing */
1497 /* we just stopped */
1498 pdb->state |= PDB_STOPPED;
1500 /* If program ended */
1501 if (!pdb->cur_opcode)
1502 (void)PDB_program_end(interp);
1503 pdb->state |= PDB_RUNNING;
1504 pdb->state &= ~PDB_STOPPED;
1506 TRACEDEB_MSG("PDB_trace finished");
1511 =item C<static unsigned short condition_regtype(const char *cmd)>
1513 =cut
1517 static unsigned short
1518 condition_regtype(ARGIN(const char *cmd))
1520 ASSERT_ARGS(condition_regtype)
1521 switch (*cmd) {
1522 case 'i':
1523 case 'I':
1524 return PDB_cond_int;
1525 case 'n':
1526 case 'N':
1527 return PDB_cond_num;
1528 case 's':
1529 case 'S':
1530 return PDB_cond_str;
1531 case 'p':
1532 case 'P':
1533 return PDB_cond_pmc;
1534 default:
1535 return 0;
1541 =item C<PDB_condition_t * PDB_cond(PARROT_INTERP, const char *command)>
1543 Analyzes a condition from the user input.
1545 =cut
1549 PARROT_CAN_RETURN_NULL
1550 PDB_condition_t *
1551 PDB_cond(PARROT_INTERP, ARGIN(const char *command))
1553 ASSERT_ARGS(PDB_cond)
1554 PDB_condition_t *condition;
1555 const char *auxcmd;
1556 char str[DEBUG_CMD_BUFFER_LENGTH + 1];
1557 unsigned short cond_argleft;
1558 unsigned short cond_type;
1559 unsigned char regleft;
1560 int i, reg_number;
1562 TRACEDEB_MSG("PDB_cond");
1564 /* Return if no more arguments */
1565 if (!(command && *command)) {
1566 Parrot_io_eprintf(interp->pdb->debugger, "No condition specified\n");
1567 return NULL;
1570 command = skip_whitespace(command);
1571 #if TRACE_DEBUGGER
1572 fprintf(stderr, "PDB_trace: '%s'\n", command);
1573 #endif
1575 cond_argleft = condition_regtype(command);
1577 /* get the register number */
1578 auxcmd = ++command;
1579 regleft = (unsigned char)get_uint(&command, 0);
1580 if (auxcmd == command) {
1581 Parrot_io_eprintf(interp->pdb->debugger, "Invalid register\n");
1582 return NULL;
1585 /* Now the condition */
1586 command = skip_whitespace(command);
1587 switch (*command) {
1588 case '>':
1589 if (*(command + 1) == '=')
1590 cond_type = PDB_cond_ge;
1591 else
1592 cond_type = PDB_cond_gt;
1593 break;
1594 case '<':
1595 if (*(command + 1) == '=')
1596 cond_type = PDB_cond_le;
1597 else
1598 cond_type = PDB_cond_lt;
1599 break;
1600 case '=':
1601 if (*(command + 1) == '=')
1602 cond_type = PDB_cond_eq;
1603 else
1604 goto INV_COND;
1605 break;
1606 case '!':
1607 if (*(command + 1) == '=')
1608 cond_type = PDB_cond_ne;
1609 else
1610 goto INV_COND;
1611 break;
1612 case '\0':
1613 if (cond_argleft != PDB_cond_str && cond_argleft != PDB_cond_pmc) {
1614 Parrot_io_eprintf(interp->pdb->debugger, "Invalid null condition\n");
1615 return NULL;
1617 cond_type = PDB_cond_notnull;
1618 break;
1619 default:
1620 INV_COND: Parrot_io_eprintf(interp->pdb->debugger, "Invalid condition\n");
1621 return NULL;
1624 /* if there's an '=', skip it */
1625 if (*(command + 1) == '=')
1626 command += 2;
1627 else
1628 command++;
1630 command = skip_whitespace(command);
1632 /* return if no notnull condition and no more arguments */
1633 if (!(command && *command) && (cond_type != PDB_cond_notnull)) {
1634 Parrot_io_eprintf(interp->pdb->debugger, "Can't compare a register with nothing\n");
1635 return NULL;
1638 /* Allocate new condition */
1639 condition = mem_allocate_zeroed_typed(PDB_condition_t);
1641 condition->type = cond_argleft | cond_type;
1643 if (cond_type != PDB_cond_notnull) {
1645 if (isalpha((unsigned char)*command)) {
1646 /* It's a register - we first check that it's the correct type */
1648 unsigned short cond_argright = condition_regtype(command);
1650 if (cond_argright != cond_argleft) {
1651 Parrot_io_eprintf(interp->pdb->debugger, "Register types don't agree\n");
1652 mem_sys_free(condition);
1653 return NULL;
1656 /* Now we check and store the register number */
1657 auxcmd = ++command;
1658 reg_number = (int)get_uint(&command, 0);
1659 if (auxcmd == command) {
1660 Parrot_io_eprintf(interp->pdb->debugger, "Invalid register\n");
1661 mem_sys_free(condition);
1662 return NULL;
1665 if (reg_number < 0) {
1666 Parrot_io_eprintf(interp->pdb->debugger, "Out-of-bounds register\n");
1667 mem_sys_free(condition);
1668 return NULL;
1671 condition->value = mem_allocate_typed(int);
1672 *(int *)condition->value = reg_number;
1674 /* If the first argument was an integer */
1675 else if (condition->type & PDB_cond_int) {
1676 /* This must be either an integer constant or register */
1677 condition->value = mem_allocate_typed(INTVAL);
1678 *(INTVAL *)condition->value = (INTVAL)atoi(command);
1679 condition->type |= PDB_cond_const;
1681 else if (condition->type & PDB_cond_num) {
1682 condition->value = mem_allocate_typed(FLOATVAL);
1683 *(FLOATVAL *)condition->value = (FLOATVAL)atof(command);
1684 condition->type |= PDB_cond_const;
1686 else if (condition->type & PDB_cond_str) {
1687 for (i = 1; ((command[i] != '"') && (i < DEBUG_CMD_BUFFER_LENGTH)); i++)
1688 str[i - 1] = command[i];
1689 str[i - 1] = '\0';
1690 #if TRACE_DEBUGGER
1691 fprintf(stderr, "PDB_break: '%s'\n", str);
1692 #endif
1693 condition->value = string_make(interp, str, (UINTVAL)(i - 1),
1694 NULL, 0);
1696 condition->type |= PDB_cond_const;
1698 else if (condition->type & PDB_cond_pmc) {
1699 /* RT #46123 Need to figure out what to do in this case.
1700 * For the time being, we just bail. */
1701 Parrot_io_eprintf(interp->pdb->debugger, "Can't compare PMC with constant\n");
1702 mem_sys_free(condition);
1703 return NULL;
1708 return condition;
1713 =item C<void PDB_watchpoint(PARROT_INTERP, const char *command)>
1715 Set a watchpoint.
1717 =cut
1721 void
1722 PDB_watchpoint(PARROT_INTERP, ARGIN(const char *command))
1724 ASSERT_ARGS(PDB_watchpoint)
1725 PDB_t * const pdb = interp->pdb;
1726 PDB_condition_t * const condition = PDB_cond(interp, command);
1728 if (!condition)
1729 return;
1731 /* Add it to the head of the list */
1732 if (pdb->watchpoint)
1733 condition->next = pdb->watchpoint;
1734 pdb->watchpoint = condition;
1735 fprintf(stderr, "Adding watchpoint\n");
1740 =item C<void PDB_set_break(PARROT_INTERP, const char *command)>
1742 Set a break point, the source code file must be loaded.
1744 =cut
1748 void
1749 PDB_set_break(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1751 ASSERT_ARGS(PDB_set_break)
1752 PDB_t * const pdb = interp->pdb;
1753 PDB_breakpoint_t *newbreak;
1754 PDB_breakpoint_t **lbreak;
1755 PDB_line_t *line = NULL;
1756 long bp_id;
1757 opcode_t *breakpos = NULL;
1759 unsigned long ln = get_ulong(& command, 0);
1761 TRACEDEB_MSG("PDB_set_break");
1763 /* If there is a source file use line number, else opcode position */
1766 if (pdb->file) {
1767 TRACEDEB_MSG("PDB_set_break file");
1769 if (!pdb->file->size) {
1770 Parrot_io_eprintf(pdb->debugger,
1771 "Can't set a breakpoint in empty file\n");
1772 return;
1775 /* If no line number was specified, set it at the current line */
1776 if (ln != 0) {
1777 unsigned long i;
1779 /* Move to the line where we will set the break point */
1780 line = pdb->file->line;
1782 for (i = 1; ((i < ln) && (line->next)); i++)
1783 line = line->next;
1785 /* Abort if the line number provided doesn't exist */
1786 if (line == NULL || !line->next) {
1787 Parrot_io_eprintf(pdb->debugger,
1788 "Can't set a breakpoint at line number %li\n", ln);
1789 return;
1792 else {
1793 /* Get the line to set it */
1794 line = pdb->file->line;
1796 TRACEDEB_MSG("PDB_set_break reading ops");
1797 while (line->opcode != pdb->cur_opcode) {
1798 line = line->next;
1799 if (!line) {
1800 Parrot_io_eprintf(pdb->debugger,
1801 "No current line found and no line number specified\n");
1802 return;
1806 /* Skip lines that are not related to an opcode */
1807 while (line && !line->opcode)
1808 line = line->next;
1809 /* Abort if the line number provided doesn't exist */
1810 if (!line) {
1811 Parrot_io_eprintf(pdb->debugger,
1812 "Can't set a breakpoint at line number %li\n", ln);
1813 return;
1816 breakpos = line->opcode;
1818 else {
1819 TRACEDEB_MSG("PDB_set_break no file");
1820 breakpos = interp->code->base.data + ln;
1823 TRACEDEB_MSG("PDB_set_break allocate breakpoint");
1824 /* Allocate the new break point */
1825 newbreak = mem_allocate_zeroed_typed(PDB_breakpoint_t);
1827 if (command) {
1828 /*command = skip_command(command);*/
1830 else {
1831 Parrot_ex_throw_from_c_args(interp, NULL, 1,
1832 "NULL command passed to PDB_set_break");
1835 /* if there is another argument to break, besides the line number,
1836 * it should be an 'if', so we call another handler. */
1837 if (command && *command) {
1838 command = skip_whitespace(command);
1839 while (! isspace((unsigned char)*command))
1840 ++command;
1841 command = skip_whitespace(command);
1842 newbreak->condition = PDB_cond(interp, command);
1845 /* Set the address where to stop */
1846 newbreak->pc = breakpos;
1848 /* No next breakpoint */
1849 newbreak->next = NULL;
1851 /* Don't skip (at least initially) */
1852 newbreak->skip = 0;
1854 /* Add the breakpoint to the end of the list */
1855 bp_id = 1;
1856 lbreak = & pdb->breakpoint;
1857 while (*lbreak) {
1858 bp_id = (*lbreak)->id + 1;
1859 lbreak = & (*lbreak)->next;
1861 newbreak->prev = *lbreak;
1862 *lbreak = newbreak;
1863 newbreak->id = bp_id;
1865 /* Show breakpoint position */
1867 Parrot_io_eprintf(pdb->debugger, "Breakpoint %li at", newbreak->id);
1868 if (line)
1869 Parrot_io_eprintf(pdb->debugger, " line %li", line->number);
1870 Parrot_io_eprintf(pdb->debugger, " pos %li\n", newbreak->pc - interp->code->base.data);
1875 =item C<static void list_breakpoints(PDB_t *pdb)>
1877 =cut
1881 static void
1882 list_breakpoints(ARGIN(PDB_t *pdb))
1884 ASSERT_ARGS(list_breakpoints)
1886 PDB_breakpoint_t **lbreak;
1887 for (lbreak = & pdb->breakpoint; *lbreak; lbreak = & (*lbreak)->next) {
1888 PDB_breakpoint_t *br = *lbreak;
1889 Parrot_io_eprintf(pdb->debugger, "Breakpoint %li at", br->id);
1890 Parrot_io_eprintf(pdb->debugger, " pos %li", br->pc - pdb->debugee->code->base.data);
1891 if (br->skip == -1)
1892 Parrot_io_eprintf(pdb->debugger, " (disabled)");
1893 Parrot_io_eprintf(pdb->debugger, "\n");
1899 =item C<void PDB_init(PARROT_INTERP, const char *command)>
1901 Init the program.
1903 =cut
1907 void
1908 PDB_init(PARROT_INTERP, SHIM(const char *command))
1910 ASSERT_ARGS(PDB_init)
1911 PDB_t * const pdb = interp->pdb;
1913 /* Restart if we are already running */
1914 if (pdb->state & PDB_RUNNING)
1915 Parrot_io_eprintf(pdb->debugger, "Restarting\n");
1917 /* Add the RUNNING state */
1918 pdb->state |= PDB_RUNNING;
1923 =item C<void PDB_continue(PARROT_INTERP, const char *command)>
1925 Continue running the program. If a number is specified, skip that many
1926 breakpoints.
1928 =cut
1932 void
1933 PDB_continue(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1935 ASSERT_ARGS(PDB_continue)
1936 PDB_t * const pdb = interp->pdb;
1937 unsigned long ln = 0;
1939 TRACEDEB_MSG("PDB_continue");
1941 /* Skip any breakpoint? */
1942 if (command)
1943 ln = get_ulong(& command, 0);
1945 if (ln != 0) {
1946 if (!pdb->breakpoint) {
1947 Parrot_io_eprintf(pdb->debugger, "No breakpoints to skip\n");
1948 return;
1951 PDB_skip_breakpoint(interp, ln);
1954 /* Run while no break point is reached */
1956 while (!PDB_break(interp))
1957 DO_OP(pdb->cur_opcode, pdb->debugee);
1960 #if 0
1961 pdb->tracing = 0;
1962 Parrot_runcore_switch(pdb->debugee, CONST_STRING(interp, "debugger"));
1964 new_internal_exception(pdb->debugee);
1965 if (setjmp(pdb->debugee->exceptions->destination)) {
1966 Parrot_io_eprintf(pdb->debugee, "Unhandled exception while debugging: %Ss\n",
1967 pdb->debugee->exceptions->msg);
1968 pdb->state |= PDB_STOPPED;
1969 return;
1971 runops_int(pdb->debugee, pdb->debugee->code->base.data - pdb->cur_opcode);
1972 if (!pdb->cur_opcode)
1973 (void)PDB_program_end(interp);
1974 #endif
1975 pdb->state |= PDB_RUNNING;
1976 pdb->state &= ~PDB_BREAK;
1977 pdb->state &= ~PDB_STOPPED;
1982 =item C<PDB_breakpoint_t * PDB_find_breakpoint(PARROT_INTERP, const char
1983 *command)>
1985 Find breakpoint number N; returns C<NULL> if the breakpoint doesn't
1986 exist or if no breakpoint was specified.
1988 =cut
1992 PARROT_CAN_RETURN_NULL
1993 PARROT_WARN_UNUSED_RESULT
1994 PDB_breakpoint_t *
1995 PDB_find_breakpoint(PARROT_INTERP, ARGIN(const char *command))
1997 ASSERT_ARGS(PDB_find_breakpoint)
1998 const char *oldcmd = command;
1999 const unsigned long n = get_ulong(&command, 0);
2000 if (command != oldcmd) {
2001 PDB_breakpoint_t *breakpoint = interp->pdb->breakpoint;
2003 while (breakpoint && breakpoint->id != n)
2004 breakpoint = breakpoint->next;
2006 if (!breakpoint) {
2007 Parrot_io_eprintf(interp->pdb->debugger, "No breakpoint number %ld", n);
2008 return NULL;
2011 return breakpoint;
2013 else {
2014 /* Report an appropriate error */
2015 if (*command)
2016 Parrot_io_eprintf(interp->pdb->debugger, "Not a valid breakpoint");
2017 else
2018 Parrot_io_eprintf(interp->pdb->debugger, "No breakpoint specified");
2020 return NULL;
2026 =item C<void PDB_disable_breakpoint(PARROT_INTERP, const char *command)>
2028 Disable a breakpoint; it can be reenabled with the enable command.
2030 =cut
2034 void
2035 PDB_disable_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2037 ASSERT_ARGS(PDB_disable_breakpoint)
2038 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2040 /* if the breakpoint exists, disable it. */
2041 if (breakpoint)
2042 breakpoint->skip = -1;
2047 =item C<void PDB_enable_breakpoint(PARROT_INTERP, const char *command)>
2049 Reenable a disabled breakpoint; if the breakpoint was not disabled, has
2050 no effect.
2052 =cut
2056 void
2057 PDB_enable_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2059 ASSERT_ARGS(PDB_enable_breakpoint)
2060 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2062 /* if the breakpoint exists, and it was disabled, enable it. */
2063 if (breakpoint && breakpoint->skip == -1)
2064 breakpoint->skip = 0;
2069 =item C<void PDB_delete_breakpoint(PARROT_INTERP, const char *command)>
2071 Delete a breakpoint.
2073 =cut
2077 void
2078 PDB_delete_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2080 ASSERT_ARGS(PDB_delete_breakpoint)
2081 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2082 const PDB_line_t *line;
2083 long bp_id;
2085 if (breakpoint) {
2086 if (!interp->pdb->file)
2087 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No file loaded");
2089 line = interp->pdb->file->line;
2090 while (line->opcode != breakpoint->pc)
2091 line = line->next;
2093 /* Delete the condition structure, if there is one */
2094 if (breakpoint->condition) {
2095 PDB_delete_condition(interp, breakpoint);
2096 breakpoint->condition = NULL;
2099 /* Remove the breakpoint from the list */
2100 if (breakpoint->prev && breakpoint->next) {
2101 breakpoint->prev->next = breakpoint->next;
2102 breakpoint->next->prev = breakpoint->prev;
2104 else if (breakpoint->prev && !breakpoint->next) {
2105 breakpoint->prev->next = NULL;
2107 else if (!breakpoint->prev && breakpoint->next) {
2108 breakpoint->next->prev = NULL;
2109 interp->pdb->breakpoint = breakpoint->next;
2111 else {
2112 interp->pdb->breakpoint = NULL;
2114 bp_id = breakpoint->id;
2115 /* Kill the breakpoint */
2116 mem_sys_free(breakpoint);
2118 Parrot_io_eprintf(interp->pdb->debugger, "Breakpoint %li deleted\n", bp_id);
2124 =item C<void PDB_delete_condition(PARROT_INTERP, PDB_breakpoint_t *breakpoint)>
2126 Delete a condition associated with a breakpoint.
2128 =cut
2132 void
2133 PDB_delete_condition(SHIM_INTERP, ARGMOD(PDB_breakpoint_t *breakpoint))
2135 ASSERT_ARGS(PDB_delete_condition)
2136 if (breakpoint->condition->value) {
2137 if (breakpoint->condition->type & PDB_cond_str) {
2138 /* 'value' is a string, so we need to be careful */
2139 PObj_external_CLEAR((STRING*)breakpoint->condition->value);
2140 PObj_on_free_list_SET((STRING*)breakpoint->condition->value);
2141 /* it should now be properly garbage collected after
2142 we destroy the condition */
2144 else {
2145 /* 'value' is a float or an int, so we can just free it */
2146 mem_sys_free(breakpoint->condition->value);
2147 breakpoint->condition->value = NULL;
2151 mem_sys_free(breakpoint->condition);
2152 breakpoint->condition = NULL;
2157 =item C<void PDB_skip_breakpoint(PARROT_INTERP, unsigned long i)>
2159 Skip C<i> times all breakpoints.
2161 =cut
2165 void
2166 PDB_skip_breakpoint(PARROT_INTERP, unsigned long i)
2168 ASSERT_ARGS(PDB_skip_breakpoint)
2169 #if TRACE_DEBUGGER
2170 fprintf(stderr, "PDB_skip_breakpoint: %li\n", i);
2171 #endif
2173 interp->pdb->breakpoint_skip = i;
2178 =item C<char PDB_program_end(PARROT_INTERP)>
2180 End the program.
2182 =cut
2186 char
2187 PDB_program_end(PARROT_INTERP)
2189 ASSERT_ARGS(PDB_program_end)
2190 PDB_t * const pdb = interp->pdb;
2192 TRACEDEB_MSG("PDB_program_end");
2194 /* Remove the RUNNING state */
2195 pdb->state &= ~PDB_RUNNING;
2197 Parrot_io_eprintf(pdb->debugger, "Program exited.\n");
2198 return 1;
2203 =item C<char PDB_check_condition(PARROT_INTERP, const PDB_condition_t
2204 *condition)>
2206 Returns true if the condition was met.
2208 =cut
2212 PARROT_WARN_UNUSED_RESULT
2213 char
2214 PDB_check_condition(PARROT_INTERP, ARGIN(const PDB_condition_t *condition))
2216 ASSERT_ARGS(PDB_check_condition)
2217 PMC *ctx = CURRENT_CONTEXT(interp);
2219 TRACEDEB_MSG("PDB_check_condition");
2221 PARROT_ASSERT(ctx);
2223 if (condition->type & PDB_cond_int) {
2224 INTVAL i, j;
2225 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_INT))
2226 return 0;
2227 i = CTX_REG_INT(ctx, condition->reg);
2229 if (condition->type & PDB_cond_const)
2230 j = *(INTVAL *)condition->value;
2231 else
2232 j = REG_INT(interp, *(int *)condition->value);
2234 if (((condition->type & PDB_cond_gt) && (i > j)) ||
2235 ((condition->type & PDB_cond_ge) && (i >= j)) ||
2236 ((condition->type & PDB_cond_eq) && (i == j)) ||
2237 ((condition->type & PDB_cond_ne) && (i != j)) ||
2238 ((condition->type & PDB_cond_le) && (i <= j)) ||
2239 ((condition->type & PDB_cond_lt) && (i < j)))
2240 return 1;
2242 return 0;
2244 else if (condition->type & PDB_cond_num) {
2245 FLOATVAL k, l;
2247 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_NUM))
2248 return 0;
2249 k = CTX_REG_NUM(ctx, condition->reg);
2251 if (condition->type & PDB_cond_const)
2252 l = *(FLOATVAL *)condition->value;
2253 else
2254 l = REG_NUM(interp, *(int *)condition->value);
2256 if (((condition->type & PDB_cond_gt) && (k > l)) ||
2257 ((condition->type & PDB_cond_ge) && (k >= l)) ||
2258 ((condition->type & PDB_cond_eq) && (k == l)) ||
2259 ((condition->type & PDB_cond_ne) && (k != l)) ||
2260 ((condition->type & PDB_cond_le) && (k <= l)) ||
2261 ((condition->type & PDB_cond_lt) && (k < l)))
2262 return 1;
2264 return 0;
2266 else if (condition->type & PDB_cond_str) {
2267 STRING *m, *n;
2269 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_STR))
2270 return 0;
2271 m = CTX_REG_STR(ctx, condition->reg);
2273 if (condition->type & PDB_cond_notnull)
2274 return ! STRING_IS_NULL(m);
2276 if (condition->type & PDB_cond_const)
2277 n = (STRING *)condition->value;
2278 else
2279 n = REG_STR(interp, *(int *)condition->value);
2281 if (((condition->type & PDB_cond_gt) &&
2282 (Parrot_str_compare(interp, m, n) > 0)) ||
2283 ((condition->type & PDB_cond_ge) &&
2284 (Parrot_str_compare(interp, m, n) >= 0)) ||
2285 ((condition->type & PDB_cond_eq) &&
2286 (Parrot_str_compare(interp, m, n) == 0)) ||
2287 ((condition->type & PDB_cond_ne) &&
2288 (Parrot_str_compare(interp, m, n) != 0)) ||
2289 ((condition->type & PDB_cond_le) &&
2290 (Parrot_str_compare(interp, m, n) <= 0)) ||
2291 ((condition->type & PDB_cond_lt) &&
2292 (Parrot_str_compare(interp, m, n) < 0)))
2293 return 1;
2295 return 0;
2297 else if (condition->type & PDB_cond_pmc) {
2298 PMC *m;
2300 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_PMC))
2301 return 0;
2302 m = CTX_REG_PMC(ctx, condition->reg);
2304 if (condition->type & PDB_cond_notnull)
2305 return ! PMC_IS_NULL(m);
2306 return 0;
2308 else
2309 return 0;
2314 =item C<static PDB_breakpoint_t * current_breakpoint(PDB_t * pdb)>
2316 Returns a pointer to the breakpoint at the current position,
2317 or NULL if there is none.
2319 =cut
2323 PARROT_CAN_RETURN_NULL
2324 static PDB_breakpoint_t *
2325 current_breakpoint(ARGIN(PDB_t * pdb))
2327 ASSERT_ARGS(current_breakpoint)
2328 PDB_breakpoint_t *breakpoint = pdb->breakpoint;
2329 while (breakpoint) {
2330 if (pdb->cur_opcode == breakpoint->pc)
2331 break;
2332 breakpoint = breakpoint->next;
2334 return breakpoint;
2339 =item C<char PDB_break(PARROT_INTERP)>
2341 Returns true if we have to stop running.
2343 =cut
2347 PARROT_WARN_UNUSED_RESULT
2348 char
2349 PDB_break(PARROT_INTERP)
2351 ASSERT_ARGS(PDB_break)
2352 PDB_t * const pdb = interp->pdb;
2353 PDB_condition_t *watchpoint = pdb->watchpoint;
2354 PDB_breakpoint_t *breakpoint;
2357 TRACEDEB_MSG("PDB_break");
2360 /* Check the watchpoints first. */
2361 while (watchpoint) {
2362 if (PDB_check_condition(interp, watchpoint)) {
2363 pdb->state |= PDB_STOPPED;
2364 return 1;
2367 watchpoint = watchpoint->next;
2370 /* If program ended */
2371 if (!pdb->cur_opcode)
2372 return PDB_program_end(interp);
2374 /* If the program is STOPPED allow it to continue */
2375 if (pdb->state & PDB_STOPPED) {
2376 pdb->state &= ~PDB_STOPPED;
2377 return 0;
2380 breakpoint = current_breakpoint(pdb);
2381 if (breakpoint) {
2382 /* If we have to skip breakpoints, do so. */
2383 if (pdb->breakpoint_skip) {
2384 TRACEDEB_MSG("PDB_break skipping");
2385 pdb->breakpoint_skip--;
2386 return 0;
2389 if (breakpoint->skip < 0)
2390 return 0;
2392 /* Check if there is a condition for this breakpoint */
2393 if ((breakpoint->condition) &&
2394 (!PDB_check_condition(interp, breakpoint->condition)))
2395 return 0;
2397 TRACEDEB_MSG("PDB_break stopping");
2399 /* Add the STOPPED state and stop */
2400 pdb->state |= PDB_STOPPED;
2401 return 1;
2404 return 0;
2409 =item C<char * PDB_escape(const char *string, UINTVAL length)>
2411 Escapes C<">, C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2413 The returned string must be freed.
2415 =cut
2419 PARROT_WARN_UNUSED_RESULT
2420 PARROT_CAN_RETURN_NULL
2421 PARROT_MALLOC
2422 char *
2423 PDB_escape(ARGIN(const char *string), UINTVAL length)
2425 ASSERT_ARGS(PDB_escape)
2426 const char *end;
2427 char *_new, *fill;
2429 length = length > 20 ? 20 : length;
2430 end = string + length;
2432 /* Return if there is no string to escape*/
2433 if (!string)
2434 return NULL;
2436 fill = _new = (char *)mem_sys_allocate(length * 2 + 1);
2438 for (; string < end; string++) {
2439 switch (*string) {
2440 case '\0':
2441 *(fill++) = '\\';
2442 *(fill++) = '0';
2443 break;
2444 case '\n':
2445 *(fill++) = '\\';
2446 *(fill++) = 'n';
2447 break;
2448 case '\r':
2449 *(fill++) = '\\';
2450 *(fill++) = 'r';
2451 break;
2452 case '\t':
2453 *(fill++) = '\\';
2454 *(fill++) = 't';
2455 break;
2456 case '\a':
2457 *(fill++) = '\\';
2458 *(fill++) = 'a';
2459 break;
2460 case '\\':
2461 *(fill++) = '\\';
2462 *(fill++) = '\\';
2463 break;
2464 case '"':
2465 *(fill++) = '\\';
2466 *(fill++) = '"';
2467 break;
2468 default:
2469 *(fill++) = *string;
2470 break;
2474 *fill = '\0';
2476 return _new;
2481 =item C<int PDB_unescape(char *string)>
2483 Do inplace unescape of C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2485 =cut
2490 PDB_unescape(ARGMOD(char *string))
2492 ASSERT_ARGS(PDB_unescape)
2493 int l = 0;
2495 for (; *string; string++) {
2496 l++;
2498 if (*string == '\\') {
2499 char *fill;
2500 int i;
2502 switch (string[1]) {
2503 case 'n':
2504 *string = '\n';
2505 break;
2506 case 'r':
2507 *string = '\r';
2508 break;
2509 case 't':
2510 *string = '\t';
2511 break;
2512 case 'a':
2513 *string = '\a';
2514 break;
2515 case '\\':
2516 *string = '\\';
2517 break;
2518 default:
2519 continue;
2522 fill = string;
2524 for (i = 1; fill[i + 1]; i++)
2525 fill[i] = fill[i + 1];
2527 fill[i] = '\0';
2531 return l;
2536 =item C<size_t PDB_disassemble_op(PARROT_INTERP, char *dest, size_t space, const
2537 op_info_t *info, const opcode_t *op, PDB_file_t *file, const opcode_t
2538 *code_start, int full_name)>
2540 Disassembles C<op>.
2542 =cut
2546 size_t
2547 PDB_disassemble_op(PARROT_INTERP, ARGOUT(char *dest), size_t space,
2548 ARGIN(const op_info_t *info), ARGIN(const opcode_t *op),
2549 ARGMOD_NULLOK(PDB_file_t *file), ARGIN_NULLOK(const opcode_t *code_start),
2550 int full_name)
2552 ASSERT_ARGS(PDB_disassemble_op)
2553 int j;
2554 size_t size = 0;
2555 int specialop = 0;
2557 /* Write the opcode name */
2558 const char * p = full_name ? info->full_name : info->name;
2560 TRACEDEB_MSG("PDB_disassemble_op");
2562 if (! p)
2563 p= "**UNKNOWN**";
2564 strcpy(dest, p);
2565 size += strlen(p);
2567 dest[size++] = ' ';
2569 /* Concat the arguments */
2570 for (j = 1; j < info->op_count; j++) {
2571 char buf[256];
2572 INTVAL i = 0;
2574 PARROT_ASSERT(size + 2 < space);
2576 switch (info->types[j - 1]) {
2577 case PARROT_ARG_I:
2578 dest[size++] = 'I';
2579 goto INTEGER;
2580 case PARROT_ARG_N:
2581 dest[size++] = 'N';
2582 goto INTEGER;
2583 case PARROT_ARG_S:
2584 dest[size++] = 'S';
2585 goto INTEGER;
2586 case PARROT_ARG_P:
2587 dest[size++] = 'P';
2588 goto INTEGER;
2589 case PARROT_ARG_IC:
2590 /* If the opcode jumps and this is the last argument,
2591 that means this is a label */
2592 if ((j == info->op_count - 1) &&
2593 (info->jump & PARROT_JUMP_RELATIVE)) {
2594 if (file) {
2595 dest[size++] = 'L';
2596 i = PDB_add_label(file, op, op[j]);
2598 else if (code_start) {
2599 dest[size++] = 'O';
2600 dest[size++] = 'P';
2601 i = op[j] + (op - code_start);
2603 else {
2604 if (op[j] > 0)
2605 dest[size++] = '+';
2606 i = op[j];
2610 /* Convert the integer to a string */
2611 INTEGER:
2612 if (i == 0)
2613 i = (INTVAL) op[j];
2615 PARROT_ASSERT(size + 20 < space);
2617 size += sprintf(&dest[size], INTVAL_FMT, i);
2619 break;
2620 case PARROT_ARG_NC:
2622 /* Convert the float to a string */
2623 const FLOATVAL f = interp->code->const_table->constants[op[j]]->u.number;
2624 Parrot_snprintf(interp, buf, sizeof (buf), FLOATVAL_FMT, f);
2625 strcpy(&dest[size], buf);
2626 size += strlen(buf);
2628 break;
2629 case PARROT_ARG_SC:
2630 dest[size++] = '"';
2631 if (interp->code->const_table->constants[op[j]]-> u.string->strlen) {
2632 char * const unescaped =
2633 Parrot_str_to_cstring(interp, interp->code->
2634 const_table->constants[op[j]]->u.string);
2635 char * const escaped =
2636 PDB_escape(unescaped, interp->code->const_table->
2637 constants[op[j]]->u.string->strlen);
2638 if (escaped) {
2639 strcpy(&dest[size], escaped);
2640 size += strlen(escaped);
2641 mem_sys_free(escaped);
2643 Parrot_str_free_cstring(unescaped);
2645 dest[size++] = '"';
2646 break;
2647 case PARROT_ARG_PC:
2648 Parrot_snprintf(interp, buf, sizeof (buf), "PMC_CONST(%d)", op[j]);
2649 strcpy(&dest[size], buf);
2650 size += strlen(buf);
2651 break;
2652 case PARROT_ARG_K:
2653 dest[size - 1] = '[';
2654 Parrot_snprintf(interp, buf, sizeof (buf), "P" INTVAL_FMT, op[j]);
2655 strcpy(&dest[size], buf);
2656 size += strlen(buf);
2657 dest[size++] = ']';
2658 break;
2659 case PARROT_ARG_KC:
2661 PMC * k = interp->code->const_table->constants[op[j]]->u.key;
2662 dest[size - 1] = '[';
2663 while (k) {
2664 switch (PObj_get_FLAGS(k)) {
2665 case 0:
2666 break;
2667 case KEY_integer_FLAG:
2668 Parrot_snprintf(interp, buf, sizeof (buf),
2669 INTVAL_FMT, VTABLE_get_integer(interp, k));
2670 strcpy(&dest[size], buf);
2671 size += strlen(buf);
2672 break;
2673 case KEY_number_FLAG:
2674 Parrot_snprintf(interp, buf, sizeof (buf),
2675 FLOATVAL_FMT, VTABLE_get_number(interp, k));
2676 strcpy(&dest[size], buf);
2677 size += strlen(buf);
2678 break;
2679 case KEY_string_FLAG:
2680 dest[size++] = '"';
2682 char * const temp = Parrot_str_to_cstring(interp,
2683 VTABLE_get_string(interp, k));
2684 strcpy(&dest[size], temp);
2685 Parrot_str_free_cstring(temp);
2687 size += Parrot_str_byte_length(interp,
2688 VTABLE_get_string(interp, (k)));
2689 dest[size++] = '"';
2690 break;
2691 case KEY_integer_FLAG|KEY_register_FLAG:
2692 Parrot_snprintf(interp, buf, sizeof (buf),
2693 "I" INTVAL_FMT, VTABLE_get_integer(interp, k));
2694 strcpy(&dest[size], buf);
2695 size += strlen(buf);
2696 break;
2697 case KEY_number_FLAG|KEY_register_FLAG:
2698 Parrot_snprintf(interp, buf, sizeof (buf),
2699 "N" INTVAL_FMT, VTABLE_get_integer(interp, k));
2700 strcpy(&dest[size], buf);
2701 size += strlen(buf);
2702 break;
2703 case KEY_string_FLAG|KEY_register_FLAG:
2704 Parrot_snprintf(interp, buf, sizeof (buf),
2705 "S" INTVAL_FMT, VTABLE_get_integer(interp, k));
2706 strcpy(&dest[size], buf);
2707 size += strlen(buf);
2708 break;
2709 case KEY_pmc_FLAG|KEY_register_FLAG:
2710 Parrot_snprintf(interp, buf, sizeof (buf),
2711 "P" INTVAL_FMT, VTABLE_get_integer(interp, k));
2712 strcpy(&dest[size], buf);
2713 size += strlen(buf);
2714 break;
2715 default:
2716 dest[size++] = '?';
2717 break;
2719 GETATTR_Key_next_key(interp, k, k);
2720 if (k)
2721 dest[size++] = ';';
2723 dest[size++] = ']';
2725 break;
2726 case PARROT_ARG_KI:
2727 dest[size - 1] = '[';
2728 Parrot_snprintf(interp, buf, sizeof (buf), "I" INTVAL_FMT, op[j]);
2729 strcpy(&dest[size], buf);
2730 size += strlen(buf);
2731 dest[size++] = ']';
2732 break;
2733 case PARROT_ARG_KIC:
2734 dest[size - 1] = '[';
2735 Parrot_snprintf(interp, buf, sizeof (buf), INTVAL_FMT, op[j]);
2736 strcpy(&dest[size], buf);
2737 size += strlen(buf);
2738 dest[size++] = ']';
2739 break;
2740 default:
2741 Parrot_ex_throw_from_c_args(interp, NULL, 1, "Unknown opcode type");
2744 if (j != info->op_count - 1)
2745 dest[size++] = ',';
2748 /* Special decoding for the signature used in args/returns. Such ops have
2749 one fixed parameter (the signature vector), plus a varying number of
2750 registers/constants. For each arg/return, we show the register and its
2751 flags using PIR syntax. */
2752 if (*(op) == PARROT_OP_set_args_pc || *(op) == PARROT_OP_set_returns_pc)
2753 specialop = 1;
2755 /* if it's a retrieving op, specialop = 2, so that later a :flat flag
2756 * can be changed into a :slurpy flag. See flag handling below.
2758 if (*(op) == PARROT_OP_get_results_pc || *(op) == PARROT_OP_get_params_pc)
2759 specialop = 2;
2761 if (specialop > 0) {
2762 char buf[1000];
2763 PMC * const sig = interp->code->const_table->constants[op[1]]->u.key;
2764 const int n_values = VTABLE_elements(interp, sig);
2765 /* The flag_names strings come from Call_bits_enum_t (with which it
2766 should probably be colocated); they name the bits from LSB to MSB.
2767 The two least significant bits are not flags; they are the register
2768 type, which is decoded elsewhere. We also want to show unused bits,
2769 which could indicate problems.
2771 PARROT_OBSERVER const char * const flag_names[] = {
2774 " :unused004",
2775 " :unused008",
2776 " :const",
2777 " :flat", /* should be :slurpy for args */
2778 " :unused040",
2779 " :optional",
2780 " :opt_flag",
2781 " :named",
2782 NULL
2786 /* Register decoding. It would be good to abstract this, too. */
2787 PARROT_OBSERVER static const char regs[] = "ISPN";
2789 for (j = 0; j < n_values; j++) {
2790 size_t idx = 0;
2791 const int sig_value = VTABLE_get_integer_keyed_int(interp, sig, j);
2793 /* Print the register name, e.g. P37. */
2794 buf[idx++] = ',';
2795 buf[idx++] = ' ';
2796 buf[idx++] = regs[sig_value & PARROT_ARG_TYPE_MASK];
2797 Parrot_snprintf(interp, &buf[idx], sizeof (buf)-idx,
2798 INTVAL_FMT, op[j+2]);
2799 idx = strlen(buf);
2801 /* Add flags, if we have any. */
2803 int flag_idx = 0;
2804 int flags = sig_value;
2806 /* End when we run out of flags, off the end of flag_names, or
2807 * get too close to the end of buf.
2808 * 100 is just an estimate of all buf lengths added together.
2810 while (flags && idx < sizeof (buf) - 100) {
2811 const char * const flag_string
2812 = (specialop == 2 && STREQ(flag_names[flag_idx], " :flat"))
2813 ? " :slurpy"
2814 : flag_names[flag_idx];
2816 if (! flag_string)
2817 break;
2818 if (flags & 1 && *flag_string) {
2819 const size_t n = strlen(flag_string);
2820 strcpy(&buf[idx], flag_string);
2821 idx += n;
2823 flags >>= 1;
2824 flag_idx++;
2828 /* Add it to dest. */
2829 buf[idx++] = '\0';
2830 strcpy(&dest[size], buf);
2831 size += strlen(buf);
2835 dest[size] = '\0';
2836 return ++size;
2841 =item C<void PDB_disassemble(PARROT_INTERP, const char *command)>
2843 Disassemble the bytecode.
2845 =cut
2849 void
2850 PDB_disassemble(PARROT_INTERP, SHIM(const char *command))
2852 ASSERT_ARGS(PDB_disassemble)
2853 PDB_t * const pdb = interp->pdb;
2854 opcode_t * pc = interp->code->base.data;
2856 PDB_file_t *pfile;
2857 PDB_line_t *pline, *newline;
2858 PDB_label_t *label;
2859 opcode_t *code_end;
2861 const unsigned int default_size = 32768;
2862 size_t space; /* How much space do we have? */
2863 size_t size, alloced, n;
2865 TRACEDEB_MSG("PDB_disassemble");
2867 pfile = mem_allocate_zeroed_typed(PDB_file_t);
2868 pline = mem_allocate_zeroed_typed(PDB_line_t);
2870 /* If we already got a source, free it */
2871 if (pdb->file) {
2872 PDB_free_file(interp, pdb->file);
2873 pdb->file = NULL;
2876 pfile->line = pline;
2877 pline->number = 1;
2878 pfile->source = (char *)mem_sys_allocate(default_size);
2880 alloced = space = default_size;
2881 code_end = pc + interp->code->base.size;
2883 while (pc != code_end) {
2884 /* Grow it early */
2885 if (space < default_size) {
2886 alloced += default_size;
2887 space += default_size;
2888 pfile->source = (char *)mem_sys_realloc(pfile->source, alloced);
2891 size = PDB_disassemble_op(interp, pfile->source + pfile->size,
2892 space, &interp->op_info_table[*pc], pc, pfile, NULL, 1);
2893 space -= size;
2894 pfile->size += size;
2895 pfile->source[pfile->size - 1] = '\n';
2897 /* Store the opcode of this line */
2898 pline->opcode = pc;
2899 n = interp->op_info_table[*pc].op_count;
2901 ADD_OP_VAR_PART(interp, interp->code, pc, n);
2902 pc += n;
2904 /* Prepare for next line */
2905 newline = mem_allocate_typed(PDB_line_t);
2906 newline->label = NULL;
2907 newline->next = NULL;
2908 newline->number = pline->number + 1;
2909 pline->next = newline;
2910 pline = newline;
2911 pline->source_offset = pfile->size;
2914 /* Add labels to the lines they belong to */
2915 label = pfile->label;
2917 while (label) {
2918 /* Get the line to apply the label */
2919 pline = pfile->line;
2921 while (pline && pline->opcode != label->opcode)
2922 pline = pline->next;
2924 if (!pline) {
2925 Parrot_io_eprintf(pdb->debugger,
2926 "Label number %li out of bounds.\n", label->number);
2928 PDB_free_file(interp, pfile);
2929 return;
2932 pline->label = label;
2934 label = label->next;
2937 pdb->state |= PDB_SRC_LOADED;
2938 pdb->file = pfile;
2943 =item C<long PDB_add_label(PDB_file_t *file, const opcode_t *cur_opcode,
2944 opcode_t offset)>
2946 Add a label to the label list.
2948 =cut
2952 long
2953 PDB_add_label(ARGMOD(PDB_file_t *file), ARGIN(const opcode_t *cur_opcode),
2954 opcode_t offset)
2956 ASSERT_ARGS(PDB_add_label)
2957 PDB_label_t *_new;
2958 PDB_label_t *label = file->label;
2960 /* See if there is already a label at this line */
2961 while (label) {
2962 if (label->opcode == cur_opcode + offset)
2963 return label->number;
2964 label = label->next;
2967 /* Allocate a new label */
2968 label = file->label;
2969 _new = mem_allocate_typed(PDB_label_t);
2970 _new->opcode = cur_opcode + offset;
2971 _new->next = NULL;
2973 if (label) {
2974 while (label->next)
2975 label = label->next;
2977 _new->number = label->number + 1;
2978 label->next = _new;
2980 else {
2981 file->label = _new;
2982 _new->number = 1;
2985 return _new->number;
2990 =item C<void PDB_free_file(PARROT_INTERP, PDB_file_t *file)>
2992 Frees any allocated source files.
2994 =cut
2998 void
2999 PDB_free_file(SHIM_INTERP, ARGIN_NULLOK(PDB_file_t *file))
3001 ASSERT_ARGS(PDB_free_file)
3002 while (file) {
3003 /* Free all of the allocated line structures */
3004 PDB_line_t *line = file->line;
3005 PDB_label_t *label;
3006 PDB_file_t *nfile;
3008 while (line) {
3009 PDB_line_t * const nline = line->next;
3010 mem_sys_free(line);
3011 line = nline;
3014 /* Free all of the allocated label structures */
3015 label = file->label;
3017 while (label) {
3018 PDB_label_t * const nlabel = label->next;
3020 mem_sys_free(label);
3021 label = nlabel;
3024 /* Free the remaining allocated portions of the file structure */
3025 if (file->sourcefilename)
3026 mem_sys_free(file->sourcefilename);
3028 if (file->source)
3029 mem_sys_free(file->source);
3031 nfile = file->next;
3032 mem_sys_free(file);
3033 file = nfile;
3039 =item C<void PDB_load_source(PARROT_INTERP, const char *command)>
3041 Load a source code file.
3043 =cut
3047 PARROT_EXPORT
3048 void
3049 PDB_load_source(PARROT_INTERP, ARGIN(const char *command))
3051 ASSERT_ARGS(PDB_load_source)
3052 FILE *file;
3053 char f[DEBUG_CMD_BUFFER_LENGTH + 1];
3054 int i, j, c;
3055 PDB_file_t *pfile;
3056 PDB_line_t *pline;
3057 PDB_t * const pdb = interp->pdb;
3058 opcode_t *pc = interp->code->base.data;
3060 unsigned long size = 0;
3062 TRACEDEB_MSG("PDB_load_source");
3064 /* If there was a file already loaded or the bytecode was
3065 disassembled, free it */
3066 if (pdb->file) {
3067 PDB_free_file(interp->pdb->debugee, interp->pdb->debugee->pdb->file);
3068 interp->pdb->debugee->pdb->file = NULL;
3071 /* Get the name of the file */
3072 for (j = 0; command[j] == ' '; ++j)
3073 continue;
3074 for (i = 0; command[j]; i++, j++)
3075 f[i] = command[j];
3077 f[i] = '\0';
3079 /* open the file */
3080 file = fopen(f, "r");
3082 /* abort if fopen failed */
3083 if (!file) {
3084 Parrot_io_eprintf(pdb->debugger, "Unable to load '%s'\n", f);
3085 return;
3088 pfile = mem_allocate_zeroed_typed(PDB_file_t);
3089 pline = mem_allocate_zeroed_typed(PDB_line_t);
3091 pfile->source = (char *)mem_sys_allocate(1024);
3092 pfile->line = pline;
3093 pline->number = 1;
3095 PARROT_ASSERT(interp->op_info_table);
3096 PARROT_ASSERT(pc);
3098 while ((c = fgetc(file)) != EOF) {
3099 /* Grow it */
3100 if (++size == 1024) {
3101 pfile->source = (char *)mem_sys_realloc(pfile->source,
3102 (size_t)pfile->size + 1024);
3103 size = 0;
3105 pfile->source[pfile->size] = (char)c;
3107 pfile->size++;
3109 if (c == '\n') {
3110 /* If the line has an opcode move to the next one,
3111 otherwise leave it with NULL to skip it. */
3112 PDB_line_t *newline = mem_allocate_zeroed_typed(PDB_line_t);
3114 if (PDB_hasinstruction(pfile->source + pline->source_offset)) {
3115 size_t n = interp->op_info_table[*pc].op_count;
3116 pline->opcode = pc;
3117 ADD_OP_VAR_PART(interp, interp->code, pc, n);
3118 pc += n;
3120 /* don't walk off the end of the program into neverland */
3121 if (pc >= interp->code->base.data + interp->code->base.size)
3122 break;
3125 newline->number = pline->number + 1;
3126 pline->next = newline;
3127 pline = newline;
3128 pline->source_offset = pfile->size;
3129 pline->opcode = NULL;
3130 pline->label = NULL;
3134 fclose(file);
3136 pdb->state |= PDB_SRC_LOADED;
3137 pdb->file = pfile;
3139 TRACEDEB_MSG("PDB_load_source finished");
3144 =item C<char PDB_hasinstruction(const char *c)>
3146 Return true if the line has an instruction.
3148 =cut
3152 PARROT_WARN_UNUSED_RESULT
3153 PARROT_PURE_FUNCTION
3154 char
3155 PDB_hasinstruction(ARGIN(const char *c))
3157 ASSERT_ARGS(PDB_hasinstruction)
3158 char h = 0;
3160 /* as long as c is not NULL, we're not looking at a comment (#...) or a '\n'... */
3161 while (*c && *c != '#' && *c != '\n') {
3162 /* ... and c is alphanumeric or a quoted string then the line contains
3163 * an instruction. */
3164 if (isalnum((unsigned char) *c) || *c == '"') {
3165 h = 1;
3167 else if (*c == ':') {
3168 /* probably a label */
3169 h = 0;
3172 c++;
3175 return h;
3180 =item C<static void no_such_register(PARROT_INTERP, char register_type, UINTVAL
3181 register_num)>
3183 Auxiliar error message function.
3185 =cut
3189 static void
3190 no_such_register(PARROT_INTERP, char register_type, UINTVAL register_num)
3192 ASSERT_ARGS(no_such_register)
3194 Parrot_io_eprintf(interp, "%c%u = no such register\n",
3195 register_type, register_num);
3200 =item C<void PDB_assign(PARROT_INTERP, const char *command)>
3202 Assign to registers.
3204 =cut
3208 void
3209 PDB_assign(PARROT_INTERP, ARGIN(const char *command))
3211 ASSERT_ARGS(PDB_assign)
3212 UINTVAL register_num;
3213 char reg_type_id;
3214 int reg_type;
3215 PDB_t *pdb = interp->pdb;
3216 Interp *debugger = pdb ? pdb->debugger : interp;
3217 Interp *debugee = pdb ? pdb->debugee : interp;
3219 /* smallest valid commad length is 4, i.e. "I0 1" */
3220 if (strlen(command) < 4) {
3221 Parrot_io_eprintf(debugger, "Must give a register number and value to assign\n");
3222 return;
3224 reg_type_id = (unsigned char) toupper((unsigned char) command[0]);
3225 command++;
3226 register_num = get_ulong(&command, 0);
3228 switch (reg_type_id) {
3229 case 'I':
3230 reg_type = REGNO_INT;
3231 break;
3232 case 'N':
3233 reg_type = REGNO_NUM;
3234 break;
3235 case 'S':
3236 reg_type = REGNO_STR;
3237 break;
3238 case 'P':
3239 reg_type = REGNO_PMC;
3240 Parrot_io_eprintf(debugger, "Assigning to PMCs is not currently supported\n");
3241 return;
3242 default:
3243 Parrot_io_eprintf(debugger, "Invalid register type %c\n", reg_type_id);
3244 return;
3246 if (register_num >= Parrot_pcc_get_regs_used(debugee,
3247 CURRENT_CONTEXT(debugee), reg_type)) {
3248 no_such_register(debugger, reg_type_id, register_num);
3249 return;
3251 switch (reg_type) {
3252 case REGNO_INT:
3253 IREG(register_num) = get_ulong(&command, 0);
3254 break;
3255 case REGNO_NUM:
3256 NREG(register_num) = atof(command);
3257 break;
3258 case REGNO_STR:
3259 SREG(register_num) = Parrot_str_new(debugee, command, strlen(command));
3260 break;
3261 default: ; /* Must never come here */
3263 Parrot_io_eprintf(debugger, "\n %c%u = ", reg_type_id, register_num);
3264 Parrot_io_eprintf(debugger, "%Ss\n", GDB_print_reg(debugee, reg_type, register_num));
3269 =item C<void PDB_list(PARROT_INTERP, const char *command)>
3271 Show lines from the source code file.
3273 =cut
3277 void
3278 PDB_list(PARROT_INTERP, ARGIN(const char *command))
3280 ASSERT_ARGS(PDB_list)
3281 char *c;
3282 unsigned long line_number;
3283 unsigned long i;
3284 PDB_line_t *line;
3285 PDB_t *pdb = interp->pdb;
3286 unsigned long n = 10;
3288 TRACEDEB_MSG("PDB_list");
3289 if (!pdb->file || !pdb->file->line) {
3290 Parrot_io_eprintf(pdb->debugger, "No source file loaded\n");
3291 return;
3294 /* set the list line if provided */
3295 line_number = get_ulong(&command, 0);
3296 pdb->file->list_line = (unsigned long) line_number;
3298 /* set the number of lines to print */
3299 n = get_ulong(&command, 10);
3301 /* if n is zero, we simply return, as we don't have to print anything */
3302 if (n == 0)
3303 return;
3305 line = pdb->file->line;
3307 for (i = 0; i < pdb->file->list_line && line->next; i++)
3308 line = line->next;
3310 i = 1;
3311 while (line->next) {
3312 Parrot_io_eprintf(pdb->debugger, "%li ", pdb->file->list_line + i);
3313 /* If it has a label print it */
3314 if (line->label)
3315 Parrot_io_eprintf(pdb->debugger, "L%li:\t", line->label->number);
3317 c = pdb->file->source + line->source_offset;
3319 while (*c != '\n')
3320 Parrot_io_eprintf(pdb->debugger, "%c", *(c++));
3322 Parrot_io_eprintf(pdb->debugger, "\n");
3324 line = line->next;
3326 if (i++ == n)
3327 break;
3330 if (--i != n)
3331 pdb->file->list_line = 0;
3332 else
3333 pdb->file->list_line += n;
3338 =item C<void PDB_eval(PARROT_INTERP, const char *command)>
3340 C<eval>s an instruction.
3342 =cut
3346 void
3347 PDB_eval(PARROT_INTERP, ARGIN(const char *command))
3349 ASSERT_ARGS(PDB_eval)
3351 PDB_t *pdb = interp->pdb;
3352 Interp *warninterp = (interp->pdb && interp->pdb->debugger) ?
3353 interp->pdb->debugger : interp;
3354 TRACEDEB_MSG("PDB_eval");
3355 UNUSED(command);
3356 Parrot_io_eprintf(warninterp, "The eval command is currently unimplemeneted\n");
3361 =item C<opcode_t * PDB_compile(PARROT_INTERP, const char *command)>
3363 Compiles instructions with the PASM compiler.
3365 Appends an C<end> op.
3367 This may be called from C<PDB_eval> above or from the compile opcode
3368 which generates a malloced string.
3370 =cut
3374 PARROT_CAN_RETURN_NULL
3375 opcode_t *
3376 PDB_compile(PARROT_INTERP, ARGIN(const char *command))
3378 ASSERT_ARGS(PDB_compile)
3380 UNUSED(command);
3381 Parrot_ex_throw_from_c_args(interp, NULL,
3382 EXCEPTION_UNIMPLEMENTED,
3383 "PDB_compile ('PASM1' compiler) has been deprecated");
3388 =item C<static void dump_string(PARROT_INTERP, const STRING *s)>
3390 Dumps the buflen, flags, bufused, strlen, and offset associated with a string
3391 and the string itself.
3393 =cut
3397 static void
3398 dump_string(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
3400 ASSERT_ARGS(dump_string)
3401 if (!s)
3402 return;
3404 Parrot_io_eprintf(interp, "\tBuflen =\t%12ld\n", Buffer_buflen(s));
3405 Parrot_io_eprintf(interp, "\tFlags =\t%12ld\n", PObj_get_FLAGS(s));
3406 Parrot_io_eprintf(interp, "\tBufused =\t%12ld\n", s->bufused);
3407 Parrot_io_eprintf(interp, "\tStrlen =\t%12ld\n", s->strlen);
3408 Parrot_io_eprintf(interp, "\tOffset =\t%12ld\n",
3409 (char*) s->strstart - (char*) Buffer_bufstart(s));
3410 Parrot_io_eprintf(interp, "\tString =\t%S\n", s);
3415 =item C<void PDB_print(PARROT_INTERP, const char *command)>
3417 Print interp registers.
3419 =cut
3423 void
3424 PDB_print(PARROT_INTERP, ARGIN(const char *command))
3426 ASSERT_ARGS(PDB_print)
3427 const STRING *s = GDB_P(interp->pdb->debugee, command);
3429 TRACEDEB_MSG("PDB_print");
3430 Parrot_io_eprintf(interp, "%Ss\n", s);
3436 =item C<void PDB_info(PARROT_INTERP)>
3438 Print the interpreter info.
3440 =cut
3444 void
3445 PDB_info(PARROT_INTERP)
3447 ASSERT_ARGS(PDB_info)
3449 /* If a debugger is created, use it for printing and use the
3450 * data in his debugee. Otherwise, use current interpreter
3451 * for both */
3452 Parrot_Interp itdeb = interp->pdb ? interp->pdb->debugger : interp;
3453 Parrot_Interp itp = interp->pdb ? interp->pdb->debugee : interp;
3455 Parrot_io_eprintf(itdeb, "Total memory allocated = %ld\n",
3456 interpinfo(itp, TOTAL_MEM_ALLOC));
3457 Parrot_io_eprintf(itdeb, "GC mark runs = %ld\n",
3458 interpinfo(itp, GC_MARK_RUNS));
3459 Parrot_io_eprintf(itdeb, "Lazy gc mark runs = %ld\n",
3460 interpinfo(itp, GC_LAZY_MARK_RUNS));
3461 Parrot_io_eprintf(itdeb, "GC collect runs = %ld\n",
3462 interpinfo(itp, GC_COLLECT_RUNS));
3463 Parrot_io_eprintf(itdeb, "Collect memory = %ld\n",
3464 interpinfo(itp, TOTAL_COPIED));
3465 Parrot_io_eprintf(itdeb, "Active PMCs = %ld\n",
3466 interpinfo(itp, ACTIVE_PMCS));
3467 Parrot_io_eprintf(itdeb, "Extended PMCs = %ld\n",
3468 interpinfo(itp, EXTENDED_PMCS));
3469 Parrot_io_eprintf(itdeb, "Timely GC PMCs = %ld\n",
3470 interpinfo(itp, IMPATIENT_PMCS));
3471 Parrot_io_eprintf(itdeb, "Total PMCs = %ld\n",
3472 interpinfo(itp, TOTAL_PMCS));
3473 Parrot_io_eprintf(itdeb, "Active buffers = %ld\n",
3474 interpinfo(itp, ACTIVE_BUFFERS));
3475 Parrot_io_eprintf(itdeb, "Total buffers = %ld\n",
3476 interpinfo(itp, TOTAL_BUFFERS));
3477 Parrot_io_eprintf(itdeb, "Header allocations since last collect = %ld\n",
3478 interpinfo(itp, HEADER_ALLOCS_SINCE_COLLECT));
3479 Parrot_io_eprintf(itdeb, "Memory allocations since last collect = %ld\n",
3480 interpinfo(itp, MEM_ALLOCS_SINCE_COLLECT));
3485 =item C<void PDB_help(PARROT_INTERP, const char *command)>
3487 Print the help text. "Help" with no arguments prints a list of commands.
3488 "Help xxx" prints information on command xxx.
3490 =cut
3494 void
3495 PDB_help(PARROT_INTERP, ARGIN(const char *command))
3497 ASSERT_ARGS(PDB_help)
3498 const DebuggerCmd *cmd;
3500 const char * cmdline = command;
3501 cmd = get_cmd(& cmdline);
3503 if (cmd) {
3504 Parrot_io_eprintf(interp->pdb->debugger, "%s\n", cmd->help);
3506 else {
3507 if (*cmdline == '\0') {
3508 unsigned int i;
3509 Parrot_io_eprintf(interp->pdb->debugger, "List of commands:\n");
3510 for (i= 0; i < sizeof (DebCmdList) / sizeof (DebuggerCmdList); ++i) {
3511 const DebuggerCmdList *cmdlist = DebCmdList + i;
3512 Parrot_io_eprintf(interp->pdb->debugger,
3513 " %-12s-- %s\n", cmdlist->name, cmdlist->cmd->shorthelp);
3515 Parrot_io_eprintf(interp->pdb->debugger, "\n"
3516 "Type \"help\" followed by a command name for full documentation.\n\n");
3519 else {
3520 Parrot_io_eprintf(interp->pdb->debugger, "Unknown command: %s\n", command);
3527 =item C<void PDB_backtrace(PARROT_INTERP)>
3529 Prints a backtrace of the interp's call chain.
3531 =cut
3535 void
3536 PDB_backtrace(PARROT_INTERP)
3538 ASSERT_ARGS(PDB_backtrace)
3539 STRING *str;
3540 PMC *old = PMCNULL;
3541 int rec_level = 0;
3543 /* information about the current sub */
3544 PMC *sub = interpinfo_p(interp, CURRENT_SUB);
3545 PMC *ctx = CURRENT_CONTEXT(interp);
3547 if (!PMC_IS_NULL(sub)) {
3548 str = Parrot_Context_infostr(interp, ctx);
3549 if (str) {
3550 Parrot_io_eprintf(interp, "%Ss", str);
3551 if (interp->code->annotations) {
3552 PMC *annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
3553 Parrot_pcc_get_pc(interp, ctx) - interp->code->base.data + 1, NULL);
3554 if (!PMC_IS_NULL(annot)) {
3555 PMC *pfile = VTABLE_get_pmc_keyed_str(interp, annot,
3556 Parrot_str_new_constant(interp, "file"));
3557 PMC *pline = VTABLE_get_pmc_keyed_str(interp, annot,
3558 Parrot_str_new_constant(interp, "line"));
3559 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
3560 STRING *file = VTABLE_get_string(interp, pfile);
3561 INTVAL line = VTABLE_get_integer(interp, pline);
3562 Parrot_io_eprintf(interp, " (%Ss:%li)", file, (long)line);
3566 Parrot_io_eprintf(interp, "\n");
3570 /* backtrace: follow the continuation chain */
3571 while (1) {
3572 Parrot_Continuation_attributes *sub_cont;
3573 sub = Parrot_pcc_get_continuation(interp, ctx);
3575 if (PMC_IS_NULL(sub))
3576 break;
3578 sub_cont = PARROT_CONTINUATION(sub);
3580 if (!sub_cont)
3581 break;
3583 str = Parrot_Context_infostr(interp, sub_cont->to_ctx);
3585 if (!str)
3586 break;
3588 /* recursion detection */
3589 if (!PMC_IS_NULL(old) && PMC_cont(old) &&
3590 Parrot_pcc_get_pc(interp, PMC_cont(old)->to_ctx) ==
3591 Parrot_pcc_get_pc(interp, PMC_cont(sub)->to_ctx) &&
3592 Parrot_pcc_get_sub(interp, PMC_cont(old)->to_ctx) ==
3593 Parrot_pcc_get_sub(interp, PMC_cont(sub)->to_ctx)) {
3594 ++rec_level;
3596 else if (rec_level != 0) {
3597 Parrot_io_eprintf(interp, "... call repeated %d times\n", rec_level);
3598 rec_level = 0;
3601 /* print the context description */
3602 if (rec_level == 0) {
3603 Parrot_io_eprintf(interp, "%Ss", str);
3604 if (interp->code->annotations) {
3605 PMC *annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
3606 Parrot_pcc_get_pc(interp, sub_cont->to_ctx) - interp->code->base.data + 1,
3607 NULL);
3609 if (!PMC_IS_NULL(annot)) {
3610 PMC *pfile = VTABLE_get_pmc_keyed_str(interp, annot,
3611 Parrot_str_new_constant(interp, "file"));
3612 PMC *pline = VTABLE_get_pmc_keyed_str(interp, annot,
3613 Parrot_str_new_constant(interp, "line"));
3614 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
3615 STRING *file = VTABLE_get_string(interp, pfile);
3616 INTVAL line = VTABLE_get_integer(interp, pline);
3617 Parrot_io_eprintf(interp, " (%Ss:%li)", file, (long)line);
3621 Parrot_io_eprintf(interp, "\n");
3624 /* get the next Continuation */
3625 ctx = PARROT_CONTINUATION(sub)->to_ctx;
3626 old = sub;
3628 if (!ctx)
3629 break;
3632 if (rec_level != 0)
3633 Parrot_io_eprintf(interp, "... call repeated %d times\n", rec_level);
3637 * GDB functions
3639 * GDB_P gdb> pp $I0 print register I0 value
3641 * RT46139 more, more
3646 =item C<static STRING * GDB_print_reg(PARROT_INTERP, int t, int n)>
3648 Used by GDB_P to convert register values for display. Takes register
3649 type and number as arguments.
3651 Returns a pointer to the start of the string, (except for PMCs, which
3652 print directly and return "").
3654 =cut
3658 PARROT_WARN_UNUSED_RESULT
3659 PARROT_CANNOT_RETURN_NULL
3660 PARROT_OBSERVER
3661 static STRING *
3662 GDB_print_reg(PARROT_INTERP, int t, int n)
3664 ASSERT_ARGS(GDB_print_reg)
3665 char * string;
3667 if (n >= 0 && (UINTVAL)n < Parrot_pcc_get_regs_used(interp, CURRENT_CONTEXT(interp), t)) {
3668 switch (t) {
3669 case REGNO_INT:
3670 return Parrot_str_from_int(interp, IREG(n));
3671 case REGNO_NUM:
3672 return Parrot_str_from_num(interp, NREG(n));
3673 case REGNO_STR:
3674 /* This hack is needed because we occasionally are told
3675 that we have string registers when we actually don't */
3676 string = (char *) SREG(n);
3678 if (string == '\0')
3679 return Parrot_str_new(interp, "", 0);
3680 else
3681 return SREG(n);
3682 case REGNO_PMC:
3683 /* prints directly */
3684 trace_pmc_dump(interp, PREG(n));
3685 return Parrot_str_new(interp, "", 0);
3686 default:
3687 break;
3690 return Parrot_str_new(interp, "no such register", 0);
3695 =item C<static STRING * GDB_P(PARROT_INTERP, const char *s)>
3697 Used by PDB_print to print register values. Takes a pointer to the
3698 register name(s).
3700 Returns "" or error message.
3702 =cut
3706 PARROT_WARN_UNUSED_RESULT
3707 PARROT_CANNOT_RETURN_NULL
3708 PARROT_OBSERVER
3709 static STRING *
3710 GDB_P(PARROT_INTERP, ARGIN(const char *s))
3712 ASSERT_ARGS(GDB_P)
3713 int t;
3714 char reg_type;
3716 TRACEDEB_MSG("GDB_P");
3717 /* Skip leading whitespace. */
3718 while (isspace((unsigned char)*s))
3719 s++;
3721 reg_type = (unsigned char) toupper((unsigned char)*s);
3723 switch (reg_type) {
3724 case 'I': t = REGNO_INT; break;
3725 case 'N': t = REGNO_NUM; break;
3726 case 'S': t = REGNO_STR; break;
3727 case 'P': t = REGNO_PMC; break;
3728 default: return Parrot_str_new(interp, "Need a register.", 0);
3730 if (! s[1]) {
3731 /* Print all registers of this type. */
3732 const int max_reg = Parrot_pcc_get_regs_used(interp, CURRENT_CONTEXT(interp), t);
3733 int n;
3735 for (n = 0; n < max_reg; n++) {
3736 /* this must be done in two chunks because PMC's print directly. */
3737 Parrot_io_eprintf(interp, "\n %c%d = ", reg_type, n);
3738 Parrot_io_eprintf(interp, "%Ss", GDB_print_reg(interp, t, n));
3740 return Parrot_str_new(interp, "", 0);
3742 else if (s[1] && isdigit((unsigned char)s[1])) {
3743 const int n = atoi(s + 1);
3744 return GDB_print_reg(interp, t, n);
3746 else
3747 return Parrot_str_new(interp, "no such register", 0);
3753 =back
3755 =head1 SEE ALSO
3757 F<include/parrot/debugger.h>, F<src/parrot_debugger.c> and F<ops/debug.ops>.
3759 =head1 HISTORY
3761 =over 4
3763 =item Initial version by Daniel Grunblatt on 2002.5.19.
3765 =item Start of rewrite - leo 2005.02.16
3767 The debugger now uses its own interpreter. User code is run in
3768 Interp *debugee. We have:
3770 debug_interp->pdb->debugee->debugger
3773 +------------- := -----------+
3775 Debug commands are mostly run inside the C<debugger>. User code
3776 runs of course in the C<debugee>.
3778 =back
3780 =cut
3786 * Local variables:
3787 * c-file-style: "parrot"
3788 * End:
3789 * vim: expandtab shiftwidth=4: