]> git.sur5r.net Git - cc65/blob - src/ca65/lineinfo.c
If a debug symbol is an import, write out the import id.
[cc65] / src / ca65 / lineinfo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                lineinfo.c                                 */
4 /*                                                                           */
5 /*                      Source file line info structure                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                70794 Filderstadt                                          */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* common */
39 #include "coll.h"
40 #include "hashfunc.h"
41 #include "xmalloc.h"
42
43 /* ca65 */
44 #include "global.h"
45 #include "lineinfo.h"
46 #include "objfile.h"
47 #include "scanner.h"
48 #include "span.h"
49
50
51
52 /*****************************************************************************/
53 /*                                 Forwards                                  */
54 /*****************************************************************************/
55
56
57
58 static unsigned HT_GenHash (const void* Key);
59 /* Generate the hash over a key. */
60
61 static const void* HT_GetKey (const void* Entry);
62 /* Given a pointer to the user entry data, return a pointer to the key */
63
64 static int HT_Compare (const void* Key1, const void* Key2);
65 /* Compare two keys. The function must return a value less than zero if
66  * Key1 is smaller than Key2, zero if both are equal, and a value greater
67  * than zero if Key1 is greater then Key2.
68  */
69
70
71
72 /*****************************************************************************/
73 /*                                   Data                                    */
74 /*****************************************************************************/
75
76
77
78 /* Structure that holds the key for a line info */
79 typedef struct LineInfoKey LineInfoKey;
80 struct LineInfoKey {
81     FilePos         Pos;                /* File position */
82     unsigned short  Type;               /* Type of line info */
83     unsigned short  Count;              /* Recursion counter */
84 };
85
86 /* Structure that holds line info */
87 struct LineInfo {
88     HashNode        Node;               /* Hash table node */
89     unsigned        Id;                 /* Index */
90     LineInfoKey     Key;                /* Key for this line info */
91     unsigned char   Hashed;             /* True if in hash list */
92     unsigned char   Referenced;         /* Force reference even if no spans */
93     Collection      Spans;              /* Segment spans for this line info */
94     Collection      OpenSpans;          /* List of currently open spans */
95 };
96
97
98
99 /* Collection containing all line infos */
100 static Collection LineInfoList = STATIC_COLLECTION_INITIALIZER;
101
102 /* Collection with currently active line infos */
103 static Collection CurLineInfo = STATIC_COLLECTION_INITIALIZER;
104
105 /* Hash table functions */
106 static const HashFunctions HashFunc = {
107     HT_GenHash,
108     HT_GetKey,
109     HT_Compare
110 };
111
112 /* Line info hash table */
113 static HashTable LineInfoTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
114
115 /* The current assembler input line */
116 static LineInfo* AsmLineInfo = 0;
117
118
119
120 /*****************************************************************************/
121 /*                           Hash table functions                            */
122 /*****************************************************************************/
123
124
125
126 static unsigned HT_GenHash (const void* Key)
127 /* Generate the hash over a key. */
128 {
129     /* Key is a LineInfoKey pointer */
130     const LineInfoKey* K = Key;
131
132     /* Hash over a combination of type, file and line */
133     return HashInt ((K->Type << 18) ^ (K->Pos.Name << 14) ^ K->Pos.Line);
134 }
135
136
137
138 static const void* HT_GetKey (const void* Entry)
139 /* Given a pointer to the user entry data, return a pointer to the key */
140 {
141     return &((const LineInfo*)Entry)->Key;
142 }
143
144
145
146 static int HT_Compare (const void* Key1, const void* Key2)
147 /* Compare two keys. The function must return a value less than zero if
148  * Key1 is smaller than Key2, zero if both are equal, and a value greater
149  * than zero if Key1 is greater then Key2.
150  */
151 {
152     /* Convert both parameters to FileInfoKey pointers */
153     const LineInfoKey* K1 = Key1;
154     const LineInfoKey* K2 = Key2;
155
156     /* Compare line number, then file and type, then count */
157     int Res = (int)K2->Pos.Line - (int)K1->Pos.Line;
158     if (Res == 0) {
159         Res = (int)K2->Pos.Name - (int)K1->Pos.Name;
160         if (Res == 0) {
161             Res = (int)K2->Type - (int)K1->Type;
162             if (Res == 0) {
163                 Res = (int)K2->Count - (int)K1->Count;
164             }
165         }
166     }
167
168     /* Done */
169     return Res;
170 }
171
172
173
174 /*****************************************************************************/
175 /*                              struct LineInfo                              */
176 /*****************************************************************************/
177
178
179
180 static LineInfo* NewLineInfo (const LineInfoKey* Key)
181 /* Create and return a new line info. Usage will be zero. */
182 {
183     /* Allocate memory */
184     LineInfo* LI = xmalloc (sizeof (LineInfo));
185
186     /* Initialize the fields */
187     InitHashNode (&LI->Node);
188     LI->Id        = ~0U;
189     LI->Key       = *Key;
190     LI->Hashed    = 0;
191     LI->Referenced= 0;
192     InitCollection (&LI->Spans);
193     InitCollection (&LI->OpenSpans);
194
195     /* Return the new struct */
196     return LI;
197 }
198
199
200
201 static void FreeLineInfo (LineInfo* LI)
202 /* Free a LineInfo structure */
203 {
204     /* Free the Spans collection. It is supposed to be empty */
205     CHECK (CollCount (&LI->Spans) == 0);
206     DoneCollection (&LI->Spans);
207     DoneCollection (&LI->OpenSpans);
208
209     /* Free the structure itself */
210     xfree (LI);
211 }
212
213
214
215 static void RememberLineInfo (LineInfo* LI)
216 /* Remember a LineInfo by adding it to the hash table and the global list.
217  * This will also assign the id which is actually the list position.
218  */
219 {
220     /* Assign the id */
221     LI->Id = CollCount (&LineInfoList);
222
223     /* Remember it in the global list */
224     CollAppend (&LineInfoList, LI);
225
226     /* Add it to the hash table, so we will find it if necessary */
227     HT_InsertEntry (&LineInfoTab, LI);
228
229     /* Remember that we have it */
230     LI->Hashed = 1;
231 }
232
233
234
235 /*****************************************************************************/
236 /*                                   Code                                    */
237 /*****************************************************************************/
238
239
240
241 void InitLineInfo (void)
242 /* Initialize the line infos */
243 {
244     static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
245
246     /* Increase the initial count of the line info collection */
247     CollGrow (&LineInfoList, 200);
248
249     /* Create a LineInfo for the default source. This is necessary to allow
250      * error message to be generated without any input file open.
251      */
252     AsmLineInfo = StartLine (&DefaultPos, LI_TYPE_ASM, 0);
253 }
254
255
256
257 void DoneLineInfo (void)
258 /* Close down line infos */
259 {
260     /* Close all current line infos */
261     unsigned Count = CollCount (&CurLineInfo);
262     while (Count) {
263         EndLine (CollAt (&CurLineInfo, --Count));
264     }
265 }
266
267
268
269 void EndLine (LineInfo* LI)
270 /* End a line that is tracked by the given LineInfo structure */
271 {
272     unsigned I;
273
274     /* Close the spans for the line */
275     CloseSpans (&LI->OpenSpans);
276
277     /* Move the spans to the list of all spans for this line, then clear the
278      * list of open spans.
279      */
280     for (I = 0; I < CollCount (&LI->OpenSpans); ++I) {
281         CollAppend (&LI->Spans, CollAtUnchecked (&LI->OpenSpans, I));
282     }
283     CollDeleteAll (&LI->OpenSpans);
284
285     /* Line info is no longer active - remove it from the list of current
286      * line infos.
287      */
288     CollDeleteItem (&CurLineInfo, LI);
289
290     /* If this line info is already hashed, we're done. Otherwise, if it is
291      * marked as referenced or has non empty spans, remember it. It it is not
292      * referenced or doesn't have open spans, delete it.
293      */
294     if (!LI->Hashed) {
295         if (LI->Referenced || CollCount (&LI->Spans) > 0) {
296             RememberLineInfo (LI);
297         } else {
298             FreeLineInfo (LI);
299         }
300     }
301 }
302
303
304
305 LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
306 /* Start line info for a new line */
307 {
308     LineInfoKey Key;
309     LineInfo* LI;
310
311     /* Prepare the key struct */
312     Key.Pos   = *Pos;
313     Key.Type  = Type;
314     Key.Count = Count;
315
316     /* Try to find a line info with this position and type in the hash table.
317      * If so, reuse it. Otherwise create a new one.
318      */
319     LI = HT_FindEntry (&LineInfoTab, &Key);
320     if (LI == 0) {
321         /* Allocate a new LineInfo */
322         LI = NewLineInfo (&Key);
323     } else {
324         Key.Count = 2;
325     }
326
327     /* Open the spans for this line info */
328     OpenSpans (&LI->OpenSpans);
329
330     /* Add the line info to the list of current line infos */
331     CollAppend (&CurLineInfo, LI);
332
333     /* Return the new info */
334     return LI;
335 }
336
337
338
339 void NewAsmLine (void)
340 /* Start a new assembler input line. Use this function when generating new
341  * line of LI_TYPE_ASM. It will check if line and/or file have actually
342  * changed, end the old and start the new line as necessary.
343  */
344 {
345     /* Check if we can reuse the old line */
346     if (AsmLineInfo) {
347         if (AsmLineInfo->Key.Pos.Line == CurTok.Pos.Line &&
348             AsmLineInfo->Key.Pos.Name == CurTok.Pos.Name) {
349             /* We do already have line info for this line */
350             return;
351         }
352
353         /* Line has changed -> end the old line */
354         EndLine (AsmLineInfo);
355     }
356
357     /* Start a new line using the current line info */
358     AsmLineInfo = StartLine (&CurTok.Pos, LI_TYPE_ASM, 0);
359 }
360
361
362
363 void GetFullLineInfo (Collection* LineInfos, int ForceRef)
364 /* Return full line infos, that is line infos for currently active Slots. The
365  * function will clear LineInfos before usage. If ForceRef is not zero, a
366  * forced reference will be added to all line infos, with the consequence that
367  * they won't get deleted, even if there is no code or data generated for these
368  * lines.
369  */
370 {
371     unsigned I;
372
373     /* Clear the collection */
374     CollDeleteAll (LineInfos);
375
376     /* Grow the collection as necessary */
377     CollGrow (LineInfos, CollCount (&CurLineInfo));
378
379     /* Copy all valid line infos to the collection */
380     for (I = 0; I < CollCount (&CurLineInfo); ++I) {
381
382         /* Get the line info from the slot */
383         LineInfo* LI = CollAt (&CurLineInfo, I);
384
385         /* Mark it as referenced */
386         if (ForceRef) {
387             LI->Referenced = 1;
388         }
389
390         /* Return it to the caller */
391         CollAppend (LineInfos, LI);
392     }
393 }
394
395
396
397 const FilePos* GetSourcePos (const LineInfo* LI)
398 /* Return the source file position from the given line info */
399 {
400     return &LI->Key.Pos;
401 }
402
403
404
405 unsigned GetLineInfoType (const LineInfo* LI)
406 /* Return the type of a line info */
407 {
408     return LI_GET_TYPE (LI->Key.Type);
409 }
410
411
412
413 void WriteLineInfo (const Collection* LineInfos)
414 /* Write a list of line infos to the object file. */
415 {
416     unsigned I;
417
418     /* Write the count */
419     ObjWriteVar (CollCount (LineInfos));
420
421     /* Write the line info indices */
422     for (I = 0; I < CollCount (LineInfos); ++I) {
423
424         /* Get a pointer to the line info */
425         const LineInfo* LI = CollConstAt (LineInfos, I);
426
427         CHECK (LI->Id != ~0U);
428
429         /* Write the index to the file */
430         ObjWriteVar (LI->Id);
431     }
432 }
433
434
435
436 void WriteLineInfos (void)
437 /* Write a list of all line infos to the object file. */
438 {
439     unsigned I;
440
441     /* Tell the object file module that we're about to write line infos */
442     ObjStartLineInfos ();
443
444     /* Write the line info count to the list */
445     ObjWriteVar (CollCount (&LineInfoList));
446
447     /* Walk over the list and write all line infos */
448     for (I = 0; I < CollCount (&LineInfoList); ++I) {
449
450         /* Get a pointer to this line info */
451         LineInfo* LI = CollAt (&LineInfoList, I);
452
453         /* Write the source file position */
454         ObjWritePos (&LI->Key.Pos);
455
456         /* Write the type and count of the line info */
457         ObjWriteVar (LI_MAKE_TYPE (LI->Key.Type, LI->Key.Count));
458
459         /* Write the spans for this line */
460         WriteSpans (&LI->Spans);
461     }
462
463     /* End of line infos */
464     ObjEndLineInfos ();
465 }
466
467
468