I know I can generate debug symbol using -g option. However the symbol is embeded in the target file. Could gcc generate debug symbol outside the result executable/library? Like .pdb file of windows VC++ compiler did.
问题:
回答1:
You need to use objcopy to separate the debug information:
objcopy --only-keep-debug \"${tostripfile}\" \"${debugdir}/${debugfile}\"
strip --strip-debug --strip-unneeded \"${tostripfile}\"
objcopy --add-gnu-debuglink=\"${debugdir}/${debugfile}\" \"${tostripfile}\"
I use the bash script below to separate the debug information into files with a .debug extension in a .debug directory. This way I can tar the libraries and executables in one tar file and the .debug directories in another. If I want to add the debug info later on I simply extract the debug tar file and voila I have symbolic debug information.
This is the bash script:
#!/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}\"
回答2:
Compile with debug information:
gcc -g -o main main.c
Separate the debug information:
objcopy --only-keep-debug main main.debug
or
cp main main.debug
strip --only-keep-debug main.debug
Strip debug information from origin file:
objcopy --strip-debug main
or
strip --strip-debug --strip-unneeded main
debug by debuglink mode:
objcopy --add-gnu-debuglink main.debug main
gdb main
You can also use exec file and symbol file separatly:
gdb -s main.debug -e main
or
gdb
(gdb) exec-file main
(gdb) symbol-file main.debug
For 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
回答3:
Check out the \"--only-keep-debug\" option of the strip command.
From the link:
The intention is that this option will be used in conjunction with --add-gnu-debuglink to create a two part executable. One a stripped binary which will occupy less space in RAM and in a distribution and the second a debugging information file which is only needed if debugging abilities are required.
回答4:
NOTE: Programs compiled with high-optimization levels (-O3, -O4) cannot generate many debugging symbols for optimized variables, in-lined functions and unrolled loops, regardless of the symbols being embedded (-g) or extracted (objcopy) into a \'.debug\' file.
Alternate approaches are
- Embed the versioning (VCS, git, svn) data into the program, for compiler optimized executables (-O3, -O4).
- Build a 2nd non-optimized version of the executable.
The first option provides a means to rebuild the production code with full debugging and symbols at a later date. Being able to re-build the original production code with no optimizations is a tremendous help for debugging. (NOTE: This assumes testing was done with the optimized version of the program).
Your build system can create a .c file loaded with the compile date, commit, and other VCS details. Here is a \'make + git\' example:
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
After the program is compiled you can locate the original \'commit\' for your code by using the command: 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
All that is left is to check-out the original code, re-compile without optimizations, and start debugging.