diff --git a/doc/cc65.sgml b/doc/cc65.sgml index df58a0a95..67323931c 100644 --- a/doc/cc65.sgml +++ b/doc/cc65.sgml @@ -198,6 +198,189 @@ Here is a description of all the command line options: Enables debug mode, for debugging the behavior of cc65. + --debug-tables name + + Writes symbol table information to a file, which includes details on structs, unions + functions, and global variables. For example, given the following code: + + + struct l { + unsigned char m; + unsigned char n; + }; + + struct hello { + unsigned char j; + unsigned char k; + struct l l; + }; + + struct sub { + unsigned char x; + unsigned char y; + }; + + union xy { + struct sub xy; + unsigned int mem; + }; + + typedef struct hello thingy; + + unsigned char single; + + unsigned char test_local_vars_main(void) { + static unsigned char wahoo; + static unsigned char bonanza = 0x42; + unsigned char i; + unsigned int j; + unsigned int *random; + unsigned char *lol; + signed char whoa; + struct hello wow; + thingy *cool; + union xy xy; + + return 0; + } + + + The following output would be produced: + + + SC_FUNC: _test_local_vars_main: Symbol table + ============================================ + __fixargs__: + Flags: SC_CONST SC_DEF + Type: unsigned int + __argsize__: + Flags: SC_CONST SC_DEF + Type: unsigned char + wahoo: + AsmName: M0001 + Flags: SC_STATIC SC_DEF SC_REF + Type: unsigned char + bonanza: + AsmName: M0002 + Flags: SC_STATIC SC_DEF SC_REF + Type: unsigned char + i: + Flags: SC_AUTO SC_DEF SC_REF + Type: unsigned char + j: + Flags: SC_AUTO SC_DEF SC_REF + Type: unsigned int + random: + Flags: SC_AUTO SC_DEF SC_REF + Type: unsigned int * + lol: + Flags: SC_AUTO SC_DEF SC_REF + Type: unsigned char * + whoa: + Flags: SC_AUTO SC_DEF SC_REF + Type: signed char + wow: + Flags: SC_AUTO SC_DEF SC_REF + Type: struct hello + cool: + Flags: SC_AUTO SC_DEF SC_REF + Type: struct hello * + xy: + Flags: SC_AUTO SC_DEF SC_REF + Type: union xy + + + + + Global symbol table + =================== + thingy: + AsmName: _thingy + Flags: SC_TYPEDEF 0x100000 + Type: struct hello + single: + AsmName: _single + Flags: SC_STATIC SC_EXTERN SC_STORAGE SC_DEF SC_REF 0x100000 + Type: unsigned char + test_local_vars_main: + AsmName: _test_local_vars_main + Flags: SC_FUNC SC_STATIC SC_EXTERN SC_DEF 0x100000 + Type: unsigned char (void) + + + + + Global tag table + ================ + l: + Flags: SC_STRUCT SC_DEF + Type: (none) + hello: + Flags: SC_STRUCT SC_DEF + Type: (none) + sub: + Flags: SC_STRUCT SC_DEF + Type: (none) + xy: + Flags: SC_UNION SC_DEF + Type: (none) + + + + + Global struct and union definitions + ========================= + + SC_STRUCT: l + ============ + m: + Flags: SC_STRUCTFIELD + Type: unsigned char + n: + Flags: SC_STRUCTFIELD + Type: unsigned char + + + + + SC_STRUCT: hello + ================ + j: + Flags: SC_STRUCTFIELD + Type: unsigned char + k: + Flags: SC_STRUCTFIELD + Type: unsigned char + l: + Flags: SC_STRUCTFIELD + Type: struct l + + + + + SC_STRUCT: sub + ============== + x: + Flags: SC_STRUCTFIELD + Type: unsigned char + y: + Flags: SC_STRUCTFIELD + Type: unsigned char + + + + + SC_UNION: xy + ============ + xy: + Flags: SC_STRUCTFIELD + Type: struct sub + mem: + Flags: SC_STRUCTFIELD + Type: unsigned int + + + --debug-opt name The named file contains a list of specific optimization steps to enable or disable. diff --git a/src/cc65/global.c b/src/cc65/global.c index a337549fe..8b9838dc5 100644 --- a/src/cc65/global.c +++ b/src/cc65/global.c @@ -66,6 +66,7 @@ IntStack CodeSizeFactor = INTSTACK(100);/* Size factor for generated code */ IntStack DataAlignment = INTSTACK(1); /* Alignment for data */ /* File names */ -StrBuf DepName = STATIC_STRBUF_INITIALIZER; /* Name of dependencies file */ -StrBuf FullDepName = STATIC_STRBUF_INITIALIZER; /* Name of full dependencies file */ -StrBuf DepTarget = STATIC_STRBUF_INITIALIZER; /* Name of dependency target */ +StrBuf DepName = STATIC_STRBUF_INITIALIZER; /* Name of dependencies file */ +StrBuf FullDepName = STATIC_STRBUF_INITIALIZER; /* Name of full dependencies file */ +StrBuf DepTarget = STATIC_STRBUF_INITIALIZER; /* Name of dependency target */ +StrBuf DebugTableName = STATIC_STRBUF_INITIALIZER; /* Name of debug table dump file */ diff --git a/src/cc65/global.h b/src/cc65/global.h index b9bcf5550..266035346 100644 --- a/src/cc65/global.h +++ b/src/cc65/global.h @@ -77,6 +77,7 @@ extern IntStack DataAlignment; /* Alignment for data */ extern StrBuf DepName; /* Name of dependencies file */ extern StrBuf FullDepName; /* Name of full dependencies file */ extern StrBuf DepTarget; /* Name of dependency target */ +extern StrBuf DebugTableName; /* Name of debug table dump file */ diff --git a/src/cc65/main.c b/src/cc65/main.c index 0ed5af986..74d4fd146 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -114,6 +114,7 @@ static void Usage (void) " --create-full-dep name\tCreate a full make dependency file\n" " --data-name seg\t\tSet the name of the DATA segment\n" " --debug\t\t\tDebug mode\n" + " --debug-tables name\t\tWrite symbol table debug info to a file\n" " --debug-info\t\t\tAdd debug info to object file\n" " --debug-opt name\t\tDebug optimization steps\n" " --debug-opt-output\t\tDebug output of each optimization step\n" @@ -494,7 +495,11 @@ static void OptDebug (const char* Opt attribute ((unused)), ++Debug; } - +static void OptDebugTables (const char* Opt, const char* Arg) +/* Dump tables to file */ +{ + FileNameOption (Opt, Arg, &DebugTableName); +} static void OptDebugInfo (const char* Opt attribute ((unused)), const char* Arg attribute ((unused))) @@ -865,6 +870,7 @@ int main (int argc, char* argv[]) { "--create-full-dep", 1, OptCreateFullDep }, { "--data-name", 1, OptDataName }, { "--debug", 0, OptDebug }, + { "--debug-tables", 1, OptDebugTables }, { "--debug-info", 0, OptDebugInfo }, { "--debug-opt", 1, OptDebugOpt }, { "--debug-opt-output", 0, OptDebugOptOutput }, diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index c1c5c4696..b4c97e962 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -37,6 +37,7 @@ #include #include #include +#include /* common */ #include "check.h" @@ -68,8 +69,6 @@ /* Data */ /*****************************************************************************/ - - /* An empty symbol table */ SymTable EmptySymTab = { 0, /* PrevTab */ @@ -99,6 +98,7 @@ static SymTable* LabelTab = 0; static SymTable* SPAdjustTab = 0; static SymTable* FailSafeTab = 0; /* For errors */ +static FILE* DebugTableFile = 0; /*****************************************************************************/ /* struct SymTable */ @@ -256,11 +256,25 @@ void PopLexicalLevel (void) --LexLevelDepth; } - - void EnterGlobalLevel (void) /* Enter the program global lexical level */ { + const char* OutName = NULL; + if (!SB_IsEmpty (&DebugTableName)) { + OutName = SB_GetConstBuf (&DebugTableName); + } + + if (OutName) { + /* Open the table file */ + DebugTableFile = fopen (OutName, "w"); + if (DebugTableFile == 0) { + Error ("Cannot create table dump file '%s': %s", OutName, strerror (errno)); + } + } + else if (Debug) { + DebugTableFile = stdout; + } + /* Safety */ PRECONDITION (GetLexicalLevel () == LEX_LEVEL_NONE); @@ -280,8 +294,6 @@ void EnterGlobalLevel (void) FailSafeTab = NewSymTable (SYMTAB_SIZE_GLOBAL); } - - void LeaveGlobalLevel (void) /* Leave the program global lexical level */ { @@ -292,9 +304,41 @@ void LeaveGlobalLevel (void) CheckSymTable (SymTab0); /* Dump the tables if requested */ - if (Debug) { - PrintSymTable (SymTab0, stdout, "Global symbol table"); - PrintSymTable (TagTab0, stdout, "Global tag table"); + if (DebugTableFile) { + SymEntry* Entry; + StrBuf* Header; + + PrintSymTable (SymTab0, DebugTableFile, "Global symbol table"); + PrintSymTable (TagTab0, DebugTableFile, "Global tag table"); + + Entry = TagTab0->SymHead; + if (Entry) { + fputs ("\nGlobal struct and union definitions", DebugTableFile); + fputs ("\n=========================\n", DebugTableFile); + + do { + if (!((Entry->Flags & SC_STRUCT) || (Entry->Flags & SC_UNION)) || !Entry->V.S.SymTab) { + continue; + } + + Header = NewStrBuf(); + if(Entry->Flags & SC_STRUCT) { + SB_AppendStr (Header, "SC_STRUCT: "); + } + else { + SB_AppendStr (Header, "SC_UNION: "); + } + SB_AppendStr (Header, Entry->Name); + SB_Terminate (Header); + + PrintSymTable (Entry->V.S.SymTab, DebugTableFile, SB_GetConstBuf (Header)); + } while ((Entry = Entry->NextSym)); + } + + /* Close the file */ + if (DebugTableFile != stdout && fclose (DebugTableFile) != 0) { + Error ("Error closing table dump file '%s': %s", SB_GetConstBuf(&DebugTableName), strerror (errno)); + } } /* Don't delete the symbol and struct tables! */ @@ -386,6 +430,18 @@ void LeaveFunctionLevel (void) CheckSymTable (SymTab); CheckSymTable (LabelTab); + /* Dump the tables if requested */ + if (DebugTableFile) { + StrBuf* SymbolHeader = NewStrBuf(); + + SB_AppendStr (SymbolHeader, "SC_FUNC: "); + SB_AppendStr (SymbolHeader, CurrentFunc->FuncEntry->AsmName); + SB_AppendStr (SymbolHeader, ": Symbol table"); + SB_Terminate (SymbolHeader); + + PrintSymTable (SymTab, DebugTableFile, SB_GetConstBuf(SymbolHeader)); + } + /* Drop the label table if it is empty */ if (LabelTab->SymCount == 0) { FreeSymTable (LabelTab);