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