This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Add -### option
- To: Zack Weinberg <zack at codesourcery dot com>
- Subject: Re: [PATCH] Add -### option
- From: Ira Ruben <ira at apple dot com>
- Date: Mon, 29 Oct 2001 17:19:54 -0800
- Cc: Robert Lipe <robertlipe at usa dot net>, Graham Stott <grahams at redhat dot com>, gcc-patches at gcc dot gnu dot org
At 4:33 PM -0800 10/29/01, Zack Weinberg wrote:
>As a vaguely related thing: I was contemplating, not so long ago, a mode
>for the driver where it would run gdb on cc1 for you. I got stuck because
>as far as I know there is no way to set the debuggee's command line arguments
>from gdb's command line. Your script sounds like it solves this - how?
There were two ways to do this, both involve using a gdb set args command:
1. Place a set args command in a (local) .gdbinit script in the
current directory assuming that's where you're debugging from. Gdb
will always search the cwd for a .gdbinit as well as your home
directory.
2. Place a set args in a file and use the gdb -command command line
option which sources in the file just like it would a local .gdbinit).
Form 2 is what I use because I don't have to worry about clobbering a
previous local .gdbinit (like the one in the gcc object directory).
FWIW, I've enclosed my script (shown below). I've extracted it from
my bash startup environment scripts. I think it's stand-alone enough
to run outside that environment but I've never tried it that way.
Ira
PS: Forgive me if anyone is getting this message twice. I sent it
with the script as an enclosure from my OS9 machine (where I do mail)
and the email bounced. I think it's because my emailer (Eudora)
compressed the enclosure in an "unacceptable" form (for the
receivers). It was mime type application/mac-binhex40. Just to be
save this time I stuck it as aprt of this email.
-----------------------------------------------------------------------------------
#
## Help info for the debug_gcc function
#
debug_gcc_help()
{
echo
echo "debug_gcc cc [-Bdir/] [-cpp|-driver]
[--dir=dir1:dir2:...:dirN | --dir=name]"
echo " [-ver=n] [--save-commands] [--echo args | dir
| all] [--help]"
echo " cc-options ..."
echo
echo "cc The compiler to invoke. Note that
this MUST be the"
echo " first argument."
echo
echo "-Bdir/ Specifies where to find the cc1*
compiler. Normally"
echo " this may be omitted unless
debugging a specific"
echo " compiler. Since cc must be the
first argument the"
echo " -B is recognized as a compiler
option thus allowing"
echo " a macro to be defined to passed for cc."
echo
echo "-cpp Debug the preprocessor (or cpp-precomp)."
echo
echo "-driver Debug the driver. Either -cpp or
-driver but not both"
echo " may be specified. If neither are
specified then the"
echo " compiler phase is to be debugged
(e.g., cc1plus)."
echo
echo "-ver=n Version of gcc being used if -cpp
not specified. This"
echo " can be 2 or 3. See Notes [2],
[3], and [4] below."
echo
echo "--echo args | dir | all Echo the gdb set args command
written to the command"
echo " file, or the gdb dir command, or
echo both of them."
echo
echo "--dir=dir1:dir2:...:dirN A list of directories for gdb
that will be placed in"
echo " a gdb dir command placed in the
command file."
echo
echo "--dir=name Alternative way to specify the
gdb dir paths. The"
echo " name can either be a filename
containing a line of"
echo " paths separated by colons (like
the explicit previous"
echo " form) OR it can be an environment
variable similarly"
echo " defined with the directory paths.
It is an error for"
echo " the name to be both an
environment variable and a"
echo " filename."
echo
echo "--help Only display this help
information. This can be"
echo " specified in place of the cc."
echo
echo "--save-commands Do not delete command file
(\"debug_gcc_command_file\")."
echo " Setting environment variable
SAVE_COMMANDS to 1 can"
echo " be used in place of --save-commands."
echo
echo
echo "Note [1]: If the command file \"debug_gcc_command_file\"
already exists in the"
echo " current directory when this script is run it is renamed to"
echo " \"debug_gcc_command_file-previous\". When you
exit gdb the original"
echo " debug_gcc_command_file is restored. This is only
mentioned in case"
echo " for some reason you don't exit gdb cleanly."
echo
echo "Note [2]: Gcc 3.x has an integrated preprocessor. Thus
-cpp implies that"
echo " a -save-temps will be added to debug the
stand-alone preprocessor,"
echo " cpp0. For debugging the compiler itself,
including the integrated"
echo " preprocessor, omit the -cpp option."
echo
echo "Note [3]: Gcc 2.x always uses a separate preprocessor and
thus the -cpp is"
echo " always required to debug it. Further, the script
needs to know when"
echo " you want to debug the compiler since it must add
a -save-temps to the"
echo " command to save the temporary file for the
compiler input. Thus a"
echo " -ver=2 is required when debugging a gcc 2.x
compiler. As stated in"
echo " Note [2] this is unnecessary for gcc 3.x because
of it's integrated"
echo " preprocessor and the reason you don't want to add
a -save-temps when"
echo " debugging a gcc 3.x compiler is that implies a
different behavior of"
echo " the compiler (i.e., invoking cpp0 and then the
compiler instead of"
echo " just the compiler)."
echo
echo "Note [4]: The Gcc 3.x driver (at least the Apple version)
supports an option"
echo " (-###) specifically designed to support script
like this one. The"
echo " option is basically the same as -v except that
the displayed"
echo " command line is not executed (since we only need
it for gdb) and"
echo " all arguments are quoted. A -v doesn't quote the
displayed"
echo " arguments leading to possible quoting problems
passing the arguments"
echo " to gdb. Of course for Gcc 2.x you're just screwed!"
}
#
## debug_gcc cc [-Bdir/] [-cpp|-driver] [-ver=n]
[--dir=dir1:dir2:...:dirN | --dir=name]
## [--echo args | dir | all] cc-options...
##
## This script can be used to debug all phases of the gcc compiler;
driver, preprocessor,
## or gcc compiler. It invokes gdb on the appropriate component and
sets up a local
## command script (passed to gdb using its -command option) to define
all the arguments
## appropriate to that phase along with path definitions so that gdb
can access the
## compiler source.
##
## If not debugging the driver, the script will add a -v (and
-save-temps for gcc
## 2.x) option to the command line to allow it to capture the
phases's tool name
## (e.g., cc1plus) and all the arguments passed to that phase. The
tool name is
## what's passed to gdb. The arguments are used to build a SET args
gdb command
## which is placed in a command file generated into the current directory. The
## command file is passed to gdb to execute when gdb is invoked by the script.
##
## Debugging the driver is similar to debugging the preprocessor or
compiler phases
## except the command line use is basically the one passed to the
script minus the
## script's own arguments. Again we have the tool name (e.g., cc)
and its arguments
## for building the command file and invoking gdb.
##
## This script also allows you to specify a set of directory paths
for gdb to use
## through a gdb dir command that would be added to the command file.
##
## Note [1]: If the command file "debug_gcc_command_file" already exists in the
## current directory when this script is run it is renamed to
## "debug_gcc_command_file-previous". When you exit gdb the original
## debug_gcc_command_file is restored. This is only
mentioned in case
## for some reason you don't exit gdb cleanly.
##
## Note [2]: Gcc 3.x has an integrated preprocessor. Thus -cpp implies that
## a -save-temps will be added to debug the stand-alone preprocessor,
## cpp0. For debugging the compiler itself, including the integrated
## preprocessor, omit the -cpp option.
##
## Note [3]: Gcc 2.x always uses a separate preprocessor and thus the -cpp is
## always required to debug it. Further, the script needs
to know when
## you want to debug the compiler since it must add a
-save-temps to the
## command to save the temporary file for the compiler input. Thus a
## -ver=2 is required when debugging a gcc 2.x compiler.
As stated in
## Note [2] this is unnecessary for gcc 3.x because of it's
integrated
## preprocessor and the reason you don't want to add a
-save-temps when
## debugging a gcc 3.x compiler is that implies a different
behavior of
## the compiler (i.e., invoking cpp0 and then the compiler instead of
## just the compiler).
##
## Note [4]: The Gcc 3.x driver (at least the Apple version) supports
an option"
## (-###) specifically designed to support script like this one. The
## option is basically the same as -v except that the displayed"
## command line is not executed (since we only need it for gdb) and"
## all arguments are quoted. A -v doesn't quote the displayed"
## arguments leading to possible quoting problems passing
the arguments"
## to gdb. Of course for Gcc 2.x you're just screwed!"
##
## Options: Must precede any of the gcc command lines options for the compiler.
##
## cc The compiler to invoke. Note that
this MUST be the
## first argument.
##
## -Bdir/ Specifies where to find the cc1*
compiler. Normally
## this may be omitted unless debugging a specific
## compiler. Since cc must be the first
argument the
## -B is recognized as a compiler option
thus allowing
## a macro to be defined to passed for cc.
##
## -cpp Debug the preprocessor (or cpp-precomp).
##
## -driver Debug the driver. Either -cpp or
-driver but not both
## may be specified. If neither are
specified then the
## compiler phase is to be debugged
(e.g., cc1plus).
##
## -ver=n Version of gcc being used if -cpp not
specified. This
## can be 2 or 3. See Notes [2], [3],
and [4] above.
##
## --echo args | dir | all Echo the gdb set args command written
to the command
## file, or the gdb dir command, or echo
both of them.
##
## --dir=dir1:dir2:...:dirN A list of directories for gdb that
will be placed in
## a gdb dir command placed in the command file.
##
## --dir=name Alternative way to specify the gdb
dir paths. The name can
## either be a filename containing a
line of paths separated
## by colons (like the explicit previous
form) OR it can
## be an environment variable similarly
defined with the
## directory paths. It is an error for
the name to be both
## an environment variable and a filename.
##
## --help Only display this help information.
This can be
## specified in place of the cc.
##
## --save-commands Do not delete command file
("debug_gcc_command_file").
## Setting environment variable SAVE_COMMANDS to 1
## can be used in place of --save-commands.
##
## Any script option that is not one of the above is assumed to be
the start of the
## compiler options.
#
debug_gcc()
{
declare -i done=0 shift_cnt=0 cpp=0 driver=0 previous=0 ver=3
status cc_args_index=0
local arg next_arg= cc= objdir= dir= dir1= yn= saw_dir= alius echo= v="-v"
local save_temps=
local line= tool= args=
local save=0 command_file=debug_gcc_command_file
local -a cc_args
if [ $# -eq 0 ]; then
debug_gcc_help
return 0
fi
if [ "$1" != "--help" ] && [ "$1" != "-help" ] && [ "$1" != "-h" ]; then
cc=$1
shift
fi
for arg; do
case $next_arg in
-dir | --dir)
dir="$arg"
saw_dir="$next_arg"
next_arg=
shift_cnt=$shift_cnt+2
;;
-echo | --echo)
echo="$arg"
next_arg=
shift_cnt=$shift_cnt+2
;;
-ver | --ver)
ver=$arg
shift_cnt=$shift_cnt+2
;;
*)
case $arg in
-help | --help | -h)
debug_gcc_help
return 0
;;
-cpp | --cpp)
cpp=1
shift_cnt=$shift_cnt+1
;;
-driver | --driver)
driver=1
shift_cnt=$shift_cnt+1
;;
-echo=* | --echo=*)
echo=`echo $arg | sed -e 's/-*echo=//'`
shift_cnt=$shift_cnt+1
;;
-echo | --echo)
next_arg=$arg
;;
-dir=* | --dir=*)
dir=`echo $arg | sed -e 's/-*dir=//'`
saw_dir=`echo $arg | sed -e 's/\(-*dir\).*$/\1/'`
shift_cnt=$shift_cnt+1
;;
-dir | --dir)
next_arg=$arg
;;
-save-commands | --save-commands)
save=1
shift_cnt=$shift_cnt+1
;;
-ver=* | --ver=*)
ver=`echo $arg | sed -e 's/-*ver=//'`
shift_cnt=$shift_cnt+1
;;
-B*)
cc="$cc $arg"
shift_cnt=$shift_cnt+1
;;
*)
next_arg=
done=1
;;
esac
esac
if [ $done != 0 ]; then
break
fi
done
shift $shift_cnt
# See if the use explicitly specified -v. If so we won't need to
add it when
# we need to generate the command lines.
for arg; do
if [ "$arg" = "-v" ]; then
v=
break
fi
done
if [ $driver -ne 0 ] && [ $cpp -ne 0 ]; then
echo "What do you want to debug? Driver or preprocessor. You
can't do both!"
return 1
fi
if [ "$echo" != "" ] && \
[ "$echo" != "dir" ] && \
[ "$echo" != "args" ] && \
[ "$echo" != "all" ]; then
echo "Invalid --echo specification: $echo"
return 1
fi
if [ $ver != 3 -a $ver -ne 2 ]; then
echo "Invalid compiler version specified (2 or 3 expected): $ver"
return 1
fi
if [ "$dir" != "" ] && [ "`echo $dir | sed -e '/:/D'`" != "" ]; then
if [ -f "$dir" ]; then
if [ "`eval echo $\`echo $dir\``" != "" ]; then
echo "$dir is ambiguous -- it's a valid filename and
a valid environment variable"
return 1
fi
dir="`cat \"$dir\"`"
else
dir="`eval echo $\`echo $dir\``"
fi
fi
if [ "${dir:${#dir}-1:1}" = ":" ]; then
dir="${dir:0:${#dir}-1}"
fi
if [ "$saw_dir" != "" ] && [ "$dir" = "" ]; then
while [ "$yn" != "y" ] && [ "$yn" != "n" ]; do
echo -n "$saw_dir" 'specified which evaluated to null --
do you accept this ? (y,n) '
read -e yn;
yn="${yn:0:1}"
done
if [ "$yn" = "n" ]; then
return 1
fi
fi
if [ "$cc" = "" ]; then
echo "No compiler specifed (see --help for syntax)"
return 0
fi
#
# If the command line specified a compiler name that was actually
an alias then
# we need to get the actual tool to which that name is aliased.
#
alius="`alias \"$cc\" 2> /dev/null`"
if [ $? -eq 0 ]; then
cc="`echo \"$alius\" | sed -e \"s/alias .*='//\" -e \"s/'\$//\"`"
fi
#
# The gcc 3.x drive supports -###, after I added it :-) It will cause
# the driver to simply do a -v output without executing the command.
# It will also quote all the arguments since -v normally doesn't do that
# and we lose what needs to be quoted if we don't do this. Of course for
# gcc 2.x you're screwed. Do have any pathnames that need quoting.
#
if [ $ver -eq 2 ]; then
save_temps="-save-temps"
elif [ $driver -eq 0 ]; then
cc_args[$((cc_args_index++))]='-###'
fi
#
# Remove possible -pipe argument. Must do this in $@ to preserve quoting.
#
if [ $driver -ne 0 ]; then
for arg; do
if [ "$arg" != "-pipe" ]; then
cc_args[$((cc_args_index++))]="\"$arg\""
fi
done
else
for arg; do
if [ "$arg" != "-pipe" ]; then
cc_args[$((cc_args_index++))]="$arg"
fi
done
fi
if false; then
echo '$cc =' $cc
echo '$cpp =' $cpp
echo '$driver =' $driver
echo '$dir =' $dir
echo '$echo =' $echo
echo '$objdir =' $objdir
echo '$save =' $save
echo '$v =' $v
echo '$ver =' $ver
echo '$@ =' $@
return 1
fi
#
# Set the appropriate command line to use (driver line,
preprocessor line, or c/c++
# compiler line) depending on the script options. The line
allows us to extract the
# tool name that is invoked and all the arguments that follow.
The tool is what
# is passed to gdb to debug. The arguments are used to build a
set args gdb
# command for a local -command file.
#
if [ $driver -ne 0 ]; then
#
# If debugging the driver, the command line is obviously all
the script's command
# line options minus the ones specific to the script.
#
line="$cc ""${cc_args[@]}"
tool="`echo $line | sed -e 's/^[ ]*\([^ ]*\)\(.*\)$/\1/'`"
if [ "$tool" = "" ]; then
echo "Could not find driver name (?)"
return 1
fi
else
#
# Compile program and save the -v output in a temp file that
we can grep for
# the prerocessor line or c/c++ compiler line. If the user exlicitly
# specified -v then we don't have to. But if we do then we
must remove it
# from the gdb args list. In other words the args list only
has the -v if
# the user explicitly specified it.
#
$cc "${cc_args[@]}" $v -c $save_temps 2> /tmp/dbg.$$
status=$?
if [ $status -gt 1 ]; then
echo "Unexpected status returned from compilation: $status"
more /tmp/dbg.$$
return 1
fi
# ignore any compile-time errors
if false; then
echo '##############' /tmp/dbg.$$ '##############'
more /tmp/dbg.$$
return 1
fi
if [ $cpp -ne 0 ]; then
line="`cat /tmp/dbg.$$ | grep [-]D__GNUC__`"
tool="`echo $line | sed -e 's/^[ ]*\([^ ]*\)\(.*\)$/\1/'`"
if [ "$tool" = "" ]; then
echo "Could not find preprocessor name in the -v
output (in /tmp/dbg.$$)"
return 1
fi
else
#line="`cat /tmp/dbg.$$ | grep [-]o[\ ] | grep --invert-match /as`"
#line="`cat /tmp/dbg.$$ | grep [-]o[\ ] | grep .*cc1.* `"
line="`cat /tmp/dbg.$$ | grep .*cc1.*`"
tool="`echo $line | sed -e 's/^[ ]*\([^ ]*\).*$/\1/'`"
if [ "$tool" = "" ]; then
echo "Could not find compiler name in the -v output
(in /tmp/dbg.$$)"
return 1
fi
# do -version first so -v removal doesn't screw it up.
line="`echo \"$line\" | sed -e 's/-version//'`"
if [ "$v" = "-v" ]; then
line="`echo \"$line\" | sed -e 's/-v//'`"
fi
# remove null but quoted arguments...
line="`echo \"$line\" | sed -e 's/\"\"//g'`"
fi
rm -f /tmp/dbg.$$ # don't need this any more
fi
#
# Once the tool name is known and we have the appropriate command
line from it we
# can extract all the arguments we'll need to build the gdb set
args command for the
# -command file.
#
# Note, the original line (commented out below) blows in sed
apparently when $line
# is more than 1098 characters. The second one doesn't. Go figure!
#
#args="`echo $line | sed -e 's,^[ ]*'"$tool"'[ ]*\(.*\)$,\1,'`"
args="`echo \"$line\" | sed -e 's,'\"$tool\"',,'`"
#
# At last we got all of what we were after; tool and its
arguments. Create a
# -command file in the current directory containing a set args to
define the
# tools arguments.
#
if [ $save -eq 0 ] && [ -e $command_file ] && [ "$SAVE_COMMANDS"
!= "1" ]; then
mv $command_file ${command_file}-previous
previous=1
fi
if [ "$args" != "" ];then
echo "set args $args" > $command_file # set args arguments...
if [ "$echo" = "args" ] || [ "$echo" = "all" ]; then
echo "$command_file: set args $args"
fi
fi
#
# If the --dir script options was specified add it to the command
file too as a
# dir gdb command. The --dir arguments are defines as being in
the syntax that
# gdb expects.
#
if [ "$dir" != "" ]; then
echo "dir $dir" >> $command_file # dir all the useful
compiler directories
if [ "$echo" = "dir" ] || [ "$echo" = "all" ]; then
echo "$command_file: dir $dir"
fi
fi
#
# Finally we can invoke gdb...
#
if [ "$echo" != "" ]; then
echo "gdb -command $command_file $tool"
fi
gdb -command $command_file "$tool" # debug that sucker
#
# Delete the command file and rename any previous one (unless
-save-commands
# was specified).
#
if [ $save -eq 0 ] && [ "$SAVE_COMMANDS" != "1" ]; then
rm -f $command_file # now we don't need
this any more
if [ $previous -ne 0 ]; then
mv ${command_file}-previous $command_file
fi
fi
}