mirror of
https://github.com/cc65/cc65.git
synced 2024-12-25 02:29:52 +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 SpanInfoById; /* Span infos sorted by id */
|
||||
Collection SymInfoById; /* Symbol infos sorted by id */
|
||||
Collection TypeInfoById; /* Type infos sorted by id */
|
||||
|
||||
/* Collections with other sort criteria */
|
||||
Collection FileInfoByName; /* File infos sorted by name */
|
||||
@ -238,6 +239,7 @@ typedef struct ScopeInfo ScopeInfo;
|
||||
typedef struct SegInfo SegInfo;
|
||||
typedef struct SpanInfo SpanInfo;
|
||||
typedef struct SymInfo SymInfo;
|
||||
typedef struct TypeInfo TypeInfo;
|
||||
|
||||
/* Internally used file info struct */
|
||||
struct FileInfo {
|
||||
@ -327,6 +329,10 @@ struct SpanInfo {
|
||||
unsigned Id; /* Id of segment */
|
||||
SegInfo* Info; /* Pointer to segment */
|
||||
} Seg;
|
||||
union {
|
||||
unsigned Id; /* Id of type */
|
||||
TypeInfo* Info; /* Pointer to type */
|
||||
} Type;
|
||||
Collection* ScopeInfoList; /* Scopes for this span */
|
||||
Collection* LineInfoList; /* Lines for this span */
|
||||
};
|
||||
@ -360,6 +366,13 @@ struct SymInfo {
|
||||
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_end = S->End;
|
||||
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) {
|
||||
D->scope_count = CollCount (S->ScopeInfoList);
|
||||
} 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 */
|
||||
/*****************************************************************************/
|
||||
@ -1854,6 +1928,7 @@ static DbgInfo* NewDbgInfo (const char* FileName)
|
||||
CollInit (&Info->SegInfoById);
|
||||
CollInit (&Info->SpanInfoById);
|
||||
CollInit (&Info->SymInfoById);
|
||||
CollInit (&Info->TypeInfoById);
|
||||
|
||||
CollInit (&Info->FileInfoByName);
|
||||
CollInit (&Info->ModInfoByName);
|
||||
@ -1905,6 +1980,9 @@ static void FreeDbgInfo (DbgInfo* Info)
|
||||
for (I = 0; I < CollCount (&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 */
|
||||
CollDone (&Info->FileInfoById);
|
||||
@ -1915,6 +1993,7 @@ static void FreeDbgInfo (DbgInfo* Info)
|
||||
CollDone (&Info->SegInfoById);
|
||||
CollDone (&Info->SpanInfoById);
|
||||
CollDone (&Info->SymInfoById);
|
||||
CollDone (&Info->TypeInfoById);
|
||||
|
||||
/* Free the memory used by the other collections */
|
||||
CollDone (&Info->FileInfoByName);
|
||||
@ -2471,7 +2550,8 @@ static void ParseInfo (InputData* D)
|
||||
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_SPAN && D->Tok != TOK_SYM &&
|
||||
D->Tok != TOK_TYPE) {
|
||||
|
||||
/* Try smart error recovery */
|
||||
if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
|
||||
@ -2536,6 +2616,10 @@ static void ParseInfo (InputData* D)
|
||||
CollGrow (&D->Info->SymInfoByVal, D->IVal);
|
||||
break;
|
||||
|
||||
case TOK_TYPE:
|
||||
CollGrow (&D->Info->TypeInfoById, D->IVal);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* NOTREACHED */
|
||||
UnexpectedToken (D);
|
||||
@ -3351,7 +3435,7 @@ static void ParseSpan (InputData* D)
|
||||
cc65_addr Start = 0;
|
||||
cc65_addr Size = 0;
|
||||
unsigned SegId = CC65_INV_ID;
|
||||
StrBuf Type = STRBUF_INITIALIZER;
|
||||
unsigned TypeId = CC65_INV_ID;
|
||||
SpanInfo* S;
|
||||
enum {
|
||||
ibNone = 0x000,
|
||||
@ -3434,13 +3518,12 @@ static void ParseSpan (InputData* D)
|
||||
break;
|
||||
|
||||
case TOK_TYPE:
|
||||
if (!StrConstFollows (D)) {
|
||||
if (!IntConstFollows (D)) {
|
||||
goto ErrorExit;
|
||||
}
|
||||
SB_Copy (&Type, &D->SVal);
|
||||
SB_Terminate (&Type);
|
||||
InfoBits |= ibType;
|
||||
TypeId = D->IVal;
|
||||
NextToken (D);
|
||||
InfoBits |= ibType;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -3472,15 +3555,15 @@ static void ParseSpan (InputData* D)
|
||||
|
||||
/* Create the span info and remember it */
|
||||
S = NewSpanInfo ();
|
||||
S->Id = Id;
|
||||
S->Seg.Id = SegId;
|
||||
S->Start = Start;
|
||||
S->End = Start + Size - 1;
|
||||
S->Id = Id;
|
||||
S->Start = Start;
|
||||
S->End = Start + Size - 1;
|
||||
S->Seg.Id = SegId;
|
||||
S->Type.Id = TypeId;
|
||||
CollReplaceExpand (&D->Info->SpanInfoById, S, Id);
|
||||
|
||||
ErrorExit:
|
||||
/* Entry point in case of errors */
|
||||
SB_Done (&Type);
|
||||
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)
|
||||
/* Parse a VERSION line */
|
||||
{
|
||||
@ -4458,6 +4657,19 @@ static void ProcessSpanInfo (InputData* D)
|
||||
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
|
||||
* sorted by address.
|
||||
*/
|
||||
@ -4772,6 +4984,10 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
||||
ParseSym (&D);
|
||||
break;
|
||||
|
||||
case TOK_TYPE:
|
||||
ParseType (&D);
|
||||
break;
|
||||
|
||||
case TOK_IDENT:
|
||||
/* Output a warning, then skip the line with the unknown
|
||||
* 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_end; /* End of the span (inclusive!) */
|
||||
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 scope_count; /* Number of scopes attached */
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user