[t] Refactor some namespace pmc tests to use throws_like
[parrot.git] / src / debug.c
blobdfb3bdf762f6e47f8331375436adfe345eb6e007
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 const char* 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 const char* 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 RT #42377: clone the interpreter to allow people to play into the
1138 debugger and then continue the normal execution of the program.
1140 =cut
1144 PARROT_EXPORT
1145 void
1146 Parrot_debugger_break(PARROT_INTERP, ARGIN(opcode_t * cur_opcode))
1148 ASSERT_ARGS(Parrot_debugger_break)
1149 TRACEDEB_MSG("Parrot_debugger_break");
1151 if (!interp->pdb)
1152 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1154 if (!interp->pdb->file)
1155 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No file loaded to debug");
1157 if (!(interp->pdb->state & PDB_BREAK)) {
1158 TRACEDEB_MSG("Parrot_debugger_break - in BREAK state");
1159 new_runloop_jump_point(interp);
1160 if (setjmp(interp->current_runloop->resume)) {
1161 fprintf(stderr, "Unhandled exception in debugger\n");
1162 return;
1165 interp->pdb->state |= PDB_BREAK;
1166 interp->pdb->state |= PDB_STOPPED;
1167 interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
1169 /*PDB_set_break(interp, NULL);*/
1171 debugger_cmdline(interp);
1173 /* RT #42378 this is not ok */
1174 /* exit(EXIT_SUCCESS); */
1176 else {
1177 interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
1178 /*PDB_set_break(interp, NULL);*/
1180 TRACEDEB_MSG("Parrot_debugger_break done");
1185 =item C<void PDB_get_command(PARROT_INTERP)>
1187 Get a command from the user input to execute.
1189 It saves the last command executed (in C<< pdb->last_command >>), so it
1190 first frees the old one and updates it with the current one.
1192 Also prints the next line to run if the program is still active.
1194 The user input can't be longer than DEBUG_CMD_BUFFER_LENGTH characters.
1196 The input is saved in C<< pdb->cur_command >>.
1198 =cut
1202 void
1203 PDB_get_command(PARROT_INTERP)
1205 ASSERT_ARGS(PDB_get_command)
1206 unsigned int i;
1207 int ch;
1208 char *c;
1209 PDB_t * const pdb = interp->pdb;
1211 /***********************************
1212 **** Testing ****
1213 Do not delete yet
1214 the commented out
1215 parts
1216 ***********************************/
1218 /* flush the buffered data */
1219 fflush(stdout);
1221 TRACEDEB_MSG("PDB_get_command");
1223 PARROT_ASSERT(pdb->last_command);
1224 PARROT_ASSERT(pdb->cur_command);
1226 if (interp->pdb->script_file) {
1227 FILE *fd = interp->pdb->script_file;
1228 char buf[DEBUG_CMD_BUFFER_LENGTH+1];
1229 const char *ptr;
1231 do {
1232 if (fgets(buf, DEBUG_CMD_BUFFER_LENGTH, fd) == NULL) {
1233 close_script_file(interp);
1234 return;
1236 ++pdb->script_line;
1237 chop_newline(buf);
1238 #if TRACE_DEBUGGER
1239 fprintf(stderr, "script (%lu): '%s'\n", pdb->script_line, buf);
1240 #endif
1242 /* skip spaces */
1243 ptr = skip_whitespace(buf);
1245 /* skip blank and commented lines */
1246 } while (*ptr == '\0' || *ptr == '#');
1248 if (pdb->state & PDB_ECHO)
1249 Parrot_io_eprintf(pdb->debugger, "[%lu %s]\n", pdb->script_line, buf);
1251 #if TRACE_DEBUGGER
1252 fprintf(stderr, "(script) %s\n", buf);
1253 #endif
1255 strcpy(pdb->cur_command, buf);
1257 else {
1259 /* update the last command */
1260 if (pdb->cur_command[0] != '\0')
1261 strcpy(pdb->last_command, pdb->cur_command);
1263 i = 0;
1265 c = pdb->cur_command;
1267 /*Parrot_io_eprintf(pdb->debugger, "\n(pdb) ");*/
1268 Parrot_io_eprintf(pdb->debugger, "\n");
1270 /* skip leading whitespace */
1272 do {
1273 ch = fgetc(stdin);
1274 } while (isspace((unsigned char)ch) && ch != '\n');
1277 Interp * interpdeb = interp->pdb->debugger;
1278 STRING * readline = CONST_STRING(interpdeb, "readline_interactive");
1279 STRING * prompt = CONST_STRING(interpdeb, "(pdb) ");
1280 STRING *s= Parrot_str_new(interpdeb, NULL, 0);
1281 PMC *tmp_stdin = Parrot_io_stdhandle(interpdeb, 0, NULL);
1283 Parrot_PCCINVOKE(interpdeb,
1284 tmp_stdin, readline,
1285 "S->S", prompt, & s);
1287 char * aux = Parrot_str_to_cstring(interpdeb, s);
1288 strcpy(c, aux);
1289 Parrot_str_free_cstring(aux);
1291 ch = '\n';
1294 /* generate string (no more than buffer length) */
1296 while (ch != EOF && ch != '\n' && (i < DEBUG_CMD_BUFFER_LENGTH)) {
1297 c[i++] = (char)ch;
1298 ch = fgetc(tmp_stdin);
1301 c[i] = '\0';
1303 if (ch == -1)
1304 strcpy(c, "quit");
1310 =item C<void PDB_script_file(PARROT_INTERP, const char *command)>
1312 Interprets the contents of a file as user input commands
1314 =cut
1318 PARROT_EXPORT
1319 void
1320 PDB_script_file(PARROT_INTERP, ARGIN(const char *command))
1322 ASSERT_ARGS(PDB_script_file)
1323 FILE *fd;
1325 TRACEDEB_MSG("PDB_script_file");
1327 /* If already executing a script, close it */
1328 close_script_file(interp);
1330 TRACEDEB_MSG("Opening debugger script file");
1332 fd = fopen(command, "r");
1333 if (!fd) {
1334 Parrot_io_eprintf(interp->pdb->debugger,
1335 "Error reading script file %s.\n",
1336 command);
1337 return;
1339 interp->pdb->script_file = fd;
1340 interp->pdb->script_line = 0;
1341 TRACEDEB_MSG("PDB_script_file finished");
1346 =item C<int PDB_run_command(PARROT_INTERP, const char *command)>
1348 Run a command.
1350 Hash the command to make a simple switch calling the correct handler.
1352 =cut
1356 PARROT_IGNORABLE_RESULT
1358 PDB_run_command(PARROT_INTERP, ARGIN(const char *command))
1360 ASSERT_ARGS(PDB_run_command)
1361 PDB_t * const pdb = interp->pdb;
1362 const DebuggerCmd *cmd;
1364 /* keep a pointer to the command, in case we need to report an error */
1366 const char * cmdline = command;
1368 TRACEDEB_MSG("PDB_run_command");
1369 cmd = get_cmd(& cmdline);
1371 if (cmd) {
1372 (* cmd->func)(pdb, cmdline);
1373 return 0;
1375 else {
1376 if (*cmdline == '\0') {
1377 return 0;
1379 else {
1380 Parrot_io_eprintf(pdb->debugger,
1381 "Undefined command: \"%s\"", command);
1382 if (pdb->script_file)
1383 Parrot_io_eprintf(pdb->debugger, " in line %lu", pdb->script_line);
1384 Parrot_io_eprintf(pdb->debugger, ". Try \"help\".");
1385 close_script_file(interp);
1386 return 1;
1393 =item C<void PDB_next(PARROT_INTERP, const char *command)>
1395 Execute the next N operation(s).
1397 Inits the program if needed, runs the next N >= 1 operations and stops.
1399 =cut
1403 void
1404 PDB_next(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1406 ASSERT_ARGS(PDB_next)
1407 unsigned long n;
1408 PDB_t * const pdb = interp->pdb;
1409 Interp *debugee;
1411 TRACEDEB_MSG("PDB_next");
1413 /* Init the program if it's not running */
1414 if (!(pdb->state & PDB_RUNNING))
1415 PDB_init(interp, command);
1417 /* Get the number of operations to execute if any */
1418 n = get_ulong(& command, 1);
1420 /* Erase the stopped flag */
1421 pdb->state &= ~PDB_STOPPED;
1423 /* Testing use of the debugger runloop */
1424 #if 0
1426 /* Execute */
1427 for (; n && pdb->cur_opcode; n--)
1428 DO_OP(pdb->cur_opcode, pdb->debugee);
1430 /* Set the stopped flag */
1431 pdb->state |= PDB_STOPPED;
1433 /* If program ended */
1436 * RT #46119 this doesn't handle resume opcodes
1438 if (!pdb->cur_opcode)
1439 (void)PDB_program_end(interp);
1440 #endif
1442 debugee = pdb->debugee;
1444 new_runloop_jump_point(debugee);
1445 if (setjmp(debugee->current_runloop->resume)) {
1446 Parrot_io_eprintf(pdb->debugger, "Unhandled exception while tracing\n");
1447 pdb->state |= PDB_STOPPED;
1448 return;
1451 pdb->tracing = n;
1452 Parrot_runcore_switch(pdb->debugee, CONST_STRING(interp, "debugger"));
1454 TRACEDEB_MSG("PDB_next finished");
1459 =item C<void PDB_trace(PARROT_INTERP, const char *command)>
1461 Execute the next N operations; if no number is specified, it defaults to 1.
1463 =cut
1467 void
1468 PDB_trace(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1470 ASSERT_ARGS(PDB_trace)
1471 unsigned long n;
1472 PDB_t * const pdb = interp->pdb;
1473 Interp *debugee;
1475 TRACEDEB_MSG("PDB_trace");
1477 /* if debugger is not running yet, initialize */
1479 if (!(pdb->state & PDB_RUNNING))
1480 PDB_init(interp, command);
1483 /* ge the number of ops to run, if specified */
1484 n = get_ulong(& command, 1);
1486 /* clear the PDB_STOPPED flag, we'll be running n ops now */
1487 pdb->state &= ~PDB_STOPPED;
1488 debugee = pdb->debugee;
1490 /* execute n ops */
1491 new_runloop_jump_point(debugee);
1492 if (setjmp(debugee->current_runloop->resume)) {
1493 Parrot_io_eprintf(pdb->debugger, "Unhandled exception while tracing\n");
1494 pdb->state |= PDB_STOPPED;
1495 return;
1497 pdb->tracing = n;
1498 pdb->state |= PDB_TRACING;
1499 Parrot_runcore_switch(pdb->debugee, CONST_STRING(interp, "debugger"));
1501 /* Clear the following when done some testing */
1503 /* we just stopped */
1504 pdb->state |= PDB_STOPPED;
1506 /* If program ended */
1507 if (!pdb->cur_opcode)
1508 (void)PDB_program_end(interp);
1509 pdb->state |= PDB_RUNNING;
1510 pdb->state &= ~PDB_STOPPED;
1512 TRACEDEB_MSG("PDB_trace finished");
1517 =item C<static unsigned short condition_regtype(const char *cmd)>
1519 =cut
1523 static unsigned short
1524 condition_regtype(ARGIN(const char *cmd))
1526 ASSERT_ARGS(condition_regtype)
1527 switch (*cmd) {
1528 case 'i':
1529 case 'I':
1530 return PDB_cond_int;
1531 case 'n':
1532 case 'N':
1533 return PDB_cond_num;
1534 case 's':
1535 case 'S':
1536 return PDB_cond_str;
1537 case 'p':
1538 case 'P':
1539 return PDB_cond_pmc;
1540 default:
1541 return 0;
1547 =item C<PDB_condition_t * PDB_cond(PARROT_INTERP, const char *command)>
1549 Analyzes a condition from the user input.
1551 =cut
1555 PARROT_CAN_RETURN_NULL
1556 PDB_condition_t *
1557 PDB_cond(PARROT_INTERP, ARGIN(const char *command))
1559 ASSERT_ARGS(PDB_cond)
1560 PDB_condition_t *condition;
1561 const char *auxcmd;
1562 char str[DEBUG_CMD_BUFFER_LENGTH + 1];
1563 unsigned short cond_argleft;
1564 unsigned short cond_type;
1565 unsigned char regleft;
1566 int i, reg_number;
1568 TRACEDEB_MSG("PDB_cond");
1570 /* Return if no more arguments */
1571 if (!(command && *command)) {
1572 Parrot_io_eprintf(interp->pdb->debugger, "No condition specified\n");
1573 return NULL;
1576 command = skip_whitespace(command);
1577 #if TRACE_DEBUGGER
1578 fprintf(stderr, "PDB_trace: '%s'\n", command);
1579 #endif
1581 cond_argleft = condition_regtype(command);
1583 /* get the register number */
1584 auxcmd = ++command;
1585 regleft = (unsigned char)get_uint(&command, 0);
1586 if (auxcmd == command) {
1587 Parrot_io_eprintf(interp->pdb->debugger, "Invalid register\n");
1588 return NULL;
1591 /* Now the condition */
1592 command = skip_whitespace(command);
1593 switch (*command) {
1594 case '>':
1595 if (*(command + 1) == '=')
1596 cond_type = PDB_cond_ge;
1597 else
1598 cond_type = PDB_cond_gt;
1599 break;
1600 case '<':
1601 if (*(command + 1) == '=')
1602 cond_type = PDB_cond_le;
1603 else
1604 cond_type = PDB_cond_lt;
1605 break;
1606 case '=':
1607 if (*(command + 1) == '=')
1608 cond_type = PDB_cond_eq;
1609 else
1610 goto INV_COND;
1611 break;
1612 case '!':
1613 if (*(command + 1) == '=')
1614 cond_type = PDB_cond_ne;
1615 else
1616 goto INV_COND;
1617 break;
1618 case '\0':
1619 if (cond_argleft != PDB_cond_str && cond_argleft != PDB_cond_pmc) {
1620 Parrot_io_eprintf(interp->pdb->debugger, "Invalid null condition\n");
1621 return NULL;
1623 cond_type = PDB_cond_notnull;
1624 break;
1625 default:
1626 INV_COND: Parrot_io_eprintf(interp->pdb->debugger, "Invalid condition\n");
1627 return NULL;
1630 /* if there's an '=', skip it */
1631 if (*(command + 1) == '=')
1632 command += 2;
1633 else
1634 command++;
1636 command = skip_whitespace(command);
1638 /* return if no notnull condition and no more arguments */
1639 if (!(command && *command) && (cond_type != PDB_cond_notnull)) {
1640 Parrot_io_eprintf(interp->pdb->debugger, "Can't compare a register with nothing\n");
1641 return NULL;
1644 /* Allocate new condition */
1645 condition = mem_allocate_zeroed_typed(PDB_condition_t);
1647 condition->type = cond_argleft | cond_type;
1649 if (cond_type != PDB_cond_notnull) {
1651 if (isalpha((unsigned char)*command)) {
1652 /* It's a register - we first check that it's the correct type */
1654 unsigned short cond_argright = condition_regtype(command);
1656 if (cond_argright != cond_argleft) {
1657 Parrot_io_eprintf(interp->pdb->debugger, "Register types don't agree\n");
1658 mem_sys_free(condition);
1659 return NULL;
1662 /* Now we check and store the register number */
1663 auxcmd = ++command;
1664 reg_number = (int)get_uint(&command, 0);
1665 if (auxcmd == command) {
1666 Parrot_io_eprintf(interp->pdb->debugger, "Invalid register\n");
1667 mem_sys_free(condition);
1668 return NULL;
1671 if (reg_number < 0) {
1672 Parrot_io_eprintf(interp->pdb->debugger, "Out-of-bounds register\n");
1673 mem_sys_free(condition);
1674 return NULL;
1677 condition->value = mem_allocate_typed(int);
1678 *(int *)condition->value = reg_number;
1680 /* If the first argument was an integer */
1681 else if (condition->type & PDB_cond_int) {
1682 /* This must be either an integer constant or register */
1683 condition->value = mem_allocate_typed(INTVAL);
1684 *(INTVAL *)condition->value = (INTVAL)atoi(command);
1685 condition->type |= PDB_cond_const;
1687 else if (condition->type & PDB_cond_num) {
1688 condition->value = mem_allocate_typed(FLOATVAL);
1689 *(FLOATVAL *)condition->value = (FLOATVAL)atof(command);
1690 condition->type |= PDB_cond_const;
1692 else if (condition->type & PDB_cond_str) {
1693 for (i = 1; ((command[i] != '"') && (i < DEBUG_CMD_BUFFER_LENGTH)); i++)
1694 str[i - 1] = command[i];
1695 str[i - 1] = '\0';
1696 #if TRACE_DEBUGGER
1697 fprintf(stderr, "PDB_break: '%s'\n", str);
1698 #endif
1699 condition->value = string_make(interp, str, (UINTVAL)(i - 1),
1700 NULL, 0);
1702 condition->type |= PDB_cond_const;
1704 else if (condition->type & PDB_cond_pmc) {
1705 /* RT #46123 Need to figure out what to do in this case.
1706 * For the time being, we just bail. */
1707 Parrot_io_eprintf(interp->pdb->debugger, "Can't compare PMC with constant\n");
1708 mem_sys_free(condition);
1709 return NULL;
1714 return condition;
1719 =item C<void PDB_watchpoint(PARROT_INTERP, const char *command)>
1721 Set a watchpoint.
1723 =cut
1727 void
1728 PDB_watchpoint(PARROT_INTERP, ARGIN(const char *command))
1730 ASSERT_ARGS(PDB_watchpoint)
1731 PDB_t * const pdb = interp->pdb;
1732 PDB_condition_t * const condition = PDB_cond(interp, command);
1734 if (!condition)
1735 return;
1737 /* Add it to the head of the list */
1738 if (pdb->watchpoint)
1739 condition->next = pdb->watchpoint;
1740 pdb->watchpoint = condition;
1741 fprintf(stderr, "Adding watchpoint\n");
1746 =item C<void PDB_set_break(PARROT_INTERP, const char *command)>
1748 Set a break point, the source code file must be loaded.
1750 =cut
1754 void
1755 PDB_set_break(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1757 ASSERT_ARGS(PDB_set_break)
1758 PDB_t * const pdb = interp->pdb;
1759 PDB_breakpoint_t *newbreak;
1760 PDB_breakpoint_t **lbreak;
1761 PDB_line_t *line = NULL;
1762 long bp_id;
1763 opcode_t *breakpos = NULL;
1765 unsigned long ln = get_ulong(& command, 0);
1767 TRACEDEB_MSG("PDB_set_break");
1769 /* If there is a source file use line number, else opcode position */
1772 if (pdb->file) {
1773 TRACEDEB_MSG("PDB_set_break file");
1775 if (!pdb->file->size) {
1776 Parrot_io_eprintf(pdb->debugger,
1777 "Can't set a breakpoint in empty file\n");
1778 return;
1781 /* If no line number was specified, set it at the current line */
1782 if (ln != 0) {
1783 unsigned long i;
1785 /* Move to the line where we will set the break point */
1786 line = pdb->file->line;
1788 for (i = 1; ((i < ln) && (line->next)); i++)
1789 line = line->next;
1791 /* Abort if the line number provided doesn't exist */
1792 if (line == NULL || !line->next) {
1793 Parrot_io_eprintf(pdb->debugger,
1794 "Can't set a breakpoint at line number %li\n", ln);
1795 return;
1798 else {
1799 /* Get the line to set it */
1800 line = pdb->file->line;
1802 TRACEDEB_MSG("PDB_set_break reading ops");
1803 while (line->opcode != pdb->cur_opcode) {
1804 line = line->next;
1805 if (!line) {
1806 Parrot_io_eprintf(pdb->debugger,
1807 "No current line found and no line number specified\n");
1808 return;
1812 /* Skip lines that are not related to an opcode */
1813 while (line && !line->opcode)
1814 line = line->next;
1815 /* Abort if the line number provided doesn't exist */
1816 if (!line) {
1817 Parrot_io_eprintf(pdb->debugger,
1818 "Can't set a breakpoint at line number %li\n", ln);
1819 return;
1822 breakpos = line->opcode;
1824 else {
1825 TRACEDEB_MSG("PDB_set_break no file");
1826 breakpos = interp->code->base.data + ln;
1829 TRACEDEB_MSG("PDB_set_break allocate breakpoint");
1830 /* Allocate the new break point */
1831 newbreak = mem_allocate_zeroed_typed(PDB_breakpoint_t);
1833 if (command) {
1834 /*command = skip_command(command);*/
1836 else {
1837 Parrot_ex_throw_from_c_args(interp, NULL, 1,
1838 "NULL command passed to PDB_set_break");
1841 /* if there is another argument to break, besides the line number,
1842 * it should be an 'if', so we call another handler. */
1843 if (command && *command) {
1844 command = skip_whitespace(command);
1845 while (! isspace((unsigned char)*command))
1846 ++command;
1847 command = skip_whitespace(command);
1848 newbreak->condition = PDB_cond(interp, command);
1851 /* Set the address where to stop */
1852 newbreak->pc = breakpos;
1854 /* No next breakpoint */
1855 newbreak->next = NULL;
1857 /* Don't skip (at least initially) */
1858 newbreak->skip = 0;
1860 /* Add the breakpoint to the end of the list */
1861 bp_id = 1;
1862 lbreak = & pdb->breakpoint;
1863 while (*lbreak) {
1864 bp_id = (*lbreak)->id + 1;
1865 lbreak = & (*lbreak)->next;
1867 newbreak->prev = *lbreak;
1868 *lbreak = newbreak;
1869 newbreak->id = bp_id;
1871 /* Show breakpoint position */
1873 Parrot_io_eprintf(pdb->debugger, "Breakpoint %li at", newbreak->id);
1874 if (line)
1875 Parrot_io_eprintf(pdb->debugger, " line %li", line->number);
1876 Parrot_io_eprintf(pdb->debugger, " pos %li\n", newbreak->pc - interp->code->base.data);
1881 =item C<static void list_breakpoints(PDB_t *pdb)>
1883 =cut
1887 static void
1888 list_breakpoints(ARGIN(PDB_t *pdb))
1890 ASSERT_ARGS(list_breakpoints)
1892 PDB_breakpoint_t **lbreak;
1893 for (lbreak = & pdb->breakpoint; *lbreak; lbreak = & (*lbreak)->next) {
1894 PDB_breakpoint_t *br = *lbreak;
1895 Parrot_io_eprintf(pdb->debugger, "Breakpoint %li at", br->id);
1896 Parrot_io_eprintf(pdb->debugger, " pos %li", br->pc - pdb->debugee->code->base.data);
1897 if (br->skip == -1)
1898 Parrot_io_eprintf(pdb->debugger, " (disabled)");
1899 Parrot_io_eprintf(pdb->debugger, "\n");
1905 =item C<void PDB_init(PARROT_INTERP, const char *command)>
1907 Init the program.
1909 =cut
1913 void
1914 PDB_init(PARROT_INTERP, SHIM(const char *command))
1916 ASSERT_ARGS(PDB_init)
1917 PDB_t * const pdb = interp->pdb;
1919 /* Restart if we are already running */
1920 if (pdb->state & PDB_RUNNING)
1921 Parrot_io_eprintf(pdb->debugger, "Restarting\n");
1923 /* Add the RUNNING state */
1924 pdb->state |= PDB_RUNNING;
1929 =item C<void PDB_continue(PARROT_INTERP, const char *command)>
1931 Continue running the program. If a number is specified, skip that many
1932 breakpoints.
1934 =cut
1938 void
1939 PDB_continue(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1941 ASSERT_ARGS(PDB_continue)
1942 PDB_t * const pdb = interp->pdb;
1943 unsigned long ln = 0;
1945 TRACEDEB_MSG("PDB_continue");
1947 /* Skip any breakpoint? */
1948 if (command)
1949 ln = get_ulong(& command, 0);
1951 if (ln != 0) {
1952 if (!pdb->breakpoint) {
1953 Parrot_io_eprintf(pdb->debugger, "No breakpoints to skip\n");
1954 return;
1957 PDB_skip_breakpoint(interp, ln);
1960 /* Run while no break point is reached */
1962 while (!PDB_break(interp))
1963 DO_OP(pdb->cur_opcode, pdb->debugee);
1966 #if 0
1967 pdb->tracing = 0;
1968 Parrot_runcore_switch(pdb->debugee, CONST_STRING(interp, "debugger"));
1970 new_internal_exception(pdb->debugee);
1971 if (setjmp(pdb->debugee->exceptions->destination)) {
1972 Parrot_io_eprintf(pdb->debugee, "Unhandled exception while debugging: %Ss\n",
1973 pdb->debugee->exceptions->msg);
1974 pdb->state |= PDB_STOPPED;
1975 return;
1977 runops_int(pdb->debugee, pdb->debugee->code->base.data - pdb->cur_opcode);
1978 if (!pdb->cur_opcode)
1979 (void)PDB_program_end(interp);
1980 #endif
1981 pdb->state |= PDB_RUNNING;
1982 pdb->state &= ~PDB_BREAK;
1983 pdb->state &= ~PDB_STOPPED;
1988 =item C<PDB_breakpoint_t * PDB_find_breakpoint(PARROT_INTERP, const char
1989 *command)>
1991 Find breakpoint number N; returns C<NULL> if the breakpoint doesn't
1992 exist or if no breakpoint was specified.
1994 =cut
1998 PARROT_CAN_RETURN_NULL
1999 PARROT_WARN_UNUSED_RESULT
2000 PDB_breakpoint_t *
2001 PDB_find_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2003 ASSERT_ARGS(PDB_find_breakpoint)
2004 const char *oldcmd = command;
2005 const unsigned long n = get_ulong(&command, 0);
2006 if (command != oldcmd) {
2007 PDB_breakpoint_t *breakpoint = interp->pdb->breakpoint;
2009 while (breakpoint && breakpoint->id != n)
2010 breakpoint = breakpoint->next;
2012 if (!breakpoint) {
2013 Parrot_io_eprintf(interp->pdb->debugger, "No breakpoint number %ld", n);
2014 return NULL;
2017 return breakpoint;
2019 else {
2020 /* Report an appropriate error */
2021 if (*command)
2022 Parrot_io_eprintf(interp->pdb->debugger, "Not a valid breakpoint");
2023 else
2024 Parrot_io_eprintf(interp->pdb->debugger, "No breakpoint specified");
2026 return NULL;
2032 =item C<void PDB_disable_breakpoint(PARROT_INTERP, const char *command)>
2034 Disable a breakpoint; it can be reenabled with the enable command.
2036 =cut
2040 void
2041 PDB_disable_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2043 ASSERT_ARGS(PDB_disable_breakpoint)
2044 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2046 /* if the breakpoint exists, disable it. */
2047 if (breakpoint)
2048 breakpoint->skip = -1;
2053 =item C<void PDB_enable_breakpoint(PARROT_INTERP, const char *command)>
2055 Reenable a disabled breakpoint; if the breakpoint was not disabled, has
2056 no effect.
2058 =cut
2062 void
2063 PDB_enable_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2065 ASSERT_ARGS(PDB_enable_breakpoint)
2066 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2068 /* if the breakpoint exists, and it was disabled, enable it. */
2069 if (breakpoint && breakpoint->skip == -1)
2070 breakpoint->skip = 0;
2075 =item C<void PDB_delete_breakpoint(PARROT_INTERP, const char *command)>
2077 Delete a breakpoint.
2079 =cut
2083 void
2084 PDB_delete_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2086 ASSERT_ARGS(PDB_delete_breakpoint)
2087 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2088 const PDB_line_t *line;
2089 long bp_id;
2091 if (breakpoint) {
2092 if (!interp->pdb->file)
2093 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No file loaded");
2095 line = interp->pdb->file->line;
2096 while (line->opcode != breakpoint->pc)
2097 line = line->next;
2099 /* Delete the condition structure, if there is one */
2100 if (breakpoint->condition) {
2101 PDB_delete_condition(interp, breakpoint);
2102 breakpoint->condition = NULL;
2105 /* Remove the breakpoint from the list */
2106 if (breakpoint->prev && breakpoint->next) {
2107 breakpoint->prev->next = breakpoint->next;
2108 breakpoint->next->prev = breakpoint->prev;
2110 else if (breakpoint->prev && !breakpoint->next) {
2111 breakpoint->prev->next = NULL;
2113 else if (!breakpoint->prev && breakpoint->next) {
2114 breakpoint->next->prev = NULL;
2115 interp->pdb->breakpoint = breakpoint->next;
2117 else {
2118 interp->pdb->breakpoint = NULL;
2120 bp_id = breakpoint->id;
2121 /* Kill the breakpoint */
2122 mem_sys_free(breakpoint);
2124 Parrot_io_eprintf(interp->pdb->debugger, "Breakpoint %li deleted\n", bp_id);
2130 =item C<void PDB_delete_condition(PARROT_INTERP, PDB_breakpoint_t *breakpoint)>
2132 Delete a condition associated with a breakpoint.
2134 =cut
2138 void
2139 PDB_delete_condition(SHIM_INTERP, ARGMOD(PDB_breakpoint_t *breakpoint))
2141 ASSERT_ARGS(PDB_delete_condition)
2142 if (breakpoint->condition->value) {
2143 if (breakpoint->condition->type & PDB_cond_str) {
2144 /* 'value' is a string, so we need to be careful */
2145 PObj_external_CLEAR((STRING*)breakpoint->condition->value);
2146 PObj_on_free_list_SET((STRING*)breakpoint->condition->value);
2147 /* it should now be properly garbage collected after
2148 we destroy the condition */
2150 else {
2151 /* 'value' is a float or an int, so we can just free it */
2152 mem_sys_free(breakpoint->condition->value);
2153 breakpoint->condition->value = NULL;
2157 mem_sys_free(breakpoint->condition);
2158 breakpoint->condition = NULL;
2163 =item C<void PDB_skip_breakpoint(PARROT_INTERP, unsigned long i)>
2165 Skip C<i> times all breakpoints.
2167 =cut
2171 void
2172 PDB_skip_breakpoint(PARROT_INTERP, unsigned long i)
2174 ASSERT_ARGS(PDB_skip_breakpoint)
2175 #if TRACE_DEBUGGER
2176 fprintf(stderr, "PDB_skip_breakpoint: %li\n", i);
2177 #endif
2179 interp->pdb->breakpoint_skip = i;
2184 =item C<char PDB_program_end(PARROT_INTERP)>
2186 End the program.
2188 =cut
2192 char
2193 PDB_program_end(PARROT_INTERP)
2195 ASSERT_ARGS(PDB_program_end)
2196 PDB_t * const pdb = interp->pdb;
2198 TRACEDEB_MSG("PDB_program_end");
2200 /* Remove the RUNNING state */
2201 pdb->state &= ~PDB_RUNNING;
2203 Parrot_io_eprintf(pdb->debugger, "Program exited.\n");
2204 return 1;
2209 =item C<char PDB_check_condition(PARROT_INTERP, const PDB_condition_t
2210 *condition)>
2212 Returns true if the condition was met.
2214 =cut
2218 PARROT_WARN_UNUSED_RESULT
2219 char
2220 PDB_check_condition(PARROT_INTERP, ARGIN(const PDB_condition_t *condition))
2222 ASSERT_ARGS(PDB_check_condition)
2223 PMC *ctx = CURRENT_CONTEXT(interp);
2225 TRACEDEB_MSG("PDB_check_condition");
2227 PARROT_ASSERT(ctx);
2229 if (condition->type & PDB_cond_int) {
2230 INTVAL i, j;
2231 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_INT))
2232 return 0;
2233 i = CTX_REG_INT(ctx, condition->reg);
2235 if (condition->type & PDB_cond_const)
2236 j = *(INTVAL *)condition->value;
2237 else
2238 j = REG_INT(interp, *(int *)condition->value);
2240 if (((condition->type & PDB_cond_gt) && (i > j)) ||
2241 ((condition->type & PDB_cond_ge) && (i >= j)) ||
2242 ((condition->type & PDB_cond_eq) && (i == j)) ||
2243 ((condition->type & PDB_cond_ne) && (i != j)) ||
2244 ((condition->type & PDB_cond_le) && (i <= j)) ||
2245 ((condition->type & PDB_cond_lt) && (i < j)))
2246 return 1;
2248 return 0;
2250 else if (condition->type & PDB_cond_num) {
2251 FLOATVAL k, l;
2253 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_NUM))
2254 return 0;
2255 k = CTX_REG_NUM(ctx, condition->reg);
2257 if (condition->type & PDB_cond_const)
2258 l = *(FLOATVAL *)condition->value;
2259 else
2260 l = REG_NUM(interp, *(int *)condition->value);
2262 if (((condition->type & PDB_cond_gt) && (k > l)) ||
2263 ((condition->type & PDB_cond_ge) && (k >= l)) ||
2264 ((condition->type & PDB_cond_eq) && (k == l)) ||
2265 ((condition->type & PDB_cond_ne) && (k != l)) ||
2266 ((condition->type & PDB_cond_le) && (k <= l)) ||
2267 ((condition->type & PDB_cond_lt) && (k < l)))
2268 return 1;
2270 return 0;
2272 else if (condition->type & PDB_cond_str) {
2273 STRING *m, *n;
2275 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_STR))
2276 return 0;
2277 m = CTX_REG_STR(ctx, condition->reg);
2279 if (condition->type & PDB_cond_notnull)
2280 return ! STRING_IS_NULL(m);
2282 if (condition->type & PDB_cond_const)
2283 n = (STRING *)condition->value;
2284 else
2285 n = REG_STR(interp, *(int *)condition->value);
2287 if (((condition->type & PDB_cond_gt) &&
2288 (Parrot_str_compare(interp, m, n) > 0)) ||
2289 ((condition->type & PDB_cond_ge) &&
2290 (Parrot_str_compare(interp, m, n) >= 0)) ||
2291 ((condition->type & PDB_cond_eq) &&
2292 (Parrot_str_compare(interp, m, n) == 0)) ||
2293 ((condition->type & PDB_cond_ne) &&
2294 (Parrot_str_compare(interp, m, n) != 0)) ||
2295 ((condition->type & PDB_cond_le) &&
2296 (Parrot_str_compare(interp, m, n) <= 0)) ||
2297 ((condition->type & PDB_cond_lt) &&
2298 (Parrot_str_compare(interp, m, n) < 0)))
2299 return 1;
2301 return 0;
2303 else if (condition->type & PDB_cond_pmc) {
2304 PMC *m;
2306 if (condition->reg >= Parrot_pcc_get_regs_used(interp, ctx, REGNO_PMC))
2307 return 0;
2308 m = CTX_REG_PMC(ctx, condition->reg);
2310 if (condition->type & PDB_cond_notnull)
2311 return ! PMC_IS_NULL(m);
2312 return 0;
2314 else
2315 return 0;
2320 =item C<static PDB_breakpoint_t * current_breakpoint(PDB_t * pdb)>
2322 Returns a pointer to the breakpoint at the current position,
2323 or NULL if there is none.
2325 =cut
2329 PARROT_CAN_RETURN_NULL
2330 static PDB_breakpoint_t *
2331 current_breakpoint(ARGIN(PDB_t * pdb))
2333 ASSERT_ARGS(current_breakpoint)
2334 PDB_breakpoint_t *breakpoint = pdb->breakpoint;
2335 while (breakpoint) {
2336 if (pdb->cur_opcode == breakpoint->pc)
2337 break;
2338 breakpoint = breakpoint->next;
2340 return breakpoint;
2345 =item C<char PDB_break(PARROT_INTERP)>
2347 Returns true if we have to stop running.
2349 =cut
2353 PARROT_WARN_UNUSED_RESULT
2354 char
2355 PDB_break(PARROT_INTERP)
2357 ASSERT_ARGS(PDB_break)
2358 PDB_t * const pdb = interp->pdb;
2359 PDB_condition_t *watchpoint = pdb->watchpoint;
2360 PDB_breakpoint_t *breakpoint;
2363 TRACEDEB_MSG("PDB_break");
2366 /* Check the watchpoints first. */
2367 while (watchpoint) {
2368 if (PDB_check_condition(interp, watchpoint)) {
2369 pdb->state |= PDB_STOPPED;
2370 return 1;
2373 watchpoint = watchpoint->next;
2376 /* If program ended */
2377 if (!pdb->cur_opcode)
2378 return PDB_program_end(interp);
2380 /* If the program is STOPPED allow it to continue */
2381 if (pdb->state & PDB_STOPPED) {
2382 pdb->state &= ~PDB_STOPPED;
2383 return 0;
2386 breakpoint = current_breakpoint(pdb);
2387 if (breakpoint) {
2388 /* If we have to skip breakpoints, do so. */
2389 if (pdb->breakpoint_skip) {
2390 TRACEDEB_MSG("PDB_break skipping");
2391 pdb->breakpoint_skip--;
2392 return 0;
2395 if (breakpoint->skip < 0)
2396 return 0;
2398 /* Check if there is a condition for this breakpoint */
2399 if ((breakpoint->condition) &&
2400 (!PDB_check_condition(interp, breakpoint->condition)))
2401 return 0;
2403 TRACEDEB_MSG("PDB_break stopping");
2405 /* Add the STOPPED state and stop */
2406 pdb->state |= PDB_STOPPED;
2407 return 1;
2410 return 0;
2415 =item C<char * PDB_escape(const char *string, UINTVAL length)>
2417 Escapes C<">, C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2419 The returned string must be freed.
2421 =cut
2425 PARROT_WARN_UNUSED_RESULT
2426 PARROT_CAN_RETURN_NULL
2427 PARROT_MALLOC
2428 char *
2429 PDB_escape(ARGIN(const char *string), UINTVAL length)
2431 ASSERT_ARGS(PDB_escape)
2432 const char *end;
2433 char *_new, *fill;
2435 length = length > 20 ? 20 : length;
2436 end = string + length;
2438 /* Return if there is no string to escape*/
2439 if (!string)
2440 return NULL;
2442 fill = _new = (char *)mem_sys_allocate(length * 2 + 1);
2444 for (; string < end; string++) {
2445 switch (*string) {
2446 case '\0':
2447 *(fill++) = '\\';
2448 *(fill++) = '0';
2449 break;
2450 case '\n':
2451 *(fill++) = '\\';
2452 *(fill++) = 'n';
2453 break;
2454 case '\r':
2455 *(fill++) = '\\';
2456 *(fill++) = 'r';
2457 break;
2458 case '\t':
2459 *(fill++) = '\\';
2460 *(fill++) = 't';
2461 break;
2462 case '\a':
2463 *(fill++) = '\\';
2464 *(fill++) = 'a';
2465 break;
2466 case '\\':
2467 *(fill++) = '\\';
2468 *(fill++) = '\\';
2469 break;
2470 case '"':
2471 *(fill++) = '\\';
2472 *(fill++) = '"';
2473 break;
2474 default:
2475 *(fill++) = *string;
2476 break;
2480 *fill = '\0';
2482 return _new;
2487 =item C<int PDB_unescape(char *string)>
2489 Do inplace unescape of C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2491 =cut
2496 PDB_unescape(ARGMOD(char *string))
2498 ASSERT_ARGS(PDB_unescape)
2499 int l = 0;
2501 for (; *string; string++) {
2502 l++;
2504 if (*string == '\\') {
2505 char *fill;
2506 int i;
2508 switch (string[1]) {
2509 case 'n':
2510 *string = '\n';
2511 break;
2512 case 'r':
2513 *string = '\r';
2514 break;
2515 case 't':
2516 *string = '\t';
2517 break;
2518 case 'a':
2519 *string = '\a';
2520 break;
2521 case '\\':
2522 *string = '\\';
2523 break;
2524 default:
2525 continue;
2528 fill = string;
2530 for (i = 1; fill[i + 1]; i++)
2531 fill[i] = fill[i + 1];
2533 fill[i] = '\0';
2537 return l;
2542 =item C<size_t PDB_disassemble_op(PARROT_INTERP, char *dest, size_t space, const
2543 op_info_t *info, const opcode_t *op, PDB_file_t *file, const opcode_t
2544 *code_start, int full_name)>
2546 Disassembles C<op>.
2548 =cut
2552 size_t
2553 PDB_disassemble_op(PARROT_INTERP, ARGOUT(char *dest), size_t space,
2554 ARGIN(const op_info_t *info), ARGIN(const opcode_t *op),
2555 ARGMOD_NULLOK(PDB_file_t *file), ARGIN_NULLOK(const opcode_t *code_start),
2556 int full_name)
2558 ASSERT_ARGS(PDB_disassemble_op)
2559 int j;
2560 size_t size = 0;
2561 int specialop = 0;
2563 /* Write the opcode name */
2564 const char * p = full_name ? info->full_name : info->name;
2566 TRACEDEB_MSG("PDB_disassemble_op");
2568 if (! p)
2569 p= "**UNKNOWN**";
2570 strcpy(dest, p);
2571 size += strlen(p);
2573 dest[size++] = ' ';
2575 /* Concat the arguments */
2576 for (j = 1; j < info->op_count; j++) {
2577 char buf[256];
2578 INTVAL i = 0;
2580 PARROT_ASSERT(size + 2 < space);
2582 switch (info->types[j - 1]) {
2583 case PARROT_ARG_I:
2584 dest[size++] = 'I';
2585 goto INTEGER;
2586 case PARROT_ARG_N:
2587 dest[size++] = 'N';
2588 goto INTEGER;
2589 case PARROT_ARG_S:
2590 dest[size++] = 'S';
2591 goto INTEGER;
2592 case PARROT_ARG_P:
2593 dest[size++] = 'P';
2594 goto INTEGER;
2595 case PARROT_ARG_IC:
2596 /* If the opcode jumps and this is the last argument,
2597 that means this is a label */
2598 if ((j == info->op_count - 1) &&
2599 (info->jump & PARROT_JUMP_RELATIVE)) {
2600 if (file) {
2601 dest[size++] = 'L';
2602 i = PDB_add_label(file, op, op[j]);
2604 else if (code_start) {
2605 dest[size++] = 'O';
2606 dest[size++] = 'P';
2607 i = op[j] + (op - code_start);
2609 else {
2610 if (op[j] > 0)
2611 dest[size++] = '+';
2612 i = op[j];
2616 /* Convert the integer to a string */
2617 INTEGER:
2618 if (i == 0)
2619 i = (INTVAL) op[j];
2621 PARROT_ASSERT(size + 20 < space);
2623 size += sprintf(&dest[size], INTVAL_FMT, i);
2625 break;
2626 case PARROT_ARG_NC:
2628 /* Convert the float to a string */
2629 const FLOATVAL f = interp->code->const_table->constants[op[j]]->u.number;
2630 Parrot_snprintf(interp, buf, sizeof (buf), FLOATVAL_FMT, f);
2631 strcpy(&dest[size], buf);
2632 size += strlen(buf);
2634 break;
2635 case PARROT_ARG_SC:
2636 dest[size++] = '"';
2637 if (interp->code->const_table->constants[op[j]]-> u.string->strlen) {
2638 char * const escaped =
2639 PDB_escape(interp->code->const_table->
2640 constants[op[j]]->u.string->strstart,
2641 interp->code->const_table->
2642 constants[op[j]]->u.string->strlen);
2643 if (escaped) {
2644 strcpy(&dest[size], escaped);
2645 size += strlen(escaped);
2646 mem_sys_free(escaped);
2649 dest[size++] = '"';
2650 break;
2651 case PARROT_ARG_PC:
2652 Parrot_snprintf(interp, buf, sizeof (buf), "PMC_CONST(%d)", op[j]);
2653 strcpy(&dest[size], buf);
2654 size += strlen(buf);
2655 break;
2656 case PARROT_ARG_K:
2657 dest[size - 1] = '[';
2658 Parrot_snprintf(interp, buf, sizeof (buf), "P" INTVAL_FMT, op[j]);
2659 strcpy(&dest[size], buf);
2660 size += strlen(buf);
2661 dest[size++] = ']';
2662 break;
2663 case PARROT_ARG_KC:
2665 PMC * k = interp->code->const_table->constants[op[j]]->u.key;
2666 dest[size - 1] = '[';
2667 while (k) {
2668 switch (PObj_get_FLAGS(k)) {
2669 case 0:
2670 break;
2671 case KEY_integer_FLAG:
2672 Parrot_snprintf(interp, buf, sizeof (buf),
2673 INTVAL_FMT, VTABLE_get_integer(interp, k));
2674 strcpy(&dest[size], buf);
2675 size += strlen(buf);
2676 break;
2677 case KEY_number_FLAG:
2678 Parrot_snprintf(interp, buf, sizeof (buf),
2679 FLOATVAL_FMT, VTABLE_get_number(interp, k));
2680 strcpy(&dest[size], buf);
2681 size += strlen(buf);
2682 break;
2683 case KEY_string_FLAG:
2684 dest[size++] = '"';
2686 char * const temp = Parrot_str_to_cstring(interp,
2687 VTABLE_get_string(interp, k));
2688 strcpy(&dest[size], temp);
2689 Parrot_str_free_cstring(temp);
2691 size += Parrot_str_byte_length(interp,
2692 VTABLE_get_string(interp, (k)));
2693 dest[size++] = '"';
2694 break;
2695 case KEY_integer_FLAG|KEY_register_FLAG:
2696 Parrot_snprintf(interp, buf, sizeof (buf),
2697 "I" INTVAL_FMT, VTABLE_get_integer(interp, k));
2698 strcpy(&dest[size], buf);
2699 size += strlen(buf);
2700 break;
2701 case KEY_number_FLAG|KEY_register_FLAG:
2702 Parrot_snprintf(interp, buf, sizeof (buf),
2703 "N" INTVAL_FMT, VTABLE_get_integer(interp, k));
2704 strcpy(&dest[size], buf);
2705 size += strlen(buf);
2706 break;
2707 case KEY_string_FLAG|KEY_register_FLAG:
2708 Parrot_snprintf(interp, buf, sizeof (buf),
2709 "S" INTVAL_FMT, VTABLE_get_integer(interp, k));
2710 strcpy(&dest[size], buf);
2711 size += strlen(buf);
2712 break;
2713 case KEY_pmc_FLAG|KEY_register_FLAG:
2714 Parrot_snprintf(interp, buf, sizeof (buf),
2715 "P" INTVAL_FMT, VTABLE_get_integer(interp, k));
2716 strcpy(&dest[size], buf);
2717 size += strlen(buf);
2718 break;
2719 default:
2720 dest[size++] = '?';
2721 break;
2723 GETATTR_Key_next_key(interp, k, k);
2724 if (k)
2725 dest[size++] = ';';
2727 dest[size++] = ']';
2729 break;
2730 case PARROT_ARG_KI:
2731 dest[size - 1] = '[';
2732 Parrot_snprintf(interp, buf, sizeof (buf), "I" INTVAL_FMT, op[j]);
2733 strcpy(&dest[size], buf);
2734 size += strlen(buf);
2735 dest[size++] = ']';
2736 break;
2737 case PARROT_ARG_KIC:
2738 dest[size - 1] = '[';
2739 Parrot_snprintf(interp, buf, sizeof (buf), INTVAL_FMT, op[j]);
2740 strcpy(&dest[size], buf);
2741 size += strlen(buf);
2742 dest[size++] = ']';
2743 break;
2744 default:
2745 Parrot_ex_throw_from_c_args(interp, NULL, 1, "Unknown opcode type");
2748 if (j != info->op_count - 1)
2749 dest[size++] = ',';
2752 /* Special decoding for the signature used in args/returns. Such ops have
2753 one fixed parameter (the signature vector), plus a varying number of
2754 registers/constants. For each arg/return, we show the register and its
2755 flags using PIR syntax. */
2756 if (*(op) == PARROT_OP_set_args_pc || *(op) == PARROT_OP_set_returns_pc)
2757 specialop = 1;
2759 /* if it's a retrieving op, specialop = 2, so that later a :flat flag
2760 * can be changed into a :slurpy flag. See flag handling below.
2762 if (*(op) == PARROT_OP_get_results_pc || *(op) == PARROT_OP_get_params_pc)
2763 specialop = 2;
2765 if (specialop > 0) {
2766 char buf[1000];
2767 PMC * const sig = interp->code->const_table->constants[op[1]]->u.key;
2768 const int n_values = VTABLE_elements(interp, sig);
2769 /* The flag_names strings come from Call_bits_enum_t (with which it
2770 should probably be colocated); they name the bits from LSB to MSB.
2771 The two least significant bits are not flags; they are the register
2772 type, which is decoded elsewhere. We also want to show unused bits,
2773 which could indicate problems.
2775 PARROT_OBSERVER const char * const flag_names[] = {
2778 " :unused004",
2779 " :unused008",
2780 " :const",
2781 " :flat", /* should be :slurpy for args */
2782 " :unused040",
2783 " :optional",
2784 " :opt_flag",
2785 " :named",
2786 NULL
2790 /* Register decoding. It would be good to abstract this, too. */
2791 PARROT_OBSERVER static const char regs[] = "ISPN";
2793 for (j = 0; j < n_values; j++) {
2794 size_t idx = 0;
2795 const int sig_value = VTABLE_get_integer_keyed_int(interp, sig, j);
2797 /* Print the register name, e.g. P37. */
2798 buf[idx++] = ',';
2799 buf[idx++] = ' ';
2800 buf[idx++] = regs[sig_value & PARROT_ARG_TYPE_MASK];
2801 Parrot_snprintf(interp, &buf[idx], sizeof (buf)-idx,
2802 INTVAL_FMT, op[j+2]);
2803 idx = strlen(buf);
2805 /* Add flags, if we have any. */
2807 int flag_idx = 0;
2808 int flags = sig_value;
2810 /* End when we run out of flags, off the end of flag_names, or
2811 * get too close to the end of buf.
2812 * 100 is just an estimate of all buf lengths added together.
2814 while (flags && idx < sizeof (buf) - 100) {
2815 const char * const flag_string
2816 = (specialop == 2 && STREQ(flag_names[flag_idx], " :flat"))
2817 ? " :slurpy"
2818 : flag_names[flag_idx];
2820 if (! flag_string)
2821 break;
2822 if (flags & 1 && *flag_string) {
2823 const size_t n = strlen(flag_string);
2824 strcpy(&buf[idx], flag_string);
2825 idx += n;
2827 flags >>= 1;
2828 flag_idx++;
2832 /* Add it to dest. */
2833 buf[idx++] = '\0';
2834 strcpy(&dest[size], buf);
2835 size += strlen(buf);
2839 dest[size] = '\0';
2840 return ++size;
2845 =item C<void PDB_disassemble(PARROT_INTERP, const char *command)>
2847 Disassemble the bytecode.
2849 =cut
2853 void
2854 PDB_disassemble(PARROT_INTERP, SHIM(const char *command))
2856 ASSERT_ARGS(PDB_disassemble)
2857 PDB_t * const pdb = interp->pdb;
2858 opcode_t * pc = interp->code->base.data;
2860 PDB_file_t *pfile;
2861 PDB_line_t *pline, *newline;
2862 PDB_label_t *label;
2863 opcode_t *code_end;
2865 const unsigned int default_size = 32768;
2866 size_t space; /* How much space do we have? */
2867 size_t size, alloced, n;
2869 TRACEDEB_MSG("PDB_disassemble");
2871 pfile = mem_allocate_zeroed_typed(PDB_file_t);
2872 pline = mem_allocate_zeroed_typed(PDB_line_t);
2874 /* If we already got a source, free it */
2875 if (pdb->file) {
2876 PDB_free_file(interp, pdb->file);
2877 pdb->file = NULL;
2880 pfile->line = pline;
2881 pline->number = 1;
2882 pfile->source = (char *)mem_sys_allocate(default_size);
2884 alloced = space = default_size;
2885 code_end = pc + interp->code->base.size;
2887 while (pc != code_end) {
2888 /* Grow it early */
2889 if (space < default_size) {
2890 alloced += default_size;
2891 space += default_size;
2892 pfile->source = (char *)mem_sys_realloc(pfile->source, alloced);
2895 size = PDB_disassemble_op(interp, pfile->source + pfile->size,
2896 space, &interp->op_info_table[*pc], pc, pfile, NULL, 1);
2897 space -= size;
2898 pfile->size += size;
2899 pfile->source[pfile->size - 1] = '\n';
2901 /* Store the opcode of this line */
2902 pline->opcode = pc;
2903 n = interp->op_info_table[*pc].op_count;
2905 ADD_OP_VAR_PART(interp, interp->code, pc, n);
2906 pc += n;
2908 /* Prepare for next line */
2909 newline = mem_allocate_typed(PDB_line_t);
2910 newline->label = NULL;
2911 newline->next = NULL;
2912 newline->number = pline->number + 1;
2913 pline->next = newline;
2914 pline = newline;
2915 pline->source_offset = pfile->size;
2918 /* Add labels to the lines they belong to */
2919 label = pfile->label;
2921 while (label) {
2922 /* Get the line to apply the label */
2923 pline = pfile->line;
2925 while (pline && pline->opcode != label->opcode)
2926 pline = pline->next;
2928 if (!pline) {
2929 Parrot_io_eprintf(pdb->debugger,
2930 "Label number %li out of bounds.\n", label->number);
2932 PDB_free_file(interp, pfile);
2933 return;
2936 pline->label = label;
2938 label = label->next;
2941 pdb->state |= PDB_SRC_LOADED;
2942 pdb->file = pfile;
2947 =item C<long PDB_add_label(PDB_file_t *file, const opcode_t *cur_opcode,
2948 opcode_t offset)>
2950 Add a label to the label list.
2952 =cut
2956 long
2957 PDB_add_label(ARGMOD(PDB_file_t *file), ARGIN(const opcode_t *cur_opcode),
2958 opcode_t offset)
2960 ASSERT_ARGS(PDB_add_label)
2961 PDB_label_t *_new;
2962 PDB_label_t *label = file->label;
2964 /* See if there is already a label at this line */
2965 while (label) {
2966 if (label->opcode == cur_opcode + offset)
2967 return label->number;
2968 label = label->next;
2971 /* Allocate a new label */
2972 label = file->label;
2973 _new = mem_allocate_typed(PDB_label_t);
2974 _new->opcode = cur_opcode + offset;
2975 _new->next = NULL;
2977 if (label) {
2978 while (label->next)
2979 label = label->next;
2981 _new->number = label->number + 1;
2982 label->next = _new;
2984 else {
2985 file->label = _new;
2986 _new->number = 1;
2989 return _new->number;
2994 =item C<void PDB_free_file(PARROT_INTERP, PDB_file_t *file)>
2996 Frees any allocated source files.
2998 =cut
3002 void
3003 PDB_free_file(SHIM_INTERP, ARGIN_NULLOK(PDB_file_t *file))
3005 ASSERT_ARGS(PDB_free_file)
3006 while (file) {
3007 /* Free all of the allocated line structures */
3008 PDB_line_t *line = file->line;
3009 PDB_label_t *label;
3010 PDB_file_t *nfile;
3012 while (line) {
3013 PDB_line_t * const nline = line->next;
3014 mem_sys_free(line);
3015 line = nline;
3018 /* Free all of the allocated label structures */
3019 label = file->label;
3021 while (label) {
3022 PDB_label_t * const nlabel = label->next;
3024 mem_sys_free(label);
3025 label = nlabel;
3028 /* Free the remaining allocated portions of the file structure */
3029 if (file->sourcefilename)
3030 mem_sys_free(file->sourcefilename);
3032 if (file->source)
3033 mem_sys_free(file->source);
3035 nfile = file->next;
3036 mem_sys_free(file);
3037 file = nfile;
3043 =item C<void PDB_load_source(PARROT_INTERP, const char *command)>
3045 Load a source code file.
3047 =cut
3051 PARROT_EXPORT
3052 void
3053 PDB_load_source(PARROT_INTERP, ARGIN(const char *command))
3055 ASSERT_ARGS(PDB_load_source)
3056 FILE *file;
3057 char f[DEBUG_CMD_BUFFER_LENGTH + 1];
3058 int i, j, c;
3059 PDB_file_t *pfile;
3060 PDB_line_t *pline;
3061 PDB_t * const pdb = interp->pdb;
3062 opcode_t *pc = interp->code->base.data;
3064 unsigned long size = 0;
3066 TRACEDEB_MSG("PDB_load_source");
3068 /* If there was a file already loaded or the bytecode was
3069 disassembled, free it */
3070 if (pdb->file) {
3071 PDB_free_file(interp->pdb->debugee, interp->pdb->debugee->pdb->file);
3072 interp->pdb->debugee->pdb->file = NULL;
3075 /* Get the name of the file */
3076 for (j = 0; command[j] == ' '; ++j)
3077 continue;
3078 for (i = 0; command[j]; i++, j++)
3079 f[i] = command[j];
3081 f[i] = '\0';
3083 /* open the file */
3084 file = fopen(f, "r");
3086 /* abort if fopen failed */
3087 if (!file) {
3088 Parrot_io_eprintf(pdb->debugger, "Unable to load '%s'\n", f);
3089 return;
3092 pfile = mem_allocate_zeroed_typed(PDB_file_t);
3093 pline = mem_allocate_zeroed_typed(PDB_line_t);
3095 pfile->source = (char *)mem_sys_allocate(1024);
3096 pfile->line = pline;
3097 pline->number = 1;
3099 PARROT_ASSERT(interp->op_info_table);
3100 PARROT_ASSERT(pc);
3102 while ((c = fgetc(file)) != EOF) {
3103 /* Grow it */
3104 if (++size == 1024) {
3105 pfile->source = (char *)mem_sys_realloc(pfile->source,
3106 (size_t)pfile->size + 1024);
3107 size = 0;
3109 pfile->source[pfile->size] = (char)c;
3111 pfile->size++;
3113 if (c == '\n') {
3114 /* If the line has an opcode move to the next one,
3115 otherwise leave it with NULL to skip it. */
3116 PDB_line_t *newline = mem_allocate_zeroed_typed(PDB_line_t);
3118 if (PDB_hasinstruction(pfile->source + pline->source_offset)) {
3119 size_t n = interp->op_info_table[*pc].op_count;
3120 pline->opcode = pc;
3121 ADD_OP_VAR_PART(interp, interp->code, pc, n);
3122 pc += n;
3124 /* don't walk off the end of the program into neverland */
3125 if (pc >= interp->code->base.data + interp->code->base.size)
3126 break;
3129 newline->number = pline->number + 1;
3130 pline->next = newline;
3131 pline = newline;
3132 pline->source_offset = pfile->size;
3133 pline->opcode = NULL;
3134 pline->label = NULL;
3138 fclose(file);
3140 pdb->state |= PDB_SRC_LOADED;
3141 pdb->file = pfile;
3143 TRACEDEB_MSG("PDB_load_source finished");
3148 =item C<char PDB_hasinstruction(const char *c)>
3150 Return true if the line has an instruction.
3152 RT #46129:
3154 =over 4
3156 =item * This should take the line, get an instruction, get the opcode for
3157 that instruction and check that is the correct one.
3159 =item * Decide what to do with macros if anything.
3161 =back
3163 =cut
3167 PARROT_WARN_UNUSED_RESULT
3168 PARROT_PURE_FUNCTION
3169 char
3170 PDB_hasinstruction(ARGIN(const char *c))
3172 ASSERT_ARGS(PDB_hasinstruction)
3173 char h = 0;
3175 /* as long as c is not NULL, we're not looking at a comment (#...) or a '\n'... */
3176 while (*c && *c != '#' && *c != '\n') {
3177 /* ... and c is alphanumeric or a quoted string then the line contains
3178 * an instruction. */
3179 if (isalnum((unsigned char) *c) || *c == '"') {
3180 h = 1;
3182 else if (*c == ':') {
3183 /* this is a label. RT #46137 right? */
3184 h = 0;
3187 c++;
3190 return h;
3195 =item C<static void no_such_register(PARROT_INTERP, char register_type, UINTVAL
3196 register_num)>
3198 Auxiliar error message function.
3200 =cut
3204 static void
3205 no_such_register(PARROT_INTERP, char register_type, UINTVAL register_num)
3207 ASSERT_ARGS(no_such_register)
3209 Parrot_io_eprintf(interp, "%c%u = no such register\n",
3210 register_type, register_num);
3215 =item C<void PDB_assign(PARROT_INTERP, const char *command)>
3217 Assign to registers.
3219 =cut
3223 void
3224 PDB_assign(PARROT_INTERP, ARGIN(const char *command))
3226 ASSERT_ARGS(PDB_assign)
3227 UINTVAL register_num;
3228 char reg_type_id;
3229 int reg_type;
3230 PDB_t *pdb = interp->pdb;
3231 Interp *debugger = pdb ? pdb->debugger : interp;
3232 Interp *debugee = pdb ? pdb->debugee : interp;
3234 /* smallest valid commad length is 4, i.e. "I0 1" */
3235 if (strlen(command) < 4) {
3236 Parrot_io_eprintf(debugger, "Must give a register number and value to assign\n");
3237 return;
3239 reg_type_id = (char) command[0];
3240 command++;
3241 register_num = get_ulong(&command, 0);
3243 switch (reg_type_id) {
3244 case 'I':
3245 reg_type = REGNO_INT;
3246 break;
3247 case 'N':
3248 reg_type = REGNO_NUM;
3249 break;
3250 case 'S':
3251 reg_type = REGNO_STR;
3252 break;
3253 case 'P':
3254 reg_type = REGNO_PMC;
3255 Parrot_io_eprintf(debugger, "Assigning to PMCs is not currently supported\n");
3256 return;
3257 default:
3258 Parrot_io_eprintf(debugger, "Invalid register type %c\n", reg_type_id);
3259 return;
3261 if (register_num >= Parrot_pcc_get_regs_used(debugee,
3262 CURRENT_CONTEXT(debugee), reg_type)) {
3263 no_such_register(debugger, reg_type_id, register_num);
3264 return;
3266 switch (reg_type) {
3267 case REGNO_INT:
3268 IREG(register_num) = get_ulong(&command, 0);
3269 break;
3270 case REGNO_NUM:
3271 NREG(register_num) = atof(command);
3272 break;
3273 case REGNO_STR:
3274 SREG(register_num) = Parrot_str_new(debugee, command, strlen(command));
3275 break;
3276 default: ; /* Must never come here */
3278 Parrot_io_eprintf(debugger, "\n %c%u = ", reg_type_id, register_num);
3279 Parrot_io_eprintf(debugger, "%s\n", GDB_print_reg(debugee, reg_type, register_num));
3284 =item C<void PDB_list(PARROT_INTERP, const char *command)>
3286 Show lines from the source code file.
3288 =cut
3292 void
3293 PDB_list(PARROT_INTERP, ARGIN(const char *command))
3295 ASSERT_ARGS(PDB_list)
3296 char *c;
3297 unsigned long line_number;
3298 unsigned long i;
3299 PDB_line_t *line;
3300 PDB_t *pdb = interp->pdb;
3301 unsigned long n = 10;
3303 TRACEDEB_MSG("PDB_list");
3304 if (!pdb->file || !pdb->file->line) {
3305 Parrot_io_eprintf(pdb->debugger, "No source file loaded\n");
3306 return;
3309 /* set the list line if provided */
3310 line_number = get_ulong(&command, 0);
3311 pdb->file->list_line = (unsigned long) line_number;
3313 /* set the number of lines to print */
3314 n = get_ulong(&command, 10);
3316 /* if n is zero, we simply return, as we don't have to print anything */
3317 if (n == 0)
3318 return;
3320 line = pdb->file->line;
3322 for (i = 0; i < pdb->file->list_line && line->next; i++)
3323 line = line->next;
3325 i = 1;
3326 while (line->next) {
3327 Parrot_io_eprintf(pdb->debugger, "%li ", pdb->file->list_line + i);
3328 /* If it has a label print it */
3329 if (line->label)
3330 Parrot_io_eprintf(pdb->debugger, "L%li:\t", line->label->number);
3332 c = pdb->file->source + line->source_offset;
3334 while (*c != '\n')
3335 Parrot_io_eprintf(pdb->debugger, "%c", *(c++));
3337 Parrot_io_eprintf(pdb->debugger, "\n");
3339 line = line->next;
3341 if (i++ == n)
3342 break;
3345 if (--i != n)
3346 pdb->file->list_line = 0;
3347 else
3348 pdb->file->list_line += n;
3353 =item C<void PDB_eval(PARROT_INTERP, const char *command)>
3355 C<eval>s an instruction.
3357 =cut
3361 void
3362 PDB_eval(PARROT_INTERP, ARGIN(const char *command))
3364 ASSERT_ARGS(PDB_eval)
3366 PDB_t *pdb = interp->pdb;
3367 Interp *warninterp = (interp->pdb && interp->pdb->debugger) ?
3368 interp->pdb->debugger : interp;
3369 TRACEDEB_MSG("PDB_eval");
3370 UNUSED(command);
3371 Parrot_io_eprintf(warninterp, "The eval command is currently unimplemeneted\n");
3376 =item C<opcode_t * PDB_compile(PARROT_INTERP, const char *command)>
3378 Compiles instructions with the PASM compiler.
3380 Appends an C<end> op.
3382 This may be called from C<PDB_eval> above or from the compile opcode
3383 which generates a malloced string.
3385 =cut
3389 PARROT_CAN_RETURN_NULL
3390 opcode_t *
3391 PDB_compile(PARROT_INTERP, ARGIN(const char *command))
3393 ASSERT_ARGS(PDB_compile)
3395 UNUSED(command);
3396 Parrot_ex_throw_from_c_args(interp, NULL,
3397 EXCEPTION_UNIMPLEMENTED,
3398 "PDB_compile ('PASM1' compiler) has been deprecated");
3403 =item C<static void dump_string(PARROT_INTERP, const STRING *s)>
3405 Dumps the buflen, flags, bufused, strlen, and offset associated with a string
3406 and the string itself.
3408 =cut
3412 static void
3413 dump_string(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
3415 ASSERT_ARGS(dump_string)
3416 if (!s)
3417 return;
3419 Parrot_io_eprintf(interp, "\tBuflen =\t%12ld\n", Buffer_buflen(s));
3420 Parrot_io_eprintf(interp, "\tFlags =\t%12ld\n", PObj_get_FLAGS(s));
3421 Parrot_io_eprintf(interp, "\tBufused =\t%12ld\n", s->bufused);
3422 Parrot_io_eprintf(interp, "\tStrlen =\t%12ld\n", s->strlen);
3423 Parrot_io_eprintf(interp, "\tOffset =\t%12ld\n",
3424 (char*) s->strstart - (char*) Buffer_bufstart(s));
3425 Parrot_io_eprintf(interp, "\tString =\t%S\n", s);
3430 =item C<void PDB_print(PARROT_INTERP, const char *command)>
3432 Print interp registers.
3434 =cut
3438 void
3439 PDB_print(PARROT_INTERP, ARGIN(const char *command))
3441 ASSERT_ARGS(PDB_print)
3442 const char * const s = GDB_P(interp->pdb->debugee, command);
3444 TRACEDEB_MSG("PDB_print");
3445 Parrot_io_eprintf(interp, "%s\n", s);
3451 =item C<void PDB_info(PARROT_INTERP)>
3453 Print the interpreter info.
3455 =cut
3459 void
3460 PDB_info(PARROT_INTERP)
3462 ASSERT_ARGS(PDB_info)
3464 /* If a debugger is created, use it for printing and use the
3465 * data in his debugee. Otherwise, use current interpreter
3466 * for both */
3467 Parrot_Interp itdeb = interp->pdb ? interp->pdb->debugger : interp;
3468 Parrot_Interp itp = interp->pdb ? interp->pdb->debugee : interp;
3470 Parrot_io_eprintf(itdeb, "Total memory allocated = %ld\n",
3471 interpinfo(itp, TOTAL_MEM_ALLOC));
3472 Parrot_io_eprintf(itdeb, "GC mark runs = %ld\n",
3473 interpinfo(itp, GC_MARK_RUNS));
3474 Parrot_io_eprintf(itdeb, "Lazy gc mark runs = %ld\n",
3475 interpinfo(itp, GC_LAZY_MARK_RUNS));
3476 Parrot_io_eprintf(itdeb, "GC collect runs = %ld\n",
3477 interpinfo(itp, GC_COLLECT_RUNS));
3478 Parrot_io_eprintf(itdeb, "Collect memory = %ld\n",
3479 interpinfo(itp, TOTAL_COPIED));
3480 Parrot_io_eprintf(itdeb, "Active PMCs = %ld\n",
3481 interpinfo(itp, ACTIVE_PMCS));
3482 Parrot_io_eprintf(itdeb, "Extended PMCs = %ld\n",
3483 interpinfo(itp, EXTENDED_PMCS));
3484 Parrot_io_eprintf(itdeb, "Timely GC PMCs = %ld\n",
3485 interpinfo(itp, IMPATIENT_PMCS));
3486 Parrot_io_eprintf(itdeb, "Total PMCs = %ld\n",
3487 interpinfo(itp, TOTAL_PMCS));
3488 Parrot_io_eprintf(itdeb, "Active buffers = %ld\n",
3489 interpinfo(itp, ACTIVE_BUFFERS));
3490 Parrot_io_eprintf(itdeb, "Total buffers = %ld\n",
3491 interpinfo(itp, TOTAL_BUFFERS));
3492 Parrot_io_eprintf(itdeb, "Header allocations since last collect = %ld\n",
3493 interpinfo(itp, HEADER_ALLOCS_SINCE_COLLECT));
3494 Parrot_io_eprintf(itdeb, "Memory allocations since last collect = %ld\n",
3495 interpinfo(itp, MEM_ALLOCS_SINCE_COLLECT));
3500 =item C<void PDB_help(PARROT_INTERP, const char *command)>
3502 Print the help text. "Help" with no arguments prints a list of commands.
3503 "Help xxx" prints information on command xxx.
3505 =cut
3509 void
3510 PDB_help(PARROT_INTERP, ARGIN(const char *command))
3512 ASSERT_ARGS(PDB_help)
3513 const DebuggerCmd *cmd;
3515 const char * cmdline = command;
3516 cmd = get_cmd(& cmdline);
3518 if (cmd) {
3519 Parrot_io_eprintf(interp->pdb->debugger, "%s\n", cmd->help);
3521 else {
3522 if (*cmdline == '\0') {
3523 unsigned int i;
3524 Parrot_io_eprintf(interp->pdb->debugger, "List of commands:\n");
3525 for (i= 0; i < sizeof (DebCmdList) / sizeof (DebuggerCmdList); ++i) {
3526 const DebuggerCmdList *cmdlist = DebCmdList + i;
3527 Parrot_io_eprintf(interp->pdb->debugger,
3528 " %-12s-- %s\n", cmdlist->name, cmdlist->cmd->shorthelp);
3530 Parrot_io_eprintf(interp->pdb->debugger, "\n"
3531 "Type \"help\" followed by a command name for full documentation.\n\n");
3534 else {
3535 Parrot_io_eprintf(interp->pdb->debugger, "Unknown command: %s\n", command);
3542 =item C<void PDB_backtrace(PARROT_INTERP)>
3544 Prints a backtrace of the interp's call chain.
3546 =cut
3550 void
3551 PDB_backtrace(PARROT_INTERP)
3553 ASSERT_ARGS(PDB_backtrace)
3554 STRING *str;
3555 PMC *old = PMCNULL;
3556 int rec_level = 0;
3558 /* information about the current sub */
3559 PMC *sub = interpinfo_p(interp, CURRENT_SUB);
3560 PMC *ctx = CURRENT_CONTEXT(interp);
3562 if (!PMC_IS_NULL(sub)) {
3563 str = Parrot_Context_infostr(interp, ctx);
3564 if (str) {
3565 Parrot_io_eprintf(interp, "%Ss", str);
3566 if (interp->code->annotations) {
3567 PMC *annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
3568 Parrot_pcc_get_pc(interp, ctx) - interp->code->base.data + 1, NULL);
3569 if (!PMC_IS_NULL(annot)) {
3570 PMC *pfile = VTABLE_get_pmc_keyed_str(interp, annot,
3571 Parrot_str_new_constant(interp, "file"));
3572 PMC *pline = VTABLE_get_pmc_keyed_str(interp, annot,
3573 Parrot_str_new_constant(interp, "line"));
3574 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
3575 STRING *file = VTABLE_get_string(interp, pfile);
3576 INTVAL line = VTABLE_get_integer(interp, pline);
3577 Parrot_io_eprintf(interp, " (%Ss:%li)", file, (long)line);
3581 Parrot_io_eprintf(interp, "\n");
3585 /* backtrace: follow the continuation chain */
3586 while (1) {
3587 Parrot_Continuation_attributes *sub_cont;
3588 sub = Parrot_pcc_get_continuation(interp, ctx);
3590 if (PMC_IS_NULL(sub))
3591 break;
3593 sub_cont = PARROT_CONTINUATION(sub);
3595 if (!sub_cont)
3596 break;
3598 str = Parrot_Context_infostr(interp, sub_cont->to_ctx);
3600 if (!str)
3601 break;
3603 /* recursion detection */
3604 if (!PMC_IS_NULL(old) && PMC_cont(old) &&
3605 Parrot_pcc_get_pc(interp, PMC_cont(old)->to_ctx) ==
3606 Parrot_pcc_get_pc(interp, PMC_cont(sub)->to_ctx) &&
3607 Parrot_pcc_get_sub(interp, PMC_cont(old)->to_ctx) ==
3608 Parrot_pcc_get_sub(interp, PMC_cont(sub)->to_ctx)) {
3609 ++rec_level;
3611 else if (rec_level != 0) {
3612 Parrot_io_eprintf(interp, "... call repeated %d times\n", rec_level);
3613 rec_level = 0;
3616 /* print the context description */
3617 if (rec_level == 0) {
3618 Parrot_io_eprintf(interp, "%Ss", str);
3619 if (interp->code->annotations) {
3620 PMC *annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
3621 Parrot_pcc_get_pc(interp, sub_cont->to_ctx) - interp->code->base.data + 1,
3622 NULL);
3624 if (!PMC_IS_NULL(annot)) {
3625 PMC *pfile = VTABLE_get_pmc_keyed_str(interp, annot,
3626 Parrot_str_new_constant(interp, "file"));
3627 PMC *pline = VTABLE_get_pmc_keyed_str(interp, annot,
3628 Parrot_str_new_constant(interp, "line"));
3629 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
3630 STRING *file = VTABLE_get_string(interp, pfile);
3631 INTVAL line = VTABLE_get_integer(interp, pline);
3632 Parrot_io_eprintf(interp, " (%Ss:%li)", file, (long)line);
3636 Parrot_io_eprintf(interp, "\n");
3639 /* get the next Continuation */
3640 ctx = PARROT_CONTINUATION(sub)->to_ctx;
3641 old = sub;
3643 if (!ctx)
3644 break;
3647 if (rec_level != 0)
3648 Parrot_io_eprintf(interp, "... call repeated %d times\n", rec_level);
3652 * GDB functions
3654 * GDB_P gdb> pp $I0 print register I0 value
3656 * RT46139 more, more
3661 =item C<static const char* GDB_print_reg(PARROT_INTERP, int t, int n)>
3663 Used by GDB_P to convert register values for display. Takes register
3664 type and number as arguments.
3666 Returns a pointer to the start of the string, (except for PMCs, which
3667 print directly and return "").
3669 =cut
3673 PARROT_WARN_UNUSED_RESULT
3674 PARROT_CANNOT_RETURN_NULL
3675 PARROT_OBSERVER
3676 static const char*
3677 GDB_print_reg(PARROT_INTERP, int t, int n)
3679 ASSERT_ARGS(GDB_print_reg)
3680 char * string;
3682 if (n >= 0 && (UINTVAL)n < Parrot_pcc_get_regs_used(interp, CURRENT_CONTEXT(interp), t)) {
3683 switch (t) {
3684 case REGNO_INT:
3685 return Parrot_str_from_int(interp, IREG(n))->strstart;
3686 case REGNO_NUM:
3687 return Parrot_str_from_num(interp, NREG(n))->strstart;
3688 case REGNO_STR:
3689 /* This hack is needed because we occasionally are told
3690 that we have string registers when we actually don't */
3691 string = (char *) SREG(n);
3693 if (string == '\0')
3694 return "";
3695 else
3696 return SREG(n)->strstart;
3697 case REGNO_PMC:
3698 /* prints directly */
3699 trace_pmc_dump(interp, PREG(n));
3700 return "";
3701 default:
3702 break;
3705 return "no such register";
3710 =item C<static const char* GDB_P(PARROT_INTERP, const char *s)>
3712 Used by PDB_print to print register values. Takes a pointer to the
3713 register name(s).
3715 Returns "" or error message.
3717 =cut
3721 PARROT_WARN_UNUSED_RESULT
3722 PARROT_CANNOT_RETURN_NULL
3723 PARROT_OBSERVER
3724 static const char*
3725 GDB_P(PARROT_INTERP, ARGIN(const char *s))
3727 ASSERT_ARGS(GDB_P)
3728 int t;
3729 char reg_type;
3731 TRACEDEB_MSG("GDB_P");
3732 /* Skip leading whitespace. */
3733 while (isspace((unsigned char)*s))
3734 s++;
3736 reg_type = (unsigned char) toupper((unsigned char)*s);
3738 switch (reg_type) {
3739 case 'I': t = REGNO_INT; break;
3740 case 'N': t = REGNO_NUM; break;
3741 case 'S': t = REGNO_STR; break;
3742 case 'P': t = REGNO_PMC; break;
3743 default: return "Need a register.";
3745 if (! s[1]) {
3746 /* Print all registers of this type. */
3747 const int max_reg = Parrot_pcc_get_regs_used(interp, CURRENT_CONTEXT(interp), t);
3748 int n;
3750 for (n = 0; n < max_reg; n++) {
3751 /* this must be done in two chunks because PMC's print directly. */
3752 Parrot_io_eprintf(interp, "\n %c%d = ", reg_type, n);
3753 Parrot_io_eprintf(interp, "%s", GDB_print_reg(interp, t, n));
3755 return "";
3757 else if (s[1] && isdigit((unsigned char)s[1])) {
3758 const int n = atoi(s + 1);
3759 return GDB_print_reg(interp, t, n);
3761 else
3762 return "no such register";
3768 =back
3770 =head1 SEE ALSO
3772 F<include/parrot/debugger.h>, F<src/parrot_debugger.c> and F<ops/debug.ops>.
3774 =head1 HISTORY
3776 =over 4
3778 =item Initial version by Daniel Grunblatt on 2002.5.19.
3780 =item Start of rewrite - leo 2005.02.16
3782 The debugger now uses its own interpreter. User code is run in
3783 Interp *debugee. We have:
3785 debug_interp->pdb->debugee->debugger
3788 +------------- := -----------+
3790 Debug commands are mostly run inside the C<debugger>. User code
3791 runs of course in the C<debugee>.
3793 =back
3795 =cut
3801 * Local variables:
3802 * c-file-style: "parrot"
3803 * End:
3804 * vim: expandtab shiftwidth=4: