Small improvements to the parrot_debugger documentation
[parrot.git] / src / debug.c
blob2994c9d927ab4c4ac7222f9edd594ca9140037ad
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
52 typedef struct DebuggerCmd DebuggerCmd;
53 typedef struct DebuggerCmdList DebuggerCmdList;
56 /* HEADERIZER HFILE: include/parrot/debugger.h */
58 /* HEADERIZER BEGIN: static */
59 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
61 static void chop_newline(ARGMOD(char * buf))
62 __attribute__nonnull__(1)
63 FUNC_MODIFIES(* buf);
65 static void close_script_file(PARROT_INTERP)
66 __attribute__nonnull__(1);
68 static unsigned short condition_regtype(ARGIN(const char *cmd))
69 __attribute__nonnull__(1);
71 PARROT_CAN_RETURN_NULL
72 static PDB_breakpoint_t * current_breakpoint(ARGIN(PDB_t * pdb))
73 __attribute__nonnull__(1);
75 static void debugger_cmdline(PARROT_INTERP)
76 __attribute__nonnull__(1);
78 static void dump_string(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
79 __attribute__nonnull__(1);
81 PARROT_WARN_UNUSED_RESULT
82 PARROT_CANNOT_RETURN_NULL
83 PARROT_OBSERVER
84 static const char* GDB_P(PARROT_INTERP, ARGIN(const char *s))
85 __attribute__nonnull__(1)
86 __attribute__nonnull__(2);
88 PARROT_WARN_UNUSED_RESULT
89 PARROT_CANNOT_RETURN_NULL
90 PARROT_OBSERVER
91 static const char* GDB_print_reg(PARROT_INTERP, int t, int n)
92 __attribute__nonnull__(1);
94 PARROT_WARN_UNUSED_RESULT
95 PARROT_CAN_RETURN_NULL
96 static const DebuggerCmd * get_cmd(ARGIN_NULLOK(const char **cmd));
98 PARROT_WARN_UNUSED_RESULT
99 static unsigned long get_uint(ARGMOD(const char **cmd), unsigned int def)
100 __attribute__nonnull__(1)
101 FUNC_MODIFIES(*cmd);
103 PARROT_WARN_UNUSED_RESULT
104 static unsigned long get_ulong(ARGMOD(const char **cmd), unsigned long def)
105 __attribute__nonnull__(1)
106 FUNC_MODIFIES(*cmd);
108 static void list_breakpoints(ARGIN(PDB_t *pdb))
109 __attribute__nonnull__(1);
111 PARROT_CAN_RETURN_NULL
112 PARROT_WARN_UNUSED_RESULT
113 static const char * nextarg(ARGIN_NULLOK(const char *command));
115 PARROT_CANNOT_RETURN_NULL
116 PARROT_WARN_UNUSED_RESULT
117 static const char * parse_int(ARGIN(const char *str), ARGOUT(int *intP))
118 __attribute__nonnull__(1)
119 __attribute__nonnull__(2)
120 FUNC_MODIFIES(*intP);
122 PARROT_CAN_RETURN_NULL
123 PARROT_WARN_UNUSED_RESULT
124 static const char* parse_key(PARROT_INTERP,
125 ARGIN(const char *str),
126 ARGOUT(PMC **keyP))
127 __attribute__nonnull__(1)
128 __attribute__nonnull__(2)
129 __attribute__nonnull__(3)
130 FUNC_MODIFIES(*keyP);
132 PARROT_CAN_RETURN_NULL
133 PARROT_WARN_UNUSED_RESULT
134 static const char * parse_string(PARROT_INTERP,
135 ARGIN(const char *str),
136 ARGOUT(STRING **strP))
137 __attribute__nonnull__(1)
138 __attribute__nonnull__(2)
139 __attribute__nonnull__(3)
140 FUNC_MODIFIES(*strP);
142 PARROT_CANNOT_RETURN_NULL
143 static const char * skip_command(ARGIN(const char *str))
144 __attribute__nonnull__(1);
146 PARROT_WARN_UNUSED_RESULT
147 PARROT_CANNOT_RETURN_NULL
148 static const char * skip_whitespace(ARGIN(const char *cmd))
149 __attribute__nonnull__(1);
151 #define ASSERT_ARGS_chop_newline __attribute__unused__ int _ASSERT_ARGS_CHECK = \
152 PARROT_ASSERT_ARG(buf)
153 #define ASSERT_ARGS_close_script_file __attribute__unused__ int _ASSERT_ARGS_CHECK = \
154 PARROT_ASSERT_ARG(interp)
155 #define ASSERT_ARGS_condition_regtype __attribute__unused__ int _ASSERT_ARGS_CHECK = \
156 PARROT_ASSERT_ARG(cmd)
157 #define ASSERT_ARGS_current_breakpoint __attribute__unused__ int _ASSERT_ARGS_CHECK = \
158 PARROT_ASSERT_ARG(pdb)
159 #define ASSERT_ARGS_debugger_cmdline __attribute__unused__ int _ASSERT_ARGS_CHECK = \
160 PARROT_ASSERT_ARG(interp)
161 #define ASSERT_ARGS_dump_string __attribute__unused__ int _ASSERT_ARGS_CHECK = \
162 PARROT_ASSERT_ARG(interp)
163 #define ASSERT_ARGS_GDB_P __attribute__unused__ int _ASSERT_ARGS_CHECK = \
164 PARROT_ASSERT_ARG(interp) \
165 || PARROT_ASSERT_ARG(s)
166 #define ASSERT_ARGS_GDB_print_reg __attribute__unused__ int _ASSERT_ARGS_CHECK = \
167 PARROT_ASSERT_ARG(interp)
168 #define ASSERT_ARGS_get_cmd __attribute__unused__ int _ASSERT_ARGS_CHECK = 0
169 #define ASSERT_ARGS_get_uint __attribute__unused__ int _ASSERT_ARGS_CHECK = \
170 PARROT_ASSERT_ARG(cmd)
171 #define ASSERT_ARGS_get_ulong __attribute__unused__ int _ASSERT_ARGS_CHECK = \
172 PARROT_ASSERT_ARG(cmd)
173 #define ASSERT_ARGS_list_breakpoints __attribute__unused__ int _ASSERT_ARGS_CHECK = \
174 PARROT_ASSERT_ARG(pdb)
175 #define ASSERT_ARGS_nextarg __attribute__unused__ int _ASSERT_ARGS_CHECK = 0
176 #define ASSERT_ARGS_parse_int __attribute__unused__ int _ASSERT_ARGS_CHECK = \
177 PARROT_ASSERT_ARG(str) \
178 || PARROT_ASSERT_ARG(intP)
179 #define ASSERT_ARGS_parse_key __attribute__unused__ int _ASSERT_ARGS_CHECK = \
180 PARROT_ASSERT_ARG(interp) \
181 || PARROT_ASSERT_ARG(str) \
182 || PARROT_ASSERT_ARG(keyP)
183 #define ASSERT_ARGS_parse_string __attribute__unused__ int _ASSERT_ARGS_CHECK = \
184 PARROT_ASSERT_ARG(interp) \
185 || PARROT_ASSERT_ARG(str) \
186 || PARROT_ASSERT_ARG(strP)
187 #define ASSERT_ARGS_skip_command __attribute__unused__ int _ASSERT_ARGS_CHECK = \
188 PARROT_ASSERT_ARG(str)
189 #define ASSERT_ARGS_skip_whitespace __attribute__unused__ int _ASSERT_ARGS_CHECK = \
190 PARROT_ASSERT_ARG(cmd)
191 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
192 /* HEADERIZER END: static */
195 * Command functions and help dispatch
198 typedef void (* debugger_func_t)(PDB_t * pdb, const char * cmd);
200 static int nomoreargs(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
202 if (*skip_whitespace(cmd) == '\0')
203 return 1;
204 else {
205 Parrot_eprintf(pdb->debugger, "Spurious arg\n");
206 return 0;
210 static void dbg_break(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
212 TRACEDEB_MSG("dbg_break");
214 PDB_set_break(pdb->debugee, cmd);
217 static void dbg_continue(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
219 TRACEDEB_MSG("dbg_continue");
221 PDB_continue(pdb->debugee, cmd);
224 static void dbg_delete(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
226 TRACEDEB_MSG("dbg_delete");
228 PDB_delete_breakpoint(pdb->debugee, cmd);
231 static void dbg_disable(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
233 TRACEDEB_MSG("dbg_disable");
235 PDB_disable_breakpoint(pdb->debugee, cmd);
238 static void dbg_disassemble(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
240 TRACEDEB_MSG("dbg_disassemble");
242 PDB_disassemble(pdb->debugee, cmd);
245 static void dbg_echo(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
247 TRACEDEB_MSG("dbg_echo");
249 if (! nomoreargs(pdb, cmd))
250 return;
252 if (pdb->state & PDB_ECHO) {
253 TRACEDEB_MSG("Disabling echo");
254 pdb->state &= ~PDB_ECHO;
256 else {
257 TRACEDEB_MSG("Enabling echo");
258 pdb->state |= PDB_ECHO;
262 static void dbg_enable(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
264 PDB_enable_breakpoint(pdb->debugee, cmd);
267 static void dbg_eval(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
269 PDB_eval(pdb->debugee, cmd);
272 static void dbg_gcdebug(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
274 TRACEDEB_MSG("dbg_gcdebug");
276 if (! nomoreargs(pdb, cmd))
277 return;
279 if (pdb->state & PDB_GCDEBUG) {
280 TRACEDEB_MSG("Disabling gcdebug mode");
281 pdb->state &= ~PDB_GCDEBUG;
283 else {
284 TRACEDEB_MSG("Enabling gcdebug mode");
285 pdb->state |= PDB_GCDEBUG;
289 static void dbg_help(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
291 TRACEDEB_MSG("dbg_help");
293 PDB_help(pdb->debugee, cmd);
296 static void dbg_info(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
298 TRACEDEB_MSG("dbg_info");
300 if (! nomoreargs(pdb, cmd))
301 return;
303 PDB_info(pdb->debugger);
306 static void dbg_list(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
308 TRACEDEB_MSG("dbg_list");
310 PDB_list(pdb->debugee, cmd);
313 static void dbg_listbreakpoints(PDB_t * pdb, SHIM(const char * cmd)) /* HEADERIZER SKIP */
315 TRACEDEB_MSG("dbg_list");
317 list_breakpoints(pdb);
320 static void dbg_load(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
322 TRACEDEB_MSG("dbg_load");
324 PDB_load_source(pdb->debugee, cmd);
327 static void dbg_next(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
329 TRACEDEB_MSG("dbg_next");
331 PDB_next(pdb->debugee, cmd);
334 static void dbg_print(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
336 TRACEDEB_MSG("dbg_print");
338 PDB_print(pdb->debugee, cmd);
341 static void dbg_quit(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
343 TRACEDEB_MSG("dbg_quit");
345 if (! nomoreargs(pdb, cmd))
346 return;
348 pdb->state |= PDB_EXIT;
349 pdb->state &= ~PDB_STOPPED;
352 static void dbg_run(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
354 TRACEDEB_MSG("dbg_run");
356 PDB_init(pdb->debugee, cmd);
357 PDB_continue(pdb->debugee, NULL);
360 static void dbg_script(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
362 TRACEDEB_MSG("dbg_script");
364 PDB_script_file(pdb->debugee, cmd);
367 static void dbg_stack(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
369 TRACEDEB_MSG("dbg_stack");
371 if (! nomoreargs(pdb, cmd))
372 return;
374 PDB_backtrace(pdb->debugee);
377 static void dbg_trace(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
379 TRACEDEB_MSG("dbg_trace");
381 PDB_trace(pdb->debugee, cmd);
384 static void dbg_watch(PDB_t * pdb, const char * cmd) /* HEADERIZER SKIP */
386 TRACEDEB_MSG("dbg_watch");
388 PDB_watchpoint(pdb->debugee, cmd);
391 struct DebuggerCmd {
392 debugger_func_t func;
393 PARROT_OBSERVER const char * const shorthelp;
394 PARROT_OBSERVER const char * const help;
397 static const DebuggerCmd
398 cmd_break = {
399 & dbg_break,
400 "add a breakpoint",
401 "Set a breakpoint at a given line number (which must be specified).\n\n\
402 Optionally, specify a condition, in which case the breakpoint will only\n\
403 activate if the condition is met. Conditions take the form:\n\n\
404 if [REGISTER] [COMPARISON] [REGISTER or CONSTANT]\n\n\
406 For example:\n\n\
407 break 10 if I4 > I3\n\n\
408 break 45 if S1 == \"foo\"\n\n\
409 The command returns a number which is the breakpoint identifier."
411 cmd_continue = {
412 & dbg_continue,
413 "continue the program execution",
414 "Continue the program execution.\n\n\
415 Without arguments, the program runs until a breakpoint is found\n\
416 (or until the program terminates for some other reason).\n\n\
417 If a number is specified, then skip that many breakpoints.\n\n\
418 If the program has terminated, then \"continue\" will do nothing;\n\
419 use \"run\" to re-run the program."
421 cmd_delete = {
422 & dbg_delete,
423 "delete a breakpoint",
424 "Delete a breakpoint.\n\n\
425 The breakpoint to delete must be specified by its breakpoint number.\n\
426 Deleted breakpoints are gone completely. If instead you want to\n\
427 temporarily disable a breakpoint, use \"disable\"."
429 cmd_disable = {
430 & dbg_disable,
431 "disable a breakpoint",
432 "Disable a breakpoint.\n\n\
433 The breakpoint to disable must be specified by its breakpoint number.\n\
434 Disabled breakpoints are not forgotten, but have no effect until re-enabled\n\
435 with the \"enable\" command."
437 cmd_disassemble = {
438 & dbg_disassemble,
439 "disassemble the bytecode",
440 "Disassemble code"
442 cmd_echo = {
443 & dbg_echo,
444 "toggle echo of script commands",
445 "Toggle echo mode.\n\n\
446 In echo mode the script commands are written to stderr before executing."
448 cmd_enable = {
449 & dbg_enable,
450 "reenable a disabled breakpoint",
451 "Re-enable a disabled breakpoint."
453 cmd_eval = {
454 & dbg_eval,
455 "run an instruction",
456 "No documentation yet"
458 cmd_gcdebug = {
459 & dbg_gcdebug,
460 "toggle gcdebug mode",
461 "Toggle gcdebug mode.\n\n\
462 In gcdebug mode a garbage collection cycle is run before each opcocde,\n\
463 same as using the gcdebug core."
465 cmd_help = {
466 & dbg_help,
467 "print this help",
468 "Print a list of available commands."
470 cmd_info = {
471 & dbg_info,
472 "print interpreter information",
473 "Print information about the current interpreter"
475 cmd_list = {
476 & dbg_list,
477 "list the source code file",
478 "List the source code.\n\n\
479 Optionally specify the line number to begin the listing from and the number\n\
480 of lines to display."
482 cmd_listbreakpoints = {
483 & dbg_listbreakpoints,
484 "list breakpoints",
485 "List breakpoints."
487 cmd_load = {
488 & dbg_load,
489 "load a source code file",
490 "Load a source code file."
492 cmd_next = {
493 & dbg_next,
494 "run the next instruction",
495 "Execute a specified number of instructions.\n\n\
496 If a number is specified with the command (e.g. \"next 5\"), then\n\
497 execute that number of instructions, unless the program reaches a\n\
498 breakpoint, or stops for some other reason.\n\n\
499 If no number is specified, it defaults to 1."
501 cmd_print = {
502 & dbg_print,
503 "print the interpreter registers",
504 "Print register: e.g. \"p i2\"\n\
505 Note that the register type is case-insensitive. If no digits appear\n\
506 after the register type, all registers of that type are printed."
508 cmd_quit = {
509 & dbg_quit,
510 "exit the debugger",
511 "Exit the debugger"
513 cmd_run = {
514 & dbg_run,
515 "run the program",
516 "Run (or restart) the program being debugged.\n\n\
517 Arguments specified after \"run\" are passed as command line arguments to\n\
518 the program.\n"
520 cmd_script = {
521 & dbg_script,
522 "interprets a file as user commands",
523 "Interprets a file s user commands.\n\
524 Usage:\n\
525 (pdb) script file.script"
527 cmd_stack = {
528 & dbg_stack,
529 "examine the stack",
530 "Print a stack trace of the parrot VM"
532 cmd_trace = {
533 & dbg_trace,
534 "trace the next instruction",
535 "Similar to \"next\", but prints additional trace information.\n\
536 This is the same as the information you get when running Parrot with\n\
537 the -t option.\n"
539 cmd_watch = {
540 & dbg_watch,
541 "add a watchpoint",
542 "Add a watchpoint"
545 struct DebuggerCmdList {
546 PARROT_OBSERVER const char * const name;
547 char shortname;
548 PARROT_OBSERVER const DebuggerCmd * const cmd;
551 DebuggerCmdList DebCmdList [] = {
552 { "break", '\0', &cmd_break },
553 { "continue", '\0', &cmd_continue },
554 { "delete", 'd', &cmd_delete },
555 { "disable", '\0', &cmd_disable },
556 { "disassemble", '\0', &cmd_disassemble },
557 { "e", '\0', &cmd_eval },
558 { "echo", '\0', &cmd_echo },
559 { "enable", '\0', &cmd_enable },
560 { "eval", '\0', &cmd_eval },
561 { "f", '\0', &cmd_script },
562 { "gcdebug", '\0', &cmd_gcdebug },
563 { "help", '\0', &cmd_help },
564 { "info", '\0', &cmd_info },
565 { "L", '\0', &cmd_listbreakpoints },
566 { "list", 'l', &cmd_list },
567 { "load", '\0', &cmd_load },
568 { "next", '\0', &cmd_next },
569 { "print", '\0', &cmd_print },
570 { "quit", '\0', &cmd_quit },
571 { "run", '\0', &cmd_run },
572 { "script", '\0', &cmd_script },
573 { "stack", 's', &cmd_stack },
574 { "trace", '\0', &cmd_trace },
575 { "watch", '\0', &cmd_watch }
580 =item C<static const DebuggerCmd * get_cmd(const char **cmd)>
582 =cut
586 PARROT_WARN_UNUSED_RESULT
587 PARROT_CAN_RETURN_NULL
588 static const DebuggerCmd *
589 get_cmd(ARGIN_NULLOK(const char **cmd))
591 ASSERT_ARGS(get_cmd)
592 if (cmd && *cmd) {
593 const char * const start = skip_whitespace(*cmd);
594 const char *next = start;
595 char c;
596 unsigned int i, l;
597 int found = -1;
598 int hits = 0;
600 *cmd = start;
601 for (; (c= *next) != '\0' && !isspace((unsigned char)c); ++next)
602 continue;
603 l = next - start;
604 if (l == 0)
605 return NULL;
606 for (i= 0; i < sizeof (DebCmdList) / sizeof (DebuggerCmdList); ++i) {
607 const DebuggerCmdList * const cmdlist = DebCmdList + i;
608 if (l == 1 && cmdlist->shortname == (*cmd)[0]) {
609 hits = 1;
610 found = i;
611 break;
613 if (strncmp(*cmd, cmdlist->name, l) == 0) {
614 if (strlen(cmdlist->name) == l) {
615 hits = 1;
616 found = i;
617 break;
619 else {
620 ++hits;
621 found = i;
625 if (hits == 1) {
626 *cmd = skip_whitespace(next);
627 return DebCmdList[found].cmd;
630 return NULL;
635 =item C<static const char * skip_whitespace(const char *cmd)>
637 =cut
641 PARROT_WARN_UNUSED_RESULT
642 PARROT_CANNOT_RETURN_NULL
643 static const char *
644 skip_whitespace(ARGIN(const char *cmd))
646 ASSERT_ARGS(skip_whitespace)
647 while (*cmd && isspace((unsigned char)*cmd))
648 ++cmd;
649 return cmd;
654 =item C<static unsigned long get_uint(const char **cmd, unsigned int def)>
656 =cut
661 PARROT_WARN_UNUSED_RESULT
662 static unsigned long
663 get_uint(ARGMOD(const char **cmd), unsigned int def)
665 ASSERT_ARGS(get_uint)
666 char *cmdnext;
667 unsigned int result = strtoul(skip_whitespace(* cmd), & cmdnext, 0);
668 if (cmdnext != *cmd)
669 *cmd = cmdnext;
670 else
671 result = def;
672 return result;
677 =item C<static unsigned long get_ulong(const char **cmd, unsigned long def)>
679 =cut
684 PARROT_WARN_UNUSED_RESULT
685 static unsigned long
686 get_ulong(ARGMOD(const char **cmd), unsigned long def)
688 ASSERT_ARGS(get_ulong)
689 char *cmdnext;
690 unsigned long result = strtoul(skip_whitespace(* cmd), & cmdnext, 0);
691 if (cmdnext != * cmd)
692 * cmd = cmdnext;
693 else
694 result = def;
695 return result;
700 =item C<static void chop_newline(char * buf)>
702 If the C string argument end with a newline, delete it.
704 =cut
708 static void
709 chop_newline(ARGMOD(char * buf))
711 ASSERT_ARGS(chop_newline)
712 size_t l;
713 l = strlen(buf);
714 if (l > 0 && buf [l - 1] == '\n')
715 buf [l - 1] = '\0';
720 =item C<static const char * nextarg(const char *command)>
722 Returns the position just past the current argument in the PASM instruction
723 C<command>. This is not the same as C<skip_command()>, which is intended for
724 debugger commands. This function is used for C<eval>.
726 =cut
730 PARROT_CAN_RETURN_NULL
731 PARROT_WARN_UNUSED_RESULT
732 static const char *
733 nextarg(ARGIN_NULLOK(const char *command))
735 ASSERT_ARGS(nextarg)
736 /* as long as the character pointed to by command is not NULL,
737 * and it is either alphanumeric, a comma or a closing bracket,
738 * continue looking for the next argument.
740 if (command) {
741 while (isalnum((unsigned char) *command) || *command == ',' || *command == ']')
742 command++;
744 /* eat as much space as possible */
745 command = skip_whitespace(command);
748 return command;
753 =item C<static const char * skip_command(const char *str)>
755 Returns the pointer past the current debugger command. (This is an
756 alternative to the C<skip_command()> macro above.)
758 =cut
762 PARROT_CANNOT_RETURN_NULL
763 static const char *
764 skip_command(ARGIN(const char *str))
766 ASSERT_ARGS(skip_command)
767 /* while str is not null and it contains a command (no spaces),
768 * skip the character
770 while (*str && !isspace((unsigned char) *str))
771 str++;
773 /* eat all space after that */
774 return skip_whitespace(str);
779 =item C<static const char * parse_int(const char *str, int *intP)>
781 Parse an C<int> out of a string and return a pointer to just after the C<int>.
782 The output parameter C<intP> contains the parsed value.
784 =cut
788 PARROT_CANNOT_RETURN_NULL
789 PARROT_WARN_UNUSED_RESULT
790 static const char *
791 parse_int(ARGIN(const char *str), ARGOUT(int *intP))
793 ASSERT_ARGS(parse_int)
794 char *end;
796 *intP = strtol(str, &end, 0);
798 return end;
803 =item C<static const char * parse_string(PARROT_INTERP, const char *str, STRING
804 **strP)>
806 Parse a double-quoted string out of a C string and return a pointer to
807 just after the string. The parsed string is converted to a Parrot
808 C<STRING> and placed in the output parameter C<strP>.
810 =cut
814 PARROT_CAN_RETURN_NULL
815 PARROT_WARN_UNUSED_RESULT
816 static const char *
817 parse_string(PARROT_INTERP, ARGIN(const char *str), ARGOUT(STRING **strP))
819 ASSERT_ARGS(parse_string)
820 const char *string_start;
822 /* if this is not a quoted string, there's nothing to parse */
823 if (*str != '"')
824 return NULL;
826 /* skip the quote */
827 str++;
829 string_start = str;
831 /* parse while there's no closing quote */
832 while (*str && *str != '"') {
833 /* skip any potentially escaped quotes */
834 if (*str == '\\' && str[1])
835 str += 2;
836 else
837 str++;
840 /* create the output STRING */
841 *strP = string_make(interp, string_start, (UINTVAL)(str - string_start),
842 NULL, 0);
844 /* skip the closing quote */
845 if (*str)
846 str++;
848 return str;
853 =item C<static const char* parse_key(PARROT_INTERP, const char *str, PMC
854 **keyP)>
856 Parse an aggregate key out of a string and return a pointer to just
857 after the key. Currently only string and integer keys are allowed.
859 =cut
863 PARROT_CAN_RETURN_NULL
864 PARROT_WARN_UNUSED_RESULT
865 static const char*
866 parse_key(PARROT_INTERP, ARGIN(const char *str), ARGOUT(PMC **keyP))
868 ASSERT_ARGS(parse_key)
869 /* clear output parameter */
870 *keyP = NULL;
872 /* make sure it's a key */
873 if (*str != '[')
874 return NULL;
876 /* Skip [ */
877 str++;
879 /* if this is a string key, create a Parrot STRING */
880 if (*str == '"') {
881 STRING *parrot_string;
882 str = parse_string(interp, str, &parrot_string);
883 *keyP = key_new_string(interp, parrot_string);
885 /* if this is a numeric key */
886 else if (isdigit((unsigned char) *str)) {
887 int value;
888 str = parse_int(str, &value);
889 *keyP = key_new_integer(interp, (INTVAL) value);
891 /* unsupported case; neither a string nor a numeric key */
892 else {
893 return NULL;
896 /* hm, but if this doesn't match, it's probably an error */
897 /* XXX str can be NULL from parse_string() */
898 if (*str != ']')
899 return NULL;
901 /* skip the closing brace on the key */
902 return ++str;
907 =item C<static void debugger_cmdline(PARROT_INTERP)>
909 Debugger command line.
911 Gets and executes commands, looping until the debugger state
912 is changed, either to exit or to start executing code.
914 =cut
918 static void
919 debugger_cmdline(PARROT_INTERP)
921 ASSERT_ARGS(debugger_cmdline)
922 TRACEDEB_MSG("debugger_cmdline");
924 /*while (!(interp->pdb->state & PDB_EXIT)) {*/
925 while (interp->pdb->state & PDB_STOPPED) {
926 const char * command;
927 interp->pdb->state &= ~PDB_TRACING;
928 PDB_get_command(interp);
929 command = interp->pdb->cur_command;
930 if (command[0] == '\0')
931 command = interp->pdb->last_command;
933 PDB_run_command(interp, command);
935 TRACEDEB_MSG("debugger_cmdline finished");
940 =item C<static void close_script_file(PARROT_INTERP)>
942 Close the script file, returning to command prompt mode.
944 =cut
948 static void
949 close_script_file(PARROT_INTERP)
951 ASSERT_ARGS(close_script_file)
952 TRACEDEB_MSG("Closing debugger script file");
953 if (interp->pdb->script_file) {
954 fclose(interp->pdb->script_file);
955 interp->pdb->script_file = NULL;
956 interp->pdb->state|= PDB_STOPPED;
957 interp->pdb->last_command[0] = '\0';
958 interp->pdb->cur_command[0] = '\0';
964 =item C<void Parrot_debugger_init(PARROT_INTERP)>
966 Initializes the Parrot debugger, if it's not already initialized.
968 =cut
972 PARROT_EXPORT
973 void
974 Parrot_debugger_init(PARROT_INTERP)
976 ASSERT_ARGS(Parrot_debugger_init)
977 TRACEDEB_MSG("Parrot_debugger_init");
979 if (! interp->pdb) {
980 PDB_t *pdb = mem_allocate_zeroed_typed(PDB_t);
981 Parrot_Interp debugger = Parrot_new(interp);
982 interp->pdb = pdb;
983 debugger->pdb = pdb;
984 pdb->debugee = interp;
985 pdb->debugger = debugger;
987 /* Allocate space for command line buffers, NUL terminated c strings */
988 pdb->cur_command = (char *)mem_sys_allocate_zeroed(DEBUG_CMD_BUFFER_LENGTH + 1);
989 pdb->last_command = (char *)mem_sys_allocate_zeroed(DEBUG_CMD_BUFFER_LENGTH + 1);
990 pdb->file = mem_allocate_zeroed_typed(PDB_file_t);
993 /* PDB_disassemble(interp, NULL); */
995 interp->pdb->state |= PDB_RUNNING;
1000 =item C<void Parrot_debugger_destroy(PARROT_INTERP)>
1002 Destroy the current Parrot debugger instance.
1004 =cut
1008 PARROT_EXPORT
1009 void
1010 Parrot_debugger_destroy(PARROT_INTERP)
1012 ASSERT_ARGS(Parrot_debugger_destroy)
1013 /* Unfinished.
1014 Free all debugger allocated resources.
1016 PDB_t *pdb = interp->pdb;
1018 TRACEDEB_MSG("Parrot_debugger_destroy");
1020 PARROT_ASSERT(pdb);
1021 PARROT_ASSERT(pdb->debugee == interp);
1023 mem_sys_free(pdb->last_command);
1024 mem_sys_free(pdb->cur_command);
1026 mem_sys_free(pdb);
1027 interp->pdb = NULL;
1032 =item C<void Parrot_debugger_load(PARROT_INTERP, STRING *filename)>
1034 Loads a Parrot source file for the current program.
1036 =cut
1040 PARROT_EXPORT
1041 void
1042 Parrot_debugger_load(PARROT_INTERP, ARGIN_NULLOK(STRING *filename))
1044 ASSERT_ARGS(Parrot_debugger_load)
1045 char *file;
1047 TRACEDEB_MSG("Parrot_debugger_load");
1049 if (!interp->pdb)
1050 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1052 file = Parrot_str_to_cstring(interp, filename);
1053 PDB_load_source(interp, file);
1054 Parrot_str_free_cstring(file);
1059 =item C<void Parrot_debugger_start(PARROT_INTERP, opcode_t * cur_opcode)>
1061 Start debugger.
1063 =cut
1067 PARROT_EXPORT
1068 void
1069 Parrot_debugger_start(PARROT_INTERP, ARGIN(opcode_t * cur_opcode))
1071 ASSERT_ARGS(Parrot_debugger_start)
1072 TRACEDEB_MSG("Parrot_debugger_start");
1074 if (!interp->pdb)
1075 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1077 interp->pdb->cur_opcode = interp->code->base.data;
1079 if (interp->pdb->state & PDB_ENTER) {
1080 if (!interp->pdb->file) {
1081 /* PDB_disassemble(interp, NULL); */
1083 interp->pdb->state &= ~PDB_ENTER;
1086 interp->pdb->cur_opcode = cur_opcode;
1088 interp->pdb->state |= PDB_STOPPED;
1090 debugger_cmdline(interp);
1092 if (interp->pdb->state & PDB_EXIT) {
1093 TRACEDEB_MSG("Parrot_debugger_start Parrot_exit");
1094 Parrot_exit(interp, 0);
1096 TRACEDEB_MSG("Parrot_debugger_start ends");
1101 =item C<void Parrot_debugger_break(PARROT_INTERP, opcode_t * cur_opcode)>
1103 Breaks execution and drops into the debugger. If we are already into the
1104 debugger and it is the first call, set a breakpoint.
1106 When you re run/continue the program being debugged it will pay no attention to
1107 the debug ops.
1109 RT #42377: clone the interpreter to allow people to play into the
1110 debugger and then continue the normal execution of the program.
1112 =cut
1116 PARROT_EXPORT
1117 void
1118 Parrot_debugger_break(PARROT_INTERP, ARGIN(opcode_t * cur_opcode))
1120 ASSERT_ARGS(Parrot_debugger_break)
1121 TRACEDEB_MSG("Parrot_debugger_break");
1123 if (!interp->pdb)
1124 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No debugger");
1126 if (!interp->pdb->file)
1127 Parrot_ex_throw_from_c_args(interp, NULL, 0, "No file loaded to debug");
1129 if (!(interp->pdb->state & PDB_BREAK)) {
1130 TRACEDEB_MSG("Parrot_debugger_break - in BREAK state");
1131 new_runloop_jump_point(interp);
1132 if (setjmp(interp->current_runloop->resume)) {
1133 fprintf(stderr, "Unhandled exception in debugger\n");
1134 return;
1137 interp->pdb->state |= PDB_BREAK;
1138 interp->pdb->state |= PDB_STOPPED;
1139 interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
1141 /*PDB_set_break(interp, NULL);*/
1143 debugger_cmdline(interp);
1145 /* RT #42378 this is not ok */
1146 /* exit(EXIT_SUCCESS); */
1148 else {
1149 interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
1150 /*PDB_set_break(interp, NULL);*/
1152 TRACEDEB_MSG("Parrot_debugger_break done");
1157 =item C<void PDB_get_command(PARROT_INTERP)>
1159 Get a command from the user input to execute.
1161 It saves the last command executed (in C<< pdb->last_command >>), so it
1162 first frees the old one and updates it with the current one.
1164 Also prints the next line to run if the program is still active.
1166 The user input can't be longer than DEBUG_CMD_BUFFER_LENGTH characters.
1168 The input is saved in C<< pdb->cur_command >>.
1170 =cut
1174 void
1175 PDB_get_command(PARROT_INTERP)
1177 ASSERT_ARGS(PDB_get_command)
1178 unsigned int i;
1179 int ch;
1180 char *c;
1181 PDB_t * const pdb = interp->pdb;
1183 /***********************************
1184 **** Testing ****
1185 Do not delete yet
1186 the commented out
1187 parts
1188 ***********************************/
1190 /* flush the buffered data */
1191 fflush(stdout);
1193 TRACEDEB_MSG("PDB_get_command");
1195 PARROT_ASSERT(pdb->last_command);
1196 PARROT_ASSERT(pdb->cur_command);
1198 if (interp->pdb->script_file) {
1199 FILE *fd = interp->pdb->script_file;
1200 char buf[DEBUG_CMD_BUFFER_LENGTH+1];
1201 const char *ptr;
1203 do {
1204 if (fgets(buf, DEBUG_CMD_BUFFER_LENGTH, fd) == NULL) {
1205 close_script_file(interp);
1206 return;
1208 ++pdb->script_line;
1209 chop_newline(buf);
1210 #if TRACE_DEBUGGER
1211 fprintf(stderr, "script (%lu): '%s'\n", pdb->script_line, buf);
1212 #endif
1214 /* skip spaces */
1215 ptr = skip_whitespace(buf);
1217 /* skip blank and commented lines */
1218 } while (*ptr == '\0' || *ptr == '#');
1220 if (pdb->state & PDB_ECHO)
1221 Parrot_eprintf(pdb->debugger, "[%lu %s]\n", pdb->script_line, buf);
1223 #if TRACE_DEBUGGER
1224 fprintf(stderr, "(script) %s\n", buf);
1225 #endif
1227 strcpy(pdb->cur_command, buf);
1229 else {
1231 /* update the last command */
1232 if (pdb->cur_command[0] != '\0')
1233 strcpy(pdb->last_command, pdb->cur_command);
1235 i = 0;
1237 c = pdb->cur_command;
1239 /*Parrot_io_eprintf(pdb->debugger, "\n(pdb) ");*/
1240 Parrot_io_eprintf(pdb->debugger, "\n");
1242 /* skip leading whitespace */
1244 do {
1245 ch = fgetc(stdin);
1246 } while (isspace((unsigned char)ch) && ch != '\n');
1249 Interp * interpdeb = interp->pdb->debugger;
1250 STRING * readline = CONST_STRING(interpdeb, "readline_interactive");
1251 STRING * prompt = CONST_STRING(interpdeb, "(pdb) ");
1252 STRING *s= Parrot_str_new(interpdeb, NULL, 0);
1253 PMC *tmp_stdin = Parrot_io_stdhandle(interpdeb, 0, NULL);
1255 Parrot_PCCINVOKE(interpdeb,
1256 tmp_stdin, readline,
1257 "S->S", prompt, & s);
1259 char * aux = Parrot_str_to_cstring(interpdeb, s);
1260 strcpy(c, aux);
1261 Parrot_str_free_cstring(aux);
1263 ch = '\n';
1266 /* generate string (no more than buffer length) */
1268 while (ch != EOF && ch != '\n' && (i < DEBUG_CMD_BUFFER_LENGTH)) {
1269 c[i++] = (char)ch;
1270 ch = fgetc(tmp_stdin);
1273 c[i] = '\0';
1275 if (ch == -1)
1276 strcpy(c, "quit");
1282 =item C<void PDB_script_file(PARROT_INTERP, const char *command)>
1284 Interprets the contents of a file as user input commands
1286 =cut
1290 PARROT_EXPORT
1291 void
1292 PDB_script_file(PARROT_INTERP, ARGIN(const char *command))
1294 ASSERT_ARGS(PDB_script_file)
1295 FILE *fd;
1297 TRACEDEB_MSG("PDB_script_file");
1299 /* If already executing a script, close it */
1300 close_script_file(interp);
1302 TRACEDEB_MSG("Opening debugger script file");
1304 fd = fopen(command, "r");
1305 if (!fd) {
1306 Parrot_io_eprintf(interp->pdb->debugger,
1307 "Error reading script file %s.\n",
1308 command);
1309 return;
1311 interp->pdb->script_file = fd;
1312 interp->pdb->script_line = 0;
1313 TRACEDEB_MSG("PDB_script_file finished");
1318 =item C<int PDB_run_command(PARROT_INTERP, const char *command)>
1320 Run a command.
1322 Hash the command to make a simple switch calling the correct handler.
1324 =cut
1328 PARROT_IGNORABLE_RESULT
1330 PDB_run_command(PARROT_INTERP, ARGIN(const char *command))
1332 ASSERT_ARGS(PDB_run_command)
1333 PDB_t * const pdb = interp->pdb;
1334 const DebuggerCmd *cmd;
1336 /* keep a pointer to the command, in case we need to report an error */
1338 const char * cmdline = command;
1340 TRACEDEB_MSG("PDB_run_command");
1341 cmd = get_cmd(& cmdline);
1343 if (cmd) {
1344 (* cmd->func)(pdb, cmdline);
1345 return 0;
1347 else {
1348 if (*cmdline == '\0') {
1349 return 0;
1351 else {
1352 Parrot_io_eprintf(pdb->debugger,
1353 "Undefined command: \"%s\"", command);
1354 if (pdb->script_file)
1355 Parrot_io_eprintf(pdb->debugger, " in line %lu", pdb->script_line);
1356 Parrot_io_eprintf(pdb->debugger, ". Try \"help\".");
1357 #if TRACE_DEBUGGER
1358 fprintf(stderr, " (parse_command result: %li)", c);
1359 #endif
1360 close_script_file(interp);
1361 return 1;
1368 =item C<void PDB_next(PARROT_INTERP, const char *command)>
1370 Execute the next N operation(s).
1372 Inits the program if needed, runs the next N >= 1 operations and stops.
1374 =cut
1378 void
1379 PDB_next(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1381 ASSERT_ARGS(PDB_next)
1382 unsigned long n;
1383 PDB_t * const pdb = interp->pdb;
1384 Interp *debugee;
1386 TRACEDEB_MSG("PDB_next");
1388 /* Init the program if it's not running */
1389 if (!(pdb->state & PDB_RUNNING))
1390 PDB_init(interp, command);
1392 /* Get the number of operations to execute if any */
1393 n = get_ulong(& command, 1);
1395 /* Erase the stopped flag */
1396 pdb->state &= ~PDB_STOPPED;
1398 /* Testing use of the debugger runloop */
1399 #if 0
1401 /* Execute */
1402 for (; n && pdb->cur_opcode; n--)
1403 DO_OP(pdb->cur_opcode, pdb->debugee);
1405 /* Set the stopped flag */
1406 pdb->state |= PDB_STOPPED;
1408 /* If program ended */
1411 * RT #46119 this doesn't handle resume opcodes
1413 if (!pdb->cur_opcode)
1414 (void)PDB_program_end(interp);
1415 #endif
1417 debugee = pdb->debugee;
1419 new_runloop_jump_point(debugee);
1420 if (setjmp(debugee->current_runloop->resume)) {
1421 Parrot_eprintf(pdb->debugger, "Unhandled exception while tracing\n");
1422 pdb->state |= PDB_STOPPED;
1423 return;
1425 pdb->tracing = n;
1426 pdb->debugee->run_core = PARROT_DEBUGGER_CORE;
1428 TRACEDEB_MSG("PDB_next finished");
1433 =item C<void PDB_trace(PARROT_INTERP, const char *command)>
1435 Execute the next N operations; if no number is specified, it defaults to 1.
1437 =cut
1441 void
1442 PDB_trace(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1444 ASSERT_ARGS(PDB_trace)
1445 unsigned long n;
1446 PDB_t * const pdb = interp->pdb;
1447 Interp *debugee;
1449 TRACEDEB_MSG("PDB_trace");
1451 /* if debugger is not running yet, initialize */
1453 if (!(pdb->state & PDB_RUNNING))
1454 PDB_init(interp, command);
1457 /* ge the number of ops to run, if specified */
1458 n = get_ulong(& command, 1);
1460 /* clear the PDB_STOPPED flag, we'll be running n ops now */
1461 pdb->state &= ~PDB_STOPPED;
1462 debugee = pdb->debugee;
1464 /* execute n ops */
1465 new_runloop_jump_point(debugee);
1466 if (setjmp(debugee->current_runloop->resume)) {
1467 Parrot_eprintf(pdb->debugger, "Unhandled exception while tracing\n");
1468 pdb->state |= PDB_STOPPED;
1469 return;
1471 pdb->tracing = n;
1472 pdb->debugee->run_core = PARROT_DEBUGGER_CORE;
1473 pdb->state |= PDB_TRACING;
1475 /* Clear the following when done some testing */
1477 /* we just stopped */
1478 pdb->state |= PDB_STOPPED;
1480 /* If program ended */
1481 if (!pdb->cur_opcode)
1482 (void)PDB_program_end(interp);
1483 pdb->state |= PDB_RUNNING;
1484 pdb->state &= ~PDB_STOPPED;
1486 TRACEDEB_MSG("PDB_trace finished");
1491 =item C<static unsigned short condition_regtype(const char *cmd)>
1493 =cut
1497 static unsigned short
1498 condition_regtype(ARGIN(const char *cmd))
1500 ASSERT_ARGS(condition_regtype)
1501 switch (*cmd) {
1502 case 'i':
1503 case 'I':
1504 return PDB_cond_int;
1505 case 'n':
1506 case 'N':
1507 return PDB_cond_num;
1508 case 's':
1509 case 'S':
1510 return PDB_cond_str;
1511 case 'p':
1512 case 'P':
1513 return PDB_cond_pmc;
1514 default:
1515 return 0;
1521 =item C<PDB_condition_t * PDB_cond(PARROT_INTERP, const char *command)>
1523 Analyzes a condition from the user input.
1525 =cut
1529 PARROT_CAN_RETURN_NULL
1530 PDB_condition_t *
1531 PDB_cond(PARROT_INTERP, ARGIN(const char *command))
1533 ASSERT_ARGS(PDB_cond)
1534 PDB_condition_t *condition;
1535 const char *auxcmd;
1536 char str[DEBUG_CMD_BUFFER_LENGTH + 1];
1537 unsigned short cond_argleft;
1538 unsigned short cond_type;
1539 unsigned char regleft;
1540 int i, reg_number;
1542 TRACEDEB_MSG("PDB_cond");
1544 /* Return if no more arguments */
1545 if (!(command && *command)) {
1546 Parrot_io_eprintf(interp->pdb->debugger, "No condition specified\n");
1547 return NULL;
1550 command = skip_whitespace(command);
1551 #if TRACE_DEBUGGER
1552 fprintf(stderr, "PDB_trace: '%s'\n", command);
1553 #endif
1555 cond_argleft = condition_regtype(command);
1557 /* get the register number */
1558 auxcmd = ++command;
1559 regleft = (unsigned char)get_uint(&command, 0);
1560 if (auxcmd == command) {
1561 Parrot_io_eprintf(interp->pdb->debugger, "Invalid register\n");
1562 return NULL;
1565 /* Now the condition */
1566 command = skip_whitespace(command);
1567 switch (*command) {
1568 case '>':
1569 if (*(command + 1) == '=')
1570 cond_type = PDB_cond_ge;
1571 else
1572 cond_type = PDB_cond_gt;
1573 break;
1574 case '<':
1575 if (*(command + 1) == '=')
1576 cond_type = PDB_cond_le;
1577 else
1578 cond_type = PDB_cond_lt;
1579 break;
1580 case '=':
1581 if (*(command + 1) == '=')
1582 cond_type = PDB_cond_eq;
1583 else
1584 goto INV_COND;
1585 break;
1586 case '!':
1587 if (*(command + 1) == '=')
1588 cond_type = PDB_cond_ne;
1589 else
1590 goto INV_COND;
1591 break;
1592 case '\0':
1593 if (cond_argleft != PDB_cond_str && cond_argleft != PDB_cond_pmc) {
1594 Parrot_io_eprintf(interp->pdb->debugger, "Invalid null condition\n");
1595 return NULL;
1597 cond_type = PDB_cond_notnull;
1598 break;
1599 default:
1600 INV_COND: Parrot_io_eprintf(interp->pdb->debugger, "Invalid condition\n");
1601 return NULL;
1604 /* if there's an '=', skip it */
1605 if (*(command + 1) == '=')
1606 command += 2;
1607 else
1608 command++;
1610 command = skip_whitespace(command);
1612 /* return if no notnull condition and no more arguments */
1613 if (!(command && *command) && (cond_type != PDB_cond_notnull)) {
1614 Parrot_io_eprintf(interp->pdb->debugger, "Can't compare a register with nothing\n");
1615 return NULL;
1618 /* Allocate new condition */
1619 condition = mem_allocate_zeroed_typed(PDB_condition_t);
1621 condition->type = cond_argleft | cond_type;
1623 if (cond_type != PDB_cond_notnull) {
1625 if (isalpha((unsigned char)*command)) {
1626 /* It's a register - we first check that it's the correct type */
1628 unsigned short cond_argright = condition_regtype(command);
1630 if (cond_argright != cond_argleft) {
1631 Parrot_io_eprintf(interp->pdb->debugger, "Register types don't agree\n");
1632 mem_sys_free(condition);
1633 return NULL;
1636 /* Now we check and store the register number */
1637 auxcmd = ++command;
1638 reg_number = (int)get_uint(&command, 0);
1639 if (auxcmd == command) {
1640 Parrot_io_eprintf(interp->pdb->debugger, "Invalid register\n");
1641 mem_sys_free(condition);
1642 return NULL;
1645 if (reg_number < 0) {
1646 Parrot_io_eprintf(interp->pdb->debugger, "Out-of-bounds register\n");
1647 mem_sys_free(condition);
1648 return NULL;
1651 condition->value = mem_allocate_typed(int);
1652 *(int *)condition->value = reg_number;
1654 /* If the first argument was an integer */
1655 else if (condition->type & PDB_cond_int) {
1656 /* This must be either an integer constant or register */
1657 condition->value = mem_allocate_typed(INTVAL);
1658 *(INTVAL *)condition->value = (INTVAL)atoi(command);
1659 condition->type |= PDB_cond_const;
1661 else if (condition->type & PDB_cond_num) {
1662 condition->value = mem_allocate_typed(FLOATVAL);
1663 *(FLOATVAL *)condition->value = (FLOATVAL)atof(command);
1664 condition->type |= PDB_cond_const;
1666 else if (condition->type & PDB_cond_str) {
1667 for (i = 1; ((command[i] != '"') && (i < DEBUG_CMD_BUFFER_LENGTH)); i++)
1668 str[i - 1] = command[i];
1669 str[i - 1] = '\0';
1670 #if TRACE_DEBUGGER
1671 fprintf(stderr, "PDB_break: '%s'\n", str);
1672 #endif
1673 condition->value = string_make(interp, str, (UINTVAL)(i - 1),
1674 NULL, 0);
1676 condition->type |= PDB_cond_const;
1678 else if (condition->type & PDB_cond_pmc) {
1679 /* RT #46123 Need to figure out what to do in this case.
1680 * For the time being, we just bail. */
1681 Parrot_io_eprintf(interp->pdb->debugger, "Can't compare PMC with constant\n");
1682 mem_sys_free(condition);
1683 return NULL;
1688 return condition;
1693 =item C<void PDB_watchpoint(PARROT_INTERP, const char *command)>
1695 Set a watchpoint.
1697 =cut
1701 void
1702 PDB_watchpoint(PARROT_INTERP, ARGIN(const char *command))
1704 ASSERT_ARGS(PDB_watchpoint)
1705 PDB_t * const pdb = interp->pdb;
1706 PDB_condition_t * const condition = PDB_cond(interp, command);
1708 if (!condition)
1709 return;
1711 /* Add it to the head of the list */
1712 if (pdb->watchpoint)
1713 condition->next = pdb->watchpoint;
1715 pdb->watchpoint = condition;
1720 =item C<void PDB_set_break(PARROT_INTERP, const char *command)>
1722 Set a break point, the source code file must be loaded.
1724 =cut
1728 void
1729 PDB_set_break(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1731 ASSERT_ARGS(PDB_set_break)
1732 PDB_t * const pdb = interp->pdb;
1733 PDB_breakpoint_t *newbreak;
1734 PDB_breakpoint_t **lbreak;
1735 PDB_line_t *line = NULL;
1736 long bp_id;
1737 opcode_t *breakpos = NULL;
1739 unsigned long ln = get_ulong(& command, 0);
1741 TRACEDEB_MSG("PDB_set_break");
1744 /* If there is a source file use line number, else opcode position */
1746 if (pdb->file) {
1747 /* If no line number was specified, set it at the current line */
1748 if (ln != 0) {
1749 unsigned long i;
1751 /* Move to the line where we will set the break point */
1752 line = pdb->file->line;
1754 for (i = 1; ((i < ln) && (line->next)); i++)
1755 line = line->next;
1757 /* Abort if the line number provided doesn't exist */
1758 if (line == NULL || !line->next) {
1759 Parrot_io_eprintf(pdb->debugger,
1760 "Can't set a breakpoint at line number %li\n", ln);
1761 return;
1764 else {
1765 /* Get the line to set it */
1766 line = pdb->file->line;
1768 while (line->opcode != pdb->cur_opcode) {
1769 line = line->next;
1770 if (!line) {
1771 Parrot_io_eprintf(pdb->debugger,
1772 "No current line found and no line number specified\n");
1773 return;
1777 /* Skip lines that are not related to an opcode */
1778 while (line && !line->opcode)
1779 line = line->next;
1780 /* Abort if the line number provided doesn't exist */
1781 if (!line) {
1782 Parrot_io_eprintf(pdb->debugger,
1783 "Can't set a breakpoint at line number %li\n", ln);
1784 return;
1787 breakpos = line->opcode;
1789 else {
1790 breakpos = interp->code->base.data + ln;
1793 /* Allocate the new break point */
1794 newbreak = mem_allocate_zeroed_typed(PDB_breakpoint_t);
1796 if (command) {
1797 /*command = skip_command(command);*/
1799 else {
1800 Parrot_ex_throw_from_c_args(interp, NULL, 1,
1801 "NULL command passed to PDB_set_break");
1804 /* if there is another argument to break, besides the line number,
1805 * it should be an 'if', so we call another handler. */
1806 if (command && *command) {
1807 command = skip_whitespace(command);
1808 while (! isspace((unsigned char)*command))
1809 ++command;
1810 command = skip_whitespace(command);
1811 newbreak->condition = PDB_cond(interp, command);
1814 /* Set the address where to stop */
1815 newbreak->pc = breakpos;
1817 /* No next breakpoint */
1818 newbreak->next = NULL;
1820 /* Don't skip (at least initially) */
1821 newbreak->skip = 0;
1823 /* Add the breakpoint to the end of the list */
1824 bp_id = 1;
1825 lbreak = & pdb->breakpoint;
1826 while (*lbreak) {
1827 bp_id = (*lbreak)->id + 1;
1828 lbreak = & (*lbreak)->next;
1830 newbreak->prev = *lbreak;
1831 *lbreak = newbreak;
1832 newbreak->id = bp_id;
1834 /* Show breakpoint position */
1836 Parrot_io_eprintf(pdb->debugger, "Breakpoint %li at", newbreak->id);
1837 if (line)
1838 Parrot_io_eprintf(pdb->debugger, " line %li", line->number);
1839 Parrot_io_eprintf(pdb->debugger, " pos %li\n", newbreak->pc - interp->code->base.data);
1844 =item C<static void list_breakpoints(PDB_t *pdb)>
1846 =cut
1850 static void
1851 list_breakpoints(ARGIN(PDB_t *pdb))
1853 ASSERT_ARGS(list_breakpoints)
1855 PDB_breakpoint_t **lbreak;
1856 for (lbreak = & pdb->breakpoint; *lbreak; lbreak = & (*lbreak)->next) {
1857 PDB_breakpoint_t *br = *lbreak;
1858 Parrot_io_eprintf(pdb->debugger, "Breakpoint %li at", br->id);
1859 Parrot_io_eprintf(pdb->debugger, " pos %li", br->pc - pdb->debugee->code->base.data);
1860 if (br->skip == -1)
1861 Parrot_io_eprintf(pdb->debugger, " (disabled)");
1862 Parrot_io_eprintf(pdb->debugger, "\n");
1868 =item C<void PDB_init(PARROT_INTERP, const char *command)>
1870 Init the program.
1872 =cut
1876 void
1877 PDB_init(PARROT_INTERP, SHIM(const char *command))
1879 ASSERT_ARGS(PDB_init)
1880 PDB_t * const pdb = interp->pdb;
1882 /* Restart if we are already running */
1883 if (pdb->state & PDB_RUNNING)
1884 Parrot_io_eprintf(pdb->debugger, "Restarting\n");
1886 /* Add the RUNNING state */
1887 pdb->state |= PDB_RUNNING;
1892 =item C<void PDB_continue(PARROT_INTERP, const char *command)>
1894 Continue running the program. If a number is specified, skip that many
1895 breakpoints.
1897 =cut
1901 void
1902 PDB_continue(PARROT_INTERP, ARGIN_NULLOK(const char *command))
1904 ASSERT_ARGS(PDB_continue)
1905 PDB_t * const pdb = interp->pdb;
1906 unsigned long ln = 0;
1908 TRACEDEB_MSG("PDB_continue");
1910 /* Skip any breakpoint? */
1911 if (command)
1912 ln = get_ulong(& command, 0);
1914 if (ln != 0) {
1915 if (!pdb->breakpoint) {
1916 Parrot_io_eprintf(pdb->debugger, "No breakpoints to skip\n");
1917 return;
1920 PDB_skip_breakpoint(interp, ln);
1923 /* Run while no break point is reached */
1925 while (!PDB_break(interp))
1926 DO_OP(pdb->cur_opcode, pdb->debugee);
1929 #if 0
1930 pdb->tracing = 0;
1931 pdb->debugee->run_core = PARROT_DEBUGGER_CORE;
1932 new_internal_exception(pdb->debugee);
1933 if (setjmp(pdb->debugee->exceptions->destination)) {
1934 Parrot_eprintf(pdb->debugee, "Unhandled exception while debugging: %Ss\n",
1935 pdb->debugee->exceptions->msg);
1936 pdb->state |= PDB_STOPPED;
1937 return;
1939 runops_int(pdb->debugee, pdb->debugee->code->base.data - pdb->cur_opcode);
1940 if (!pdb->cur_opcode)
1941 (void)PDB_program_end(interp);
1942 #endif
1943 pdb->state |= PDB_RUNNING;
1944 pdb->state &= ~PDB_BREAK;
1945 pdb->state &= ~PDB_STOPPED;
1950 =item C<PDB_breakpoint_t * PDB_find_breakpoint(PARROT_INTERP, const char
1951 *command)>
1953 Find breakpoint number N; returns C<NULL> if the breakpoint doesn't
1954 exist or if no breakpoint was specified.
1956 =cut
1960 PARROT_CAN_RETURN_NULL
1961 PARROT_WARN_UNUSED_RESULT
1962 PDB_breakpoint_t *
1963 PDB_find_breakpoint(PARROT_INTERP, ARGIN(const char *command))
1965 ASSERT_ARGS(PDB_find_breakpoint)
1966 const char *oldcmd = command;
1967 const unsigned long n = get_ulong(&command, 0);
1968 if (command != oldcmd) {
1969 PDB_breakpoint_t *breakpoint = interp->pdb->breakpoint;
1971 while (breakpoint && breakpoint->id != n)
1972 breakpoint = breakpoint->next;
1974 if (!breakpoint) {
1975 Parrot_io_eprintf(interp->pdb->debugger, "No breakpoint number %ld", n);
1976 return NULL;
1979 return breakpoint;
1981 else {
1982 /* Report an appropriate error */
1983 if (*command)
1984 Parrot_io_eprintf(interp->pdb->debugger, "Not a valid breakpoint");
1985 else
1986 Parrot_io_eprintf(interp->pdb->debugger, "No breakpoint specified");
1988 return NULL;
1994 =item C<void PDB_disable_breakpoint(PARROT_INTERP, const char *command)>
1996 Disable a breakpoint; it can be reenabled with the enable command.
1998 =cut
2002 void
2003 PDB_disable_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2005 ASSERT_ARGS(PDB_disable_breakpoint)
2006 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2008 /* if the breakpoint exists, disable it. */
2009 if (breakpoint)
2010 breakpoint->skip = -1;
2015 =item C<void PDB_enable_breakpoint(PARROT_INTERP, const char *command)>
2017 Reenable a disabled breakpoint; if the breakpoint was not disabled, has
2018 no effect.
2020 =cut
2024 void
2025 PDB_enable_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2027 ASSERT_ARGS(PDB_enable_breakpoint)
2028 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2030 /* if the breakpoint exists, and it was disabled, enable it. */
2031 if (breakpoint && breakpoint->skip == -1)
2032 breakpoint->skip = 0;
2037 =item C<void PDB_delete_breakpoint(PARROT_INTERP, const char *command)>
2039 Delete a breakpoint.
2041 =cut
2045 void
2046 PDB_delete_breakpoint(PARROT_INTERP, ARGIN(const char *command))
2048 ASSERT_ARGS(PDB_delete_breakpoint)
2049 PDB_breakpoint_t * const breakpoint = PDB_find_breakpoint(interp, command);
2051 if (breakpoint) {
2052 const PDB_line_t *line = interp->pdb->file->line;
2054 while (line->opcode != breakpoint->pc)
2055 line = line->next;
2057 /* Delete the condition structure, if there is one */
2058 if (breakpoint->condition) {
2059 PDB_delete_condition(interp, breakpoint);
2060 breakpoint->condition = NULL;
2063 /* Remove the breakpoint from the list */
2064 if (breakpoint->prev && breakpoint->next) {
2065 breakpoint->prev->next = breakpoint->next;
2066 breakpoint->next->prev = breakpoint->prev;
2068 else if (breakpoint->prev && !breakpoint->next) {
2069 breakpoint->prev->next = NULL;
2071 else if (!breakpoint->prev && breakpoint->next) {
2072 breakpoint->next->prev = NULL;
2073 interp->pdb->breakpoint = breakpoint->next;
2075 else {
2076 interp->pdb->breakpoint = NULL;
2079 /* Kill the breakpoint */
2080 mem_sys_free(breakpoint);
2086 =item C<void PDB_delete_condition(PARROT_INTERP, PDB_breakpoint_t *breakpoint)>
2088 Delete a condition associated with a breakpoint.
2090 =cut
2094 void
2095 PDB_delete_condition(SHIM_INTERP, ARGMOD(PDB_breakpoint_t *breakpoint))
2097 ASSERT_ARGS(PDB_delete_condition)
2098 if (breakpoint->condition->value) {
2099 if (breakpoint->condition->type & PDB_cond_str) {
2100 /* 'value' is a string, so we need to be careful */
2101 PObj_external_CLEAR((STRING*)breakpoint->condition->value);
2102 PObj_on_free_list_SET((STRING*)breakpoint->condition->value);
2103 /* it should now be properly garbage collected after
2104 we destroy the condition */
2106 else {
2107 /* 'value' is a float or an int, so we can just free it */
2108 mem_sys_free(breakpoint->condition->value);
2109 breakpoint->condition->value = NULL;
2113 mem_sys_free(breakpoint->condition);
2114 breakpoint->condition = NULL;
2119 =item C<void PDB_skip_breakpoint(PARROT_INTERP, unsigned long i)>
2121 Skip C<i> times all breakpoints.
2123 =cut
2127 void
2128 PDB_skip_breakpoint(PARROT_INTERP, unsigned long i)
2130 ASSERT_ARGS(PDB_skip_breakpoint)
2131 #if TRACE_DEBUGGER
2132 fprintf(stderr, "PDB_skip_breakpoint: %li\n", i);
2133 #endif
2135 interp->pdb->breakpoint_skip = i;
2140 =item C<char PDB_program_end(PARROT_INTERP)>
2142 End the program.
2144 =cut
2148 char
2149 PDB_program_end(PARROT_INTERP)
2151 ASSERT_ARGS(PDB_program_end)
2152 PDB_t * const pdb = interp->pdb;
2154 TRACEDEB_MSG("PDB_program_end");
2156 /* Remove the RUNNING state */
2157 pdb->state &= ~PDB_RUNNING;
2159 Parrot_io_eprintf(pdb->debugger, "Program exited.\n");
2160 return 1;
2165 =item C<char PDB_check_condition(PARROT_INTERP, const PDB_condition_t
2166 *condition)>
2168 Returns true if the condition was met.
2170 =cut
2174 PARROT_WARN_UNUSED_RESULT
2175 char
2176 PDB_check_condition(PARROT_INTERP, ARGIN(const PDB_condition_t *condition))
2178 ASSERT_ARGS(PDB_check_condition)
2179 Parrot_Context *ctx = CONTEXT(interp);
2181 TRACEDEB_MSG("PDB_check_condition");
2183 PARROT_ASSERT(ctx);
2185 if (condition->type & PDB_cond_int) {
2186 INTVAL i, j;
2187 if (condition->reg >= ctx->n_regs_used[REGNO_INT])
2188 return 0;
2189 i = CTX_REG_INT(ctx, condition->reg);
2191 if (condition->type & PDB_cond_const)
2192 j = *(INTVAL *)condition->value;
2193 else
2194 j = REG_INT(interp, *(int *)condition->value);
2196 if (((condition->type & PDB_cond_gt) && (i > j)) ||
2197 ((condition->type & PDB_cond_ge) && (i >= j)) ||
2198 ((condition->type & PDB_cond_eq) && (i == j)) ||
2199 ((condition->type & PDB_cond_ne) && (i != j)) ||
2200 ((condition->type & PDB_cond_le) && (i <= j)) ||
2201 ((condition->type & PDB_cond_lt) && (i < j)))
2202 return 1;
2204 return 0;
2206 else if (condition->type & PDB_cond_num) {
2207 FLOATVAL k, l;
2209 if (condition->reg >= ctx->n_regs_used[REGNO_NUM])
2210 return 0;
2211 k = CTX_REG_NUM(ctx, condition->reg);
2213 if (condition->type & PDB_cond_const)
2214 l = *(FLOATVAL *)condition->value;
2215 else
2216 l = REG_NUM(interp, *(int *)condition->value);
2218 if (((condition->type & PDB_cond_gt) && (k > l)) ||
2219 ((condition->type & PDB_cond_ge) && (k >= l)) ||
2220 ((condition->type & PDB_cond_eq) && (k == l)) ||
2221 ((condition->type & PDB_cond_ne) && (k != l)) ||
2222 ((condition->type & PDB_cond_le) && (k <= l)) ||
2223 ((condition->type & PDB_cond_lt) && (k < l)))
2224 return 1;
2226 return 0;
2228 else if (condition->type & PDB_cond_str) {
2229 STRING *m, *n;
2231 if (condition->reg >= ctx->n_regs_used[REGNO_STR])
2232 return 0;
2233 m = CTX_REG_STR(ctx, condition->reg);
2235 if (condition->type & PDB_cond_notnull)
2236 return ! STRING_IS_NULL(m);
2238 if (condition->type & PDB_cond_const)
2239 n = (STRING *)condition->value;
2240 else
2241 n = REG_STR(interp, *(int *)condition->value);
2243 if (((condition->type & PDB_cond_gt) &&
2244 (Parrot_str_compare(interp, m, n) > 0)) ||
2245 ((condition->type & PDB_cond_ge) &&
2246 (Parrot_str_compare(interp, m, n) >= 0)) ||
2247 ((condition->type & PDB_cond_eq) &&
2248 (Parrot_str_compare(interp, m, n) == 0)) ||
2249 ((condition->type & PDB_cond_ne) &&
2250 (Parrot_str_compare(interp, m, n) != 0)) ||
2251 ((condition->type & PDB_cond_le) &&
2252 (Parrot_str_compare(interp, m, n) <= 0)) ||
2253 ((condition->type & PDB_cond_lt) &&
2254 (Parrot_str_compare(interp, m, n) < 0)))
2255 return 1;
2257 return 0;
2259 else if (condition->type & PDB_cond_pmc) {
2260 PMC *m;
2262 if (condition->reg >= ctx->n_regs_used[REGNO_PMC])
2263 return 0;
2264 m = CTX_REG_PMC(ctx, condition->reg);
2266 if (condition->type & PDB_cond_notnull)
2267 return ! PMC_IS_NULL(m);
2268 return 0;
2270 else
2271 return 0;
2276 =item C<static PDB_breakpoint_t * current_breakpoint(PDB_t * pdb)>
2278 Returns a pointer to the breakpoint at the current position,
2279 or NULL if there is none.
2281 =cut
2285 PARROT_CAN_RETURN_NULL
2286 static PDB_breakpoint_t *
2287 current_breakpoint(ARGIN(PDB_t * pdb))
2289 ASSERT_ARGS(current_breakpoint)
2290 PDB_breakpoint_t *breakpoint = pdb->breakpoint;
2291 while (breakpoint) {
2292 if (pdb->cur_opcode == breakpoint->pc)
2293 break;
2294 breakpoint = breakpoint->next;
2296 return breakpoint;
2301 =item C<char PDB_break(PARROT_INTERP)>
2303 Returns true if we have to stop running.
2305 =cut
2309 PARROT_WARN_UNUSED_RESULT
2310 char
2311 PDB_break(PARROT_INTERP)
2313 ASSERT_ARGS(PDB_break)
2314 PDB_t * const pdb = interp->pdb;
2315 PDB_condition_t *watchpoint = pdb->watchpoint;
2316 PDB_breakpoint_t *breakpoint;
2319 TRACEDEB_MSG("PDB_break");
2322 /* Check the watchpoints first. */
2323 while (watchpoint) {
2324 if (PDB_check_condition(interp, watchpoint)) {
2325 pdb->state |= PDB_STOPPED;
2326 return 1;
2329 watchpoint = watchpoint->next;
2332 /* If program ended */
2333 if (!pdb->cur_opcode)
2334 return PDB_program_end(interp);
2336 /* If the program is STOPPED allow it to continue */
2337 if (pdb->state & PDB_STOPPED) {
2338 pdb->state &= ~PDB_STOPPED;
2339 return 0;
2342 breakpoint = current_breakpoint(pdb);
2343 if (breakpoint) {
2344 /* If we have to skip breakpoints, do so. */
2345 if (pdb->breakpoint_skip) {
2346 TRACEDEB_MSG("PDB_break skipping");
2347 pdb->breakpoint_skip--;
2348 return 0;
2351 if (breakpoint->skip < 0)
2352 return 0;
2354 /* Check if there is a condition for this breakpoint */
2355 if ((breakpoint->condition) &&
2356 (!PDB_check_condition(interp, breakpoint->condition)))
2357 return 0;
2359 TRACEDEB_MSG("PDB_break stopping");
2361 /* Add the STOPPED state and stop */
2362 pdb->state |= PDB_STOPPED;
2363 return 1;
2366 return 0;
2371 =item C<char * PDB_escape(const char *string, UINTVAL length)>
2373 Escapes C<">, C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2375 The returned string must be freed.
2377 =cut
2381 PARROT_WARN_UNUSED_RESULT
2382 PARROT_CAN_RETURN_NULL
2383 PARROT_MALLOC
2384 char *
2385 PDB_escape(ARGIN(const char *string), UINTVAL length)
2387 ASSERT_ARGS(PDB_escape)
2388 const char *end;
2389 char *_new, *fill;
2391 length = length > 20 ? 20 : length;
2392 end = string + length;
2394 /* Return if there is no string to escape*/
2395 if (!string)
2396 return NULL;
2398 fill = _new = (char *)mem_sys_allocate(length * 2 + 1);
2400 for (; string < end; string++) {
2401 switch (*string) {
2402 case '\0':
2403 *(fill++) = '\\';
2404 *(fill++) = '0';
2405 break;
2406 case '\n':
2407 *(fill++) = '\\';
2408 *(fill++) = 'n';
2409 break;
2410 case '\r':
2411 *(fill++) = '\\';
2412 *(fill++) = 'r';
2413 break;
2414 case '\t':
2415 *(fill++) = '\\';
2416 *(fill++) = 't';
2417 break;
2418 case '\a':
2419 *(fill++) = '\\';
2420 *(fill++) = 'a';
2421 break;
2422 case '\\':
2423 *(fill++) = '\\';
2424 *(fill++) = '\\';
2425 break;
2426 case '"':
2427 *(fill++) = '\\';
2428 *(fill++) = '"';
2429 break;
2430 default:
2431 *(fill++) = *string;
2432 break;
2436 *fill = '\0';
2438 return _new;
2443 =item C<int PDB_unescape(char *string)>
2445 Do inplace unescape of C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2447 =cut
2452 PDB_unescape(ARGMOD(char *string))
2454 ASSERT_ARGS(PDB_unescape)
2455 int l = 0;
2457 for (; *string; string++) {
2458 l++;
2460 if (*string == '\\') {
2461 char *fill;
2462 int i;
2464 switch (string[1]) {
2465 case 'n':
2466 *string = '\n';
2467 break;
2468 case 'r':
2469 *string = '\r';
2470 break;
2471 case 't':
2472 *string = '\t';
2473 break;
2474 case 'a':
2475 *string = '\a';
2476 break;
2477 case '\\':
2478 *string = '\\';
2479 break;
2480 default:
2481 continue;
2484 fill = string;
2486 for (i = 1; fill[i + 1]; i++)
2487 fill[i] = fill[i + 1];
2489 fill[i] = '\0';
2493 return l;
2498 =item C<size_t PDB_disassemble_op(PARROT_INTERP, char *dest, size_t space, const
2499 op_info_t *info, const opcode_t *op, PDB_file_t *file, const opcode_t
2500 *code_start, int full_name)>
2502 Disassembles C<op>.
2504 =cut
2508 size_t
2509 PDB_disassemble_op(PARROT_INTERP, ARGOUT(char *dest), size_t space,
2510 ARGIN(const op_info_t *info), ARGIN(const opcode_t *op),
2511 ARGMOD_NULLOK(PDB_file_t *file), ARGIN_NULLOK(const opcode_t *code_start),
2512 int full_name)
2514 ASSERT_ARGS(PDB_disassemble_op)
2515 int j;
2516 size_t size = 0;
2517 int specialop = 0;
2519 /* Write the opcode name */
2520 const char * p = full_name ? info->full_name : info->name;
2522 TRACEDEB_MSG("PDB_disassemble_op");
2524 if (! p)
2525 p= "**UNKNOWN**";
2526 strcpy(dest, p);
2527 size += strlen(p);
2529 dest[size++] = ' ';
2531 /* Concat the arguments */
2532 for (j = 1; j < info->op_count; j++) {
2533 char buf[256];
2534 INTVAL i = 0;
2536 PARROT_ASSERT(size + 2 < space);
2538 switch (info->types[j - 1]) {
2539 case PARROT_ARG_I:
2540 dest[size++] = 'I';
2541 goto INTEGER;
2542 case PARROT_ARG_N:
2543 dest[size++] = 'N';
2544 goto INTEGER;
2545 case PARROT_ARG_S:
2546 dest[size++] = 'S';
2547 goto INTEGER;
2548 case PARROT_ARG_P:
2549 dest[size++] = 'P';
2550 goto INTEGER;
2551 case PARROT_ARG_IC:
2552 /* If the opcode jumps and this is the last argument,
2553 that means this is a label */
2554 if ((j == info->op_count - 1) &&
2555 (info->jump & PARROT_JUMP_RELATIVE)) {
2556 if (file) {
2557 dest[size++] = 'L';
2558 i = PDB_add_label(file, op, op[j]);
2560 else if (code_start) {
2561 dest[size++] = 'O';
2562 dest[size++] = 'P';
2563 i = op[j] + (op - code_start);
2565 else {
2566 if (op[j] > 0)
2567 dest[size++] = '+';
2568 i = op[j];
2572 /* Convert the integer to a string */
2573 INTEGER:
2574 if (i == 0)
2575 i = (INTVAL) op[j];
2577 PARROT_ASSERT(size + 20 < space);
2579 size += sprintf(&dest[size], INTVAL_FMT, i);
2581 break;
2582 case PARROT_ARG_NC:
2584 /* Convert the float to a string */
2585 const FLOATVAL f = interp->code->const_table->constants[op[j]]->u.number;
2586 Parrot_snprintf(interp, buf, sizeof (buf), FLOATVAL_FMT, f);
2587 strcpy(&dest[size], buf);
2588 size += strlen(buf);
2590 break;
2591 case PARROT_ARG_SC:
2592 dest[size++] = '"';
2593 if (interp->code->const_table->constants[op[j]]-> u.string->strlen) {
2594 char * const escaped =
2595 PDB_escape(interp->code->const_table->
2596 constants[op[j]]->u.string->strstart,
2597 interp->code->const_table->
2598 constants[op[j]]->u.string->strlen);
2599 if (escaped) {
2600 strcpy(&dest[size], escaped);
2601 size += strlen(escaped);
2602 mem_sys_free(escaped);
2605 dest[size++] = '"';
2606 break;
2607 case PARROT_ARG_PC:
2608 Parrot_snprintf(interp, buf, sizeof (buf), "PMC_CONST(%d)", op[j]);
2609 strcpy(&dest[size], buf);
2610 size += strlen(buf);
2611 break;
2612 case PARROT_ARG_K:
2613 dest[size - 1] = '[';
2614 Parrot_snprintf(interp, buf, sizeof (buf), "P" INTVAL_FMT, op[j]);
2615 strcpy(&dest[size], buf);
2616 size += strlen(buf);
2617 dest[size++] = ']';
2618 break;
2619 case PARROT_ARG_KC:
2621 PMC * k = interp->code->const_table->constants[op[j]]->u.key;
2622 dest[size - 1] = '[';
2623 while (k) {
2624 switch (PObj_get_FLAGS(k)) {
2625 case 0:
2626 break;
2627 case KEY_integer_FLAG:
2628 Parrot_snprintf(interp, buf, sizeof (buf),
2629 INTVAL_FMT, VTABLE_get_integer(interp, k));
2630 strcpy(&dest[size], buf);
2631 size += strlen(buf);
2632 break;
2633 case KEY_number_FLAG:
2634 Parrot_snprintf(interp, buf, sizeof (buf),
2635 FLOATVAL_FMT, VTABLE_get_number(interp, k));
2636 strcpy(&dest[size], buf);
2637 size += strlen(buf);
2638 break;
2639 case KEY_string_FLAG:
2640 dest[size++] = '"';
2642 char * const temp = Parrot_str_to_cstring(interp,
2643 VTABLE_get_string(interp, k));
2644 strcpy(&dest[size], temp);
2645 Parrot_str_free_cstring(temp);
2647 size += Parrot_str_byte_length(interp,
2648 VTABLE_get_string(interp, (k)));
2649 dest[size++] = '"';
2650 break;
2651 case KEY_integer_FLAG|KEY_register_FLAG:
2652 Parrot_snprintf(interp, buf, sizeof (buf),
2653 "I" INTVAL_FMT, VTABLE_get_integer(interp, k));
2654 strcpy(&dest[size], buf);
2655 size += strlen(buf);
2656 break;
2657 case KEY_number_FLAG|KEY_register_FLAG:
2658 Parrot_snprintf(interp, buf, sizeof (buf),
2659 "N" INTVAL_FMT, VTABLE_get_integer(interp, k));
2660 strcpy(&dest[size], buf);
2661 size += strlen(buf);
2662 break;
2663 case KEY_string_FLAG|KEY_register_FLAG:
2664 Parrot_snprintf(interp, buf, sizeof (buf),
2665 "S" INTVAL_FMT, VTABLE_get_integer(interp, k));
2666 strcpy(&dest[size], buf);
2667 size += strlen(buf);
2668 break;
2669 case KEY_pmc_FLAG|KEY_register_FLAG:
2670 Parrot_snprintf(interp, buf, sizeof (buf),
2671 "P" INTVAL_FMT, VTABLE_get_integer(interp, k));
2672 strcpy(&dest[size], buf);
2673 size += strlen(buf);
2674 break;
2675 default:
2676 dest[size++] = '?';
2677 break;
2679 GETATTR_Key_next_key(interp, k, k);
2680 if (k)
2681 dest[size++] = ';';
2683 dest[size++] = ']';
2685 break;
2686 case PARROT_ARG_KI:
2687 dest[size - 1] = '[';
2688 Parrot_snprintf(interp, buf, sizeof (buf), "I" INTVAL_FMT, op[j]);
2689 strcpy(&dest[size], buf);
2690 size += strlen(buf);
2691 dest[size++] = ']';
2692 break;
2693 case PARROT_ARG_KIC:
2694 dest[size - 1] = '[';
2695 Parrot_snprintf(interp, buf, sizeof (buf), INTVAL_FMT, op[j]);
2696 strcpy(&dest[size], buf);
2697 size += strlen(buf);
2698 dest[size++] = ']';
2699 break;
2700 default:
2701 Parrot_ex_throw_from_c_args(interp, NULL, 1, "Unknown opcode type");
2704 if (j != info->op_count - 1)
2705 dest[size++] = ',';
2708 /* Special decoding for the signature used in args/returns. Such ops have
2709 one fixed parameter (the signature vector), plus a varying number of
2710 registers/constants. For each arg/return, we show the register and its
2711 flags using PIR syntax. */
2712 if (*(op) == PARROT_OP_set_args_pc || *(op) == PARROT_OP_set_returns_pc)
2713 specialop = 1;
2715 /* if it's a retrieving op, specialop = 2, so that later a :flat flag
2716 * can be changed into a :slurpy flag. See flag handling below.
2718 if (*(op) == PARROT_OP_get_results_pc || *(op) == PARROT_OP_get_params_pc)
2719 specialop = 2;
2721 if (specialop > 0) {
2722 char buf[1000];
2723 PMC * const sig = interp->code->const_table->constants[op[1]]->u.key;
2724 const int n_values = VTABLE_elements(interp, sig);
2725 /* The flag_names strings come from Call_bits_enum_t (with which it
2726 should probably be colocated); they name the bits from LSB to MSB.
2727 The two least significant bits are not flags; they are the register
2728 type, which is decoded elsewhere. We also want to show unused bits,
2729 which could indicate problems.
2731 PARROT_OBSERVER const char * const flag_names[] = {
2734 " :unused004",
2735 " :unused008",
2736 " :const",
2737 " :flat", /* should be :slurpy for args */
2738 " :unused040",
2739 " :optional",
2740 " :opt_flag",
2741 " :named",
2742 NULL
2746 /* Register decoding. It would be good to abstract this, too. */
2747 PARROT_OBSERVER static const char regs[] = "ISPN";
2749 for (j = 0; j < n_values; j++) {
2750 size_t idx = 0;
2751 const int sig_value = VTABLE_get_integer_keyed_int(interp, sig, j);
2753 /* Print the register name, e.g. P37. */
2754 buf[idx++] = ',';
2755 buf[idx++] = ' ';
2756 buf[idx++] = regs[sig_value & PARROT_ARG_TYPE_MASK];
2757 Parrot_snprintf(interp, &buf[idx], sizeof (buf)-idx,
2758 INTVAL_FMT, op[j+2]);
2759 idx = strlen(buf);
2761 /* Add flags, if we have any. */
2763 int flag_idx = 0;
2764 int flags = sig_value;
2766 /* End when we run out of flags, off the end of flag_names, or
2767 * get too close to the end of buf.
2768 * 100 is just an estimate of all buf lengths added together.
2770 while (flags && idx < sizeof (buf) - 100) {
2771 const char * const flag_string
2772 = (specialop == 2 && STREQ(flag_names[flag_idx], " :flat"))
2773 ? " :slurpy"
2774 : flag_names[flag_idx];
2776 if (! flag_string)
2777 break;
2778 if (flags & 1 && *flag_string) {
2779 const size_t n = strlen(flag_string);
2780 strcpy(&buf[idx], flag_string);
2781 idx += n;
2783 flags >>= 1;
2784 flag_idx++;
2788 /* Add it to dest. */
2789 buf[idx++] = '\0';
2790 strcpy(&dest[size], buf);
2791 size += strlen(buf);
2795 dest[size] = '\0';
2796 return ++size;
2801 =item C<void PDB_disassemble(PARROT_INTERP, const char *command)>
2803 Disassemble the bytecode.
2805 =cut
2809 void
2810 PDB_disassemble(PARROT_INTERP, SHIM(const char *command))
2812 ASSERT_ARGS(PDB_disassemble)
2813 PDB_t * const pdb = interp->pdb;
2814 opcode_t * pc = interp->code->base.data;
2816 PDB_file_t *pfile;
2817 PDB_line_t *pline, *newline;
2818 PDB_label_t *label;
2819 opcode_t *code_end;
2821 const unsigned int default_size = 32768;
2822 size_t space; /* How much space do we have? */
2823 size_t size, alloced, n;
2825 TRACEDEB_MSG("PDB_disassemble");
2827 pfile = mem_allocate_zeroed_typed(PDB_file_t);
2828 pline = mem_allocate_zeroed_typed(PDB_line_t);
2830 /* If we already got a source, free it */
2831 if (pdb->file) {
2832 PDB_free_file(interp, pdb->file);
2833 pdb->file = NULL;
2836 pfile->line = pline;
2837 pline->number = 1;
2838 pfile->source = (char *)mem_sys_allocate(default_size);
2840 alloced = space = default_size;
2841 code_end = pc + interp->code->base.size;
2843 while (pc != code_end) {
2844 /* Grow it early */
2845 if (space < default_size) {
2846 alloced += default_size;
2847 space += default_size;
2848 pfile->source = (char *)mem_sys_realloc(pfile->source, alloced);
2851 size = PDB_disassemble_op(interp, pfile->source + pfile->size,
2852 space, &interp->op_info_table[*pc], pc, pfile, NULL, 1);
2853 space -= size;
2854 pfile->size += size;
2855 pfile->source[pfile->size - 1] = '\n';
2857 /* Store the opcode of this line */
2858 pline->opcode = pc;
2859 n = interp->op_info_table[*pc].op_count;
2861 ADD_OP_VAR_PART(interp, interp->code, pc, n);
2862 pc += n;
2864 /* Prepare for next line */
2865 newline = mem_allocate_typed(PDB_line_t);
2866 newline->label = NULL;
2867 newline->next = NULL;
2868 newline->number = pline->number + 1;
2869 pline->next = newline;
2870 pline = newline;
2871 pline->source_offset = pfile->size;
2874 /* Add labels to the lines they belong to */
2875 label = pfile->label;
2877 while (label) {
2878 /* Get the line to apply the label */
2879 pline = pfile->line;
2881 while (pline && pline->opcode != label->opcode)
2882 pline = pline->next;
2884 if (!pline) {
2885 Parrot_io_eprintf(pdb->debugger,
2886 "Label number %li out of bounds.\n", label->number);
2888 PDB_free_file(interp, pfile);
2889 return;
2892 pline->label = label;
2894 label = label->next;
2897 pdb->state |= PDB_SRC_LOADED;
2898 pdb->file = pfile;
2903 =item C<long PDB_add_label(PDB_file_t *file, const opcode_t *cur_opcode,
2904 opcode_t offset)>
2906 Add a label to the label list.
2908 =cut
2912 long
2913 PDB_add_label(ARGMOD(PDB_file_t *file), ARGIN(const opcode_t *cur_opcode),
2914 opcode_t offset)
2916 ASSERT_ARGS(PDB_add_label)
2917 PDB_label_t *_new;
2918 PDB_label_t *label = file->label;
2920 /* See if there is already a label at this line */
2921 while (label) {
2922 if (label->opcode == cur_opcode + offset)
2923 return label->number;
2924 label = label->next;
2927 /* Allocate a new label */
2928 label = file->label;
2929 _new = mem_allocate_typed(PDB_label_t);
2930 _new->opcode = cur_opcode + offset;
2931 _new->next = NULL;
2933 if (label) {
2934 while (label->next)
2935 label = label->next;
2937 _new->number = label->number + 1;
2938 label->next = _new;
2940 else {
2941 file->label = _new;
2942 _new->number = 1;
2945 return _new->number;
2950 =item C<void PDB_free_file(PARROT_INTERP, PDB_file_t *file)>
2952 Frees any allocated source files.
2954 =cut
2958 void
2959 PDB_free_file(SHIM_INTERP, ARGIN_NULLOK(PDB_file_t *file))
2961 ASSERT_ARGS(PDB_free_file)
2962 while (file) {
2963 /* Free all of the allocated line structures */
2964 PDB_line_t *line = file->line;
2965 PDB_label_t *label;
2966 PDB_file_t *nfile;
2968 while (line) {
2969 PDB_line_t * const nline = line->next;
2970 mem_sys_free(line);
2971 line = nline;
2974 /* Free all of the allocated label structures */
2975 label = file->label;
2977 while (label) {
2978 PDB_label_t * const nlabel = label->next;
2980 mem_sys_free(label);
2981 label = nlabel;
2984 /* Free the remaining allocated portions of the file structure */
2985 if (file->sourcefilename)
2986 mem_sys_free(file->sourcefilename);
2988 if (file->source)
2989 mem_sys_free(file->source);
2991 nfile = file->next;
2992 mem_sys_free(file);
2993 file = nfile;
2999 =item C<void PDB_load_source(PARROT_INTERP, const char *command)>
3001 Load a source code file.
3003 =cut
3007 PARROT_EXPORT
3008 void
3009 PDB_load_source(PARROT_INTERP, ARGIN(const char *command))
3011 ASSERT_ARGS(PDB_load_source)
3012 FILE *file;
3013 char f[DEBUG_CMD_BUFFER_LENGTH + 1];
3014 int i, j, c;
3015 PDB_file_t *pfile;
3016 PDB_line_t *pline;
3017 PDB_t * const pdb = interp->pdb;
3018 opcode_t *pc = interp->code->base.data;
3020 unsigned long size = 0;
3022 TRACEDEB_MSG("PDB_load_source");
3024 /* If there was a file already loaded or the bytecode was
3025 disassembled, free it */
3026 if (pdb->file) {
3027 PDB_free_file(interp->pdb->debugee, interp->pdb->debugee->pdb->file);
3028 interp->pdb->debugee->pdb->file = NULL;
3031 /* Get the name of the file */
3032 for (j = 0; command[j] == ' '; ++j)
3033 continue;
3034 for (i = 0; command[j]; i++, j++)
3035 f[i] = command[j];
3037 f[i] = '\0';
3039 /* open the file */
3040 file = fopen(f, "r");
3042 /* abort if fopen failed */
3043 if (!file) {
3044 Parrot_io_eprintf(pdb->debugger, "Unable to load '%s'\n", f);
3045 return;
3048 pfile = mem_allocate_zeroed_typed(PDB_file_t);
3049 pline = mem_allocate_zeroed_typed(PDB_line_t);
3051 pfile->source = (char *)mem_sys_allocate(1024);
3052 pfile->line = pline;
3053 pline->number = 1;
3055 PARROT_ASSERT(interp->op_info_table);
3056 PARROT_ASSERT(pc);
3058 while ((c = fgetc(file)) != EOF) {
3059 /* Grow it */
3060 if (++size == 1024) {
3061 pfile->source = (char *)mem_sys_realloc(pfile->source,
3062 (size_t)pfile->size + 1024);
3063 size = 0;
3065 pfile->source[pfile->size] = (char)c;
3067 pfile->size++;
3069 if (c == '\n') {
3070 /* If the line has an opcode move to the next one,
3071 otherwise leave it with NULL to skip it. */
3072 PDB_line_t *newline = mem_allocate_zeroed_typed(PDB_line_t);
3074 if (PDB_hasinstruction(pfile->source + pline->source_offset)) {
3075 size_t n = interp->op_info_table[*pc].op_count;
3076 pline->opcode = pc;
3077 ADD_OP_VAR_PART(interp, interp->code, pc, n);
3078 pc += n;
3080 /* don't walk off the end of the program into neverland */
3081 if (pc >= interp->code->base.data + interp->code->base.size)
3082 return;
3085 newline->number = pline->number + 1;
3086 pline->next = newline;
3087 pline = newline;
3088 pline->source_offset = pfile->size;
3089 pline->opcode = NULL;
3090 pline->label = NULL;
3094 fclose(file);
3096 pdb->state |= PDB_SRC_LOADED;
3097 pdb->file = pfile;
3099 TRACEDEB_MSG("PDB_load_source finished");
3104 =item C<char PDB_hasinstruction(const char *c)>
3106 Return true if the line has an instruction.
3108 RT #46129:
3110 =over 4
3112 =item * This should take the line, get an instruction, get the opcode for
3113 that instruction and check that is the correct one.
3115 =item * Decide what to do with macros if anything.
3117 =back
3119 =cut
3123 PARROT_WARN_UNUSED_RESULT
3124 PARROT_PURE_FUNCTION
3125 char
3126 PDB_hasinstruction(ARGIN(const char *c))
3128 ASSERT_ARGS(PDB_hasinstruction)
3129 char h = 0;
3131 /* as long as c is not NULL, we're not looking at a comment (#...) or a '\n'... */
3132 while (*c && *c != '#' && *c != '\n') {
3133 /* ... and c is alphanumeric or a quoted string then the line contains
3134 * an instruction. */
3135 if (isalnum((unsigned char) *c) || *c == '"') {
3136 h = 1;
3138 else if (*c == ':') {
3139 /* this is a label. RT #46137 right? */
3140 h = 0;
3143 c++;
3146 return h;
3151 =item C<void PDB_list(PARROT_INTERP, const char *command)>
3153 Show lines from the source code file.
3155 =cut
3159 void
3160 PDB_list(PARROT_INTERP, ARGIN(const char *command))
3162 ASSERT_ARGS(PDB_list)
3163 char *c;
3164 unsigned long line_number;
3165 unsigned long i;
3166 PDB_line_t *line;
3167 PDB_t *pdb = interp->pdb;
3168 unsigned long n = 10;
3170 TRACEDEB_MSG("PDB_list");
3171 if (!pdb->file || !pdb->file->line) {
3172 Parrot_io_eprintf(pdb->debugger, "No source file loaded\n");
3173 return;
3176 /* set the list line if provided */
3177 line_number = get_ulong(&command, 0);
3178 pdb->file->list_line = (unsigned long) line_number;
3180 /* set the number of lines to print */
3181 n = get_ulong(&command, 10);
3183 /* if n is zero, we simply return, as we don't have to print anything */
3184 if (n == 0)
3185 return;
3187 line = pdb->file->line;
3189 for (i = 0; i < pdb->file->list_line && line->next; i++)
3190 line = line->next;
3192 i = 1;
3193 while (line->next) {
3194 Parrot_io_eprintf(pdb->debugger, "%li ", pdb->file->list_line + i);
3195 /* If it has a label print it */
3196 if (line->label)
3197 Parrot_io_eprintf(pdb->debugger, "L%li:\t", line->label->number);
3199 c = pdb->file->source + line->source_offset;
3201 while (*c != '\n')
3202 Parrot_io_eprintf(pdb->debugger, "%c", *(c++));
3204 Parrot_io_eprintf(pdb->debugger, "\n");
3206 line = line->next;
3208 if (i++ == n)
3209 break;
3212 if (--i != n)
3213 pdb->file->list_line = 0;
3214 else
3215 pdb->file->list_line += n;
3220 =item C<void PDB_eval(PARROT_INTERP, const char *command)>
3222 C<eval>s an instruction.
3224 =cut
3228 void
3229 PDB_eval(PARROT_INTERP, ARGIN(const char *command))
3231 ASSERT_ARGS(PDB_eval)
3232 /* This code is almost certainly wrong. The Parrot debugger needs love. */
3233 opcode_t *run = PDB_compile(interp, command);
3235 if (run)
3236 DO_OP(run, interp);
3241 =item C<opcode_t * PDB_compile(PARROT_INTERP, const char *command)>
3243 Compiles instructions with the PASM compiler.
3245 Appends an C<end> op.
3247 This may be called from C<PDB_eval> above or from the compile opcode
3248 which generates a malloced string.
3250 =cut
3254 PARROT_CAN_RETURN_NULL
3255 opcode_t *
3256 PDB_compile(PARROT_INTERP, ARGIN(const char *command))
3258 ASSERT_ARGS(PDB_compile)
3259 STRING *buf;
3260 const char *end = "\nend\n";
3261 STRING *key = CONST_STRING(interp, "PASM");
3262 PMC *compreg_hash = VTABLE_get_pmc_keyed_int(interp,
3263 interp->iglobals, IGLOBALS_COMPREG_HASH);
3264 PMC *compiler = VTABLE_get_pmc_keyed_str(interp, compreg_hash, key);
3266 if (!VTABLE_defined(interp, compiler)) {
3267 fprintf(stderr, "Couldn't find PASM compiler");
3268 return NULL;
3271 buf = Parrot_sprintf_c(interp, "%s%s", command, end);
3273 return VTABLE_invoke(interp, compiler, buf);
3278 =item C<static void dump_string(PARROT_INTERP, const STRING *s)>
3280 Dumps the buflen, flags, bufused, strlen, and offset associated with a string
3281 and the string itself.
3283 =cut
3287 static void
3288 dump_string(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
3290 ASSERT_ARGS(dump_string)
3291 if (!s)
3292 return;
3294 Parrot_io_eprintf(interp, "\tBuflen =\t%12ld\n", PObj_buflen(s));
3295 Parrot_io_eprintf(interp, "\tFlags =\t%12ld\n", PObj_get_FLAGS(s));
3296 Parrot_io_eprintf(interp, "\tBufused =\t%12ld\n", s->bufused);
3297 Parrot_io_eprintf(interp, "\tStrlen =\t%12ld\n", s->strlen);
3298 Parrot_io_eprintf(interp, "\tOffset =\t%12ld\n",
3299 (char*) s->strstart - (char*) PObj_bufstart(s));
3300 Parrot_io_eprintf(interp, "\tString =\t%S\n", s);
3305 =item C<void PDB_print(PARROT_INTERP, const char *command)>
3307 Print interp registers.
3309 =cut
3313 void
3314 PDB_print(PARROT_INTERP, ARGIN(const char *command))
3316 ASSERT_ARGS(PDB_print)
3317 const char * const s = GDB_P(interp->pdb->debugee, command);
3318 Parrot_io_eprintf(interp, "%s\n", s);
3324 =item C<void PDB_info(PARROT_INTERP)>
3326 Print the interpreter info.
3328 =cut
3332 void
3333 PDB_info(PARROT_INTERP)
3335 ASSERT_ARGS(PDB_info)
3337 /* If a debugger is created, use it for printing and use the
3338 * data in his debugee. Otherwise, use current interpreter
3339 * for both */
3340 Parrot_Interp itdeb = interp->pdb ? interp->pdb->debugger : interp;
3341 Parrot_Interp itp = interp->pdb ? interp->pdb->debugee : interp;
3343 Parrot_io_eprintf(itdeb, "Total memory allocated = %ld\n",
3344 interpinfo(itp, TOTAL_MEM_ALLOC));
3345 Parrot_io_eprintf(itdeb, "GC mark runs = %ld\n",
3346 interpinfo(itp, GC_MARK_RUNS));
3347 Parrot_io_eprintf(itdeb, "Lazy gc mark runs = %ld\n",
3348 interpinfo(itp, GC_LAZY_MARK_RUNS));
3349 Parrot_io_eprintf(itdeb, "GC collect runs = %ld\n",
3350 interpinfo(itp, GC_COLLECT_RUNS));
3351 Parrot_io_eprintf(itdeb, "Collect memory = %ld\n",
3352 interpinfo(itp, TOTAL_COPIED));
3353 Parrot_io_eprintf(itdeb, "Active PMCs = %ld\n",
3354 interpinfo(itp, ACTIVE_PMCS));
3355 Parrot_io_eprintf(itdeb, "Extended PMCs = %ld\n",
3356 interpinfo(itp, EXTENDED_PMCS));
3357 Parrot_io_eprintf(itdeb, "Timely GC PMCs = %ld\n",
3358 interpinfo(itp, IMPATIENT_PMCS));
3359 Parrot_io_eprintf(itdeb, "Total PMCs = %ld\n",
3360 interpinfo(itp, TOTAL_PMCS));
3361 Parrot_io_eprintf(itdeb, "Active buffers = %ld\n",
3362 interpinfo(itp, ACTIVE_BUFFERS));
3363 Parrot_io_eprintf(itdeb, "Total buffers = %ld\n",
3364 interpinfo(itp, TOTAL_BUFFERS));
3365 Parrot_io_eprintf(itdeb, "Header allocations since last collect = %ld\n",
3366 interpinfo(itp, HEADER_ALLOCS_SINCE_COLLECT));
3367 Parrot_io_eprintf(itdeb, "Memory allocations since last collect = %ld\n",
3368 interpinfo(itp, MEM_ALLOCS_SINCE_COLLECT));
3373 =item C<void PDB_help(PARROT_INTERP, const char *command)>
3375 Print the help text. "Help" with no arguments prints a list of commands.
3376 "Help xxx" prints information on command xxx.
3378 =cut
3382 void
3383 PDB_help(PARROT_INTERP, ARGIN(const char *command))
3385 ASSERT_ARGS(PDB_help)
3386 const DebuggerCmd *cmd;
3388 const char * cmdline = command;
3389 cmd = get_cmd(& cmdline);
3391 if (cmd) {
3392 Parrot_io_eprintf(interp->pdb->debugger, "%s\n", cmd->help);
3394 else {
3395 if (*cmdline == '\0') {
3396 unsigned int i;
3397 Parrot_io_eprintf(interp->pdb->debugger, "List of commands:\n");
3398 for (i= 0; i < sizeof (DebCmdList) / sizeof (DebuggerCmdList); ++i) {
3399 const DebuggerCmdList *cmdlist = DebCmdList + i;
3400 Parrot_io_eprintf(interp->pdb->debugger,
3401 " %-12s-- %s\n", cmdlist->name, cmdlist->cmd->shorthelp);
3403 Parrot_io_eprintf(interp->pdb->debugger, "\n"
3404 "Type \"help\" followed by a command name for full documentation.\n\n");
3407 else {
3408 Parrot_io_eprintf(interp->pdb->debugger, "Unknown command: %s\n", command);
3415 =item C<void PDB_backtrace(PARROT_INTERP)>
3417 Prints a backtrace of the interp's call chain.
3419 =cut
3423 void
3424 PDB_backtrace(PARROT_INTERP)
3426 ASSERT_ARGS(PDB_backtrace)
3427 STRING *str;
3428 PMC *old = PMCNULL;
3429 int rec_level = 0;
3431 /* information about the current sub */
3432 PMC *sub = interpinfo_p(interp, CURRENT_SUB);
3433 Parrot_Context *ctx = CONTEXT(interp);
3435 if (!PMC_IS_NULL(sub)) {
3436 str = Parrot_Context_infostr(interp, ctx);
3437 if (str) {
3438 Parrot_io_eprintf(interp, "%Ss", str);
3439 if (interp->code->annotations) {
3440 PMC *annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
3441 ctx->current_pc - interp->code->base.data + 1, NULL);
3442 if (!PMC_IS_NULL(annot)) {
3443 PMC *pfile = VTABLE_get_pmc_keyed_str(interp, annot,
3444 Parrot_str_new_constant(interp, "file"));
3445 PMC *pline = VTABLE_get_pmc_keyed_str(interp, annot,
3446 Parrot_str_new_constant(interp, "line"));
3447 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
3448 STRING *file = VTABLE_get_string(interp, pfile);
3449 INTVAL line = VTABLE_get_integer(interp, pline);
3450 Parrot_io_eprintf(interp, " (%Ss:%li)", file, (long)line);
3454 Parrot_io_eprintf(interp, "\n");
3458 /* backtrace: follow the continuation chain */
3459 while (1) {
3460 Parrot_cont *sub_cont;
3461 sub = ctx->current_cont;
3463 if (!sub)
3464 break;
3466 sub_cont = PMC_cont(sub);
3468 if (!sub_cont)
3469 break;
3471 str = Parrot_Context_infostr(interp, sub_cont->to_ctx);
3473 if (!str)
3474 break;
3476 /* recursion detection */
3477 if (!PMC_IS_NULL(old) && PMC_cont(old) &&
3478 PMC_cont(old)->to_ctx->current_pc ==
3479 PMC_cont(sub)->to_ctx->current_pc &&
3480 PMC_cont(old)->to_ctx->current_sub ==
3481 PMC_cont(sub)->to_ctx->current_sub) {
3482 ++rec_level;
3484 else if (rec_level != 0) {
3485 Parrot_io_eprintf(interp, "... call repeated %d times\n", rec_level);
3486 rec_level = 0;
3489 /* print the context description */
3490 if (rec_level == 0) {
3491 Parrot_io_eprintf(interp, "%Ss", str);
3492 if (interp->code->annotations) {
3493 PMC *annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
3494 sub_cont->to_ctx->current_pc - interp->code->base.data + 1, NULL);
3495 if (!PMC_IS_NULL(annot)) {
3496 PMC *pfile = VTABLE_get_pmc_keyed_str(interp, annot,
3497 Parrot_str_new_constant(interp, "file"));
3498 PMC *pline = VTABLE_get_pmc_keyed_str(interp, annot,
3499 Parrot_str_new_constant(interp, "line"));
3500 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
3501 STRING *file = VTABLE_get_string(interp, pfile);
3502 INTVAL line = VTABLE_get_integer(interp, pline);
3503 Parrot_io_eprintf(interp, " (%Ss:%li)", file, (long)line);
3507 Parrot_io_eprintf(interp, "\n");
3510 /* get the next Continuation */
3511 ctx = PMC_cont(sub)->to_ctx;
3512 old = sub;
3514 if (!ctx)
3515 break;
3518 if (rec_level != 0)
3519 Parrot_io_eprintf(interp, "... call repeated %d times\n", rec_level);
3523 * GDB functions
3525 * GDB_P gdb> pp $I0 print register I0 value
3527 * RT46139 more, more
3532 =item C<static const char* GDB_print_reg(PARROT_INTERP, int t, int n)>
3534 Used by GDB_P to convert register values for display. Takes register
3535 type and number as arguments.
3537 Returns a pointer to the start of the string, (except for PMCs, which
3538 print directly and return "").
3540 =cut
3544 PARROT_WARN_UNUSED_RESULT
3545 PARROT_CANNOT_RETURN_NULL
3546 PARROT_OBSERVER
3547 static const char*
3548 GDB_print_reg(PARROT_INTERP, int t, int n)
3550 ASSERT_ARGS(GDB_print_reg)
3552 if (n >= 0 && n < CONTEXT(interp)->n_regs_used[t]) {
3553 switch (t) {
3554 case REGNO_INT:
3555 return Parrot_str_from_int(interp, REG_INT(interp, n))->strstart;
3556 case REGNO_NUM:
3557 return Parrot_str_from_num(interp, REG_NUM(interp, n))->strstart;
3558 case REGNO_STR:
3559 return REG_STR(interp, n)->strstart;
3560 case REGNO_PMC:
3561 /* prints directly */
3562 trace_pmc_dump(interp, REG_PMC(interp, n));
3563 return "";
3564 default:
3565 break;
3568 return "no such reg";
3573 =item C<static const char* GDB_P(PARROT_INTERP, const char *s)>
3575 Used by PDB_print to print register values. Takes a pointer to the
3576 register name(s).
3578 Returns "" or error message.
3580 =cut
3584 PARROT_WARN_UNUSED_RESULT
3585 PARROT_CANNOT_RETURN_NULL
3586 PARROT_OBSERVER
3587 static const char*
3588 GDB_P(PARROT_INTERP, ARGIN(const char *s))
3590 ASSERT_ARGS(GDB_P)
3591 int t;
3592 char reg_type;
3594 /* Skip leading whitespace. */
3595 while (isspace((unsigned char)*s))
3596 s++;
3598 reg_type = (unsigned char) toupper((unsigned char)*s);
3599 switch (reg_type) {
3600 case 'I': t = REGNO_INT; break;
3601 case 'N': t = REGNO_NUM; break;
3602 case 'S': t = REGNO_STR; break;
3603 case 'P': t = REGNO_PMC; break;
3604 default: return "Need a register.";
3606 if (! s[1]) {
3607 /* Print all registers of this type. */
3608 const int max_reg = CONTEXT(interp)->n_regs_used[t];
3609 int n;
3611 for (n = 0; n < max_reg; n++) {
3612 /* this must be done in two chunks because PMC's print directly. */
3613 Parrot_io_eprintf(interp, "\n %c%d = ", reg_type, n);
3614 Parrot_io_eprintf(interp, "%s", GDB_print_reg(interp, t, n));
3616 return "";
3618 else if (s[1] && isdigit((unsigned char)s[1])) {
3619 const int n = atoi(s + 1);
3620 return GDB_print_reg(interp, t, n);
3622 else
3623 return "no such reg";
3629 =back
3631 =head1 SEE ALSO
3633 F<include/parrot/debugger.h>, F<src/parrot_debugger.c> and F<ops/debug.ops>.
3635 =head1 HISTORY
3637 =over 4
3639 =item Initial version by Daniel Grunblatt on 2002.5.19.
3641 =item Start of rewrite - leo 2005.02.16
3643 The debugger now uses its own interpreter. User code is run in
3644 Interp *debugee. We have:
3646 debug_interp->pdb->debugee->debugger
3649 +------------- := -----------+
3651 Debug commands are mostly run inside the C<debugger>. User code
3652 runs of course in the C<debugee>.
3654 =back
3656 =cut
3662 * Local variables:
3663 * c-file-style: "parrot"
3664 * End:
3665 * vim: expandtab shiftwidth=4: