com web/bugs: Move backtrace pages to templates: include/functions.php templates/pages/bugs_generating_backtrace.php templates
/pages/bugs_generating_backtrace_win32.php www/bu gs-generating-backtrace-win32.php www/bugs-generating-b acktrace.php
| From: | Peter Kokot | Date: | Wed, 22 May 2019 02:43:45 +0000 |
| Subject: | com web/bugs: Move backtrace pages to templates: include/functions.php templates/pages/bugs_generating_backtrace.php templates /pages/bugs_generating_backtrace_win32.php www/bu gs-generating-backtrace-win32.php www/bugs-generating-b acktrace.php |
||
| Groups: | php.webmaster | ||
| Request: | Send a blank email to php-webmaster+get-28062@lists.php.net to get a copy of this message | ||
Commit: 49dd23a4a88040cf1134c374b2369a104f803765
Author: Peter Kokot <peterkokot@gmail.com> Wed, 22 May 2019 04:43:45 +0200
Parents: 35a1baa22f5a5388194047182e3eca31371c6b40
Branches: master
Link: http://git.php.net/?p=web/bugs.git;a=commitdiff;h=49dd23a4a88040cf1134c374b2369a104f803765
Log:
Move backtrace pages to templates
Changed paths:
M include/functions.php
A templates/pages/bugs_generating_backtrace.php
A templates/pages/bugs_generating_backtrace_win32.php
M www/bugs-generating-backtrace-win32.php
M www/bugs-generating-backtrace.php
diff --git a/include/functions.php b/include/functions.php index 5e314a2..fd3bbd7 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1707,32 +1707,6 @@ function inline_content_menu($base_url, $current_action, array $menu) echo "</p>\n"; } -/** - * Inline content menu for backtraces - * - * Specify either 'Unix' or 'Windows' to select the current page - */ -function backtrace_inline_menu($platform) -{ - if ($platform != 'Unix' && $platform != 'Windows') { - return; - } - - $buffer = ''; - - foreach (['Unix' => '', 'Windows' => '-win32'] as $platform_key => $platform_suffix) { - if ($platform_key == $platform) { - $buffer .= sprintf('<strong>%s</strong> | ', $platform_key); - } else { - $buffer .= sprintf('<a href="/bugs-generating-backtrace%s.php">%s</a> | ', $platform_suffix, $platform_key); - } - } - - echo "<p>"; - echo rtrim($buffer, ' | '); - echo "</p>\n"; -} - function admin_table_static(array $header, array $rows) { if (!$header || !$rows || sizeof($header) != sizeof($rows[0])) { diff --git a/templates/pages/bugs_generating_backtrace.php b/templates/pages/bugs_generating_backtrace.php new file mode 100644 index 0000000..b99f383 --- /dev/null +++ b/templates/pages/bugs_generating_backtrace.php @@ -0,0 +1,179 @@ +<?php $this->extends('layout.php', ['title' => 'Generating a gdb backtrace']) ?> + +<?php $this->start('content') ?> + +<p> +<strong>Unix</strong> | <a href="/bugs-generating-backtrace-win32.php">Windows</a> +</p> + +<h1>Generating a gdb backtrace</h1> + +<h3>Noticing PHP crashes</h3> + +There's no absolute way to know that PHP is crashing, but there may be signs. +Typically, if you access a page that is always supposed to generate output (has +a leading HTML block, for example), and suddenly get "Document contains no data" +from your browser, it may mean that PHP crashes somewhere along the execution of +the script. Another way to tell that PHP is crashing is by looking at the Apache +error logs, and looking for SEGV (Apache 1.2) or Segmentation Fault (Apache +1.3). + +<h3>Important!</h3> +To get a backtrace with correct information you must have PHP configured with +<code>--enable-debug</code>! + +<h3>If you don't have a core file yet:</h3> + +<ul> + <li> + Remove any limits you may have on core dump size from your shell: + <ul> + <li>tcsh: unlimit coredumpsize</li> + <li>bash/sh: ulimit -c unlimited</li> + </ul> + </li> + <li> + Ensure that the directory in which you're running PHP, or the + PHP-enabled httpd, has write permissions for the user who's running PHP. + </li> + <li> + Cause PHP to crash: + <ul> + <li>PHP CGI: Simply run php with the script that crashes it</li> + <li>PHP Apache Module: Run httpd -X, and access the script that crashes PHP</li> + </ul> + </li> +</ul> + +<h3>Generic way to get a core on Linux</h3> + +<ul> + <li> + Set up the core pattern (run this command as <i>root</i>): + <ul> + <li>echo "<cores dir>/core-%e.%p" > /proc/sys/kernel/core_pattern</li> + <li>make sure the directory is writable by PHP</li> + </ul> + </li> + <li>Set the ulimit (see above how to do it).</li> + <li>Restart/rerun PHP.</li> +</ul> + +<p>After that any process crashing in your system, including PHP, will leave its +core file in the directory you've specified in <i>core_pattern</i>.</p> + +<h3>Once you have the core file:</h3> + +<ul> + <li> + Run gdb with the path to the PHP or PHP-enabled httpd binary, and path + to the core file. Some examples: + <ul> + <li><code>gdb /usr/local/apache/sbin/httpd /usr/local/apache/sbin/core</code></li> + <li><code>gdb /home/user/dev/php-snaps/sapi/cli/php /home/user/dev/testing/core</code></li> + </ul> + </li> + <li> + At the gdb prompt, run: + <ul> + <li><code>(gdb) bt</code></li> + </ul> + </li> +</ul> + +<h3>If you can't get a core file:</h3> +<ul> + <li> + Run httpd -X under gdb with something like: + <ul> + <li><code>gdb /usr/local/apache/sbin/httpd</code></li> + <li>(gdb) run -X</li> + </ul> + </li> + <li> + Then use your web browser and access your server to force the crash. You + should see a gdb prompt appear and some message indicating that there + was a crash. At this gdb prompt, type: + <ul> + <li><code>(gdb) bt</code></li> + </ul> + <ul> + <li> + or, running from the commandline + <ul> + <li> + gdb /home/user/dev/php-snaps/sapi/cli/php + <ul> + <li><code>(gdb) run /path/to/script.php</code></li> + <li><code>(gdb) bt</code></li> + </ul> + </li> + </ul> + </li> + </ul> + </li> +</ul> + +<p>This should generate a backtrace, that you should submit in the bug report, +along with any other details you can give us about your setup, and offending +script.</p> + +<h3>Locating which function call caused a segfault:</h3> + +<p>You can locate the function call that caused a segfault, easily, with gdb. +First, you need a core file or to generate a segfault under gdb as described +above.</p> + +<p>In PHP, each function is executed by an internal function called +<b><code>execute()</code></b> and has its own stack. Each line generated by the +<b><code>bt</code></b> command represents a function call stack. Typically, you +will see several <b><code>execute()</code></b> lines when you issue +<b><code>bt</code></b>. You are interested in the last +<b><code>execute()</code></b> stack (i.e. smallest frame number). You can move +the current working stack with the <b><code>up</code></b>, <code>down</code> or +<b><code>frame</code></b> commands. Below is an example gdb session that can be +used as a guideline on how to handle your segfault.</p> + +<ul> + <li>Sample gdb session</li> + <pre><code> +(gdb) bt +#0 0x080ca21b in _efree (ptr=0xbfffdb9b) at zend_alloc.c:240 +#1 0x080d691a in _zval_dtor (zvalue=0x8186b94) at zend_variables.c:44 +#2 0x080cfab3 in _zval_ptr_dtor (zval_ptr=0xbfffdbfc) at zend_execute_API.c:274 +#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 +#4 0x080f1e06 in execute (op_array=0x816c530) at ./zend_execute.c:1638 +#5 0x080f1e06 in execute (op_array=0x816c278) at ./zend_execute.c:1638 +#6 0x080f1e06 in execute (op_array=0x8166eec) at ./zend_execute.c:1638 +#7 0x080d7b93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at zend.c:810 +#8 0x0805ea75 in php_execute_script (primary_file=0xbffff650) at main.c:1310 +#9 0x0805cdb3 in main (argc=2, argv=0xbffff6fc) at cgi_main.c:753 +#10 0x400c91be in __libc_start_main (main=0x805c580 <main>, argc=2, ubp_av=0xbffff6fc, + init=0x805b080 <_init>, fini=0x80f67b4 <_fini>, rtld_fini=0x4000ddd0 <_dl_fini>, + stack_end=0xbffff6ec) at ../sysdeps/generic/libc-start.c:129 +(gdb) frame 3 +#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 +(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name +$14 = 0x80fa6fa "pg_result_error" +(gdb) print (char *)executor_globals.active_op_array->function_name +$15 = 0x816cfc4 "result_error" +(gdb) print (char *)executor_globals.active_op_array->filename +$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php" +(gdb) + </code></pre> +</ul> + +<p>In this session, frame 3 is the last <b><code>execute()</code></b> call. The +<b><code>frame 3</code></b> command moves the current working stack to the +proper frame.<br> +<b><code>print (char *)(executor_globals.function_state_ptr->function)->common.function_name</code></b><br> +prints the function name. In the sample gdb session, the +<code>pg_result_error()</code> call is causing the segfault. You can print any +internal data that you like, if you know the internal data structure. Please do +not ask how to use gdb or about the internal data structure. Refer to gdb manual +for gdb usage and to the PHP source for the internal data structure.</p> + +<p>You may not see <b><code>execute</code></b> if the segfault happens without +calling any functions.</p> + +<?php $this->end('content') ?> diff --git a/templates/pages/bugs_generating_backtrace_win32.php b/templates/pages/bugs_generating_backtrace_win32.php new file mode 100644 index 0000000..985be24 --- /dev/null +++ b/templates/pages/bugs_generating_backtrace_win32.php @@ -0,0 +1,105 @@ +<?php $this->extends('layout.php', ['title' => 'Generating a backtrace on Windows']) ?> + +<?php $this->start('content') ?> + +<p> +<a href="/bugs-generating-backtrace.php">Unix</a> | <strong>Windows</strong> +</p> + +<h1>Generating a backtrace, <u>with</u> a compiler, on Windows</h1> + +<p>You'll need to install MS Visual Studio 2008, 2012 or later. You'll also need to</p> +<ul> + <li>either download the debug-pack for your PHP version from <a href="https://windows.php.net/download/">windows.php.net/download</a></li> + <li>or compile your own PHP with <code>--enable-dbg-pack</code> or <code>--enable-debug</code></li> +</ul> + +<p>If you downloaded the debug-pack from the snaps site, extract it into your +PHP directory and be sure to put the PDB files that belong to the extensions +into your extension directory.</p> + +<p>If you compile PHP by your own, you can also use a newer version of MSVC.</p> + +<p>When PHP crashes, click <em>Cancel</em> to debug the process. Now MSVC starts +up in <em>Debug View</em>. If you don't already see the call stack, go into the +<em>View</em> menu and choose <em>Debug Windows</em> → <em>Call Stack</em>.</p> + +<p>You'll now see something similar to the following lines, this is the backtrace:</p> +<pre><code> +_efree(void * 0x00000000) line 286 + 3 bytes +zif_http_test(int 0, _zval_struct * 0x007bc3b0, _zval_struct * * 0x00000000, _zval_struct * 0x00000000, int 0, void * * * 0x00792cd0) line 1685 + 8 bytes +zend_do_fcall_common_helper_SPEC(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 188 + 95 bytes +ZEND_DO_FCALL_SPEC_CONST_HANDLER(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 1578 + 13 bytes +execute(_zend_op_array * 0x007bc880, void * * * 0x00792cd0) line 88 + 13 bytes +zend_eval_string(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', void * * * 0x00792cd0) line 1056 + 14 bytes +zend_eval_string_ex(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', int 1, void * * * 0x00792cd0) line 1090 + 21 bytes +main(int 3, char * * 0x00793ba8) line 1078 + 23 bytes +PHP! mainCRTStartup + 227 bytes +KERNEL32! 77e81af6() +</code></pre> + +<!-- + Everything below is stolen from Pierre Joye + https://blog.thepimp.net/index.php/post/2007/06/10/debug-pack-or-how-to-generate-backtrack-on-windows-without-compiling +--> +<h1>Generating backtrace, <u>without</u> compiler, on Windows</h1> + +<p>You'll need:</p> + +<ul> +<li>A PHP <a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a> release</li> +<li>PHP Debug pack (<a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a>)</li> +<li>Microsoft <a href="https://www.microsoft.com/en-us/download/details.aspx?id=49924">Debug Diagnostic Tools</a></li> +<li>Evil script to crash PHP</li> +</ul> + +<p>For the sake of this example, we will simply use PHP in the shell. The same +method can be used for IIS or any other process or services.</p> + + +<p>Once you have installed the Debug diagnostic tools and uncompressed PHP and +its debug pack (they can be kept in two separate folders), the first step is to +configure the diagnostic tools. Select the tools menu and click on "Options and +settings". The first tab contains the path to the symbols files, add the "debug +folder" to the existing list using the "browse" button:</p> + +<p><img src="/images/backtrace-images-win32/dbg_options.png" alt="Options"></p> + +<p>Now we are ready to generate our backtrace.</p> + +<p>We will use the wizard, click the "Add a rule" button and choose "Crash" as +the rule type:</p> +<p><img src="/images/backtrace-images-win32/dbg_wizard_1.png" alt="Wizard #1"></p> + +<p>In the next window, select "a specific process":</p> + +<p><img src="/images/backtrace-images-win32/dbg_wizard_2.png" alt="Wizard #2"></p> + +<p>Add a "sleep(10);" for the first run (from the cmd: "php.exe crashme.php"), +it will let you enough time to click "next" and select the php process. If you +are debugging the Apache module, start Apache with -X option and choose +httpd.exe instead of php.exe from the process list. Then proceed further:</p> + +<p><img src="/images/backtrace-images-win32/dbg_select_php.png" alt="Select the php process"></p> + +<p>Click again next and let it crash. If everything went well, you should see +your new rule as shown in the image below:</p> + +<p><img src="/images/backtrace-images-win32/rules.jpg" alt="rules list"></p> + +<p>It also detected that "php.exe" was used. A rule has been created for all +instance of "php.exe". It will save you the sleep and process selection.</p> + +<p>Now you can click the "Analyze data" button:</p> + +<p><img src="/images/backtrace-images-win32/analyze.jpg" alt="Analyze"></p> + +<p>Et voila, the complete report will show up in your internet explorer +(compressed html):</p> + +<p><img src="/images/backtrace-images-win32/backtrace.jpg" alt="Debug report backtrace screenshot"></a></p> + +<p>What we need is the backtrace itself which can be found under "Thread X - +System ID XXX".</p> + +<?php $this->end('content') ?> diff --git a/www/bugs-generating-backtrace-win32.php b/www/bugs-generating-backtrace-win32.php index a12c26a..cc09a36 100644 --- a/www/bugs-generating-backtrace-win32.php +++ b/www/bugs-generating-backtrace-win32.php @@ -1,99 +1,14 @@ <?php -session_start(); +/** + * Page with a quick info how to generate backtrace with compiler on Windows. + */ -require_once '../include/prepend.php'; +// Application bootstrap +require_once __DIR__.'/../include/prepend.php'; -// Authenticate -bugs_authenticate($user, $pw, $logged_in, $user_flags); +// Authentication +require_once __DIR__.'/../include/auth.php'; -response_header('Generating a backtrace on Windows'); - -backtrace_inline_menu('Windows'); -?> - -<h1>Generating a backtrace, <u>with</u> a compiler, on Windows</h1> - -<p>You'll need to install MS Visual Studio 2008, 2012 or later. You'll also need to</p> -<ul> - <li>either download the debug-pack for your PHP version from <a href="https://windows.php.net/download/">windows.php.net/download</a></li> - <li>or compile your own PHP with <code>--enable-dbg-pack</code> or <code>--enable-debug</code></li> -</ul> - -<p>If you downloaded the debug-pack from the snaps site, extract it into -your PHP directory and be sure to put the PDB files that belong to the -extensions into your extension directory.</p> - -<p>If you compile PHP by your own, you can also use a newer version of MSVC.</p> - -<p>When PHP crashes, click <em>Cancel</em> to debug the process. Now MSVC starts -up in <em>Debug View</em>. If you don't already see the call stack, go into the -<em>View</em> menu and choose <em>Debug Windows</em> → <em>Call Stack</em>.</p> - -<p>You'll now see something similar to the following lines, this is the backtrace:</p> -<pre><code> -_efree(void * 0x00000000) line 286 + 3 bytes -zif_http_test(int 0, _zval_struct * 0x007bc3b0, _zval_struct * * 0x00000000, _zval_struct * 0x00000000, int 0, void * * * 0x00792cd0) line 1685 + 8 bytes -zend_do_fcall_common_helper_SPEC(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 188 + 95 bytes -ZEND_DO_FCALL_SPEC_CONST_HANDLER(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 1578 + 13 bytes -execute(_zend_op_array * 0x007bc880, void * * * 0x00792cd0) line 88 + 13 bytes -zend_eval_string(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', void * * * 0x00792cd0) line 1056 + 14 bytes -zend_eval_string_ex(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', int 1, void * * * 0x00792cd0) line 1090 + 21 bytes -main(int 3, char * * 0x00793ba8) line 1078 + 23 bytes -PHP! mainCRTStartup + 227 bytes -KERNEL32! 77e81af6() -</code></pre> - -<!-- - Everything below is stolen from Pierre Joye - https://blog.thepimp.net/index.php/post/2007/06/10/debug-pack-or-how-to-generate-backtrack-on-windows-without-compiling ---> -<h1>Generating backtrace, <u>without</u> compiler, on Windows</h1> -<p>You'll need:</p> -<ul> -<li>A PHP <a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a> release</li> -<li>PHP Debug pack (<a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a>)</li> -<li>Microsoft <a href="https://www.microsoft.com/en-us/download/details.aspx?id=49924">Debug Diagnostic Tools</a></li> -<li>Evil script to crash PHP</li> -</ul> -<p>For the sake of this example, we will simply use PHP in the shell. -The same method can be used for IIS or any other process or services.</p> - - -<p>Once you have installed the Debug diagnostic tools and uncompressed -PHP and its debug pack (they can be kept in two separate folders), the -first step is to configure the diagnostic tools. Select the -tools menu and click on "Options and settings". The first tab contains -the path to the symbols files, add the "debug folder" to the existing -list using the "browse" button:</p> -<p><img src="/images/backtrace-images-win32/dbg_options.png" alt="Options"></p> - -<p>Now we are ready to generate our backtrace.</p> -<p>We will use the wizard, click the "Add a rule" button and choose "Crash" as the rule type:</p> -<p><img src="/images/backtrace-images-win32/dbg_wizard_1.png" alt="Wizard #1"></p> - -<p>In the next window, select "a specific process":</p> -<p><img src="/images/backtrace-images-win32/dbg_wizard_2.png" alt="Wizard #2"></p> - -<p>Add a "sleep(10);" for the first run (from the cmd: "php.exe -crashme.php"), it will let you enough time to click "next" and select -the php process. I you are debugging the Apache module, start Apache with -X option and choose -httpd.exe instead of php.exe from the process list. -Then proceed further:</p> -<p><img src="/images/backtrace-images-win32/dbg_select_php.png" alt="Select the php process"></p> - -<p>Click again next and let it crash. If everything went well, you should see your new rule as shown in the image below:</p> -<p><img src="/images/backtrace-images-win32/rules.jpg" alt="rules list"></p> - -<p>It also detected that "php.exe" was used. A rule has been created -for all instance of "php.exe". It will save you the sleep and process -selection.</p> -<p>Now you can click the "Analyze data" button:</p> -<p><img src="/images/backtrace-images-win32/analyze.jpg" alt="Analyze"></p> - -<p>Et voila, the complete report will show up in your internet explorer (compressed html):</p> -<p><img src="/images/backtrace-images-win32/backtrace.jpg" alt="Debug report backtrace screenshot"></a></p> - -<p>What we need is the backtrace itself which can be found under "Thread X - System ID XXX".</p> - -<?php response_footer(); +// Output template with given template variables. +echo $template->render('pages/bugs_generating_backtrace_win32.php'); diff --git a/www/bugs-generating-backtrace.php b/www/bugs-generating-backtrace.php index 5e6fafc..4729ec6 100644 --- a/www/bugs-generating-backtrace.php +++ b/www/bugs-generating-backtrace.php @@ -1,192 +1,14 @@ <?php -session_start(); +/** + * Page with a quick info how to generate gdb backtrace on Unix. + */ -require_once '../include/prepend.php'; +// Application bootstrap +require_once __DIR__.'/../include/prepend.php'; -// Authenticate -bugs_authenticate($user, $pw, $logged_in, $user_flags); +// Authentication +require_once __DIR__.'/../include/auth.php'; -response_header('Generating a gdb backtrace'); - -backtrace_inline_menu('Unix'); - -?> - -<h1>Generating a gdb backtrace</h1> - -<h3>Noticing PHP crashes</h3> - -There's no absolute way to know that PHP is crashing, but there may -be signs. Typically, if you access a page that is always supposed -to generate output (has a leading HTML block, for example), and -suddenly get "Document contains no data" from your browser, it may -mean that PHP crashes somewhere along the execution of the script. -Another way to tell that PHP is crashing is by looking at the Apache -error logs, and looking for SEGV (Apache 1.2) or Segmentation -Fault (Apache 1.3). - -<h3>Important!</h3> -To get a backtrace with correct information you must have -PHP configured with <code>--enable-debug</code>! - -<h3>If you don't have a core file yet:</h3> - -<ul> - <li> - Remove any limits you may have on core dump size from your shell: - <ul> - <li>tcsh: unlimit coredumpsize</li> - <li>bash/sh: ulimit -c unlimited</li> - </ul> - </li> - <li> - Ensure that the directory in which you're running PHP, or the - PHP-enabled httpd, has write permissions for the user who's running PHP. - </li> - <li> - Cause PHP to crash: - <ul> - <li>PHP CGI: Simply run php with the script that crashes it</li> - <li>PHP Apache Module: Run httpd -X, and access the script that crashes PHP</li> - </ul> - </li> -</ul> - -<h3>Generic way to get a core on Linux</h3> - -<ul> - <li> - Set up the core pattern (run this command as <i>root</i>): - <ul> - <li>echo "<cores dir>/core-%e.%p" > /proc/sys/kernel/core_pattern</li> - <li>make sure the directory is writable by PHP</li> - </ul> - </li> - <li> - Set the ulimit (see above how to do it). - </li> - <li> - Restart/rerun PHP. - </li> -</ul> -<p>After that any process crashing in your system, including PHP, will leave -its core file in the directory you've specified in <i>core_pattern</i>.</p> - -<h3>Once you have the core file:</h3> - -<ul> - <li> - Run gdb with the path to the PHP or PHP-enabled httpd binary, and - path to the core file. Some examples: - <ul> - <li><code>gdb /usr/local/apache/sbin/httpd /usr/local/apache/sbin/core</code></li> - <li><code>gdb /home/user/dev/php-snaps/sapi/cli/php /home/user/dev/testing/core</code></li> - </ul> - </li> - <li> - At the gdb prompt, run: - <ul> - <li><code>(gdb) bt</code></li> - </ul> - </li> -</ul> - -<h3>If you can't get a core file:</h3> -<ul> - <li> - Run httpd -X under gdb with something like: - <ul> - <li><code>gdb /usr/local/apache/sbin/httpd</code></li> - <li>(gdb) run -X</li> - </ul> - </li> - <li> - Then use your web browser and access your server to force the crash. - You should see a gdb prompt appear and some message indicating that - there was a crash. At this gdb prompt, type: - <ul> - <li><code>(gdb) bt</code></li> - </ul> - <ul> - <li> - or, running from the commandline - <ul> - <li> - gdb /home/user/dev/php-snaps/sapi/cli/php - <ul> - <li><code>(gdb) run /path/to/script.php</code></li> - <li><code>(gdb) bt</code></li> - </ul> - </li> - </ul> - </li> - </ul> - </li> -</ul> - -<p>This should generate a backtrace, that you should submit in -the bug report, along with any other details you can give us -about your setup, and offending script.</p> - -<h3>Locating which function call caused a segfault:</h3> - -<p>You can locate the function call that caused a segfault, easily, with gdb. -First, you need a core file or to generate a segfault under gdb as described -above.</p> - -<p>In PHP, each function is executed by an internal function called -<b><code>execute()</code></b> and has its own stack. Each line -generated by the <b><code>bt</code></b> command represents a function call -stack. Typically, you will see several <b><code>execute()</code></b> lines -when you issue <b><code>bt</code></b>. You are interested in the last -<b><code>execute()</code></b> stack (i.e. smallest frame -number). You can move the current working stack with the -<b><code>up</code></b>, <code>down</code> or -<b><code>frame</code></b> commands. Below is an example gdb session that can -be used as a guideline on how to handle your segfault.</p> - -<ul> - <li>Sample gdb session</li> - <pre><code> -(gdb) bt -#0 0x080ca21b in _efree (ptr=0xbfffdb9b) at zend_alloc.c:240 -#1 0x080d691a in _zval_dtor (zvalue=0x8186b94) at zend_variables.c:44 -#2 0x080cfab3 in _zval_ptr_dtor (zval_ptr=0xbfffdbfc) at zend_execute_API.c:274 -#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 -#4 0x080f1e06 in execute (op_array=0x816c530) at ./zend_execute.c:1638 -#5 0x080f1e06 in execute (op_array=0x816c278) at ./zend_execute.c:1638 -#6 0x080f1e06 in execute (op_array=0x8166eec) at ./zend_execute.c:1638 -#7 0x080d7b93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at zend.c:810 -#8 0x0805ea75 in php_execute_script (primary_file=0xbffff650) at main.c:1310 -#9 0x0805cdb3 in main (argc=2, argv=0xbffff6fc) at cgi_main.c:753 -#10 0x400c91be in __libc_start_main (main=0x805c580 <main>, argc=2, ubp_av=0xbffff6fc, - init=0x805b080 <_init>, fini=0x80f67b4 <_fini>, rtld_fini=0x4000ddd0 <_dl_fini>, - stack_end=0xbffff6ec) at ../sysdeps/generic/libc-start.c:129 -(gdb) frame 3 -#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 -(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name -$14 = 0x80fa6fa "pg_result_error" -(gdb) print (char *)executor_globals.active_op_array->function_name -$15 = 0x816cfc4 "result_error" -(gdb) print (char *)executor_globals.active_op_array->filename -$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php" -(gdb) - </code></pre> -</ul> - -<p>In this session, frame 3 is the last <b><code>execute()</code></b> -call. The <b><code>frame 3</code></b> command moves the current working stack -to the proper frame.<br> -<b><code>print (char *)(executor_globals.function_state_ptr->function)->common.function_name</code></b><br> -prints the function name. In the sample gdb session, the -<code>pg_result_error()</code> call -is causing the segfault. You can print any internal data that you like, -if you know the internal data structure. Please do not ask how to use gdb -or about the internal data structure. Refer to gdb manual for gdb usage -and to the PHP source for the internal data structure.</p> - -<p>You may not see <b><code>execute</code></b> if the segfault happens -without calling any functions.</p> - -<?php response_footer(); +// Output template with given template variables. +echo $template->render('pages/bugs_generating_backtrace.php');
diff --git a/include/functions.php b/include/functions.php index 5e314a2..fd3bbd7 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1707,32 +1707,6 @@ function inline_content_menu($base_url, $current_action, array $menu) echo "</p>\n"; } -/** - * Inline content menu for backtraces - * - * Specify either 'Unix' or 'Windows' to select the current page - */ -function backtrace_inline_menu($platform) -{ - if ($platform != 'Unix' && $platform != 'Windows') { - return; - } - - $buffer = ''; - - foreach (['Unix' => '', 'Windows' => '-win32'] as $platform_key => $platform_suffix) { - if ($platform_key == $platform) { - $buffer .= sprintf('<strong>%s</strong> | ', $platform_key); - } else { - $buffer .= sprintf('<a href="/bugs-generating-backtrace%s.php">%s</a> | ', $platform_suffix, $platform_key); - } - } - - echo "<p>"; - echo rtrim($buffer, ' | '); - echo "</p>\n"; -} - function admin_table_static(array $header, array $rows) { if (!$header || !$rows || sizeof($header) != sizeof($rows[0])) { diff --git a/templates/pages/bugs_generating_backtrace.php b/templates/pages/bugs_generating_backtrace.php new file mode 100644 index 0000000..b99f383 --- /dev/null +++ b/templates/pages/bugs_generating_backtrace.php @@ -0,0 +1,179 @@ +<?php $this->extends('layout.php', ['title' => 'Generating a gdb backtrace']) ?> + +<?php $this->start('content') ?> + +<p> +<strong>Unix</strong> | <a href="/bugs-generating-backtrace-win32.php">Windows</a> +</p> + +<h1>Generating a gdb backtrace</h1> + +<h3>Noticing PHP crashes</h3> + +There's no absolute way to know that PHP is crashing, but there may be signs. +Typically, if you access a page that is always supposed to generate output (has +a leading HTML block, for example), and suddenly get "Document contains no data" +from your browser, it may mean that PHP crashes somewhere along the execution of +the script. Another way to tell that PHP is crashing is by looking at the Apache +error logs, and looking for SEGV (Apache 1.2) or Segmentation Fault (Apache +1.3). + +<h3>Important!</h3> +To get a backtrace with correct information you must have PHP configured with +<code>--enable-debug</code>! + +<h3>If you don't have a core file yet:</h3> + +<ul> + <li> + Remove any limits you may have on core dump size from your shell: + <ul> + <li>tcsh: unlimit coredumpsize</li> + <li>bash/sh: ulimit -c unlimited</li> + </ul> + </li> + <li> + Ensure that the directory in which you're running PHP, or the + PHP-enabled httpd, has write permissions for the user who's running PHP. + </li> + <li> + Cause PHP to crash: + <ul> + <li>PHP CGI: Simply run php with the script that crashes it</li> + <li>PHP Apache Module: Run httpd -X, and access the script that crashes PHP</li> + </ul> + </li> +</ul> + +<h3>Generic way to get a core on Linux</h3> + +<ul> + <li> + Set up the core pattern (run this command as <i>root</i>): + <ul> + <li>echo "<cores dir>/core-%e.%p" > /proc/sys/kernel/core_pattern</li> + <li>make sure the directory is writable by PHP</li> + </ul> + </li> + <li>Set the ulimit (see above how to do it).</li> + <li>Restart/rerun PHP.</li> +</ul> + +<p>After that any process crashing in your system, including PHP, will leave its +core file in the directory you've specified in <i>core_pattern</i>.</p> + +<h3>Once you have the core file:</h3> + +<ul> + <li> + Run gdb with the path to the PHP or PHP-enabled httpd binary, and path + to the core file. Some examples: + <ul> + <li><code>gdb /usr/local/apache/sbin/httpd /usr/local/apache/sbin/core</code></li> + <li><code>gdb /home/user/dev/php-snaps/sapi/cli/php /home/user/dev/testing/core</code></li> + </ul> + </li> + <li> + At the gdb prompt, run: + <ul> + <li><code>(gdb) bt</code></li> + </ul> + </li> +</ul> + +<h3>If you can't get a core file:</h3> +<ul> + <li> + Run httpd -X under gdb with something like: + <ul> + <li><code>gdb /usr/local/apache/sbin/httpd</code></li> + <li>(gdb) run -X</li> + </ul> + </li> + <li> + Then use your web browser and access your server to force the crash. You + should see a gdb prompt appear and some message indicating that there + was a crash. At this gdb prompt, type: + <ul> + <li><code>(gdb) bt</code></li> + </ul> + <ul> + <li> + or, running from the commandline + <ul> + <li> + gdb /home/user/dev/php-snaps/sapi/cli/php + <ul> + <li><code>(gdb) run /path/to/script.php</code></li> + <li><code>(gdb) bt</code></li> + </ul> + </li> + </ul> + </li> + </ul> + </li> +</ul> + +<p>This should generate a backtrace, that you should submit in the bug report, +along with any other details you can give us about your setup, and offending +script.</p> + +<h3>Locating which function call caused a segfault:</h3> + +<p>You can locate the function call that caused a segfault, easily, with gdb. +First, you need a core file or to generate a segfault under gdb as described +above.</p> + +<p>In PHP, each function is executed by an internal function called +<b><code>execute()</code></b> and has its own stack. Each line generated by the +<b><code>bt</code></b> command represents a function call stack. Typically, you +will see several <b><code>execute()</code></b> lines when you issue +<b><code>bt</code></b>. You are interested in the last +<b><code>execute()</code></b> stack (i.e. smallest frame number). You can move +the current working stack with the <b><code>up</code></b>, <code>down</code> or +<b><code>frame</code></b> commands. Below is an example gdb session that can be +used as a guideline on how to handle your segfault.</p> + +<ul> + <li>Sample gdb session</li> + <pre><code> +(gdb) bt +#0 0x080ca21b in _efree (ptr=0xbfffdb9b) at zend_alloc.c:240 +#1 0x080d691a in _zval_dtor (zvalue=0x8186b94) at zend_variables.c:44 +#2 0x080cfab3 in _zval_ptr_dtor (zval_ptr=0xbfffdbfc) at zend_execute_API.c:274 +#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 +#4 0x080f1e06 in execute (op_array=0x816c530) at ./zend_execute.c:1638 +#5 0x080f1e06 in execute (op_array=0x816c278) at ./zend_execute.c:1638 +#6 0x080f1e06 in execute (op_array=0x8166eec) at ./zend_execute.c:1638 +#7 0x080d7b93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at zend.c:810 +#8 0x0805ea75 in php_execute_script (primary_file=0xbffff650) at main.c:1310 +#9 0x0805cdb3 in main (argc=2, argv=0xbffff6fc) at cgi_main.c:753 +#10 0x400c91be in __libc_start_main (main=0x805c580 <main>, argc=2, ubp_av=0xbffff6fc, + init=0x805b080 <_init>, fini=0x80f67b4 <_fini>, rtld_fini=0x4000ddd0 <_dl_fini>, + stack_end=0xbffff6ec) at ../sysdeps/generic/libc-start.c:129 +(gdb) frame 3 +#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 +(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name +$14 = 0x80fa6fa "pg_result_error" +(gdb) print (char *)executor_globals.active_op_array->function_name +$15 = 0x816cfc4 "result_error" +(gdb) print (char *)executor_globals.active_op_array->filename +$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php" +(gdb) + </code></pre> +</ul> + +<p>In this session, frame 3 is the last <b><code>execute()</code></b> call. The +<b><code>frame 3</code></b> command moves the current working stack to the +proper frame.<br> +<b><code>print (char *)(executor_globals.function_state_ptr->function)->common.function_name</code></b><br> +prints the function name. In the sample gdb session, the +<code>pg_result_error()</code> call is causing the segfault. You can print any +internal data that you like, if you know the internal data structure. Please do +not ask how to use gdb or about the internal data structure. Refer to gdb manual +for gdb usage and to the PHP source for the internal data structure.</p> + +<p>You may not see <b><code>execute</code></b> if the segfault happens without +calling any functions.</p> + +<?php $this->end('content') ?> diff --git a/templates/pages/bugs_generating_backtrace_win32.php b/templates/pages/bugs_generating_backtrace_win32.php new file mode 100644 index 0000000..985be24 --- /dev/null +++ b/templates/pages/bugs_generating_backtrace_win32.php @@ -0,0 +1,105 @@ +<?php $this->extends('layout.php', ['title' => 'Generating a backtrace on Windows']) ?> + +<?php $this->start('content') ?> + +<p> +<a href="/bugs-generating-backtrace.php">Unix</a> | <strong>Windows</strong> +</p> + +<h1>Generating a backtrace, <u>with</u> a compiler, on Windows</h1> + +<p>You'll need to install MS Visual Studio 2008, 2012 or later. You'll also need to</p> +<ul> + <li>either download the debug-pack for your PHP version from <a href="https://windows.php.net/download/">windows.php.net/download</a></li> + <li>or compile your own PHP with <code>--enable-dbg-pack</code> or <code>--enable-debug</code></li> +</ul> + +<p>If you downloaded the debug-pack from the snaps site, extract it into your +PHP directory and be sure to put the PDB files that belong to the extensions +into your extension directory.</p> + +<p>If you compile PHP by your own, you can also use a newer version of MSVC.</p> + +<p>When PHP crashes, click <em>Cancel</em> to debug the process. Now MSVC starts +up in <em>Debug View</em>. If you don't already see the call stack, go into the +<em>View</em> menu and choose <em>Debug Windows</em> → <em>Call Stack</em>.</p> + +<p>You'll now see something similar to the following lines, this is the backtrace:</p> +<pre><code> +_efree(void * 0x00000000) line 286 + 3 bytes +zif_http_test(int 0, _zval_struct * 0x007bc3b0, _zval_struct * * 0x00000000, _zval_struct * 0x00000000, int 0, void * * * 0x00792cd0) line 1685 + 8 bytes +zend_do_fcall_common_helper_SPEC(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 188 + 95 bytes +ZEND_DO_FCALL_SPEC_CONST_HANDLER(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 1578 + 13 bytes +execute(_zend_op_array * 0x007bc880, void * * * 0x00792cd0) line 88 + 13 bytes +zend_eval_string(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', void * * * 0x00792cd0) line 1056 + 14 bytes +zend_eval_string_ex(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', int 1, void * * * 0x00792cd0) line 1090 + 21 bytes +main(int 3, char * * 0x00793ba8) line 1078 + 23 bytes +PHP! mainCRTStartup + 227 bytes +KERNEL32! 77e81af6() +</code></pre> + +<!-- + Everything below is stolen from Pierre Joye + https://blog.thepimp.net/index.php/post/2007/06/10/debug-pack-or-how-to-generate-backtrack-on-windows-without-compiling +--> +<h1>Generating backtrace, <u>without</u> compiler, on Windows</h1> + +<p>You'll need:</p> + +<ul> +<li>A PHP <a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a> release</li> +<li>PHP Debug pack (<a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a>)</li> +<li>Microsoft <a href="https://www.microsoft.com/en-us/download/details.aspx?id=49924">Debug Diagnostic Tools</a></li> +<li>Evil script to crash PHP</li> +</ul> + +<p>For the sake of this example, we will simply use PHP in the shell. The same +method can be used for IIS or any other process or services.</p> + + +<p>Once you have installed the Debug diagnostic tools and uncompressed PHP and +its debug pack (they can be kept in two separate folders), the first step is to +configure the diagnostic tools. Select the tools menu and click on "Options and +settings". The first tab contains the path to the symbols files, add the "debug +folder" to the existing list using the "browse" button:</p> + +<p><img src="/images/backtrace-images-win32/dbg_options.png" alt="Options"></p> + +<p>Now we are ready to generate our backtrace.</p> + +<p>We will use the wizard, click the "Add a rule" button and choose "Crash" as +the rule type:</p> +<p><img src="/images/backtrace-images-win32/dbg_wizard_1.png" alt="Wizard #1"></p> + +<p>In the next window, select "a specific process":</p> + +<p><img src="/images/backtrace-images-win32/dbg_wizard_2.png" alt="Wizard #2"></p> + +<p>Add a "sleep(10);" for the first run (from the cmd: "php.exe crashme.php"), +it will let you enough time to click "next" and select the php process. If you +are debugging the Apache module, start Apache with -X option and choose +httpd.exe instead of php.exe from the process list. Then proceed further:</p> + +<p><img src="/images/backtrace-images-win32/dbg_select_php.png" alt="Select the php process"></p> + +<p>Click again next and let it crash. If everything went well, you should see +your new rule as shown in the image below:</p> + +<p><img src="/images/backtrace-images-win32/rules.jpg" alt="rules list"></p> + +<p>It also detected that "php.exe" was used. A rule has been created for all +instance of "php.exe". It will save you the sleep and process selection.</p> + +<p>Now you can click the "Analyze data" button:</p> + +<p><img src="/images/backtrace-images-win32/analyze.jpg" alt="Analyze"></p> + +<p>Et voila, the complete report will show up in your internet explorer +(compressed html):</p> + +<p><img src="/images/backtrace-images-win32/backtrace.jpg" alt="Debug report backtrace screenshot"></a></p> + +<p>What we need is the backtrace itself which can be found under "Thread X - +System ID XXX".</p> + +<?php $this->end('content') ?> diff --git a/www/bugs-generating-backtrace-win32.php b/www/bugs-generating-backtrace-win32.php index a12c26a..cc09a36 100644 --- a/www/bugs-generating-backtrace-win32.php +++ b/www/bugs-generating-backtrace-win32.php @@ -1,99 +1,14 @@ <?php -session_start(); +/** + * Page with a quick info how to generate backtrace with compiler on Windows. + */ -require_once '../include/prepend.php'; +// Application bootstrap +require_once __DIR__.'/../include/prepend.php'; -// Authenticate -bugs_authenticate($user, $pw, $logged_in, $user_flags); +// Authentication +require_once __DIR__.'/../include/auth.php'; -response_header('Generating a backtrace on Windows'); - -backtrace_inline_menu('Windows'); -?> - -<h1>Generating a backtrace, <u>with</u> a compiler, on Windows</h1> - -<p>You'll need to install MS Visual Studio 2008, 2012 or later. You'll also need to</p> -<ul> - <li>either download the debug-pack for your PHP version from <a href="https://windows.php.net/download/">windows.php.net/download</a></li> - <li>or compile your own PHP with <code>--enable-dbg-pack</code> or <code>--enable-debug</code></li> -</ul> - -<p>If you downloaded the debug-pack from the snaps site, extract it into -your PHP directory and be sure to put the PDB files that belong to the -extensions into your extension directory.</p> - -<p>If you compile PHP by your own, you can also use a newer version of MSVC.</p> - -<p>When PHP crashes, click <em>Cancel</em> to debug the process. Now MSVC starts -up in <em>Debug View</em>. If you don't already see the call stack, go into the -<em>View</em> menu and choose <em>Debug Windows</em> → <em>Call Stack</em>.</p> - -<p>You'll now see something similar to the following lines, this is the backtrace:</p> -<pre><code> -_efree(void * 0x00000000) line 286 + 3 bytes -zif_http_test(int 0, _zval_struct * 0x007bc3b0, _zval_struct * * 0x00000000, _zval_struct * 0x00000000, int 0, void * * * 0x00792cd0) line 1685 + 8 bytes -zend_do_fcall_common_helper_SPEC(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 188 + 95 bytes -ZEND_DO_FCALL_SPEC_CONST_HANDLER(_zend_execute_data * 0x0012fd6c, void * * * 0x00792cd0) line 1578 + 13 bytes -execute(_zend_op_array * 0x007bc880, void * * * 0x00792cd0) line 88 + 13 bytes -zend_eval_string(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', void * * * 0x00792cd0) line 1056 + 14 bytes -zend_eval_string_ex(char * 0x00793bce, _zval_struct * 0x00000000, char * 0x00404588 tring', int 1, void * * * 0x00792cd0) line 1090 + 21 bytes -main(int 3, char * * 0x00793ba8) line 1078 + 23 bytes -PHP! mainCRTStartup + 227 bytes -KERNEL32! 77e81af6() -</code></pre> - -<!-- - Everything below is stolen from Pierre Joye - https://blog.thepimp.net/index.php/post/2007/06/10/debug-pack-or-how-to-generate-backtrack-on-windows-without-compiling ---> -<h1>Generating backtrace, <u>without</u> compiler, on Windows</h1> -<p>You'll need:</p> -<ul> -<li>A PHP <a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a> release</li> -<li>PHP Debug pack (<a href="https://windows.php.net/downloads/snaps/">snapshot</a> or <a href="https://windows.php.net/download/">stable</a>)</li> -<li>Microsoft <a href="https://www.microsoft.com/en-us/download/details.aspx?id=49924">Debug Diagnostic Tools</a></li> -<li>Evil script to crash PHP</li> -</ul> -<p>For the sake of this example, we will simply use PHP in the shell. -The same method can be used for IIS or any other process or services.</p> - - -<p>Once you have installed the Debug diagnostic tools and uncompressed -PHP and its debug pack (they can be kept in two separate folders), the -first step is to configure the diagnostic tools. Select the -tools menu and click on "Options and settings". The first tab contains -the path to the symbols files, add the "debug folder" to the existing -list using the "browse" button:</p> -<p><img src="/images/backtrace-images-win32/dbg_options.png" alt="Options"></p> - -<p>Now we are ready to generate our backtrace.</p> -<p>We will use the wizard, click the "Add a rule" button and choose "Crash" as the rule type:</p> -<p><img src="/images/backtrace-images-win32/dbg_wizard_1.png" alt="Wizard #1"></p> - -<p>In the next window, select "a specific process":</p> -<p><img src="/images/backtrace-images-win32/dbg_wizard_2.png" alt="Wizard #2"></p> - -<p>Add a "sleep(10);" for the first run (from the cmd: "php.exe -crashme.php"), it will let you enough time to click "next" and select -the php process. I you are debugging the Apache module, start Apache with -X option and choose -httpd.exe instead of php.exe from the process list. -Then proceed further:</p> -<p><img src="/images/backtrace-images-win32/dbg_select_php.png" alt="Select the php process"></p> - -<p>Click again next and let it crash. If everything went well, you should see your new rule as shown in the image below:</p> -<p><img src="/images/backtrace-images-win32/rules.jpg" alt="rules list"></p> - -<p>It also detected that "php.exe" was used. A rule has been created -for all instance of "php.exe". It will save you the sleep and process -selection.</p> -<p>Now you can click the "Analyze data" button:</p> -<p><img src="/images/backtrace-images-win32/analyze.jpg" alt="Analyze"></p> - -<p>Et voila, the complete report will show up in your internet explorer (compressed html):</p> -<p><img src="/images/backtrace-images-win32/backtrace.jpg" alt="Debug report backtrace screenshot"></a></p> - -<p>What we need is the backtrace itself which can be found under "Thread X - System ID XXX".</p> - -<?php response_footer(); +// Output template with given template variables. +echo $template->render('pages/bugs_generating_backtrace_win32.php'); diff --git a/www/bugs-generating-backtrace.php b/www/bugs-generating-backtrace.php index 5e6fafc..4729ec6 100644 --- a/www/bugs-generating-backtrace.php +++ b/www/bugs-generating-backtrace.php @@ -1,192 +1,14 @@ <?php -session_start(); +/** + * Page with a quick info how to generate gdb backtrace on Unix. + */ -require_once '../include/prepend.php'; +// Application bootstrap +require_once __DIR__.'/../include/prepend.php'; -// Authenticate -bugs_authenticate($user, $pw, $logged_in, $user_flags); +// Authentication +require_once __DIR__.'/../include/auth.php'; -response_header('Generating a gdb backtrace'); - -backtrace_inline_menu('Unix'); - -?> - -<h1>Generating a gdb backtrace</h1> - -<h3>Noticing PHP crashes</h3> - -There's no absolute way to know that PHP is crashing, but there may -be signs. Typically, if you access a page that is always supposed -to generate output (has a leading HTML block, for example), and -suddenly get "Document contains no data" from your browser, it may -mean that PHP crashes somewhere along the execution of the script. -Another way to tell that PHP is crashing is by looking at the Apache -error logs, and looking for SEGV (Apache 1.2) or Segmentation -Fault (Apache 1.3). - -<h3>Important!</h3> -To get a backtrace with correct information you must have -PHP configured with <code>--enable-debug</code>! - -<h3>If you don't have a core file yet:</h3> - -<ul> - <li> - Remove any limits you may have on core dump size from your shell: - <ul> - <li>tcsh: unlimit coredumpsize</li> - <li>bash/sh: ulimit -c unlimited</li> - </ul> - </li> - <li> - Ensure that the directory in which you're running PHP, or the - PHP-enabled httpd, has write permissions for the user who's running PHP. - </li> - <li> - Cause PHP to crash: - <ul> - <li>PHP CGI: Simply run php with the script that crashes it</li> - <li>PHP Apache Module: Run httpd -X, and access the script that crashes PHP</li> - </ul> - </li> -</ul> - -<h3>Generic way to get a core on Linux</h3> - -<ul> - <li> - Set up the core pattern (run this command as <i>root</i>): - <ul> - <li>echo "<cores dir>/core-%e.%p" > /proc/sys/kernel/core_pattern</li> - <li>make sure the directory is writable by PHP</li> - </ul> - </li> - <li> - Set the ulimit (see above how to do it). - </li> - <li> - Restart/rerun PHP. - </li> -</ul> -<p>After that any process crashing in your system, including PHP, will leave -its core file in the directory you've specified in <i>core_pattern</i>.</p> - -<h3>Once you have the core file:</h3> - -<ul> - <li> - Run gdb with the path to the PHP or PHP-enabled httpd binary, and - path to the core file. Some examples: - <ul> - <li><code>gdb /usr/local/apache/sbin/httpd /usr/local/apache/sbin/core</code></li> - <li><code>gdb /home/user/dev/php-snaps/sapi/cli/php /home/user/dev/testing/core</code></li> - </ul> - </li> - <li> - At the gdb prompt, run: - <ul> - <li><code>(gdb) bt</code></li> - </ul> - </li> -</ul> - -<h3>If you can't get a core file:</h3> -<ul> - <li> - Run httpd -X under gdb with something like: - <ul> - <li><code>gdb /usr/local/apache/sbin/httpd</code></li> - <li>(gdb) run -X</li> - </ul> - </li> - <li> - Then use your web browser and access your server to force the crash. - You should see a gdb prompt appear and some message indicating that - there was a crash. At this gdb prompt, type: - <ul> - <li><code>(gdb) bt</code></li> - </ul> - <ul> - <li> - or, running from the commandline - <ul> - <li> - gdb /home/user/dev/php-snaps/sapi/cli/php - <ul> - <li><code>(gdb) run /path/to/script.php</code></li> - <li><code>(gdb) bt</code></li> - </ul> - </li> - </ul> - </li> - </ul> - </li> -</ul> - -<p>This should generate a backtrace, that you should submit in -the bug report, along with any other details you can give us -about your setup, and offending script.</p> - -<h3>Locating which function call caused a segfault:</h3> - -<p>You can locate the function call that caused a segfault, easily, with gdb. -First, you need a core file or to generate a segfault under gdb as described -above.</p> - -<p>In PHP, each function is executed by an internal function called -<b><code>execute()</code></b> and has its own stack. Each line -generated by the <b><code>bt</code></b> command represents a function call -stack. Typically, you will see several <b><code>execute()</code></b> lines -when you issue <b><code>bt</code></b>. You are interested in the last -<b><code>execute()</code></b> stack (i.e. smallest frame -number). You can move the current working stack with the -<b><code>up</code></b>, <code>down</code> or -<b><code>frame</code></b> commands. Below is an example gdb session that can -be used as a guideline on how to handle your segfault.</p> - -<ul> - <li>Sample gdb session</li> - <pre><code> -(gdb) bt -#0 0x080ca21b in _efree (ptr=0xbfffdb9b) at zend_alloc.c:240 -#1 0x080d691a in _zval_dtor (zvalue=0x8186b94) at zend_variables.c:44 -#2 0x080cfab3 in _zval_ptr_dtor (zval_ptr=0xbfffdbfc) at zend_execute_API.c:274 -#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 -#4 0x080f1e06 in execute (op_array=0x816c530) at ./zend_execute.c:1638 -#5 0x080f1e06 in execute (op_array=0x816c278) at ./zend_execute.c:1638 -#6 0x080f1e06 in execute (op_array=0x8166eec) at ./zend_execute.c:1638 -#7 0x080d7b93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at zend.c:810 -#8 0x0805ea75 in php_execute_script (primary_file=0xbffff650) at main.c:1310 -#9 0x0805cdb3 in main (argc=2, argv=0xbffff6fc) at cgi_main.c:753 -#10 0x400c91be in __libc_start_main (main=0x805c580 <main>, argc=2, ubp_av=0xbffff6fc, - init=0x805b080 <_init>, fini=0x80f67b4 <_fini>, rtld_fini=0x4000ddd0 <_dl_fini>, - stack_end=0xbffff6ec) at ../sysdeps/generic/libc-start.c:129 -(gdb) frame 3 -#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605 -(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name -$14 = 0x80fa6fa "pg_result_error" -(gdb) print (char *)executor_globals.active_op_array->function_name -$15 = 0x816cfc4 "result_error" -(gdb) print (char *)executor_globals.active_op_array->filename -$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php" -(gdb) - </code></pre> -</ul> - -<p>In this session, frame 3 is the last <b><code>execute()</code></b> -call. The <b><code>frame 3</code></b> command moves the current working stack -to the proper frame.<br> -<b><code>print (char *)(executor_globals.function_state_ptr->function)->common.function_name</code></b><br> -prints the function name. In the sample gdb session, the -<code>pg_result_error()</code> call -is causing the segfault. You can print any internal data that you like, -if you know the internal data structure. Please do not ask how to use gdb -or about the internal data structure. Refer to gdb manual for gdb usage -and to the PHP source for the internal data structure.</p> - -<p>You may not see <b><code>execute</code></b> if the segfault happens -without calling any functions.</p> - -<?php response_footer(); +// Output template with given template variables. +echo $template->render('pages/bugs_generating_backtrace.php');