c++ - raspberry - ¿Cómo se lee un mensaje de registro de kernel segfault?
segmentation fault raspberry pi (3)
Si es una biblioteca compartida
Estás sucio, desafortunadamente; no es posible saber dónde colocaron las bibliotecas en memoria el enlazador dinámico después de los hechos .
Bueno, todavía hay una posibilidad de recuperar la información, no del binario, sino del objeto. Pero necesitas la dirección base del objeto. Y esta información aún está dentro del núcleo, en la estructura link_map.
Entonces primero quieres importar la estructura link_map en GDB. Entonces, compilemos un programa con el símbolo de depuración y lo agreguemos al GDB.
link.c
#include <link.h>
toto(){struct link_map * s = 0x400;}
get_baseaddr_from_coredump.sh
#!/bin/bash
BINARY=$(which myapplication)
IsBinPIE ()
{
readelf -h $1|grep ''Type'' |grep "EXEC">/dev/null || return 0
return 1
}
Hex2Decimal ()
{
export number="`echo "$1" | sed -e ''s:^0[xX]::'' | tr ''[a-f]'' ''[A-F]''`"
export number=`echo "ibase=16; $number" | bc`
}
GetBinaryLength ()
{
if [ $# != 1 ]; then
echo "Error, no argument provided"
fi
IsBinPIE $1 || (echo "ET_EXEC file, need a base_address"; exit 0)
export totalsize=0
# Get PT_LOAD''s size segment out of Program Header Table (ELF format)
export sizes="$(readelf -l $1 |grep LOAD |awk ''{print $6}''|tr ''/n'' '' '')"
for size in $sizes
do Hex2Decimal "$size"; export totalsize=$(expr $number + $totalsize); export totalsize=$(expr $number + $totalsize)
done
return $totalsize
}
if [ $# = 1 ]; then
echo "Using binary $1"
IsBinPIE $1 && (echo "NOT ET_EXEC, need a base_address..."; exit 0)
BINARY=$1
fi
gcc -g3 -fPIC -shared link.c -o link.so
GOTADDR=$(readelf -S $BINARY|grep -E ''/.got.plt[ /t]''|awk ''{print $4}'')
echo "First do the following command :"
echo file $BINARY
echo add-symbol-file ./link.so 0x0
read
echo "Now copy/paste the following into your gdb session with attached coredump"
cat <<EOF
set /$linkmapaddr = *(0x$GOTADDR + 4)
set /$mylinkmap = (struct link_map *) /$linkmapaddr
while (/$mylinkmap != 0)
if (/$mylinkmap->l_addr)
printf "add-symbol-file .%s %#.08x/n", /$mylinkmap->l_name, /$mylinkmap->l_addr
end
set /$mylinkmap = /$mylinkmap->l_next
end
le imprimirá todo el contenido link_map, dentro de un conjunto de comandos GDB.
En sí mismo, puede parecer que no se escanea, pero con el base_addr del objeto compartido que tratamos, puede obtener más información de una dirección depurando directamente el objeto compartido involucrado en otra instancia de GDB. Guarde el primer gdb para tener una idea del símbolo.
NOTA: la secuencia de comandos es bastante incompleta, sospecho que puede agregar al segundo parámetro de agregar-símbolo-archivo impreso la suma con este valor:
readelf -S $SO_PATH|grep -E ''/.text[ /t]''|awk ''{print $5}''
donde $ SO_PATH es el primer argumento del add-symbol-file
Espero eso ayude
Esta puede ser una pregunta muy simple, estoy intentando depurar una aplicación que genera el siguiente error segfault en kern.log
kernel: myapp[15514]: segfault at 794ef0 ip 080513b sp 794ef0 error 6 in myapp[8048000+24000]
Aquí están mis preguntas:
¿Hay alguna documentación sobre cuáles son los números de error de diferencia en segfault, en este caso es el error 6, pero he visto el error 4, 5?
¿Cuál es el significado de la información
at bf794ef0 ip 0805130b sp bf794ef0 and myapp[8048000+24000]
?
Hasta ahora pude compilar con símbolos, y cuando hago un x 0x8048000+24000
, devuelve un símbolo, ¿es esa la forma correcta de hacerlo? Mis suposiciones hasta ahora son las siguientes:
- sp = puntero de pila?
- ip = puntero de instrucción
- at = ????
- myapp [8048000 + 24000] = dirección del símbolo?
Cuando el informe apunta a un programa, no a una biblioteca compartida
Ejecute addr2line -e myapp 080513b
(y repita para los otros valores de puntero de instrucción proporcionados) para ver dónde está ocurriendo el error. Mejor, obtenga una compilación instrumentada de depuración y reproduzca el problema bajo un depurador como gdb.
Si es una biblioteca compartida
En la parte libfoo.so[NNNNNN+YYYY]
, el NNNNNN
es donde se cargó la biblioteca. Reste esto del puntero de instrucción ( ip
) y obtendrá el desplazamiento en el .so
de la instrucción ofensiva. Luego puede usar objdump -DCgl libfoo.so
y buscar las instrucciones en ese desplazamiento. Debería ser capaz de averiguar fácilmente qué función es de las etiquetas asm. Si .so
no tiene optimizaciones, también puede intentar usar addr2line -e libfoo.so <offset>
.
Lo que significa el error
Aquí está el desglose de los campos:
-
address
: la ubicación en la memoria a la que intenta acceder el código (es probable que10
y11
sean desplazamientos desde un puntero que esperamos que se establezca en un valor válido pero que apunta a0
) -
ip
- puntero de instrucción, es decir. donde el código que está tratando de hacer esto vive - puntero
sp
- stack -
error
- Indicadores específicos de la arquitectura; verarch/*/mm/fault.c
para su plataforma.
En base a mi conocimiento limitado, sus suposiciones son correctas.
-
sp
= puntero de pila -
ip
= puntero de instrucción -
myapp[8048000+24000]
= dirección
Si estuviera depurando el problema, modificaría el código para producir un volcado de núcleo o registrar una traza inversa en el bloqueo. También puede ejecutar el programa debajo (o adjuntar) GDB.
El código de error es solo el código de error arquitectónico para fallas de página y parece ser específico de la arquitectura. A menudo están documentados en arch/*/mm/fault.c
en la fuente del kernel. Mi copia de Linux/arch/i386/mm/fault.c
tiene la siguiente definición para error_code:
- bit 0 == 0 significa que no se encontró la página, 1 significa falla de protección
- bit 1 == 0 significa leer, 1 significa escribir
- bit 2 == 0 significa kernel, 1 significa modo de usuario
Mi copia de Linux/arch/x86_64/mm/fault.c
agrega lo siguiente:
- bit 3 == 1 significa que la falla fue una instrucción de búsqueda