Wie generiere ich ein gcc-Debug-Symbol außerhalb des Build-Ziels?

176

Ich weiß, dass ich mit der Option -g ein Debug-Symbol generieren kann. Das Symbol ist jedoch in die Zieldatei eingebettet. Könnte gcc ein Debug-Symbol außerhalb der ausführbaren Ergebnisbibliothek / Bibliothek generieren? Wie die PDF-Datei des Windows VC ++ - Compilers.

kcwu
quelle

Antworten:

184

Sie müssen objcopy verwenden , um die Debug-Informationen zu trennen :

objcopy --only-keep-debug "${tostripfile}" "${debugdir}/${debugfile}"
strip --strip-debug --strip-unneeded "${tostripfile}"
objcopy --add-gnu-debuglink="${debugdir}/${debugfile}" "${tostripfile}"

Ich verwende das folgende Bash-Skript, um die Debug-Informationen in Dateien mit der Erweiterung .debug in einem .debug-Verzeichnis zu unterteilen. Auf diese Weise kann ich die Bibliotheken und ausführbaren Dateien in einer TAR-Datei und die .debug-Verzeichnisse in einer anderen tarieren. Wenn ich die Debug-Informationen später hinzufügen möchte, extrahiere ich einfach die Debug-Tar-Datei und voila, ich habe symbolische Debug-Informationen.

Dies ist das Bash-Skript:

#!/bin/bash

scriptdir=`dirname ${0}`
scriptdir=`(cd ${scriptdir}; pwd)`
scriptname=`basename ${0}`

set -e

function errorexit()
{
  errorcode=${1}
  shift
  echo $@
  exit ${errorcode}
}

function usage()
{
  echo "USAGE ${scriptname} <tostrip>"
}

tostripdir=`dirname "$1"`
tostripfile=`basename "$1"`


if [ -z ${tostripfile} ] ; then
  usage
  errorexit 0 "tostrip must be specified"
fi

cd "${tostripdir}"

debugdir=.debug
debugfile="${tostripfile}.debug"

if [ ! -d "${debugdir}" ] ; then
  echo "creating dir ${tostripdir}/${debugdir}"
  mkdir -p "${debugdir}"
fi
echo "stripping ${tostripfile}, putting debug info into ${debugfile}"
objcopy --only-keep-debug "${tostripfile}" "${debugdir}/${debugfile}"
strip --strip-debug --strip-unneeded "${tostripfile}"
objcopy --add-gnu-debuglink="${debugdir}/${debugfile}" "${tostripfile}"
chmod -x "${debugdir}/${debugfile}"
Lothar
quelle
8
Wenn Sie ein Problem in der Produktion haben und den Prozess mit gdb anhängen müssen, können Sie GDB dann die Debug-Symboldatei zur Verfügung stellen? Und wie, wenn ja? thnx
yves Baum
3
@yves Baumes Fügen Sie einfach das .debug-Verzeichnis mit den .debug-Dateien zu Ihrer Produktionsbox hinzu, und GDB sollte sie abholen. Nach der Debug-Sitzung können Sie sie wieder entfernen.
Lothar
Ein Beispiel finden Sie in den Antwortkommentaren von @Lance Richardson.
GuruM
7
Ist es auch möglich, die ursprüngliche Binärdatei wiederherzustellen (z. B. gestrippte Binärdatei + .debug-Datei = ursprüngliche Binärdatei)?
Paul Praet
1
Haben Sie Probleme beim Weglassen der --build-idLinker-Option ?
JWW
109

Kompilieren Sie mit Debug-Informationen:

gcc -g -o main main.c

Trennen Sie die Debug-Informationen:

objcopy --only-keep-debug main main.debug

oder

cp main main.debug
strip --only-keep-debug main.debug

Debug-Informationen aus der Ursprungsdatei entfernen:

objcopy --strip-debug main

oder

strip --strip-debug --strip-unneeded main

Debugging im Debuglink-Modus:

objcopy --add-gnu-debuglink main.debug main
gdb main

Sie können die Exec-Datei und die Symboldatei auch separat verwenden:

gdb -s main.debug -e main

oder

gdb
(gdb) exec-file main
(gdb) symbol-file main.debug

Für Details:

(gdb) help exec-file
(gdb) help symbol-file

Ref:
https://sourceware.org/gdb/onlinedocs/gdb/Files.html#Files https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html

Herodot
quelle
2
Und Sie sollten verwenden objcopy --add-gnu-debuglink main main.debug, um den Namen der erstellten Debug-Datei und eine Prüfsumme einzubetten. In diesem Fall versucht gdb, den Debug-Code selbst an einigen verteilungsabhängigen Orten zu finden. Die Option -s wird nicht mehr benötigt.
Lothar
9

Überprüfen Sie die Option "--only-keep-debug" des Befehls strip .

Über den Link:

Diese Option soll in Verbindung mit --add-gnu-debuglink verwendet werden, um eine zweiteilige ausführbare Datei zu erstellen. Zum einen eine abgespeckte Binärdatei, die weniger Speicherplatz im RAM und in einer Distribution belegt, und zum anderen eine Debugging-Informationsdatei, die nur benötigt wird, wenn Debugging-Fähigkeiten erforderlich sind.

Lance Richardson
quelle
1
Ja, ich habe es versucht: gcc -ggdb -o test test.c; cp test test.debug; strip --only-keep-debug test.debug; Streifentest; objcopy --add-gnu-debuglink = test.debug test; Dann ist es in
Ordnung,
8

HINWEIS: Programme, die mit hohen Optimierungsstufen (-O3, -O4) kompiliert wurden, können nicht viele Debugging-Symbole für optimierte Variablen, Inline-Funktionen und entrollte Schleifen generieren, unabhängig davon, welche Symbole in a eingebettet (-g) oder extrahiert (objcopy) werden '.debug' Datei.

Alternative Ansätze sind

  1. Betten Sie die Versionsdaten (VCS, git, svn) für compileroptimierte ausführbare Dateien (-O3, -O4) in das Programm ein.
  2. Erstellen Sie eine zweite nicht optimierte Version der ausführbaren Datei.

Die erste Option bietet die Möglichkeit, den Produktionscode zu einem späteren Zeitpunkt mit vollständigem Debugging und Symbolen neu zu erstellen. Die Möglichkeit, den ursprünglichen Produktionscode ohne Optimierungen neu zu erstellen, ist eine enorme Hilfe beim Debuggen. (HINWEIS: Dies setzt voraus, dass die Tests mit der optimierten Version des Programms durchgeführt wurden.)

Ihr Build-System kann eine C-Datei erstellen, die mit dem Kompilierungsdatum, dem Commit und anderen VCS-Details geladen ist. Hier ist ein Beispiel für 'make + git':

program: program.o version.o 

program.o: program.cpp program.h 

build_version.o: build_version.c    

build_version.c: 
    @echo "const char *build1=\"VCS: Commit: $(shell git log -1 --pretty=%H)\";" > "$@"
    @echo "const char *build2=\"VCS: Date: $(shell git log -1 --pretty=%cd)\";" >> "$@"
    @echo "const char *build3=\"VCS: Author: $(shell git log -1 --pretty="%an %ae")\";" >> "$@"
    @echo "const char *build4=\"VCS: Branch: $(shell git symbolic-ref HEAD)\";" >> "$@"
    # TODO: Add compiler options and other build details

.TEMPORARY: build_version.c

Nachdem das Programm kompiliert wurde, können Sie das ursprüngliche 'Commit' für Ihren Code mithilfe des folgenden Befehls suchen: strings -a my_program | grep VCS

VCS: PROGRAM_NAME=my_program
VCS: Commit=190aa9cace3b12e2b58b692f068d4f5cf22b0145
VCS: BRANCH=refs/heads/PRJ123_feature_desc
VCS: AUTHOR=Joe Developer  joe.developer@somewhere.com
VCS: COMMIT_DATE=2013-12-19

Sie müssen nur noch den Originalcode auschecken, ohne Optimierungen neu kompilieren und mit dem Debuggen beginnen.

J Jorgenson
quelle
3
-O4existiert nicht einmal.
Hi-Angel
3
Hoppla, das könnte von Mai-Suncc-Tagen stammen, an denen '-O5' sogar eine Option war. Hier ist ein Link zu den Optionen gcc4.4.7 -O: gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/…
J Jorgenson
3
Dies behebt nicht das häufig auftretende Problem, einen Core-Dump zu interpretieren, der möglicherweise nicht leicht reproduzierbar ist. Die Beratung in dieser Antwort ist solide, aber es nicht die Frage beantworten.
David Rodríguez - Dribeas
4

Bisher keine Antwort erwähnt eu-strip --strip-debug -f <out.debug> <input>.

  • Dies wird per elfutilsPaket bereitgestellt .
  • Das Ergebnis ist, dass die <input>Datei von Debug-Symbolen befreit wurde, die jetzt alle enthalten sind <out.debug>.
Unapiedra
quelle