#!/bin/sh -f # Generate a source code listing for C or C++ code with assembler code. The # listing is always written to stdout. # Author: Igor Metz # Revision 1.4 94/08/26 13:58:27 coxs # lister now guesses how to should be configured. Added elf and coff support. # # Revision 1.3 89/12/18 13:58:27 metz # lister must now be configured before it can be used. This is done in the # /bin/sh part of the code. # # # Revision 1.2 89/08/16 17:35:02 metz # Support for SPARC added. # # Revision 1.1 89/08/16 16:49:22 metz # Initial revision # # Requires: gawk (may be it works also with nawk) # usage: lister filename [compiler-options] # Method: # compile the source with -g option to assembler code, then merge the # generated assembler code with the source code. Compiler options # can be supplied on the command line (for example -O) # To install lister, assign one of the supported values to the variable MYSYS: # mc68020 for Motorola 68020 (Sun-3, ..) # mc68030 for Motorola 68030 (Sun-3, ..) # sparc for SPARC (SUN-4, ..) # i386 for i386 (Sun i386, ...) # i386-gnu-linux for i386 (GNU/Linux, ...) # Guess what kind of objects we are creating and thus what type of assembler # symbols to look for ex /tmp/$$.c </dev/null a main (){} . w q END WD=`pwd` cd /tmp gcc -c $$.c case "`file $$.o`" in *ELF*) MYSYS=elf ;; *COFF*|*BCS*) MYSYS=coff ;; *mc68k*|*M68000*) MYSYS=mc68030 ;; *SPARC*) MYSYS=sparc ;; *386*) MYSYS=i386 ;; esac rm $$.c $$.o cd $WD # uncomment the line you need if the above guesses incorrectly: # MYSYS=mc68020 # MYSYS=mc68030 # MYSYS=sparc # MYSYS=i386 # MYSYS=i386-gnu-linux # MYSYS=`mach` # this will work on Suns with SunOS > 4.0.0 # MYSYS=elf # MYSYS=coff WHOAMI=$0 if [ $# -gt 0 ] ; then FILENAME=$1 shift fi exec gawk -v whoami=$WHOAMI -vsys=$MYSYS -voptions="$*" ' # commandline arguments: # ARGV[0] = "gawk" # ARGV[1] = processid # ARGV[2] = filename BEGIN { if (ARGC != 3) { usage() exit 1 } # Declaration of global variables c_filename = "" asm_filename = "" cmdline = "" asm_code = "" c_code = "" c_lineno = 0 oldlineno = 0 newlineno = 0 ignore_stabd = 0 num_of_fields = 0 # check processor architecture and set sourcecode line_hint accordingly if (sys == "sparc" || sys == "i386") { line_hint = "^[ \t]*\.stabn.*" line_field = 3; line_delimiter = ","; line_offset = 0; } else if (sys == "mc68020" || sys == "mc68030" || sys == "i386-gnu-linux") { line_hint = "^[ \t]*\.stabd.*" line_field = 3; line_delimiter = ","; line_offset = 0; } else if (sys == "elf") { line_hint = "section.*\.line" line_field = 3; line_delimiter = "\t"; line_offset = 0; } else if (sys == "coff") { line_hint = "^[ \t]*ln" line_field = 3; line_delimiter = "\t"; } else { error("Processor type " sys " is not supported yet, sorry") } parse_cmdline() printf("compiling %s to asm code\n", c_filename ) > "/dev/stderr" if (system(cmdline) != 0 ) { error("Compilation of " c_filename " failed") } printf("generating listing\n") > "/dev/stderr" while ( getline asm_code < asm_filename > 0 ) { if ( (ignore_stabd==0) && (asm_code ~ line_hint)) { while ( sys == "elf" && (asm_code !~ "word" && asm_code !~ "byte") && getline asm_code < asm_filename > 0); # source line hint found. Split the line into fields separated by commas. # num_of_fields is 4 for sparc, 3 for m68k num_of_fields = split(asm_code, fields, line_delimiter) newlineno = fields[line_field] + line_offset; if (newlineno > oldlineno) { while ( newlineno > c_lineno && getline c_code < c_filename > 0) { c_lineno++ printf("%4d %s\n", c_lineno, c_code) } oldlineno = newlineno } } else if ( asm_code ~ ".*Ltext[ \t]*$" ) { # filename hint found if ( match(asm_code, c_filename)) { ignore_stabd = 0 } else { ignore_stabd = 1 } } else if ( sys == "elf" && asm_code ~ "section.*\.debug" ) { while ( asm_code !~ "^[ \t]*[.]*previous" && asm_code !~ "\.popsection" && getline asm_code < asm_filename > 0 ); if ( ! (getline asm_code < asm_filename > 0)) break; } else if ( sys == "coff" && asm_code ~ "^[ \t]*sdef" ) { if ( asm_code ~ "\.bf" ) { while ( asm_code !~ "^[ \t]*line" && getline asm_code < asm_filename > 0 ) { num_of_fields = split(asm_code, fields, "\t") line_offset = fields[line_field] - 1; } } while ( asm_code !~ "^[ \t]*endef" && getline asm_code < asm_filename > 0 ) { } if ( ! (getline asm_code < asm_filename > 0)) break; } printf("\t\t\t%s\n", asm_code) } # general cleanup system("/bin/rm " asm_filename) } function usage() { printf("usage: %s filename compiler-options\n", whoami) > "/dev/stderr" } function error(s) { printf("error: %s\n", s) > "/dev/stderr" exit 1 } function parse_cmdline( i) { # construct filenames to use asm_filename = "/tmp/lister" ARGV[1] ".s" ARGV[1] = "" c_filename = ARGV[2] ARGV[2] = "" # construct commandline to use if ( match(c_filename, ".C") || match(c_filename, ".cc") ) { cmdline = "g++" } else if (match(c_filename, ".c") || match(c_filename, ".i")) { cmdline = "gcc" } else { error("unknown extension for file " c_filename) } cmdline = cmdline " -g -S -o " asm_filename # now we append the compiler options specified by the user cmdline = cmdline " " options # last but not least: the name of the file to compile cmdline = cmdline " " c_filename } ' $$ $FILENAME