1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
|
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Felipe Pena <felipe@php.net> |
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
| Authors: Bob Weinand <bwoebi@php.net> |
| Authors: Terry Ellison <terry@ellisons.org.uk> |
+----------------------------------------------------------------------+
*/
#include "phpdbg.h"
#include "phpdbg_help.h"
#include "phpdbg_prompt.h"
#include "zend.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
/* {{{ Commands Table */
#define PHPDBG_COMMAND_HELP_D(name, tip, alias, action) \
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, action, &phpdbg_prompt_commands[16], 0, NULL, (bool) 0}
const phpdbg_command_t phpdbg_help_commands[] = {
PHPDBG_COMMAND_HELP_D(aliases, "show alias list", 'a', phpdbg_do_help_aliases),
PHPDBG_COMMAND_HELP_D(options, "command line options", 0, NULL),
PHPDBG_COMMAND_HELP_D(overview, "help overview", 0, NULL),
PHPDBG_COMMAND_HELP_D(phpdbginit, "phpdbginit file format", 0, NULL),
PHPDBG_COMMAND_HELP_D(syntax, "syntax overview", 0, NULL),
PHPDBG_END_COMMAND
}; /* }}} */
/* {{{ pretty_print. Formatting escapes and wrapping text in a string before printing it. */
static void pretty_print(const char *text)
{
char *new, *q;
const char *prompt_escape = phpdbg_get_prompt();
size_t prompt_escape_len = strlen(prompt_escape);
size_t prompt_len = strlen(PHPDBG_G(prompt)[0]);
const char *bold_on_escape = PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "\033[1m" : "";
const char *bold_off_escape = PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "\033[0m" : "";
size_t bold_escape_len = strlen(bold_on_escape);
uint32_t term_width = phpdbg_get_terminal_width();
uint32_t size = 0;
int in_bold = 0;
char *last_new_blank = NULL; /* position in new buffer of last blank char */
uint32_t last_blank_count = 0; /* printable char offset of last blank char */
uint32_t line_count = 0; /* number printable chars on current line */
/* First pass calculates a safe size for the pretty print version */
const char *p;
for (p = text; *p; p++) {
if (UNEXPECTED(p[0] == '*') && p[1] == '*') {
size += bold_escape_len - 2;
p++;
} else if (UNEXPECTED(p[0] == '$') && p[1] == 'P') {
size += prompt_escape_len - 2;
p++;
} else if (UNEXPECTED(p[0] == '\\')) {
p++;
}
}
size += (p-text)+1;
new = emalloc(size);
/*
* Second pass substitutes the bold and prompt escape sequences and line wrap
*
* ** toggles bold on and off if PHPDBG_IS_COLOURED flag is set
* $P substitutes the prompt sequence
* Lines are wrapped by replacing the last blank with a CR before <term width>
* characters. (This defaults to 100 if the width can't be detected). In the
* pathological case where no blanks are found, then the wrap occurs at the
* first blank.
*/
for (p = text, q = new; *p; p++) {
if (UNEXPECTED(*p == ' ')) {
last_new_blank = q;
last_blank_count = line_count++;
*q++ = ' ';
} else if (UNEXPECTED(*p == '\n')) {
last_new_blank = NULL;
*q++ = *p;
last_blank_count = 0;
line_count = 0;
} else if (UNEXPECTED(p[0] == '*') && p[1] == '*') {
if (bold_escape_len) {
in_bold = !in_bold;
q = zend_mempcpy(q, in_bold ? bold_on_escape : bold_off_escape, bold_escape_len);
/* bold on/off has zero print width so line count is unchanged */
}
p++;
} else if (UNEXPECTED(p[0] == '$') && p[1] == 'P') {
q = zend_mempcpy(q, prompt_escape, prompt_escape_len);
line_count += prompt_len;
p++;
} else if (UNEXPECTED(p[0] == '\\')) {
p++;
*q++ = *p;
line_count++;
} else {
*q++ = *p;
line_count++;
}
if (UNEXPECTED(line_count>=term_width) && last_new_blank) {
*last_new_blank = '\n';
last_new_blank = NULL;
line_count -= last_blank_count;
last_blank_count = 0;
}
}
*q++ = '\0';
if ((q-new)>size) {
phpdbg_error("Output overrun of %" PRIu32 " bytes", (uint32_t) ((q - new) - size));
}
phpdbg_out("%s\n", new);
efree(new);
} /* }}} */
/* {{{ summary_print. Print a summary line giving, the command, its alias and tip */
void summary_print(phpdbg_command_t const * const cmd)
{
char *summary;
spprintf(&summary, 0, "Command: **%s** Alias: **%c** **%s**\n", cmd->name, cmd->alias, cmd->tip);
pretty_print(summary);
efree(summary);
}
/* {{{ get_help. Retries and formats text from the phpdbg help text table */
static const char *get_help(const char * const key)
{
const phpdbg_help_text_t *p;
/* Note that phpdbg_help_text is not assumed to be collated in key order. This is an
inconvenience that means that help can't be logically grouped Not worth
the savings */
for (p = phpdbg_help_text; p->key; p++) {
if (!strcmp(p->key, key)) {
return p->text;
}
}
return ""; /* return empty string to denote no match found */
} /* }}} */
/* {{{ get_command. Return number of matching commands from a command table.
* Unlike the command parser, the help search is sloppy that is partial matches can occur
* * Any single character key is taken as an alias.
* * Other keys are matched again the table on the first len characters.
* * This means that non-unique keys can generate multiple matches.
* * The first matching command is returned as an OUT parameter. *
* The rationale here is to assist users in finding help on commands. So unique matches
* will be used to generate a help message but non-unique one will be used to list alternatives.
*/
static int get_command(
const char *key, size_t len, /* pointer and length of key */
phpdbg_command_t const **command, /* address of first matching command */
phpdbg_command_t const * commands /* command table to be scanned */
)
{
const phpdbg_command_t *c;
unsigned int num_matches = 0;
if (len == 1) {
for (c=commands; c->name; c++) {
if (c->alias == key[0]) {
num_matches++;
if ( num_matches == 1 && command) {
*command = c;
}
}
}
} else {
for (c=commands; c->name; c++) {
if (!strncmp(c->name, key, len)) {
++num_matches;
if ( num_matches == 1 && command) {
*command = c;
}
}
}
}
return num_matches;
} /* }}} */
void phpdbg_do_help_cmd(const char *type) { /* {{{ */
const char *help;
if (!type) {
pretty_print(get_help("overview!"));
return;
}
help = get_help(type);
if (!help || memcmp(help, "", sizeof("")) == SUCCESS) {
pretty_print(get_help("overview!"));
pretty_print(
"\nrequested help page could not be found");
return;
}
pretty_print(help);
} /* }}} */
PHPDBG_COMMAND(help) /* {{{ */
{
phpdbg_command_t const *cmd;
int n;
if (!param || param->type == EMPTY_PARAM) {
pretty_print(get_help("overview!"));
return SUCCESS;
}
if (param && param->type == STR_PARAM) {
n = get_command(param->str, param->len, &cmd, phpdbg_prompt_commands);
if (n==1) {
summary_print(cmd);
pretty_print(get_help(cmd->name));
return SUCCESS;
} else if (n>1) {
if (param->len > 1) {
for (cmd=phpdbg_prompt_commands; cmd->name; cmd++) {
if (!strncmp(cmd->name, param->str, param->len)) {
summary_print(cmd);
}
}
pretty_print(get_help("duplicate!"));
return SUCCESS;
} else {
phpdbg_error("Internal help error, non-unique alias \"%c\"", param->str[0]);
return FAILURE;
}
} else { /* no prompt command found so try help topic */
n = get_command( param->str, param->len, &cmd, phpdbg_help_commands);
if (n>0) {
if (cmd->alias == 'a') { /* help aliases executes a canned routine */
return cmd->handler(param);
} else {
pretty_print(get_help(cmd->name));
return SUCCESS;
}
} else {
phpdbg_error("No help topic found for %s", param->str);
}
}
}
return FAILURE;
} /* }}} */
PHPDBG_HELP(aliases) /* {{{ */
{
const phpdbg_command_t *c, *c_sub;
int len;
/* Print out aliases for all commands except help as this one comes last */
phpdbg_writeln("Below are the aliased, short versions of all supported commands");
for(c = phpdbg_prompt_commands; c->name; c++) {
if (c->alias && c->alias != 'h') {
phpdbg_writeln(" %c %-20s %s", c->alias, c->name, c->tip);
if (c->subs) {
len = 20 - 1 - c->name_len;
for(c_sub = c->subs; c_sub->alias; c_sub++) {
if (c_sub->alias) {
phpdbg_writeln(" %c %c %s %-*s %s",
c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip);
}
}
}
}
}
/* Print out aliases for help as this one comes last, with the added text on how aliases are used */
get_command("h", 1, &c, phpdbg_prompt_commands);
phpdbg_writeln(" %c %-20s %s\n", c->alias, c->name, c->tip);
len = 20 - 1 - c->name_len;
for(c_sub = c->subs; c_sub->alias; c_sub++) {
if (c_sub->alias) {
phpdbg_writeln(" %c %c %s %-*s %s",
c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip);
}
}
pretty_print(get_help("aliases!"));
return SUCCESS;
} /* }}} */
/* {{{ Help Text Table
* Contains help text entries keyed by a lowercase ascii key.
* Text is in ascii and enriched by a simple markup:
* ** toggles bold font emphasis.
* $P insert an bold phpdbg> prompt.
* \ escapes the following character. Note that this is itself escaped inside string
* constants so \\\\ is required to output a single \ e.g. as in namespace names.
*
* Text will be wrapped according to the STDOUT terminal width, so paragraphs are
* flowed using the C stringizing and the CR definition. Also note that entries
* are collated in alphabetic order on key.
*
* Also note the convention that help text not directly referenceable as a help param
* has a key ending in !
*/
#define CR "\n"
const phpdbg_help_text_t phpdbg_help_text[] = {
/******************************** General Help Topics ********************************/
{"overview!", CR
"**phpdbg** is a lightweight, powerful and easy to use debugging platform for PHP" CR
"It supports the following commands:" CR CR
"**Information**" CR
" **list** list PHP source" CR
" **info** displays information on the debug session" CR
" **print** show opcodes" CR
" **frame** select a stack frame and print a stack frame summary" CR
" **generator** show active generators or select a generator frame" CR
" **back** shows the current backtrace" CR
" **help** provide help on a topic" CR CR
"**Starting and Stopping Execution**" CR
" **exec** set execution context" CR
" **stdin** set executing script from stdin" CR
" **run** attempt execution" CR
" **step** continue execution until other line is reached" CR
" **continue** continue execution" CR
" **until** continue execution up to the given location" CR
" **next** continue execution up to the given location and halt on the first line after it" CR
" **finish** continue up to end of the current execution frame" CR
" **leave** continue up to end of the current execution frame and halt after the calling instruction" CR
" **break** set a breakpoint at the specified target" CR
" **watch** set a watchpoint on $variable" CR
" **clear** clear one or all breakpoints" CR
" **clean** clean the execution environment" CR CR
"**Miscellaneous**" CR
" **set** set the phpdbg configuration" CR
" **source** execute a phpdbginit script" CR
" **register** register a phpdbginit function as a command alias" CR
" **sh** shell a command" CR
" **ev** evaluate some code" CR
" **quit** exit phpdbg" CR CR
"Type **help <command>** or (**help alias**) to get detailed help on any of the above commands, "
"for example **help list** or **h l**. Note that help will also match partial commands if unique "
"(and list out options if not unique), so **help exp** will give help on the **export** command, "
"but **help ex** will list the summary for **exec** and **export**." CR CR
"Type **help aliases** to show a full alias list, including any registered phpdbginit functions" CR
"Type **help syntax** for a general introduction to the command syntax." CR
"Type **help options** for a list of phpdbg command line options." CR
"Type **help phpdbginit** to show how to customize the debugger environment."
},
{"options", CR
"Below are the command line options supported by phpdbg" CR CR
/* note the extra 4 space index in because of the extra **** */
"**Command Line Options and Flags**" CR
" **Option** **Example Argument** **Description**" CR
" **-c** **-c**/my/php.ini Set php.ini file to load" CR
" **-d** **-d**memory_limit=4G Set a php.ini directive" CR
" **-n** Disable default php.ini" CR
" **-q** Suppress welcome banner" CR
" **-v** Enable oplog output" CR
" **-b** Disable colour" CR
" **-i** **-i**my.init Set .phpdbginit file" CR
" **-I** Ignore default .phpdbginit" CR
" **-r** Run execution context" CR
" **-rr** Run execution context and quit after execution (not respecting breakpoints)" CR
" **-e** Generate extended information for debugger/profiler" CR
" **-E** Enable step through eval, careful!" CR
" **-s** **-s=**, **-s**=foo Read code to execute from stdin with an optional delimiter" CR
" **-S** **-S**cli Override SAPI name, careful!" CR
" **-p** **-p**, **-p=func**, **-p* ** Output opcodes and quit" CR
" **-z** **-z**extlib Load Zend extension" CR
" **-h** Print the help overview" CR
" **-V** Print version number" CR
" **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv "
"argument after it" CR CR
"**Reading from stdin**" CR CR
"The **-s** option allows inputting a script to execute directly from stdin. The given delimiter "
"(\"foo\" in the example) needs to be specified at the end of the input on its own line, followed by "
"a line break. If **-rr** has been specified, it is allowed to omit the delimiter (**-s=**) and "
"it will read until EOF. See also the help entry for the **stdin** command." CR CR
"**Opcode output**" CR CR
"Outputting opcodes requires that a file path is passed as last argument. Modes of execution:" CR
"**-p** Outputs the main execution context" CR
"**-p* **Outputs all opcodes in the whole file (including classes and functions)" CR
"**-p=function_name** Outputs opcodes of a given function in the file" CR
"**-p=class_name::** Outputs opcodes of all the methods of a given class" CR
"**-p=class_name::method** Outputs opcodes of a given method"
},
{"phpdbginit", CR
"Phpdbg uses an debugger script file to initialize the debugger context. By default, phpdbg looks "
"for the file named **.phpdbginit** in the current working directory. This location can be "
"overridden on the command line using the **-i** switch (see **help options** for a more "
"details)." CR CR
"Debugger scripts can also be executed using the **source** command." CR CR
"A script file can contain a sequence of valid debugger commands, comments and embedded PHP "
"code. " CR CR
"Comment lines are prefixed by the **#** character. Note that comments are only allowed in script "
"files and not in interactive sessions." CR CR
"PHP code is delimited by the start and end escape tags **<:** and **:>**. PHP code can be used "
"to define application context for a debugging session and also to extend the debugger by defining "
"and **register** PHP functions as new commands." CR CR
"Also note that executing a **clear** command will cause the current **phpdbginit** to be reparsed "
"/ reloaded."
},
{"syntax", CR
"Commands start with a keyword, and some (**break**, "
"**info**, **set**, **print** and **list**) may include a subcommand keyword. All keywords are "
"lower case but also have a single letter alias that may be used as an alternative to typing in the"
"keyword in full. Note some aliases are uppercase, and that keywords cannot be abbreviated other "
"than by substitution by the alias." CR CR
"Some commands take an argument. Arguments are typed according to their format:" CR
" * **omitted**" CR
" * **address** **0x** followed by a hex string" CR
" * **number** an optionally signed number" CR
" * **method** a valid **Class::methodName** expression" CR
" * **func#op** a valid **Function name** follow by # and an integer" CR
" * **method#op** a valid **Class::methodName** follow by # and an integer" CR
" * **string** a general string" CR
" * **function** a valid **Function name**" CR
" * **file:line** a valid **filename** follow by : and an integer" CR CR
"In some cases the type of the argument enables the second keyword to be omitted." CR CR
"Type **help** for an overview of all commands and type **help <command>** to get detailed help "
"on any specific command." CR CR
"**Valid Examples**" CR CR
" $P quit" CR
" $P q" CR
" Quit the debugger" CR CR
" $P ev $total[2]" CR
" Evaluate and print the variable $total[2] in the current stack frame" CR
" " CR
" $P break 200" CR
" $P b my_source.php:200" CR
" Break at line 200 in the current source and in file **my_source.php**. " CR CR
" $P b @ ClassX::get_args if $arg[0] == \"fred\"" CR
" $P b ~ 3" CR
" Break at ClassX::get_args() if $arg[0] == \"fred\" and delete breakpoint 3" CR CR
"**Examples of invalid commands**" CR
" $P #This is a comment" CR
" Comments introduced by the **#** character are only allowed in **phpdbginit** script files."
},
/******************************** Help Codicils ********************************/
{"aliases!", CR
"Note that aliases can be used for either command or sub-command keywords or both, so **info b** "
"is a synonym for **info break** and **l func** for **list func**, etc." CR CR
"Note that help will also accept any alias as a parameter and provide help on that command, for example **h p** will provide help on the print command."
},
{"duplicate!", CR
"Parameter is not unique. For detailed help select help on one of the above commands."
},
/******************************** Help on Commands ********************************/
{"back",
"Provide a formatted backtrace using the standard debug_backtrace() functionality. An optional "
"unsigned integer argument specifying the maximum number of frames to be traced; if omitted then "
"a complete backtrace is given." CR CR
"**Examples**" CR CR
" $P back 5" CR
" $P t " CR
" " CR
"A backtrace can be executed at any time during execution."
},
{"break",
"Breakpoints can be set at a range of targets within the execution environment. Execution will "
"be paused if the program flow hits a breakpoint. The break target can be one of the following "
"types:" CR CR
" **Target** **Alias** **Purpose**" CR
" **at** **@** specify breakpoint by location and condition" CR
" **del** **~** delete breakpoint by breakpoint identifier number" CR CR
"**Break at** takes two arguments. The first is any valid target. The second "
"is a valid PHP expression which will trigger the break in "
"execution, if evaluated as true in a boolean context at the specified target." CR CR
"Note that breakpoints can also be disabled and re-enabled by the **set break** command." CR CR
"**Examples**" CR CR
" $P break test.php:100" CR
" $P b test.php:100" CR
" Break execution at line 100 of test.php" CR CR
" $P break 200" CR
" $P b 200" CR
" Break execution at line 200 of the currently PHP script file" CR CR
" $P break \\\\mynamespace\\\\my_function" CR
" $P b \\\\mynamespace\\\\my_function" CR
" Break execution on entry to \\\\mynamespace\\\\my_function" CR CR
" $P break classX::method" CR
" $P b classX::method" CR
" Break execution on entry to classX::method" CR CR
" $P break 0x7ff68f570e08" CR
" $P b 0x7ff68f570e08" CR
" Break at the opline at the address 0x7ff68f570e08" CR CR
" $P break my_function#14" CR
" $P b my_function#14" CR
" Break at the opline #14 of the function my_function" CR CR
" $P break \\\\my\\\\class::method#2" CR
" $P b \\\\my\\\\class::method#2" CR
" Break at the opline #2 of the method \\\\my\\\\class::method" CR CR
" $P break test.php:#3" CR
" $P b test.php:#3" CR
" Break at opline #3 in test.php" CR CR
" $P break if $cnt > 10" CR
" $P b if $cnt > 10" CR
" Break when the condition ($cnt > 10) evaluates to true" CR CR
" $P break at phpdbg::isGreat if $opt == 'S'" CR
" $P break @ phpdbg::isGreat if $opt == 'S'" CR
" Break at any opcode in phpdbg::isGreat when the condition ($opt == 'S') is true" CR CR
" $P break at test.php:20 if !isset($x)" CR
" Break at every opcode on line 20 of test.php when the condition evaluates to true" CR CR
" $P break ZEND_ADD" CR
" $P b ZEND_ADD" CR
" Break on any occurrence of the opcode ZEND_ADD" CR CR
" $P break del 2" CR
" $P b ~ 2" CR
" Remove breakpoint 2" CR CR
"Note: Conditional breaks are costly in terms of runtime overhead. Use them only when required "
"as they significantly slow execution." CR CR
"Note: An address is only valid for the current compilation."
},
{"clean",
"Classes, constants or functions can only be declared once in PHP. You may experience errors "
"during a debug session if you attempt to recompile a PHP source. The clean command clears "
"the Zend runtime tables which holds the sets of compiled classes, constants and functions, "
"releasing any associated storage back into the storage pool. This enables recompilation to "
"take place." CR CR
"Note that you cannot selectively trim any of these resource pools. You can only do a complete "
"clean."
},
{"clear",
"Clearing breakpoints means you can once again run code without interruption." CR CR
"Note: use break delete N to clear a specific breakpoint." CR CR
"Note: if all breakpoints are cleared, then the PHP script will run until normal completion."
},
{"ev",
"The **ev** command takes a string expression which it evaluates and then displays. It "
"evaluates in the context of the lowest (that is the executing) frame, unless this has first "
"been explicitly changed by issuing a **frame** command. " CR CR
"**Examples**" CR CR
" $P ev $variable" CR
" Will print_r($variable) on the console, if it is defined" CR CR
" $P ev $variable = \"Hello phpdbg :)\"" CR
" Will set $variable in the current scope" CR CR
"Note that **ev** allows any valid PHP expression including assignments, function calls and "
"other write statements. This enables you to change the environment during execution, so care "
"is needed here. You can even call PHP functions which have breakpoints defined. " CR CR
"Note: **ev** will always show the result, so do not prefix the code with **return**"
},
{"exec",
"The **exec** command sets the execution context, that is the script to be executed. The "
"execution context must be defined either by executing the **exec** command or by using the "
"**-e** command line option." CR CR
"Note that the **exec** command also can be used to replace a previously defined execution "
"context." CR CR
"**Examples**" CR CR
" $P exec /tmp/script.php" CR
" $P e /tmp/script.php" CR
" Set the execution context to **/tmp/script.php**"
},
{"stdin",
"The **stdin** command takes a string serving as delimiter. It will then read all the input from "
"stdin until encountering the given delimiter on a standalone line. It can also be passed at "
"startup using the **-s=** command line option (the delimiter then is optional if **-rr** is "
"also passed - in that case it will just read until EOF)." CR
"This input will be then compiled as PHP code and set as execution context." CR CR
"**Example**" CR CR
" $P stdin foo" CR
" <?php" CR
" echo \"Hello, world!\\n\";" CR
" foo"
},
//*********** Does F skip any breakpoints lower stack frames or only the current??
{"finish",
"The **finish** command causes control to be passed back to the vm, continuing execution. Any "
"breakpoints that are encountered within the current stack frame will be skipped. Execution "
"will then continue until the next breakpoint after leaving the stack frame or until "
"completion of the script" CR CR
"Note when **step**ping is enabled, any opcode steps within the current stack frame are also "
"skipped. "CR CR
"Note **finish** will trigger a \"not executing\" error if not executing."
},
{"frame",
"The **frame** takes an optional integer argument. If omitted, then the current frame is displayed. "
"If specified, then the current scope is set to the corresponding frame listed in a **back** trace. "
"This can be used to allowing access to the variables in a higher stack frame than that currently being executed." CR CR
"**Examples**" CR CR
" $P frame 2" CR
" $P ev $count" CR
" Go to frame 2 and print out variable **$count** in that frame" CR CR
"Note that this frame scope is discarded when execution continues, with the execution frame "
"then reset to the lowest executing frame."
},
{"generator",
"The **generator** command takes an optional integer argument. If omitted, then a list of the "
"currently active generators is displayed. If specified then the current scope is set to the frame "
"of the generator with the corresponding object handle. This can be used to inspect any generators "
"not in the current **back** trace." CR CR
"**Examples**" CR CR
" $P generator" CR
" List of generators, with the #id being the object handle, e.g.:" CR
" #3: my_generator(argument=\"value\") at test.php:5" CR
" $P g 3" CR
" $P ev $i" CR
" Go to frame of generator with object handle 3 and print out variable **$i** in that frame" CR CR
"Note that this frame scope is discarded when execution continues, with the execution frame "
"then reset to the lowest executing frame."
},
{"info",
"**info** commands provide quick access to various types of information about the PHP environment" CR
"By default general information about environment and PHP build is shown." CR
"Specific info commands are show below:" CR CR
" **Target** **Alias** **Purpose**" CR
" **break** **b** show current breakpoints" CR
" **files** **F** show included files" CR
" **classes** **c** show loaded classes" CR
" **funcs** **f** show loaded functions" CR
" **error** **e** show last error" CR
" **constants** **d** show user-defined constants" CR
" **vars** **v** show active variables" CR
" **globals** **g** show superglobal variables" CR
" **literal** **l** show active literal constants" CR
" **memory** **m** show memory manager stats"
},
// ******** same issue about breakpoints in called frames
{"leave",
"The **leave** command causes control to be passed back to the vm, continuing execution. Any "
"breakpoints that are encountered within the current stack frame will be skipped. In effect a "
"temporary breakpoint is associated with any return opcode, so that a break in execution occurs "
"before leaving the current stack frame. This allows inspection / modification of any frame "
"variables including the return value before it is returned" CR CR
"**Examples**" CR CR
" $P leave" CR
" $P L" CR CR
"Note when **step**ping is enabled, any opcode steps within the current stack frame are also "
"skipped. "CR CR
"Note **leave** will trigger a \"not executing\" error if not executing."
},
{"list",
"The list command displays source code for the given argument. The target type is specified by "
"a second subcommand keyword:" CR CR
" **Type** **Alias** **Purpose**" CR
" **lines** **l** List N lines from the current execution point" CR
" **func** **f** List the complete source for a specified function" CR
" **method** **m** List the complete source for a specified class::method" CR
" **class** **c** List the complete source for a specified class" CR CR
"Note that the context of **lines**, **func** and **method** can be determined by parsing the "
"argument, so these subcommands are optional. However, you must specify the **class** keyword "
"to list off a class." CR CR
"**Examples**" CR CR
" $P list 2" CR
" $P l l 2" CR
" List the next 2 lines from the current file" CR CR
" $P list my_function" CR
" $P l f my_function" CR
" List the source of the function **my_function**" CR CR
//************ ????
" $P list func .mine" CR
" $P l f .mine" CR
" List the source of the method **mine** from the active class in scope" CR CR
" $P list m my::method" CR
" $P l my::method" CR
" List the source of **my::method**" CR CR
" $P list c myClass" CR
" $P l c myClass" CR
" List the source of **myClass**" CR CR
"Note that functions and classes can only be listed if the corresponding classes and functions "
"table in the Zend executor has a corresponding entry. You can use the compile command to "
"populate these tables for a given execution context."
},
{"continue",
"Continue with execution after hitting a break or watchpoint" CR CR
"**Examples**" CR CR
" $P continue" CR
" $P c" CR
" Continue executing until the next break or watchpoint" CR CR
"Note **continue** will trigger a \"not running\" error if not executing."
},
{"print",
"By default, print will show the opcodes of the current execution context." CR
"Other printing commands give access to instruction information." CR
"Specific printers loaded are show below:" CR CR
" **Type** **Alias** **Purpose**" CR
" **exec** **e** print out the instructions in the execution context" CR
" **opline** **o** print out the instruction in the current opline" CR
" **class** **c** print out the instructions in the specified class" CR
" **method** **m** print out the instructions in the specified method" CR
" **func** **f** print out the instructions in the specified function" CR
" **stack** **s** print out the instructions in the current stack" CR CR
"In case passed argument does not match a specific printing command, it will treat it as function or method name and print its opcodes" CR CR
"**Examples**" CR CR
" $P print class \\\\my\\\\class" CR
" $P p c \\\\my\\\\class" CR
" Print the instructions for the methods in \\\\my\\\\class" CR CR
" $P print method \\\\my\\\\class::method" CR
" $P p m \\\\my\\\\class::method" CR
" Print the instructions for \\\\my\\\\class::method" CR CR
" $P print func .getSomething" CR
" $P p f .getSomething" CR
//************* Check this local method scope
" Print the instructions for ::getSomething in the active scope" CR CR
" $P print func my_function" CR
" $P p f my_function" CR
" Print the instructions for the global function my_function" CR CR
" $P print opline" CR
" $P p o" CR
" Print the instruction for the current opline" CR CR
" $P print exec" CR
" $P p e" CR
" Print the instructions for the execution context" CR CR
" $P print stack" CR
" $P p s" CR
" Print the instructions for the current stack"
},
{"register",
//******* Needs a general explanation of the how registered functions work
"Register any global function for use as a command in phpdbg console" CR CR
"**Examples**" CR CR
" $P register scandir" CR
" $P R scandir" CR
" Will register the scandir function for use in phpdbg" CR CR
"Note: arguments passed as strings, return (if present) print_r'd on console"
},
{"run",
"Enter the vm, starting execution. Execution will then continue until the next breakpoint "
"or completion of the script. Add parameters you want to use as $argv. Add a trailing "
"**< filename** for reading STDIN from a file." CR CR
"**Examples**" CR CR
" $P run" CR
" $P r" CR
" Will cause execution of the context, if it is set" CR CR
" $P r test < foo.txt" CR
" Will execute with $argv[1] == \"test\" and read from the foo.txt file for STDIN" CR CR
"Note that the execution context must be set. If not previously compiled, then the script will "
"be compiled before execution."
},
{"set",
"The **set** command is used to configure how phpdbg looks and behaves. Specific set commands "
"are as follows:" CR CR
" **Type** **Alias** **Purpose**" CR
" **prompt** **p** set the prompt" CR
" **color** **c** set color <element> <color>" CR
" **colors** **C** set colors [<on|off>]" CR
" **break** **b** set break **id** <on|off>" CR
" **breaks** **B** set breaks [<on|off>]" CR
" **quiet** **q** set quiet [<on|off>]" CR
" **stepping** **s** set stepping [<opcode|line>]" CR
" **refcount** **r** set refcount [<on|off>] " CR CR
"Valid colors are **none**, **white**, **red**, **green**, **yellow**, **blue**, **purple**, "
"**cyan** and **black**. All colours except **none** can be followed by an optional "
"**-bold** or **-underline** qualifier." CR CR
"Color elements can be one of **prompt**, **notice**, or **error**." CR CR
"**Examples**" CR CR
" $P S C on" CR
" Set colors on" CR CR
" $P set p >" CR
" $P set color prompt white-bold" CR
" Set the prompt to a bold >" CR CR
" $P S c error red-bold" CR
" Use red bold for errors" CR CR
" $P S refcount on" CR
" Enable refcount display when hitting watchpoints" CR CR
" $P S b 4 off" CR
" Temporarily disable breakpoint 4. This can be subsequently re-enabled by a **S b 4 on**." CR
//*********** check oplog syntax
},
{"sh",
"Direct access to shell commands saves having to switch windows/consoles" CR CR
"**Examples**" CR CR
" $P sh ls /usr/src/php-src" CR
" Will execute ls /usr/src/php-src, displaying the output in the console"
//*********** what does this mean????Note: read only commands please!
},
{"source",
"Sourcing a **phpdbginit** script during your debugging session might save some time." CR CR
"**Examples**" CR CR
" $P source /my/init" CR
" $P < /my/init" CR
" Will execute the phpdbginit file at /my/init" CR CR
},
{"export",
"Exporting breakpoints allows you to share, and or save your current debugging session" CR CR
"**Examples**" CR CR
" $P export /my/exports" CR
" $P > /my/exports" CR
" Will export all breakpoints to /my/exports" CR CR
},
{"step",
"Execute opcodes until next line" CR CR
"**Examples**" CR CR
" $P s" CR
" Will continue and break again in the next encountered line" CR CR
},
{"next",
"The **next** command causes control to be passed back to the vm, continuing execution. Any "
"breakpoints that are encountered before the next source line will be skipped. Execution will"
"be stopped when that line is left." CR CR
"Note when **step**ping is enabled, any opcode steps within the current line are also skipped. "CR CR
"Note that if the next line is **not** executed then **all** subsequent breakpoints will be "
"skipped. " CR CR
"Note **next** will trigger a \"not executing\" error if not executing."
},
{"until",
"The **until** command causes control to be passed back to the vm, continuing execution. Any "
"breakpoints that are encountered before the next source line will be skipped. Execution "
"will then continue until the next breakpoint or completion of the script" CR CR
"Note when **step**ping is enabled, any opcode steps within the current line are also skipped. "CR CR
"Note that if the next line is **not** executed then **all** subsequent breakpoints will be "
"skipped. " CR CR
"Note **until** will trigger a \"not executing\" error if not executing."
},
{"watch",
"Sets watchpoints on variables as long as they are defined" CR
"Passing no parameter to **watch**, lists all actually active watchpoints" CR CR
"**Format for $variable**" CR CR
" **$var** Variable $var" CR
" **$var[]** All array elements of $var" CR
" **$var->** All properties of $var" CR
" **$var->a** Property $var->a" CR
" **$var[b]** Array element with key b in array $var" CR CR
"Subcommands of **watch**:" CR CR
" **Type** **Alias** **Purpose**" CR
" **array** **a** Sets watchpoint on array/object to observe if an entry is added or removed" CR
" **recursive** **r** Watches variable recursively and automatically adds watchpoints if some entry is added to an array/object" CR
" **delete** **d** Removes watchpoint" CR CR
"Note when **recursive** watchpoints are removed, watchpoints on all the children are removed too" CR CR
"**Examples**" CR CR
" $P watch" CR
" List currently active watchpoints" CR CR
" $P watch $array" CR
" $P w $array" CR
" Set watchpoint on $array" CR CR
" $P watch recursive $obj->" CR
" $P w r $obj->" CR
" Set recursive watchpoint on $obj->" CR CR
" $P watch delete $obj->a" CR
" $P w d $obj->a" CR
" Remove watchpoint $obj->a" CR CR
"Technical note: If using this feature with a debugger, you will get many segmentation faults, each time when a memory page containing a watched address is hit." CR
" You then you can continue, phpdbg will remove the write protection, so that the program can continue." CR
" If phpdbg could not handle that segfault, the same segfault is triggered again and this time phpdbg will abort."
},
{NULL, NULL /* end of table marker */}
}; /* }}} */
|