Major changes: Names of structures, fields and subroutine names have changed.
Support for additional segment info and file offsets for an address. The version number is now mandatory and checked to avoid problems with old formats. git-svn-id: svn://svn.cc65.org/cc65/trunk@4798 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
14e567aed2
commit
99fd891126
3 changed files with 296 additions and 168 deletions
|
@ -52,6 +52,10 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Version numbers of the debug format we understand */
|
||||||
|
#define VER_MAJOR 1U
|
||||||
|
#define VER_MINOR 0U
|
||||||
|
|
||||||
/* Dynamic strings */
|
/* Dynamic strings */
|
||||||
typedef struct StrBuf StrBuf;
|
typedef struct StrBuf StrBuf;
|
||||||
struct StrBuf {
|
struct StrBuf {
|
||||||
|
@ -114,6 +118,8 @@ typedef enum {
|
||||||
TOK_MINOR, /* MINOR keyword */
|
TOK_MINOR, /* MINOR keyword */
|
||||||
TOK_MTIME, /* MTIME keyword */
|
TOK_MTIME, /* MTIME keyword */
|
||||||
TOK_NAME, /* NAME keyword */
|
TOK_NAME, /* NAME keyword */
|
||||||
|
TOK_OUTPUTNAME, /* OUTPUTNAME keyword */
|
||||||
|
TOK_OUTPUTOFFS, /* OUTPUTOFFS keyword */
|
||||||
TOK_RANGE, /* RANGE keyword */
|
TOK_RANGE, /* RANGE keyword */
|
||||||
TOK_RO, /* RO keyword */
|
TOK_RO, /* RO keyword */
|
||||||
TOK_RW, /* RW keyword */
|
TOK_RW, /* RW keyword */
|
||||||
|
@ -156,6 +162,8 @@ struct SegInfo {
|
||||||
unsigned Id; /* Id of segment */
|
unsigned Id; /* Id of segment */
|
||||||
cc65_addr Start; /* Start address of segment */
|
cc65_addr Start; /* Start address of segment */
|
||||||
cc65_addr Size; /* Size of segment */
|
cc65_addr Size; /* Size of segment */
|
||||||
|
char* OutputName; /* Name of output file */
|
||||||
|
unsigned long OutputOffs; /* Offset in output file */
|
||||||
char SegName[1]; /* Name of segment */
|
char SegName[1]; /* Name of segment */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -405,6 +413,26 @@ static void SB_AppendChar (StrBuf* B, int C)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char* SB_StrDup (const StrBuf* B)
|
||||||
|
/* Return the contents of B as a dynamically allocated string. The string
|
||||||
|
* will always be NUL terminated.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Allocate memory */
|
||||||
|
char* S = xmalloc (B->Len + 1);
|
||||||
|
|
||||||
|
/* Copy the string */
|
||||||
|
memcpy (S, B->Buf, B->Len);
|
||||||
|
|
||||||
|
/* Terminate it */
|
||||||
|
S[B->Len] = '\0';
|
||||||
|
|
||||||
|
/* And return the result */
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Collections */
|
/* Collections */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -614,7 +642,8 @@ void CollSort (Collection* C, int (*Compare) (const void*, const void*))
|
||||||
|
|
||||||
|
|
||||||
static SegInfo* NewSegInfo (const StrBuf* SegName, unsigned Id,
|
static SegInfo* NewSegInfo (const StrBuf* SegName, unsigned Id,
|
||||||
cc65_addr Start, cc65_addr Size)
|
cc65_addr Start, cc65_addr Size,
|
||||||
|
const StrBuf* OutputName, unsigned long OutputOffs)
|
||||||
/* Create a new SegInfo struct and return it */
|
/* Create a new SegInfo struct and return it */
|
||||||
{
|
{
|
||||||
/* Allocate memory */
|
/* Allocate memory */
|
||||||
|
@ -624,6 +653,15 @@ static SegInfo* NewSegInfo (const StrBuf* SegName, unsigned Id,
|
||||||
S->Id = Id;
|
S->Id = Id;
|
||||||
S->Start = Start;
|
S->Start = Start;
|
||||||
S->Size = Size;
|
S->Size = Size;
|
||||||
|
if (SB_GetLen (OutputName) > 0) {
|
||||||
|
/* Output file given */
|
||||||
|
S->OutputName = SB_StrDup (OutputName);
|
||||||
|
S->OutputOffs = OutputOffs;
|
||||||
|
} else {
|
||||||
|
/* No output file given */
|
||||||
|
S->OutputName = 0;
|
||||||
|
S->OutputOffs = 0;
|
||||||
|
}
|
||||||
memcpy (S->SegName, SB_GetConstBuf (SegName), SB_GetLen (SegName) + 1);
|
memcpy (S->SegName, SB_GetConstBuf (SegName), SB_GetLen (SegName) + 1);
|
||||||
|
|
||||||
/* Return it */
|
/* Return it */
|
||||||
|
@ -853,6 +891,28 @@ static void FreeDbgInfo (DbgInfo* Info)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void CopyLineInfo (cc65_linedata* D, const LineInfo* L)
|
||||||
|
/* Copy data from a LineInfo struct to the cc65_linedata struct returned to
|
||||||
|
* the caller.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
D->source_name = L->File.Info->FileName;
|
||||||
|
D->source_size = L->File.Info->Size;
|
||||||
|
D->source_mtime = L->File.Info->MTime;
|
||||||
|
D->source_line = L->Line;
|
||||||
|
D->line_start = L->Start;
|
||||||
|
D->line_end = L->End;
|
||||||
|
if (L->Seg.Info->OutputName) {
|
||||||
|
D->output_name = L->Seg.Info->OutputName;
|
||||||
|
D->output_offs = L->Seg.Info->OutputOffs + L->Start - L->Seg.Info->Start;
|
||||||
|
} else {
|
||||||
|
D->output_name = 0;
|
||||||
|
D->output_offs = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseError (InputData* D, cc65_error_severity Type, const char* Msg, ...)
|
static void ParseError (InputData* D, cc65_error_severity Type, const char* Msg, ...)
|
||||||
/* Call the user supplied parse error function */
|
/* Call the user supplied parse error function */
|
||||||
{
|
{
|
||||||
|
@ -910,14 +970,6 @@ static void UnexpectedToken (InputData* D)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void MissingAttribute (InputData* D, const char* AttrName)
|
|
||||||
/* Print an error about a missing attribute */
|
|
||||||
{
|
|
||||||
ParseError (D, CC65_ERROR, "Attribute \"%s\" is mising", AttrName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void UnknownKeyword (InputData* D)
|
static void UnknownKeyword (InputData* D)
|
||||||
/* Print a warning about an unknown keyword in the file. Try to do smart
|
/* 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
|
* recovery, so if later versions of the debug information add additional
|
||||||
|
@ -988,7 +1040,7 @@ static void NextToken (InputData* D)
|
||||||
/* Read the next token from the input stream */
|
/* Read the next token from the input stream */
|
||||||
{
|
{
|
||||||
static const struct KeywordEntry {
|
static const struct KeywordEntry {
|
||||||
const char Keyword[10];
|
const char Keyword[16];
|
||||||
Token Tok;
|
Token Tok;
|
||||||
} KeywordTable[] = {
|
} KeywordTable[] = {
|
||||||
{ "absolute", TOK_ABSOLUTE },
|
{ "absolute", TOK_ABSOLUTE },
|
||||||
|
@ -1003,6 +1055,8 @@ static void NextToken (InputData* D)
|
||||||
{ "minor", TOK_MINOR },
|
{ "minor", TOK_MINOR },
|
||||||
{ "mtime", TOK_MTIME },
|
{ "mtime", TOK_MTIME },
|
||||||
{ "name", TOK_NAME },
|
{ "name", TOK_NAME },
|
||||||
|
{ "outputname", TOK_OUTPUTNAME },
|
||||||
|
{ "outputoffs", TOK_OUTPUTOFFS },
|
||||||
{ "range", TOK_RANGE },
|
{ "range", TOK_RANGE },
|
||||||
{ "ro", TOK_RO },
|
{ "ro", TOK_RO },
|
||||||
{ "rw", TOK_RW },
|
{ "rw", TOK_RW },
|
||||||
|
@ -1197,6 +1251,20 @@ static int ConsumeMinus (InputData* D)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void ConsumeEOL (InputData* D)
|
||||||
|
/* Consume an end-of-line token, if we aren't at end-of-file */
|
||||||
|
{
|
||||||
|
if (D->Tok != TOK_EOF) {
|
||||||
|
if (D->Tok != TOK_EOL) {
|
||||||
|
ParseError (D, CC65_ERROR, "Extra tokens in line");
|
||||||
|
SkipLine (D);
|
||||||
|
}
|
||||||
|
NextToken (D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseFile (InputData* D)
|
static void ParseFile (InputData* D)
|
||||||
/* Parse a FILE line */
|
/* Parse a FILE line */
|
||||||
{
|
{
|
||||||
|
@ -1304,7 +1372,7 @@ static void ParseFile (InputData* D)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for required information */
|
/* Check for required information */
|
||||||
if (InfoBits != ibRequired) {
|
if ((InfoBits & ibRequired) != ibRequired) {
|
||||||
ParseError (D, CC65_ERROR, "Required attributes missing");
|
ParseError (D, CC65_ERROR, "Required attributes missing");
|
||||||
goto ErrorExit;
|
goto ErrorExit;
|
||||||
}
|
}
|
||||||
|
@ -1436,7 +1504,7 @@ static void ParseLine (InputData* D)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for required information */
|
/* Check for required information */
|
||||||
if (InfoBits != ibRequired) {
|
if ((InfoBits & ibRequired) != ibRequired) {
|
||||||
ParseError (D, CC65_ERROR, "Required attributes missing");
|
ParseError (D, CC65_ERROR, "Required attributes missing");
|
||||||
goto ErrorExit;
|
goto ErrorExit;
|
||||||
}
|
}
|
||||||
|
@ -1459,6 +1527,8 @@ static void ParseSegment (InputData* D)
|
||||||
cc65_addr Start;
|
cc65_addr Start;
|
||||||
cc65_addr Size;
|
cc65_addr Size;
|
||||||
StrBuf SegName = STRBUF_INITIALIZER;
|
StrBuf SegName = STRBUF_INITIALIZER;
|
||||||
|
StrBuf OutputName = STRBUF_INITIALIZER;
|
||||||
|
unsigned long OutputOffs;
|
||||||
SegInfo* S;
|
SegInfo* S;
|
||||||
enum {
|
enum {
|
||||||
ibNone = 0x00,
|
ibNone = 0x00,
|
||||||
|
@ -1468,6 +1538,8 @@ static void ParseSegment (InputData* D)
|
||||||
ibSize = 0x08,
|
ibSize = 0x08,
|
||||||
ibAddrSize = 0x10,
|
ibAddrSize = 0x10,
|
||||||
ibType = 0x20,
|
ibType = 0x20,
|
||||||
|
ibOutputName= 0x40,
|
||||||
|
ibOutputOffs= 0x80,
|
||||||
ibRequired = ibId | ibSegName | ibStart | ibSize | ibAddrSize | ibType,
|
ibRequired = ibId | ibSegName | ibStart | ibSize | ibAddrSize | ibType,
|
||||||
} InfoBits = ibNone;
|
} InfoBits = ibNone;
|
||||||
|
|
||||||
|
@ -1486,9 +1558,10 @@ static void ParseSegment (InputData* D)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Something we know? */
|
/* Something we know? */
|
||||||
if (D->Tok != TOK_ID && D->Tok != TOK_NAME &&
|
if (D->Tok != TOK_ADDRSIZE && D->Tok != TOK_ID &&
|
||||||
D->Tok != TOK_START && D->Tok != TOK_SIZE &&
|
D->Tok != TOK_NAME && D->Tok != TOK_OUTPUTNAME &&
|
||||||
D->Tok != TOK_ADDRSIZE && D->Tok != TOK_TYPE) {
|
D->Tok != TOK_OUTPUTOFFS && D->Tok != TOK_SIZE &&
|
||||||
|
D->Tok != TOK_START && D->Tok != TOK_TYPE) {
|
||||||
/* Done */
|
/* Done */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1522,6 +1595,25 @@ static void ParseSegment (InputData* D)
|
||||||
NextToken (D);
|
NextToken (D);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_OUTPUTNAME:
|
||||||
|
if (!StrConstFollows (D)) {
|
||||||
|
goto ErrorExit;
|
||||||
|
}
|
||||||
|
SB_Copy (&OutputName, &D->SVal);
|
||||||
|
SB_Terminate (&OutputName);
|
||||||
|
InfoBits |= ibOutputName;
|
||||||
|
NextToken (D);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_OUTPUTOFFS:
|
||||||
|
if (!IntConstFollows (D)) {
|
||||||
|
goto ErrorExit;
|
||||||
|
}
|
||||||
|
OutputOffs = D->IVal;
|
||||||
|
NextToken (D);
|
||||||
|
InfoBits |= ibOutputOffs;
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_START:
|
case TOK_START:
|
||||||
if (!IntConstFollows (D)) {
|
if (!IntConstFollows (D)) {
|
||||||
goto ErrorExit;
|
goto ErrorExit;
|
||||||
|
@ -1572,18 +1664,19 @@ static void ParseSegment (InputData* D)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for required information */
|
/* Check for required information */
|
||||||
if (InfoBits != ibRequired) {
|
if ((InfoBits & ibRequired) != ibRequired) {
|
||||||
ParseError (D, CC65_ERROR, "Required attributes missing");
|
ParseError (D, CC65_ERROR, "Required attributes missing");
|
||||||
goto ErrorExit;
|
goto ErrorExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the segment info and remember it */
|
/* Create the segment info and remember it */
|
||||||
S = NewSegInfo (&SegName, Id, Start, Size);
|
S = NewSegInfo (&SegName, Id, Start, Size, &OutputName, OutputOffs);
|
||||||
CollAppend (&D->Info->SegInfoByName, S);
|
CollAppend (&D->Info->SegInfoByName, S);
|
||||||
|
|
||||||
ErrorExit:
|
ErrorExit:
|
||||||
/* Entry point in case of errors */
|
/* Entry point in case of errors */
|
||||||
SB_Done (&SegName);
|
SB_Done (&SegName);
|
||||||
|
SB_Done (&OutputName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1604,7 +1697,12 @@ static void ParseSym (InputData* D)
|
||||||
static void ParseVersion (InputData* D)
|
static void ParseVersion (InputData* D)
|
||||||
/* Parse a VERSION line */
|
/* Parse a VERSION line */
|
||||||
{
|
{
|
||||||
enum { None = 0x00, Major = 0x01, Minor = 0x02 } InfoBits = None;
|
enum {
|
||||||
|
ibNone = 0x00,
|
||||||
|
ibMajor = 0x01,
|
||||||
|
ibMinor = 0x02,
|
||||||
|
ibRequired = ibMajor | ibMinor,
|
||||||
|
} InfoBits = ibNone;
|
||||||
|
|
||||||
/* Skip the VERSION token */
|
/* Skip the VERSION token */
|
||||||
NextToken (D);
|
NextToken (D);
|
||||||
|
@ -1624,7 +1722,7 @@ static void ParseVersion (InputData* D)
|
||||||
}
|
}
|
||||||
D->MajorVersion = D->IVal;
|
D->MajorVersion = D->IVal;
|
||||||
NextToken (D);
|
NextToken (D);
|
||||||
InfoBits |= Major;
|
InfoBits |= ibMajor;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_MINOR:
|
case TOK_MINOR:
|
||||||
|
@ -1637,7 +1735,7 @@ static void ParseVersion (InputData* D)
|
||||||
}
|
}
|
||||||
D->MinorVersion = D->IVal;
|
D->MinorVersion = D->IVal;
|
||||||
NextToken (D);
|
NextToken (D);
|
||||||
InfoBits |= Minor;
|
InfoBits |= ibMinor;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_IDENT:
|
case TOK_IDENT:
|
||||||
|
@ -1665,12 +1763,8 @@ static void ParseVersion (InputData* D)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for required information */
|
/* Check for required information */
|
||||||
if ((InfoBits & Major) == None) {
|
if ((InfoBits & ibRequired) != ibRequired) {
|
||||||
MissingAttribute (D, "major");
|
ParseError (D, CC65_ERROR, "Required attributes missing");
|
||||||
goto ErrorExit;
|
|
||||||
}
|
|
||||||
if ((InfoBits & Minor) == None) {
|
|
||||||
MissingAttribute (D, "minor");
|
|
||||||
goto ErrorExit;
|
goto ErrorExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2110,6 +2204,24 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
||||||
/* Prime the pump */
|
/* Prime the pump */
|
||||||
NextToken (&D);
|
NextToken (&D);
|
||||||
|
|
||||||
|
/* The first line in the file must specify version information */
|
||||||
|
if (D.Tok != TOK_VERSION) {
|
||||||
|
ParseError (&D, CC65_ERROR,
|
||||||
|
"\"version\" keyword missing in first line - this is not "
|
||||||
|
"a valid debug info file");
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Parse the version directive and check the version */
|
||||||
|
ParseVersion (&D);
|
||||||
|
if (D.MajorVersion > VER_MAJOR) {
|
||||||
|
ParseError (&D, CC65_WARNING,
|
||||||
|
"The format of this debug info file is newer than what we "
|
||||||
|
"know. Will proceed but probably fail. Version found = %u, "
|
||||||
|
"version supported = %u",
|
||||||
|
D.MajorVersion, VER_MAJOR);
|
||||||
|
}
|
||||||
|
ConsumeEOL (&D);
|
||||||
|
|
||||||
/* Parse lines */
|
/* Parse lines */
|
||||||
while (D.Tok != TOK_EOF) {
|
while (D.Tok != TOK_EOF) {
|
||||||
|
|
||||||
|
@ -2131,10 +2243,6 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
||||||
ParseSym (&D);
|
ParseSym (&D);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_VERSION:
|
|
||||||
ParseVersion (&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.
|
||||||
|
@ -2152,12 +2260,7 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOL or EOF must follow */
|
/* EOL or EOF must follow */
|
||||||
if (D.Tok != TOK_EOF) {
|
ConsumeEOL (&D);
|
||||||
if (D.Tok != TOK_EOL) {
|
|
||||||
ParseError (&D, 1, "Extra tokens in line");
|
|
||||||
SkipLine (&D);
|
|
||||||
}
|
|
||||||
NextToken (&D);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2240,17 +2343,8 @@ cc65_lineinfo* cc65_lineinfo_byaddr (cc65_dbginfo Handle, unsigned long Addr)
|
||||||
(CollCount (&LineInfos) - 1) * sizeof (D->data[0]));
|
(CollCount (&LineInfos) - 1) * sizeof (D->data[0]));
|
||||||
D->count = CollCount (&LineInfos);
|
D->count = CollCount (&LineInfos);
|
||||||
for (I = 0; I < D->count; ++I) {
|
for (I = 0; I < D->count; ++I) {
|
||||||
|
|
||||||
/* Pointer to this info */
|
|
||||||
LineInfo* L = CollAt (&LineInfos, I);
|
|
||||||
|
|
||||||
/* Copy data */
|
/* Copy data */
|
||||||
D->data[I].name = L->File.Info->FileName;
|
CopyLineInfo (D->data + I, CollAt (&LineInfos, I));
|
||||||
D->data[I].size = L->File.Info->Size;
|
|
||||||
D->data[I].mtime = L->File.Info->MTime;
|
|
||||||
D->data[I].line = L->Line;
|
|
||||||
D->data[I].start = L->Start;
|
|
||||||
D->data[I].end = L->End;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2299,12 +2393,7 @@ cc65_lineinfo* cc65_lineinfo_byname (cc65_dbginfo Handle, const char* FileName,
|
||||||
D->count = 1;
|
D->count = 1;
|
||||||
|
|
||||||
/* Copy data */
|
/* Copy data */
|
||||||
D->data[0].name = L->File.Info->FileName;
|
CopyLineInfo (D->data, L);
|
||||||
D->data[0].size = L->File.Info->Size;
|
|
||||||
D->data[0].mtime = L->File.Info->MTime;
|
|
||||||
D->data[0].line = L->Line;
|
|
||||||
D->data[0].start = L->Start;
|
|
||||||
D->data[0].end = L->End;
|
|
||||||
|
|
||||||
/* Return the allocated struct */
|
/* Return the allocated struct */
|
||||||
return D;
|
return D;
|
||||||
|
@ -2324,12 +2413,12 @@ void cc65_free_lineinfo (cc65_dbginfo Handle, cc65_lineinfo* Info)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cc65_filelist* cc65_get_filelist (cc65_dbginfo Handle)
|
cc65_sourceinfo* cc65_get_sourcelist (cc65_dbginfo Handle)
|
||||||
/* Return a list of all files referenced in the debug information */
|
/* Return a list of all source files */
|
||||||
{
|
{
|
||||||
DbgInfo* Info;
|
DbgInfo* Info;
|
||||||
Collection* FileInfoByName;
|
Collection* FileInfoByName;
|
||||||
cc65_filelist* D;
|
cc65_sourceinfo* D;
|
||||||
unsigned I;
|
unsigned I;
|
||||||
|
|
||||||
/* Check the parameter */
|
/* Check the parameter */
|
||||||
|
@ -2353,9 +2442,9 @@ cc65_filelist* cc65_get_filelist (cc65_dbginfo Handle)
|
||||||
FileInfo* F = CollAt (FileInfoByName, I);
|
FileInfo* F = CollAt (FileInfoByName, I);
|
||||||
|
|
||||||
/* Copy the data */
|
/* Copy the data */
|
||||||
D->data[I].name = F->FileName;
|
D->data[I].source_name = F->FileName;
|
||||||
D->data[I].size = F->Size;
|
D->data[I].source_size = F->Size;
|
||||||
D->data[I].mtime = F->MTime;
|
D->data[I].source_mtime = F->MTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the result */
|
/* Return the result */
|
||||||
|
@ -2364,24 +2453,24 @@ cc65_filelist* cc65_get_filelist (cc65_dbginfo Handle)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cc65_free_filelist (cc65_dbginfo Handle, cc65_filelist* List)
|
void cc65_free_sourceinfo (cc65_dbginfo Handle, cc65_sourceinfo* Info)
|
||||||
/* Free a file list returned by cc65_get_filelist() */
|
/* Free a source info record */
|
||||||
{
|
{
|
||||||
/* Just for completeness, check the handle */
|
/* Just for completeness, check the handle */
|
||||||
assert (Handle != 0);
|
assert (Handle != 0);
|
||||||
|
|
||||||
/* Just free the memory */
|
/* Free the memory */
|
||||||
xfree (List);
|
xfree (Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cc65_segmentlist* cc65_get_segmentlist (cc65_dbginfo Handle)
|
cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle)
|
||||||
/* Return a list of all segments referenced in the debug information */
|
/* Return a list of all segments referenced in the debug information */
|
||||||
{
|
{
|
||||||
DbgInfo* Info;
|
DbgInfo* Info;
|
||||||
Collection* SegInfoByName;
|
Collection* SegInfoByName;
|
||||||
cc65_segmentlist* D;
|
cc65_segmentinfo* D;
|
||||||
unsigned I;
|
unsigned I;
|
||||||
|
|
||||||
/* Check the parameter */
|
/* Check the parameter */
|
||||||
|
@ -2405,9 +2494,11 @@ cc65_segmentlist* cc65_get_segmentlist (cc65_dbginfo Handle)
|
||||||
SegInfo* S = CollAt (SegInfoByName, I);
|
SegInfo* S = CollAt (SegInfoByName, I);
|
||||||
|
|
||||||
/* Copy the data */
|
/* Copy the data */
|
||||||
D->data[I].name = S->SegName;
|
D->data[I].segment_name = S->SegName;
|
||||||
D->data[I].start = S->Start;
|
D->data[I].segment_start = S->Start;
|
||||||
D->data[I].end = S->Start + S->Size - 1;
|
D->data[I].segment_size = S->Size;
|
||||||
|
D->data[I].output_name = S->OutputName;
|
||||||
|
D->data[I].output_offs = S->OutputOffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the result */
|
/* Return the result */
|
||||||
|
@ -2416,14 +2507,14 @@ cc65_segmentlist* cc65_get_segmentlist (cc65_dbginfo Handle)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cc65_free_segmentlist (cc65_dbginfo Handle, cc65_segmentlist* List)
|
void cc65_free_segmentinfo (cc65_dbginfo Handle, cc65_segmentinfo* Info)
|
||||||
/* Free a file list returned by cc65_get_filelist() */
|
/* Free a segment info record */
|
||||||
{
|
{
|
||||||
/* Just for completeness, check the handle */
|
/* Just for completeness, check the handle */
|
||||||
assert (Handle != 0);
|
assert (Handle != 0);
|
||||||
|
|
||||||
/* Just free the memory */
|
/* Free the memory */
|
||||||
xfree (List);
|
xfree (Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,42 +74,66 @@ struct cc65_parseerror {
|
||||||
/* Function that is called in case of parse errors */
|
/* Function that is called in case of parse errors */
|
||||||
typedef void (*cc65_errorfunc) (const struct cc65_parseerror*);
|
typedef void (*cc65_errorfunc) (const struct cc65_parseerror*);
|
||||||
|
|
||||||
/* Line information */
|
/* Line information.
|
||||||
|
* Notes:
|
||||||
|
* - line_end is inclusive
|
||||||
|
* - output_name may be NULL if the data wasn't written to the output file
|
||||||
|
* (example: bss segment)
|
||||||
|
* - output_offs is invalid if there is no output_name, and may not be of
|
||||||
|
* much use in case of a relocatable output file
|
||||||
|
*/
|
||||||
|
typedef struct cc65_linedata cc65_linedata;
|
||||||
|
struct cc65_linedata {
|
||||||
|
const char* source_name; /* Name of the file */
|
||||||
|
unsigned long source_size; /* Size of file */
|
||||||
|
unsigned long source_mtime; /* Modification time */
|
||||||
|
cc65_line source_line; /* Line number */
|
||||||
|
cc65_addr line_start; /* Start address for this line */
|
||||||
|
cc65_addr line_end; /* End address for this line */
|
||||||
|
const char* output_name; /* Output file */
|
||||||
|
unsigned long output_offs; /* Offset in output file */
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct cc65_lineinfo cc65_lineinfo;
|
typedef struct cc65_lineinfo cc65_lineinfo;
|
||||||
struct cc65_lineinfo {
|
struct cc65_lineinfo {
|
||||||
unsigned count; /* Number of data sets that follow */
|
unsigned count; /* Number of data sets that follow */
|
||||||
struct {
|
cc65_linedata data[1]; /* Data sets, number is dynamic */
|
||||||
const char* name; /* Name of the file */
|
|
||||||
unsigned long size; /* Size of file */
|
|
||||||
unsigned long mtime; /* Modification time */
|
|
||||||
cc65_line line; /* Line number */
|
|
||||||
cc65_addr start; /* Start address for this line */
|
|
||||||
cc65_addr end; /* End address for this line */
|
|
||||||
} data[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A list of files with some information */
|
/* Source file information */
|
||||||
typedef struct cc65_filelist cc65_filelist;
|
typedef struct cc65_sourcedata cc65_sourcedata;
|
||||||
struct cc65_filelist {
|
struct cc65_sourcedata {
|
||||||
unsigned count; /* Number of data sets that follow */
|
const char* source_name; /* Name of the file */
|
||||||
struct {
|
unsigned long source_size; /* Size of file */
|
||||||
const char* name; /* Name of the file */
|
unsigned long source_mtime; /* Modification time */
|
||||||
unsigned long size; /* Size of file */
|
|
||||||
unsigned long mtime; /* Modification time */
|
|
||||||
} data[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct cc65_sourceinfo cc65_sourceinfo;
|
||||||
|
struct cc65_sourceinfo {
|
||||||
/* A list of segments with some information */
|
|
||||||
typedef struct cc65_segmentlist cc65_segmentlist;
|
|
||||||
struct cc65_segmentlist {
|
|
||||||
unsigned count; /* Number of data sets that follow */
|
unsigned count; /* Number of data sets that follow */
|
||||||
struct {
|
cc65_sourcedata data[1]; /* Data sets, number is dynamic */
|
||||||
const char* name; /* Name of the file */
|
};
|
||||||
cc65_addr start; /* Start address of segment */
|
|
||||||
cc65_addr end; /* End address of segment */
|
/* Segment information.
|
||||||
} data[1];
|
* Notes:
|
||||||
|
* - output_name may be NULL if the data wasn't written to the output file
|
||||||
|
* (example: bss segment)
|
||||||
|
* - output_offs is invalid if there is no output_name, and may not be of
|
||||||
|
* much use in case of a relocatable output file
|
||||||
|
*/
|
||||||
|
typedef struct cc65_segmentdata cc65_segmentdata;
|
||||||
|
struct cc65_segmentdata {
|
||||||
|
const char* segment_name; /* Name of the segment */
|
||||||
|
cc65_addr segment_start; /* Start address of segment */
|
||||||
|
cc65_addr segment_size; /* Size of segment */
|
||||||
|
const char* output_name; /* Output file this seg was written to */
|
||||||
|
unsigned long output_offs; /* Offset of this seg in output file */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cc65_segmentinfo cc65_segmentinfo;
|
||||||
|
struct cc65_segmentinfo {
|
||||||
|
unsigned count; /* Number of data sets that follow */
|
||||||
|
cc65_segmentdata data[1]; /* Data sets, number is dynamic */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,17 +169,17 @@ cc65_lineinfo* cc65_lineinfo_byname (cc65_dbginfo handle, const char* filename,
|
||||||
void cc65_free_lineinfo (cc65_dbginfo handle, cc65_lineinfo* info);
|
void cc65_free_lineinfo (cc65_dbginfo handle, cc65_lineinfo* info);
|
||||||
/* Free line info returned by one of the other functions */
|
/* Free line info returned by one of the other functions */
|
||||||
|
|
||||||
cc65_filelist* cc65_get_filelist (cc65_dbginfo handle);
|
cc65_sourceinfo* cc65_get_sourcelist (cc65_dbginfo handle);
|
||||||
/* Return a list of all files referenced in the debug information */
|
/* Return a list of all source files */
|
||||||
|
|
||||||
void cc65_free_filelist (cc65_dbginfo handle, cc65_filelist* list);
|
void cc65_free_sourceinfo (cc65_dbginfo handle, cc65_sourceinfo* info);
|
||||||
/* free a file list returned by cc65_get_filelist() */
|
/* Free a source info record */
|
||||||
|
|
||||||
cc65_segmentlist* cc65_get_segmentlist (cc65_dbginfo handle);
|
cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo handle);
|
||||||
/* Return a list of all segments referenced in the debug information */
|
/* Return a list of all segments referenced in the debug information */
|
||||||
|
|
||||||
void cc65_free_segmentlist (cc65_dbginfo handle, cc65_segmentlist* list);
|
void cc65_free_segmentinfo (cc65_dbginfo handle, cc65_segmentinfo* info);
|
||||||
/* Free a file list returned by cc65_get_filelist() */
|
/* Free a segment info record */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,8 @@ int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
const char* Input;
|
const char* Input;
|
||||||
cc65_dbginfo Info;
|
cc65_dbginfo Info;
|
||||||
cc65_filelist* Files;
|
cc65_sourceinfo* Sources;
|
||||||
cc65_segmentlist* Segments;
|
cc65_segmentinfo* Segments;
|
||||||
cc65_lineinfo* L;
|
cc65_lineinfo* L;
|
||||||
unsigned I;
|
unsigned I;
|
||||||
unsigned long Addr;
|
unsigned long Addr;
|
||||||
|
@ -87,23 +87,29 @@ int main (int argc, char** argv)
|
||||||
printf ("Input file \"%s\" successfully read\n", Input);
|
printf ("Input file \"%s\" successfully read\n", Input);
|
||||||
|
|
||||||
/* Output a list of files */
|
/* Output a list of files */
|
||||||
printf ("Files used in compilation:\n");
|
printf ("List of source files:\n");
|
||||||
Files = cc65_get_filelist (Info);
|
Sources = cc65_get_sourcelist (Info);
|
||||||
for (I = 0; I < Files->count; ++I) {
|
for (I = 0; I < Sources->count; ++I) {
|
||||||
printf (" %s\n", Files->data[I].name);
|
printf (" %s\n", Sources->data[I].source_name);
|
||||||
}
|
}
|
||||||
cc65_free_filelist (Info, Files);
|
cc65_free_sourceinfo (Info, Sources);
|
||||||
|
|
||||||
/* Output a list of segments */
|
/* Output a list of segments */
|
||||||
printf ("Segments processed when linking:\n");
|
printf ("Segments processed when linking:\n");
|
||||||
Segments = cc65_get_segmentlist (Info);
|
Segments = cc65_get_segmentlist (Info);
|
||||||
for (I = 0; I < Segments->count; ++I) {
|
for (I = 0; I < Segments->count; ++I) {
|
||||||
printf (" %-20s $%06lX-$%06lX\n",
|
printf (" %-20s $%06lX $%04lX",
|
||||||
Segments->data[I].name,
|
Segments->data[I].segment_name,
|
||||||
(unsigned long) Segments->data[I].start,
|
(unsigned long) Segments->data[I].segment_start,
|
||||||
(unsigned long) Segments->data[I].end);
|
(unsigned long) Segments->data[I].segment_size);
|
||||||
|
if (Segments->data[I].output_name) {
|
||||||
|
printf (" %-20s $%06lX",
|
||||||
|
Segments->data[I].output_name,
|
||||||
|
Segments->data[I].output_offs);
|
||||||
}
|
}
|
||||||
cc65_free_segmentlist (Info, Segments);
|
putchar ('\n');
|
||||||
|
}
|
||||||
|
cc65_free_segmentinfo (Info, Segments);
|
||||||
|
|
||||||
/* Check one line */
|
/* Check one line */
|
||||||
printf ("Requesting line info for crt0.s(59):\n");
|
printf ("Requesting line info for crt0.s(59):\n");
|
||||||
|
@ -111,12 +117,12 @@ int main (int argc, char** argv)
|
||||||
if (L == 0) {
|
if (L == 0) {
|
||||||
printf (" Not found\n");
|
printf (" Not found\n");
|
||||||
} else {
|
} else {
|
||||||
printf (" Code range is $%04X-$%04X\n", L->data[0].start, L->data[0].end);
|
printf (" Code range is $%04X-$%04X\n",
|
||||||
|
L->data[0].line_start,
|
||||||
|
L->data[0].line_end);
|
||||||
cc65_free_lineinfo (Info, L);
|
cc65_free_lineinfo (Info, L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Output debug information for all addresses in the complete 6502 address
|
/* Output debug information for all addresses in the complete 6502 address
|
||||||
* space. This is also sort of a benchmark for the search algorithms.
|
* space. This is also sort of a benchmark for the search algorithms.
|
||||||
*/
|
*/
|
||||||
|
@ -130,8 +136,15 @@ int main (int argc, char** argv)
|
||||||
if (I > 0) {
|
if (I > 0) {
|
||||||
printf (", ");
|
printf (", ");
|
||||||
}
|
}
|
||||||
printf ("%s(%lu)", L->data[I].name,
|
printf ("%s(%lu)",
|
||||||
(unsigned long) L->data[I].line);
|
L->data[I].source_name,
|
||||||
|
(unsigned long) L->data[I].source_line);
|
||||||
|
if (L->data[I].output_name) {
|
||||||
|
printf (" %s($%06lX)",
|
||||||
|
L->data[I].output_name,
|
||||||
|
L->data[I].output_offs);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
cc65_free_lineinfo (Info, L);
|
cc65_free_lineinfo (Info, L);
|
||||||
|
|
Loading…
Add table
Reference in a new issue