1 /*****************************************************************************/
5 /* Handle the .dbg commands */
9 /* (C) 2000-2012, 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 /*****************************************************************************/
42 #include "hlldbgsym.h"
43 #include "scopedefs.h"
60 /*****************************************************************************/
62 /*****************************************************************************/
66 /* Structure used for a high level language function or symbol */
67 typedef struct HLLDbgSym 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 */
80 /* The current line info */
81 static LineInfo* CurLineInfo = 0;
83 /* List of high level language debug symbols */
84 static Collection HLLDbgSyms = STATIC_COLLECTION_INITIALIZER;
88 /*****************************************************************************/
90 /*****************************************************************************/
94 static HLLDbgSym* NewHLLDbgSym (unsigned Flags, unsigned Name, unsigned Type)
95 /* Allocate and return a new HLLDbgSym structure */
98 HLLDbgSym* S = xmalloc (sizeof (*S));
100 /* Initialize the fields as necessary */
103 S->AsmName = EMPTY_STRING_ID;
107 S->Scope = CurrentScope;
111 /* Return the result */
117 static unsigned HexValue (char C)
118 /* Convert the ascii representation of a hex nibble into the hex nibble */
122 } else if (islower (C)) {
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.
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");
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");
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]);
164 Type->Len = (Length /= 2);
166 /* Allocate the type and return it */
167 return GetStrBufId (Type);
172 void DbgInfoFile (void)
173 /* Parse and handle FILE subcommand of the .dbg pseudo instruction */
175 StrBuf Name = STATIC_STRBUF_INITIALIZER;
179 /* Parameters are separated by a comma */
183 if (CurTok.Tok != TOK_STRCON) {
184 ErrorSkip ("String constant expected");
187 SB_Copy (&Name, &CurTok.SVal);
194 Size = ConstExpression ();
200 MTime = ConstExpression ();
202 /* Insert the file into the table */
203 AddFile (&Name, FT_DBGINFO, Size, MTime);
205 /* Free memory used for Name */
211 void DbgInfoFunc (void)
212 /* Parse and handle func subcommand of the .dbg pseudo instruction */
214 static const char* const StorageKeys[] = {
226 /* Parameters are separated by a comma */
230 if (CurTok.Tok != TOK_STRCON) {
231 ErrorSkip ("String constant expected");
234 Name = GetStrBufId (&CurTok.SVal);
241 if (CurTok.Tok != TOK_STRCON) {
242 ErrorSkip ("String constant expected");
245 Type = ValidateType (&CurTok.SVal);
254 /* The storage class follows */
255 if (CurTok.Tok != TOK_IDENT) {
256 ErrorSkip ("Storage class specifier expected");
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;
269 /* Assembler name follows */
270 if (CurTok.Tok != TOK_STRCON) {
271 ErrorSkip ("String constant expected");
274 AsmName = GetStrBufId (&CurTok.SVal);
277 /* There may only be one function per scope */
278 if (CurrentScope == RootScope) {
279 ErrorSkip ("Functions may not be used in the root scope");
281 } else if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) {
282 ErrorSkip ("Functions can only be tagged to .PROC scopes");
284 } else if (CurrentScope->Label->HLLSym != 0) {
285 ErrorSkip ("Only one HLL symbol per asm symbol is allowed");
287 } else if (CurrentScope->Label->Name != AsmName) {
288 ErrorSkip ("Scope label and asm name for function must match");
292 /* Add the function */
293 S = NewHLLDbgSym (Flags, Name, Type);
294 S->Sym = CurrentScope->Label;
295 CurrentScope->Label->HLLSym = S;
296 CollAppend (&HLLDbgSyms, S);
301 void DbgInfoLine (void)
302 /* Parse and handle LINE subcommand of the .dbg pseudo instruction */
305 FilePos Pos = STATIC_FILEPOS_INITIALIZER;
307 /* Any new line info terminates the last one */
309 EndLine (CurLineInfo);
313 /* If a parameters follow, this is actual line info. If no parameters
314 ** follow, the last line info is terminated.
316 if (CurTok.Tok == TOK_SEP) {
320 /* Parameters are separated by a comma */
323 /* The name of the file follows */
324 if (CurTok.Tok != TOK_STRCON) {
325 ErrorSkip ("String constant expected");
329 /* Get the index in the file table for the name */
330 Pos.Name = GetFileIndex (&CurTok.SVal);
339 Line = ConstExpression ();
341 ErrorSkip ("Line number is out of valid range");
346 /* Generate a new external line info */
347 CurLineInfo = StartLine (&Pos, LI_TYPE_EXT, 0);
352 void DbgInfoSym (void)
353 /* Parse and handle SYM subcommand of the .dbg pseudo instruction */
355 static const char* const StorageKeys[] = {
364 unsigned AsmName = EMPTY_STRING_ID;
370 /* Parameters are separated by a comma */
374 if (CurTok.Tok != TOK_STRCON) {
375 ErrorSkip ("String constant expected");
378 Name = GetStrBufId (&CurTok.SVal);
385 if (CurTok.Tok != TOK_STRCON) {
386 ErrorSkip ("String constant expected");
389 Type = ValidateType (&CurTok.SVal);
398 /* The storage class follows */
399 if (CurTok.Tok != TOK_IDENT) {
400 ErrorSkip ("Storage class specifier expected");
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;
411 /* Skip the storage class token and the following comma */
415 /* The next tokens depend on the storage class */
416 if (Flags == HLL_SC_AUTO) {
417 /* Auto: Stack offset follows */
418 Offs = ConstExpression ();
420 /* Register, extern or static: Assembler name follows */
421 if (CurTok.Tok != TOK_STRCON) {
422 ErrorSkip ("String constant expected");
425 AsmName = GetStrBufId (&CurTok.SVal);
428 /* For register, an offset follows */
429 if (Flags == HLL_SC_REG) {
431 Offs = ConstExpression ();
435 /* Add the function */
436 S = NewHLLDbgSym (Flags | HLL_TYPE_SYM, Name, Type);
437 S->AsmName = AsmName;
439 CollAppend (&HLLDbgSyms, S);
444 void DbgInfoCheck (void)
445 /* Do checks on all hll debug info symbols when assembly is complete */
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.
453 for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
455 /* Get the next symbol */
456 HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
458 /* Ignore functions and auto symbols, because the later live on the
459 ** stack and don't have corresponding asm symbols.
461 if (HLL_IS_FUNC (S->Flags) || HLL_GET_SC (S->Flags) == HLL_SC_AUTO) {
466 CHECK (S->Sym == 0 && S->Scope != 0);
468 /* Search for the symbol name */
469 S->Sym = SymFindAny (S->Scope, GetStrBuf (S->AsmName));
471 PError (&S->Pos, "Assembler symbol `%s' not found",
472 GetString (S->AsmName));
474 /* Set the backlink */
483 void WriteHLLDbgSyms (void)
484 /* Write a list of all high level language symbols to the object file. */
488 /* Only if debug info is enabled */
491 /* Write the symbol count to the list */
492 ObjWriteVar (CollCount (&HLLDbgSyms));
494 /* Walk through list and write all symbols to the file. */
495 for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
497 /* Get the next symbol */
498 HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
500 /* Get the type of the symbol */
501 unsigned SC = HLL_GET_SC (S->Flags);
503 /* Remember if the symbol has debug info attached
504 ** ### This should go into DbgInfoCheck
506 if (S->Sym && S->Sym->DebugSymId != ~0U) {
507 S->Flags |= HLL_DATA_SYM;
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);
516 if (SC == HLL_SC_AUTO || SC == HLL_SC_REG) {
517 ObjWriteVar (S->Offs);
519 ObjWriteVar (S->Type);
520 ObjWriteVar (S->Scope->Id);
525 /* Write a count of zero */