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);