2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/debug.c - Parrot debugging
11 This file implements Parrot debugging and is used by C<parrot_debugger>,
12 the Parrot debugger, and the C<debug> ops.
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"
34 #include "pmc/pmc_continuation.h"
36 /* Hand switched debugger tracing
37 * Set to 1 to enable tracing to stderr
40 #define TRACE_DEBUGGER 0
43 # define TRACEDEB_MSG(msg) fprintf(stderr, "%s\n", (msg))
45 # define TRACEDEB_MSG(msg)
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)
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
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
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)
103 PARROT_WARN_UNUSED_RESULT
104 static unsigned long get_ulong(ARGMOD(const char **cmd
), unsigned long def
)
105 __attribute__nonnull__(1)
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
),
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')
205 Parrot_eprintf(pdb
->debugger
, "Spurious arg\n");
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
))
252 if (pdb
->state
& PDB_ECHO
) {
253 TRACEDEB_MSG("Disabling echo");
254 pdb
->state
&= ~PDB_ECHO
;
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
))
279 if (pdb
->state
& PDB_GCDEBUG
) {
280 TRACEDEB_MSG("Disabling gcdebug mode");
281 pdb
->state
&= ~PDB_GCDEBUG
;
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
))
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
))
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
))
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
);
392 debugger_func_t func
;
393 PARROT_OBSERVER
const char * const shorthelp
;
394 PARROT_OBSERVER
const char * const help
;
397 static const DebuggerCmd
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\
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."
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."
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\"."
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."
439 "disassemble the bytecode",
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."
450 "reenable a disabled breakpoint",
451 "Re-enable a disabled breakpoint."
455 "run an instruction",
456 "No documentation yet"
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."
468 "Print a list of available commands."
472 "print interpreter information",
473 "Print information about the current interpreter"
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
,
489 "load a source code file",
490 "Load a source code file."
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."
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."
516 "Run (or restart) the program being debugged.\n\n\
517 Arguments specified after \"run\" are passed as command line arguments to\n\
522 "interprets a file as user commands",
523 "Interprets a file s user commands.\n\
525 (pdb) script file.script"
530 "Print a stack trace of the parrot VM"
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\
545 struct DebuggerCmdList
{
546 PARROT_OBSERVER
const char * const name
;
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)>
586 PARROT_WARN_UNUSED_RESULT
587 PARROT_CAN_RETURN_NULL
588 static const DebuggerCmd
*
589 get_cmd(ARGIN_NULLOK(const char **cmd
))
593 const char * const start
= skip_whitespace(*cmd
);
594 const char *next
= start
;
601 for (; (c
= *next
) != '\0' && !isspace((unsigned char)c
); ++next
)
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]) {
613 if (strncmp(*cmd
, cmdlist
->name
, l
) == 0) {
614 if (strlen(cmdlist
->name
) == l
) {
626 *cmd
= skip_whitespace(next
);
627 return DebCmdList
[found
].cmd
;
635 =item C<static const char * skip_whitespace(const char *cmd)>
641 PARROT_WARN_UNUSED_RESULT
642 PARROT_CANNOT_RETURN_NULL
644 skip_whitespace(ARGIN(const char *cmd
))
646 ASSERT_ARGS(skip_whitespace
)
647 while (*cmd
&& isspace((unsigned char)*cmd
))
654 =item C<static unsigned long get_uint(const char **cmd, unsigned int def)>
661 PARROT_WARN_UNUSED_RESULT
663 get_uint(ARGMOD(const char **cmd
), unsigned int def
)
665 ASSERT_ARGS(get_uint
)
667 unsigned int result
= strtoul(skip_whitespace(* cmd
), & cmdnext
, 0);
677 =item C<static unsigned long get_ulong(const char **cmd, unsigned long def)>
684 PARROT_WARN_UNUSED_RESULT
686 get_ulong(ARGMOD(const char **cmd
), unsigned long def
)
688 ASSERT_ARGS(get_ulong
)
690 unsigned long result
= strtoul(skip_whitespace(* cmd
), & cmdnext
, 0);
691 if (cmdnext
!= * cmd
)
700 =item C<static void chop_newline(char * buf)>
702 If the C string argument end with a newline, delete it.
709 chop_newline(ARGMOD(char * buf
))
711 ASSERT_ARGS(chop_newline
)
714 if (l
> 0 && buf
[l
- 1] == '\n')
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>.
730 PARROT_CAN_RETURN_NULL
731 PARROT_WARN_UNUSED_RESULT
733 nextarg(ARGIN_NULLOK(const char *command
))
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.
741 while (isalnum((unsigned char) *command
) || *command
== ',' || *command
== ']')
744 /* eat as much space as possible */
745 command
= skip_whitespace(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.)
762 PARROT_CANNOT_RETURN_NULL
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),
770 while (*str
&& !isspace((unsigned char) *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.
788 PARROT_CANNOT_RETURN_NULL
789 PARROT_WARN_UNUSED_RESULT
791 parse_int(ARGIN(const char *str
), ARGOUT(int *intP
))
793 ASSERT_ARGS(parse_int
)
796 *intP
= strtol(str
, &end
, 0);
803 =item C<static const char * parse_string(PARROT_INTERP, const char *str, STRING
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>.
814 PARROT_CAN_RETURN_NULL
815 PARROT_WARN_UNUSED_RESULT
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 */
831 /* parse while there's no closing quote */
832 while (*str
&& *str
!= '"') {
833 /* skip any potentially escaped quotes */
834 if (*str
== '\\' && str
[1])
840 /* create the output STRING */
841 *strP
= string_make(interp
, string_start
, (UINTVAL
)(str
- string_start
),
844 /* skip the closing quote */
853 =item C<static const char* parse_key(PARROT_INTERP, const char *str, PMC
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.
863 PARROT_CAN_RETURN_NULL
864 PARROT_WARN_UNUSED_RESULT
866 parse_key(PARROT_INTERP
, ARGIN(const char *str
), ARGOUT(PMC
**keyP
))
868 ASSERT_ARGS(parse_key
)
869 /* clear output parameter */
872 /* make sure it's a key */
879 /* if this is a string key, create a Parrot STRING */
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
)) {
888 str
= parse_int(str
, &value
);
889 *keyP
= key_new_integer(interp
, (INTVAL
) value
);
891 /* unsupported case; neither a string nor a numeric key */
896 /* hm, but if this doesn't match, it's probably an error */
897 /* XXX str can be NULL from parse_string() */
901 /* skip the closing brace on the key */
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.
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.
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.
974 Parrot_debugger_init(PARROT_INTERP
)
976 ASSERT_ARGS(Parrot_debugger_init
)
977 TRACEDEB_MSG("Parrot_debugger_init");
980 PDB_t
*pdb
= mem_allocate_zeroed_typed(PDB_t
);
981 Parrot_Interp debugger
= Parrot_new(interp
);
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.
1010 Parrot_debugger_destroy(PARROT_INTERP
)
1012 ASSERT_ARGS(Parrot_debugger_destroy
)
1014 Free all debugger allocated resources.
1016 PDB_t
*pdb
= interp
->pdb
;
1018 TRACEDEB_MSG("Parrot_debugger_destroy");
1021 PARROT_ASSERT(pdb
->debugee
== interp
);
1023 mem_sys_free(pdb
->last_command
);
1024 mem_sys_free(pdb
->cur_command
);
1032 =item C<void Parrot_debugger_load(PARROT_INTERP, STRING *filename)>
1034 Loads a Parrot source file for the current program.
1042 Parrot_debugger_load(PARROT_INTERP
, ARGIN_NULLOK(STRING
*filename
))
1044 ASSERT_ARGS(Parrot_debugger_load
)
1047 TRACEDEB_MSG("Parrot_debugger_load");
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)>
1069 Parrot_debugger_start(PARROT_INTERP
, ARGIN(opcode_t
* cur_opcode
))
1071 ASSERT_ARGS(Parrot_debugger_start
)
1072 TRACEDEB_MSG("Parrot_debugger_start");
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
1109 RT #42377: clone the interpreter to allow people to play into the
1110 debugger and then continue the normal execution of the program.
1118 Parrot_debugger_break(PARROT_INTERP
, ARGIN(opcode_t
* cur_opcode
))
1120 ASSERT_ARGS(Parrot_debugger_break
)
1121 TRACEDEB_MSG("Parrot_debugger_break");
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");
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); */
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 >>.
1175 PDB_get_command(PARROT_INTERP
)
1177 ASSERT_ARGS(PDB_get_command
)
1181 PDB_t
* const pdb
= interp
->pdb
;
1183 /***********************************
1188 ***********************************/
1190 /* flush the buffered data */
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];
1204 if (fgets(buf
, DEBUG_CMD_BUFFER_LENGTH
, fd
) == NULL
) {
1205 close_script_file(interp
);
1211 fprintf(stderr
, "script (%lu): '%s'\n", pdb
->script_line
, buf
);
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
);
1224 fprintf(stderr
, "(script) %s\n", buf
);
1227 strcpy(pdb
->cur_command
, buf
);
1231 /* update the last command */
1232 if (pdb
->cur_command
[0] != '\0')
1233 strcpy(pdb
->last_command
, pdb
->cur_command
);
1237 c
= pdb
->cur_command
;
1239 /*Parrot_io_eprintf(pdb->debugger, "\n(pdb) ");*/
1240 Parrot_io_eprintf(pdb
->debugger
, "\n");
1242 /* skip leading whitespace */
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
);
1261 Parrot_str_free_cstring(aux
);
1266 /* generate string (no more than buffer length) */
1268 while (ch != EOF && ch != '\n' && (i < DEBUG_CMD_BUFFER_LENGTH)) {
1270 ch = fgetc(tmp_stdin);
1282 =item C<void PDB_script_file(PARROT_INTERP, const char *command)>
1284 Interprets the contents of a file as user input commands
1292 PDB_script_file(PARROT_INTERP
, ARGIN(const char *command
))
1294 ASSERT_ARGS(PDB_script_file
)
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");
1306 Parrot_io_eprintf(interp
->pdb
->debugger
,
1307 "Error reading script file %s.\n",
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)>
1322 Hash the command to make a simple switch calling the correct handler.
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
);
1344 (* cmd
->func
)(pdb
, cmdline
);
1348 if (*cmdline
== '\0') {
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\".");
1358 fprintf(stderr
, " (parse_command result: %li)", c
);
1360 close_script_file(interp
);
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.
1379 PDB_next(PARROT_INTERP
, ARGIN_NULLOK(const char *command
))
1381 ASSERT_ARGS(PDB_next
)
1383 PDB_t
* const pdb
= interp
->pdb
;
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 */
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
);
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
;
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.
1442 PDB_trace(PARROT_INTERP
, ARGIN_NULLOK(const char *command
))
1444 ASSERT_ARGS(PDB_trace
)
1446 PDB_t
* const pdb
= interp
->pdb
;
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
;
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
;
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)>
1497 static unsigned short
1498 condition_regtype(ARGIN(const char *cmd
))
1500 ASSERT_ARGS(condition_regtype
)
1504 return PDB_cond_int
;
1507 return PDB_cond_num
;
1510 return PDB_cond_str
;
1513 return PDB_cond_pmc
;
1521 =item C<PDB_condition_t * PDB_cond(PARROT_INTERP, const char *command)>
1523 Analyzes a condition from the user input.
1529 PARROT_CAN_RETURN_NULL
1531 PDB_cond(PARROT_INTERP
, ARGIN(const char *command
))
1533 ASSERT_ARGS(PDB_cond
)
1534 PDB_condition_t
*condition
;
1536 char str
[DEBUG_CMD_BUFFER_LENGTH
+ 1];
1537 unsigned short cond_argleft
;
1538 unsigned short cond_type
;
1539 unsigned char regleft
;
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");
1550 command
= skip_whitespace(command
);
1552 fprintf(stderr
, "PDB_trace: '%s'\n", command
);
1555 cond_argleft
= condition_regtype(command
);
1557 /* get the register number */
1559 regleft
= (unsigned char)get_uint(&command
, 0);
1560 if (auxcmd
== command
) {
1561 Parrot_io_eprintf(interp
->pdb
->debugger
, "Invalid register\n");
1565 /* Now the condition */
1566 command
= skip_whitespace(command
);
1569 if (*(command
+ 1) == '=')
1570 cond_type
= PDB_cond_ge
;
1572 cond_type
= PDB_cond_gt
;
1575 if (*(command
+ 1) == '=')
1576 cond_type
= PDB_cond_le
;
1578 cond_type
= PDB_cond_lt
;
1581 if (*(command
+ 1) == '=')
1582 cond_type
= PDB_cond_eq
;
1587 if (*(command
+ 1) == '=')
1588 cond_type
= PDB_cond_ne
;
1593 if (cond_argleft
!= PDB_cond_str
&& cond_argleft
!= PDB_cond_pmc
) {
1594 Parrot_io_eprintf(interp
->pdb
->debugger
, "Invalid null condition\n");
1597 cond_type
= PDB_cond_notnull
;
1600 INV_COND
: Parrot_io_eprintf(interp
->pdb
->debugger
, "Invalid condition\n");
1604 /* if there's an '=', skip it */
1605 if (*(command
+ 1) == '=')
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");
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
);
1636 /* Now we check and store the register number */
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
);
1645 if (reg_number
< 0) {
1646 Parrot_io_eprintf(interp
->pdb
->debugger
, "Out-of-bounds register\n");
1647 mem_sys_free(condition
);
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
];
1671 fprintf(stderr
, "PDB_break: '%s'\n", str
);
1673 condition
->value
= string_make(interp
, str
, (UINTVAL
)(i
- 1),
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
);
1693 =item C<void PDB_watchpoint(PARROT_INTERP, const char *command)>
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
);
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.
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
;
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 */
1747 /* If no line number was specified, set it at the current line */
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
++)
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
);
1765 /* Get the line to set it */
1766 line
= pdb
->file
->line
;
1768 while (line
->opcode
!= pdb
->cur_opcode
) {
1771 Parrot_io_eprintf(pdb
->debugger
,
1772 "No current line found and no line number specified\n");
1777 /* Skip lines that are not related to an opcode */
1778 while (line
&& !line
->opcode
)
1780 /* Abort if the line number provided doesn't exist */
1782 Parrot_io_eprintf(pdb
->debugger
,
1783 "Can't set a breakpoint at line number %li\n", ln
);
1787 breakpos
= line
->opcode
;
1790 breakpos
= interp
->code
->base
.data
+ ln
;
1793 /* Allocate the new break point */
1794 newbreak
= mem_allocate_zeroed_typed(PDB_breakpoint_t
);
1797 /*command = skip_command(command);*/
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
))
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) */
1823 /* Add the breakpoint to the end of the list */
1825 lbreak
= & pdb
->breakpoint
;
1827 bp_id
= (*lbreak
)->id
+ 1;
1828 lbreak
= & (*lbreak
)->next
;
1830 newbreak
->prev
= *lbreak
;
1832 newbreak
->id
= bp_id
;
1834 /* Show breakpoint position */
1836 Parrot_io_eprintf(pdb
->debugger
, "Breakpoint %li at", newbreak
->id
);
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)>
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
);
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)>
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
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? */
1912 ln
= get_ulong(& command
, 0);
1915 if (!pdb
->breakpoint
) {
1916 Parrot_io_eprintf(pdb
->debugger
, "No breakpoints to skip\n");
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);
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
;
1939 runops_int(pdb
->debugee
, pdb
->debugee
->code
->base
.data
- pdb
->cur_opcode
);
1940 if (!pdb
->cur_opcode
)
1941 (void)PDB_program_end(interp
);
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
1953 Find breakpoint number N; returns C<NULL> if the breakpoint doesn't
1954 exist or if no breakpoint was specified.
1960 PARROT_CAN_RETURN_NULL
1961 PARROT_WARN_UNUSED_RESULT
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
;
1975 Parrot_io_eprintf(interp
->pdb
->debugger
, "No breakpoint number %ld", n
);
1982 /* Report an appropriate error */
1984 Parrot_io_eprintf(interp
->pdb
->debugger
, "Not a valid breakpoint");
1986 Parrot_io_eprintf(interp
->pdb
->debugger
, "No breakpoint specified");
1994 =item C<void PDB_disable_breakpoint(PARROT_INTERP, const char *command)>
1996 Disable a breakpoint; it can be reenabled with the enable command.
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. */
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
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.
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
);
2052 const PDB_line_t
*line
= interp
->pdb
->file
->line
;
2054 while (line
->opcode
!= breakpoint
->pc
)
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
;
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.
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 */
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.
2128 PDB_skip_breakpoint(PARROT_INTERP
, unsigned long i
)
2130 ASSERT_ARGS(PDB_skip_breakpoint
)
2132 fprintf(stderr
, "PDB_skip_breakpoint: %li\n", i
);
2135 interp
->pdb
->breakpoint_skip
= i
;
2140 =item C<char PDB_program_end(PARROT_INTERP)>
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");
2165 =item C<char PDB_check_condition(PARROT_INTERP, const PDB_condition_t
2168 Returns true if the condition was met.
2174 PARROT_WARN_UNUSED_RESULT
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");
2185 if (condition
->type
& PDB_cond_int
) {
2187 if (condition
->reg
>= ctx
->n_regs_used
[REGNO_INT
])
2189 i
= CTX_REG_INT(ctx
, condition
->reg
);
2191 if (condition
->type
& PDB_cond_const
)
2192 j
= *(INTVAL
*)condition
->value
;
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
)))
2206 else if (condition
->type
& PDB_cond_num
) {
2209 if (condition
->reg
>= ctx
->n_regs_used
[REGNO_NUM
])
2211 k
= CTX_REG_NUM(ctx
, condition
->reg
);
2213 if (condition
->type
& PDB_cond_const
)
2214 l
= *(FLOATVAL
*)condition
->value
;
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
)))
2228 else if (condition
->type
& PDB_cond_str
) {
2231 if (condition
->reg
>= ctx
->n_regs_used
[REGNO_STR
])
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
;
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)))
2259 else if (condition
->type
& PDB_cond_pmc
) {
2262 if (condition
->reg
>= ctx
->n_regs_used
[REGNO_PMC
])
2264 m
= CTX_REG_PMC(ctx
, condition
->reg
);
2266 if (condition
->type
& PDB_cond_notnull
)
2267 return ! PMC_IS_NULL(m
);
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.
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
)
2294 breakpoint
= breakpoint
->next
;
2301 =item C<char PDB_break(PARROT_INTERP)>
2303 Returns true if we have to stop running.
2309 PARROT_WARN_UNUSED_RESULT
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
;
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
;
2342 breakpoint
= current_breakpoint(pdb
);
2344 /* If we have to skip breakpoints, do so. */
2345 if (pdb
->breakpoint_skip
) {
2346 TRACEDEB_MSG("PDB_break skipping");
2347 pdb
->breakpoint_skip
--;
2351 if (breakpoint
->skip
< 0)
2354 /* Check if there is a condition for this breakpoint */
2355 if ((breakpoint
->condition
) &&
2356 (!PDB_check_condition(interp
, breakpoint
->condition
)))
2359 TRACEDEB_MSG("PDB_break stopping");
2361 /* Add the STOPPED state and stop */
2362 pdb
->state
|= PDB_STOPPED
;
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.
2381 PARROT_WARN_UNUSED_RESULT
2382 PARROT_CAN_RETURN_NULL
2385 PDB_escape(ARGIN(const char *string
), UINTVAL length
)
2387 ASSERT_ARGS(PDB_escape
)
2391 length
= length
> 20 ? 20 : length
;
2392 end
= string
+ length
;
2394 /* Return if there is no string to escape*/
2398 fill
= _new
= (char *)mem_sys_allocate(length
* 2 + 1);
2400 for (; string
< end
; string
++) {
2431 *(fill
++) = *string
;
2443 =item C<int PDB_unescape(char *string)>
2445 Do inplace unescape of C<\r>, C<\n>, C<\t>, C<\a> and C<\\>.
2452 PDB_unescape(ARGMOD(char *string
))
2454 ASSERT_ARGS(PDB_unescape
)
2457 for (; *string
; string
++) {
2460 if (*string
== '\\') {
2464 switch (string
[1]) {
2486 for (i
= 1; fill
[i
+ 1]; i
++)
2487 fill
[i
] = fill
[i
+ 1];
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)>
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
),
2514 ASSERT_ARGS(PDB_disassemble_op
)
2519 /* Write the opcode name */
2520 const char * p
= full_name
? info
->full_name
: info
->name
;
2522 TRACEDEB_MSG("PDB_disassemble_op");
2531 /* Concat the arguments */
2532 for (j
= 1; j
< info
->op_count
; j
++) {
2536 PARROT_ASSERT(size
+ 2 < space
);
2538 switch (info
->types
[j
- 1]) {
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
)) {
2558 i
= PDB_add_label(file
, op
, op
[j
]);
2560 else if (code_start
) {
2563 i
= op
[j
] + (op
- code_start
);
2572 /* Convert the integer to a string */
2577 PARROT_ASSERT(size
+ 20 < space
);
2579 size
+= sprintf(&dest
[size
], INTVAL_FMT
, i
);
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
);
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
);
2600 strcpy(&dest
[size
], escaped
);
2601 size
+= strlen(escaped
);
2602 mem_sys_free(escaped
);
2608 Parrot_snprintf(interp
, buf
, sizeof (buf
), "PMC_CONST(%d)", op
[j
]);
2609 strcpy(&dest
[size
], buf
);
2610 size
+= strlen(buf
);
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
);
2621 PMC
* k
= interp
->code
->const_table
->constants
[op
[j
]]->u
.key
;
2622 dest
[size
- 1] = '[';
2624 switch (PObj_get_FLAGS(k
)) {
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
);
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
);
2639 case KEY_string_FLAG
:
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
)));
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
);
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
);
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
);
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
);
2679 GETATTR_Key_next_key(interp
, k
, k
);
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
);
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
);
2701 Parrot_ex_throw_from_c_args(interp
, NULL
, 1, "Unknown opcode type");
2704 if (j
!= info
->op_count
- 1)
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
)
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
)
2721 if (specialop
> 0) {
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
[] = {
2737 " :flat", /* should be :slurpy for args */
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
++) {
2751 const int sig_value
= VTABLE_get_integer_keyed_int(interp
, sig
, j
);
2753 /* Print the register name, e.g. P37. */
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]);
2761 /* Add flags, if we have any. */
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"))
2774 : flag_names
[flag_idx
];
2778 if (flags
& 1 && *flag_string
) {
2779 const size_t n
= strlen(flag_string
);
2780 strcpy(&buf
[idx
], flag_string
);
2788 /* Add it to dest. */
2790 strcpy(&dest
[size
], buf
);
2791 size
+= strlen(buf
);
2801 =item C<void PDB_disassemble(PARROT_INTERP, const char *command)>
2803 Disassemble the bytecode.
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
;
2817 PDB_line_t
*pline
, *newline
;
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 */
2832 PDB_free_file(interp
, pdb
->file
);
2836 pfile
->line
= pline
;
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
) {
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);
2854 pfile
->size
+= size
;
2855 pfile
->source
[pfile
->size
- 1] = '\n';
2857 /* Store the opcode of this line */
2859 n
= interp
->op_info_table
[*pc
].op_count
;
2861 ADD_OP_VAR_PART(interp
, interp
->code
, 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
;
2871 pline
->source_offset
= pfile
->size
;
2874 /* Add labels to the lines they belong to */
2875 label
= pfile
->label
;
2878 /* Get the line to apply the label */
2879 pline
= pfile
->line
;
2881 while (pline
&& pline
->opcode
!= label
->opcode
)
2882 pline
= pline
->next
;
2885 Parrot_io_eprintf(pdb
->debugger
,
2886 "Label number %li out of bounds.\n", label
->number
);
2888 PDB_free_file(interp
, pfile
);
2892 pline
->label
= label
;
2894 label
= label
->next
;
2897 pdb
->state
|= PDB_SRC_LOADED
;
2903 =item C<long PDB_add_label(PDB_file_t *file, const opcode_t *cur_opcode,
2906 Add a label to the label list.
2913 PDB_add_label(ARGMOD(PDB_file_t
*file
), ARGIN(const opcode_t
*cur_opcode
),
2916 ASSERT_ARGS(PDB_add_label
)
2918 PDB_label_t
*label
= file
->label
;
2920 /* See if there is already a label at this line */
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
;
2935 label
= label
->next
;
2937 _new
->number
= label
->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.
2959 PDB_free_file(SHIM_INTERP
, ARGIN_NULLOK(PDB_file_t
*file
))
2961 ASSERT_ARGS(PDB_free_file
)
2963 /* Free all of the allocated line structures */
2964 PDB_line_t
*line
= file
->line
;
2969 PDB_line_t
* const nline
= line
->next
;
2974 /* Free all of the allocated label structures */
2975 label
= file
->label
;
2978 PDB_label_t
* const nlabel
= label
->next
;
2980 mem_sys_free(label
);
2984 /* Free the remaining allocated portions of the file structure */
2985 if (file
->sourcefilename
)
2986 mem_sys_free(file
->sourcefilename
);
2989 mem_sys_free(file
->source
);
2999 =item C<void PDB_load_source(PARROT_INTERP, const char *command)>
3001 Load a source code file.
3009 PDB_load_source(PARROT_INTERP
, ARGIN(const char *command
))
3011 ASSERT_ARGS(PDB_load_source
)
3013 char f
[DEBUG_CMD_BUFFER_LENGTH
+ 1];
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 */
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
)
3034 for (i
= 0; command
[j
]; i
++, j
++)
3040 file
= fopen(f
, "r");
3042 /* abort if fopen failed */
3044 Parrot_io_eprintf(pdb
->debugger
, "Unable to load '%s'\n", f
);
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
;
3055 PARROT_ASSERT(interp
->op_info_table
);
3058 while ((c
= fgetc(file
)) != EOF
) {
3060 if (++size
== 1024) {
3061 pfile
->source
= (char *)mem_sys_realloc(pfile
->source
,
3062 (size_t)pfile
->size
+ 1024);
3065 pfile
->source
[pfile
->size
] = (char)c
;
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
;
3077 ADD_OP_VAR_PART(interp
, interp
->code
, 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
)
3085 newline
->number
= pline
->number
+ 1;
3086 pline
->next
= newline
;
3088 pline
->source_offset
= pfile
->size
;
3089 pline
->opcode
= NULL
;
3090 pline
->label
= NULL
;
3096 pdb
->state
|= PDB_SRC_LOADED
;
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.
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.
3123 PARROT_WARN_UNUSED_RESULT
3124 PARROT_PURE_FUNCTION
3126 PDB_hasinstruction(ARGIN(const char *c
))
3128 ASSERT_ARGS(PDB_hasinstruction
)
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
== '"') {
3138 else if (*c
== ':') {
3139 /* this is a label. RT #46137 right? */
3151 =item C<void PDB_list(PARROT_INTERP, const char *command)>
3153 Show lines from the source code file.
3160 PDB_list(PARROT_INTERP
, ARGIN(const char *command
))
3162 ASSERT_ARGS(PDB_list
)
3164 unsigned long line_number
;
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");
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 */
3187 line
= pdb
->file
->line
;
3189 for (i
= 0; i
< pdb
->file
->list_line
&& line
->next
; i
++)
3193 while (line
->next
) {
3194 Parrot_io_eprintf(pdb
->debugger
, "%li ", pdb
->file
->list_line
+ i
);
3195 /* If it has a label print it */
3197 Parrot_io_eprintf(pdb
->debugger
, "L%li:\t", line
->label
->number
);
3199 c
= pdb
->file
->source
+ line
->source_offset
;
3202 Parrot_io_eprintf(pdb
->debugger
, "%c", *(c
++));
3204 Parrot_io_eprintf(pdb
->debugger
, "\n");
3213 pdb
->file
->list_line
= 0;
3215 pdb
->file
->list_line
+= n
;
3220 =item C<void PDB_eval(PARROT_INTERP, const char *command)>
3222 C<eval>s an instruction.
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
);
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.
3254 PARROT_CAN_RETURN_NULL
3256 PDB_compile(PARROT_INTERP
, ARGIN(const char *command
))
3258 ASSERT_ARGS(PDB_compile
)
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");
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.
3288 dump_string(PARROT_INTERP
, ARGIN_NULLOK(const STRING
*s
))
3290 ASSERT_ARGS(dump_string
)
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.
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.
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
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.
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
);
3392 Parrot_io_eprintf(interp
->pdb
->debugger
, "%s\n", cmd
->help
);
3395 if (*cmdline
== '\0') {
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");
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.
3424 PDB_backtrace(PARROT_INTERP
)
3426 ASSERT_ARGS(PDB_backtrace
)
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
);
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 */
3460 Parrot_cont
*sub_cont
;
3461 sub
= ctx
->current_cont
;
3466 sub_cont
= PMC_cont(sub
);
3471 str
= Parrot_Context_infostr(interp
, sub_cont
->to_ctx
);
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
) {
3484 else if (rec_level
!= 0) {
3485 Parrot_io_eprintf(interp
, "... call repeated %d times\n", rec_level
);
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
;
3519 Parrot_io_eprintf(interp
, "... call repeated %d times\n", rec_level
);
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 "").
3544 PARROT_WARN_UNUSED_RESULT
3545 PARROT_CANNOT_RETURN_NULL
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
]) {
3555 return Parrot_str_from_int(interp
, REG_INT(interp
, n
))->strstart
;
3557 return Parrot_str_from_num(interp
, REG_NUM(interp
, n
))->strstart
;
3559 return REG_STR(interp
, n
)->strstart
;
3561 /* prints directly */
3562 trace_pmc_dump(interp
, REG_PMC(interp
, n
));
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
3578 Returns "" or error message.
3584 PARROT_WARN_UNUSED_RESULT
3585 PARROT_CANNOT_RETURN_NULL
3588 GDB_P(PARROT_INTERP
, ARGIN(const char *s
))
3594 /* Skip leading whitespace. */
3595 while (isspace((unsigned char)*s
))
3598 reg_type
= (unsigned char) toupper((unsigned char)*s
);
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.";
3607 /* Print all registers of this type. */
3608 const int max_reg
= CONTEXT(interp
)->n_regs_used
[t
];
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
));
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
);
3623 return "no such reg";
3633 F<include/parrot/debugger.h>, F<src/parrot_debugger.c> and F<ops/debug.ops>.
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>.
3663 * c-file-style: "parrot"
3665 * vim: expandtab shiftwidth=4: