1 /*****************************************************************************/
5 /* cc65 debug info handling */
9 /* (C) 2010-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
49 /*****************************************************************************/
51 /*****************************************************************************/
55 /* Use this for debugging - beware, lots of output */
58 /* Version numbers of the debug format we understand */
63 typedef struct StrBuf StrBuf;
65 char* Buf; /* Pointer to buffer */
66 unsigned Len; /* Length of the string */
67 unsigned Allocated; /* Size of allocated memory */
70 /* Initializer for a string buffer */
71 #define STRBUF_INITIALIZER { 0, 0, 0 }
73 /* An array of unsigneds/pointers that grows if needed. C guarantees that a
74 ** pointer to a union correctly converted points to each of its members.
75 ** So what we do here is using union entries that contain an unsigned
76 ** (used to store ids until they're resolved) and pointers to actual items
79 typedef union CollEntry CollEntry;
85 typedef struct Collection Collection;
87 unsigned Count; /* Number of items in the list */
88 unsigned Size; /* Size of allocated array */
89 CollEntry* Items; /* Array with dynamic size */
92 /* Initializer for static collections */
93 #define COLLECTION_INITIALIZER { 0, 0, 0 }
95 /* Span info management. The following table has as many entries as there
96 ** are addresses active in spans. Each entry lists the spans for this address.
98 typedef struct SpanInfoListEntry SpanInfoListEntry;
99 struct SpanInfoListEntry {
100 cc65_addr Addr; /* Unique address */
101 unsigned Count; /* Number of SpanInfos for this address */
102 void* Data; /* Either SpanInfo* or SpanInfo** */
105 typedef struct SpanInfoList SpanInfoList;
106 struct SpanInfoList {
107 unsigned Count; /* Number of entries */
108 SpanInfoListEntry* List; /* Dynamic array with entries */
114 TOK_INVALID, /* Invalid token */
115 TOK_EOF, /* End of file reached */
117 TOK_INTCON, /* Integer constant */
118 TOK_STRCON, /* String constant */
127 TOK_ABSOLUTE = TOK_FIRST_KEYWORD, /* ABSOLUTE keyword */
128 TOK_ADDRSIZE, /* ADDRSIZE keyword */
129 TOK_AUTO, /* AUTO keyword */
130 TOK_COUNT, /* COUNT keyword */
131 TOK_CSYM, /* CSYM keyword */
132 TOK_DEF, /* DEF keyword */
133 TOK_ENUM, /* ENUM keyword */
134 TOK_EQUATE, /* EQUATE keyword */
135 TOK_EXPORT, /* EXPORT keyword */
136 TOK_EXTERN, /* EXTERN keyword */
137 TOK_FILE, /* FILE keyword */
138 TOK_FUNC, /* FUNC keyword */
139 TOK_GLOBAL, /* GLOBAL keyword */
140 TOK_ID, /* ID keyword */
141 TOK_IMPORT, /* IMPORT keyword */
142 TOK_INFO, /* INFO keyword */
143 TOK_LABEL, /* LABEL keyword */
144 TOK_LIBRARY, /* LIBRARY keyword */
145 TOK_LINE, /* LINE keyword */
146 TOK_LONG, /* LONG_keyword */
147 TOK_MAJOR, /* MAJOR keyword */
148 TOK_MINOR, /* MINOR keyword */
149 TOK_MODULE, /* MODULE keyword */
150 TOK_MTIME, /* MTIME keyword */
151 TOK_NAME, /* NAME keyword */
152 TOK_OFFS, /* OFFS keyword */
153 TOK_OUTPUTNAME, /* OUTPUTNAME keyword */
154 TOK_OUTPUTOFFS, /* OUTPUTOFFS keyword */
155 TOK_PARENT, /* PARENT keyword */
156 TOK_REF, /* REF keyword */
157 TOK_REGISTER, /* REGISTER keyword */
158 TOK_RO, /* RO keyword */
159 TOK_RW, /* RW keyword */
160 TOK_SC, /* SC keyword */
161 TOK_SCOPE, /* SCOPE keyword */
162 TOK_SEGMENT, /* SEGMENT keyword */
163 TOK_SIZE, /* SIZE keyword */
164 TOK_SPAN, /* SPAN keyword */
165 TOK_START, /* START keyword */
166 TOK_STATIC, /* STATIC keyword */
167 TOK_STRUCT, /* STRUCT keyword */
168 TOK_SYM, /* SYM keyword */
169 TOK_TYPE, /* TYPE keyword */
170 TOK_VALUE, /* VALUE keyword */
171 TOK_VAR, /* VAR keyword */
172 TOK_VERSION, /* VERSION keyword */
173 TOK_ZEROPAGE, /* ZEROPAGE keyword */
174 TOK_LAST_KEYWORD = TOK_ZEROPAGE,
176 TOK_IDENT, /* To catch unknown keywords */
179 /* Data structure containing information from the debug info file. A pointer
180 ** to this structure is passed as handle to callers from the outside.
182 typedef struct DbgInfo DbgInfo;
185 /* First we have all items in collections sorted by id. The ids are
186 ** continous, so an access by id is almost as cheap as an array access.
187 ** The collections are also used when the objects are deleted, so they're
188 ** actually the ones that "own" the items.
190 Collection CSymInfoById; /* C symbol infos sorted by id */
191 Collection FileInfoById; /* File infos sorted by id */
192 Collection LibInfoById; /* Library infos sorted by id */
193 Collection LineInfoById; /* Line infos sorted by id */
194 Collection ModInfoById; /* Module infos sorted by id */
195 Collection ScopeInfoById; /* Scope infos sorted by id */
196 Collection SegInfoById; /* Segment infos sorted by id */
197 Collection SpanInfoById; /* Span infos sorted by id */
198 Collection SymInfoById; /* Symbol infos sorted by id */
199 Collection TypeInfoById; /* Type infos sorted by id */
201 /* Collections with other sort criteria */
202 Collection CSymFuncByName; /* C functions sorted by name */
203 Collection FileInfoByName; /* File infos sorted by name */
204 Collection ModInfoByName; /* Module info sorted by name */
205 Collection ScopeInfoByName;/* Scope infos sorted by name */
206 Collection SegInfoByName; /* Segment infos sorted by name */
207 Collection SymInfoByName; /* Symbol infos sorted by name */
208 Collection SymInfoByVal; /* Symbol infos sorted by value */
211 SpanInfoList SpanInfoByAddr; /* Span infos sorted by unique address */
214 unsigned long MemUsage; /* Memory usage for the data */
215 unsigned MajorVersion; /* Major version number of loaded file */
216 unsigned MinorVersion; /* Minor version number of loaded file */
217 char FileName[1]; /* Name of input file */
220 /* Data used when parsing the debug info file */
221 typedef struct InputData InputData;
223 const char* FileName; /* Name of input file */
224 cc65_line Line; /* Current line number */
225 unsigned Col; /* Current column number */
226 cc65_line SLine; /* Line number at start of token */
227 unsigned SCol; /* Column number at start of token */
228 unsigned Errors; /* Number of errors */
229 FILE* F; /* Input file */
230 int C; /* Input character */
231 Token Tok; /* Token from input stream */
232 unsigned long IVal; /* Integer constant */
233 StrBuf SVal; /* String constant */
234 cc65_errorfunc Error; /* Function called in case of errors */
235 DbgInfo* Info; /* Pointer to debug info */
238 /* Typedefs for the item structures. Do also serve as forwards */
239 typedef struct CSymInfo CSymInfo;
240 typedef struct FileInfo FileInfo;
241 typedef struct LibInfo LibInfo;
242 typedef struct LineInfo LineInfo;
243 typedef struct ModInfo ModInfo;
244 typedef struct ScopeInfo ScopeInfo;
245 typedef struct SegInfo SegInfo;
246 typedef struct SpanInfo SpanInfo;
247 typedef struct SymInfo SymInfo;
248 typedef struct TypeInfo TypeInfo;
250 /* Internally used c symbol info struct */
252 unsigned Id; /* Id of file */
253 unsigned short Kind; /* Kind of C symbol */
254 unsigned short SC; /* Storage class of C symbol */
255 int Offs; /* Offset */
257 unsigned Id; /* Id of attached asm symbol */
258 SymInfo* Info; /* Pointer to attached asm symbol */
261 unsigned Id; /* Id of type */
262 TypeInfo* Info; /* Pointer to type */
265 unsigned Id; /* Id of scope */
266 ScopeInfo* Info; /* Pointer to scope */
268 char Name[1]; /* Name of file with full path */
271 /* Internally used file info struct */
273 unsigned Id; /* Id of file */
274 unsigned long Size; /* Size of file */
275 unsigned long MTime; /* Modification time */
276 Collection ModInfoByName; /* Modules in which this file is used */
277 Collection LineInfoByLine; /* Line infos sorted by line */
278 char Name[1]; /* Name of file with full path */
281 /* Internally used library info struct */
283 unsigned Id; /* Id of library */
284 char Name[1]; /* Name of library with path */
287 /* Internally used line info struct */
289 unsigned Id; /* Id of line info */
290 cc65_line Line; /* Line number */
292 unsigned Id; /* Id of file */
293 FileInfo* Info; /* Pointer to file info */
295 cc65_line_type Type; /* Type of line */
296 unsigned Count; /* Nesting counter for macros */
297 Collection SpanInfoList; /* List of spans for this line */
300 /* Internally used module info struct */
302 unsigned Id; /* Id of library */
304 unsigned Id; /* Id of main source file */
305 FileInfo* Info; /* Pointer to file info */
308 unsigned Id; /* Id of library if any */
309 LibInfo* Info; /* Pointer to library info */
311 ScopeInfo* MainScope; /* Pointer to main scope */
312 Collection CSymFuncByName; /* C functions by name */
313 Collection FileInfoByName; /* Files for this module */
314 Collection ScopeInfoByName;/* Scopes for this module */
315 char Name[1]; /* Name of module with path */
318 /* Internally used scope info struct */
320 unsigned Id; /* Id of scope */
321 cc65_scope_type Type; /* Type of scope */
322 cc65_size Size; /* Size of scope */
324 unsigned Id; /* Id of module */
325 ModInfo* Info; /* Pointer to module info */
328 unsigned Id; /* Id of parent scope */
329 ScopeInfo* Info; /* Pointer to parent scope */
332 unsigned Id; /* Id of label symbol */
333 SymInfo* Info; /* Pointer to label symbol */
335 CSymInfo* CSymFunc; /* C function for this scope */
336 Collection SpanInfoList; /* List of spans for this scope */
337 Collection SymInfoByName; /* Symbols in this scope */
338 Collection* CSymInfoByName; /* C symbols for this scope */
339 Collection* ChildScopeList; /* Child scopes of this scope */
340 char Name[1]; /* Name of scope */
343 /* Internally used segment info struct */
345 unsigned Id; /* Id of segment */
346 cc65_addr Start; /* Start address of segment */
347 cc65_size Size; /* Size of segment */
348 char* OutputName; /* Name of output file */
349 unsigned long OutputOffs; /* Offset in output file */
350 char Name[1]; /* Name of segment */
353 /* Internally used span info struct */
355 unsigned Id; /* Id of span */
356 cc65_addr Start; /* Start of span */
357 cc65_addr End; /* End of span */
359 unsigned Id; /* Id of segment */
360 SegInfo* Info; /* Pointer to segment */
363 unsigned Id; /* Id of type */
364 TypeInfo* Info; /* Pointer to type */
366 Collection* ScopeInfoList; /* Scopes for this span */
367 Collection* LineInfoList; /* Lines for this span */
370 /* Internally used symbol info struct */
372 unsigned Id; /* Id of symbol */
373 cc65_symbol_type Type; /* Type of symbol */
374 long Value; /* Value of symbol */
375 cc65_size Size; /* Size of symbol */
377 unsigned Id; /* Id of export if any */
378 SymInfo* Info; /* Pointer to export if any */
381 unsigned Id; /* Id of segment if any */
382 SegInfo* Info; /* Pointer to segment if any */
385 unsigned Id; /* Id of symbol scope */
386 ScopeInfo* Info; /* Pointer to symbol scope */
389 unsigned Id; /* Parent symbol if any */
390 SymInfo* Info; /* Pointer to parent symbol if any */
392 CSymInfo* CSym; /* Corresponding C symbol */
393 Collection* ImportList; /* List of imports if this is an export */
394 Collection* CheapLocals; /* List of cheap local symbols */
395 Collection DefLineInfoList;/* Line info of symbol definition */
396 Collection RefLineInfoList;/* Line info of symbol references */
397 char Name[1]; /* Name of symbol */
400 /* Internally used type info struct */
402 unsigned Id; /* Id of type */
403 cc65_typedata Data[1]; /* Data, dynamically allocated */
406 /* A structure used when parsing a type string into a set of cc65_typedata
409 typedef struct TypeParseData TypeParseData;
410 struct TypeParseData {
414 cc65_typedata* ItemData;
422 /*****************************************************************************/
424 /*****************************************************************************/
428 static void NextToken (InputData* D);
429 /* Read the next token from the input stream */
433 /*****************************************************************************/
434 /* Memory allocation */
435 /*****************************************************************************/
439 static void* xmalloc (size_t Size)
440 /* Allocate memory, check for out of memory condition. Do some debugging */
444 /* Allow zero sized requests and return NULL in this case */
447 /* Allocate memory */
450 /* Check for errors */
454 /* Return a pointer to the block */
460 static void* xrealloc (void* P, size_t Size)
461 /* Reallocate a memory block, check for out of memory */
463 /* Reallocate the block */
464 void* N = realloc (P, Size);
466 /* Check for errors */
467 assert (N != 0 || Size == 0);
469 /* Return the pointer to the new block */
475 static void xfree (void* Block)
476 /* Free the block, do some debugging */
483 /*****************************************************************************/
484 /* Dynamic strings */
485 /*****************************************************************************/
489 static void SB_Done (StrBuf* B)
490 /* Free the data of a string buffer (but not the struct itself) */
499 static void SB_Realloc (StrBuf* B, unsigned NewSize)
500 /* Reallocate the string buffer space, make sure at least NewSize bytes are
504 /* Get the current size, use a minimum of 8 bytes */
505 unsigned NewAllocated = B->Allocated;
506 if (NewAllocated == 0) {
510 /* Round up to the next power of two */
511 while (NewAllocated < NewSize) {
515 /* Reallocate the buffer. Beware: The allocated size may be zero while the
516 ** length is not. This means that we have a buffer that wasn't allocated
520 /* Just reallocate the block */
521 B->Buf = xrealloc (B->Buf, NewAllocated);
523 /* Allocate a new block and copy */
524 B->Buf = memcpy (xmalloc (NewAllocated), B->Buf, B->Len);
527 /* Remember the new block size */
528 B->Allocated = NewAllocated;
533 static void SB_CheapRealloc (StrBuf* B, unsigned NewSize)
534 /* Reallocate the string buffer space, make sure at least NewSize bytes are
535 ** available. This function won't copy the old buffer contents over to the new
536 ** buffer and may be used if the old contents are overwritten later.
539 /* Get the current size, use a minimum of 8 bytes */
540 unsigned NewAllocated = B->Allocated;
541 if (NewAllocated == 0) {
545 /* Round up to the next power of two */
546 while (NewAllocated < NewSize) {
550 /* Free the old buffer if there is one */
555 /* Allocate a fresh block */
556 B->Buf = xmalloc (NewAllocated);
558 /* Remember the new block size */
559 B->Allocated = NewAllocated;
564 static unsigned SB_GetLen (const StrBuf* B)
565 /* Return the length of the buffer contents */
572 static char* SB_GetBuf (StrBuf* B)
573 /* Return a buffer pointer */
580 static const char* SB_GetConstBuf (const StrBuf* B)
581 /* Return a buffer pointer */
588 static char SB_At (const StrBuf* B, unsigned Pos)
589 /* Return the character from a specific position */
591 assert (Pos <= B->Len);
597 static void SB_Terminate (StrBuf* B)
598 /* Zero terminate the given string buffer. NOTE: The terminating zero is not
599 ** accounted for in B->Len, if you want that, you have to use AppendChar!
602 unsigned NewLen = B->Len + 1;
603 if (NewLen > B->Allocated) {
604 SB_Realloc (B, NewLen);
606 B->Buf[B->Len] = '\0';
611 static void SB_Clear (StrBuf* B)
612 /* Clear the string buffer (make it empty) */
619 static void SB_CopyBuf (StrBuf* Target, const char* Buf, unsigned Size)
620 /* Copy Buf to Target, discarding the old contents of Target */
623 if (Target->Allocated < Size) {
624 SB_CheapRealloc (Target, Size);
626 memcpy (Target->Buf, Buf, Size);
633 static void SB_Copy (StrBuf* Target, const StrBuf* Source)
634 /* Copy Source to Target, discarding the old contents of Target */
636 SB_CopyBuf (Target, Source->Buf, Source->Len);
641 static void SB_AppendChar (StrBuf* B, int C)
642 /* Append a character to a string buffer */
644 unsigned NewLen = B->Len + 1;
645 if (NewLen > B->Allocated) {
646 SB_Realloc (B, NewLen);
648 B->Buf[B->Len] = (char) C;
654 static char* SB_StrDup (const StrBuf* B)
655 /* Return the contents of B as a dynamically allocated string. The string
656 ** will always be NUL terminated.
659 /* Allocate memory */
660 char* S = xmalloc (B->Len + 1);
662 /* Copy the string */
663 memcpy (S, B->Buf, B->Len);
668 /* And return the result */
674 /*****************************************************************************/
676 /*****************************************************************************/
680 static Collection* CollInit (Collection* C)
681 /* Initialize a collection and return it. */
683 /* Intialize the fields. */
688 /* Return the new struct */
694 static Collection* CollNew (void)
695 /* Allocate a new collection, initialize and return it */
697 return CollInit (xmalloc (sizeof (Collection)));
702 static void CollDone (Collection* C)
703 /* Free the data for a collection. This will not free the data contained in
707 /* Free the pointer array */
710 /* Clear the fields, so the collection may be reused (or CollDone called)
720 static void CollFree (Collection* C)
721 /* Free a dynamically allocated collection */
723 /* Accept NULL pointers */
732 static unsigned CollCount (const Collection* C)
733 /* Return the number of items in the collection. Return 0 if C is NULL. */
735 return C? C->Count : 0;
740 static void CollMove (Collection* Source, Collection* Target)
741 /* Move all data from one collection to another. This function will first free
742 ** the data in the target collection, and - after the move - clear the data
743 ** from the source collection.
746 /* Free the target collection data */
747 xfree (Target->Items);
749 /* Now copy the whole bunch over */
760 static void CollGrow (Collection* C, unsigned Size)
761 /* Grow the collection C so it is able to hold Size items without a resize
762 ** being necessary. This can be called for performance reasons if the number
763 ** of items to be placed in the collection is known in advance.
768 /* Ignore the call if the collection is already large enough */
769 if (Size <= C->Size) {
773 /* Grow the collection */
775 NewItems = xmalloc (C->Size * sizeof (CollEntry));
776 memcpy (NewItems, C->Items, C->Count * sizeof (CollEntry));
783 static void CollPrepareInsert (Collection* C, unsigned Index)
784 /* Prepare for insertion of the data at a given position in the collection */
786 /* Check for invalid indices */
787 assert (Index <= C->Count);
789 /* Grow the array if necessary */
790 if (C->Count >= C->Size) {
792 CollGrow (C, (C->Size == 0)? 1 : C->Size * 2);
795 /* Move the existing elements if needed */
796 if (C->Count != Index) {
797 memmove (C->Items+Index+1, C->Items+Index, (C->Count-Index) * sizeof (void*));
804 static void CollInsert (Collection* C, void* Item, unsigned Index)
805 /* Insert the data at the given position in the collection */
807 /* Prepare for insertion (free the given slot) */
808 CollPrepareInsert (C, Index);
810 /* Store the new item */
811 C->Items[Index].Ptr = Item;
816 static void CollInsertId (Collection* C, unsigned Id, unsigned Index)
817 /* Insert the data at the given position in the collection */
819 /* Prepare for insertion (free the given slot) */
820 CollPrepareInsert (C, Index);
822 /* Store the new item */
823 C->Items[Index].Id = Id;
828 static void CollReplace (Collection* C, void* Item, unsigned Index)
829 /* Replace the item at the given position by a new one */
831 /* Check the index */
832 assert (Index < C->Count);
834 /* Replace the element */
835 C->Items[Index].Ptr = Item;
840 static void CollReplaceExpand (Collection* C, void* Item, unsigned Index)
841 /* If Index is a valid index for the collection, replace the item at this
842 ** position by the one passed. If the collection is too small, expand it,
843 ** filling unused pointers with NULL, then add the new item at the given
847 if (Index < C->Count) {
848 /* Collection is already large enough */
849 C->Items[Index].Ptr = Item;
851 /* Must expand the collection */
852 unsigned Size = C->Size;
856 while (Index >= Size) {
861 /* Fill up unused slots with NULL */
862 while (C->Count < Index) {
863 C->Items[C->Count++].Ptr = 0;
866 /* Fill in the item */
867 C->Items[C->Count++].Ptr = Item;
873 static void CollAppend (Collection* C, void* Item)
874 /* Append an item to the end of the collection */
876 /* Insert the item at the end of the current list */
877 CollInsert (C, Item, C->Count);
882 static void CollAppendId (Collection* C, unsigned Id)
883 /* Append an id to the end of the collection */
885 /* Insert the id at the end of the current list */
886 CollInsertId (C, Id, C->Count);
891 static void* CollAt (const Collection* C, unsigned Index)
892 /* Return the item at the given index */
894 /* Check the index */
895 assert (Index < C->Count);
897 /* Return the element */
898 return C->Items[Index].Ptr;
903 static unsigned CollIdAt (const Collection* C, unsigned Index)
904 /* Return the id at the given index */
906 /* Check the index */
907 assert (Index < C->Count);
909 /* Return the element */
910 return C->Items[Index].Id;
915 static void CollQuickSort (Collection* C, int Lo, int Hi,
916 int (*Compare) (const void*, const void*))
917 /* Internal recursive sort function. */
919 /* Get a pointer to the items */
920 CollEntry* Items = C->Items;
927 while (I <= J && Compare (Items[Lo].Ptr, Items[I].Ptr) >= 0) {
930 while (I <= J && Compare (Items[Lo].Ptr, Items[J].Ptr) < 0) {
935 CollEntry Tmp = Items[I];
944 CollEntry Tmp = Items[J];
945 Items[J] = Items[Lo];
948 if (J > (Hi + Lo) / 2) {
949 CollQuickSort (C, J + 1, Hi, Compare);
952 CollQuickSort (C, Lo, J - 1, Compare);
960 static void CollSort (Collection* C, int (*Compare) (const void*, const void*))
961 /* Sort the collection using the given compare function. */
964 CollQuickSort (C, 0, C->Count-1, Compare);
970 /*****************************************************************************/
971 /* Debugging stuff */
972 /*****************************************************************************/
979 #define DBGPRINT(format, ...) printf ((format), __VA_ARGS__)
983 static void DumpFileInfo (Collection* FileInfos)
984 /* Dump a list of file infos */
989 for (I = 0; I < CollCount (FileInfos); ++I) {
990 const FileInfo* FI = CollAt (FileInfos, I);
991 printf ("File info %u:\n"
997 (unsigned long) FI->Size,
998 (unsigned long) FI->MTime);
1004 static void DumpOneLineInfo (unsigned Num, LineInfo* LI)
1005 /* Dump one line info entry */
1007 printf (" Index: %u\n"
1010 " Range: 0x%06lX-0x%06lX\n"
1014 LI->File.Info->Name,
1015 (unsigned long) LI->Line,
1016 (unsigned long) LI->Start,
1017 (unsigned long) LI->End,
1024 static void DumpSpanInfo (SpanInfoList* L)
1025 /* Dump a list of span infos */
1030 for (I = 0; I < L->Count; ++I) {
1031 const SpanInfoListEntry* E = &L->List[I];
1032 printf ("Addr: %lu\n", (unsigned long) E->Addr);
1033 if (E->Count == 1) {
1034 DumpOneLineInfo (0, E->Data);
1036 for (J = 0; J < E->Count; ++J) {
1037 DumpOneLineInfo (J, ((LineInfo**) E->Data)[J]);
1045 static void DumpData (InputData* D)
1046 /* Dump internal data to stdout for debugging */
1049 DumpFileInfo (&D->Info->FileInfoById);
1050 DumpLineInfo (&D->Info->LineInfoByAddr);
1056 static void DBGPRINT(const char* format, ...) {}
1058 #define DBGPRINT(format, ...)
1065 /*****************************************************************************/
1066 /* Helper functions */
1067 /*****************************************************************************/
1071 static unsigned GetId (const void* Data)
1072 /* Return the id of one of the info structures. All structures have the Id
1073 ** field as first member, and the C standard allows converting a union pointer
1074 ** to the data type of the first member, so this is safe and portable.
1078 return *(const unsigned*)Data;
1086 static unsigned HexValue (char C)
1087 /* Convert the ascii representation of a hex nibble into the hex nibble */
1091 } else if (islower (C)) {
1092 return C - 'a' + 10;
1094 return C - 'A' + 10;
1100 static void ParseError (InputData* D, cc65_error_severity Type, const char* Msg, ...)
1101 /* Call the user supplied parse error function */
1107 /* Test-format the error message so we know how much space to allocate */
1109 MsgSize = vsnprintf (0, 0, Msg, ap);
1112 /* Allocate memory */
1113 E = xmalloc (sizeof (*E) + MsgSize);
1115 /* Write data to E */
1117 E->name = D->FileName;
1119 E->column = D->SCol;
1121 vsnprintf (E->errormsg, MsgSize+1, Msg, ap);
1124 /* Call the caller:-) */
1127 /* Free the data structure */
1131 if (Type == CC65_ERROR) {
1138 static void SkipLine (InputData* D)
1139 /* Error recovery routine. Skip tokens until EOL or EOF is reached */
1141 while (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
1148 static void UnexpectedToken (InputData* D)
1149 /* Call ParseError with a message about an unexpected input token */
1151 ParseError (D, CC65_ERROR, "Unexpected input token %d", D->Tok);
1157 static void UnknownKeyword (InputData* D)
1158 /* Print a warning about an unknown keyword in the file. Try to do smart
1159 ** recovery, so if later versions of the debug information add additional
1160 ** keywords, this code may be able to at least ignore them.
1163 /* Output a warning */
1164 ParseError (D, CC65_WARNING, "Unknown keyword \"%s\" - skipping",
1165 SB_GetConstBuf (&D->SVal));
1167 /* Skip the identifier */
1170 /* If an equal sign follows, ignore anything up to the next line end
1171 ** or comma. If a comma or line end follows, we're already done. If
1172 ** we have none of both, we ignore the remainder of the line.
1174 if (D->Tok == TOK_EQUAL) {
1176 while (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
1179 } else if (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
1186 /*****************************************************************************/
1188 /*****************************************************************************/
1192 static CSymInfo* NewCSymInfo (const StrBuf* Name)
1193 /* Create a new CSymInfo struct and return it */
1195 /* Allocate memory */
1196 CSymInfo* S = xmalloc (sizeof (CSymInfo) + SB_GetLen (Name));
1199 memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1207 static void FreeCSymInfo (CSymInfo* S)
1208 /* Free a CSymInfo struct */
1210 /* Free the structure itself */
1216 static cc65_csyminfo* new_cc65_csyminfo (unsigned Count)
1217 /* Allocate and return a cc65_csyminfo struct that is able to hold Count
1218 ** entries. Initialize the count field of the returned struct.
1221 cc65_csyminfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1222 Count * sizeof (S->data[0]));
1229 static void CopyCSymInfo (cc65_csymdata* D, const CSymInfo* S)
1230 /* Copy data from a CSymInfo struct to a cc65_csymdata struct */
1233 D->csym_kind = S->Kind;
1235 D->csym_offs = S->Offs;
1236 D->type_id = GetId (S->Type.Info);
1237 D->symbol_id = GetId (S->Sym.Info);
1238 D->scope_id = GetId (S->Scope.Info);
1239 D->csym_name = S->Name;
1244 static int CompareCSymInfoByName (const void* L, const void* R)
1245 /* Helper function to sort c symbol infos in a collection by name */
1247 /* Sort by symbol name, then by id */
1248 int Res = strcmp (((const CSymInfo*) L)->Name, ((const CSymInfo*) R)->Name);
1250 Res = (int)((const CSymInfo*) L)->Id - (int)((const CSymInfo*) R)->Id;
1257 /*****************************************************************************/
1259 /*****************************************************************************/
1263 static FileInfo* NewFileInfo (const StrBuf* Name)
1264 /* Create a new FileInfo struct and return it */
1266 /* Allocate memory */
1267 FileInfo* F = xmalloc (sizeof (FileInfo) + SB_GetLen (Name));
1270 CollInit (&F->ModInfoByName);
1271 CollInit (&F->LineInfoByLine);
1272 memcpy (F->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1280 static void FreeFileInfo (FileInfo* F)
1281 /* Free a FileInfo struct */
1283 /* Delete the collections */
1284 CollDone (&F->ModInfoByName);
1285 CollDone (&F->LineInfoByLine);
1287 /* Free the file info structure itself */
1293 static cc65_sourceinfo* new_cc65_sourceinfo (unsigned Count)
1294 /* Allocate and return a cc65_sourceinfo struct that is able to hold Count
1295 ** entries. Initialize the count field of the returned struct.
1298 cc65_sourceinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1299 Count * sizeof (S->data[0]));
1306 static void CopyFileInfo (cc65_sourcedata* D, const FileInfo* F)
1307 /* Copy data from a FileInfo struct to a cc65_sourcedata struct */
1309 D->source_id = F->Id;
1310 D->source_name = F->Name;
1311 D->source_size = F->Size;
1312 D->source_mtime = F->MTime;
1317 static int CompareFileInfoByName (const void* L, const void* R)
1318 /* Helper function to sort file infos in a collection by name */
1320 /* Sort by file name. If names are equal, sort by timestamp,
1321 ** then sort by size. Which means, identical files will go
1324 int Res = strcmp (((const FileInfo*) L)->Name,
1325 ((const FileInfo*) R)->Name);
1329 if (((const FileInfo*) L)->MTime > ((const FileInfo*) R)->MTime) {
1331 } else if (((const FileInfo*) L)->MTime < ((const FileInfo*) R)->MTime) {
1334 if (((const FileInfo*) L)->Size > ((const FileInfo*) R)->Size) {
1336 } else if (((const FileInfo*) L)->Size < ((const FileInfo*) R)->Size) {
1345 /*****************************************************************************/
1347 /*****************************************************************************/
1351 static LibInfo* NewLibInfo (const StrBuf* Name)
1352 /* Create a new LibInfo struct, intialize and return it */
1354 /* Allocate memory */
1355 LibInfo* L = xmalloc (sizeof (LibInfo) + SB_GetLen (Name));
1357 /* Initialize the name */
1358 memcpy (L->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1366 static void FreeLibInfo (LibInfo* L)
1367 /* Free a LibInfo struct */
1374 static cc65_libraryinfo* new_cc65_libraryinfo (unsigned Count)
1375 /* Allocate and return a cc65_libraryinfo struct that is able to hold Count
1376 ** entries. Initialize the count field of the returned struct.
1379 cc65_libraryinfo* L = xmalloc (sizeof (*L) - sizeof (L->data[0]) +
1380 Count * sizeof (L->data[0]));
1387 static void CopyLibInfo (cc65_librarydata* D, const LibInfo* L)
1388 /* Copy data from a LibInfo struct to a cc65_librarydata struct */
1390 D->library_id = L->Id;
1391 D->library_name = L->Name;
1396 /*****************************************************************************/
1398 /*****************************************************************************/
1402 static LineInfo* NewLineInfo (void)
1403 /* Create a new LineInfo struct and return it */
1405 /* Allocate memory */
1406 LineInfo* L = xmalloc (sizeof (LineInfo));
1408 /* Initialize and return it */
1409 CollInit (&L->SpanInfoList);
1415 static void FreeLineInfo (LineInfo* L)
1416 /* Free a LineInfo struct */
1418 CollDone (&L->SpanInfoList);
1424 static cc65_lineinfo* new_cc65_lineinfo (unsigned Count)
1425 /* Allocate and return a cc65_lineinfo struct that is able to hold Count
1426 ** entries. Initialize the count field of the returned struct.
1429 cc65_lineinfo* L = xmalloc (sizeof (*L) - sizeof (L->data[0]) +
1430 Count * sizeof (L->data[0]));
1437 static void CopyLineInfo (cc65_linedata* D, const LineInfo* L)
1438 /* Copy data from a LineInfo struct to a cc65_linedata struct */
1441 D->source_id = L->File.Info->Id;
1442 D->source_line = L->Line;
1443 D->line_type = L->Type;
1444 D->count = L->Count;
1449 static int CompareLineInfoByLine (const void* L, const void* R)
1450 /* Helper function to sort line infos in a collection by line. */
1452 int Left = ((const LineInfo*) L)->Line;
1453 int Right = ((const LineInfo*) R)->Line;
1454 return Left - Right;
1459 /*****************************************************************************/
1461 /*****************************************************************************/
1465 static ModInfo* NewModInfo (const StrBuf* Name)
1466 /* Create a new ModInfo struct, intialize and return it */
1468 /* Allocate memory */
1469 ModInfo* M = xmalloc (sizeof (ModInfo) + SB_GetLen (Name));
1473 CollInit (&M->CSymFuncByName);
1474 CollInit (&M->FileInfoByName);
1475 CollInit (&M->ScopeInfoByName);
1476 memcpy (M->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1484 static void FreeModInfo (ModInfo* M)
1485 /* Free a ModInfo struct */
1487 /* Free the collections */
1488 CollDone (&M->CSymFuncByName);
1489 CollDone (&M->FileInfoByName);
1490 CollDone (&M->ScopeInfoByName);
1492 /* Free the structure itself */
1498 static cc65_moduleinfo* new_cc65_moduleinfo (unsigned Count)
1499 /* Allocate and return a cc65_moduleinfo struct that is able to hold Count
1500 ** entries. Initialize the count field of the returned struct.
1503 cc65_moduleinfo* M = xmalloc (sizeof (*M) - sizeof (M->data[0]) +
1504 Count * sizeof (M->data[0]));
1511 static void CopyModInfo (cc65_moduledata* D, const ModInfo* M)
1512 /* Copy data from a ModInfo struct to a cc65_moduledata struct */
1514 D->module_id = M->Id;
1515 D->module_name = M->Name;
1516 D->source_id = M->File.Info->Id;
1517 D->library_id = GetId (M->Lib.Info);
1518 D->scope_id = GetId (M->MainScope);
1523 static int CompareModInfoByName (const void* L, const void* R)
1524 /* Helper function to sort module infos in a collection by name */
1526 /* Compare module name */
1527 return strcmp (((const ModInfo*) L)->Name, ((const ModInfo*) R)->Name);
1532 /*****************************************************************************/
1534 /*****************************************************************************/
1538 static ScopeInfo* NewScopeInfo (const StrBuf* Name)
1539 /* Create a new ScopeInfo struct, intialize and return it */
1541 /* Allocate memory */
1542 ScopeInfo* S = xmalloc (sizeof (ScopeInfo) + SB_GetLen (Name));
1544 /* Initialize the fields as necessary */
1546 CollInit (&S->SpanInfoList);
1547 CollInit (&S->SymInfoByName);
1548 S->CSymInfoByName = 0;
1549 S->ChildScopeList = 0;
1550 memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1558 static void FreeScopeInfo (ScopeInfo* S)
1559 /* Free a ScopeInfo struct */
1561 CollDone (&S->SpanInfoList);
1562 CollDone (&S->SymInfoByName);
1563 CollFree (S->CSymInfoByName);
1564 CollFree (S->ChildScopeList);
1570 static cc65_scopeinfo* new_cc65_scopeinfo (unsigned Count)
1571 /* Allocate and return a cc65_scopeinfo struct that is able to hold Count
1572 ** entries. Initialize the count field of the returned struct.
1575 cc65_scopeinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1576 Count * sizeof (S->data[0]));
1583 static void CopyScopeInfo (cc65_scopedata* D, const ScopeInfo* S)
1584 /* Copy data from a ScopeInfo struct to a cc65_scopedata struct */
1586 D->scope_id = S->Id;
1587 D->scope_name = S->Name;
1588 D->scope_type = S->Type;
1589 D->scope_size = S->Size;
1590 D->parent_id = GetId (S->Parent.Info);
1591 D->symbol_id = GetId (S->Label.Info);
1592 D->module_id = S->Mod.Info->Id;
1597 static int CompareScopeInfoByName (const void* L, const void* R)
1598 /* Helper function to sort scope infos in a collection by name */
1600 const ScopeInfo* Left = L;
1601 const ScopeInfo* Right = R;
1603 /* Compare scope name, then id */
1604 int Res = strcmp (Left->Name, Right->Name);
1606 Res = (int)Left->Id - (int)Right->Id;
1613 /*****************************************************************************/
1615 /*****************************************************************************/
1619 static SegInfo* NewSegInfo (const StrBuf* Name, unsigned Id,
1620 cc65_addr Start, cc65_addr Size,
1621 const StrBuf* OutputName, unsigned long OutputOffs)
1622 /* Create a new SegInfo struct and return it */
1624 /* Allocate memory */
1625 SegInfo* S = xmalloc (sizeof (SegInfo) + SB_GetLen (Name));
1631 if (SB_GetLen (OutputName) > 0) {
1632 /* Output file given */
1633 S->OutputName = SB_StrDup (OutputName);
1634 S->OutputOffs = OutputOffs;
1636 /* No output file given */
1640 memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1648 static void FreeSegInfo (SegInfo* S)
1649 /* Free a SegInfo struct */
1651 xfree (S->OutputName);
1657 static cc65_segmentinfo* new_cc65_segmentinfo (unsigned Count)
1658 /* Allocate and return a cc65_segmentinfo struct that is able to hold Count
1659 ** entries. Initialize the count field of the returned struct.
1662 cc65_segmentinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1663 Count * sizeof (S->data[0]));
1670 static void CopySegInfo (cc65_segmentdata* D, const SegInfo* S)
1671 /* Copy data from a SegInfo struct to a cc65_segmentdata struct */
1673 D->segment_id = S->Id;
1674 D->segment_name = S->Name;
1675 D->segment_start = S->Start;
1676 D->segment_size = S->Size;
1677 D->output_name = S->OutputName;
1678 D->output_offs = S->OutputOffs;
1683 static int CompareSegInfoByName (const void* L, const void* R)
1684 /* Helper function to sort segment infos in a collection by name */
1686 /* Sort by file name */
1687 return strcmp (((const SegInfo*) L)->Name,
1688 ((const SegInfo*) R)->Name);
1693 /*****************************************************************************/
1695 /*****************************************************************************/
1699 static SpanInfo* NewSpanInfo (void)
1700 /* Create a new SpanInfo struct, intialize and return it */
1702 /* Allocate memory */
1703 SpanInfo* S = xmalloc (sizeof (SpanInfo));
1705 /* Initialize and return it */
1706 S->ScopeInfoList = 0;
1707 S->LineInfoList = 0;
1713 static void FreeSpanInfo (SpanInfo* S)
1714 /* Free a SpanInfo struct */
1716 CollFree (S->ScopeInfoList);
1717 CollFree (S->LineInfoList);
1723 static cc65_spaninfo* new_cc65_spaninfo (unsigned Count)
1724 /* Allocate and return a cc65_spaninfo struct that is able to hold Count
1725 ** entries. Initialize the count field of the returned struct.
1728 cc65_spaninfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1729 Count * sizeof (S->data[0]));
1736 static void CopySpanInfo (cc65_spandata* D, const SpanInfo* S)
1737 /* Copy data from a SpanInfo struct to a cc65_spandata struct */
1740 D->span_start = S->Start;
1741 D->span_end = S->End;
1742 D->segment_id = S->Seg.Info->Id;
1743 D->type_id = GetId (S->Type.Info);
1744 D->scope_count = CollCount (S->ScopeInfoList);
1745 D->line_count = CollCount (S->LineInfoList);
1750 static int CompareSpanInfoByAddr (const void* L, const void* R)
1751 /* Helper function to sort span infos in a collection by address. Span infos
1752 ** with smaller start address are considered smaller. If start addresses are
1753 ** equal, line spans with smaller end address are considered smaller. This
1754 ** means, that when CompareSpanInfoByAddr is used for sorting, a range with
1755 ** identical start addresses will have smaller spans first, followed by
1759 /* Sort by start of span */
1760 if (((const SpanInfo*) L)->Start > ((const SpanInfo*) R)->Start) {
1762 } else if (((const SpanInfo*) L)->Start < ((const SpanInfo*) R)->Start) {
1764 } else if (((const SpanInfo*) L)->End > ((const SpanInfo*) R)->End) {
1766 } else if (((const SpanInfo*) L)->End < ((const SpanInfo*) R)->End) {
1775 /*****************************************************************************/
1777 /*****************************************************************************/
1781 static SymInfo* NewSymInfo (const StrBuf* Name)
1782 /* Create a new SymInfo struct, intialize and return it */
1784 /* Allocate memory */
1785 SymInfo* S = xmalloc (sizeof (SymInfo) + SB_GetLen (Name));
1787 /* Initialize it as necessary */
1791 CollInit (&S->DefLineInfoList);
1792 CollInit (&S->RefLineInfoList);
1793 memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1801 static void FreeSymInfo (SymInfo* S)
1802 /* Free a SymInfo struct */
1804 CollFree (S->ImportList);
1805 CollFree (S->CheapLocals);
1806 CollDone (&S->DefLineInfoList);
1807 CollDone (&S->RefLineInfoList);
1813 static cc65_symbolinfo* new_cc65_symbolinfo (unsigned Count)
1814 /* Allocate and return a cc65_symbolinfo struct that is able to hold Count
1815 ** entries. Initialize the count field of the returned struct.
1818 cc65_symbolinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1819 Count * sizeof (S->data[0]));
1826 static void CopySymInfo (cc65_symboldata* D, const SymInfo* S)
1827 /* Copy data from a SymInfo struct to a cc65_symboldata struct */
1831 D->symbol_id = S->Id;
1832 D->symbol_name = S->Name;
1833 D->symbol_type = S->Type;
1834 D->symbol_size = S->Size;
1836 /* If this is an import, it doesn't have a value or segment. Use the data
1837 ** from the matching export instead.
1840 /* This is an import, because it has a matching export */
1841 D->export_id = S->Exp.Info->Id;
1842 D->symbol_value = S->Exp.Info->Value;
1843 Seg = S->Exp.Info->Seg.Info;
1845 D->export_id = CC65_INV_ID;
1846 D->symbol_value = S->Value;
1850 D->segment_id = Seg->Id;
1852 D->segment_id = CC65_INV_ID;
1854 D->scope_id = S->Scope.Info->Id;
1855 if (S->Parent.Info) {
1856 D->parent_id = S->Parent.Info->Id;
1858 D->parent_id = CC65_INV_ID;
1864 static int CompareSymInfoByName (const void* L, const void* R)
1865 /* Helper function to sort symbol infos in a collection by name */
1867 /* Sort by symbol name */
1868 return strcmp (((const SymInfo*) L)->Name,
1869 ((const SymInfo*) R)->Name);
1874 static int CompareSymInfoByVal (const void* L, const void* R)
1875 /* Helper function to sort symbol infos in a collection by value */
1877 /* Sort by symbol value. If both are equal, sort by symbol name so it
1878 ** looks nice when such a list is returned.
1880 if (((const SymInfo*) L)->Value > ((const SymInfo*) R)->Value) {
1882 } else if (((const SymInfo*) L)->Value < ((const SymInfo*) R)->Value) {
1885 return CompareSymInfoByName (L, R);
1891 /*****************************************************************************/
1893 /*****************************************************************************/
1897 /* The following definitions are actually just taken from gentype.h */
1899 /* Size of a data type */
1900 #define GT_SIZE_1 0x00U
1901 #define GT_SIZE_2 0x01U
1902 #define GT_SIZE_3 0x02U
1903 #define GT_SIZE_4 0x03U
1904 #define GT_SIZE_MASK 0x07U
1906 #define GT_GET_SIZE(x) (((x) & GT_SIZE_MASK) + 1U)
1908 /* Sign of the data type */
1909 #define GT_UNSIGNED 0x00U
1910 #define GT_SIGNED 0x08U
1911 #define GT_SIGN_MASK 0x08U
1913 #define GT_HAS_SIGN(x) (((x) & GT_SIZE_MASK) == GT_SIGNED)
1916 #define GT_LITTLE_ENDIAN 0x00U
1917 #define GT_BIG_ENDIAN 0x10U
1918 #define GT_BYTEORDER_MASK 0x10U
1920 #define GT_IS_LITTLE_ENDIAN(x) (((x) & GT_BYTEORDER_MASK) == GT_LITTLE_ENDIAN)
1921 #define GT_IS_BIG_ENDIAN(x) (((x) & GT_BYTEORDER_MASK) == GT_BIG_ENDIAN)
1923 /* Type of the data. */
1924 #define GT_TYPE_VOID 0x00U
1925 #define GT_TYPE_INT 0x20U
1926 #define GT_TYPE_PTR 0x40U
1927 #define GT_TYPE_FLOAT 0x60U
1928 #define GT_TYPE_ARRAY 0x80U
1929 #define GT_TYPE_FUNC 0xA0U
1930 #define GT_TYPE_STRUCT 0xC0U
1931 #define GT_TYPE_UNION 0xE0U
1932 #define GT_TYPE_MASK 0xE0U
1934 #define GT_GET_TYPE(x) ((x) & GT_TYPE_MASK)
1935 #define GT_IS_INTEGER(x) (GT_GET_TYPE(x) == GT_TYPE_INTEGER)
1936 #define GT_IS_POINTER(x) (GT_GET_TYPE(x) == GT_TYPE_POINTER)
1937 #define GT_IS_FLOAT(x) (GT_GET_TYPE(x) == GT_TYPE_FLOAT)
1938 #define GT_IS_ARRAY(x) (GT_GET_TYPE(x) == GT_TYPE_ARRAY)
1939 #define GT_IS_FUNCTION(x) (GT_GET_TYPE(x) == GT_TYPE_FUNCTION)
1940 #define GT_IS_STRUCT(x) (GT_GET_TYPE(x) == GT_TYPE_STRUCT)
1941 #define GT_IS_UNION(x) (GT_GET_TYPE(x) == GT_TYPE_UNION)
1943 /* Combined values for the 6502 family */
1944 #define GT_VOID (GT_TYPE_VOID)
1945 #define GT_BYTE (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_1)
1946 #define GT_WORD (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_2)
1947 #define GT_DWORD (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_4)
1948 #define GT_DBYTE (GT_TYPE_PTR | GT_BIG_ENDIAN | GT_UNSIGNED | GT_SIZE_2)
1949 #define GT_PTR (GT_TYPE_PTR | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_2)
1950 #define GT_FAR_PTR (GT_TYPE_PTR | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_3)
1951 #define GT_ARRAY(size) (GT_TYPE_ARRAY | ((size) - 1))
1955 static void FreeTypeInfo (TypeInfo* T)
1956 /* Free a TypeInfo struct */
1963 static void InitTypeParseData (TypeParseData* P, const StrBuf* Type,
1965 /* Initialize a TypeParseData structure */
1967 P->Info = xmalloc (sizeof (*P->Info) - sizeof (P->Info->Data[0]) +
1968 ItemCount * sizeof (P->Info->Data[0]));
1969 P->ItemCount = ItemCount;
1971 P->ItemData = P->Info->Data;
1979 static cc65_typedata* TypeFromString (TypeParseData* P)
1980 /* Parse a type string and return a set of typedata structures. Will be called
1981 ** recursively. Will set P->Error and return NULL in case of problems.
1984 cc65_typedata* Data;
1989 /* Allocate a new entry */
1990 if (P->ItemIndex >= P->ItemCount) {
1994 Data = &P->ItemData[P->ItemIndex++];
1996 /* Assume no following node */
1999 /* Get the next char, then skip it */
2000 if (P->Pos >= SB_GetLen (P->Type)) {
2004 B = SB_At (P->Type, P->Pos++);
2008 /* We only handle those that are currently in use */
2010 Data->what = CC65_TYPE_VOID;
2015 Data->what = CC65_TYPE_BYTE;
2016 Data->size = GT_GET_SIZE (B);
2020 Data->what = CC65_TYPE_WORD;
2021 Data->size = GT_GET_SIZE (B);
2025 Data->what = CC65_TYPE_DWORD;
2026 Data->size = GT_GET_SIZE (B);
2030 Data->what = CC65_TYPE_DBYTE;
2031 Data->size = GT_GET_SIZE (B);
2035 Data->what = CC65_TYPE_PTR;
2036 Data->data.ptr.ind_type = TypeFromString (P);
2037 Data->size = GT_GET_SIZE (B);
2041 Data->what = CC65_TYPE_FARPTR;
2042 Data->data.ptr.ind_type = TypeFromString (P);
2043 Data->size = GT_GET_SIZE (B);
2047 if (GT_GET_TYPE (B) == GT_TYPE_ARRAY) {
2049 I = GT_GET_SIZE (B);
2050 if (I == 0 || I > 4) {
2055 if (P->Pos > SB_GetLen (P->Type)) {
2061 Count |= (unsigned char) SB_At (P->Type, P->Pos - I);
2064 Data->what = CC65_TYPE_ARRAY;
2065 Data->data.array.ele_count = Count;
2066 Data->data.array.ele_type = TypeFromString (P);
2068 Data->size = Data->data.array.ele_count *
2069 Data->data.array.ele_type->size;
2078 /* Return our structure or NULL in case of errors */
2079 return P->Error? 0 : Data;
2085 static TypeInfo* ParseTypeString (InputData* D, StrBuf* Type)
2086 /* Check if the string T contains a valid type string. Convert it from readable
2087 ** to binary. Calculate how many cc65_typedata structures are necessary when it
2088 ** is converted. Convert the string into a set of cc65_typedata structures and
2099 /* The length must not be zero and divideable by two */
2100 unsigned Length = SB_GetLen (Type);
2101 if (Length < 2 || (Length & 0x01) != 0) {
2102 ParseError (D, CC65_ERROR, "Type value has invalid length");
2106 /* The string must consist completely of hex digit chars */
2107 A = SB_GetConstBuf (Type);
2108 for (I = 0; I < Length; ++I) {
2109 if (!isxdigit (A[I])) {
2110 ParseError (D, CC65_ERROR, "Type value contains invalid characters");
2115 /* Convert the type to binary */
2116 B = SB_GetBuf (Type);
2117 while (A < SB_GetConstBuf (Type) + Length) {
2118 /* Since we know, there are only hex digits, there can't be any errors */
2119 *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]);
2122 Type->Len = (Length /= 2);
2124 /* Get a pointer to the type data, then count the number of cc65_typedata
2127 A = SB_GetConstBuf (Type);
2130 while (I < Length) {
2132 /* We only handle those that are currently in use */
2145 if (GT_GET_TYPE (A[I]) == GT_TYPE_ARRAY) {
2147 I += GT_GET_SIZE (A[I]) + 1;
2149 /* Unknown type in type string */
2150 ParseError (D, CC65_ERROR, "Unkown type in type value");
2157 /* Check that we're even */
2159 ParseError (D, CC65_ERROR, "Syntax error in type in type value");
2163 /* Initialize the data structure for parsing the type string */
2164 InitTypeParseData (&P, Type, Count);
2166 /* Parse the type string and check for errors */
2167 if (TypeFromString (&P) == 0 || P.ItemCount != P.ItemIndex) {
2168 ParseError (D, CC65_ERROR, "Error parsing the type value");
2169 FreeTypeInfo (P.Info);
2173 /* Return the result of the parse operation */
2179 /*****************************************************************************/
2181 /*****************************************************************************/
2185 static void InitSpanInfoList (SpanInfoList* L)
2186 /* Initialize a span info list */
2194 static void CreateSpanInfoList (SpanInfoList* L, Collection* SpanInfos)
2195 /* Create a SpanInfoList from a Collection with span infos. The collection
2196 ** must be sorted by ascending start addresses.
2201 SpanInfoListEntry* List;
2202 unsigned StartIndex;
2207 /* Initialize and check if there's something to do */
2210 if (CollCount (SpanInfos) == 0) {
2215 /* Step 1: Determine the number of unique address entries needed */
2216 S = CollAt (SpanInfos, 0);
2217 L->Count += (S->End - S->Start) + 1;
2219 for (I = 1; I < CollCount (SpanInfos); ++I) {
2221 /* Get next entry */
2222 S = CollAt (SpanInfos, I);
2224 /* Check for additional unique addresses in this span info */
2225 if (S->Start > End) {
2226 L->Count += (S->End - S->Start) + 1;
2228 } else if (S->End > End) {
2229 L->Count += (S->End - End);
2235 /* Step 2: Allocate memory and initialize it */
2236 L->List = List = xmalloc (L->Count * sizeof (*List));
2237 for (I = 0; I < L->Count; ++I) {
2242 /* Step 3: Determine the number of entries per unique address */
2244 S = CollAt (SpanInfos, 0);
2248 for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2249 List[J].Addr = Addr;
2252 for (I = 1; I < CollCount (SpanInfos); ++I) {
2254 /* Get next entry */
2255 S = CollAt (SpanInfos, I);
2257 /* Determine the start index of the next range. Line infos are sorted
2258 ** by ascending start address, so the start address of the next entry
2259 ** is always larger than the previous one - we don't need to check
2262 if (S->Start <= End) {
2263 /* Range starts within out already known linear range */
2264 StartIndex += (unsigned) (S->Start - Start);
2270 /* Range starts after the already known */
2271 StartIndex += (unsigned) (End - Start) + 1;
2275 for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2276 List[J].Addr = Addr;
2281 /* Step 4: Allocate memory for the indirect tables */
2282 for (I = 0, List = L->List; I < L->Count; ++I, ++List) {
2284 /* For a count of 1, we store the pointer to the lineinfo for this
2285 ** address in the Data pointer directly. For counts > 1, we allocate
2286 ** an array of pointers and reset the counter, so we can use it as
2287 ** an index later. This is dangerous programming since it disables
2288 ** all possible checks!
2290 if (List->Count > 1) {
2291 List->Data = xmalloc (List->Count * sizeof (SpanInfo*));
2296 /* Step 5: Enter the data into the table */
2298 S = CollAt (SpanInfos, 0);
2302 for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2303 assert (List[J].Addr == Addr);
2304 if (List[J].Count == 1 && List[J].Data == 0) {
2307 ((SpanInfo**) List[J].Data)[List[J].Count++] = S;
2310 for (I = 1; I < CollCount (SpanInfos); ++I) {
2312 /* Get next entry */
2313 S = CollAt (SpanInfos, I);
2315 /* Determine the start index of the next range. Line infos are sorted
2316 ** by ascending start address, so the start address of the next entry
2317 ** is always larger than the previous one - we don't need to check
2320 if (S->Start <= End) {
2321 /* Range starts within out already known linear range */
2322 StartIndex += (unsigned) (S->Start - Start);
2328 /* Range starts after the already known */
2329 StartIndex += (unsigned) (End - Start) + 1;
2333 for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2334 assert (List[J].Addr == Addr);
2335 if (List[J].Count == 1 && List[J].Data == 0) {
2338 ((SpanInfo**) List[J].Data)[List[J].Count++] = S;
2346 static void DoneSpanInfoList (SpanInfoList* L)
2347 /* Delete the contents of a span info list */
2351 /* Delete the span info and the indirect data */
2352 for (I = 0; I < L->Count; ++I) {
2354 /* Get a pointer to the entry */
2355 SpanInfoListEntry* E = &L->List[I];
2357 /* Check for indirect memory */
2359 /* SpanInfo addressed indirectly */
2364 /* Delete the list */
2370 /*****************************************************************************/
2372 /*****************************************************************************/
2376 static DbgInfo* NewDbgInfo (const char* FileName)
2377 /* Create a new DbgInfo struct and return it */
2379 /* Get the length of the name */
2380 unsigned Len = strlen (FileName);
2382 /* Allocate memory */
2383 DbgInfo* Info = xmalloc (sizeof (DbgInfo) + Len);
2386 CollInit (&Info->CSymInfoById);
2387 CollInit (&Info->FileInfoById);
2388 CollInit (&Info->LibInfoById);
2389 CollInit (&Info->LineInfoById);
2390 CollInit (&Info->ModInfoById);
2391 CollInit (&Info->ScopeInfoById);
2392 CollInit (&Info->SegInfoById);
2393 CollInit (&Info->SpanInfoById);
2394 CollInit (&Info->SymInfoById);
2395 CollInit (&Info->TypeInfoById);
2397 CollInit (&Info->CSymFuncByName);
2398 CollInit (&Info->FileInfoByName);
2399 CollInit (&Info->ModInfoByName);
2400 CollInit (&Info->ScopeInfoByName);
2401 CollInit (&Info->SegInfoByName);
2402 CollInit (&Info->SymInfoByName);
2403 CollInit (&Info->SymInfoByVal);
2405 InitSpanInfoList (&Info->SpanInfoByAddr);
2408 Info->MajorVersion = 0;
2409 Info->MinorVersion = 0;
2410 memcpy (&Info->FileName, FileName, Len+1);
2418 static void FreeDbgInfo (DbgInfo* Info)
2419 /* Free a DbgInfo struct */
2423 /* First, free the items in the collections */
2424 for (I = 0; I < CollCount (&Info->CSymInfoById); ++I) {
2425 FreeCSymInfo (CollAt (&Info->CSymInfoById, I));
2427 for (I = 0; I < CollCount (&Info->FileInfoById); ++I) {
2428 FreeFileInfo (CollAt (&Info->FileInfoById, I));
2430 for (I = 0; I < CollCount (&Info->LibInfoById); ++I) {
2431 FreeLibInfo (CollAt (&Info->LibInfoById, I));
2433 for (I = 0; I < CollCount (&Info->LineInfoById); ++I) {
2434 FreeLineInfo (CollAt (&Info->LineInfoById, I));
2436 for (I = 0; I < CollCount (&Info->ModInfoById); ++I) {
2437 FreeModInfo (CollAt (&Info->ModInfoById, I));
2439 for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) {
2440 FreeScopeInfo (CollAt (&Info->ScopeInfoById, I));
2442 for (I = 0; I < CollCount (&Info->SegInfoById); ++I) {
2443 FreeSegInfo (CollAt (&Info->SegInfoById, I));
2445 for (I = 0; I < CollCount (&Info->SpanInfoById); ++I) {
2446 FreeSpanInfo (CollAt (&Info->SpanInfoById, I));
2448 for (I = 0; I < CollCount (&Info->SymInfoById); ++I) {
2449 FreeSymInfo (CollAt (&Info->SymInfoById, I));
2451 for (I = 0; I < CollCount (&Info->TypeInfoById); ++I) {
2452 FreeTypeInfo (CollAt (&Info->TypeInfoById, I));
2455 /* Free the memory used by the id collections */
2456 CollDone (&Info->CSymInfoById);
2457 CollDone (&Info->FileInfoById);
2458 CollDone (&Info->LibInfoById);
2459 CollDone (&Info->LineInfoById);
2460 CollDone (&Info->ModInfoById);
2461 CollDone (&Info->ScopeInfoById);
2462 CollDone (&Info->SegInfoById);
2463 CollDone (&Info->SpanInfoById);
2464 CollDone (&Info->SymInfoById);
2465 CollDone (&Info->TypeInfoById);
2467 /* Free the memory used by the other collections */
2468 CollDone (&Info->CSymFuncByName);
2469 CollDone (&Info->FileInfoByName);
2470 CollDone (&Info->ModInfoByName);
2471 CollDone (&Info->ScopeInfoByName);
2472 CollDone (&Info->SegInfoByName);
2473 CollDone (&Info->SymInfoByName);
2474 CollDone (&Info->SymInfoByVal);
2476 /* Free span info */
2477 DoneSpanInfoList (&Info->SpanInfoByAddr);
2479 /* Free the structure itself */
2485 /*****************************************************************************/
2486 /* Scanner and parser */
2487 /*****************************************************************************/
2491 static int DigitVal (int C)
2492 /* Return the value for a numeric digit. Return -1 if C is invalid */
2496 } else if (isxdigit (C)) {
2497 return toupper (C) - 'A' + 10;
2505 static void NextChar (InputData* D)
2506 /* Read the next character from the input. Count lines and columns */
2508 /* Check if we've encountered EOF before */
2514 D->C = fgetc (D->F);
2521 static void NextToken (InputData* D)
2522 /* Read the next token from the input stream */
2524 static const struct KeywordEntry {
2525 const char Keyword[12];
2527 } KeywordTable[] = {
2528 { "abs", TOK_ABSOLUTE },
2529 { "addrsize", TOK_ADDRSIZE },
2530 { "auto", TOK_AUTO },
2531 { "count", TOK_COUNT },
2532 { "csym", TOK_CSYM },
2534 { "enum", TOK_ENUM },
2535 { "equ", TOK_EQUATE },
2536 { "exp", TOK_EXPORT },
2537 { "ext", TOK_EXTERN },
2538 { "file", TOK_FILE },
2539 { "func", TOK_FUNC },
2540 { "global", TOK_GLOBAL },
2542 { "imp", TOK_IMPORT },
2543 { "info", TOK_INFO },
2544 { "lab", TOK_LABEL },
2545 { "lib", TOK_LIBRARY },
2546 { "line", TOK_LINE },
2547 { "long", TOK_LONG },
2548 { "major", TOK_MAJOR },
2549 { "minor", TOK_MINOR },
2550 { "mod", TOK_MODULE },
2551 { "mtime", TOK_MTIME },
2552 { "name", TOK_NAME },
2553 { "offs", TOK_OFFS },
2554 { "oname", TOK_OUTPUTNAME },
2555 { "ooffs", TOK_OUTPUTOFFS },
2556 { "parent", TOK_PARENT },
2558 { "reg", TOK_REGISTER },
2562 { "scope", TOK_SCOPE },
2563 { "seg", TOK_SEGMENT },
2564 { "size", TOK_SIZE },
2565 { "span", TOK_SPAN },
2566 { "start", TOK_START },
2567 { "static", TOK_STATIC },
2568 { "struct", TOK_STRUCT },
2570 { "type", TOK_TYPE },
2571 { "val", TOK_VALUE },
2573 { "version", TOK_VERSION },
2574 { "zp", TOK_ZEROPAGE },
2578 /* Skip whitespace */
2579 while (D->C == ' ' || D->C == '\t' || D->C == '\r') {
2583 /* Remember the current position as start of the next token */
2588 if (D->C == '_' || isalpha (D->C)) {
2590 const struct KeywordEntry* Entry;
2592 /* Read the identifier */
2593 SB_Clear (&D->SVal);
2594 while (D->C == '_' || isalnum (D->C)) {
2595 SB_AppendChar (&D->SVal, D->C);
2598 SB_Terminate (&D->SVal);
2600 /* Search the identifier in the keyword table */
2601 Entry = bsearch (SB_GetConstBuf (&D->SVal),
2603 sizeof (KeywordTable) / sizeof (KeywordTable[0]),
2604 sizeof (KeywordTable[0]),
2605 (int (*)(const void*, const void*)) strcmp);
2609 D->Tok = Entry->Tok;
2615 if (isdigit (D->C)) {
2620 if (toupper (D->C) == 'X') {
2630 while ((Val = DigitVal (D->C)) >= 0 && Val < Base) {
2631 D->IVal = D->IVal * Base + Val;
2634 D->Tok = TOK_INTCON;
2638 /* Other characters */
2662 SB_Clear (&D->SVal);
2665 if (D->C == '\n' || D->C == EOF) {
2666 ParseError (D, CC65_ERROR, "Unterminated string constant");
2673 SB_AppendChar (&D->SVal, D->C);
2676 SB_Terminate (&D->SVal);
2677 D->Tok = TOK_STRCON;
2690 ParseError (D, CC65_ERROR, "Invalid input character `%c'", D->C);
2697 static int TokenIsKeyword (Token Tok)
2698 /* Return true if the given token is a keyword */
2700 return (Tok >= TOK_FIRST_KEYWORD && Tok <= TOK_LAST_KEYWORD);
2705 static int TokenFollows (InputData* D, Token Tok, const char* Name)
2706 /* Check for a specific token that follows. */
2708 if (D->Tok != Tok) {
2709 ParseError (D, CC65_ERROR, "%s expected", Name);
2719 static int IntConstFollows (InputData* D)
2720 /* Check for an integer constant */
2722 return TokenFollows (D, TOK_INTCON, "Integer constant");
2727 static int StrConstFollows (InputData* D)
2728 /* Check for a string literal */
2730 return TokenFollows (D, TOK_STRCON, "String literal");
2735 static int Consume (InputData* D, Token Tok, const char* Name)
2736 /* Check for a token and consume it. Return true if the token was comsumed,
2737 ** return false otherwise.
2740 if (TokenFollows (D, Tok, Name)) {
2750 static int ConsumeEqual (InputData* D)
2751 /* Consume an equal sign */
2753 return Consume (D, TOK_EQUAL, "'='");
2758 static void ConsumeEOL (InputData* D)
2759 /* Consume an end-of-line token, if we aren't at end-of-file */
2761 if (D->Tok != TOK_EOF) {
2762 if (D->Tok != TOK_EOL) {
2763 ParseError (D, CC65_ERROR, "Extra tokens in line");
2772 static void ParseCSym (InputData* D)
2773 /* Parse a CSYM line */
2775 /* Most of the following variables are initialized with a value that is
2776 ** overwritten later. This is just to avoid compiler warnings.
2779 StrBuf Name = STRBUF_INITIALIZER;
2781 cc65_csym_sc SC = CC65_CSYM_AUTO;
2782 unsigned ScopeId = 0;
2783 unsigned SymId = CC65_INV_ID;
2784 unsigned TypeId = CC65_INV_ID;
2797 ibRequired = ibId | ibName | ibSC | ibScopeId | ibType,
2798 } InfoBits = ibNone;
2800 /* Skip the CSYM token */
2803 /* More stuff follows */
2808 /* Something we know? */
2809 if (D->Tok != TOK_ID && D->Tok != TOK_NAME &&
2810 D->Tok != TOK_OFFS && D->Tok != TOK_SC &&
2811 D->Tok != TOK_SCOPE && D->Tok != TOK_SYM &&
2812 D->Tok != TOK_TYPE) {
2814 /* Try smart error recovery */
2815 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
2824 /* Remember the token, skip it, check for equal */
2827 if (!ConsumeEqual (D)) {
2831 /* Check what the token was */
2835 if (!IntConstFollows (D)) {
2844 if (!StrConstFollows (D)) {
2847 SB_Copy (&Name, &D->SVal);
2848 SB_Terminate (&Name);
2855 if (D->Tok == TOK_MINUS) {
2859 if (!IntConstFollows (D)) {
2862 Offs *= (int) D->IVal;
2869 case TOK_AUTO: SC = CC65_CSYM_AUTO; break;
2870 case TOK_EXTERN: SC = CC65_CSYM_EXTERN; break;
2871 case TOK_REGISTER: SC = CC65_CSYM_REG; break;
2872 case TOK_STATIC: SC = CC65_CSYM_STATIC; break;
2874 ParseError (D, CC65_ERROR, "Invalid storage class token");
2882 if (!IntConstFollows (D)) {
2887 InfoBits |= ibScopeId;
2891 if (!IntConstFollows (D)) {
2896 InfoBits |= ibSymId;
2900 if (!IntConstFollows (D)) {
2910 UnexpectedToken (D);
2916 if (D->Tok != TOK_COMMA) {
2922 /* Check for end of line */
2923 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
2924 UnexpectedToken (D);
2929 /* Check for required and/or matched information */
2930 if ((InfoBits & ibRequired) != ibRequired) {
2931 ParseError (D, CC65_ERROR, "Required attributes missing");
2935 /* Symbol only valid if storage class not auto */
2936 if (((InfoBits & ibSymId) != 0) && (SC == CC65_CSYM_AUTO)) {
2937 ParseError (D, CC65_ERROR, "Only non auto symbols can have a symbol attached");
2941 /* Create the symbol info */
2942 S = NewCSymInfo (&Name);
2944 S->Kind = CC65_CSYM_VAR;
2948 S->Type.Id = TypeId;
2949 S->Scope.Id = ScopeId;
2952 CollReplaceExpand (&D->Info->CSymInfoById, S, Id);
2955 /* Entry point in case of errors */
2962 static void ParseFile (InputData* D)
2963 /* Parse a FILE line */
2966 unsigned long Size = 0;
2967 unsigned long MTime = 0;
2968 Collection ModIds = COLLECTION_INITIALIZER;
2969 StrBuf Name = STRBUF_INITIALIZER;
2978 ibRequired = ibId | ibName | ibSize | ibMTime | ibModId,
2979 } InfoBits = ibNone;
2981 /* Skip the FILE token */
2984 /* More stuff follows */
2989 /* Something we know? */
2990 if (D->Tok != TOK_ID && D->Tok != TOK_MODULE &&
2991 D->Tok != TOK_MTIME && D->Tok != TOK_NAME &&
2992 D->Tok != TOK_SIZE) {
2994 /* Try smart error recovery */
2995 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3004 /* Remember the token, skip it, check for equal */
3007 if (!ConsumeEqual (D)) {
3011 /* Check what the token was */
3015 if (!IntConstFollows (D)) {
3024 if (!IntConstFollows (D)) {
3029 InfoBits |= ibMTime;
3034 if (!IntConstFollows (D)) {
3037 CollAppendId (&ModIds, (unsigned) D->IVal);
3039 if (D->Tok != TOK_PLUS) {
3044 InfoBits |= ibModId;
3048 if (!StrConstFollows (D)) {
3051 SB_Copy (&Name, &D->SVal);
3052 SB_Terminate (&Name);
3058 if (!IntConstFollows (D)) {
3068 UnexpectedToken (D);
3074 if (D->Tok != TOK_COMMA) {
3080 /* Check for end of line */
3081 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3082 UnexpectedToken (D);
3087 /* Check for required information */
3088 if ((InfoBits & ibRequired) != ibRequired) {
3089 ParseError (D, CC65_ERROR, "Required attributes missing");
3093 /* Create the file info and remember it */
3094 F = NewFileInfo (&Name);
3098 CollMove (&ModIds, &F->ModInfoByName);
3099 CollReplaceExpand (&D->Info->FileInfoById, F, Id);
3100 CollAppend (&D->Info->FileInfoByName, F);
3103 /* Entry point in case of errors */
3111 static void ParseInfo (InputData* D)
3112 /* Parse an INFO line */
3114 /* Skip the INFO token */
3117 /* More stuff follows */
3122 /* Something we know? */
3123 if (D->Tok != TOK_CSYM && D->Tok != TOK_FILE &&
3124 D->Tok != TOK_LIBRARY && D->Tok != TOK_LINE &&
3125 D->Tok != TOK_MODULE && D->Tok != TOK_SCOPE &&
3126 D->Tok != TOK_SEGMENT && D->Tok != TOK_SPAN &&
3127 D->Tok != TOK_SYM && D->Tok != TOK_TYPE) {
3129 /* Try smart error recovery */
3130 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3139 /* Remember the token, skip it, check for equal, check for an integer
3144 if (!ConsumeEqual (D)) {
3147 if (!IntConstFollows (D)) {
3151 /* Check what the token was */
3155 CollGrow (&D->Info->CSymInfoById, D->IVal);
3159 CollGrow (&D->Info->FileInfoById, D->IVal);
3160 CollGrow (&D->Info->FileInfoByName, D->IVal);
3164 CollGrow (&D->Info->LibInfoById, D->IVal);
3168 CollGrow (&D->Info->LineInfoById, D->IVal);
3172 CollGrow (&D->Info->ModInfoById, D->IVal);
3173 CollGrow (&D->Info->ModInfoByName, D->IVal);
3177 CollGrow (&D->Info->ScopeInfoById, D->IVal);
3178 CollGrow (&D->Info->ScopeInfoByName, D->IVal);
3182 CollGrow (&D->Info->SegInfoById, D->IVal);
3183 CollGrow (&D->Info->SegInfoByName, D->IVal);
3187 CollGrow (&D->Info->SpanInfoById, D->IVal);
3191 CollGrow (&D->Info->SymInfoById, D->IVal);
3192 CollGrow (&D->Info->SymInfoByName, D->IVal);
3193 CollGrow (&D->Info->SymInfoByVal, D->IVal);
3197 CollGrow (&D->Info->TypeInfoById, D->IVal);
3202 UnexpectedToken (D);
3207 /* Skip the number */
3211 if (D->Tok != TOK_COMMA) {
3217 /* Check for end of line */
3218 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3219 UnexpectedToken (D);
3225 /* Entry point in case of errors */
3231 static void ParseLibrary (InputData* D)
3232 /* Parse a LIBRARY line */
3235 StrBuf Name = STRBUF_INITIALIZER;
3241 ibRequired = ibId | ibName,
3242 } InfoBits = ibNone;
3244 /* Skip the LIBRARY token */
3247 /* More stuff follows */
3252 /* Something we know? */
3253 if (D->Tok != TOK_ID && D->Tok != TOK_NAME) {
3255 /* Try smart error recovery */
3256 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3265 /* Remember the token, skip it, check for equal */
3268 if (!ConsumeEqual (D)) {
3272 /* Check what the token was */
3276 if (!IntConstFollows (D)) {
3285 if (!StrConstFollows (D)) {
3288 SB_Copy (&Name, &D->SVal);
3289 SB_Terminate (&Name);
3296 UnexpectedToken (D);
3302 if (D->Tok != TOK_COMMA) {
3308 /* Check for end of line */
3309 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3310 UnexpectedToken (D);
3315 /* Check for required information */
3316 if ((InfoBits & ibRequired) != ibRequired) {
3317 ParseError (D, CC65_ERROR, "Required attributes missing");
3321 /* Create the library info and remember it */
3322 L = NewLibInfo (&Name);
3324 CollReplaceExpand (&D->Info->LibInfoById, L, Id);
3327 /* Entry point in case of errors */
3334 static void ParseLine (InputData* D)
3335 /* Parse a LINE line */
3337 unsigned Id = CC65_INV_ID;
3338 unsigned FileId = CC65_INV_ID;
3339 Collection SpanIds = COLLECTION_INITIALIZER;
3341 cc65_line_type Type = CC65_LINE_ASM;
3354 ibRequired = ibFileId | ibId | ibLine,
3355 } InfoBits = ibNone;
3357 /* Skip the LINE token */
3360 /* More stuff follows */
3365 /* Something we know? */
3366 if (D->Tok != TOK_COUNT && D->Tok != TOK_FILE &&
3367 D->Tok != TOK_ID && D->Tok != TOK_LINE &&
3368 D->Tok != TOK_SPAN && D->Tok != TOK_TYPE) {
3370 /* Try smart error recovery */
3371 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3380 /* Remember the token, skip it, check for equal */
3383 if (!ConsumeEqual (D)) {
3387 /* Check what the token was */
3391 if (!IntConstFollows (D)) {
3395 InfoBits |= ibFileId;
3400 if (!IntConstFollows (D)) {
3409 if (!IntConstFollows (D)) {
3412 Line = (cc65_line) D->IVal;
3419 if (!IntConstFollows (D)) {
3422 CollAppendId (&SpanIds, (unsigned) D->IVal);
3424 if (D->Tok != TOK_PLUS) {
3429 InfoBits |= ibSpanId;
3433 if (!IntConstFollows (D)) {
3436 Type = (cc65_line_type) D->IVal;
3442 if (!IntConstFollows (D)) {
3446 InfoBits |= ibCount;
3452 UnexpectedToken (D);
3458 if (D->Tok != TOK_COMMA) {
3464 /* Check for end of line */
3465 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3466 UnexpectedToken (D);
3471 /* Check for required information */
3472 if ((InfoBits & ibRequired) != ibRequired) {
3473 ParseError (D, CC65_ERROR, "Required attributes missing");
3477 /* Create the line info and remember it */
3481 L->File.Id = FileId;
3484 CollMove (&SpanIds, &L->SpanInfoList);
3485 CollReplaceExpand (&D->Info->LineInfoById, L, Id);
3488 /* Entry point in case of errors */
3489 CollDone (&SpanIds);
3495 static void ParseModule (InputData* D)
3496 /* Parse a MODULE line */
3498 /* Most of the following variables are initialized with a value that is
3499 ** overwritten later. This is just to avoid compiler warnings.
3501 unsigned Id = CC65_INV_ID;
3502 StrBuf Name = STRBUF_INITIALIZER;
3503 unsigned FileId = CC65_INV_ID;
3504 unsigned LibId = CC65_INV_ID;
3514 ibRequired = ibId | ibName | ibFileId,
3515 } InfoBits = ibNone;
3517 /* Skip the MODULE token */
3520 /* More stuff follows */
3525 /* Something we know? */
3526 if (D->Tok != TOK_FILE && D->Tok != TOK_ID &&
3527 D->Tok != TOK_NAME && D->Tok != TOK_LIBRARY) {
3529 /* Try smart error recovery */
3530 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3539 /* Remember the token, skip it, check for equal */
3542 if (!ConsumeEqual (D)) {
3546 /* Check what the token was */
3550 if (!IntConstFollows (D)) {
3554 InfoBits |= ibFileId;
3559 if (!IntConstFollows (D)) {
3568 if (!StrConstFollows (D)) {
3571 SB_Copy (&Name, &D->SVal);
3572 SB_Terminate (&Name);
3578 if (!IntConstFollows (D)) {
3582 InfoBits |= ibLibId;
3588 UnexpectedToken (D);
3594 if (D->Tok != TOK_COMMA) {
3600 /* Check for end of line */
3601 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3602 UnexpectedToken (D);
3607 /* Check for required and/or matched information */
3608 if ((InfoBits & ibRequired) != ibRequired) {
3609 ParseError (D, CC65_ERROR, "Required attributes missing");
3613 /* Create the scope info */
3614 M = NewModInfo (&Name);
3615 M->File.Id = FileId;
3619 /* ... and remember it */
3620 CollReplaceExpand (&D->Info->ModInfoById, M, Id);
3621 CollAppend (&D->Info->ModInfoByName, M);
3624 /* Entry point in case of errors */
3631 static void ParseScope (InputData* D)
3632 /* Parse a SCOPE line */
3634 /* Most of the following variables are initialized with a value that is
3635 ** overwritten later. This is just to avoid compiler warnings.
3637 unsigned Id = CC65_INV_ID;
3638 cc65_scope_type Type = CC65_SCOPE_MODULE;
3640 StrBuf Name = STRBUF_INITIALIZER;
3641 unsigned ModId = CC65_INV_ID;
3642 unsigned ParentId = CC65_INV_ID;
3643 Collection SpanIds = COLLECTION_INITIALIZER;
3644 unsigned SymId = CC65_INV_ID;
3658 ibRequired = ibId | ibModId | ibName,
3659 } InfoBits = ibNone;
3661 /* Skip the SCOPE token */
3664 /* More stuff follows */
3669 /* Something we know? */
3670 if (D->Tok != TOK_ID && D->Tok != TOK_MODULE &&
3671 D->Tok != TOK_NAME && D->Tok != TOK_PARENT &&
3672 D->Tok != TOK_SIZE && D->Tok != TOK_SPAN &&
3673 D->Tok != TOK_SYM && D->Tok != TOK_TYPE) {
3675 /* Try smart error recovery */
3676 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3685 /* Remember the token, skip it, check for equal */
3688 if (!ConsumeEqual (D)) {
3692 /* Check what the token was */
3696 if (!IntConstFollows (D)) {
3705 if (!IntConstFollows (D)) {
3709 InfoBits |= ibModId;
3714 if (!StrConstFollows (D)) {
3717 SB_Copy (&Name, &D->SVal);
3718 SB_Terminate (&Name);
3724 if (!IntConstFollows (D)) {
3729 InfoBits |= ibParentId;
3733 if (!IntConstFollows (D)) {
3736 Size = (cc65_size) D->IVal;
3743 if (!IntConstFollows (D)) {
3746 CollAppendId (&SpanIds, (unsigned) D->IVal);
3748 if (D->Tok != TOK_PLUS) {
3753 InfoBits |= ibSpanId;
3757 if (!IntConstFollows (D)) {
3762 InfoBits |= ibSymId;
3767 case TOK_GLOBAL: Type = CC65_SCOPE_GLOBAL; break;
3768 case TOK_FILE: Type = CC65_SCOPE_MODULE; break;
3769 case TOK_SCOPE: Type = CC65_SCOPE_SCOPE; break;
3770 case TOK_STRUCT: Type = CC65_SCOPE_STRUCT; break;
3771 case TOK_ENUM: Type = CC65_SCOPE_ENUM; break;
3773 ParseError (D, CC65_ERROR,
3774 "Unknown value for attribute \"type\"");
3784 UnexpectedToken (D);
3790 if (D->Tok != TOK_COMMA) {
3796 /* Check for end of line */
3797 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3798 UnexpectedToken (D);
3803 /* Check for required and/or matched information */
3804 if ((InfoBits & ibRequired) != ibRequired) {
3805 ParseError (D, CC65_ERROR, "Required attributes missing");
3809 /* Create the scope info ... */
3810 S = NewScopeInfo (&Name);
3815 S->Parent.Id = ParentId;
3816 S->Label.Id = SymId;
3817 CollMove (&SpanIds, &S->SpanInfoList);
3819 /* ... and remember it */
3820 CollReplaceExpand (&D->Info->ScopeInfoById, S, Id);
3821 CollAppend (&D->Info->ScopeInfoByName, S);
3824 /* Entry point in case of errors */
3825 CollDone (&SpanIds);
3832 static void ParseSegment (InputData* D)
3833 /* Parse a SEGMENT line */
3836 cc65_addr Start = 0;
3838 StrBuf Name = STRBUF_INITIALIZER;
3839 StrBuf OutputName = STRBUF_INITIALIZER;
3840 unsigned long OutputOffs = 0;
3847 ibOutputName= 0x004,
3848 ibOutputOffs= 0x008,
3854 ibRequired = ibId | ibName | ibStart | ibSize | ibAddrSize | ibType,
3855 } InfoBits = ibNone;
3857 /* Skip the SEGMENT token */
3860 /* More stuff follows */
3865 /* Something we know? */
3866 if (D->Tok != TOK_ADDRSIZE && D->Tok != TOK_ID &&
3867 D->Tok != TOK_NAME && D->Tok != TOK_OUTPUTNAME &&
3868 D->Tok != TOK_OUTPUTOFFS && D->Tok != TOK_SIZE &&
3869 D->Tok != TOK_START && D->Tok != TOK_TYPE) {
3871 /* Try smart error recovery */
3872 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3880 /* Remember the token, skip it, check for equal */
3883 if (!ConsumeEqual (D)) {
3887 /* Check what the token was */
3892 InfoBits |= ibAddrSize;
3896 if (!IntConstFollows (D)) {
3905 if (!StrConstFollows (D)) {
3908 SB_Copy (&Name, &D->SVal);
3909 SB_Terminate (&Name);
3914 case TOK_OUTPUTNAME:
3915 if (!StrConstFollows (D)) {
3918 SB_Copy (&OutputName, &D->SVal);
3919 SB_Terminate (&OutputName);
3920 InfoBits |= ibOutputName;
3924 case TOK_OUTPUTOFFS:
3925 if (!IntConstFollows (D)) {
3928 OutputOffs = D->IVal;
3930 InfoBits |= ibOutputOffs;
3934 if (!IntConstFollows (D)) {
3943 if (!IntConstFollows (D)) {
3946 Start = (cc65_addr) D->IVal;
3948 InfoBits |= ibStart;
3958 UnexpectedToken (D);
3964 if (D->Tok != TOK_COMMA) {
3970 /* Check for end of line */
3971 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3972 UnexpectedToken (D);
3977 /* Check for required and/or matched information */
3978 if ((InfoBits & ibRequired) != ibRequired) {
3979 ParseError (D, CC65_ERROR, "Required attributes missing");
3982 InfoBits &= (ibOutputName | ibOutputOffs);
3983 if (InfoBits != ibNone && InfoBits != (ibOutputName | ibOutputOffs)) {
3984 ParseError (D, CC65_ERROR,
3985 "Attributes \"outputname\" and \"outputoffs\" must be paired");
3989 /* Fix OutputOffs if not given */
3990 if (InfoBits == ibNone) {
3994 /* Create the segment info and remember it */
3995 S = NewSegInfo (&Name, Id, Start, Size, &OutputName, OutputOffs);
3996 CollReplaceExpand (&D->Info->SegInfoById, S, Id);
3997 CollAppend (&D->Info->SegInfoByName, S);
4000 /* Entry point in case of errors */
4002 SB_Done (&OutputName);
4008 static void ParseSpan (InputData* D)
4009 /* Parse a SPAN line */
4012 cc65_addr Start = 0;
4014 unsigned SegId = CC65_INV_ID;
4015 unsigned TypeId = CC65_INV_ID;
4026 ibRequired = ibId | ibSegId | ibSize | ibStart,
4027 } InfoBits = ibNone;
4029 /* Skip the SEGMENT token */
4032 /* More stuff follows */
4037 /* Something we know? */
4038 if (D->Tok != TOK_ID && D->Tok != TOK_SEGMENT &&
4039 D->Tok != TOK_SIZE && D->Tok != TOK_START &&
4040 D->Tok != TOK_TYPE) {
4042 /* Try smart error recovery */
4043 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
4051 /* Remember the token, skip it, check for equal */
4054 if (!ConsumeEqual (D)) {
4058 /* Check what the token was */
4062 if (!IntConstFollows (D)) {
4071 if (!IntConstFollows (D)) {
4075 InfoBits |= ibSegId;
4080 if (!IntConstFollows (D)) {
4089 if (!IntConstFollows (D)) {
4092 Start = (cc65_addr) D->IVal;
4094 InfoBits |= ibStart;
4098 if (!IntConstFollows (D)) {
4108 UnexpectedToken (D);
4114 if (D->Tok != TOK_COMMA) {
4120 /* Check for end of line */
4121 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4122 UnexpectedToken (D);
4127 /* Check for required and/or matched information */
4128 if ((InfoBits & ibRequired) != ibRequired) {
4129 ParseError (D, CC65_ERROR, "Required attributes missing");
4133 /* Create the span info and remember it */
4137 S->End = Start + Size - 1;
4139 S->Type.Id = TypeId;
4140 CollReplaceExpand (&D->Info->SpanInfoById, S, Id);
4143 /* Entry point in case of errors */
4149 static void ParseSym (InputData* D)
4150 /* Parse a SYM line */
4152 /* Most of the following variables are initialized with a value that is
4153 ** overwritten later. This is just to avoid compiler warnings.
4155 Collection DefLineIds = COLLECTION_INITIALIZER;
4156 unsigned ExportId = CC65_INV_ID;
4157 unsigned FileId = CC65_INV_ID;
4158 unsigned Id = CC65_INV_ID;
4159 StrBuf Name = STRBUF_INITIALIZER;
4160 unsigned ParentId = CC65_INV_ID;
4161 Collection RefLineIds = COLLECTION_INITIALIZER;
4162 unsigned ScopeId = CC65_INV_ID;
4163 unsigned SegId = CC65_INV_ID;
4165 cc65_symbol_type Type = CC65_SYM_EQUATE;
4172 ibAddrSize = 0x0001,
4173 ibDefLineId = 0x0002,
4174 ibExportId = 0x0004,
4177 ibParentId = 0x0020,
4178 ibRefLineId = 0x0040,
4186 ibRequired = ibAddrSize | ibId | ibName,
4187 } InfoBits = ibNone;
4189 /* Skip the SYM token */
4192 /* More stuff follows */
4197 /* Something we know? */
4198 if (D->Tok != TOK_ADDRSIZE && D->Tok != TOK_DEF &&
4199 D->Tok != TOK_EXPORT && D->Tok != TOK_FILE &&
4200 D->Tok != TOK_ID && D->Tok != TOK_NAME &&
4201 D->Tok != TOK_PARENT && D->Tok != TOK_REF &&
4202 D->Tok != TOK_SCOPE && D->Tok != TOK_SEGMENT &&
4203 D->Tok != TOK_SIZE && D->Tok != TOK_TYPE &&
4204 D->Tok != TOK_VALUE) {
4206 /* Try smart error recovery */
4207 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
4216 /* Remember the token, skip it, check for equal */
4219 if (!ConsumeEqual (D)) {
4223 /* Check what the token was */
4228 InfoBits |= ibAddrSize;
4233 if (!IntConstFollows (D)) {
4236 CollAppendId (&DefLineIds, (unsigned) D->IVal);
4238 if (D->Tok != TOK_PLUS) {
4243 InfoBits |= ibDefLineId;
4247 if (!IntConstFollows (D)) {
4251 InfoBits |= ibExportId;
4256 if (!IntConstFollows (D)) {
4260 InfoBits |= ibFileId;
4265 if (!IntConstFollows (D)) {
4274 if (!StrConstFollows (D)) {
4277 SB_Copy (&Name, &D->SVal);
4278 SB_Terminate (&Name);
4284 if (!IntConstFollows (D)) {
4289 InfoBits |= ibParentId;
4294 if (!IntConstFollows (D)) {
4297 CollAppendId (&RefLineIds, (unsigned) D->IVal);
4299 if (D->Tok != TOK_PLUS) {
4304 InfoBits |= ibRefLineId;
4308 if (!IntConstFollows (D)) {
4313 InfoBits |= ibScopeId;
4317 if (!IntConstFollows (D)) {
4320 SegId = (unsigned) D->IVal;
4321 InfoBits |= ibSegId;
4326 if (!IntConstFollows (D)) {
4329 Size = (cc65_size) D->IVal;
4336 case TOK_EQUATE: Type = CC65_SYM_EQUATE; break;
4337 case TOK_IMPORT: Type = CC65_SYM_IMPORT; break;
4338 case TOK_LABEL: Type = CC65_SYM_LABEL; break;
4340 ParseError (D, CC65_ERROR,
4341 "Unknown value for attribute \"type\"");
4350 if (!IntConstFollows (D)) {
4354 InfoBits |= ibValue;
4360 UnexpectedToken (D);
4366 if (D->Tok != TOK_COMMA) {
4372 /* Check for end of line */
4373 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4374 UnexpectedToken (D);
4379 /* Check for required and/or matched information */
4380 if ((InfoBits & ibRequired) != ibRequired) {
4381 ParseError (D, CC65_ERROR, "Required attributes missing");
4384 if ((InfoBits & (ibScopeId | ibParentId)) == 0 ||
4385 (InfoBits & (ibScopeId | ibParentId)) == (ibScopeId | ibParentId)) {
4386 ParseError (D, CC65_ERROR, "Only one of \"parent\", \"scope\" must be specified");
4390 /* Create the symbol info */
4391 S = NewSymInfo (&Name);
4396 S->Exp.Id = ExportId;
4398 S->Scope.Id = ScopeId;
4399 S->Parent.Id = ParentId;
4400 CollMove (&DefLineIds, &S->DefLineInfoList);
4401 CollMove (&RefLineIds, &S->RefLineInfoList);
4404 CollReplaceExpand (&D->Info->SymInfoById, S, Id);
4405 CollAppend (&D->Info->SymInfoByName, S);
4406 CollAppend (&D->Info->SymInfoByVal, S);
4409 /* Entry point in case of errors */
4410 CollDone (&DefLineIds);
4411 CollDone (&RefLineIds);
4418 static void ParseType (InputData* D)
4419 /* Parse a TYPE line */
4421 /* Most of the following variables are initialized with a value that is
4422 ** overwritten later. This is just to avoid compiler warnings.
4424 unsigned Id = CC65_INV_ID;
4425 StrBuf Value = STRBUF_INITIALIZER;
4434 ibRequired = ibId | ibValue,
4435 } InfoBits = ibNone;
4437 /* Skip the SYM token */
4440 /* More stuff follows */
4445 /* Something we know? */
4446 if (D->Tok != TOK_ID && D->Tok != TOK_VALUE) {
4448 /* Try smart error recovery */
4449 if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
4458 /* Remember the token, skip it, check for equal */
4461 if (!ConsumeEqual (D)) {
4465 /* Check what the token was */
4469 if (!IntConstFollows (D)) {
4478 if (!StrConstFollows (D)) {
4481 SB_Copy (&Value, &D->SVal);
4482 InfoBits |= ibValue;
4488 UnexpectedToken (D);
4494 if (D->Tok != TOK_COMMA) {
4500 /* Check for end of line */
4501 if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4502 UnexpectedToken (D);
4507 /* Check for required and/or matched information */
4508 if ((InfoBits & ibRequired) != ibRequired) {
4509 ParseError (D, CC65_ERROR, "Required attributes missing");
4513 /* Parse the type string to create the type info */
4514 T = ParseTypeString (D, &Value);
4521 CollReplaceExpand (&D->Info->TypeInfoById, T, Id);
4524 /* Entry point in case of errors */
4531 static void ParseVersion (InputData* D)
4532 /* Parse a VERSION line */
4538 ibRequired = ibMajor | ibMinor,
4539 } InfoBits = ibNone;
4541 /* Skip the VERSION token */
4544 /* More stuff follows */
4545 while (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4551 if (!ConsumeEqual (D)) {
4554 if (!IntConstFollows (D)) {
4557 D->Info->MajorVersion = D->IVal;
4559 InfoBits |= ibMajor;
4564 if (!ConsumeEqual (D)) {
4567 if (!IntConstFollows (D)) {
4570 D->Info->MinorVersion = D->IVal;
4572 InfoBits |= ibMinor;
4576 /* Try to skip unknown keywords that may have been added by
4583 UnexpectedToken (D);
4588 /* Comma follows before next attribute */
4589 if (D->Tok == TOK_COMMA) {
4591 } else if (D->Tok == TOK_EOL || D->Tok == TOK_EOF) {
4594 UnexpectedToken (D);
4599 /* Check for required information */
4600 if ((InfoBits & ibRequired) != ibRequired) {
4601 ParseError (D, CC65_ERROR, "Required attributes missing");
4606 /* Entry point in case of errors */
4612 /*****************************************************************************/
4613 /* Data processing */
4614 /*****************************************************************************/
4618 static int FindCSymInfoByName (const Collection* CSymInfos, const char* Name,
4620 /* Find the C symbol info with a given file name. The function returns true if
4621 ** the name was found. In this case, Index contains the index of the first item
4622 ** that matches. If the item wasn't found, the function returns false and
4623 ** Index contains the insert position for Name.
4626 /* Do a binary search */
4628 int Hi = (int) CollCount (CSymInfos) - 1;
4633 int Cur = (Lo + Hi) / 2;
4636 const CSymInfo* CurItem = CollAt (CSymInfos, Cur);
4639 int Res = strcmp (CurItem->Name, Name);
4646 /* Since we may have duplicates, repeat the search until we've
4647 ** the first item that has a match.
4655 /* Pass back the index. This is also the insert position */
4662 static int FindFileInfoByName (const Collection* FileInfos, const char* Name,
4664 /* Find the FileInfo for a given file name. The function returns true if the
4665 ** name was found. In this case, Index contains the index of the first item
4666 ** that matches. If the item wasn't found, the function returns false and
4667 ** Index contains the insert position for Name.
4670 /* Do a binary search */
4672 int Hi = (int) CollCount (FileInfos) - 1;
4677 int Cur = (Lo + Hi) / 2;
4680 const FileInfo* CurItem = CollAt (FileInfos, Cur);
4683 int Res = strcmp (CurItem->Name, Name);
4690 /* Since we may have duplicates, repeat the search until we've
4691 ** the first item that has a match.
4699 /* Pass back the index. This is also the insert position */
4706 static SpanInfoListEntry* FindSpanInfoByAddr (const SpanInfoList* L, cc65_addr Addr)
4707 /* Find the index of a SpanInfo for a given address. Returns 0 if no such
4708 ** SpanInfo was found.
4711 /* Do a binary search */
4713 int Hi = (int) L->Count - 1;
4717 int Cur = (Lo + Hi) / 2;
4720 SpanInfoListEntry* CurItem = &L->List[Cur];
4723 if (CurItem->Addr > Addr) {
4725 } else if (CurItem->Addr < Addr) {
4739 static LineInfo* FindLineInfoByLine (const Collection* LineInfos, cc65_line Line)
4740 /* Find the LineInfo for a given line number. The function returns the line
4741 ** info or NULL if none was found.
4744 /* Do a binary search */
4746 int Hi = (int) CollCount (LineInfos) - 1;
4750 int Cur = (Lo + Hi) / 2;
4753 LineInfo* CurItem = CollAt (LineInfos, Cur);
4756 if (Line > CurItem->Line) {
4758 } else if (Line < CurItem->Line) {
4772 static SegInfo* FindSegInfoByName (const Collection* SegInfos, const char* Name)
4773 /* Find the SegInfo for a given segment name. The function returns the segment
4774 ** info or NULL if none was found.
4777 /* Do a binary search */
4779 int Hi = (int) CollCount (SegInfos) - 1;
4783 int Cur = (Lo + Hi) / 2;
4786 SegInfo* CurItem = CollAt (SegInfos, Cur);
4789 int Res = strcmp (CurItem->Name, Name);
4794 } else if (Res > 0) {
4808 static int FindScopeInfoByName (const Collection* ScopeInfos, const char* Name,
4810 /* Find the ScopeInfo for a given scope name. The function returns true if the
4811 ** name was found. In this case, Index contains the index of the first item
4812 ** that matches. If the item wasn't found, the function returns false and
4813 ** Index contains the insert position for Name.
4816 /* Do a binary search */
4818 int Hi = (int) CollCount (ScopeInfos) - 1;
4823 int Cur = (Lo + Hi) / 2;
4826 const ScopeInfo* CurItem = CollAt (ScopeInfos, Cur);
4829 int Res = strcmp (CurItem->Name, Name);
4836 /* Since we may have duplicates, repeat the search until we've
4837 ** the first item that has a match.
4845 /* Pass back the index. This is also the insert position */
4852 static int FindSymInfoByName (const Collection* SymInfos, const char* Name,
4854 /* Find the SymInfo for a given file name. The function returns true if the
4855 ** name was found. In this case, Index contains the index of the first item
4856 ** that matches. If the item wasn't found, the function returns false and
4857 ** Index contains the insert position for Name.
4860 /* Do a binary search */
4862 int Hi = (int) CollCount (SymInfos) - 1;
4867 int Cur = (Lo + Hi) / 2;
4870 const SymInfo* CurItem = CollAt (SymInfos, Cur);
4873 int Res = strcmp (CurItem->Name, Name);
4880 /* Since we may have duplicates, repeat the search until we've
4881 ** the first item that has a match.
4889 /* Pass back the index. This is also the insert position */
4896 static int FindSymInfoByValue (const Collection* SymInfos, long Value,
4898 /* Find the SymInfo for a given value. The function returns true if the
4899 ** value was found. In this case, Index contains the index of the first item
4900 ** that matches. If the item wasn't found, the function returns false and
4901 ** Index contains the insert position for the given value.
4904 /* Do a binary search */
4906 int Hi = (int) CollCount (SymInfos) - 1;
4911 int Cur = (Lo + Hi) / 2;
4914 SymInfo* CurItem = CollAt (SymInfos, Cur);
4917 if (Value > CurItem->Value) {
4921 /* Since we may have duplicates, repeat the search until we've
4922 ** the first item that has a match.
4924 if (Value == CurItem->Value) {
4930 /* Pass back the index. This is also the insert position */
4937 static void ProcessCSymInfo (InputData* D)
4938 /* Postprocess c symbol infos */
4942 /* Walk over all c symbols. Resolve the ids and add the c symbols to the
4943 ** corresponding asm symbols.
4945 for (I = 0; I < CollCount (&D->Info->CSymInfoById); ++I) {
4947 /* Get this c symbol info */
4948 CSymInfo* S = CollAt (&D->Info->CSymInfoById, I);
4950 /* Resolve the asm symbol */
4951 if (S->Sym.Id == CC65_INV_ID) {
4953 } else if (S->Sym.Id >= CollCount (&D->Info->SymInfoById)) {
4956 "Invalid symbol id %u for c symbol with id %u",
4960 S->Sym.Info = CollAt (&D->Info->SymInfoById, S->Sym.Id);
4962 /* For normal (=static) symbols, add a backlink to the symbol but
4963 ** check that there is not more than one.
4965 if (S->SC != CC65_CSYM_AUTO && S->SC != CC65_CSYM_REG) {
4966 if (S->Sym.Info->CSym) {
4969 "Asm symbol id %u has more than one C symbol attached",
4973 S->Sym.Info->CSym = S;
4978 /* Resolve the type */
4979 if (S->Type.Id >= CollCount (&D->Info->TypeInfoById)) {
4982 "Invalid type id %u for c symbol with id %u",
4986 S->Type.Info = CollAt (&D->Info->TypeInfoById, S->Type.Id);
4989 /* Resolve the scope */
4990 if (S->Scope.Id >= CollCount (&D->Info->ScopeInfoById)) {
4993 "Invalid scope id %u for c symbol with id %u",
4994 S->Scope.Id, S->Id);
4997 S->Scope.Info = CollAt (&D->Info->ScopeInfoById, S->Scope.Id);
4999 /* Add the c symbol to the list of all c symbols for this scope */
5000 if (S->Scope.Info->CSymInfoByName == 0) {
5001 S->Scope.Info->CSymInfoByName = CollNew ();
5003 CollAppend (S->Scope.Info->CSymInfoByName, S);
5005 /* If the scope has an owner symbol, it's a .PROC scope. If this
5006 ** symbol is identical to the one attached to the C symbol, this
5007 ** is actuallay a C function and the scope is the matching scope.
5008 ** Remember the C symbol in the scope in this case.
5009 ** Beware: Scopes haven't been postprocessed, so we don't have a
5010 ** pointer but just an id.
5012 if (S->Sym.Info && S->Scope.Info->Label.Id == S->Sym.Info->Id) {
5013 /* This scope is our function scope */
5014 S->Scope.Info->CSymFunc = S;
5015 /* Add it to the list of all c functions */
5016 CollAppend (&D->Info->CSymFuncByName, S);
5022 /* Walk over all scopes and sort the c symbols by name. */
5023 for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) {
5025 /* Get this scope */
5026 ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I);
5028 /* Ignore scopes without C symbols */
5029 if (CollCount (S->CSymInfoByName) > 1) {
5030 /* Sort the c symbols for this scope by name */
5031 CollSort (S->CSymInfoByName, CompareCSymInfoByName);
5035 /* Sort the main list of all C functions by name */
5036 CollSort (&D->Info->CSymFuncByName, CompareCSymInfoByName);
5041 static void ProcessFileInfo (InputData* D)
5042 /* Postprocess file infos */
5044 /* Walk over all file infos and resolve the module ids */
5046 for (I = 0; I < CollCount (&D->Info->FileInfoById); ++I) {
5048 /* Get this file info */
5049 FileInfo* F = CollAt (&D->Info->FileInfoById, I);
5051 /* Resolve the module ids */
5053 for (J = 0; J < CollCount (&F->ModInfoByName); ++J) {
5055 /* Get the id of this module */
5056 unsigned ModId = CollIdAt (&F->ModInfoByName, J);
5057 if (ModId >= CollCount (&D->Info->ModInfoById)) {
5060 "Invalid module id %u for file with id %u",
5062 CollReplace (&F->ModInfoByName, 0, J);
5065 /* Get a pointer to the module */
5066 ModInfo* M = CollAt (&D->Info->ModInfoById, ModId);
5068 /* Replace the id by the pointer */
5069 CollReplace (&F->ModInfoByName, M, J);
5071 /* Insert a backpointer into the module */
5072 CollAppend (&M->FileInfoByName, F);
5076 /* If we didn't have any errors, sort the modules by name */
5077 if (D->Errors == 0) {
5078 CollSort (&F->ModInfoByName, CompareModInfoByName);
5082 /* Now walk over all modules and sort the file infos by name */
5083 for (I = 0; I < CollCount (&D->Info->ModInfoById); ++I) {
5085 /* Get this module info */
5086 ModInfo* M = CollAt (&D->Info->ModInfoById, I);
5088 /* Sort the files by name */
5089 CollSort (&M->FileInfoByName, CompareFileInfoByName);
5092 /* Sort the file infos by name, so we can do a binary search */
5093 CollSort (&D->Info->FileInfoByName, CompareFileInfoByName);
5098 static void ProcessLineInfo (InputData* D)
5099 /* Postprocess line infos */
5103 /* Get pointers to the collections */
5104 Collection* LineInfos = &D->Info->LineInfoById;
5105 Collection* FileInfos = &D->Info->FileInfoById;
5107 /* Walk over the line infos and replace the id numbers of file and segment
5108 ** with pointers to the actual structs. Add the line info to each file
5109 ** where it is defined. Resolve the spans and add backpointers to the
5112 for (I = 0; I < CollCount (LineInfos); ++I) {
5114 /* Get LineInfo struct */
5115 LineInfo* L = CollAt (LineInfos, I);
5117 /* Replace the file id by a pointer to the FileInfo. Add a back
5120 if (L->File.Id >= CollCount (FileInfos)) {
5123 "Invalid file id %u for line with id %u",
5127 L->File.Info = CollAt (FileInfos, L->File.Id);
5128 CollAppend (&L->File.Info->LineInfoByLine, L);
5131 /* Resolve the spans ids */
5132 for (J = 0; J < CollCount (&L->SpanInfoList); ++J) {
5134 /* Get the id of this span */
5135 unsigned SpanId = CollIdAt (&L->SpanInfoList, J);
5136 if (SpanId >= CollCount (&D->Info->SpanInfoById)) {
5139 "Invalid span id %u for line with id %u",
5141 CollReplace (&L->SpanInfoList, 0, J);
5144 /* Get a pointer to the span */
5145 SpanInfo* SP = CollAt (&D->Info->SpanInfoById, SpanId);
5147 /* Replace the id by the pointer */
5148 CollReplace (&L->SpanInfoList, SP, J);
5150 /* Insert a backpointer into the span */
5151 if (SP->LineInfoList == 0) {
5152 SP->LineInfoList = CollNew ();
5154 CollAppend (SP->LineInfoList, L);
5159 /* Walk over all files and sort the line infos for each file so we can
5160 ** do a binary search later.
5162 for (I = 0; I < CollCount (FileInfos); ++I) {
5164 /* Get a pointer to this file info */
5165 FileInfo* F = CollAt (FileInfos, I);
5167 /* Sort the line infos for this file */
5168 CollSort (&F->LineInfoByLine, CompareLineInfoByLine);
5174 static void ProcessModInfo (InputData* D)
5175 /* Postprocess module infos */
5179 /* Walk over all scopes and resolve the ids */
5180 for (I = 0; I < CollCount (&D->Info->ModInfoById); ++I) {
5182 /* Get this module info */
5183 ModInfo* M = CollAt (&D->Info->ModInfoById, I);
5185 /* Resolve the main file */
5186 if (M->File.Id >= CollCount (&D->Info->FileInfoById)) {
5189 "Invalid file id %u for module with id %u",
5193 M->File.Info = CollAt (&D->Info->FileInfoById, M->File.Id);
5196 /* Resolve the library */
5197 if (M->Lib.Id == CC65_INV_ID) {
5199 } else if (M->Lib.Id >= CollCount (&D->Info->LibInfoById)) {
5202 "Invalid library id %u for module with id %u",
5206 M->Lib.Info = CollAt (&D->Info->LibInfoById, M->Lib.Id);
5210 /* Sort the collection that contains the module info by name */
5211 CollSort (&D->Info->ModInfoByName, CompareModInfoByName);
5216 static void ProcessScopeInfo (InputData* D)
5217 /* Postprocess scope infos */
5221 /* Walk over all scopes. Resolve the ids and add the scopes to the list
5222 ** of scopes for a module.
5224 for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) {
5226 /* Get this scope info */
5227 ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I);
5229 /* Resolve the module */
5230 if (S->Mod.Id >= CollCount (&D->Info->ModInfoById)) {
5233 "Invalid module id %u for scope with id %u",
5237 S->Mod.Info = CollAt (&D->Info->ModInfoById, S->Mod.Id);
5239 /* Add the scope to the list of scopes for this module */
5240 CollAppend (&S->Mod.Info->ScopeInfoByName, S);
5242 /* If this is a main scope, add a pointer to the corresponding
5245 if (S->Parent.Id == CC65_INV_ID) {
5246 /* No parent means main scope */
5247 S->Mod.Info->MainScope = S;
5250 /* If this is the scope that implements a C function, add the
5251 ** function to the list of all functions in this module.
5254 CollAppend (&S->Mod.Info->CSymFuncByName, S->CSymFunc);
5258 /* Resolve the parent scope */
5259 if (S->Parent.Id == CC65_INV_ID) {
5261 } else if (S->Parent.Id >= CollCount (&D->Info->ScopeInfoById)) {
5264 "Invalid parent scope id %u for scope with id %u",
5265 S->Parent.Id, S->Id);
5268 S->Parent.Info = CollAt (&D->Info->ScopeInfoById, S->Parent.Id);
5270 /* Set a backpointer in the parent */
5271 if (S->Parent.Info->ChildScopeList == 0) {
5272 S->Parent.Info->ChildScopeList = CollNew ();
5274 CollAppend (S->Parent.Info->ChildScopeList, S);
5277 /* Resolve the label */
5278 if (S->Label.Id == CC65_INV_ID) {
5280 } else if (S->Label.Id >= CollCount (&D->Info->SymInfoById)) {
5283 "Invalid label id %u for scope with id %u",
5284 S->Label.Id, S->Id);
5287 S->Label.Info = CollAt (&D->Info->SymInfoById, S->Label.Id);
5290 /* Resolve the spans ids */
5291 for (J = 0; J < CollCount (&S->SpanInfoList); ++J) {
5293 /* Get the id of this span */
5294 unsigned SpanId = CollIdAt (&S->SpanInfoList, J);
5295 if (SpanId >= CollCount (&D->Info->SpanInfoById)) {
5298 "Invalid span id %u for scope with id %u",
5300 CollReplace (&S->SpanInfoList, 0, J);
5303 /* Get a pointer to the span */
5304 SpanInfo* SP = CollAt (&D->Info->SpanInfoById, SpanId);
5306 /* Replace the id by the pointer */
5307 CollReplace (&S->SpanInfoList, SP, J);
5309 /* Insert a backpointer into the span */
5310 if (SP->ScopeInfoList == 0) {
5311 SP->ScopeInfoList = CollNew ();
5313 CollAppend (SP->ScopeInfoList, S);
5318 /* Walk over all modules. If a module doesn't have scopes, it wasn't
5319 ** compiled with debug info which is ok. If it has debug info, it must
5320 ** also have a main scope. If there are scopes, sort them by name. Do
5321 ** also sort C functions in this module by name.
5323 for (I = 0; I < CollCount (&D->Info->ModInfoById); ++I) {
5325 /* Get this module */
5326 ModInfo* M = CollAt (&D->Info->ModInfoById, I);
5328 /* Ignore modules without any scopes (no debug info) */
5329 if (CollCount (&M->ScopeInfoByName) == 0) {
5333 /* Must have a main scope */
5334 if (M->MainScope == 0) {
5337 "Module with id %u has no main scope",
5341 /* Sort the scopes for this module by name */
5342 CollSort (&M->ScopeInfoByName, CompareScopeInfoByName);
5344 /* Sort the C functions in this module by name */
5345 CollSort (&M->CSymFuncByName, CompareCSymInfoByName);
5348 /* Sort the scope infos */
5349 CollSort (&D->Info->ScopeInfoByName, CompareScopeInfoByName);
5354 static void ProcessSegInfo (InputData* D)
5355 /* Postprocess segment infos */
5357 /* Sort the segment infos by name */
5358 CollSort (&D->Info->SegInfoByName, CompareSegInfoByName);
5363 static void ProcessSpanInfo (InputData* D)
5364 /* Postprocess span infos */
5368 /* Temporary collection with span infos sorted by address */
5369 Collection SpanInfoByAddr = COLLECTION_INITIALIZER;
5371 /* Resize the temporary collection */
5372 CollGrow (&SpanInfoByAddr, CollCount (&D->Info->SpanInfoById));
5374 /* Walk over all spans and resolve the ids */
5375 for (I = 0; I < CollCount (&D->Info->SpanInfoById); ++I) {
5377 /* Get this span info */
5378 SpanInfo* S = CollAt (&D->Info->SpanInfoById, I);
5380 /* Resolve the segment and relocate the span */
5381 if (S->Seg.Id >= CollCount (&D->Info->SegInfoById)) {
5384 "Invalid segment id %u for span with id %u",
5388 S->Seg.Info = CollAt (&D->Info->SegInfoById, S->Seg.Id);
5389 S->Start += S->Seg.Info->Start;
5390 S->End += S->Seg.Info->Start;
5393 /* Resolve the type if we have it */
5394 if (S->Type.Id == CC65_INV_ID) {
5396 } else if (S->Type.Id >= CollCount (&D->Info->TypeInfoById)) {
5399 "Invalid type id %u for span with id %u",
5403 S->Type.Info = CollAt (&D->Info->TypeInfoById, S->Type.Id);
5406 /* Append this span info to the temporary collection that is later
5407 ** sorted by address.
5409 CollAppend (&SpanInfoByAddr, S);
5412 /* Sort the collection with all span infos by address */
5413 CollSort (&SpanInfoByAddr, CompareSpanInfoByAddr);
5415 /* Create the span info list from the span info collection */
5416 CreateSpanInfoList (&D->Info->SpanInfoByAddr, &SpanInfoByAddr);
5418 /* Remove the temporary collection */
5419 CollDone (&SpanInfoByAddr);
5424 static void ProcessSymInfo (InputData* D)
5425 /* Postprocess symbol infos */
5429 /* Walk over the symbols and resolve the references */
5430 for (I = 0; I < CollCount (&D->Info->SymInfoById); ++I) {
5432 /* Get the symbol info */
5433 SymInfo* S = CollAt (&D->Info->SymInfoById, I);
5435 /* Resolve export */
5436 if (S->Exp.Id == CC65_INV_ID) {
5438 } else if (S->Exp.Id >= CollCount (&D->Info->SymInfoById)) {
5441 "Invalid export id %u for symbol with id %u",
5445 S->Exp.Info = CollAt (&D->Info->SymInfoById, S->Exp.Id);
5447 /* Add a backpointer, so the export knows its imports */
5448 if (S->Exp.Info->ImportList == 0) {
5449 S->Exp.Info->ImportList = CollNew ();
5451 CollAppend (S->Exp.Info->ImportList, S);
5454 /* Resolve segment */
5455 if (S->Seg.Id == CC65_INV_ID) {
5457 } else if (S->Seg.Id >= CollCount (&D->Info->SegInfoById)) {
5460 "Invalid segment id %u for symbol with id %u",
5464 S->Seg.Info = CollAt (&D->Info->SegInfoById, S->Seg.Id);
5467 /* Resolve the scope */
5468 if (S->Scope.Id == CC65_INV_ID) {
5470 } else if (S->Scope.Id >= CollCount (&D->Info->ScopeInfoById)) {
5473 "Invalid scope id %u for symbol with id %u",
5474 S->Scope.Id, S->Id);
5477 S->Scope.Info = CollAt (&D->Info->ScopeInfoById, S->Scope.Id);
5479 /* Place a backpointer to the symbol in the scope */
5480 CollAppend (&S->Scope.Info->SymInfoByName, S);
5483 /* Resolve the parent for cheap locals */
5484 if (S->Parent.Id == CC65_INV_ID) {
5486 } else if (S->Parent.Id >= CollCount (&D->Info->SymInfoById)) {
5489 "Invalid parent id %u for symbol with id %u",
5490 S->Parent.Id, S->Id);
5493 S->Parent.Info = CollAt (&D->Info->SymInfoById, S->Parent.Id);
5495 /* Place a backpointer to the cheap local into the parent */
5496 if (S->Parent.Info->CheapLocals == 0) {
5497 S->Parent.Info->CheapLocals = CollNew ();
5499 CollAppend (S->Parent.Info->CheapLocals, S);
5502 /* Resolve the line infos for the symbol definition */
5503 for (J = 0; J < CollCount (&S->DefLineInfoList); ++J) {
5505 /* Get the id of this line info */
5506 unsigned LineId = CollIdAt (&S->DefLineInfoList, J);
5507 if (LineId >= CollCount (&D->Info->LineInfoById)) {
5510 "Invalid line id %u for symbol with id %u",
5512 CollReplace (&S->DefLineInfoList, 0, J);
5514 /* Get a pointer to the line info */
5515 LineInfo* LI = CollAt (&D->Info->LineInfoById, LineId);
5517 /* Replace the id by the pointer */
5518 CollReplace (&S->DefLineInfoList, LI, J);
5522 /* Resolve the line infos for symbol references */
5523 for (J = 0; J < CollCount (&S->RefLineInfoList); ++J) {
5525 /* Get the id of this line info */
5526 unsigned LineId = CollIdAt (&S->RefLineInfoList, J);
5527 if (LineId >= CollCount (&D->Info->LineInfoById)) {
5530 "Invalid line id %u for symbol with id %u",
5532 CollReplace (&S->RefLineInfoList, 0, J);
5534 /* Get a pointer to the line info */
5535 LineInfo* LI = CollAt (&D->Info->LineInfoById, LineId);
5537 /* Replace the id by the pointer */
5538 CollReplace (&S->RefLineInfoList, LI, J);
5544 /* Second run. Resolve scopes for cheap locals */
5545 for (I = 0; I < CollCount (&D->Info->SymInfoById); ++I) {
5547 /* Get the symbol info */
5548 SymInfo* S = CollAt (&D->Info->SymInfoById, I);
5550 /* Resolve the scope */
5551 if (S->Scope.Info == 0) {
5552 /* No scope - must have a parent */
5553 if (S->Parent.Info == 0) {
5556 "Symbol with id %u has no parent and no scope",
5558 } else if (S->Parent.Info->Scope.Info == 0) {
5561 "Symbol with id %u has parent %u without a scope",
5562 S->Id, S->Parent.Info->Id);
5564 S->Scope.Info = S->Parent.Info->Scope.Info;
5569 /* Walk over the scopes and sort the symbols in the scope by name */
5570 for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) {
5572 /* Get the scope info */
5573 ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I);
5575 /* Sort the symbols in this scope by name */
5576 CollSort (&S->SymInfoByName, CompareSymInfoByName);
5579 /* Sort the symbol infos */
5580 CollSort (&D->Info->SymInfoByName, CompareSymInfoByName);
5581 CollSort (&D->Info->SymInfoByVal, CompareSymInfoByVal);
5586 /*****************************************************************************/
5587 /* Debug info files */
5588 /*****************************************************************************/
5592 cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
5593 /* Parse the debug info file with the given name. On success, the function
5594 ** will return a pointer to an opaque cc65_dbginfo structure, that must be
5595 ** passed to the other functions in this module to retrieve information.
5596 ** errorfunc is called in case of warnings and errors. If the file cannot be
5597 ** read successfully, NULL is returned.
5600 /* Data structure used to control scanning and parsing */
5602 0, /* Name of input file */
5603 1, /* Line number */
5605 0, /* Line at start of current token */
5606 0, /* Column at start of current token */
5607 0, /* Number of errors */
5609 ' ', /* Input character */
5610 TOK_INVALID, /* Input token */
5611 0, /* Integer constant */
5612 STRBUF_INITIALIZER, /* String constant */
5613 0, /* Function called in case of errors */
5614 0, /* Pointer to debug info */
5616 D.FileName = FileName;
5619 /* Open the input file */
5620 D.F = fopen (FileName, "rt");
5623 ParseError (&D, CC65_ERROR,
5624 "Cannot open input file \"%s\": %s",
5625 FileName, strerror (errno));
5629 /* Create a new debug info struct */
5630 D.Info = NewDbgInfo (FileName);
5632 /* Prime the pump */
5635 /* The first line in the file must specify version information */
5636 if (D.Tok != TOK_VERSION) {
5637 ParseError (&D, CC65_ERROR,
5638 "\"version\" keyword missing in first line - this is not "
5639 "a valid debug info file");
5643 /* Parse the version directive */
5646 /* Do several checks on the version number */
5647 if (D.Info->MajorVersion < VER_MAJOR) {
5650 "This is an old version of the debug info format that is no "
5651 "longer supported. Version found = %u.%u, version supported "
5653 D.Info->MajorVersion, D.Info->MinorVersion,
5654 VER_MAJOR, VER_MINOR
5657 } else if (D.Info->MajorVersion == VER_MAJOR &&
5658 D.Info->MinorVersion > VER_MINOR) {
5661 "This is a slightly newer version of the debug info format. "
5662 "It might work, but you may get errors about unknown keywords "
5663 "and similar. Version found = %u.%u, version supported = %u.%u",
5664 D.Info->MajorVersion, D.Info->MinorVersion,
5665 VER_MAJOR, VER_MINOR
5667 } else if (D.Info->MajorVersion > VER_MAJOR) {
5670 "The format of this debug info file is newer than what we "
5671 "know. Will proceed but probably fail. Version found = %u.%u, "
5672 "version supported = %u.%u",
5673 D.Info->MajorVersion, D.Info->MinorVersion,
5674 VER_MAJOR, VER_MINOR
5680 while (D.Tok != TOK_EOF) {
5729 /* Output a warning, then skip the line with the unknown
5730 ** keyword that may have been added by a later version.
5732 ParseError (&D, CC65_WARNING,
5733 "Unknown keyword \"%s\" - skipping",
5734 SB_GetConstBuf (&D.SVal));
5740 UnexpectedToken (&D);
5744 /* EOL or EOF must follow */
5749 /* Close the file */
5752 /* Free memory allocated for SVal */
5755 /* In case of errors, delete the debug info already allocated and
5759 /* Free allocated stuff */
5760 FreeDbgInfo (D.Info);
5764 /* We do now have all the information from the input file. Do
5765 ** postprocessing. Beware: Some of the following postprocessing
5766 ** depends on the order of the calls.
5768 ProcessCSymInfo (&D);
5769 ProcessFileInfo (&D);
5770 ProcessLineInfo (&D);
5771 ProcessModInfo (&D);
5772 ProcessScopeInfo (&D);
5773 ProcessSegInfo (&D);
5774 ProcessSpanInfo (&D);
5775 ProcessSymInfo (&D);
5782 /* Return the debug info struct that was created */
5788 void cc65_free_dbginfo (cc65_dbginfo Handle)
5789 /* Free debug information read from a file */
5792 FreeDbgInfo ((DbgInfo*) Handle);
5798 /*****************************************************************************/
5800 /*****************************************************************************/
5804 const cc65_csyminfo* cc65_get_csymlist (cc65_dbginfo Handle)
5805 /* Return a list of all c symbols */
5807 const DbgInfo* Info;
5811 /* Check the parameter */
5812 assert (Handle != 0);
5814 /* The handle is actually a pointer to a debug info struct */
5817 /* Allocate memory for the data structure returned to the caller */
5818 S = new_cc65_csyminfo (CollCount (&Info->CSymInfoById));
5820 /* Fill in the data */
5821 for (I = 0; I < CollCount (&Info->CSymInfoById); ++I) {
5823 CopyCSymInfo (S->data + I, CollAt (&Info->CSymInfoById, I));
5826 /* Return the result */
5832 const cc65_csyminfo* cc65_csym_byid (cc65_dbginfo Handle, unsigned Id)
5833 /* Return information about a c symbol with a specific id. The function
5834 ** returns NULL if the id is invalid (no such c symbol) and otherwise a
5835 ** cc65_csyminfo structure with one entry that contains the requested
5836 ** symbol information.
5839 const DbgInfo* Info;
5842 /* Check the parameter */
5843 assert (Handle != 0);
5845 /* The handle is actually a pointer to a debug info struct */
5848 /* Check if the id is valid */
5849 if (Id >= CollCount (&Info->CSymInfoById)) {
5853 /* Allocate memory for the data structure returned to the caller */
5854 S = new_cc65_csyminfo (1);
5856 /* Fill in the data */
5857 CopyCSymInfo (S->data, CollAt (&Info->CSymInfoById, Id));
5859 /* Return the result */
5865 const cc65_csyminfo* cc65_cfunc_bymodule (cc65_dbginfo Handle, unsigned ModId)
5866 /* Return the list of C functions (not symbols!) for a specific module. If
5867 ** the module id is invalid, the function will return NULL, otherwise a
5868 ** (possibly empty) c symbol list.
5871 const DbgInfo* Info;
5877 /* Check the parameter */
5878 assert (Handle != 0);
5880 /* The handle is actually a pointer to a debug info struct */
5883 /* Check if the module id is valid */
5884 if (ModId >= CollCount (&Info->ModInfoById)) {
5888 /* Get a pointer to the module info */
5889 M = CollAt (&Info->ModInfoById, ModId);
5891 /* Allocate memory for the data structure returned to the caller */
5892 D = new_cc65_csyminfo (CollCount (&M->CSymFuncByName));
5894 /* Fill in the data */
5895 for (I = 0; I < CollCount (&M->CSymFuncByName); ++I) {
5896 CopyCSymInfo (D->data + I, CollAt (&M->CSymFuncByName, I));
5899 /* Return the result */
5905 const cc65_csyminfo* cc65_cfunc_byname (cc65_dbginfo Handle, const char* Name)
5906 /* Return a list of all C functions with the given name that have a
5910 const DbgInfo* Info;
5918 /* Check the parameter */
5919 assert (Handle != 0);
5921 /* The handle is actually a pointer to a debug info struct */
5924 /* Search for a function with the given name */
5925 if (!FindCSymInfoByName (&Info->CSymFuncByName, Name, &Index)) {
5929 /* Count functions with this name */
5933 if (++I >= CollCount (&Info->CSymFuncByName)) {
5936 S = CollAt (&Info->CSymFuncByName, I);
5937 if (strcmp (S->Name, Name) != 0) {
5938 /* Next symbol has another name */
5944 /* Allocate memory for the data structure returned to the caller */
5945 D = new_cc65_csyminfo (Count);
5947 /* Fill in the data */
5948 for (I = 0; I < Count; ++I, ++Index) {
5949 CopyCSymInfo (D->data + I, CollAt (&Info->CSymFuncByName, Index));
5952 /* Return the result */
5958 const cc65_csyminfo* cc65_csym_byscope (cc65_dbginfo Handle, unsigned ScopeId)
5959 /* Return all C symbols for a scope. The function will return NULL if the
5960 ** given id is invalid.
5963 const DbgInfo* Info;
5969 /* Check the parameter */
5970 assert (Handle != 0);
5972 /* The handle is actually a pointer to a debug info struct */
5975 /* Check if the scope id is valid */
5976 if (ScopeId >= CollCount (&Info->ScopeInfoById)) {
5980 /* Get a pointer to the scope */
5981 S = CollAt (&Info->ScopeInfoById, ScopeId);
5983 /* Allocate memory for the data structure returned to the caller */
5984 D = new_cc65_csyminfo (CollCount (S->CSymInfoByName));
5986 /* Fill in the data */
5987 for (I = 0; I < CollCount (S->CSymInfoByName); ++I) {
5988 CopyCSymInfo (D->data + I, CollAt (S->CSymInfoByName, I));
5991 /* Return the result */
5997 void cc65_free_csyminfo (cc65_dbginfo Handle, const cc65_csyminfo* Info)
5998 /* Free a c symbol info record */
6000 /* Just for completeness, check the handle */
6001 assert (Handle != 0);
6003 /* Just free the memory */
6004 xfree ((cc65_csyminfo*) Info);
6009 /*****************************************************************************/
6011 /*****************************************************************************/
6015 const cc65_libraryinfo* cc65_get_librarylist (cc65_dbginfo Handle)
6016 /* Return a list of all libraries */
6018 const DbgInfo* Info;
6019 cc65_libraryinfo* D;
6022 /* Check the parameter */
6023 assert (Handle != 0);
6025 /* The handle is actually a pointer to a debug info struct */
6028 /* Allocate memory for the data structure returned to the caller */
6029 D = new_cc65_libraryinfo (CollCount (&Info->LibInfoById));
6031 /* Fill in the data */
6032 for (I = 0; I < CollCount (&Info->LibInfoById); ++I) {
6034 CopyLibInfo (D->data + I, CollAt (&Info->LibInfoById, I));
6037 /* Return the result */
6043 const cc65_libraryinfo* cc65_library_byid (cc65_dbginfo Handle, unsigned Id)
6044 /* Return information about a library with a specific id. The function
6045 ** returns NULL if the id is invalid (no such library) and otherwise a
6046 ** cc65_libraryinfo structure with one entry that contains the requested
6047 ** library information.
6050 const DbgInfo* Info;
6051 cc65_libraryinfo* D;
6053 /* Check the parameter */
6054 assert (Handle != 0);
6056 /* The handle is actually a pointer to a debug info struct */
6059 /* Check if the id is valid */
6060 if (Id >= CollCount (&Info->LibInfoById)) {
6064 /* Allocate memory for the data structure returned to the caller */
6065 D = new_cc65_libraryinfo (1);
6067 /* Fill in the data */
6068 CopyLibInfo (D->data, CollAt (&Info->LibInfoById, Id));
6070 /* Return the result */
6076 void cc65_free_libraryinfo (cc65_dbginfo Handle, const cc65_libraryinfo* Info)
6077 /* Free a library info record */
6079 /* Just for completeness, check the handle */
6080 assert (Handle != 0);
6082 /* Just free the memory */
6083 xfree ((cc65_libraryinfo*) Info);
6088 /*****************************************************************************/
6090 /*****************************************************************************/
6094 const cc65_lineinfo* cc65_line_byid (cc65_dbginfo Handle, unsigned Id)
6095 /* Return information about a line with a specific id. The function
6096 ** returns NULL if the id is invalid (no such line) and otherwise a
6097 ** cc65_lineinfo structure with one entry that contains the requested
6098 ** module information.
6101 const DbgInfo* Info;
6104 /* Check the parameter */
6105 assert (Handle != 0);
6107 /* The handle is actually a pointer to a debug info struct */
6110 /* Check if the id is valid */
6111 if (Id >= CollCount (&Info->LineInfoById)) {
6115 /* Allocate memory for the data structure returned to the caller */
6116 D = new_cc65_lineinfo (1);
6118 /* Fill in the data */
6119 CopyLineInfo (D->data, CollAt (&Info->LineInfoById, Id));
6121 /* Return the result */
6127 const cc65_lineinfo* cc65_line_bynumber (cc65_dbginfo Handle, unsigned FileId,
6129 /* Return line information for a source file/line number combination. The
6130 ** function returns NULL if no line information was found.
6133 const DbgInfo* Info;
6138 /* Check the parameter */
6139 assert (Handle != 0);
6141 /* The handle is actually a pointer to a debug info struct */
6144 /* Check if the source file id is valid */
6145 if (FileId >= CollCount (&Info->FileInfoById)) {
6150 F = CollAt (&Info->FileInfoById, FileId);
6152 /* Search in the file for the given line */
6153 L = FindLineInfoByLine (&F->LineInfoByLine, Line);
6155 /* Bail out if we didn't find the line */
6160 /* Prepare the struct we will return to the caller */
6161 D = new_cc65_lineinfo (1);
6164 CopyLineInfo (D->data, L);
6166 /* Return the allocated struct */
6172 const cc65_lineinfo* cc65_line_bysource (cc65_dbginfo Handle, unsigned FileId)
6173 /* Return line information for a source file. The function returns NULL if the
6174 ** file id is invalid.
6177 const DbgInfo* Info;
6182 /* Check the parameter */
6183 assert (Handle != 0);
6185 /* The handle is actually a pointer to a debug info struct */
6188 /* Check if the source file id is valid */
6189 if (FileId >= CollCount (&Info->FileInfoById)) {
6194 F = CollAt (&Info->FileInfoById, FileId);
6196 /* Prepare the struct we will return to the caller */
6197 D = new_cc65_lineinfo (CollCount (&F->LineInfoByLine));
6199 /* Fill in the data */
6200 for (I = 0; I < CollCount (&F->LineInfoByLine); ++I) {
6202 CopyLineInfo (D->data + I, CollAt (&F->LineInfoByLine, I));
6205 /* Return the allocated struct */
6211 const cc65_lineinfo* cc65_line_bysymdef (cc65_dbginfo Handle, unsigned SymId)
6212 /* Return line information for the definition of a symbol. The function
6213 ** returns NULL if the symbol id is invalid, otherwise a list of line infos.
6216 const DbgInfo* Info;
6221 /* Check the parameter */
6222 assert (Handle != 0);
6224 /* The handle is actually a pointer to a debug info struct */
6227 /* Check if the symbol id is valid */
6228 if (SymId >= CollCount (&Info->SymInfoById)) {
6232 /* Get the symbol */
6233 S = CollAt (&Info->SymInfoById, SymId);
6235 /* Prepare the struct we will return to the caller */
6236 D = new_cc65_lineinfo (CollCount (&S->DefLineInfoList));
6238 /* Fill in the data */
6239 for (I = 0; I < CollCount (&S->DefLineInfoList); ++I) {
6241 CopyLineInfo (D->data + I, CollAt (&S->DefLineInfoList, I));
6244 /* Return the allocated struct */
6250 const cc65_lineinfo* cc65_line_bysymref (cc65_dbginfo Handle, unsigned SymId)
6251 /* Return line information for all references of a symbol. The function
6252 ** returns NULL if the symbol id is invalid, otherwise a list of line infos.
6255 const DbgInfo* Info;
6260 /* Check the parameter */
6261 assert (Handle != 0);
6263 /* The handle is actually a pointer to a debug info struct */
6266 /* Check if the symbol id is valid */
6267 if (SymId >= CollCount (&Info->SymInfoById)) {
6271 /* Get the symbol */
6272 S = CollAt (&Info->SymInfoById, SymId);
6274 /* Prepare the struct we will return to the caller */
6275 D = new_cc65_lineinfo (CollCount (&S->RefLineInfoList));
6277 /* Fill in the data */
6278 for (I = 0; I < CollCount (&S->RefLineInfoList); ++I) {
6280 CopyLineInfo (D->data + I, CollAt (&S->RefLineInfoList, I));
6283 /* Return the allocated struct */
6289 const cc65_lineinfo* cc65_line_byspan (cc65_dbginfo Handle, unsigned SpanId)
6290 /* Return line information for a a span. The function returns NULL if the
6291 ** span id is invalid, otherwise a list of line infos.
6294 const DbgInfo* Info;
6299 /* Check the parameter */
6300 assert (Handle != 0);
6302 /* The handle is actually a pointer to a debug info struct */
6305 /* Check if the span id is valid */
6306 if (SpanId >= CollCount (&Info->SpanInfoById)) {
6311 S = CollAt (&Info->SpanInfoById, SpanId);
6313 /* Prepare the struct we will return to the caller */
6314 D = new_cc65_lineinfo (CollCount (S->LineInfoList));
6316 /* Fill in the data. Since S->LineInfoList may be NULL, we will use the
6317 ** count field of the returned data struct instead.
6319 for (I = 0; I < D->count; ++I) {
6321 CopyLineInfo (D->data + I, CollAt (S->LineInfoList, I));
6324 /* Return the allocated struct */
6330 void cc65_free_lineinfo (cc65_dbginfo Handle, const cc65_lineinfo* Info)
6331 /* Free line info returned by one of the other functions */
6333 /* Just for completeness, check the handle */
6334 assert (Handle != 0);
6336 /* Just free the memory */
6337 xfree ((cc65_lineinfo*) Info);
6342 /*****************************************************************************/
6344 /*****************************************************************************/
6348 const cc65_moduleinfo* cc65_get_modulelist (cc65_dbginfo Handle)
6349 /* Return a list of all modules */
6351 const DbgInfo* Info;
6355 /* Check the parameter */
6356 assert (Handle != 0);
6358 /* The handle is actually a pointer to a debug info struct */
6361 /* Allocate memory for the data structure returned to the caller */
6362 D = new_cc65_moduleinfo (CollCount (&Info->ModInfoById));
6364 /* Fill in the data */
6365 for (I = 0; I < CollCount (&Info->ModInfoById); ++I) {
6367 CopyModInfo (D->data + I, CollAt (&Info->ModInfoById, I));
6370 /* Return the result */
6376 const cc65_moduleinfo* cc65_module_byid (cc65_dbginfo Handle, unsigned Id)
6377 /* Return information about a module with a specific id. The function
6378 ** returns NULL if the id is invalid (no such module) and otherwise a
6379 ** cc65_moduleinfo structure with one entry that contains the requested
6380 ** module information.
6383 const DbgInfo* Info;
6386 /* Check the parameter */
6387 assert (Handle != 0);
6389 /* The handle is actually a pointer to a debug info struct */
6392 /* Check if the id is valid */
6393 if (Id >= CollCount (&Info->ModInfoById)) {
6397 /* Allocate memory for the data structure returned to the caller */
6398 D = new_cc65_moduleinfo (1);
6400 /* Fill in the data */
6401 CopyModInfo (D->data, CollAt (&Info->ModInfoById, Id));
6403 /* Return the result */
6409 void cc65_free_moduleinfo (cc65_dbginfo Handle, const cc65_moduleinfo* Info)
6410 /* Free a module info record */
6412 /* Just for completeness, check the handle */
6413 assert (Handle != 0);
6415 /* Just free the memory */
6416 xfree ((cc65_moduleinfo*) Info);
6421 /*****************************************************************************/
6423 /*****************************************************************************/
6427 const cc65_spaninfo* cc65_get_spanlist (cc65_dbginfo Handle)
6428 /* Return a list of all spans */
6430 const DbgInfo* Info;
6434 /* Check the parameter */
6435 assert (Handle != 0);
6437 /* The handle is actually a pointer to a debug info struct */
6440 /* Allocate memory for the data structure returned to the caller */
6441 D = new_cc65_spaninfo (CollCount (&Info->SpanInfoById));
6443 /* Fill in the data */
6444 for (I = 0; I < CollCount (&Info->SpanInfoById); ++I) {
6446 CopySpanInfo (D->data + I, CollAt (&Info->SpanInfoById, I));
6449 /* Return the result */
6455 const cc65_spaninfo* cc65_span_byid (cc65_dbginfo Handle, unsigned Id)
6456 /* Return information about a span with a specific id. The function
6457 ** returns NULL if the id is invalid (no such span) and otherwise a
6458 ** cc65_spaninfo structure with one entry that contains the requested
6459 ** span information.
6462 const DbgInfo* Info;
6465 /* Check the parameter */
6466 assert (Handle != 0);
6468 /* The handle is actually a pointer to a debug info struct */
6471 /* Check if the id is valid */
6472 if (Id >= CollCount (&Info->SpanInfoById)) {
6476 /* Allocate memory for the data structure returned to the caller */
6477 D = new_cc65_spaninfo (1);
6479 /* Fill in the data */
6480 CopySpanInfo (D->data, CollAt (&Info->SpanInfoById, Id));
6482 /* Return the result */
6488 const cc65_spaninfo* cc65_span_byaddr (cc65_dbginfo Handle, unsigned long Addr)
6489 /* Return span information for the given address. The function returns NULL
6490 ** if no spans were found for this address.
6493 const DbgInfo* Info;
6494 SpanInfoListEntry* E;
6495 cc65_spaninfo* D = 0;
6497 /* Check the parameter */
6498 assert (Handle != 0);
6500 /* The handle is actually a pointer to a debug info struct */
6503 /* Search for spans that cover this address */
6504 E = FindSpanInfoByAddr (&Info->SpanInfoByAddr, Addr);
6506 /* Do we have spans? */
6511 /* Prepare the struct we will return to the caller */
6512 D = new_cc65_spaninfo (E->Count);
6513 if (E->Count == 1) {
6514 CopySpanInfo (D->data, E->Data);
6516 for (I = 0; I < D->count; ++I) {
6518 CopySpanInfo (D->data + I, ((SpanInfo**) E->Data)[I]);
6523 /* Return the struct we've created */
6529 const cc65_spaninfo* cc65_span_byline (cc65_dbginfo Handle, unsigned LineId)
6530 /* Return span information for the given source line. The function returns NULL
6531 ** if the line id is invalid, otherwise the spans for this line (possibly zero).
6534 const DbgInfo* Info;
6539 /* Check the parameter */
6540 assert (Handle != 0);
6542 /* The handle is actually a pointer to a debug info struct */
6545 /* Check if the line id is valid */
6546 if (LineId >= CollCount (&Info->LineInfoById)) {
6550 /* Get the line with this id */
6551 L = CollAt (&Info->LineInfoById, LineId);
6553 /* Allocate memory for the data structure returned to the caller */
6554 D = new_cc65_spaninfo (CollCount (&L->SpanInfoList));
6556 /* Fill in the data */
6557 for (I = 0; I < CollCount (&L->SpanInfoList); ++I) {
6559 CopySpanInfo (D->data + I, CollAt (&L->SpanInfoList, I));
6562 /* Return the result */
6568 const cc65_spaninfo* cc65_span_byscope (cc65_dbginfo Handle, unsigned ScopeId)
6569 /* Return span information for the given scope. The function returns NULL if
6570 ** the scope id is invalid, otherwise the spans for this scope (possibly zero).
6573 const DbgInfo* Info;
6578 /* Check the parameter */
6579 assert (Handle != 0);
6581 /* The handle is actually a pointer to a debug info struct */
6584 /* Check if the scope id is valid */
6585 if (ScopeId >= CollCount (&Info->ScopeInfoById)) {
6589 /* Get the scope with this id */
6590 S = CollAt (&Info->ScopeInfoById, ScopeId);
6592 /* Allocate memory for the data structure returned to the caller */
6593 D = new_cc65_spaninfo (CollCount (&S->SpanInfoList));
6595 /* Fill in the data */
6596 for (I = 0; I < CollCount (&S->SpanInfoList); ++I) {
6598 CopySpanInfo (D->data + I, CollAt (&S->SpanInfoList, I));
6601 /* Return the result */
6607 void cc65_free_spaninfo (cc65_dbginfo Handle, const cc65_spaninfo* Info)
6608 /* Free a span info record */
6610 /* Just for completeness, check the handle */
6611 assert (Handle != 0);
6613 /* Just free the memory */
6614 xfree ((cc65_spaninfo*) Info);
6619 /*****************************************************************************/
6621 /*****************************************************************************/
6625 const cc65_sourceinfo* cc65_get_sourcelist (cc65_dbginfo Handle)
6626 /* Return a list of all source files */
6628 const DbgInfo* Info;
6632 /* Check the parameter */
6633 assert (Handle != 0);
6635 /* The handle is actually a pointer to a debug info struct */
6638 /* Allocate memory for the data structure returned to the caller. */
6639 D = new_cc65_sourceinfo (CollCount (&Info->FileInfoById));
6641 /* Fill in the data */
6642 for (I = 0; I < CollCount (&Info->FileInfoById); ++I) {
6644 CopyFileInfo (D->data + I, CollAt (&Info->FileInfoById, I));
6647 /* Return the result */
6653 const cc65_sourceinfo* cc65_source_byid (cc65_dbginfo Handle, unsigned Id)
6654 /* Return information about a source file with a specific id. The function
6655 ** returns NULL if the id is invalid (no such source file) and otherwise a
6656 ** cc65_sourceinfo structure with one entry that contains the requested
6657 ** source file information.
6660 const DbgInfo* Info;
6663 /* Check the parameter */
6664 assert (Handle != 0);
6666 /* The handle is actually a pointer to a debug info struct */
6669 /* Check if the id is valid */
6670 if (Id >= CollCount (&Info->FileInfoById)) {
6674 /* Allocate memory for the data structure returned to the caller */
6675 D = new_cc65_sourceinfo (1);
6677 /* Fill in the data */
6678 CopyFileInfo (D->data, CollAt (&Info->FileInfoById, Id));
6680 /* Return the result */
6687 const cc65_sourceinfo* cc65_source_bymodule (cc65_dbginfo Handle, unsigned Id)
6688 /* Return information about the source files used to build a module. The
6689 ** function returns NULL if the module id is invalid (no such module) and
6690 ** otherwise a cc65_sourceinfo structure with one entry per source file.
6693 const DbgInfo* Info;
6698 /* Check the parameter */
6699 assert (Handle != 0);
6701 /* The handle is actually a pointer to a debug info struct */
6704 /* Check if the module id is valid */
6705 if (Id >= CollCount (&Info->ModInfoById)) {
6709 /* Get a pointer to the module info */
6710 M = CollAt (&Info->ModInfoById, Id);
6712 /* Allocate memory for the data structure returned to the caller */
6713 D = new_cc65_sourceinfo (CollCount (&M->FileInfoByName));
6715 /* Fill in the data */
6716 for (I = 0; I < CollCount (&M->FileInfoByName); ++I) {
6717 CopyFileInfo (D->data + I, CollAt (&M->FileInfoByName, I));
6720 /* Return the result */
6726 void cc65_free_sourceinfo (cc65_dbginfo Handle, const cc65_sourceinfo* Info)
6727 /* Free a source info record */
6729 /* Just for completeness, check the handle */
6730 assert (Handle != 0);
6732 /* Free the memory */
6733 xfree ((cc65_sourceinfo*) Info);
6738 /*****************************************************************************/
6740 /*****************************************************************************/
6744 const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo Handle)
6745 /* Return a list of all scopes in the debug information */
6747 const DbgInfo* Info;
6751 /* Check the parameter */
6752 assert (Handle != 0);
6754 /* The handle is actually a pointer to a debug info struct */
6757 /* Allocate memory for the data structure returned to the caller */
6758 D = new_cc65_scopeinfo (CollCount (&Info->ScopeInfoById));
6760 /* Fill in the data */
6761 for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) {
6763 CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoById, I));
6766 /* Return the result */
6772 const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id)
6773 /* Return the scope with a given id. The function returns NULL if no scope
6774 ** with this id was found.
6777 const DbgInfo* Info;
6780 /* Check the parameter */
6781 assert (Handle != 0);
6783 /* The handle is actually a pointer to a debug info struct */
6786 /* Check if the id is valid */
6787 if (Id >= CollCount (&Info->ScopeInfoById)) {
6791 /* Allocate memory for the data structure returned to the caller */
6792 D = new_cc65_scopeinfo (1);
6794 /* Fill in the data */
6795 CopyScopeInfo (D->data, CollAt (&Info->ScopeInfoById, Id));
6797 /* Return the result */
6803 const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo Handle, unsigned ModId)
6804 /* Return the list of scopes for one module. The function returns NULL if no
6805 ** scope with the given id was found.
6808 const DbgInfo* Info;
6813 /* Check the parameter */
6814 assert (Handle != 0);
6816 /* The handle is actually a pointer to a debug info struct */
6819 /* Check if the module id is valid */
6820 if (ModId >= CollCount (&Info->ModInfoById)) {
6824 /* Get a pointer to the module info */
6825 M = CollAt (&Info->ModInfoById, ModId);
6827 /* Allocate memory for the data structure returned to the caller */
6828 D = new_cc65_scopeinfo (CollCount (&M->ScopeInfoByName));
6830 /* Fill in the data */
6831 for (I = 0; I < CollCount (&M->ScopeInfoByName); ++I) {
6832 CopyScopeInfo (D->data + I, CollAt (&M->ScopeInfoByName, I));
6835 /* Return the result */
6841 const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo Handle, const char* Name)
6842 /* Return the list of scopes with a given name. Returns NULL if no scope with
6843 ** the given name was found, otherwise a non empty scope list.
6846 const DbgInfo* Info;
6854 /* Check the parameter */
6855 assert (Handle != 0);
6857 /* The handle is actually a pointer to a debug info struct */
6860 /* Search for the first item with the given name */
6861 if (!FindScopeInfoByName (&Info->ScopeInfoByName, Name, &Index)) {
6866 /* Count scopes with this name */
6870 if (++I >= CollCount (&Info->ScopeInfoByName)) {
6873 S = CollAt (&Info->ScopeInfoByName, I);
6874 if (strcmp (S->Name, Name) != 0) {
6875 /* Next symbol has another name */
6881 /* Allocate memory for the data structure returned to the caller */
6882 D = new_cc65_scopeinfo (Count);
6884 /* Fill in the data */
6885 for (I = 0; I < Count; ++I, ++Index) {
6886 CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoByName, Index));
6889 /* Return the result */
6895 const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo Handle, unsigned SpanId)
6896 /* Return scope information for a a span. The function returns NULL if the
6897 ** span id is invalid, otherwise a list of line scopes.
6900 const DbgInfo* Info;
6905 /* Check the parameter */
6906 assert (Handle != 0);
6908 /* The handle is actually a pointer to a debug info struct */
6911 /* Check if the span id is valid */
6912 if (SpanId >= CollCount (&Info->SpanInfoById)) {
6917 S = CollAt (&Info->SpanInfoById, SpanId);
6919 /* Prepare the struct we will return to the caller */
6920 D = new_cc65_scopeinfo (CollCount (S->ScopeInfoList));
6922 /* Fill in the data. Since D->ScopeInfoList may be NULL, we will use the
6923 ** count field of the returned data struct instead.
6925 for (I = 0; I < D->count; ++I) {
6927 CopyScopeInfo (D->data + I, CollAt (S->ScopeInfoList, I));
6930 /* Return the allocated struct */
6936 const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo Handle, unsigned Id)
6937 /* Return the direct child scopes of a scope with a given id. The function
6938 ** returns NULL if no scope with this id was found, otherwise a list of the
6942 const DbgInfo* Info;
6947 /* Check the parameter */
6948 assert (Handle != 0);
6950 /* The handle is actually a pointer to a debug info struct */
6953 /* Check if the id is valid */
6954 if (Id >= CollCount (&Info->ScopeInfoById)) {
6959 S = CollAt (&Info->ScopeInfoById, Id);
6961 /* Allocate memory for the data structure returned to the caller */
6962 D = new_cc65_scopeinfo (CollCount (S->ChildScopeList));
6964 /* Fill in the data */
6965 for (I = 0; I < D->count; ++I) {
6966 CopyScopeInfo (D->data + I, CollAt (S->ChildScopeList, I));
6969 /* Return the result */
6975 void cc65_free_scopeinfo (cc65_dbginfo Handle, const cc65_scopeinfo* Info)
6976 /* Free a scope info record */
6978 /* Just for completeness, check the handle */
6979 assert (Handle != 0);
6981 /* Free the memory */
6982 xfree ((cc65_scopeinfo*) Info);
6987 /*****************************************************************************/
6989 /*****************************************************************************/
6993 const cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle)
6994 /* Return a list of all segments referenced in the debug information */
6996 const DbgInfo* Info;
6997 cc65_segmentinfo* D;
7000 /* Check the parameter */
7001 assert (Handle != 0);
7003 /* The handle is actually a pointer to a debug info struct */
7006 /* Allocate memory for the data structure returned to the caller */
7007 D = new_cc65_segmentinfo (CollCount (&Info->SegInfoById));
7009 /* Fill in the data */
7010 for (I = 0; I < CollCount (&Info->SegInfoById); ++I) {
7012 CopySegInfo (D->data + I, CollAt (&Info->SegInfoById, I));
7015 /* Return the result */
7021 const cc65_segmentinfo* cc65_segment_byid (cc65_dbginfo Handle, unsigned Id)
7022 /* Return information about a segment with a specific id. The function returns
7023 ** NULL if the id is invalid (no such segment) and otherwise a segmentinfo
7024 ** structure with one entry that contains the requested segment information.
7027 const DbgInfo* Info;
7028 cc65_segmentinfo* D;
7030 /* Check the parameter */
7031 assert (Handle != 0);
7033 /* The handle is actually a pointer to a debug info struct */
7036 /* Check if the id is valid */
7037 if (Id >= CollCount (&Info->SegInfoById)) {
7041 /* Allocate memory for the data structure returned to the caller */
7042 D = new_cc65_segmentinfo (1);
7044 /* Fill in the data */
7045 CopySegInfo (D->data, CollAt (&Info->SegInfoById, Id));
7047 /* Return the result */
7053 const cc65_segmentinfo* cc65_segment_byname (cc65_dbginfo Handle,
7055 /* Return information about a segment with a specific name. The function
7056 ** returns NULL if no segment with this name exists and otherwise a
7057 ** cc65_segmentinfo structure with one entry that contains the requested
7061 const DbgInfo* Info;
7063 cc65_segmentinfo* D;
7065 /* Check the parameter */
7066 assert (Handle != 0);
7068 /* The handle is actually a pointer to a debug info struct */
7071 /* Search for the segment */
7072 S = FindSegInfoByName (&Info->SegInfoByName, Name);
7077 /* Allocate memory for the data structure returned to the caller */
7078 D = new_cc65_segmentinfo (1);
7080 /* Fill in the data */
7081 CopySegInfo (D->data, S);
7083 /* Return the result */
7089 void cc65_free_segmentinfo (cc65_dbginfo Handle, const cc65_segmentinfo* Info)
7090 /* Free a segment info record */
7092 /* Just for completeness, check the handle */
7093 assert (Handle != 0);
7095 /* Free the memory */
7096 xfree ((cc65_segmentinfo*) Info);
7101 /*****************************************************************************/
7103 /*****************************************************************************/
7107 const cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id)
7108 /* Return the symbol with a given id. The function returns NULL if no symbol
7109 ** with this id was found.
7112 const DbgInfo* Info;
7115 /* Check the parameter */
7116 assert (Handle != 0);
7118 /* The handle is actually a pointer to a debug info struct */
7121 /* Check if the id is valid */
7122 if (Id >= CollCount (&Info->SymInfoById)) {
7126 /* Allocate memory for the data structure returned to the caller */
7127 D = new_cc65_symbolinfo (1);
7129 /* Fill in the data */
7130 CopySymInfo (D->data, CollAt (&Info->SymInfoById, Id));
7132 /* Return the result */
7138 const cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name)
7139 /* Return a list of symbols with a given name. The function returns NULL if
7140 ** no symbol with this name was found.
7143 const DbgInfo* Info;
7149 /* Check the parameter */
7150 assert (Handle != 0);
7152 /* The handle is actually a pointer to a debug info struct */
7155 /* Search for the symbol */
7156 if (!FindSymInfoByName (&Info->SymInfoByName, Name, &Index)) {
7161 /* Index contains the position. Count how many symbols with this name
7162 ** we have. Skip the first one, since we have at least one.
7165 while ((unsigned) Index + Count < CollCount (&Info->SymInfoByName)) {
7166 const SymInfo* S = CollAt (&Info->SymInfoByName, (unsigned) Index + Count);
7167 if (strcmp (S->Name, Name) != 0) {
7173 /* Allocate memory for the data structure returned to the caller */
7174 D = new_cc65_symbolinfo (Count);
7176 /* Fill in the data */
7177 for (I = 0; I < Count; ++I) {
7179 CopySymInfo (D->data + I, CollAt (&Info->SymInfoByName, Index++));
7182 /* Return the result */
7188 const cc65_symbolinfo* cc65_symbol_byscope (cc65_dbginfo Handle, unsigned ScopeId)
7189 /* Return a list of symbols in the given scope. This includes cheap local
7190 ** symbols, but not symbols in subscopes. The function returns NULL if the
7191 ** scope id is invalid (no such scope) and otherwise a - possibly empty -
7195 const DbgInfo* Info;
7201 /* Check the parameter */
7202 assert (Handle != 0);
7204 /* The handle is actually a pointer to a debug info struct */
7207 /* Check if the id is valid */
7208 if (ScopeId >= CollCount (&Info->ScopeInfoById)) {
7213 S = CollAt (&Info->ScopeInfoById, ScopeId);
7215 /* Allocate memory for the data structure returned to the caller */
7216 D = new_cc65_symbolinfo (CollCount (&S->SymInfoByName));
7218 /* Fill in the data */
7219 for (I = 0; I < CollCount (&S->SymInfoByName); ++I) {
7221 CopySymInfo (D->data + I, CollAt (&S->SymInfoByName, I));
7224 /* Return the result */
7230 const cc65_symbolinfo* cc65_symbol_inrange (cc65_dbginfo Handle, cc65_addr Start,
7232 /* Return a list of labels in the given range. End is inclusive. The function
7233 ** return NULL if no symbols within the given range are found. Non label
7234 ** symbols are ignored and not returned.
7237 const DbgInfo* Info;
7238 Collection SymInfoList = COLLECTION_INITIALIZER;
7243 /* Check the parameter */
7244 assert (Handle != 0);
7246 /* The handle is actually a pointer to a debug info struct */
7249 /* Search for the symbol. Because we're searching for a range, we cannot
7250 ** make use of the function result.
7252 FindSymInfoByValue (&Info->SymInfoByVal, Start, &Index);
7254 /* Start from the given index, check all symbols until the end address is
7255 ** reached. Place all symbols into SymInfoList for later.
7257 for (I = Index; I < CollCount (&Info->SymInfoByVal); ++I) {
7260 SymInfo* Item = CollAt (&Info->SymInfoByVal, I);
7262 /* The collection is sorted by address, so if we get a value larger
7263 ** than the end address, we're done.
7265 if (Item->Value > (long) End) {
7269 /* Ignore non-labels (this will also ignore imports) */
7270 if (Item->Type != CC65_SYM_LABEL) {
7274 /* Ok, remember this one */
7275 CollAppend (&SymInfoList, Item);
7278 /* If we don't have any labels within the range, bail out. No memory has
7279 ** been allocated for SymInfoList.
7281 if (CollCount (&SymInfoList) == 0) {
7285 /* Allocate memory for the data structure returned to the caller */
7286 D = new_cc65_symbolinfo (CollCount (&SymInfoList));
7288 /* Fill in the data */
7289 for (I = 0; I < CollCount (&SymInfoList); ++I) {
7291 CopySymInfo (D->data + I, CollAt (&SymInfoList, I));
7294 /* Free the collection */
7295 CollDone (&SymInfoList);
7297 /* Return the result */
7303 void cc65_free_symbolinfo (cc65_dbginfo Handle, const cc65_symbolinfo* Info)
7304 /* Free a symbol info record */
7306 /* Just for completeness, check the handle */
7307 assert (Handle != 0);
7309 /* Free the memory */
7310 xfree ((cc65_symbolinfo*) Info);
7315 /*****************************************************************************/
7317 /*****************************************************************************/
7321 const cc65_typedata* cc65_type_byid (cc65_dbginfo Handle, unsigned Id)
7322 /* Return the data for the type with the given id. The function returns NULL
7323 ** if no type with this id was found.
7326 const DbgInfo* Info;
7329 /* Check the parameter */
7330 assert (Handle != 0);
7332 /* The handle is actually a pointer to a debug info struct */
7335 /* Check if the id is valid */
7336 if (Id >= CollCount (&Info->TypeInfoById)) {
7340 /* Get the type info with the given id */
7341 T = CollAt (&Info->TypeInfoById, Id);
7343 /* We do already have the type data. Return it. */
7349 void cc65_free_typedata (cc65_dbginfo Handle, const cc65_typedata* data)
7350 /* Free a symbol info record */
7352 /* Just for completeness, check the handle and the data*/
7353 assert (Handle != 0 && data != 0);