1#!/bin/sh -f
2# Generate a source code listing for C or C++ code with assembler code. The
3# listing is always written to stdout.
4# Author: Igor Metz <metz@iam.unibe.ch>
5
6# Revision 1.4  94/08/26  13:58:27  coxs <coxs@dg-rtp.dg.com>
7# lister now guesses how to should be configured. Added elf and coff support.
8#
9# Revision 1.3  89/12/18  13:58:27  metz
10# lister must now be configured before it can be used. This is done in the
11# /bin/sh part of the code.
12# 
13# 
14# Revision 1.2  89/08/16  17:35:02  metz
15# Support for SPARC added.
16# 
17# Revision 1.1  89/08/16  16:49:22  metz
18# Initial revision
19# 
20
21# Requires: gawk (may be it works also with nawk)
22
23# usage:  lister filename [compiler-options]
24
25# Method:
26# compile the source with -g option to assembler code, then merge the
27# generated assembler code with the source code. Compiler options
28# can be supplied on the command line (for example -O)
29
30# To install lister, assign one of the supported values to the variable MYSYS:
31# mc68020  for Motorola 68020 (Sun-3, ..)
32# mc68030  for Motorola 68030 (Sun-3, ..)
33# sparc    for SPARC (SUN-4, ..)
34# i386     for i386 (Sun i386, ...)
35# i386-gnu-linux for i386 (GNU/Linux, ...)
36
37# Guess what kind of objects we are creating and thus what type of assembler
38# symbols to look for
39
40ex /tmp/$$.c <<END >/dev/null
41a
42main (){}
43.
44w
45q
46END
47WD=`pwd`
48cd /tmp
49gcc -c $$.c
50case "`file $$.o`" in 
51*ELF*) MYSYS=elf ;;
52*COFF*|*BCS*) MYSYS=coff ;;
53*mc68k*|*M68000*) MYSYS=mc68030 ;;
54*SPARC*) MYSYS=sparc ;;
55*386*) MYSYS=i386 ;;
56esac
57rm $$.c $$.o
58cd $WD
59
60# uncomment the line you need if the above guesses incorrectly:
61# MYSYS=mc68020
62# MYSYS=mc68030
63# MYSYS=sparc
64# MYSYS=i386
65# MYSYS=i386-gnu-linux
66# MYSYS=`mach`  # this will work on Suns with SunOS > 4.0.0
67# MYSYS=elf
68# MYSYS=coff
69
70WHOAMI=$0
71if [ $# -gt 0 ] ; then
72FILENAME=$1
73shift
74fi
75
76exec gawk -v whoami=$WHOAMI -vsys=$MYSYS -voptions="$*" '
77# commandline arguments:
78#  ARGV[0] = "gawk"
79#  ARGV[1] = processid
80#  ARGV[2] = filename
81BEGIN {
82  if (ARGC != 3) {
83    usage()
84    exit 1
85  }
86
87  # Declaration of global variables
88  c_filename = ""
89  asm_filename = ""
90  cmdline = ""
91  asm_code = ""
92  c_code = ""
93  c_lineno = 0
94  oldlineno = 0
95  newlineno = 0
96  ignore_stabd = 0
97  num_of_fields = 0
98
99  # check processor architecture and set sourcecode line_hint accordingly
100  if (sys == "sparc" || sys == "i386") {
101    line_hint = "^[ \t]*\.stabn.*"
102    line_field = 3;
103    line_delimiter = ",";
104    line_offset = 0;
105  }
106  else if (sys == "mc68020" || sys == "mc68030" || sys == "i386-gnu-linux") {
107    line_hint = "^[ \t]*\.stabd.*"
108    line_field = 3;
109    line_delimiter = ",";
110    line_offset = 0;
111  }
112  else if (sys == "elf") {
113    line_hint = "section.*\.line"
114    line_field = 3;
115    line_delimiter = "\t";
116    line_offset = 0;
117  }
118  else if (sys == "coff") {
119    line_hint = "^[ \t]*ln"
120    line_field = 3;
121    line_delimiter = "\t";
122  }
123  else {
124    error("Processor type " sys " is not supported yet, sorry")
125  }
126
127  parse_cmdline()
128
129  printf("compiling %s to asm code\n", c_filename ) > "/dev/stderr"
130
131  if (system(cmdline) != 0 ) {
132    error("Compilation of " c_filename " failed")
133  }
134
135  printf("generating listing\n") > "/dev/stderr"
136
137
138  while ( getline asm_code < asm_filename > 0 ) {
139    if ( (ignore_stabd==0) && (asm_code ~ line_hint)) {
140      while ( sys == "elf" && (asm_code !~ "word" && asm_code !~ "byte") && 
141        getline asm_code < asm_filename > 0);
142      # source line hint found. Split the line into fields separated by commas.
143      # num_of_fields is 4 for sparc, 3 for m68k
144      num_of_fields = split(asm_code, fields, line_delimiter)
145      newlineno = fields[line_field] + line_offset;
146
147      if (newlineno > oldlineno) {
148        while ( newlineno > c_lineno && getline c_code < c_filename > 0) {
149	  c_lineno++
150	  printf("%4d %s\n", c_lineno, c_code)
151	}
152	oldlineno = newlineno
153      }
154    }
155    else if ( asm_code ~ ".*Ltext[ \t]*$" ) {
156      # filename hint found
157      if ( match(asm_code, c_filename)) {
158        ignore_stabd = 0
159      }
160      else {
161        ignore_stabd = 1
162      }
163    }
164    else if ( sys == "elf" && asm_code ~ "section.*\.debug" ) {
165      while ( asm_code !~ "^[ \t]*[.]*previous" &&
166	      asm_code !~ "\.popsection" && 
167              getline asm_code < asm_filename > 0 );
168      if ( ! (getline asm_code < asm_filename > 0)) break;
169    }
170    else if ( sys == "coff" && asm_code ~ "^[ \t]*sdef" ) {
171      if ( asm_code ~ "\.bf" ) {
172         while ( asm_code !~ "^[ \t]*line" && 
173                 getline asm_code < asm_filename > 0 ) {
174           num_of_fields = split(asm_code, fields, "\t")
175           line_offset = fields[line_field] - 1;
176         }
177      }
178      while ( asm_code !~ "^[ \t]*endef" && 
179              getline asm_code < asm_filename > 0 ) {
180      }
181      if ( ! (getline asm_code < asm_filename > 0)) break;
182    }
183    printf("\t\t\t%s\n", asm_code)
184  }
185
186  # general cleanup
187  system("/bin/rm " asm_filename)
188}
189
190function usage() {
191    printf("usage: %s filename compiler-options\n", whoami) > "/dev/stderr"
192}
193
194function error(s) {
195    printf("error: %s\n", s) > "/dev/stderr"
196    exit 1
197}
198
199function parse_cmdline(    i) {
200  # construct filenames to use
201  asm_filename = "/tmp/lister" ARGV[1] ".s"
202  ARGV[1] = ""
203  c_filename = ARGV[2]
204  ARGV[2] = ""
205
206  # construct commandline to use
207  if ( match(c_filename, ".C") || match(c_filename, ".cc") ) {
208    cmdline = "g++"
209  }
210  else if (match(c_filename, ".c") || match(c_filename, ".i")) {
211    cmdline = "gcc"
212  }
213  else {
214    error("unknown extension for file " c_filename)
215  }
216
217  cmdline = cmdline " -g -S -o " asm_filename
218
219  # now we append the compiler options specified by the user
220  cmdline = cmdline " " options
221
222  # last but not least: the name of the file to compile
223  cmdline = cmdline " " c_filename
224}
225
226' $$ $FILENAME
227
228