Inline GDB scripts in the PHP binary (#13600)

This inlines .gdbinit and php_gdb.py in the .debug_gdb_scripts section of the PHP binary so that GDB can auto-load them regardless of the current directory or the availability of the PHP source code (albeit some functionalities of php_gdb.py currently rely on the source being available).
This commit is contained in:
Arnaud Le Blanc 2024-04-16 15:10:01 +02:00 committed by GitHub
parent af5db45dc9
commit 46b6ad6dae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1091 additions and 2 deletions

1
.gitattributes vendored
View File

@ -21,6 +21,7 @@
# Collapse generated files within git and pull request diff.
**/*_arginfo.h linguist-generated -diff
/main/gdb_inlined_script.c linguist-generated -diff
/Zend/zend_vm_execute.h linguist-generated -diff
/Zend/zend_vm_handlers.h linguist-generated -diff
/Zend/zend_vm_opcodes.[ch] linguist-generated -diff

View File

@ -8,6 +8,7 @@ runs:
[[ "$OSTYPE" == "darwin"* ]] && export PATH="$(brew --prefix)/opt/bison/bin:$PATH"
scripts/dev/credits
scripts/dev/genfiles
scripts/gdb/debug_gdb_scripts_gen.php
Zend/zend_vm_gen.php
ext/tokenizer/tokenizer_data_gen.php
build/gen_stub.php -f --generate-optimizer-info --verify

View File

@ -1700,6 +1700,17 @@ PHP_ADD_SOURCES(main, main.c snprintf.c spprintf.c \
network.c php_open_temporary_file.c php_odbc_utils.c safe_bcmp.c \
output.c getopt.c php_syslog.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
if printf "#if __ELF__\nelf\n#endif\n" | $CC -E - | grep elf > /dev/null; then
PHP_ADD_SOURCES(main, debug_gdb_scripts.c)
cat >> Makefile.objects <<EOF
$abs_srcdir/main/debug_gdb_scripts.c: $abs_srcdir/scripts/gdb/debug_gdb_scripts_gen.php $abs_srcdir/scripts/gdb/php_gdb.py $abs_srcdir/.gdbinit
@if test ! -z "\$(PHP)"; then \\
\$(PHP) $abs_srcdir/scripts/gdb/debug_gdb_scripts_gen.php; \\
fi;
EOF
fi
PHP_ADD_SOURCES_X(main, fastcgi.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1, PHP_FASTCGI_OBJS, no)
PHP_ADD_SOURCES(main/streams, streams.c cast.c memory.c filter.c \

1018
main/debug_gdb_scripts.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
#!/usr/bin/env php
<?php
$rootDir = dirname(__DIR__, 2);
$mainDir = sprintf('%s/main', $rootDir);
$outputFile = sprintf('%s/debug_gdb_scripts.c', $mainDir);
printf("Generating %s\n", $outputFile);
$gdbscript = file_get_contents(sprintf("%s/.gdbinit", $rootDir));
$pyscript = file_get_contents(sprintf("%s/php_gdb.py", __DIR__));
// We can not inline .gdbinit, but we can embed it in the python script.
$pyscript = sprintf(
"gdb.execute('''\n%s\n''')\n%s",
addcslashes($gdbscript, '\'\\'),
$pyscript,
);
$ccode = sprintf(
<<<'C'
/*
* Generated by %s.
*
* This inlines .gdbinit and php_gdb.py into the .debug_gdb_scripts
* section of the binary, so that they can be found by gdb.
*
* See https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html#dotdebug_005fgdb_005fscripts-section
*/
asm(
".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n"
".byte 4 /* Python Text */\n"
".ascii \"gdb.inlined-script\\n\"\n"
%s
".byte 0\n"
".popsection\n"
);
C,
basename(__FILE__),
implode("\n ", array_map(function ($line) {
$escapedPy = addcslashes($line."\n", "\"\n\\");
$escapedAsm = addcslashes(sprintf(".ascii \"%s\"\n", $escapedPy), "\"\n\\");
return sprintf('"%s"', $escapedAsm);
}, explode("\n", $pyscript))),
);
$len = file_put_contents($outputFile, $ccode);
if ($len !== strlen($ccode)) {
printf("Failed\n");
exit(1);
}

View File

@ -1,9 +1,14 @@
"""GDB support for PHP types
Add this to your gdb by amending your ~/.gdbinit as follows:
This is auto-loaded by GDB if Python Auto-loading is enabled (the default), and
the PHP binary is in the auto load safe path:
source .gdb.py
# ~/.config/gdb/gdbinit (not ~/.gdbinit)
add-auto-load-safe-path /path/to/php-src
See https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-Auto_002dloading.html
See https://sourceware.org/gdb/current/onlinedocs/gdb.html/Auto_002dloading-safe-path.html#Auto_002dloading-safe-path
If needed, pretty printers can be by-passed by using the /r flag:
(gdb) p /r any_variable