]> git.sur5r.net Git - cc65/blob - src/ca65/dbginfo.c
add gotox, gotoy, and gotoxy
[cc65] / src / ca65 / dbginfo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 dbginfo.c                                 */
4 /*                                                                           */
5 /*                         Handle the .dbg commands                          */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2012, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* common */
39 #include "chartype.h"
40 #include "coll.h"
41 #include "filepos.h"
42 #include "hlldbgsym.h"
43 #include "scopedefs.h"
44 #include "strbuf.h"
45
46 /* ca65 */
47 #include "dbginfo.h"
48 #include "error.h"
49 #include "expr.h"
50 #include "filetab.h"
51 #include "global.h"
52 #include "lineinfo.h"
53 #include "objfile.h"
54 #include "nexttok.h"
55 #include "symentry.h"
56 #include "symtab.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Data                                    */
62 /*****************************************************************************/
63
64
65
66 /* Structure used for a high level language function or symbol */
67 typedef struct HLLDbgSym HLLDbgSym;
68 struct HLLDbgSym {
69     unsigned            Flags;          /* See above */
70     unsigned            Name;           /* String id of name */
71     unsigned            AsmName;        /* String id of asm symbol name */
72     SymEntry*           Sym;            /* The assembler symbol */
73     int                 Offs;           /* Offset if any */
74     unsigned            Type;           /* String id of type */
75     SymTable*           Scope;          /* Parent scope */
76     unsigned            FuncId;         /* Id of hll function if any */
77     FilePos             Pos;            /* Position of statement */
78 };
79
80 /* The current line info */
81 static LineInfo* CurLineInfo = 0;
82
83 /* List of high level language debug symbols */
84 static Collection HLLDbgSyms = STATIC_COLLECTION_INITIALIZER;
85
86
87
88 /*****************************************************************************/
89 /*                                   Code                                    */
90 /*****************************************************************************/
91
92
93
94 static HLLDbgSym* NewHLLDbgSym (unsigned Flags, unsigned Name, unsigned Type)
95 /* Allocate and return a new HLLDbgSym structure */
96 {
97     /* Allocate memory */
98     HLLDbgSym* S = xmalloc (sizeof (*S));
99
100     /* Initialize the fields as necessary */
101     S->Flags    = Flags;
102     S->Name     = Name;
103     S->AsmName  = EMPTY_STRING_ID;
104     S->Sym      = 0;
105     S->Offs     = 0;
106     S->Type     = Type;
107     S->Scope    = CurrentScope;
108     S->FuncId   = ~0U;
109     S->Pos      = CurTok.Pos;
110
111     /* Return the result */
112     return S;
113 }
114
115
116
117 static unsigned HexValue (char C)
118 /* Convert the ascii representation of a hex nibble into the hex nibble */
119 {
120     if (isdigit (C)) {
121         return C - '0';
122     } else if (islower (C)) {
123         return C - 'a' + 10;
124     } else {
125         return C - 'A' + 10;
126     }
127 }
128
129
130
131 static int ValidateType (StrBuf* Type)
132 /* Check if the given type is valid and if so, return a string id for it. If
133  * the type isn't valid, return -1. Type is overwritten when checking.
134  */
135 {
136     unsigned        I;
137     const char*     A;
138     char*           B;
139
140
141     /* The length must not be zero and divideable by two */
142     unsigned Length = SB_GetLen (Type);
143     if (Length < 2 || (Length & 0x01) != 0) {
144         ErrorSkip ("Type value has invalid length");
145         return -1;
146     }
147
148     /* The string must consist completely of hex digit chars */
149     A = SB_GetConstBuf (Type);
150     for (I = 0; I < Length; ++I) {
151         if (!IsXDigit (A[I])) {
152             ErrorSkip ("Type value contains invalid characters");
153             return -1;
154         }
155     }
156
157     /* Convert the type to binary */
158     B = SB_GetBuf (Type);
159     while (A < SB_GetConstBuf (Type) + Length) {
160         /* Since we know, there are only hex digits, there can't be any errors */
161         *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]);
162         A += 2;
163     }
164     Type->Len = (Length /= 2);
165
166     /* Allocate the type and return it */
167     return GetStrBufId (Type);
168 }
169
170
171
172 void DbgInfoFile (void)
173 /* Parse and handle FILE subcommand of the .dbg pseudo instruction */
174 {
175     StrBuf Name = STATIC_STRBUF_INITIALIZER;
176     unsigned long Size;
177     unsigned long MTime;
178
179     /* Parameters are separated by a comma */
180     ConsumeComma ();
181
182     /* Name */
183     if (CurTok.Tok != TOK_STRCON) {
184         ErrorSkip ("String constant expected");
185         return;
186     }
187     SB_Copy (&Name, &CurTok.SVal);
188     NextTok ();
189
190     /* Comma expected */
191     ConsumeComma ();
192
193     /* Size */
194     Size = ConstExpression ();
195
196     /* Comma expected */
197     ConsumeComma ();
198
199     /* MTime */
200     MTime = ConstExpression ();
201
202     /* Insert the file into the table */
203     AddFile (&Name, FT_DBGINFO, Size, MTime);
204
205     /* Free memory used for Name */
206     SB_Done (&Name);
207 }
208
209
210
211 void DbgInfoFunc (void)
212 /* Parse and handle func subcommand of the .dbg pseudo instruction */
213 {
214     static const char* StorageKeys[] = {
215         "EXTERN",
216         "STATIC",
217     };
218
219     unsigned    Name;
220     int         Type;
221     unsigned    AsmName;
222     unsigned    Flags;
223     HLLDbgSym*  S;
224
225
226     /* Parameters are separated by a comma */
227     ConsumeComma ();
228
229     /* Name */
230     if (CurTok.Tok != TOK_STRCON) {
231         ErrorSkip ("String constant expected");
232         return;
233     }
234     Name = GetStrBufId (&CurTok.SVal);
235     NextTok ();
236
237     /* Comma expected */
238     ConsumeComma ();
239
240     /* Type */
241     if (CurTok.Tok != TOK_STRCON) {
242         ErrorSkip ("String constant expected");
243         return;
244     }
245     Type = ValidateType (&CurTok.SVal);
246     if (Type < 0) {
247         return;
248     }
249     NextTok ();
250
251     /* Comma expected */
252     ConsumeComma ();
253
254     /* The storage class follows */
255     if (CurTok.Tok != TOK_IDENT) {
256         ErrorSkip ("Storage class specifier expected");
257         return;
258     }
259     switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) {
260         case 0:   Flags = HLL_TYPE_FUNC | HLL_SC_EXTERN;            break;
261         case 1:   Flags = HLL_TYPE_FUNC | HLL_SC_STATIC;            break;
262         default:  ErrorSkip ("Storage class specifier expected");   return;
263     }
264     NextTok ();
265
266     /* Comma expected */
267     ConsumeComma ();
268
269     /* Assembler name follows */
270     if (CurTok.Tok != TOK_STRCON) {
271         ErrorSkip ("String constant expected");
272         return;
273     }
274     AsmName = GetStrBufId (&CurTok.SVal);
275     NextTok ();
276
277     /* There may only be one function per scope */
278     if (CurrentScope == RootScope) {
279         ErrorSkip ("Functions may not be used in the root scope");
280         return;
281     } else if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) {
282         ErrorSkip ("Functions can only be tagged to .PROC scopes");
283         return;
284     } else if (CurrentScope->Label->HLLSym != 0) {
285         ErrorSkip ("Only one HLL symbol per asm symbol is allowed");
286         return;
287     } else if (CurrentScope->Label->Name != AsmName) {
288         ErrorSkip ("Scope label and asm name for function must match");
289         return;
290     }
291
292     /* Add the function */
293     S = NewHLLDbgSym (Flags, Name, Type);
294     S->Sym = CurrentScope->Label;
295     CurrentScope->Label->HLLSym = S;
296     CollAppend (&HLLDbgSyms, S);
297 }
298
299
300
301 void DbgInfoLine (void)
302 /* Parse and handle LINE subcommand of the .dbg pseudo instruction */
303 {
304     long Line;
305     FilePos Pos = STATIC_FILEPOS_INITIALIZER;
306
307     /* Any new line info terminates the last one */
308     if (CurLineInfo) {
309         EndLine (CurLineInfo);
310         CurLineInfo = 0;
311     }
312
313     /* If a parameters follow, this is actual line info. If no parameters
314      * follow, the last line info is terminated.
315      */
316     if (CurTok.Tok == TOK_SEP) {
317         return;
318     }
319
320     /* Parameters are separated by a comma */
321     ConsumeComma ();
322
323     /* The name of the file follows */
324     if (CurTok.Tok != TOK_STRCON) {
325         ErrorSkip ("String constant expected");
326         return;
327     }
328
329     /* Get the index in the file table for the name */
330     Pos.Name = GetFileIndex (&CurTok.SVal);
331
332     /* Skip the name */
333     NextTok ();
334
335     /* Comma expected */
336     ConsumeComma ();
337
338     /* Line number */
339     Line = ConstExpression ();
340     if (Line < 0) {
341         ErrorSkip ("Line number is out of valid range");
342         return;
343     }
344     Pos.Line = Line;
345
346     /* Generate a new external line info */
347     CurLineInfo = StartLine (&Pos, LI_TYPE_EXT, 0);
348 }
349
350
351
352 void DbgInfoSym (void)
353 /* Parse and handle SYM subcommand of the .dbg pseudo instruction */
354 {
355     static const char* StorageKeys[] = {
356         "AUTO",
357         "EXTERN",
358         "REGISTER",
359         "STATIC",
360     };
361
362     unsigned    Name;
363     int         Type;
364     unsigned    AsmName = EMPTY_STRING_ID;
365     unsigned    Flags;
366     int         Offs = 0;
367     HLLDbgSym*  S;
368
369
370     /* Parameters are separated by a comma */
371     ConsumeComma ();
372
373     /* Name */
374     if (CurTok.Tok != TOK_STRCON) {
375         ErrorSkip ("String constant expected");
376         return;
377     }
378     Name = GetStrBufId (&CurTok.SVal);
379     NextTok ();
380
381     /* Comma expected */
382     ConsumeComma ();
383
384     /* Type */
385     if (CurTok.Tok != TOK_STRCON) {
386         ErrorSkip ("String constant expected");
387         return;
388     }
389     Type = ValidateType (&CurTok.SVal);
390     if (Type < 0) {
391         return;
392     }
393     NextTok ();
394
395     /* Comma expected */
396     ConsumeComma ();
397
398     /* The storage class follows */
399     if (CurTok.Tok != TOK_IDENT) {
400         ErrorSkip ("Storage class specifier expected");
401         return;
402     }
403     switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) {
404         case 0:   Flags = HLL_SC_AUTO;                              break;
405         case 1:   Flags = HLL_SC_EXTERN;                            break;
406         case 2:   Flags = HLL_SC_REG;                               break;
407         case 3:   Flags = HLL_SC_STATIC;                            break;
408         default:  ErrorSkip ("Storage class specifier expected");   return;
409     }
410
411     /* Skip the storage class token and the following comma */
412     NextTok ();
413     ConsumeComma ();
414
415     /* The next tokens depend on the storage class */
416     if (Flags == HLL_SC_AUTO) {
417         /* Auto: Stack offset follows */
418         Offs = ConstExpression ();
419     } else {
420         /* Register, extern or static: Assembler name follows */
421         if (CurTok.Tok != TOK_STRCON) {
422             ErrorSkip ("String constant expected");
423             return;
424         }
425         AsmName = GetStrBufId (&CurTok.SVal);
426         NextTok ();
427
428         /* For register, an offset follows */
429         if (Flags == HLL_SC_REG) {
430             ConsumeComma ();
431             Offs = ConstExpression ();
432         }
433     }
434
435     /* Add the function */
436     S = NewHLLDbgSym (Flags | HLL_TYPE_SYM, Name, Type);
437     S->AsmName = AsmName;
438     S->Offs    = Offs;
439     CollAppend (&HLLDbgSyms, S);
440 }
441
442
443
444 void DbgInfoCheck (void)
445 /* Do checks on all hll debug info symbols when assembly is complete */
446 {
447     /* When parsing the debug statements for HLL symbols, we have already
448      * tagged the functions to their asm counterparts. This wasn't done for
449      * C symbols, since we will allow forward declarations. So we have to
450      * resolve the normal C symbols now.
451      */
452     unsigned I;
453     for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
454
455         /* Get the next symbol */
456         HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
457
458         /* Ignore functions and auto symbols, because the later live on the
459          * stack and don't have corresponding asm symbols.
460          */
461         if (HLL_IS_FUNC (S->Flags) || HLL_GET_SC (S->Flags) == HLL_SC_AUTO) {
462             continue;
463         }
464
465         /* Safety */
466         CHECK (S->Sym == 0 && S->Scope != 0);
467
468         /* Search for the symbol name */
469         S->Sym = SymFindAny (S->Scope, GetStrBuf (S->AsmName));
470         if (S->Sym == 0) {
471             PError (&S->Pos, "Assembler symbol `%s' not found",
472                     GetString (S->AsmName));
473         } else {
474             /* Set the backlink */
475             S->Sym->HLLSym = S;
476         }
477
478     }
479 }
480
481
482
483 void WriteHLLDbgSyms (void)
484 /* Write a list of all high level language symbols to the object file. */
485 {
486     unsigned I;
487
488     /* Only if debug info is enabled */
489     if (DbgSyms) {
490
491         /* Write the symbol count to the list */
492         ObjWriteVar (CollCount (&HLLDbgSyms));
493
494         /* Walk through list and write all symbols to the file. */
495         for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
496
497             /* Get the next symbol */
498             HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
499
500             /* Get the type of the symbol */
501             unsigned SC = HLL_GET_SC (S->Flags);
502
503             /* Remember if the symbol has debug info attached
504              * ### This should go into DbgInfoCheck
505              */
506             if (S->Sym && S->Sym->DebugSymId != ~0U) {
507                 S->Flags |= HLL_DATA_SYM;
508             }
509
510             /* Write the symbol data */
511             ObjWriteVar (S->Flags);
512             ObjWriteVar (S->Name);
513             if (HLL_HAS_SYM (S->Flags)) {
514                 ObjWriteVar (S->Sym->DebugSymId);
515             }
516             if (SC == HLL_SC_AUTO || SC == HLL_SC_REG) {
517                 ObjWriteVar (S->Offs);
518             }
519             ObjWriteVar (S->Type);
520             ObjWriteVar (S->Scope->Id);
521         }
522
523     } else {
524
525         /* Write a count of zero */
526         ObjWriteVar (0);
527
528     }
529 }
530
531
532