| #!/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 <metz@iam.unibe.ch> |
| |
| # Revision 1.4 94/08/26 13:58:27 coxs <coxs@dg-rtp.dg.com> |
| # 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 <<END >/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 |
| |