mirror of
https://github.com/cc65/cc65.git
synced 2024-12-25 17:29:50 +00:00
Track types, parse the extended debug info format with "type" lines.
git-svn-id: svn://svn.cc65.org/cc65/trunk@5264 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
374b106b06
commit
3b61ee2f5a
@ -192,6 +192,7 @@ struct DbgInfo {
|
|||||||
Collection SegInfoById; /* Segment infos sorted by id */
|
Collection SegInfoById; /* Segment infos sorted by id */
|
||||||
Collection SpanInfoById; /* Span infos sorted by id */
|
Collection SpanInfoById; /* Span infos sorted by id */
|
||||||
Collection SymInfoById; /* Symbol infos sorted by id */
|
Collection SymInfoById; /* Symbol infos sorted by id */
|
||||||
|
Collection TypeInfoById; /* Type infos sorted by id */
|
||||||
|
|
||||||
/* Collections with other sort criteria */
|
/* Collections with other sort criteria */
|
||||||
Collection FileInfoByName; /* File infos sorted by name */
|
Collection FileInfoByName; /* File infos sorted by name */
|
||||||
@ -238,6 +239,7 @@ typedef struct ScopeInfo ScopeInfo;
|
|||||||
typedef struct SegInfo SegInfo;
|
typedef struct SegInfo SegInfo;
|
||||||
typedef struct SpanInfo SpanInfo;
|
typedef struct SpanInfo SpanInfo;
|
||||||
typedef struct SymInfo SymInfo;
|
typedef struct SymInfo SymInfo;
|
||||||
|
typedef struct TypeInfo TypeInfo;
|
||||||
|
|
||||||
/* Internally used file info struct */
|
/* Internally used file info struct */
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
@ -327,6 +329,10 @@ struct SpanInfo {
|
|||||||
unsigned Id; /* Id of segment */
|
unsigned Id; /* Id of segment */
|
||||||
SegInfo* Info; /* Pointer to segment */
|
SegInfo* Info; /* Pointer to segment */
|
||||||
} Seg;
|
} Seg;
|
||||||
|
union {
|
||||||
|
unsigned Id; /* Id of type */
|
||||||
|
TypeInfo* Info; /* Pointer to type */
|
||||||
|
} Type;
|
||||||
Collection* ScopeInfoList; /* Scopes for this span */
|
Collection* ScopeInfoList; /* Scopes for this span */
|
||||||
Collection* LineInfoList; /* Lines for this span */
|
Collection* LineInfoList; /* Lines for this span */
|
||||||
};
|
};
|
||||||
@ -360,6 +366,13 @@ struct SymInfo {
|
|||||||
char Name[1]; /* Name of symbol */
|
char Name[1]; /* Name of symbol */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -1485,6 +1498,11 @@ static void CopySpanInfo (cc65_spandata* D, const SpanInfo* S)
|
|||||||
D->span_start = S->Start;
|
D->span_start = S->Start;
|
||||||
D->span_end = S->End;
|
D->span_end = S->End;
|
||||||
D->segment_id = S->Seg.Info->Id;
|
D->segment_id = S->Seg.Info->Id;
|
||||||
|
if (S->Type.Info) {
|
||||||
|
D->type_id = S->Type.Info->Id;
|
||||||
|
} else {
|
||||||
|
D->type_id = CC65_INV_ID;
|
||||||
|
}
|
||||||
if (S->ScopeInfoList) {
|
if (S->ScopeInfoList) {
|
||||||
D->scope_count = CollCount (S->ScopeInfoList);
|
D->scope_count = CollCount (S->ScopeInfoList);
|
||||||
} else {
|
} else {
|
||||||
@ -1639,6 +1657,62 @@ static int CompareSymInfoByVal (const void* L, const void* R)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Type info */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 TypeInfo* NewTypeInfo (const StrBuf* ReadableValue)
|
||||||
|
/* Create a new TypeInfo struct, intialize and return it */
|
||||||
|
{
|
||||||
|
unsigned I;
|
||||||
|
const char* P;
|
||||||
|
|
||||||
|
/* 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++));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return it */
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void FreeTypeInfo (TypeInfo* T)
|
||||||
|
/* Free a TypeInfo struct */
|
||||||
|
{
|
||||||
|
xfree (T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* SpanInfoList */
|
/* SpanInfoList */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -1854,6 +1928,7 @@ static DbgInfo* NewDbgInfo (const char* FileName)
|
|||||||
CollInit (&Info->SegInfoById);
|
CollInit (&Info->SegInfoById);
|
||||||
CollInit (&Info->SpanInfoById);
|
CollInit (&Info->SpanInfoById);
|
||||||
CollInit (&Info->SymInfoById);
|
CollInit (&Info->SymInfoById);
|
||||||
|
CollInit (&Info->TypeInfoById);
|
||||||
|
|
||||||
CollInit (&Info->FileInfoByName);
|
CollInit (&Info->FileInfoByName);
|
||||||
CollInit (&Info->ModInfoByName);
|
CollInit (&Info->ModInfoByName);
|
||||||
@ -1905,6 +1980,9 @@ static void FreeDbgInfo (DbgInfo* Info)
|
|||||||
for (I = 0; I < CollCount (&Info->SymInfoById); ++I) {
|
for (I = 0; I < CollCount (&Info->SymInfoById); ++I) {
|
||||||
FreeSymInfo (CollAt (&Info->SymInfoById, I));
|
FreeSymInfo (CollAt (&Info->SymInfoById, I));
|
||||||
}
|
}
|
||||||
|
for (I = 0; I < CollCount (&Info->TypeInfoById); ++I) {
|
||||||
|
FreeTypeInfo (CollAt (&Info->TypeInfoById, I));
|
||||||
|
}
|
||||||
|
|
||||||
/* Free the memory used by the id collections */
|
/* Free the memory used by the id collections */
|
||||||
CollDone (&Info->FileInfoById);
|
CollDone (&Info->FileInfoById);
|
||||||
@ -1915,6 +1993,7 @@ static void FreeDbgInfo (DbgInfo* Info)
|
|||||||
CollDone (&Info->SegInfoById);
|
CollDone (&Info->SegInfoById);
|
||||||
CollDone (&Info->SpanInfoById);
|
CollDone (&Info->SpanInfoById);
|
||||||
CollDone (&Info->SymInfoById);
|
CollDone (&Info->SymInfoById);
|
||||||
|
CollDone (&Info->TypeInfoById);
|
||||||
|
|
||||||
/* Free the memory used by the other collections */
|
/* Free the memory used by the other collections */
|
||||||
CollDone (&Info->FileInfoByName);
|
CollDone (&Info->FileInfoByName);
|
||||||
@ -2471,7 +2550,8 @@ static void ParseInfo (InputData* D)
|
|||||||
if (D->Tok != TOK_FILE && D->Tok != TOK_LIBRARY &&
|
if (D->Tok != TOK_FILE && D->Tok != TOK_LIBRARY &&
|
||||||
D->Tok != TOK_LINE && D->Tok != TOK_MODULE &&
|
D->Tok != TOK_LINE && D->Tok != TOK_MODULE &&
|
||||||
D->Tok != TOK_SCOPE && D->Tok != TOK_SEGMENT &&
|
D->Tok != TOK_SCOPE && D->Tok != TOK_SEGMENT &&
|
||||||
D->Tok != TOK_SPAN && D->Tok != TOK_SYM) {
|
D->Tok != TOK_SPAN && D->Tok != TOK_SYM &&
|
||||||
|
D->Tok != TOK_TYPE) {
|
||||||
|
|
||||||
/* Try smart error recovery */
|
/* Try smart error recovery */
|
||||||
if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
|
if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
|
||||||
@ -2536,6 +2616,10 @@ static void ParseInfo (InputData* D)
|
|||||||
CollGrow (&D->Info->SymInfoByVal, D->IVal);
|
CollGrow (&D->Info->SymInfoByVal, D->IVal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_TYPE:
|
||||||
|
CollGrow (&D->Info->TypeInfoById, D->IVal);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
UnexpectedToken (D);
|
UnexpectedToken (D);
|
||||||
@ -3351,7 +3435,7 @@ static void ParseSpan (InputData* D)
|
|||||||
cc65_addr Start = 0;
|
cc65_addr Start = 0;
|
||||||
cc65_addr Size = 0;
|
cc65_addr Size = 0;
|
||||||
unsigned SegId = CC65_INV_ID;
|
unsigned SegId = CC65_INV_ID;
|
||||||
StrBuf Type = STRBUF_INITIALIZER;
|
unsigned TypeId = CC65_INV_ID;
|
||||||
SpanInfo* S;
|
SpanInfo* S;
|
||||||
enum {
|
enum {
|
||||||
ibNone = 0x000,
|
ibNone = 0x000,
|
||||||
@ -3434,13 +3518,12 @@ static void ParseSpan (InputData* D)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_TYPE:
|
case TOK_TYPE:
|
||||||
if (!StrConstFollows (D)) {
|
if (!IntConstFollows (D)) {
|
||||||
goto ErrorExit;
|
goto ErrorExit;
|
||||||
}
|
}
|
||||||
SB_Copy (&Type, &D->SVal);
|
TypeId = D->IVal;
|
||||||
SB_Terminate (&Type);
|
|
||||||
InfoBits |= ibType;
|
|
||||||
NextToken (D);
|
NextToken (D);
|
||||||
|
InfoBits |= ibType;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -3472,15 +3555,15 @@ static void ParseSpan (InputData* D)
|
|||||||
|
|
||||||
/* Create the span info and remember it */
|
/* Create the span info and remember it */
|
||||||
S = NewSpanInfo ();
|
S = NewSpanInfo ();
|
||||||
S->Id = Id;
|
S->Id = Id;
|
||||||
S->Seg.Id = SegId;
|
S->Start = Start;
|
||||||
S->Start = Start;
|
S->End = Start + Size - 1;
|
||||||
S->End = Start + Size - 1;
|
S->Seg.Id = SegId;
|
||||||
|
S->Type.Id = TypeId;
|
||||||
CollReplaceExpand (&D->Info->SpanInfoById, S, Id);
|
CollReplaceExpand (&D->Info->SpanInfoById, S, Id);
|
||||||
|
|
||||||
ErrorExit:
|
ErrorExit:
|
||||||
/* Entry point in case of errors */
|
/* Entry point in case of errors */
|
||||||
SB_Done (&Type);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3755,6 +3838,122 @@ ErrorExit:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void ParseType (InputData* D)
|
||||||
|
/* Parse a TYPE line */
|
||||||
|
{
|
||||||
|
/* Most of the following variables are initialized with a value that is
|
||||||
|
* overwritten later. This is just to avoid compiler warnings.
|
||||||
|
*/
|
||||||
|
unsigned Id = CC65_INV_ID;
|
||||||
|
StrBuf Value = STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
TypeInfo* T;
|
||||||
|
enum {
|
||||||
|
ibNone = 0x0000,
|
||||||
|
|
||||||
|
ibId = 0x01,
|
||||||
|
ibValue = 0x02,
|
||||||
|
|
||||||
|
ibRequired = ibId | ibValue,
|
||||||
|
} InfoBits = ibNone;
|
||||||
|
|
||||||
|
/* Skip the SYM token */
|
||||||
|
NextToken (D);
|
||||||
|
|
||||||
|
/* More stuff follows */
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
Token Tok;
|
||||||
|
|
||||||
|
/* Something we know? */
|
||||||
|
if (D->Tok != TOK_ID && D->Tok != TOK_VALUE) {
|
||||||
|
|
||||||
|
/* 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_VALUE:
|
||||||
|
if (!StrConstFollows (D)) {
|
||||||
|
goto ErrorExit;
|
||||||
|
}
|
||||||
|
SB_Copy (&Value, &D->SVal);
|
||||||
|
InfoBits |= ibValue;
|
||||||
|
NextToken (D);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check Value */
|
||||||
|
if (SB_GetLen (&Value) < 2 || (SB_GetLen (&Value) & 0x01) != 0) {
|
||||||
|
ParseError (D, CC65_ERROR, "Invalid type value");
|
||||||
|
goto ErrorExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the type info */
|
||||||
|
T = NewTypeInfo (&Value);
|
||||||
|
T->Id = Id;
|
||||||
|
|
||||||
|
/* Remember it */
|
||||||
|
CollReplaceExpand (&D->Info->TypeInfoById, T, Id);
|
||||||
|
|
||||||
|
ErrorExit:
|
||||||
|
/* Entry point in case of errors */
|
||||||
|
SB_Done (&Value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseVersion (InputData* D)
|
static void ParseVersion (InputData* D)
|
||||||
/* Parse a VERSION line */
|
/* Parse a VERSION line */
|
||||||
{
|
{
|
||||||
@ -4458,6 +4657,19 @@ static void ProcessSpanInfo (InputData* D)
|
|||||||
S->End += S->Seg.Info->Start;
|
S->End += S->Seg.Info->Start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Resolve the type if we have it */
|
||||||
|
if (S->Type.Id == CC65_INV_ID) {
|
||||||
|
S->Type.Info = 0;
|
||||||
|
} else if (S->Type.Id >= CollCount (&D->Info->TypeInfoById)) {
|
||||||
|
ParseError (D,
|
||||||
|
CC65_ERROR,
|
||||||
|
"Invalid type id %u for span with id %u",
|
||||||
|
S->Type.Id, S->Id);
|
||||||
|
S->Type.Info = 0;
|
||||||
|
} else {
|
||||||
|
S->Type.Info = CollAt (&D->Info->TypeInfoById, S->Type.Id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Append this span info to the temporary collection that is later
|
/* Append this span info to the temporary collection that is later
|
||||||
* sorted by address.
|
* sorted by address.
|
||||||
*/
|
*/
|
||||||
@ -4772,6 +4984,10 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
|||||||
ParseSym (&D);
|
ParseSym (&D);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_TYPE:
|
||||||
|
ParseType (&D);
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_IDENT:
|
case TOK_IDENT:
|
||||||
/* Output a warning, then skip the line with the unknown
|
/* Output a warning, then skip the line with the unknown
|
||||||
* keyword that may have been added by a later version.
|
* keyword that may have been added by a later version.
|
||||||
|
@ -270,6 +270,7 @@ struct cc65_spandata {
|
|||||||
cc65_addr span_start; /* Start of the span */
|
cc65_addr span_start; /* Start of the span */
|
||||||
cc65_addr span_end; /* End of the span (inclusive!) */
|
cc65_addr span_end; /* End of the span (inclusive!) */
|
||||||
unsigned segment_id; /* Id of the segment */
|
unsigned segment_id; /* Id of the segment */
|
||||||
|
unsigned type_id; /* Id of the type of this span */
|
||||||
unsigned line_count; /* Number of lines attached */
|
unsigned line_count; /* Number of lines attached */
|
||||||
unsigned scope_count; /* Number of scopes attached */
|
unsigned scope_count; /* Number of scopes attached */
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user