TOK_ADDRSIZE, /* ADDRSIZE keyword */
TOK_AUTO, /* AUTO keyword */
TOK_COUNT, /* COUNT keyword */
+ TOK_CSYM, /* CSYM keyword */
TOK_DEF, /* DEF keyword */
TOK_ENUM, /* ENUM keyword */
TOK_EQUATE, /* EQUATE keyword */
TOK_EXPORT, /* EXPORT keyword */
+ TOK_EXTERN, /* EXTERN keyword */
TOK_FILE, /* FILE keyword */
TOK_FUNC, /* FUNC keyword */
TOK_GLOBAL, /* GLOBAL keyword */
TOK_MODULE, /* MODULE keyword */
TOK_MTIME, /* MTIME keyword */
TOK_NAME, /* NAME keyword */
+ TOK_OFFS, /* OFFS keyword */
TOK_OUTPUTNAME, /* OUTPUTNAME keyword */
TOK_OUTPUTOFFS, /* OUTPUTOFFS keyword */
TOK_PARENT, /* PARENT keyword */
TOK_REF, /* REF keyword */
+ TOK_REGISTER, /* REGISTER keyword */
TOK_RO, /* RO keyword */
TOK_RW, /* RW keyword */
+ TOK_SC, /* SC keyword */
TOK_SCOPE, /* SCOPE keyword */
TOK_SEGMENT, /* SEGMENT keyword */
TOK_SIZE, /* SIZE keyword */
* The collections are also used when the objects are deleted, so they're
* actually the ones that "own" the items.
*/
+ Collection CSymInfoById; /* C symbol infos sorted by id */
Collection FileInfoById; /* File infos sorted by id */
Collection LibInfoById; /* Library infos sorted by id */
Collection LineInfoById; /* Line infos sorted by id */
};
/* Typedefs for the item structures. Do also serve as forwards */
+typedef struct CSymInfo CSymInfo;
typedef struct FileInfo FileInfo;
typedef struct LibInfo LibInfo;
typedef struct LineInfo LineInfo;
typedef struct SymInfo SymInfo;
typedef struct TypeInfo TypeInfo;
+/* Internally used c symbol info struct */
+struct CSymInfo {
+ unsigned Id; /* Id of file */
+ unsigned short Kind; /* Kind of C symbol */
+ unsigned short SC; /* Storage class of C symbol */
+ int Offs; /* Offset */
+ union {
+ unsigned Id; /* Id of attached asm symbol */
+ SymInfo* Info; /* Pointer to attached asm symbol */
+ } Sym;
+ union {
+ unsigned Id; /* Id of type */
+ TypeInfo* Info; /* Pointer to type */
+ } Type;
+ union {
+ unsigned Id; /* Id of scope */
+ ScopeInfo* Info; /* Pointer to scope */
+ } Scope;
+ char Name[1]; /* Name of file with full path */
+};
+
/* Internally used file info struct */
struct FileInfo {
unsigned Id; /* Id of file */
+/*****************************************************************************/
+/* C symbol info */
+/*****************************************************************************/
+
+
+
+static CSymInfo* NewCSymInfo (const StrBuf* Name)
+/* Create a new CSymInfo struct and return it */
+{
+ /* Allocate memory */
+ CSymInfo* S = xmalloc (sizeof (CSymInfo) + SB_GetLen (Name));
+
+ /* Initialize it */
+ memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
+
+ /* Return it */
+ return S;
+}
+
+
+
+static void FreeCSymInfo (CSymInfo* S)
+/* Free a CSymInfo struct */
+{
+ /* Free the structure itself */
+ xfree (S);
+}
+
+
+
+static int CompareCSymInfoByName (const void* L, const void* R)
+/* Helper function to sort c symbol infos in a collection by name */
+{
+ /* Sort by symbol name */
+ return strcmp (((const CSymInfo*) L)->Name,
+ ((const CSymInfo*) R)->Name);
+}
+
+
+
/*****************************************************************************/
/* File info */
/*****************************************************************************/
DbgInfo* Info = xmalloc (sizeof (DbgInfo) + Len);
/* Initialize it */
+ CollInit (&Info->CSymInfoById);
CollInit (&Info->FileInfoById);
CollInit (&Info->LibInfoById);
CollInit (&Info->LineInfoById);
unsigned I;
/* First, free the items in the collections */
+ for (I = 0; I < CollCount (&Info->CSymInfoById); ++I) {
+ FreeCSymInfo (CollAt (&Info->CSymInfoById, I));
+ }
for (I = 0; I < CollCount (&Info->FileInfoById); ++I) {
FreeFileInfo (CollAt (&Info->FileInfoById, I));
}
}
/* Free the memory used by the id collections */
+ CollDone (&Info->CSymInfoById);
CollDone (&Info->FileInfoById);
CollDone (&Info->LibInfoById);
CollDone (&Info->LineInfoById);
{ "addrsize", TOK_ADDRSIZE },
{ "auto", TOK_AUTO },
{ "count", TOK_COUNT },
+ { "csym", TOK_CSYM },
{ "def", TOK_DEF },
{ "enum", TOK_ENUM },
{ "equ", TOK_EQUATE },
{ "exp", TOK_EXPORT },
+ { "ext", TOK_EXTERN },
{ "file", TOK_FILE },
{ "func", TOK_FUNC },
{ "global", TOK_GLOBAL },
{ "mod", TOK_MODULE },
{ "mtime", TOK_MTIME },
{ "name", TOK_NAME },
+ { "offs", TOK_OFFS },
{ "oname", TOK_OUTPUTNAME },
{ "ooffs", TOK_OUTPUTOFFS },
{ "parent", TOK_PARENT },
{ "ref", TOK_REF },
+ { "reg", TOK_REGISTER },
{ "ro", TOK_RO },
{ "rw", TOK_RW },
+ { "sc", TOK_SC },
{ "scope", TOK_SCOPE },
{ "seg", TOK_SEGMENT },
{ "size", TOK_SIZE },
+static void ParseCSym (InputData* D)
+/* Parse a CSYM line */
+{
+ /* Most of the following variables are initialized with a value that is
+ * overwritten later. This is just to avoid compiler warnings.
+ */
+ unsigned Id = 0;
+ StrBuf Name = STRBUF_INITIALIZER;
+ int Offs = 0;
+ cc65_csym_sc SC = CC65_CSYM_AUTO;
+ unsigned ScopeId = 0;
+ unsigned SymId = CC65_INV_ID;
+ unsigned TypeId = CC65_INV_ID;
+ CSymInfo* S;
+ enum {
+ ibNone = 0x0000,
+
+ ibId = 0x0001,
+ ibOffs = 0x0002,
+ ibName = 0x0004,
+ ibSC = 0x0008,
+ ibScopeId = 0x0010,
+ ibSymId = 0x0020,
+ ibType = 0x0040,
+
+ ibRequired = ibId | ibName | ibSC | ibScopeId | ibType,
+ } InfoBits = ibNone;
+
+ /* Skip the CSYM token */
+ NextToken (D);
+
+ /* More stuff follows */
+ while (1) {
+
+ Token Tok;
+
+ /* Something we know? */
+ if (D->Tok != TOK_ID && D->Tok != TOK_NAME &&
+ D->Tok != TOK_OFFS && D->Tok != TOK_SC &&
+ D->Tok != TOK_SCOPE && D->Tok != TOK_SYM &&
+ D->Tok != TOK_TYPE) {
+
+ /* Try smart error recovery */
+ if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
+ UnknownKeyword (D);
+ continue;
+ }
+
+ /* Done */
+ break;
+ }
+
+ /* Remember the token, skip it, check for equal */
+ Tok = D->Tok;
+ NextToken (D);
+ if (!ConsumeEqual (D)) {
+ goto ErrorExit;
+ }
+
+ /* Check what the token was */
+ switch (Tok) {
+
+ case TOK_ID:
+ if (!IntConstFollows (D)) {
+ goto ErrorExit;
+ }
+ Id = D->IVal;
+ NextToken (D);
+ InfoBits |= ibId;
+ break;
+
+ case TOK_NAME:
+ if (!StrConstFollows (D)) {
+ goto ErrorExit;
+ }
+ SB_Copy (&Name, &D->SVal);
+ SB_Terminate (&Name);
+ InfoBits |= ibName;
+ NextToken (D);
+ break;
+
+ case TOK_OFFS:
+ Offs = 1;
+ if (D->Tok == TOK_MINUS) {
+ Offs = -1;
+ NextToken (D);
+ }
+ if (!IntConstFollows (D)) {
+ goto ErrorExit;
+ }
+ Offs *= (int) D->IVal;
+ InfoBits |= ibOffs;
+ NextToken (D);
+ break;
+
+ case TOK_SC:
+ switch (D->Tok) {
+ case TOK_AUTO: SC = CC65_CSYM_AUTO; break;
+ case TOK_EXTERN: SC = CC65_CSYM_EXTERN; break;
+ case TOK_REGISTER: SC = CC65_CSYM_REG; break;
+ case TOK_STATIC: SC = CC65_CSYM_STATIC; break;
+ default:
+ ParseError (D, CC65_ERROR, "Invalid storage class token");
+ break;
+ }
+ InfoBits |= ibSC;
+ NextToken (D);
+ break;
+
+ case TOK_SCOPE:
+ if (!IntConstFollows (D)) {
+ goto ErrorExit;
+ }
+ ScopeId = D->IVal;
+ NextToken (D);
+ InfoBits |= ibScopeId;
+ break;
+
+ case TOK_SYM:
+ if (!IntConstFollows (D)) {
+ goto ErrorExit;
+ }
+ SymId = D->IVal;
+ NextToken (D);
+ InfoBits |= ibSymId;
+ break;
+
+ case TOK_TYPE:
+ if (!IntConstFollows (D)) {
+ goto ErrorExit;
+ }
+ TypeId = D->IVal;
+ NextToken (D);
+ InfoBits |= ibType;
+ break;
+
+ default:
+ /* NOTREACHED */
+ UnexpectedToken (D);
+ goto ErrorExit;
+
+ }
+
+ /* Comma or done */
+ if (D->Tok != TOK_COMMA) {
+ break;
+ }
+ NextToken (D);
+ }
+
+ /* Check for end of line */
+ if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
+ UnexpectedToken (D);
+ SkipLine (D);
+ goto ErrorExit;
+ }
+
+ /* Check for required and/or matched information */
+ if ((InfoBits & ibRequired) != ibRequired) {
+ ParseError (D, CC65_ERROR, "Required attributes missing");
+ goto ErrorExit;
+ }
+
+ /* Symbol only valid if storage class not auto */
+ if (((InfoBits & ibSymId) != 0) != (SC != CC65_CSYM_AUTO)) {
+ ParseError (D, CC65_ERROR, "Only non auto symbols can have a symbol attached");
+ goto ErrorExit;
+ }
+
+ /* Create the symbol info */
+ S = NewCSymInfo (&Name);
+ S->Id = Id;
+ S->Kind = CC65_CSYM_VAR;
+ S->SC = SC;
+ S->Offs = Offs;
+ S->Sym.Id = SymId;
+ S->Type.Id = TypeId;
+ S->Scope.Id = ScopeId;
+
+ /* Remember it */
+ CollReplaceExpand (&D->Info->CSymInfoById, S, Id);
+
+ErrorExit:
+ /* Entry point in case of errors */
+ SB_Done (&Name);
+ return;
+}
+
+
+
static void ParseFile (InputData* D)
/* Parse a FILE line */
{
Token Tok;
/* Something we know? */
- if (D->Tok != TOK_FILE && D->Tok != TOK_LIBRARY &&
- D->Tok != TOK_LINE && D->Tok != TOK_MODULE &&
- D->Tok != TOK_SCOPE && D->Tok != TOK_SEGMENT &&
- D->Tok != TOK_SPAN && D->Tok != TOK_SYM &&
- D->Tok != TOK_TYPE) {
+ if (D->Tok != TOK_CSYM && D->Tok != TOK_FILE &&
+ D->Tok != TOK_LIBRARY && D->Tok != TOK_LINE &&
+ D->Tok != TOK_MODULE && D->Tok != TOK_SCOPE &&
+ D->Tok != TOK_SEGMENT && D->Tok != TOK_SPAN &&
+ D->Tok != TOK_SYM && D->Tok != TOK_TYPE) {
/* Try smart error recovery */
if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
/* Check what the token was */
switch (Tok) {
+ case TOK_CSYM:
+ CollGrow (&D->Info->CSymInfoById, D->IVal);
+ break;
+
case TOK_FILE:
CollGrow (&D->Info->FileInfoById, D->IVal);
- CollGrow (&D->Info->FileInfoByName, D->IVal);
+ CollGrow (&D->Info->FileInfoByName, D->IVal);
break;
case TOK_LIBRARY:
switch (D.Tok) {
+ case TOK_CSYM:
+ ParseCSym (&D);
+ break;
+
case TOK_FILE:
ParseFile (&D);
break;
+/*****************************************************************************/
+/* C Symbols */
+/*****************************************************************************/
+
+
+
+/* C symbol kinds */
+typedef enum {
+ CC65_CSYM_FUNC,
+ CC65_CSYM_VAR
+} cc65_csym_kind;
+
+/* C object storage classes */
+typedef enum {
+ CC65_CSYM_AUTO, /* Auto = on stack */
+ CC65_CSYM_REG, /* Register = in register bank */
+ CC65_CSYM_STATIC, /* Static = static storage */
+ CC65_CSYM_EXTERN /* Extern = static storage + external visibility */
+} cc65_csym_sc;
+
+/* C symbol information */
+typedef struct cc65_csymdata cc65_csymdata;
+struct cc65_csymdata {
+ unsigned csym_id; /* The internal c symbol id */
+ unsigned char csym_kind; /* Kind of c symbol */
+ unsigned char csym_sc; /* Storage class of c symbol */
+ int csym_offs; /* Offset for auto and register */
+ unsigned symbol_id; /* Attached asm symbol if any */
+ unsigned scope_id; /* Scope of c symbol */
+ const char* csym_name; /* Name of the symbol */
+};
+
+typedef struct cc65_csyminfo cc65_csyminfo;
+struct cc65_csyminfo {
+ unsigned count; /* Number of data sets that follow */
+ cc65_csymdata data[1]; /* Data sets, number is dynamic */
+};
+
+
+
+const cc65_csyminfo* cc65_get_csymlist (cc65_dbginfo handle);
+/* Return a list of all c symbols */
+
+const cc65_csyminfo* cc65_csym_byid (cc65_dbginfo handle, unsigned id);
+/* Return information about a c symbol with a specific id. The function
+ * returns NULL if the id is invalid (no such c symbol) and otherwise a
+ * cc65_csyminfo structure with one entry that contains the requested
+ * symbol information.
+ */
+
+void cc65_free_csyminfo (cc65_dbginfo handle, const cc65_csyminfo* info);
+/* Free a c symbol info record */
+
+
+
/*****************************************************************************/
/* Libraries */
/*****************************************************************************/
/* Allow usage from C++ */
-#ifdef __cplusplus
+#ifdef __cplusplus
}
#endif