]> git.sur5r.net Git - cc65/blob - src/ca65/lineinfo.c
Started to generalize line info handling. Remove separate FilePos fields and
[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 /* Note: The line infos kept here are additional line infos supplied by the
37  * ".dbg line" command. The native line infos are always kept in the fragments
38  * itself (because one fragment always originates from one line). The
39  * additional line infos (which may not exist if none are supplied in the
40  * source) may have several fragments attached (as is the case with sources
41  * generated by the C compiler).
42  */
43
44
45
46 #include <string.h>
47 #include <limits.h>
48
49 /* common */
50 #include "coll.h"
51 #include "xmalloc.h"
52
53 /* ca65 */
54 #include "global.h"
55 #include "lineinfo.h"
56 #include "objfile.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Data                                    */
62 /*****************************************************************************/
63
64
65
66 /* An invalid line info index */
67 #define INV_LINEINFO_INDEX      UINT_MAX
68
69 /* Collection containing all line infos */
70 static Collection LineInfoColl = STATIC_COLLECTION_INITIALIZER;
71
72 /* Number of valid (=used) line infos in LineInfoColl */
73 static unsigned UsedLineInfoCount;
74
75 /* Entry in CurLineInfo */
76 typedef struct LineInfoSlot LineInfoSlot;
77 struct LineInfoSlot {
78     unsigned    Type;
79     LineInfo*   Info;
80 };
81
82 /* Dynamically allocated array of LineInfoSlots */
83 static LineInfoSlot* CurLineInfo;
84 static unsigned AllocatedSlots;
85 static unsigned UsedSlots;
86
87
88
89 /*****************************************************************************/
90 /*                              struct LineInfo                              */
91 /*****************************************************************************/
92
93
94
95 static LineInfo* NewLineInfo (unsigned Type, unsigned File,
96                               unsigned long Line, unsigned Col)
97 /* Create and return a new line info. Usage will be zero. */
98 {
99     /* Allocate memory */
100     LineInfo* LI = xmalloc (sizeof (LineInfo));
101
102     /* Initialize the fields */
103     LI->Usage    = 0;
104     LI->Type     = Type;
105     LI->Index    = INV_LINEINFO_INDEX;
106     LI->Pos.Name = File;
107     LI->Pos.Line = Line;
108     LI->Pos.Col  = Col;
109
110     /* Return the new struct */
111     return LI;
112 }
113
114
115
116 static void FreeLineInfo (LineInfo* LI)
117 /* "Free" line info. If the usage counter is non zero, move it to the
118  * collection that contains all line infos, otherwise delete it.
119  * The function handles a NULL pointer transparently.
120  */
121 {
122     if (LI) {
123         if (LI->Usage > 0) {
124             CollAppend (&LineInfoColl, LI);
125         } else {
126             xfree (LI);
127         }
128     }
129 }
130
131
132
133 /*****************************************************************************/
134 /*                                   Code                                    */
135 /*****************************************************************************/
136
137
138
139 void InitLineInfo (void)
140 /* Initialize the line infos */
141 {
142     /* Allocate 8 slots */
143     AllocatedSlots = 8;
144     CurLineInfo = xmalloc (AllocatedSlots * sizeof (LineInfoSlot));
145
146     /* Initalize the predefined slots */
147     UsedSlots = 2;
148     CurLineInfo[LI_SLOT_ASM].Type = LI_TYPE_ASM;
149     CurLineInfo[LI_SLOT_ASM].Info = 0;
150     CurLineInfo[LI_SLOT_EXT].Type = LI_TYPE_EXT; 
151     CurLineInfo[LI_SLOT_EXT].Info = 0;
152 }
153
154
155
156 unsigned AllocLineInfoSlot (unsigned Type)
157 /* Allocate a line info slot of the given type and return the slot index */
158 {
159     /* Grow the array if necessary */
160     if (UsedSlots >= AllocatedSlots) {
161         LineInfoSlot* NewLineInfo;
162         AllocatedSlots *= 2;
163         NewLineInfo = xmalloc (AllocatedSlots * sizeof (LineInfoSlot));
164         memcpy (NewLineInfo, CurLineInfo, UsedSlots * sizeof (LineInfoSlot));
165         xfree (CurLineInfo);
166         CurLineInfo = NewLineInfo;
167     }
168
169     /* Array is now big enough, add the new data */
170     CurLineInfo[UsedSlots].Type = Type;
171     CurLineInfo[UsedSlots].Info = 0;
172
173     /* Increment the count and return the index of the new slot */
174     return UsedSlots++;
175 }
176
177
178
179 void FreeLineInfoSlot (unsigned Slot)
180 /* Free the line info in the given slot. Note: Alloc/Free must be used in
181  * FIFO order.
182  */
183 {
184     /* Check the parameter */
185     PRECONDITION (Slot == UsedSlots - 1);
186
187     /* Free the last entry */
188     FreeLineInfo (CurLineInfo[Slot].Info);
189     --UsedSlots;
190 }
191
192
193
194 void GenLineInfo (unsigned Slot, unsigned File, unsigned long Line, unsigned Col)
195 /* Generate a new line info in the given slot */
196 {
197     /* Get a pointer to the slot */
198     LineInfoSlot* S = CurLineInfo + Slot;
199
200     /* Check if we already have data */
201     if (S->Info) {
202         /* Generate new data only if it is different from the existing. */
203         if (S->Info->Pos.Col == Col &&
204             S->Info->Pos.Line == Line &&
205             S->Info->Pos.Name == File) {
206             /* Already there */
207             return;
208         }
209
210         /* We have data, but it's not identical. If it is in use, copy it to
211          * line info collection, otherwise delete it.
212          */
213         FreeLineInfo (S->Info);
214
215     }
216
217     /* Allocate new data */
218     S->Info = NewLineInfo (S->Type, File, Line, Col);
219 }
220
221
222
223 void ClearLineInfo (unsigned Slot)
224 /* Clear the line info in the given slot */
225 {
226     /* Get a pointer to the slot */
227     LineInfoSlot* S = CurLineInfo + Slot;
228
229     /* Free the struct and zero the pointer */
230     FreeLineInfo (S->Info);
231     S->Info = 0;
232 }
233
234
235
236 LineInfo* GetLineInfo (unsigned Slot)
237 /* Get the line info from the given slot */
238 {
239     PRECONDITION (Slot < UsedSlots);
240     return CurLineInfo[Slot].Info;
241 }
242
243
244
245 void GetFullLineInfo (Collection* LineInfos)
246 /* Return full line infos, that is line infos for all slots in LineInfos. The
247  * function does also increase the usage counter for all line infos returned.
248  */
249 {
250    unsigned I;
251
252     /* Copy all valid line infos to the collection */
253     for (I = 0; I < UsedSlots; ++I) {
254
255         /* Get the slot */
256         LineInfoSlot* S = CurLineInfo + I;
257
258         /* Ignore empty slots */
259         if (S->Info) {
260             ++S->Info->Usage;
261             CollAppend (LineInfos, S->Info);
262         }
263     }
264 }
265
266
267
268 LineInfo* UseLineInfo (LineInfo* LI)
269 /* Increase the reference count of the given line info and return it. The
270  * function will gracefully accept NULL pointers and do nothing in this case.
271  */
272 {
273     if (LI) {
274         ++LI->Usage;
275     }
276     return LI;
277 }
278
279
280
281 LineInfo* ReleaseLineInfo (LineInfo* LI)
282 /* Decrease the reference count of the given line info and return it. The
283  * function will gracefully accept NULL pointers and do nothing in this case.
284  */
285 {
286     if (LI) {
287         /* Cannot decrease below zero */
288         CHECK (LI->Usage != 0);
289         --LI->Usage;
290     }
291     return LI;
292 }
293
294
295
296 static int CmpLineInfo (void* Data attribute ((unused)),
297                         const void* LI1_, const void* LI2_)
298 /* Compare function for the sort */
299 {
300     /* Cast the pointers */
301     const LineInfo* LI1 = LI1_;
302     const LineInfo* LI2 = LI2_;
303
304     /* Unreferenced line infos are always larger, otherwise sort by file,
305      * then by line, then by column.
306      */
307     if ((LI1->Usage == 0) == (LI2->Usage == 0)) {
308         /* Both are either referenced or unreferenced */
309         return CompareFilePos (&LI1->Pos, &LI2->Pos);
310     } else {
311         if (LI1->Usage > 0) {
312             return -1;
313         } else {
314             return 1;
315         }
316     }
317 }
318
319
320
321 void WriteLineInfo (const Collection* LineInfos)
322 /* Write a list of line infos to the object file. MakeLineInfoIndex has to
323  * be called before!
324  */
325 {
326     unsigned I;
327
328     /* Write the count */
329     ObjWriteVar (CollCount (LineInfos));
330
331     /* Write the line info indices */
332     for (I = 0; I < CollCount (LineInfos); ++I) {
333         ObjWriteVar (((const LineInfo*) CollConstAt (LineInfos, I))->Index);
334     }
335 }
336
337
338
339 void MakeLineInfoIndex (void)
340 /* Index the line infos */
341 {
342     unsigned I;
343
344     /* Sort the collection */
345     CollSort (&LineInfoColl, CmpLineInfo, 0);
346
347     /* Walk over the list, index the line infos and count the used ones */
348     UsedLineInfoCount = 0;
349     for (I = 0; I < CollCount (&LineInfoColl); ++I) {
350         /* Get a pointer to this line info */
351         LineInfo* LI = CollAtUnchecked (&LineInfoColl, I);
352
353         /* If it is invalid, terminate the loop. All unused line infos were
354          * placed at the end of the collection by the sort.
355          */
356         if (LI->Usage == 0) {
357             break;
358         }
359
360         /* Index and count this one */
361         LI->Index = I;
362         ++UsedLineInfoCount;
363     }
364 }
365
366
367
368 void WriteLineInfos (void)
369 /* Write a list of all line infos to the object file. */
370 {
371     /* Tell the object file module that we're about to write line infos */
372     ObjStartLineInfos ();
373
374     /* Check if debug info is requested */
375     if (DbgSyms) {
376
377         unsigned I;
378
379         /* Write the line info count to the list */
380         ObjWriteVar (UsedLineInfoCount);
381
382         /* Walk over the list and write all line infos */
383         for (I = 0; I < UsedLineInfoCount; ++I) {
384             /* Get a pointer to this line info */
385             LineInfo* LI = CollAt (&LineInfoColl, I);
386             /* Write the source file position */
387             ObjWritePos (&LI->Pos);
388         }
389
390     } else {
391
392         /* No line infos */
393         ObjWriteVar (0);
394
395     }
396
397     /* End of line infos */
398     ObjEndLineInfos ();
399 }
400
401
402