1 /****************************************************************************
2 *
3 * This code is Public Domain.
4 *
5 * ========================================================================
6 *
7 * Description: handles line numbers if -Zd or -Zi is set.
8 *
9 ****************************************************************************/
10
11 #include <ctype.h>
12 #include <time.h>
13
14 #include "globals.h"
15 #include "memalloc.h"
16 #include "parser.h"
17 #include "input.h"
18 #include "tokenize.h"
19 #include "segment.h"
20 #include "assume.h"
21 #include "proc.h"
22 #include "expreval.h"
23 #include "extern.h"
24 #include "fastpass.h"
25 #include "msgtext.h"
26 #include "myassert.h"
27 #include "linnum.h"
28 #include "omf.h"
29
30 extern struct qdesc LinnumQueue; /* queue of line_num_info items ( OMF only ) */
31 extern int procidx;
32
33 #if COFF_SUPPORT
34 static struct asym *dmyproc;
35 #endif
36 static uint_32 lastLineNumber;
37
AddLinnumData(struct line_num_info * data)38 static void AddLinnumData( struct line_num_info *data )
39 /*****************************************************/
40 {
41 struct qdesc *q;
42 #if COFF_SUPPORT
43 if ( Options.output_format == OFORMAT_COFF ) {
44 q = (struct qdesc *)CurrSeg->e.seginfo->LinnumQueue;
45 if ( q == NULL ) {
46 q = LclAlloc( sizeof( struct qdesc ) );
47 CurrSeg->e.seginfo->LinnumQueue = q;
48 q->head = NULL;
49 }
50 } else
51 #endif
52 q = &LinnumQueue;
53
54 data->next = NULL;
55 if ( q->head == NULL)
56 q->head = q->tail = data;
57 else {
58 ((struct line_num_info *)q->tail)->next = data;
59 q->tail = data;
60 }
61 }
62
63 /* store a reference for the current line at the current address
64 * called by
65 * - codegen.output_opc()
66 * - proc.ProcDir() - in COFF, line_num is 0 then
67 */
68
AddLinnumDataRef(unsigned srcfile,uint_32 line_num)69 void AddLinnumDataRef( unsigned srcfile, uint_32 line_num )
70 /*********************************************************/
71 {
72 struct line_num_info *curr;
73
74 #if COFF_SUPPORT
75 /* COFF line number info is related to functions/procedures. Since
76 * assembly allows code lines outside of procs, "dummy" procs must
77 * be generated. A dummy proc lasts until
78 * - a true PROC is detected or
79 * - the source file changes or
80 * - the segment/section changes ( added in v2.11 )
81 */
82 if ( Options.output_format == OFORMAT_COFF &&
83 CurrProc == NULL &&
84 ( dmyproc == NULL ||
85 dmyproc->debuginfo->file != srcfile ||
86 dmyproc->segment != (struct asym *)CurrSeg ) ) {
87 char procname[12];
88 if ( dmyproc ) {
89 /**/myassert( dmyproc->segment );
90 dmyproc->total_size =
91 ((struct dsym *)dmyproc->segment)->e.seginfo->current_loc -
92 dmyproc->offset;
93 }
94 sprintf( procname, "$$$%05u", procidx );
95 DebugMsg1(("AddLinnumDataRef(src=%u.%u): CurrProc==NULL, dmyproc=%s searching proc=%s\n", srcfile, line_num, dmyproc ? dmyproc->name : "NULL", procname ));
96 dmyproc = SymSearch( procname );
97
98 /* in pass 1, create the proc */
99 if ( dmyproc == NULL ) {
100 dmyproc = CreateProc( NULL, procname, SYM_INTERNAL );
101 DebugMsg1(("AddLinnumDataRef: new proc %s created\n", procname ));
102 dmyproc->isproc = TRUE; /* flag is usually set inside ParseProc() */
103 dmyproc->included = TRUE;
104 AddPublicData( dmyproc );
105 } else
106 procidx++; /* for passes > 1, adjust procidx */
107
108 /* if the symbols isn't a PROC, the symbol name has been used
109 * by the user - bad! A warning should be displayed */
110 if ( dmyproc->isproc == TRUE ) {
111 SetSymSegOfs( dmyproc );
112 dmyproc->Ofssize = ModuleInfo.Ofssize;
113 dmyproc->langtype = ModuleInfo.langtype;
114 if ( write_to_file == TRUE ) {
115 curr = LclAlloc( sizeof( struct line_num_info ) );
116 curr->sym = dmyproc;
117 curr->line_number = GetLineNumber();
118 curr->file = srcfile;
119 curr->number = 0;
120 DebugMsg1(("AddLinnumDataRef: CURRPROC=NULL, sym=%s, calling AddLinnumData(src=%u.%u)\n", curr->sym->name, curr->file, curr->line_number ));
121 AddLinnumData( curr );
122 }
123 }
124 }
125 #endif
126
127 if( line_num && ( write_to_file == FALSE || lastLineNumber == line_num )) {
128 #ifdef DEBUG_OUT
129 if ( write_to_file == TRUE )
130 DebugMsg1(("AddLinnumDataRef(src=%u.%u) line skipped, lastline=%u\n", srcfile, line_num, lastLineNumber ));
131 #endif
132 return;
133 }
134 DebugMsg1(("AddLinnumDataRef(src=%u.%u): currofs=%Xh, CurrProc=%s, GeneratedCode=%u\n", srcfile, line_num, GetCurrOffset(), CurrProc ? CurrProc->sym.name : "NULL", ModuleInfo.GeneratedCode ));
135
136 curr = LclAlloc( sizeof( struct line_num_info ) );
137 curr->number = line_num;
138 #if COFF_SUPPORT
139 if ( line_num == 0 ) { /* happens for COFF only */
140 /* changed v2.03 (CurrProc might have been NULL) */
141 /* if ( Options.output_format == OFORMAT_COFF && CurrProc->sym.public == FALSE ) { */
142 /* v2.09: avoid duplicates, check for pass 1 */
143 //if ( Options.output_format == OFORMAT_COFF && CurrProc && CurrProc->sym.public == FALSE ) {
144 if ( Parse_Pass == PASS_1 &&
145 Options.output_format == OFORMAT_COFF && CurrProc && CurrProc->sym.ispublic == FALSE ) {
146 CurrProc->sym.included = TRUE;
147 AddPublicData( (struct asym *)CurrProc );
148 }
149 /* changed v2.03 */
150 /* curr->sym = (struct asym *)CurrProc; */
151 curr->sym = ( CurrProc ? (struct asym *)CurrProc : dmyproc );
152 curr->line_number = GetLineNumber();
153 curr->file = srcfile;
154 /* set the function's size! */
155 if ( dmyproc ) {
156 /**/myassert( dmyproc->segment );
157 dmyproc->total_size =
158 ((struct dsym *)dmyproc->segment)->e.seginfo->current_loc -
159 dmyproc->offset;
160 dmyproc = NULL;
161 }
162 /* v2.11: write a 0x7fff line item if prologue exists */
163 if ( CurrProc && CurrProc->e.procinfo->size_prolog ) {
164 DebugMsg1(("AddLinnumDataRef: calling AddLinnumData(src=%u.%u) sym=%s\n", curr->file, curr->line_number, curr->sym->name ));
165 AddLinnumData( curr );
166 curr = LclAlloc( sizeof( struct line_num_info ) );
167 curr->number = GetLineNumber();
168 curr->offset = GetCurrOffset();
169 curr->srcfile = srcfile;
170 }
171 } else {
172 #endif
173 curr->offset = GetCurrOffset();
174 curr->srcfile = srcfile;
175 #if COFF_SUPPORT
176 }
177 #endif
178 lastLineNumber = line_num;
179
180 /* v2.11: added, improved multi source support for CV.
181 * Also, the size of line number info could have become > 1024,
182 * ( even > 4096, thus causing an "internal error in omfint.c" )
183 */
184 if ( Options.output_format == OFORMAT_OMF )
185 omf_check_flush( curr );
186
187 /* v2.10: warning if line-numbers for segments without class code! */
188 if ( CurrSeg->e.seginfo->linnum_init == FALSE ) {
189 CurrSeg->e.seginfo->linnum_init = TRUE;
190 if ( TypeFromClassName( CurrSeg, CurrSeg->e.seginfo->clsym ) != SEGTYPE_CODE ) {
191 EmitWarn( 2, LINNUM_INFO_FOR_SEGMENT_WITHOUT_CLASS_CODE, CurrSeg->sym.name );
192 }
193 }
194 DebugMsg1(("AddLinnumDataRef: calling AddLinnumData(src=%u.%u ofs=%X)\n", curr->number == 0 ? curr->file : curr->srcfile, curr->number, curr->offset ));
195 AddLinnumData( curr );
196
197 return;
198 }
199
QueueDeleteLinnum(struct qdesc * queue)200 void QueueDeleteLinnum( struct qdesc *queue )
201 /*******************************************/
202 {
203 struct line_num_info *curr;
204 struct line_num_info *next;
205
206 if ( queue == NULL )
207 return;
208 curr = queue->head;
209 for( ; curr ; curr = next ) {
210 next = curr->next;
211 LclFree( curr );
212 }
213 return;
214 }
215
216 /* if -Zd is set and there is trailing code not inside
217 * a function, set the dummy function's length now.
218 */
LinnumFini(void)219 void LinnumFini( void )
220 /*********************/
221 {
222 #if COFF_SUPPORT
223 if ( dmyproc ) {
224 dmyproc->total_size =
225 ((struct dsym *)dmyproc->segment)->e.seginfo->current_loc -
226 dmyproc->offset;
227 DebugMsg(("LinnumFini: last dummy proc size=%Xh\n"));
228 }
229 #endif
230 }
231
LinnumInit(void)232 void LinnumInit( void )
233 /*********************/
234 {
235 lastLineNumber = 0;
236 #if COFF_SUPPORT
237 dmyproc = NULL;
238 #endif
239 }
240