Comment conditionner facilement les bibliothèques nécessaires à l’parsing d’un dump (par exemple, packcore)

La version de GDB disponible sur HPUX possède une commande appelée “packcore”, qui crée une archive contenant le fichier de sauvegarde, l’exécutable et toutes les bibliothèques. J’ai trouvé cela extrêmement utile lorsque j’essaie de déboguer des vidages de mémoire sur une machine différente.

Existe-t-il une commande similaire dans la version standard de GDB que je pourrais trouver sur une machine Linux?

Je cherche une commande facile qui veut que quelqu’un qui n’est pas nécessairement un développeur puisse s’exécuter lorsque les choses vont mal sur une machine de production.

Le fichier de base comprend la commande à partir de laquelle il a été généré. Idéalement, cela inclura le chemin d’access complet à l’exécutable approprié. Par exemple:

$ file core.29529 core.29529: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from '/bin/sleep 60' 

Exécuter ldd sur un binary ELF montrera de quelles bibliothèques il dépend:

 $ ldd /bin/sleep linux-vdso.so.1 => (0x00007fff1d3ff000) libc.so.6 => /lib64/libc.so.6 (0x0000003d3ce00000) /lib64/ld-linux-x86-64.so.2 (0x0000003d3ca00000) 

Alors maintenant, je connais l’exécutable et les bibliothèques nécessaires pour parsingr le fichier de vidage principal.

La partie délicate ici consiste à extraire le chemin d’exécutable du fichier principal. Il ne semble pas être un bon outil pour lire ceci directement. Les données sont codées dans une structure prpsinfo (à partir de /usr/include/sys/procfs.h ), et vous pouvez trouver la taille de l’emplacement des données à l’aide de readelf :

 $ readelf -n core.29529 Notes at offset 0x00000468 with length 0x00000558: Owner Data size Description CORE 0x00000150 NT_PRSTATUS (prstatus structure) CORE 0x00000088 NT_PRPSINFO (prpsinfo structure) CORE 0x00000130 NT_AUXV (auxiliary vector) CORE 0x00000200 NT_FPREGSET (floating point registers) 

… ainsi, on pourrait en théorie écrire un extrait de code pour extraire la ligne de commande de cette structure et l’imprimer de manière à rendre ce processus plus facile à automatiser. Vous pouvez bien sûr simplement parsingr la sortie du file :

 $ file core.29529 | sed "s/.*from '\([^']*\)'/\1/" /bin/sleep 60 

Voilà donc toutes les parties. Voici un sharepoint départ pour tout rassembler:

 #!/bin/sh core=$1 exe=$(file $core | sed "s/.*from '\([^']*\)'/\1/" | awk '{print $1}') libs=$( ldd $exe | awk ' /=> \// {print $3} ! /=>/ {print $1} ' ) cat < 

Pour mon exemple, si je nomme ce script packcore et l'exécute sur le fichier core à partir de la commande sleep , j'obtiens ceci:

 $ packcore core.29529 tar: Removing leading `/' from member names $ tar -c -f core.29529-all.tar.xz core.29529 lib64/libc.so.6 lib64/ld-linux-x86-64.so.2 bin/sleep 

En l'état, ce script est assez fragile; J'ai fait beaucoup d'hypothèses sur la sortie de ldd uniquement sur cet exemple de sortie.

Voici un script qui effectue les étapes nécessaires (testé uniquement sur RHEL5, mais qui pourrait également fonctionner ailleurs):

 #!/bin/sh # # Take a core dump and create a tarball of all of the binaries and libraries # that are needed to debug it. # include_core=1 keep_workdir=0 usage() { argv0="$1" retval="$2" errmsg="$3" if [ ! -z "$errmsg" ] ; then echo "ERROR: $errmsg" 1>&2 fi cat < Parse a core dump and create a tarball with all binaries and libraries needed to be able to debug the core dump. Creates .tgz -k - Keep temporary working directory -x - Exclude the core dump from the generated tarball EOF exit $retval } while [ $# -gt 0 ] ; do case "$1" in -k) keep_workdir=1 ;; -x) include_core=0 ;; -h|--help) usage "$0" 0 ;; -*) usage "$0" 1 "Unknown command line arguments: $*" ;; *) break ;; esac shift done COREFILE="$1" if [ ! -e "$COREFILE" ] ; then usage "$0" 1 "core dump '$COREFILE' doesn't exist." fi case "$(file "$COREFILE")" in *"core file"*) break ;; *) usage "$0" 1 "per the 'file' command, core dump '$COREFILE' is not a core dump." ;; esac cmdname=$(file "$COREFILE" | sed -e"s/.*from '\(.*\)'/\1/") echo "Command name from core file: $cmdname" fullpath=$(which "$cmdname") if [ ! -x "$fullpath" ] ; then usage "$0" 1 "unable to find command '$cmdname'" fi echo "Full path to executable: $fullpath" mkdir "${COREFILE}.pack" gdb --eval-command="quit" "${fullpath}" ${COREFILE} 2>&1 | \ grep "Reading symbols" | \ sed -e's/Reading symbols from //' -e's/\.\.\..*//' | \ tar --files-from=- -cf - | (cd "${COREFILE}.pack" && tar xf -) if [ $include_core -eq 1 ] ; then cp "${COREFILE}" "${COREFILE}.pack" fi tar czf "${COREFILE}.pack.tgz" "${COREFILE}.pack" if [ $keep_workdir -eq 0 ] ; then rm -r "${COREFILE}.pack" fi echo "Done, created ${COREFILE}.path.tgz"