From 557b077530084a2e9019491772db6e7876797933 Mon Sep 17 00:00:00 2001 From: uz Date: Thu, 25 Aug 2011 18:59:25 +0000 Subject: [PATCH] Added code to parse type strings and convert them into a set of cc65_typedata structures. Added cc65_type_byid and cc65_free_typedata (a dummy). git-svn-id: svn://svn.cc65.org/cc65/trunk@5270 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/dbginfo/dbginfo.c | 1094 ++++++++++++++++++++++++++--------------- src/dbginfo/dbginfo.h | 174 +++++-- 2 files changed, 824 insertions(+), 444 deletions(-) diff --git a/src/dbginfo/dbginfo.c b/src/dbginfo/dbginfo.c index f0a902190..ca089cd3b 100644 --- a/src/dbginfo/dbginfo.c +++ b/src/dbginfo/dbginfo.c @@ -171,8 +171,6 @@ typedef enum { TOK_IDENT, /* To catch unknown keywords */ } Token; - - /* Data structure containing information from the debug info file. A pointer * to this structure is passed as handle to callers from the outside. */ @@ -369,8 +367,21 @@ struct SymInfo { /* Internally used type info struct */ struct TypeInfo { unsigned Id; /* Id of type */ - unsigned Length; /* Length of following data */ - unsigned char Data[1]; /* Data, dynamically allocated */ + cc65_typedata Data[1]; /* Data, dynamically allocated */ +}; + +/* A structure used when parsing a type string into a set of cc65_typedata + * structures. + */ +typedef struct TypeParseData TypeParseData; +struct TypeParseData { + TypeInfo* Info; + unsigned ItemCount; + unsigned ItemIndex; + cc65_typedata* ItemData; + const StrBuf* Type; + unsigned Pos; + unsigned Error; }; @@ -525,6 +536,14 @@ static unsigned SB_GetLen (const StrBuf* B) +static char* SB_GetBuf (StrBuf* B) +/* Return a buffer pointer */ +{ + return B->Buf; +} + + + static const char* SB_GetConstBuf (const StrBuf* B) /* Return a buffer pointer */ { @@ -533,6 +552,15 @@ static const char* SB_GetConstBuf (const StrBuf* B) +static char SB_At (const StrBuf* B, unsigned Pos) +/* Return the character from a specific position */ +{ + assert (Pos <= B->Len); + return B->Buf[Pos]; +} + + + static void SB_Terminate (StrBuf* B) /* Zero terminate the given string buffer. NOTE: The terminating zero is not * accounted for in B->Len, if you want that, you have to use AppendChar! @@ -1001,6 +1029,112 @@ static void DBGPRINT(const char* format, ...) {} +/*****************************************************************************/ +/* Helper functions */ +/*****************************************************************************/ + + + +static unsigned HexValue (char C) +/* Convert the ascii representation of a hex nibble into the hex nibble */ +{ + if (isdigit (C)) { + return C - '0'; + } else if (islower (C)) { + return C - 'a' + 10; + } else { + return C - 'A' + 10; + } +} + + + +static void ParseError (InputData* D, cc65_error_severity Type, const char* Msg, ...) +/* Call the user supplied parse error function */ +{ + va_list ap; + int MsgSize; + cc65_parseerror* E; + + /* Test-format the error message so we know how much space to allocate */ + va_start (ap, Msg); + MsgSize = vsnprintf (0, 0, Msg, ap); + va_end (ap); + + /* Allocate memory */ + E = xmalloc (sizeof (*E) + MsgSize); + + /* Write data to E */ + E->type = Type; + E->name = D->FileName; + E->line = D->SLine; + E->column = D->SCol; + va_start (ap, Msg); + vsnprintf (E->errormsg, MsgSize+1, Msg, ap); + va_end (ap); + + /* Call the caller:-) */ + D->Error (E); + + /* Free the data structure */ + xfree (E); + + /* Count errors */ + if (Type == CC65_ERROR) { + ++D->Errors; + } +} + + + +static void SkipLine (InputData* D) +/* Error recovery routine. Skip tokens until EOL or EOF is reached */ +{ + while (D->Tok != TOK_EOL && D->Tok != TOK_EOF) { + NextToken (D); + } +} + + + +static void UnexpectedToken (InputData* D) +/* Call ParseError with a message about an unexpected input token */ +{ + ParseError (D, CC65_ERROR, "Unexpected input token %d", D->Tok); + SkipLine (D); +} + + + +static void UnknownKeyword (InputData* D) +/* Print a warning about an unknown keyword in the file. Try to do smart + * recovery, so if later versions of the debug information add additional + * keywords, this code may be able to at least ignore them. + */ +{ + /* Output a warning */ + ParseError (D, CC65_WARNING, "Unknown keyword \"%s\" - skipping", + SB_GetConstBuf (&D->SVal)); + + /* Skip the identifier */ + NextToken (D); + + /* If an equal sign follows, ignore anything up to the next line end + * or comma. If a comma or line end follows, we're already done. If + * we have none of both, we ignore the remainder of the line. + */ + if (D->Tok == TOK_EQUAL) { + NextToken (D); + while (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) { + NextToken (D); + } + } else if (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) { + SkipLine (D); + } +} + + + /*****************************************************************************/ /* File info */ /*****************************************************************************/ @@ -1663,52 +1797,283 @@ static int CompareSymInfoByVal (const void* L, const void* R) -static unsigned HexValue (char C) -/* Convert the ascii representation of a hex nibble into the hex nibble */ +/* The following definitions are actually just taken from gentype.h */ + +/* Size of a data type */ +#define GT_SIZE_1 0x00U +#define GT_SIZE_2 0x01U +#define GT_SIZE_3 0x02U +#define GT_SIZE_4 0x03U +#define GT_SIZE_MASK 0x07U + +#define GT_GET_SIZE(x) (((x) & GT_SIZE_MASK) + 1U) + +/* Sign of the data type */ +#define GT_UNSIGNED 0x00U +#define GT_SIGNED 0x08U +#define GT_SIGN_MASK 0x08U + +#define GT_HAS_SIGN(x) (((x) & GT_SIZE_MASK) == GT_SIGNED) + +/* Byte order */ +#define GT_LITTLE_ENDIAN 0x00U +#define GT_BIG_ENDIAN 0x10U +#define GT_BYTEORDER_MASK 0x10U + +#define GT_IS_LITTLE_ENDIAN(x) (((x) & GT_BYTEORDER_MASK) == GT_LITTLE_ENDIAN) +#define GT_IS_BIG_ENDIAN(x) (((x) & GT_BYTEORDER_MASK) == GT_BIG_ENDIAN) + +/* Type of the data. */ +#define GT_TYPE_VOID 0x00U +#define GT_TYPE_INT 0x20U +#define GT_TYPE_PTR 0x40U +#define GT_TYPE_FLOAT 0x60U +#define GT_TYPE_ARRAY 0x80U +#define GT_TYPE_FUNC 0xA0U +#define GT_TYPE_STRUCT 0xC0U +#define GT_TYPE_UNION 0xE0U +#define GT_TYPE_MASK 0xE0U + +#define GT_GET_TYPE(x) ((x) & GT_TYPE_MASK) +#define GT_IS_INTEGER(x) (GT_GET_TYPE(x) == GT_TYPE_INTEGER) +#define GT_IS_POINTER(x) (GT_GET_TYPE(x) == GT_TYPE_POINTER) +#define GT_IS_FLOAT(x) (GT_GET_TYPE(x) == GT_TYPE_FLOAT) +#define GT_IS_ARRAY(x) (GT_GET_TYPE(x) == GT_TYPE_ARRAY) +#define GT_IS_FUNCTION(x) (GT_GET_TYPE(x) == GT_TYPE_FUNCTION) +#define GT_IS_STRUCT(x) (GT_GET_TYPE(x) == GT_TYPE_STRUCT) +#define GT_IS_UNION(x) (GT_GET_TYPE(x) == GT_TYPE_UNION) + +/* Combined values for the 6502 family */ +#define GT_VOID (GT_TYPE_VOID) +#define GT_BYTE (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_1) +#define GT_WORD (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_2) +#define GT_DWORD (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_4) +#define GT_DBYTE (GT_TYPE_PTR | GT_BIG_ENDIAN | GT_UNSIGNED | GT_SIZE_2) +#define GT_PTR (GT_TYPE_PTR | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_2) +#define GT_FAR_PTR (GT_TYPE_PTR | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_3) +#define GT_ARRAY(size) (GT_TYPE_ARRAY | ((size) - 1)) + + + +static void FreeTypeInfo (TypeInfo* T) +/* Free a TypeInfo struct */ { - if (isdigit (C)) { - return C - '0'; - } else if (islower (C)) { - return C - 'a' + 10; - } else { - return C - 'A' + 10; - } + xfree (T); } -static TypeInfo* NewTypeInfo (const StrBuf* ReadableValue) -/* Create a new TypeInfo struct, intialize and return it */ +static void InitTypeParseData (TypeParseData* P, const StrBuf* Type, + unsigned ItemCount) +/* Initialize a TypeParseData structure */ { - unsigned I; - const char* P; + P->Info = xmalloc (sizeof (*P->Info) - sizeof (P->Info->Data[0]) + + ItemCount * sizeof (P->Info->Data[0])); + P->ItemCount = ItemCount; + P->ItemIndex = 0; + P->ItemData = P->Info->Data; + P->Type = Type; + P->Pos = 0; + P->Error = 0; +} - /* Calculate the length of the final data. Since we have hex encoding, it - * is half of the length of ReadableValue. - */ - unsigned Length = SB_GetLen (ReadableValue) / 2; - /* Allocate memory */ - TypeInfo* T = xmalloc (sizeof (TypeInfo) + Length - 1); - /* Initialize it as necessary */ - T->Length = Length; - P = SB_GetConstBuf (ReadableValue); - for (I = 0; I < Length; ++I) { - unsigned char V = (HexValue (*P++) << 4); - T->Data[I] = (V | HexValue (*P++)); +static cc65_typedata* TypeFromString (TypeParseData* P) +/* Parse a type string and return a set of typedata structures. Will be called + * recursively. Will set P->Error and return NULL in case of problems. + */ +{ + unsigned char B; + unsigned I; + unsigned Count; + + /* Allocate a new entry */ + if (P->ItemIndex >= P->ItemCount) { + P->Error = 1; + return 0; } + cc65_typedata* Data = &P->ItemData[P->ItemIndex++]; - /* Return it */ - return T; + /* Assume no following node */ + Data->next = 0; + + /* Get the next char, then skip it */ + if (P->Pos >= SB_GetLen (P->Type)) { + P->Error = 1; + return 0; + } + B = SB_At (P->Type, P->Pos++); + + switch (B) { + + /* We only handle those that are currently in use */ + case GT_VOID: + Data->what = CC65_TYPE_VOID; + Data->size = 0; + break; + + case GT_BYTE: + Data->what = CC65_TYPE_BYTE; + Data->size = GT_GET_SIZE (B); + break; + + case GT_WORD: + Data->what = CC65_TYPE_WORD; + Data->size = GT_GET_SIZE (B); + break; + + case GT_DWORD: + Data->what = CC65_TYPE_DWORD; + Data->size = GT_GET_SIZE (B); + break; + + case GT_DBYTE: + Data->what = CC65_TYPE_DBYTE; + Data->size = GT_GET_SIZE (B); + break; + + case GT_PTR: + Data->what = CC65_TYPE_PTR; + Data->data.ptr.ind_type = TypeFromString (P); + Data->size = GT_GET_SIZE (B); + break; + + case GT_FAR_PTR: + Data->what = CC65_TYPE_FARPTR; + Data->data.ptr.ind_type = TypeFromString (P); + Data->size = GT_GET_SIZE (B); + break; + + default: + if (GT_GET_TYPE (B) == GT_TYPE_ARRAY) { + Count = 0; + I = GT_GET_SIZE (B); + if (I == 0 || I > 4) { + P->Error = 1; + break; + } + P->Pos += I; + if (P->Pos > SB_GetLen (P->Type)) { + P->Error = 1; + break; + } + while (I) { + Count <<= 8; + Count |= (unsigned char) SB_At (P->Type, P->Pos - I); + --I; + } + Data->what = CC65_TYPE_ARRAY; + Data->data.array.ele_count = Count; + Data->data.array.ele_type = TypeFromString (P); + if (!P->Error) { + Data->size = Data->data.array.ele_count * + Data->data.array.ele_type->size; + } + } else { + /* OOPS! */ + P->Error = 1; + } + break; + } + + /* Return our structure or NULL in case of errors */ + return P->Error? 0 : Data; } -static void FreeTypeInfo (TypeInfo* T) -/* Free a TypeInfo struct */ + +static TypeInfo* ParseTypeString (InputData* D, StrBuf* Type) +/* Check if the string T contains a valid type string. Convert it from readable + * to binary. Calculate how many cc65_typedata structures are necessary when it + * is converted. Convert the string into a set of cc65_typedata structures and + * return them. + */ { - xfree (T); + unsigned I; + unsigned Count; + const char* A; + char* B; + TypeParseData P; + + + /* The length must not be zero and divideable by two */ + unsigned Length = SB_GetLen (Type); + if (Length < 2 || (Length & 0x01) != 0) { + ParseError (D, CC65_ERROR, "Type value has invalid length"); + return 0; + } + + /* The string must consist completely of hex digit chars */ + A = SB_GetConstBuf (Type); + for (I = 0; I < Length; ++I) { + if (!isxdigit (A[I])) { + ParseError (D, CC65_ERROR, "Type value contains invalid characters"); + return 0; + } + } + + /* Convert the type to binary */ + B = SB_GetBuf (Type); + while (A < SB_GetConstBuf (Type) + Length) { + /* Since we know, there are only hex digits, there can't be any errors */ + *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]); + A += 2; + } + Type->Len = (Length /= 2); + + /* Get a pointer to the type data, then count the number of cc65_typedata + * items needed. + */ + A = SB_GetConstBuf (Type); + Count = 0; + I = 0; + while (I < Length) { + switch (A[I]) { + /* We only handle those that are currently in use */ + case GT_VOID: + case GT_BYTE: + case GT_WORD: + case GT_DWORD: + case GT_DBYTE: + case GT_PTR: + case GT_FAR_PTR: + ++Count; + ++I; + break; + + default: + if (GT_GET_TYPE (A[I]) == GT_TYPE_ARRAY) { + ++Count; + I += GT_GET_SIZE (A[I]) + 1; + } else { + /* Unknown type in type string */ + ParseError (D, CC65_ERROR, "Unkown type in type value"); + return 0; + } + break; + } + } + + /* Check that we're even */ + if (I != Length) { + ParseError (D, CC65_ERROR, "Syntax error in type in type value"); + return 0; + } + + /* Initialize the data structure for parsing the type string */ + InitTypeParseData (&P, Type, Count); + + /* Parse the type string and check for errors */ + if (TypeFromString (&P) == 0 || P.ItemCount != P.ItemIndex) { + ParseError (D, CC65_ERROR, "Error parsing the type value"); + FreeTypeInfo (P.Info); + return 0; + } + + /* Return the result of the parse operation */ + return P.Info; } @@ -2013,114 +2378,22 @@ static void FreeDbgInfo (DbgInfo* Info) /*****************************************************************************/ -/* Helper functions */ +/* Scanner and parser */ /*****************************************************************************/ -static void ParseError (InputData* D, cc65_error_severity Type, const char* Msg, ...) -/* Call the user supplied parse error function */ +static int DigitVal (int C) +/* Return the value for a numeric digit. Return -1 if C is invalid */ { - va_list ap; - int MsgSize; - cc65_parseerror* E; - - /* Test-format the error message so we know how much space to allocate */ - va_start (ap, Msg); - MsgSize = vsnprintf (0, 0, Msg, ap); - va_end (ap); - - /* Allocate memory */ - E = xmalloc (sizeof (*E) + MsgSize); - - /* Write data to E */ - E->type = Type; - E->name = D->FileName; - E->line = D->SLine; - E->column = D->SCol; - va_start (ap, Msg); - vsnprintf (E->errormsg, MsgSize+1, Msg, ap); - va_end (ap); - - /* Call the caller:-) */ - D->Error (E); - - /* Free the data structure */ - xfree (E); - - /* Count errors */ - if (Type == CC65_ERROR) { - ++D->Errors; - } -} - - - -static void SkipLine (InputData* D) -/* Error recovery routine. Skip tokens until EOL or EOF is reached */ -{ - while (D->Tok != TOK_EOL && D->Tok != TOK_EOF) { - NextToken (D); - } -} - - - -static void UnexpectedToken (InputData* D) -/* Call ParseError with a message about an unexpected input token */ -{ - ParseError (D, CC65_ERROR, "Unexpected input token %d", D->Tok); - SkipLine (D); -} - - - -static void UnknownKeyword (InputData* D) -/* Print a warning about an unknown keyword in the file. Try to do smart - * recovery, so if later versions of the debug information add additional - * keywords, this code may be able to at least ignore them. - */ -{ - /* Output a warning */ - ParseError (D, CC65_WARNING, "Unknown keyword \"%s\" - skipping", - SB_GetConstBuf (&D->SVal)); - - /* Skip the identifier */ - NextToken (D); - - /* If an equal sign follows, ignore anything up to the next line end - * or comma. If a comma or line end follows, we're already done. If - * we have none of both, we ignore the remainder of the line. - */ - if (D->Tok == TOK_EQUAL) { - NextToken (D); - while (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) { - NextToken (D); - } - } else if (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) { - SkipLine (D); - } -} - - - -/*****************************************************************************/ -/* Scanner and parser */ -/*****************************************************************************/ - - - -static int DigitVal (int C) -/* Return the value for a numeric digit. Return -1 if C is invalid */ -{ - if (isdigit (C)) { - return C - '0'; - } else if (isxdigit (C)) { - return toupper (C) - 'A' + 10; - } else { - return -1; - } -} + if (isdigit (C)) { + return C - '0'; + } else if (isxdigit (C)) { + return toupper (C) - 'A' + 10; + } else { + return -1; + } +} @@ -3933,14 +4206,11 @@ static void ParseType (InputData* D) goto ErrorExit; } - /* Check Value */ - if (SB_GetLen (&Value) < 2 || (SB_GetLen (&Value) & 0x01) != 0) { - ParseError (D, CC65_ERROR, "Invalid type value"); + /* Parse the type string to create the type info */ + T = ParseTypeString (D, &Value); + if (T == 0) { goto ErrorExit; } - - /* Create the type info */ - T = NewTypeInfo (&Value); T->Id = Id; /* Remember it */ @@ -5786,16 +6056,16 @@ void cc65_free_sourceinfo (cc65_dbginfo Handle, const cc65_sourceinfo* Info) /*****************************************************************************/ -/* Segments */ +/* Scopes */ /*****************************************************************************/ -const cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle) -/* Return a list of all segments referenced in the debug information */ +const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo Handle) +/* Return a list of all scopes in the debug information */ { const DbgInfo* Info; - cc65_segmentinfo* D; + cc65_scopeinfo* D; unsigned I; /* Check the parameter */ @@ -5805,12 +6075,12 @@ const cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle) Info = Handle; /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_segmentinfo (CollCount (&Info->SegInfoById)); + D = new_cc65_scopeinfo (CollCount (&Info->ScopeInfoById)); /* Fill in the data */ - for (I = 0; I < CollCount (&Info->SegInfoById); ++I) { + for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) { /* Copy the data */ - CopySegInfo (D->data + I, CollAt (&Info->SegInfoById, I)); + CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoById, I)); } /* Return the result */ @@ -5819,14 +6089,13 @@ const cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle) -const cc65_segmentinfo* cc65_segment_byid (cc65_dbginfo Handle, unsigned Id) -/* Return information about a segment with a specific id. The function returns - * NULL if the id is invalid (no such segment) and otherwise a segmentinfo - * structure with one entry that contains the requested segment information. +const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id) +/* Return the scope with a given id. The function returns NULL if no scope + * with this id was found. */ { const DbgInfo* Info; - cc65_segmentinfo* D; + cc65_scopeinfo* D; /* Check the parameter */ assert (Handle != 0); @@ -5835,15 +6104,15 @@ const cc65_segmentinfo* cc65_segment_byid (cc65_dbginfo Handle, unsigned Id) Info = Handle; /* Check if the id is valid */ - if (Id >= CollCount (&Info->SegInfoById)) { + if (Id >= CollCount (&Info->ScopeInfoById)) { return 0; } /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_segmentinfo (1); + D = new_cc65_scopeinfo (1); /* Fill in the data */ - CopySegInfo (D->data, CollAt (&Info->SegInfoById, Id)); + CopyScopeInfo (D->data, CollAt (&Info->ScopeInfoById, Id)); /* Return the result */ return D; @@ -5851,17 +6120,15 @@ const cc65_segmentinfo* cc65_segment_byid (cc65_dbginfo Handle, unsigned Id) -const cc65_segmentinfo* cc65_segment_byname (cc65_dbginfo Handle, - const char* Name) -/* Return information about a segment with a specific name. The function - * returns NULL if no segment with this name exists and otherwise a - * cc65_segmentinfo structure with one entry that contains the requested - * information. +const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo Handle, unsigned ModId) +/* Return the list of scopes for one module. The function returns NULL if no + * scope with the given id was found. */ { const DbgInfo* Info; - const SegInfo* S; - cc65_segmentinfo* D; + const ModInfo* M; + cc65_scopeinfo* D; + unsigned I; /* Check the parameter */ assert (Handle != 0); @@ -5869,17 +6136,21 @@ const cc65_segmentinfo* cc65_segment_byname (cc65_dbginfo Handle, /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Search for the segment */ - S = FindSegInfoByName (&Info->SegInfoByName, Name); - if (S == 0) { + /* Check if the module id is valid */ + if (ModId >= CollCount (&Info->ModInfoById)) { return 0; } + /* Get a pointer to the module info */ + M = CollAt (&Info->ModInfoById, ModId); + /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_segmentinfo (1); + D = new_cc65_scopeinfo (CollCount (&M->ScopeInfoByName)); /* Fill in the data */ - CopySegInfo (D->data, S); + for (I = 0; I < CollCount (&M->ScopeInfoByName); ++I) { + CopyScopeInfo (D->data + I, CollAt (&M->ScopeInfoByName, I)); + } /* Return the result */ return D; @@ -5887,31 +6158,18 @@ const cc65_segmentinfo* cc65_segment_byname (cc65_dbginfo Handle, -void cc65_free_segmentinfo (cc65_dbginfo Handle, const cc65_segmentinfo* Info) -/* Free a segment info record */ -{ - /* Just for completeness, check the handle */ - assert (Handle != 0); - - /* Free the memory */ - xfree ((cc65_segmentinfo*) Info); -} - - - -/*****************************************************************************/ -/* Symbols */ -/*****************************************************************************/ - - - -const cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id) -/* Return the symbol with a given id. The function returns NULL if no symbol - * with this id was found. +const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo Handle, const char* Name) +/* Return the list of scopes with a given name. Returns NULL if no scope with + * the given name was found, otherwise a non empty scope list. */ { const DbgInfo* Info; - cc65_symbolinfo* D; + unsigned Index; + const ScopeInfo* S; + cc65_scopeinfo* D; + unsigned Count; + unsigned I; + /* Check the parameter */ assert (Handle != 0); @@ -5919,16 +6177,34 @@ const cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id) /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Check if the id is valid */ - if (Id >= CollCount (&Info->SymInfoById)) { + /* Search for the first item with the given name */ + if (!FindScopeInfoByName (&Info->ScopeInfoByName, Name, &Index)) { + /* Not found */ return 0; } + /* Count scopes with this name */ + Count = 1; + I = Index; + while (1) { + if (++I >= CollCount (&Info->ScopeInfoByName)) { + break; + } + S = CollAt (&Info->ScopeInfoByName, I); + if (strcmp (S->Name, Name) != 0) { + /* Next symbol has another name */ + break; + } + ++Count; + } + /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_symbolinfo (1); + D = new_cc65_scopeinfo (Count); /* Fill in the data */ - CopySymInfo (D->data, CollAt (&Info->SymInfoById, Id)); + for (I = 0; I < Count; ++I, ++Index) { + CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoByName, Index)); + } /* Return the result */ return D; @@ -5936,16 +6212,15 @@ const cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id) -const cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name) -/* Return a list of symbols with a given name. The function returns NULL if - * no symbol with this name was found. +const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo Handle, unsigned SpanId) +/* Return scope information for a a span. The function returns NULL if the + * span id is invalid, otherwise a list of line scopes. */ { const DbgInfo* Info; - cc65_symbolinfo* D; + const SpanInfo* S; + cc65_scopeinfo* D; unsigned I; - unsigned Index; - unsigned Count; /* Check the parameter */ assert (Handle != 0); @@ -5953,52 +6228,42 @@ const cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Search for the symbol */ - if (!FindSymInfoByName (&Info->SymInfoByName, Name, &Index)) { - /* Not found */ + /* Check if the span id is valid */ + if (SpanId >= CollCount (&Info->SpanInfoById)) { return 0; } - /* Index contains the position. Count how many symbols with this name - * we have. Skip the first one, since we have at least one. - */ - Count = 1; - while ((unsigned) Index + Count < CollCount (&Info->SymInfoByName)) { - const SymInfo* S = CollAt (&Info->SymInfoByName, (unsigned) Index + Count); - if (strcmp (S->Name, Name) != 0) { - break; - } - ++Count; - } + /* Get the span */ + S = CollAt (&Info->SpanInfoById, SpanId); - /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_symbolinfo (Count); + /* Prepare the struct we will return to the caller */ + D = new_cc65_scopeinfo (S->ScopeInfoList? CollCount (S->ScopeInfoList) : 0); - /* Fill in the data */ - for (I = 0; I < Count; ++I) { + /* Fill in the data. Since D->ScopeInfoList may be NULL, we will use the + * count field of the returned data struct instead. + */ + for (I = 0; I < D->count; ++I) { /* Copy the data */ - CopySymInfo (D->data + I, CollAt (&Info->SymInfoByName, Index++)); + CopyScopeInfo (D->data + I, CollAt (S->ScopeInfoList, I)); } - /* Return the result */ + /* Return the allocated struct */ return D; } -const cc65_symbolinfo* cc65_symbol_byscope (cc65_dbginfo Handle, unsigned ScopeId) -/* Return a list of symbols in the given scope. This includes cheap local - * symbols, but not symbols in subscopes. The function returns NULL if the - * scope id is invalid (no such scope) and otherwise a - possibly empty - - * symbol list. +const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo Handle, unsigned Id) +/* Return the direct child scopes of a scope with a given id. The function + * returns NULL if no scope with this id was found, otherwise a list of the + * direct childs. */ { const DbgInfo* Info; - cc65_symbolinfo* D; + cc65_scopeinfo* D; const ScopeInfo* S; unsigned I; - /* Check the parameter */ assert (Handle != 0); @@ -6006,20 +6271,19 @@ const cc65_symbolinfo* cc65_symbol_byscope (cc65_dbginfo Handle, unsigned ScopeI Info = Handle; /* Check if the id is valid */ - if (ScopeId >= CollCount (&Info->ScopeInfoById)) { + if (Id >= CollCount (&Info->ScopeInfoById)) { return 0; } /* Get the scope */ - S = CollAt (&Info->ScopeInfoById, ScopeId); + S = CollAt (&Info->ScopeInfoById, Id); /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_symbolinfo (CollCount (&S->SymInfoByName)); + D = new_cc65_scopeinfo (S->ChildScopeList? CollCount (S->ChildScopeList) : 0); /* Fill in the data */ - for (I = 0; I < CollCount (&S->SymInfoByName); ++I) { - /* Copy the data */ - CopySymInfo (D->data + I, CollAt (&S->SymInfoByName, I)); + for (I = 0; I < D->count; ++I) { + CopyScopeInfo (D->data + I, CollAt (S->ChildScopeList, I)); } /* Return the result */ @@ -6028,103 +6292,60 @@ const cc65_symbolinfo* cc65_symbol_byscope (cc65_dbginfo Handle, unsigned ScopeI -const cc65_symbolinfo* cc65_symbol_inrange (cc65_dbginfo Handle, cc65_addr Start, - cc65_addr End) -/* Return a list of labels in the given range. End is inclusive. The function - * return NULL if no symbols within the given range are found. Non label - * symbols are ignored and not returned. - */ +void cc65_free_scopeinfo (cc65_dbginfo Handle, const cc65_scopeinfo* Info) +/* Free a scope info record */ { - const DbgInfo* Info; - Collection SymInfoList = COLLECTION_INITIALIZER; - cc65_symbolinfo* D; - unsigned I; - unsigned Index; - - /* Check the parameter */ + /* Just for completeness, check the handle */ assert (Handle != 0); - /* The handle is actually a pointer to a debug info struct */ - Info = Handle; + /* Free the memory */ + xfree ((cc65_scopeinfo*) Info); +} - /* Search for the symbol. Because we're searching for a range, we cannot - * make use of the function result. - */ - FindSymInfoByValue (&Info->SymInfoByVal, Start, &Index); - /* Start from the given index, check all symbols until the end address is - * reached. Place all symbols into SymInfoList for later. - */ - for (I = Index; I < CollCount (&Info->SymInfoByVal); ++I) { - /* Get the item */ - SymInfo* Item = CollAt (&Info->SymInfoByVal, I); +/*****************************************************************************/ +/* Segments */ +/*****************************************************************************/ - /* The collection is sorted by address, so if we get a value larger - * than the end address, we're done. - */ - if (Item->Value > (long) End) { - break; - } - /* Ignore non-labels (this will also ignore imports) */ - if (Item->Type != CC65_SYM_LABEL) { - continue; - } - /* Ok, remember this one */ - CollAppend (&SymInfoList, Item); - } +const cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle) +/* Return a list of all segments referenced in the debug information */ +{ + const DbgInfo* Info; + cc65_segmentinfo* D; + unsigned I; - /* If we don't have any labels within the range, bail out. No memory has - * been allocated for SymInfoList. - */ - if (CollCount (&SymInfoList) == 0) { - return 0; - } + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_symbolinfo (CollCount (&SymInfoList)); + D = new_cc65_segmentinfo (CollCount (&Info->SegInfoById)); /* Fill in the data */ - for (I = 0; I < CollCount (&SymInfoList); ++I) { + for (I = 0; I < CollCount (&Info->SegInfoById); ++I) { /* Copy the data */ - CopySymInfo (D->data + I, CollAt (&SymInfoList, I)); + CopySegInfo (D->data + I, CollAt (&Info->SegInfoById, I)); } - /* Free the collection */ - CollDone (&SymInfoList); - /* Return the result */ return D; } -void cc65_free_symbolinfo (cc65_dbginfo Handle, const cc65_symbolinfo* Info) -/* Free a symbol info record */ -{ - /* Just for completeness, check the handle */ - assert (Handle != 0); - - /* Free the memory */ - xfree ((cc65_symbolinfo*) Info); -} - - - -/*****************************************************************************/ -/* Scopes */ -/*****************************************************************************/ - - - -const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo Handle) -/* Return a list of all scopes in the debug information */ +const cc65_segmentinfo* cc65_segment_byid (cc65_dbginfo Handle, unsigned Id) +/* Return information about a segment with a specific id. The function returns + * NULL if the id is invalid (no such segment) and otherwise a segmentinfo + * structure with one entry that contains the requested segment information. + */ { const DbgInfo* Info; - cc65_scopeinfo* D; - unsigned I; + cc65_segmentinfo* D; /* Check the parameter */ assert (Handle != 0); @@ -6132,14 +6353,16 @@ const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo Handle) /* The handle is actually a pointer to a debug info struct */ Info = Handle; + /* Check if the id is valid */ + if (Id >= CollCount (&Info->SegInfoById)) { + return 0; + } + /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_scopeinfo (CollCount (&Info->ScopeInfoById)); + D = new_cc65_segmentinfo (1); /* Fill in the data */ - for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) { - /* Copy the data */ - CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoById, I)); - } + CopySegInfo (D->data, CollAt (&Info->SegInfoById, Id)); /* Return the result */ return D; @@ -6147,13 +6370,17 @@ const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo Handle) -const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id) -/* Return the scope with a given id. The function returns NULL if no scope - * with this id was found. +const cc65_segmentinfo* cc65_segment_byname (cc65_dbginfo Handle, + const char* Name) +/* Return information about a segment with a specific name. The function + * returns NULL if no segment with this name exists and otherwise a + * cc65_segmentinfo structure with one entry that contains the requested + * information. */ { const DbgInfo* Info; - cc65_scopeinfo* D; + const SegInfo* S; + cc65_segmentinfo* D; /* Check the parameter */ assert (Handle != 0); @@ -6161,16 +6388,17 @@ const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id) /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Check if the id is valid */ - if (Id >= CollCount (&Info->ScopeInfoById)) { + /* Search for the segment */ + S = FindSegInfoByName (&Info->SegInfoByName, Name); + if (S == 0) { return 0; } /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_scopeinfo (1); + D = new_cc65_segmentinfo (1); /* Fill in the data */ - CopyScopeInfo (D->data, CollAt (&Info->ScopeInfoById, Id)); + CopySegInfo (D->data, S); /* Return the result */ return D; @@ -6178,15 +6406,31 @@ const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id) -const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo Handle, unsigned ModId) -/* Return the list of scopes for one module. The function returns NULL if no - * scope with the given id was found. +void cc65_free_segmentinfo (cc65_dbginfo Handle, const cc65_segmentinfo* Info) +/* Free a segment info record */ +{ + /* Just for completeness, check the handle */ + assert (Handle != 0); + + /* Free the memory */ + xfree ((cc65_segmentinfo*) Info); +} + + + +/*****************************************************************************/ +/* Symbols */ +/*****************************************************************************/ + + + +const cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id) +/* Return the symbol with a given id. The function returns NULL if no symbol + * with this id was found. */ { const DbgInfo* Info; - const ModInfo* M; - cc65_scopeinfo* D; - unsigned I; + cc65_symbolinfo* D; /* Check the parameter */ assert (Handle != 0); @@ -6194,21 +6438,16 @@ const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo Handle, unsigned ModId) /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Check if the module id is valid */ - if (ModId >= CollCount (&Info->ModInfoById)) { + /* Check if the id is valid */ + if (Id >= CollCount (&Info->SymInfoById)) { return 0; } - /* Get a pointer to the module info */ - M = CollAt (&Info->ModInfoById, ModId); - /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_scopeinfo (CollCount (&M->ScopeInfoByName)); + D = new_cc65_symbolinfo (1); /* Fill in the data */ - for (I = 0; I < CollCount (&M->ScopeInfoByName); ++I) { - CopyScopeInfo (D->data + I, CollAt (&M->ScopeInfoByName, I)); - } + CopySymInfo (D->data, CollAt (&Info->SymInfoById, Id)); /* Return the result */ return D; @@ -6216,18 +6455,16 @@ const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo Handle, unsigned ModId) -const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo Handle, const char* Name) -/* Return the list of scopes with a given name. Returns NULL if no scope with - * the given name was found, otherwise a non empty scope list. +const cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name) +/* Return a list of symbols with a given name. The function returns NULL if + * no symbol with this name was found. */ { const DbgInfo* Info; + cc65_symbolinfo* D; + unsigned I; unsigned Index; - const ScopeInfo* S; - cc65_scopeinfo* D; unsigned Count; - unsigned I; - /* Check the parameter */ assert (Handle != 0); @@ -6235,33 +6472,31 @@ const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo Handle, const char* Name) /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Search for the first item with the given name */ - if (!FindScopeInfoByName (&Info->ScopeInfoByName, Name, &Index)) { + /* Search for the symbol */ + if (!FindSymInfoByName (&Info->SymInfoByName, Name, &Index)) { /* Not found */ return 0; } - /* Count scopes with this name */ + /* Index contains the position. Count how many symbols with this name + * we have. Skip the first one, since we have at least one. + */ Count = 1; - I = Index; - while (1) { - if (++I >= CollCount (&Info->ScopeInfoByName)) { - break; - } - S = CollAt (&Info->ScopeInfoByName, I); + while ((unsigned) Index + Count < CollCount (&Info->SymInfoByName)) { + const SymInfo* S = CollAt (&Info->SymInfoByName, (unsigned) Index + Count); if (strcmp (S->Name, Name) != 0) { - /* Next symbol has another name */ break; } ++Count; } /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_scopeinfo (Count); + D = new_cc65_symbolinfo (Count); /* Fill in the data */ - for (I = 0; I < Count; ++I, ++Index) { - CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoByName, Index)); + for (I = 0; I < Count; ++I) { + /* Copy the data */ + CopySymInfo (D->data + I, CollAt (&Info->SymInfoByName, Index++)); } /* Return the result */ @@ -6270,57 +6505,60 @@ const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo Handle, const char* Name) -const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo Handle, unsigned SpanId) -/* Return scope information for a a span. The function returns NULL if the - * span id is invalid, otherwise a list of line scopes. +const cc65_symbolinfo* cc65_symbol_byscope (cc65_dbginfo Handle, unsigned ScopeId) +/* Return a list of symbols in the given scope. This includes cheap local + * symbols, but not symbols in subscopes. The function returns NULL if the + * scope id is invalid (no such scope) and otherwise a - possibly empty - + * symbol list. */ { const DbgInfo* Info; - const SpanInfo* S; - cc65_scopeinfo* D; + cc65_symbolinfo* D; + const ScopeInfo* S; unsigned I; + /* Check the parameter */ assert (Handle != 0); /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Check if the span id is valid */ - if (SpanId >= CollCount (&Info->SpanInfoById)) { + /* Check if the id is valid */ + if (ScopeId >= CollCount (&Info->ScopeInfoById)) { return 0; } - /* Get the span */ - S = CollAt (&Info->SpanInfoById, SpanId); + /* Get the scope */ + S = CollAt (&Info->ScopeInfoById, ScopeId); - /* Prepare the struct we will return to the caller */ - D = new_cc65_scopeinfo (S->ScopeInfoList? CollCount (S->ScopeInfoList) : 0); + /* Allocate memory for the data structure returned to the caller */ + D = new_cc65_symbolinfo (CollCount (&S->SymInfoByName)); - /* Fill in the data. Since D->ScopeInfoList may be NULL, we will use the - * count field of the returned data struct instead. - */ - for (I = 0; I < D->count; ++I) { + /* Fill in the data */ + for (I = 0; I < CollCount (&S->SymInfoByName); ++I) { /* Copy the data */ - CopyScopeInfo (D->data + I, CollAt (S->ScopeInfoList, I)); + CopySymInfo (D->data + I, CollAt (&S->SymInfoByName, I)); } - /* Return the allocated struct */ + /* Return the result */ return D; } -const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo Handle, unsigned Id) -/* Return the direct child scopes of a scope with a given id. The function - * returns NULL if no scope with this id was found, otherwise a list of the - * direct childs. +const cc65_symbolinfo* cc65_symbol_inrange (cc65_dbginfo Handle, cc65_addr Start, + cc65_addr End) +/* Return a list of labels in the given range. End is inclusive. The function + * return NULL if no symbols within the given range are found. Non label + * symbols are ignored and not returned. */ { const DbgInfo* Info; - cc65_scopeinfo* D; - const ScopeInfo* S; + Collection SymInfoList = COLLECTION_INITIALIZER; + cc65_symbolinfo* D; unsigned I; + unsigned Index; /* Check the parameter */ assert (Handle != 0); @@ -6328,38 +6566,114 @@ const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo Handle, unsigned Id) /* The handle is actually a pointer to a debug info struct */ Info = Handle; - /* Check if the id is valid */ - if (Id >= CollCount (&Info->ScopeInfoById)) { - return 0; + /* Search for the symbol. Because we're searching for a range, we cannot + * make use of the function result. + */ + FindSymInfoByValue (&Info->SymInfoByVal, Start, &Index); + + /* Start from the given index, check all symbols until the end address is + * reached. Place all symbols into SymInfoList for later. + */ + for (I = Index; I < CollCount (&Info->SymInfoByVal); ++I) { + + /* Get the item */ + SymInfo* Item = CollAt (&Info->SymInfoByVal, I); + + /* The collection is sorted by address, so if we get a value larger + * than the end address, we're done. + */ + if (Item->Value > (long) End) { + break; + } + + /* Ignore non-labels (this will also ignore imports) */ + if (Item->Type != CC65_SYM_LABEL) { + continue; + } + + /* Ok, remember this one */ + CollAppend (&SymInfoList, Item); } - /* Get the scope */ - S = CollAt (&Info->ScopeInfoById, Id); + /* If we don't have any labels within the range, bail out. No memory has + * been allocated for SymInfoList. + */ + if (CollCount (&SymInfoList) == 0) { + return 0; + } /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_scopeinfo (S->ChildScopeList? CollCount (S->ChildScopeList) : 0); + D = new_cc65_symbolinfo (CollCount (&SymInfoList)); /* Fill in the data */ - for (I = 0; I < D->count; ++I) { - CopyScopeInfo (D->data + I, CollAt (S->ChildScopeList, I)); + for (I = 0; I < CollCount (&SymInfoList); ++I) { + /* Copy the data */ + CopySymInfo (D->data + I, CollAt (&SymInfoList, I)); } + /* Free the collection */ + CollDone (&SymInfoList); + /* Return the result */ return D; } -void cc65_free_scopeinfo (cc65_dbginfo Handle, const cc65_scopeinfo* Info) -/* Free a scope info record */ +void cc65_free_symbolinfo (cc65_dbginfo Handle, const cc65_symbolinfo* Info) +/* Free a symbol info record */ { /* Just for completeness, check the handle */ assert (Handle != 0); /* Free the memory */ - xfree ((cc65_scopeinfo*) Info); + xfree ((cc65_symbolinfo*) Info); } +/*****************************************************************************/ +/* Types */ +/*****************************************************************************/ + + + +const cc65_typedata* cc65_type_byid (cc65_dbginfo Handle, unsigned Id) +/* Return the data for the type with the given id. The function returns NULL + * if no type with this id was found. + */ +{ + const DbgInfo* Info; + const TypeInfo* T; + + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; + + /* Check if the id is valid */ + if (Id >= CollCount (&Info->TypeInfoById)) { + return 0; + } + + /* Get the type info with the given id */ + T = CollAt (&Info->TypeInfoById, Id); + + /* We do already have the type data. Return it. */ + return T->Data; +} + + + +void cc65_free_typedata (cc65_dbginfo Handle, const cc65_typedata* data) +/* Free a symbol info record */ +{ + /* Just for completeness, check the handle and the data*/ + assert (Handle != 0 && data != 0); + + /* Nothing to do */ +} + + diff --git a/src/dbginfo/dbginfo.h b/src/dbginfo/dbginfo.h index 48d398299..b2d77340c 100644 --- a/src/dbginfo/dbginfo.h +++ b/src/dbginfo/dbginfo.h @@ -359,6 +359,74 @@ void cc65_free_sourceinfo (cc65_dbginfo handle, const cc65_sourceinfo* info); +/*****************************************************************************/ +/* Scopes */ +/*****************************************************************************/ + + + +/* Scope information */ +typedef enum { + CC65_SCOPE_GLOBAL, /* Global scope */ + CC65_SCOPE_MODULE, /* Module scope */ + CC65_SCOPE_SCOPE, /* .PROC/.SCOPE */ + CC65_SCOPE_STRUCT, /* .STRUCT */ + CC65_SCOPE_ENUM, /* .ENUM */ +} cc65_scope_type; + +typedef struct cc65_scopedata cc65_scopedata; +struct cc65_scopedata { + unsigned scope_id; /* Id of scope */ + const char* scope_name; /* Name of scope */ + cc65_scope_type scope_type; /* Type of scope */ + cc65_size scope_size; /* Size of scope, 0 if unknown */ + unsigned parent_id; /* Id of parent scope */ + unsigned symbol_id; /* Id of scope symbol if any */ + unsigned module_id; /* Id of the module */ +}; + +typedef struct cc65_scopeinfo cc65_scopeinfo; +struct cc65_scopeinfo { + unsigned count; /* Number of data sets that follow */ + cc65_scopedata data[1]; /* Data sets, number is dynamic */ +}; + + + +const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo handle); +/* Return a list of all scopes in the debug information */ + +const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo handle, unsigned id); +/* Return the scope with a given id. The function returns NULL if no scope + * with this id was found. + */ + +const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo handle, unsigned module_id); +/* Return the list of scopes for one module. The function returns NULL if no + * scope with the given id was found. + */ + +const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo handle, const char* name); +/* Return the list of scopes with a given name. Returns NULL if no scope with + * the given name was found, otherwise a non empty scope list. + */ + +const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo handle, unsigned span_id); +/* Return scope information for a a span. The function returns NULL if the + * span id is invalid, otherwise a list of line scopes. + */ + +const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo handle, unsigned id); +/* Return the direct child scopes of a scope with a given id. The function + * returns NULL if no scope with this id was found, otherwise a list of the + * direct childs. + */ + +void cc65_free_scopeinfo (cc65_dbginfo Handle, const cc65_scopeinfo* Info); +/* Free a scope info record */ + + + /*****************************************************************************/ /* Segments */ /*****************************************************************************/ @@ -484,76 +552,74 @@ const cc65_symbolinfo* cc65_symbol_inrange (cc65_dbginfo handle, * symbols are ignored and not returned. */ -void cc65_free_symbolinfo (cc65_dbginfo Handle, const cc65_symbolinfo* Info); +void cc65_free_symbolinfo (cc65_dbginfo handle, const cc65_symbolinfo* info); /* Free a symbol info record */ /*****************************************************************************/ -/* Scopes */ +/* Types */ /*****************************************************************************/ -/* Scope information */ +/* Type information */ typedef enum { - CC65_SCOPE_GLOBAL, /* Global scope */ - CC65_SCOPE_MODULE, /* Module scope */ - CC65_SCOPE_SCOPE, /* .PROC/.SCOPE */ - CC65_SCOPE_STRUCT, /* .STRUCT */ - CC65_SCOPE_ENUM, /* .ENUM */ -} cc65_scope_type; - -typedef struct cc65_scopedata cc65_scopedata; -struct cc65_scopedata { - unsigned scope_id; /* Id of scope */ - const char* scope_name; /* Name of scope */ - cc65_scope_type scope_type; /* Type of scope */ - cc65_size scope_size; /* Size of scope, 0 if unknown */ - unsigned parent_id; /* Id of parent scope */ - unsigned symbol_id; /* Id of scope symbol if any */ - unsigned module_id; /* Id of the module */ -}; - -typedef struct cc65_scopeinfo cc65_scopeinfo; -struct cc65_scopeinfo { - unsigned count; /* Number of data sets that follow */ - cc65_scopedata data[1]; /* Data sets, number is dynamic */ -}; - - - -const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo handle); -/* Return a list of all scopes in the debug information */ - -const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo handle, unsigned id); -/* Return the scope with a given id. The function returns NULL if no scope - * with this id was found. - */ - -const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo handle, unsigned module_id); -/* Return the list of scopes for one module. The function returns NULL if no - * scope with the given id was found. + CC65_TYPE_VOID, + CC65_TYPE_BYTE, + CC65_TYPE_WORD, + CC65_TYPE_DBYTE, + CC65_TYPE_DWORD, + CC65_TYPE_PTR, + CC65_TYPE_FARPTR, + CC65_TYPE_ARRAY, + + /* The following ones are currently unavailable: */ + CC65_TYPE_UNION, + CC65_TYPE_STRUCT, + CC65_TYPE_FUNC, +} cc65_typetoken; + + +/* A type is a linked list of typedata structures. In case of arrays, the + * structure will contain an element count and the element type. In case of + * pointers, the structure will contain the type of the data, the pointer + * points to (currently, there are only VOID pointers). + * The next pointer points to the next entry in the list. It is NULL if the + * end of the list is reached. */ +typedef struct cc65_typedata cc65_typedata; +struct cc65_typedata { + cc65_typedata* next; /* Pointer to next entry */ + cc65_typetoken what; /* What kind of type is it? */ + cc65_size size; /* The size of the data */ + + /* Depending on "what", one of the members of this union follows */ + union { + + /* In case of CC65_TYPE_PTR or CC65_TYPE_FARPTR */ + struct { + cc65_typedata* ind_type; /* Type the pointer points to */ + } ptr; + + /* In case of CC65_TYPE_ARRAY */ + struct { + cc65_size ele_count; /* Element count */ + const cc65_typedata* ele_type; /* Element type */ + } array; + + } data; +}; -const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo handle, const char* name); -/* Return the list of scopes with a given name. Returns NULL if no scope with - * the given name was found, otherwise a non empty scope list. - */ -const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo handle, unsigned span_id); -/* Return scope information for a a span. The function returns NULL if the - * span id is invalid, otherwise a list of line scopes. - */ -const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo handle, unsigned id); -/* Return the direct child scopes of a scope with a given id. The function - * returns NULL if no scope with this id was found, otherwise a list of the - * direct childs. +const cc65_typedata* cc65_type_byid (cc65_dbginfo handle, unsigned id); +/* Return the data for the type with the given id. The function returns NULL + * if no type with this id was found. */ -void cc65_free_scopeinfo (cc65_dbginfo Handle, const cc65_scopeinfo* Info); -/* Free a scope info record */ +void cc65_free_typedata (cc65_dbginfo Handle, const cc65_typedata* data); +/* Free a symbol info record */ -- 2.39.5