Cómo depurar el núcleo de PHP para obtener información básica
lt? Función PHP recurse($num){ recurse($num);} recurse(0);
Ejecute este archivo PHP:
$php error de segmentación (volcado de núcleo)
Debido a la recursividad inalámbrica, este PHP hará que la pila explote y cause una falla de segmentación. PHP generará un archivo Coredump en el directorio de trabajo actual (si su sistema no genera un archivo Coredump, verifique la configuración relevante). de ulimit).
Bien, ahora eliminemos este test.php y olvidemos el código anterior. Todo lo que tenemos ahora es este documento básico. La tarea es descubrir qué causa este núcleo y en qué estado se produce.
Primero, abramos este archivo principal con gdb:
$ gdb php -c core.31656
Verás mucha información, déjanos preste atención primero a este párrafo:
El núcleo se genera mediante "php test.php". Programa terminado, señal 11, fallo de segmentación.
Nos contó lo que le pasó al núcleo: "Fallo de Segmentación".
En términos generales, este tipo de núcleo es el más común: desreferenciación de puntero nulo, doble libre, explosión de pila, etc. , Se activará SIGSEGV y se generará Coredump de forma predeterminada.
Ahora, echemos un vistazo a la pila cuando ocurre el núcleo:
# 0 ejecutar(op _ array = 0 xdc9a 70)en /home/la runce/package/PHP - 5.2.14/Zend/Zend_VM_execute.h: 5353 memset(EX(CVs), 0, sizeof(zval * *)* op_array-gt; last_var); (gdb) Bt # 0 ejecutar(op_array = 0x DC 9a 70) en/home/la runce/package/PHP-5 2 . home/la runce/package.....
Si continúa presionando Enter, puede ver que la pila es muy profunda. Repita Zend_do_fcall_common_helper_spec y ejecute, entonces básicamente se puede concluir que se ha producido una recursividad infinita. (No necesariamente recursividad infinita, por ejemplo, mi artículo anterior introdujo el límite máximo de retroceso/recursión de pcre), lo que resultó en una pila El núcleo de la explosión.
Bien, ahora veamos qué sucede en el núcleo de PHP.
En PHP, para el controlador del código de operación FCALL_*, ejecutar_datos representa un estado de la llamada de función actual. Este estado contiene información:
(gdb)f 1 # 1 0x 00000000006 ea 263 en Zend _ do _. fcall_common_helper_SPEC(execute_data = 0x 7 fbf 400210)at/home/la runquee/package/PHP-5.2.14/Zend/Zend_VM_execute.h:234234 Zend_execute(por ejemplo, (active_op_array(gdb)p ejecutar_data->function_status.function-gt;common -gt;nombre_función$3 = 0x 2a 95 b 65 a 78 "recurse "(gdb)p ejecutar_datos-gt; estado_función.función-gt;op_array-gt;nombre de archivo $4 = 0x 2 a95b 632 a 0 "/home/la runce/ test .PHP "(gdb)p ejecutar_data-gt;function_status.function ->op_array->line_start$5 = 2
Ahora sabemos que la función PHP que se llama es recursiva, que se define en la segunda línea de /home/home/laruence/test.php
Después de verificar repetidamente varios cuadros, puede ver que esta función PHP se llama repetidamente
Cabe señalar que para poder hacerlo. Para introducir el principio de ver la información de ejecución, solo uso gdb. Print nativo para ver. De hecho, también podemos usar el gdbinit (script de comando gdb) proporcionado en el código fuente de PHP para obtener simplemente la información anterior:
(gdb)source/home/la runce/package/ PHP-5 2 .gdbinit(gdb)zback trace[0x BF 400210]recurse()/home/l rance/test PHP: 3[0x BF 400440]recurse()/home/l rance/test PHP: 3[0x BF 400670]recurse()/home/l rance/test. rance/prueba. PHP: 3[0x BF 40000... ..
Acerca de. gdbinit es un pequeño archivo de script que define algunos núcleos que facilitan nuestra depuración de PHP. También puedes abrirlo con un editor de texto para ver algunos comandos de acceso directo definidos en él. En términos generales, suelo utilizar:
Zbacktraceprint_ht** series zmemcheck
Bien, volviendo al tema, ahora sabemos que el problema ocurre en la recursividad de /home/laruence/test .php Durante una llamada recursiva a una función.
Ahora, echemos un vistazo, ¿cuáles son los parámetros al llamar a esta función?
El paso de parámetros de PHP se basa en una pila global, es decir, EG (argumento _ pila). EG es executor_globals en situaciones sin subprocesos múltiples, lo que mantiene una gran cantidad de estado de ejecución.
argument_statck es la pila de transferencia de parámetros, que almacena los parámetros de llamada correspondientes a la capa de llamada de función PHP.
Cabe señalar que no existe una correspondencia simple uno a uno entre la pila de llamadas a funciones PHP (capas) y el rastreo visto por gdb, por lo que los parámetros no pueden corresponder directamente al rastreo de gdb y debe analizarse por separado:
//Echemos un vistazo al número de parámetros de la última llamada a la función (GDB)p(int)*(executor _ globals-> argument _ stack- gt; top _ element-2)$ 13 = 1// Mira de nuevo, la última llamada a función (GDB) p * * (zval * *) (executor_globals->argument_stack-gt; top_element-3)$2 = { value = { lval = 22445 , dval = 1.1089303420906779 e-319, str = { val = 0x57ad lt dirección 0x57ad fuera de límites gt, len = 7}, ht = 0x57ad, obj = {handle = 22445, handlers = 0x7}}, refcount = 2, type = 1 '\001' , is_ref = 0 '\0'}
Bien, ahora sabemos que el último parámetro llamado es un número entero con un valor de 22445.
En este paso obtenemos información relevante a nivel de PHP en el momento en que se produce el core. A continuación, podemos entregárselo al ingeniero de desarrollo de PHP correspondiente para que investigue las posibles causas de la recursividad infinita bajo este parámetro para solucionar este problema. ..