listing 5.64 KB
Newer Older
Stan Cox committed
1 2 3 4 5
#!/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>

Stan Cox committed
6 7 8
# 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.
#
Stan Cox committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# 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, ...)
Jeff Law committed
35
# i386-gnu-linux for i386 (GNU/Linux, ...)
Stan Cox committed
36

Stan Cox committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
# 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:
Stan Cox committed
61 62 63 64
# MYSYS=mc68020
# MYSYS=mc68030
# MYSYS=sparc
# MYSYS=i386
Jeff Law committed
65
# MYSYS=i386-gnu-linux
Stan Cox committed
66
# MYSYS=`mach`  # this will work on Suns with SunOS > 4.0.0
Stan Cox committed
67 68
# MYSYS=elf
# MYSYS=coff
Stan Cox committed
69

Stan Cox committed
70 71
WHOAMI=$0
if [ $# -gt 0 ] ; then
Stan Cox committed
72 73
FILENAME=$1
shift
Stan Cox committed
74
fi
Stan Cox committed
75

Stan Cox committed
76
exec gawk -v whoami=$WHOAMI -vsys=$MYSYS -voptions="$*" '
Stan Cox committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
# 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.*"
Stan Cox committed
102 103 104
    line_field = 3;
    line_delimiter = ",";
    line_offset = 0;
Stan Cox committed
105
  }
Jeff Law committed
106
  else if (sys == "mc68020" || sys == "mc68030" || sys == "i386-gnu-linux") {
Stan Cox committed
107
    line_hint = "^[ \t]*\.stabd.*"
Stan Cox committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121
    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";
Stan Cox committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  }
  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)) {
Stan Cox committed
140 141
      while ( sys == "elf" && (asm_code !~ "word" && asm_code !~ "byte") && 
        getline asm_code < asm_filename > 0);
Stan Cox committed
142 143
      # source line hint found. Split the line into fields separated by commas.
      # num_of_fields is 4 for sparc, 3 for m68k
Stan Cox committed
144 145
      num_of_fields = split(asm_code, fields, line_delimiter)
      newlineno = fields[line_field] + line_offset;
Stan Cox committed
146 147

      if (newlineno > oldlineno) {
Stan Cox committed
148
        while ( newlineno > c_lineno && getline c_code < c_filename > 0) {
Stan Cox committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	  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
      }
    }
Stan Cox committed
164
    else if ( sys == "elf" && asm_code ~ "section.*\.debug" ) {
165
      while ( asm_code !~ "^[ \t]*[.]*previous" &&
Stan Cox committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
	      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;
    }
Stan Cox committed
183 184 185 186 187 188 189 190
    printf("\t\t\t%s\n", asm_code)
  }

  # general cleanup
  system("/bin/rm " asm_filename)
}

function usage() {
Stan Cox committed
191
    printf("usage: %s filename compiler-options\n", whoami) > "/dev/stderr"
Stan Cox committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
}

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++"
  }
Stan Cox committed
210
  else if (match(c_filename, ".c") || match(c_filename, ".i")) {
Stan Cox committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    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