diff --git a/src/ar65/objfile.c b/src/ar65/objfile.c index c8df70e59..bfc3dd175 100644 --- a/src/ar65/objfile.c +++ b/src/ar65/objfile.c @@ -217,6 +217,11 @@ void ObjReadData (FILE* F, ObjData* O) (void) Read32 (F); } + /* Skip the size if necessary */ + if (SYM_HAS_SIZE (Type)) { + (void) ReadVar (F); + } + /* Line info indices */ SkipLineInfoList (F); } diff --git a/src/ca65/enum.c b/src/ca65/enum.c index 8b123e180..87d0380cc 100644 --- a/src/ca65/enum.c +++ b/src/ca65/enum.c @@ -65,7 +65,7 @@ void DoEnum (void) int Anon = (CurTok.Tok != TOK_IDENT); if (!Anon) { /* Enter a new scope, then skip the name */ - SymEnterLevel (&CurTok.SVal, ST_ENUM, ADDR_SIZE_ABS); + SymEnterLevel (&CurTok.SVal, ST_ENUM, ADDR_SIZE_ABS, 0); NextTok (); } diff --git a/src/ca65/main.c b/src/ca65/main.c index b51c88b76..800c8397b 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -479,7 +479,7 @@ static void OptListBytes (const char* Opt, const char* Arg) static void OptListing (const char* Opt, const char* Arg) /* Create a listing file */ -{ +{ /* Since the meaning of -l and --listing has changed, print an error if * the filename is empty or begins with the option char. */ @@ -868,7 +868,7 @@ int main (int argc, char* argv []) /* Enter the base lexical level. We must do that here, since we may * define symbols using -D. */ - SymEnterLevel (&GlobalNameSpace, ST_GLOBAL, ADDR_SIZE_DEFAULT); + SymEnterLevel (&GlobalNameSpace, ST_GLOBAL, ADDR_SIZE_DEFAULT, 0); /* Initialize the line infos. Must be done here, since we need line infos * for symbol definitions. diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 5437f0740..c1736d9da 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -1508,12 +1508,12 @@ static void DoProc (void) { StrBuf Name = STATIC_STRBUF_INITIALIZER; unsigned char AddrSize; + SymEntry* Sym = 0; + if (CurTok.Tok == TOK_IDENT) { - SymEntry* Sym; - - /* The new scope has a name. Remember it. */ + /* The new scope has a name. Remember it. */ SB_Copy (&Name, &CurTok.SVal); /* Search for the symbol, generate a new one if needed */ @@ -1538,7 +1538,7 @@ static void DoProc (void) } /* Enter a new scope */ - SymEnterLevel (&Name, ST_PROC, AddrSize); + SymEnterLevel (&Name, ST_PROC, AddrSize, Sym); /* Free memory for Name */ SB_Done (&Name); @@ -1665,7 +1665,7 @@ static void DoScope (void) AddrSize = OptionalAddrSize (); /* Enter the new scope */ - SymEnterLevel (&Name, ST_SCOPE, AddrSize); + SymEnterLevel (&Name, ST_SCOPE, AddrSize, 0); /* Free memory for Name */ SB_Done (&Name); diff --git a/src/ca65/sizeof.c b/src/ca65/sizeof.c index ba2b2281d..8d16b72bf 100644 --- a/src/ca65/sizeof.c +++ b/src/ca65/sizeof.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2003-2008, Ullrich von Bassewit */ +/* (C) 2003-2011, Ullrich von Bassewit */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -44,7 +44,7 @@ /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ @@ -52,7 +52,7 @@ /* The name of the symbol used to encode the size. The name of this entry is * choosen so that it cannot be accessed by the user. */ -const StrBuf SizeEntryName = LIT_STRBUF_INITIALIZER (".size"); +static const StrBuf SizeEntryName = LIT_STRBUF_INITIALIZER (".size"); @@ -62,6 +62,36 @@ const StrBuf SizeEntryName = LIT_STRBUF_INITIALIZER (".size"); +int IsSizeOfSymbol (const SymEntry* Sym) +/* Return true if the given symbol is the one that encodes the size of some + * entity. Sym may also be a NULL pointer in which case false is returned. + */ +{ + return (Sym != 0 && SB_Compare (GetSymName (Sym), &SizeEntryName) == 0); +} + + + +SymEntry* FindSizeOfScope (SymTable* Scope) +/* Get the size of a scope. The function returns the symbol table entry that + * encodes the size or NULL if there is no such entry. + */ +{ + return SymFind (Scope, &SizeEntryName, SYM_FIND_EXISTING); +} + + + +SymEntry* FindSizeOfSymbol (SymEntry* Sym) +/* Get the size of a symbol table entry. The function returns the symbol table + * entry that encodes the size of the symbol or NULL if there is no such entry. + */ +{ + return SymFindLocal (Sym, &SizeEntryName, SYM_FIND_EXISTING); +} + + + SymEntry* GetSizeOfScope (SymTable* Scope) /* Get the size of a scope. The function returns the symbol table entry that * encodes the size, and will create a new entry if it does not exist. diff --git a/src/ca65/sizeof.h b/src/ca65/sizeof.h index d77ddf210..7dcca1421 100644 --- a/src/ca65/sizeof.h +++ b/src/ca65/sizeof.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2003-2008, Ullrich von Bassewitz */ +/* (C) 2003-2011, Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -35,7 +35,7 @@ #ifndef SIZEOF_H #define SIZEOF_H - + /* common */ @@ -54,22 +54,27 @@ struct SymTable; -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -extern const StrBuf SizeEntryName; /* Contains name of symbol with size */ - - - /*****************************************************************************/ /* Code */ /*****************************************************************************/ +int IsSizeOfSymbol (const struct SymEntry* Sym); +/* Return true if the given symbol is the one that encodes the size of some + * entity. Sym may also be a NULL pointer in which case false is returned. + */ + +struct SymEntry* FindSizeOfScope (struct SymTable* Scope); +/* Get the size of a scope. The function returns the symbol table entry that + * encodes the size or NULL if there is no such entry. + */ + +struct SymEntry* FindSizeOfSymbol (struct SymEntry* Sym); +/* Get the size of a symbol table entry. The function returns the symbol table + * entry that encodes the size of the symbol or NULL if there is no such entry. + */ + struct SymEntry* GetSizeOfScope (struct SymTable* Scope); /* Get the size of a scope. The function returns the symbol table entry that * encodes the size, and will create a new entry if it does not exist. diff --git a/src/ca65/struct.c b/src/ca65/struct.c index 56b9856f4..2b27912f1 100644 --- a/src/ca65/struct.c +++ b/src/ca65/struct.c @@ -106,7 +106,7 @@ static long DoStructInternal (long Offs, unsigned Type) int Anon = (CurTok.Tok != TOK_IDENT); if (!Anon) { /* Enter a new scope, then skip the name */ - SymEnterLevel (&CurTok.SVal, ST_STRUCT, ADDR_SIZE_ABS); + SymEnterLevel (&CurTok.SVal, ST_STRUCT, ADDR_SIZE_ABS, 0); NextTok (); /* Start at zero offset in the new scope */ Offs = 0; @@ -116,8 +116,8 @@ static long DoStructInternal (long Offs, unsigned Type) ConsumeSep (); /* Read until end of struct */ - while (CurTok.Tok != TOK_ENDSTRUCT && - CurTok.Tok != TOK_ENDUNION && + while (CurTok.Tok != TOK_ENDSTRUCT && + CurTok.Tok != TOK_ENDUNION && CurTok.Tok != TOK_EOF) { long MemberSize; @@ -263,12 +263,12 @@ static long DoStructInternal (long Offs, unsigned Type) long GetStructSize (SymTable* Struct) /* Get the size of a struct or union */ { - SymEntry* Sym = SymFind (Struct, &SizeEntryName, SYM_FIND_EXISTING); - if (Sym == 0) { + SymEntry* SizeSym = FindSizeOfScope (Struct); + if (SizeSym == 0) { Error ("Size of struct/union is unknown"); return 0; } else { - return GetSymVal (Sym); + return GetSymVal (SizeSym); } } diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c index 661c05f6d..356f7386d 100644 --- a/src/ca65/symtab.c +++ b/src/ca65/symtab.c @@ -112,6 +112,7 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name) S->Left = 0; S->Right = 0; S->Childs = 0; + S->OwnerSym = 0; S->SegRanges = AUTO_COLLECTION_INITIALIZER; S->Flags = ST_NONE; S->AddrSize = ADDR_SIZE_DEFAULT; @@ -160,7 +161,7 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name) } else { T->Right = S; break; - } + } } else { /* Duplicate scope name */ Internal ("Duplicate scope name: `%m%p'", Name); @@ -181,7 +182,8 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name) -void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, unsigned char AddrSize) +void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, + unsigned char AddrSize, SymEntry* OwnerSym) /* Enter a new lexical level */ { /* Map a default address size to something real */ @@ -207,10 +209,11 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, unsigned char A CurrentScope = RootScope = NewSymTable (0, ScopeName); } - /* Mark the scope as defined and set type and address size */ + /* Mark the scope as defined and set type, address size and owner symbol */ CurrentScope->Flags |= ST_DEFINED; CurrentScope->AddrSize = AddrSize; CurrentScope->Type = Type; + CurrentScope->OwnerSym = OwnerSym; /* If this is a scope that allows to emit data into segments, add segment * ranges for all currently existing segments. Doing this for just a few @@ -235,11 +238,16 @@ void SymLeaveLevel (void) /* If we have segment ranges, the first one is the segment that was * active, when the scope was opened. Set the size of the scope to the - * number of data bytes emitted into this segment. + * number of data bytes emitted into this segment. If we have an owner + * symbol set the size of this symbol, too. */ if (CollCount (&CurrentScope->SegRanges) > 0) { const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0); - DefSizeOfScope (CurrentScope, GetSegRangeSize (R)); + unsigned long Size = GetSegRangeSize (R); + DefSizeOfScope (CurrentScope, Size); + if (CurrentScope->OwnerSym) { + DefSizeOfSymbol (CurrentScope->OwnerSym, Size); + } } /* Leave the scope */ @@ -502,7 +510,7 @@ static void SymCheckUndefined (SymEntry* S) /* The symbol is definitely undefined */ if (S->Flags & SF_EXPORT) { /* We will not auto-import an export */ - LIError (&S->LineInfos, + LIError (&S->LineInfos, "Exported symbol `%m%p' was never defined", GetSymName (S)); } else { @@ -513,8 +521,8 @@ static void SymCheckUndefined (SymEntry* S) S->AddrSize = CodeAddrSize; } else { /* Error */ - LIError (&S->LineInfos, - "Symbol `%m%p' is undefined", + LIError (&S->LineInfos, + "Symbol `%m%p' is undefined", GetSymName (S)); } } @@ -727,6 +735,15 @@ void WriteExports (void) long ConstVal; unsigned ExprMask = GetSymInfoFlags (S, &ConstVal); + /* Check if this symbol has a size. If so, remember it in the + * flags. + */ + long Size; + SymEntry* SizeSym = FindSizeOfSymbol (S); + if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) { + ExprMask |= SYM_SIZE; + } + /* Count the number of ConDes types */ for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { if (S->ConDesPrio[Type] != CD_PRIO_NONE) { @@ -760,6 +777,11 @@ void WriteExports (void) WriteExpr (S->Expr); } + /* If the symbol has a size, write it to the file */ + if (SYM_HAS_SIZE (ExprMask)) { + ObjWriteVar (Size); + } + /* Write the line infos */ WriteLineInfo (&S->LineInfos); } @@ -788,7 +810,8 @@ void WriteDbgSyms (void) Count = 0; S = SymList; while (S) { - if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) { + if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL && + !IsSizeOfSymbol (S)) { S->DebugSymId = Count++; } S = S->List; @@ -797,15 +820,27 @@ void WriteDbgSyms (void) /* Write the symbol count to the list */ ObjWriteVar (Count); - /* Walk through list and write all symbols to the file */ + /* Walk through list and write all symbols to the file. Ignore size + * symbols. + */ S = SymList; while (S) { - if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) { + if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL && + !IsSizeOfSymbol (S)) { /* Get the expression bits and the value */ long ConstVal; unsigned ExprMask = GetSymInfoFlags (S, &ConstVal); + /* Check if this symbol has a size. If so, remember it in the + * flags. + */ + long Size; + SymEntry* SizeSym = FindSizeOfSymbol (S); + if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) { + ExprMask |= SYM_SIZE; + } + /* Write the type */ ObjWriteVar (ExprMask); @@ -824,6 +859,11 @@ void WriteDbgSyms (void) WriteExpr (S->Expr); } + /* If the symbol has a size, write it to the file */ + if (SYM_HAS_SIZE (ExprMask)) { + ObjWriteVar (Size); + } + /* Write the line infos */ WriteLineInfo (&S->LineInfos); } diff --git a/src/ca65/symtab.h b/src/ca65/symtab.h index 9761da025..96873e061 100644 --- a/src/ca65/symtab.h +++ b/src/ca65/symtab.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2010, Ullrich von Bassewitz */ +/* (C) 1998-2011, Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -73,12 +73,13 @@ enum { /* A symbol table */ typedef struct SymTable SymTable; -struct SymTable { +struct SymTable { SymTable* Next; /* Pointer to next table in list */ SymTable* Left; /* Pointer to smaller entry */ SymTable* Right; /* Pointer to greater entry */ SymTable* Parent; /* Link to enclosing scope if any */ SymTable* Childs; /* Pointer to child scopes */ + SymEntry* OwnerSym; /* Symbol that "owns" the scope */ Collection SegRanges; /* Segment ranges for this scope */ unsigned Id; /* Scope id */ unsigned short Flags; /* Symbol table flags */ @@ -103,7 +104,8 @@ extern SymTable* RootScope; /* Root symbol table */ -void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, unsigned char AddrSize); +void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, + unsigned char AddrSize, SymEntry* OwnerSym); /* Enter a new lexical level */ void SymLeaveLevel (void); diff --git a/src/common/lidefs.h b/src/common/lidefs.h index ac45dd234..1a85dba5d 100644 --- a/src/common/lidefs.h +++ b/src/common/lidefs.h @@ -48,6 +48,7 @@ #define LI_TYPE_ASM 0U /* Normal assembler source */ #define LI_TYPE_EXT 1U /* Externally supplied line info */ #define LI_TYPE_MACRO 2U /* Macro expansion */ +#define LI_TYPE_MACPARAM 3U /* Macro parameter expansion */ /* Make a combined value from type and count */ #define LI_MAKE_TYPE(T,C) ((T) | (((unsigned)(C)) << 2U)) diff --git a/src/common/objdefs.h b/src/common/objdefs.h index ad41c1952..1a0de3c4c 100644 --- a/src/common/objdefs.h +++ b/src/common/objdefs.h @@ -46,7 +46,7 @@ /* Defines for magic and version */ #define OBJ_MAGIC 0x616E7A55 -#define OBJ_VERSION 0x000D +#define OBJ_VERSION 0x000E /* Size of an object file header */ #define OBJ_HDR_SIZE (22*4) diff --git a/src/common/symdefs.h b/src/common/symdefs.h index 3b9018a6e..b0a8648f1 100644 --- a/src/common/symdefs.h +++ b/src/common/symdefs.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2010, Ullrich von Bassewitz */ +/* (C) 1998-2011, Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -55,6 +55,13 @@ #define SYM_GET_CONDES_COUNT(x) ((x) & SYM_CONDES_MASK) #define SYM_INC_CONDES_COUNT(x) ((x)++) +/* Size of symbol available? */ +#define SYM_SIZELESS 0x00U /* No symbol size available */ +#define SYM_SIZE 0x08U /* Symbol has a size */ +#define SYM_MASK_SIZE 0x08U /* Size mask */ + +#define SYM_HAS_SIZE(x) (((x) & SYM_MASK_SIZE) == SYM_SIZE) + /* Symbol value type */ #define SYM_CONST 0x00U /* Mask bit for const values */ #define SYM_EXPR 0x10U /* Mask bit for expr values */ @@ -71,7 +78,7 @@ #define SYM_IS_EQUATE(x) (((x) & SYM_MASK_LABEL) == SYM_EQUATE) #define SYM_IS_LABEL(x) (((x) & SYM_MASK_LABEL) == SYM_LABEL) -/* Symbol type */ +/* Symbol type */ #define SYM_STD 0x00U /* Standard symbol */ #define SYM_CHEAP_LOCAL 0x40U /* Cheap local symbol */ #define SYM_MASK_TYPE 0x40U /* Value mask */ diff --git a/src/dbginfo/dbginfo.c b/src/dbginfo/dbginfo.c index ce32b4202..3195a6921 100644 --- a/src/dbginfo/dbginfo.c +++ b/src/dbginfo/dbginfo.c @@ -57,7 +57,7 @@ /* Version numbers of the debug format we understand */ #define VER_MAJOR 1U -#define VER_MINOR 1U +#define VER_MINOR 2U /* Dynamic strings */ typedef struct StrBuf StrBuf; @@ -127,7 +127,8 @@ typedef enum { TOK_PLUS, /* + */ TOK_EOL, /* \n */ - TOK_ABSOLUTE, /* ABSOLUTE keyword */ + TOK_FIRST_KEYWORD, + TOK_ABSOLUTE = TOK_FIRST_KEYWORD, /* ABSOLUTE keyword */ TOK_ADDRSIZE, /* ADDRSIZE keyword */ TOK_COUNT, /* COUNT keyword */ TOK_EQUATE, /* EQUATE keyword */ @@ -153,6 +154,7 @@ typedef enum { TOK_VALUE, /* VALUE keyword */ TOK_VERSION, /* VERSION keyword */ TOK_ZEROPAGE, /* ZEROPAGE keyword */ + TOK_LAST_KEYWORD = TOK_ZEROPAGE, TOK_IDENT, /* To catch unknown keywords */ } Token; @@ -221,6 +223,7 @@ typedef struct SymInfo SymInfo; struct SymInfo { cc65_symbol_type Type; /* Type of symbol */ long Value; /* Value of symbol */ + cc65_size Size; /* Size of symbol */ char SymName[1]; /* Name of symbol */ }; @@ -675,7 +678,7 @@ static void CollQuickSort (Collection* C, int Lo, int Hi, } if (I <= J) { /* Swap I and J */ - void* Tmp = Items[I]; + void* Tmp = Items[I]; Items[I] = Items[J]; Items[J] = Tmp; ++I; @@ -1035,15 +1038,17 @@ static int CompareFileInfoById (const void* L, const void* R) -static SymInfo* NewSymInfo (const StrBuf* Name, long Val, cc65_symbol_type Type) +static SymInfo* NewSymInfo (const StrBuf* Name, long Val, + cc65_symbol_type Type, cc65_size Size) /* Create a new SymInfo struct, intialize and return it */ { /* Allocate memory */ SymInfo* S = xmalloc (sizeof (SymInfo) + SB_GetLen (Name)); /* Initialize it */ - S->Value = Val; S->Type = Type; + S->Value = Val; + S->Size = Size; memcpy (S->SymName, SB_GetConstBuf (Name), SB_GetLen (Name) + 1); /* Return it */ @@ -1382,6 +1387,7 @@ static void CopySymInfo (cc65_symboldata* D, const SymInfo* S) { D->symbol_name = S->SymName; D->symbol_type = S->Type; + D->symbol_size = S->Size; D->symbol_value = S->Value; } @@ -1535,6 +1541,7 @@ static void NextToken (InputData* D) { "range", TOK_RANGE }, { "ro", TOK_RO }, { "rw", TOK_RW }, + { "seg", TOK_SEGMENT }, { "segment", TOK_SEGMENT }, { "size", TOK_SIZE }, { "start", TOK_START }, @@ -1665,8 +1672,16 @@ static void NextToken (InputData* D) +static int TokenIsKeyword (Token Tok) +/* Return true if the given token is a keyword */ +{ + return (Tok >= TOK_FIRST_KEYWORD && Tok <= TOK_LAST_KEYWORD); +} + + + static int TokenFollows (InputData* D, Token Tok, const char* Name) -/* Check for a comma */ +/* Check for a specific token that follows. */ { if (D->Tok != Tok) { ParseError (D, CC65_ERROR, "%s expected", Name); @@ -1765,15 +1780,16 @@ static void ParseFile (InputData* D) Token Tok; - /* Check for an unknown keyword */ - if (D->Tok == TOK_IDENT) { - UnknownKeyword (D); - continue; - } - /* Something we know? */ if (D->Tok != TOK_ID && D->Tok != TOK_MTIME && D->Tok != TOK_NAME && D->Tok != TOK_SIZE) { + + /* Try smart error recovery */ + if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) { + UnknownKeyword (D); + continue; + } + /* Done */ break; } @@ -1894,16 +1910,17 @@ static void ParseLine (InputData* D) Token Tok; - /* Check for an unknown keyword */ - if (D->Tok == TOK_IDENT) { - UnknownKeyword (D); - continue; - } - /* Something we know? */ if (D->Tok != TOK_COUNT && D->Tok != TOK_FILE && D->Tok != TOK_LINE && D->Tok != TOK_RANGE && D->Tok != TOK_SEGMENT && D->Tok != TOK_TYPE) { + + /* Try smart error recovery */ + if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) { + UnknownKeyword (D); + continue; + } + /* Done */ break; } @@ -2049,17 +2066,17 @@ static void ParseSegment (InputData* D) Token Tok; - /* Check for an unknown keyword */ - if (D->Tok == TOK_IDENT) { - UnknownKeyword (D); - continue; - } - /* Something we know? */ if (D->Tok != TOK_ADDRSIZE && D->Tok != TOK_ID && D->Tok != TOK_NAME && D->Tok != TOK_OUTPUTNAME && D->Tok != TOK_OUTPUTOFFS && D->Tok != TOK_SIZE && D->Tok != TOK_START && D->Tok != TOK_TYPE) { + + /* Try smart error recovery */ + if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) { + UnknownKeyword (D); + continue; + } /* Done */ break; } @@ -2196,6 +2213,7 @@ static void ParseSym (InputData* D) { cc65_symbol_type Type; long Value; + cc65_size Size = 0; StrBuf SymName = STRBUF_INITIALIZER; SymInfo* S; enum { @@ -2204,6 +2222,7 @@ static void ParseSym (InputData* D) ibValue = 0x02, ibAddrSize = 0x04, ibType = 0x08, + ibSize = 0x10, ibRequired = ibSymName | ibValue | ibAddrSize | ibType, } InfoBits = ibNone; @@ -2215,15 +2234,17 @@ static void ParseSym (InputData* D) Token Tok; - /* Check for an unknown keyword */ - if (D->Tok == TOK_IDENT) { - UnknownKeyword (D); - continue; - } - /* Something we know? */ if (D->Tok != TOK_ADDRSIZE && D->Tok != TOK_NAME && - D->Tok != TOK_TYPE && D->Tok != TOK_VALUE) { + D->Tok != TOK_SIZE && D->Tok != TOK_TYPE && + D->Tok != TOK_VALUE) { + + /* Try smart error recovery */ + if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) { + UnknownKeyword (D); + continue; + } + /* Done */ break; } @@ -2253,6 +2274,15 @@ static void ParseSym (InputData* D) NextToken (D); break; + case TOK_SIZE: + if (!IntConstFollows (D)) { + goto ErrorExit; + } + Size = (cc65_size) D->IVal; + InfoBits |= ibSize; + NextToken (D); + break; + case TOK_TYPE: switch (D->Tok) { case TOK_EQUATE: @@ -2308,7 +2338,7 @@ static void ParseSym (InputData* D) } /* Create the symbol info and remember it */ - S = NewSymInfo (&SymName, Value, Type); + S = NewSymInfo (&SymName, Value, Type, Size); CollAppend (&D->Info->SymInfoByName, S); CollAppend (&D->Info->SymInfoByVal, S); @@ -2892,61 +2922,83 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc) ParseError (&D, CC65_ERROR, "\"version\" keyword missing in first line - this is not " "a valid debug info file"); - } else { - - /* Parse the version directive and check the version */ - ParseVersion (&D); - if (D.MajorVersion > VER_MAJOR) { - ParseError (&D, CC65_WARNING, - "The format of this debug info file is newer than what we " - "know. Will proceed but probably fail. Version found = %u, " - "version supported = %u", - D.MajorVersion, VER_MAJOR); - } - ConsumeEOL (&D); - - /* Parse lines */ - while (D.Tok != TOK_EOF) { - - switch (D.Tok) { - - case TOK_FILE: - ParseFile (&D); - break; - - case TOK_LINE: - ParseLine (&D); - break; - - case TOK_SEGMENT: - ParseSegment (&D); - break; - - case TOK_SYM: - ParseSym (&D); - break; - - case TOK_IDENT: - /* Output a warning, then skip the line with the unknown - * keyword that may have been added by a later version. - */ - ParseError (&D, CC65_WARNING, - "Unknown keyword \"%s\" - skipping", - SB_GetConstBuf (&D.SVal)); - - SkipLine (&D); - break; - - default: - UnexpectedToken (&D); - - } - - /* EOL or EOF must follow */ - ConsumeEOL (&D); - } + goto CloseAndExit; } + /* Parse the version directive */ + ParseVersion (&D); + + /* Do several checks on the version number */ + if (D.MajorVersion < VER_MAJOR) { + ParseError ( + &D, CC65_ERROR, + "This is an old version of the debug info format that is no " + "longer supported. Version found = %u.%u, version supported " + "= %u.%u", + D.MajorVersion, D.MinorVersion, VER_MAJOR, VER_MINOR + ); + goto CloseAndExit; + } else if (D.MajorVersion == VER_MAJOR && D.MinorVersion > VER_MINOR) { + ParseError ( + &D, CC65_ERROR, + "This is a slightly newer version of the debug info format. " + "It might work, but you may get errors about unknown keywords " + "and similar. Version found = %u.%u, version supported = %u.%u", + D.MajorVersion, D.MinorVersion, VER_MAJOR, VER_MINOR + ); + } else if (D.MajorVersion > VER_MAJOR) { + ParseError ( + &D, CC65_WARNING, + "The format of this debug info file is newer than what we " + "know. Will proceed but probably fail. Version found = %u.%u, " + "version supported = %u.%u", + D.MajorVersion, D.MinorVersion, VER_MAJOR, VER_MINOR + ); + } + ConsumeEOL (&D); + + /* Parse lines */ + while (D.Tok != TOK_EOF) { + + switch (D.Tok) { + + case TOK_FILE: + ParseFile (&D); + break; + + case TOK_LINE: + ParseLine (&D); + break; + + case TOK_SEGMENT: + ParseSegment (&D); + break; + + case TOK_SYM: + ParseSym (&D); + break; + + case TOK_IDENT: + /* Output a warning, then skip the line with the unknown + * keyword that may have been added by a later version. + */ + ParseError (&D, CC65_WARNING, + "Unknown keyword \"%s\" - skipping", + SB_GetConstBuf (&D.SVal)); + + SkipLine (&D); + break; + + default: + UnexpectedToken (&D); + + } + + /* EOL or EOF must follow */ + ConsumeEOL (&D); + } + +CloseAndExit: /* Close the file */ fclose (D.F); @@ -3135,9 +3187,9 @@ cc65_sourceinfo* cc65_get_sourcelist (cc65_dbginfo Handle) /* Get a pointer to the file list */ FileInfoByName = &Info->FileInfoByName; - /* Allocate memory for the data structure returned to the caller. + /* Allocate memory for the data structure returned to the caller. * Note: To simplify things, we will allocate the maximum amount of - * memory, we may need later. This saves us the overhead of walking + * memory, we may need later. This saves us the overhead of walking * the list twice. */ D = new_cc65_sourceinfo (CollCount (FileInfoByName)); diff --git a/src/dbginfo/dbginfo.h b/src/dbginfo/dbginfo.h index c1f0bafbf..b4c6375e9 100644 --- a/src/dbginfo/dbginfo.h +++ b/src/dbginfo/dbginfo.h @@ -51,11 +51,12 @@ extern "C" { -/* Data types used for addresses and line numbers. Change to "unsigned long" - * if you ever want to run the code on a 16-bit machine. +/* Data types used for addresses, sizes and line numbers. Change to "unsigned + * long" if you ever want to run the code on a 16-bit machine. */ typedef unsigned cc65_line; /* Used to store line numbers */ -typedef unsigned cc65_addr; /* Use to store (65xx) addresses */ +typedef unsigned cc65_addr; /* Used to store (65xx) addresses */ +typedef unsigned cc65_size; /* Used to store (65xx) sizes */ /* Pointer to an opaque data structure containing information from the debug * info file. Actually a handle to the data in the file. @@ -162,6 +163,7 @@ typedef struct cc65_symboldata cc65_symboldata; struct cc65_symboldata { const char* symbol_name; /* Name of symbol */ cc65_symbol_type symbol_type; /* Type of symbol */ + cc65_size symbol_size; /* Size of symbol, 0 if unknown */ long symbol_value; /* Value of symbol */ }; diff --git a/src/dbginfo/dbgtest.c b/src/dbginfo/dbgtest.c index 54c188bf5..9d7b7ad48 100644 --- a/src/dbginfo/dbgtest.c +++ b/src/dbginfo/dbgtest.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2010, Ullrich von Bassewitz */ +/* (C) 2010-2011, Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -113,7 +113,10 @@ static void PrintLineData (const cc65_linedata* D) static void PrintSymbolData (const cc65_symboldata* D) /* Print the data for one symbol */ { - printf (" %-20s = %04lX\n", D->symbol_name, D->symbol_value); + printf (" %-20s = %04lX (size %u)\n", + D->symbol_name, + D->symbol_value, + D->symbol_size); } @@ -254,7 +257,7 @@ int main (int argc, char** argv) } /* Free the debug info */ - cc65_free_dbginfo (Info); + cc65_free_dbginfo (Info); return 0; } diff --git a/src/ld65/dbgfile.c b/src/ld65/dbgfile.c index ace32cb1e..8cde4ab66 100644 --- a/src/ld65/dbgfile.c +++ b/src/ld65/dbgfile.c @@ -65,7 +65,7 @@ void CreateDbgFile (void) } /* Output version information */ - fprintf (F, "version\tmajor=1,minor=1\n"); + fprintf (F, "version\tmajor=1,minor=2\n"); /* Clear the debug sym table (used to detect duplicates) */ ClearDbgSymTable (); diff --git a/src/ld65/dbginfo.c b/src/ld65/dbginfo.c index 1bd3fe408..2b81367cc 100644 --- a/src/ld65/dbginfo.c +++ b/src/ld65/dbginfo.c @@ -85,7 +85,7 @@ void PrintDbgInfo (ObjData* O, FILE* F) /* Print it */ fprintf (F, - "line\tfile=%u,line=%lu,segment=%u,range=0x%06lX-0x%06lX", + "line\tfile=%u,line=%lu,segment=%u,range=0x%lX-0x%lX", LI->File->Id, GetSourceLine (LI), R->Seg->Id, R->Offs, R->Offs + R->Size - 1); diff --git a/src/ld65/dbgsyms.c b/src/ld65/dbgsyms.c index 850739a26..be981ac84 100644 --- a/src/ld65/dbgsyms.c +++ b/src/ld65/dbgsyms.c @@ -84,6 +84,7 @@ static DbgSym* NewDbgSym (unsigned char Type, unsigned char AddrSize, ObjData* O D->Obj = O; D->LineInfos = EmptyCollection; D->Expr = 0; + D->Size = 0; D->Name = 0; D->Type = Type; D->AddrSize = AddrSize; @@ -144,7 +145,7 @@ DbgSym* ReadDbgSym (FILE* F, ObjData* O) /* Read a debug symbol from a file, insert and return it */ { /* Read the type and address size */ - unsigned char Type = ReadVar (F); + unsigned Type = ReadVar (F); unsigned char AddrSize = Read8 (F); /* Create a new debug symbol */ @@ -160,6 +161,11 @@ DbgSym* ReadDbgSym (FILE* F, ObjData* O) D->Expr = LiteralExpr (Read32 (F), O); } + /* Read the size */ + if (SYM_HAS_SIZE (D->Type)) { + D->Size = ReadVar (F); + } + /* Last is the list of line infos for this symbol */ ReadLineInfoList (F, O, &D->LineInfos); @@ -219,11 +225,15 @@ void PrintDbgSyms (ObjData* O, FILE* F) /* Emit the debug file line */ fprintf (F, - "sym\tname=\"%s\",value=0x%08lX,addrsize=%s,type=%s\n", + "sym\tname=\"%s\",value=0x%lX,addrsize=%s,type=%s", GetString (D->Name), Val, AddrSizeToStr (D->AddrSize), SYM_IS_LABEL (D->Type)? "label" : "equate"); + if (D->Size != 0) { + fprintf (F, ",size=%lu", D->Size); + } + fputc ('\n', F); /* Insert the symbol into the table */ InsertDbgSym (D, Val); diff --git a/src/ld65/dbgsyms.h b/src/ld65/dbgsyms.h index 4736cce9b..d18ac7ff5 100644 --- a/src/ld65/dbgsyms.h +++ b/src/ld65/dbgsyms.h @@ -63,6 +63,7 @@ struct DbgSym { ObjData* Obj; /* Object file that exports the name */ Collection LineInfos; /* Line infos of definition */ ExprNode* Expr; /* Expression (0 if not def'd) */ + unsigned long Size; /* Symbol size if any */ unsigned Name; /* Name */ unsigned char Type; /* Type of symbol */ unsigned char AddrSize; /* Address size of symbol */ diff --git a/src/ld65/exports.c b/src/ld65/exports.c index 246bd59aa..486860618 100644 --- a/src/ld65/exports.c +++ b/src/ld65/exports.c @@ -304,6 +304,7 @@ static Export* NewExport (unsigned char Type, unsigned char AddrSize, E->ImpCount = 0; E->ImpList = 0; E->Expr = 0; + E->Size = 0; E->LineInfos = EmptyCollection; E->Type = Type; E->AddrSize = AddrSize; @@ -384,6 +385,11 @@ Export* ReadExport (FILE* F, ObjData* O) E->Expr = LiteralExpr (Read32 (F), O); } + /* Read the size */ + if (SYM_HAS_SIZE (Type)) { + E->Size = ReadVar (F); + } + /* Last is the file position where the definition was done */ ReadLineInfoList (F, O, &E->LineInfos); @@ -445,7 +451,7 @@ void InsertExport (Export* E) Imp = E->ImpList; while (Imp) { Imp->Exp = E; - Imp = Imp->Next; + Imp = Imp->Next; } } else { /* Duplicate entry, ignore it */ @@ -739,7 +745,7 @@ static void PrintUnresolved (ExpCheckFunc F, void* Data) } - + static int CmpExpName (const void* K1, const void* K2) /* Compare function for qsort */ { diff --git a/src/ld65/exports.h b/src/ld65/exports.h index 83318bef3..003757278 100644 --- a/src/ld65/exports.h +++ b/src/ld65/exports.h @@ -83,6 +83,7 @@ struct Export { unsigned ImpCount; /* How many imports for this symbol? */ Import* ImpList; /* List of imports for this symbol */ ExprNode* Expr; /* Expression (0 if not def'd) */ + unsigned long Size; /* Size of the symbol if any */ Collection LineInfos; /* Line info of definition */ unsigned char Type; /* Type of export */ unsigned char AddrSize; /* Address size of export */ diff --git a/src/od65/dump.c b/src/od65/dump.c index b5cf4871c..de9fa3c39 100644 --- a/src/od65/dump.c +++ b/src/od65/dump.c @@ -206,19 +206,25 @@ static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes) case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break; } + /* Size available? */ + if (SYM_HAS_SIZE (Flags)) { + strcat (TypeDesc, ",SYM_SIZE"); + } + + /* Constructor/destructor declarations */ T = TypeDesc + strlen (TypeDesc); Count = SYM_GET_CONDES_COUNT (Flags); if (Count > 0 && ConDes) { - T += sprintf (T, ",SYM_CONDES="); - for (I = 0; I < Count; ++I) { - unsigned Type = CD_GET_TYPE (ConDes[I]); - unsigned Prio = CD_GET_PRIO (ConDes[I]); - if (I > 0) { - *T++ = ','; - } + T += sprintf (T, ",SYM_CONDES="); + for (I = 0; I < Count; ++I) { + unsigned Type = CD_GET_TYPE (ConDes[I]); + unsigned Prio = CD_GET_PRIO (ConDes[I]); + if (I > 0) { + *T++ = ','; + } T += sprintf (T, "[%u,%u]", Type, Prio); - } + } } /* Return the result */ @@ -563,8 +569,8 @@ void DumpObjExports (FILE* F, unsigned long Offset) for (I = 0; I < Count; ++I) { unsigned long Value = 0; - int HaveValue; - unsigned char ConDes [CD_TYPE_COUNT]; + unsigned long Size = 0; + unsigned char ConDes[CD_TYPE_COUNT]; const char* Name; unsigned Len; @@ -575,13 +581,14 @@ void DumpObjExports (FILE* F, unsigned long Offset) ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type)); Name = GetString (&StrPool, ReadVar (F)); Len = strlen (Name); - if (SYM_IS_EXPR (Type)) { - SkipExpr (F); - HaveValue = 0; - } else { + if (SYM_IS_CONST (Type)) { Value = Read32 (F); - HaveValue = 1; + } else { + SkipExpr (F); } + if (SYM_HAS_SIZE (Type)) { + Size = ReadVar (F); + } /* Skip the line infos */ SkipLineInfoList (F); @@ -594,8 +601,11 @@ void DumpObjExports (FILE* F, unsigned long Offset) printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize, AddrSizeToStr (AddrSize)); printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); - if (HaveValue) { - printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); + if (SYM_IS_CONST (Type)) { + printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); + } + if (SYM_HAS_SIZE (Type)) { + printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size); } } @@ -641,21 +651,22 @@ void DumpObjDbgSyms (FILE* F, unsigned long Offset) /* Read and print all debug symbols */ for (I = 0; I < Count; ++I) { - unsigned long Value = 0; - int HaveValue; + unsigned long Value = 0; + unsigned long Size = 0; /* Read the data for one symbol */ unsigned Type = ReadVar (F); unsigned char AddrSize = Read8 (F); const char* Name = GetString (&StrPool, ReadVar (F)); unsigned Len = strlen (Name); - if (SYM_IS_EXPR (Type)) { - SkipExpr (F); - HaveValue = 0; - } else { + if (SYM_IS_CONST (Type)) { Value = Read32 (F); - HaveValue = 1; + } else { + SkipExpr (F); } + if (SYM_HAS_SIZE (Type)) { + Size = ReadVar (F); + } /* Skip the line infos */ SkipLineInfoList (F); @@ -668,9 +679,12 @@ void DumpObjDbgSyms (FILE* F, unsigned long Offset) printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize, AddrSizeToStr (AddrSize)); printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); - if (HaveValue) { + if (SYM_IS_CONST (Type)) { printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); } + if (SYM_HAS_SIZE (Type)) { + printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size); + } } /* Destroy the string pool */