mirror of
https://github.com/cc65/cc65.git
synced 2025-01-11 11:30:13 +00:00
Redid the whole line info stuff, because the old data structures weren't able
to manage the new information. git-svn-id: svn://svn.cc65.org/cc65/trunk@4961 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
6cbbe66c87
commit
bcfa2c31cf
@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2010, Ullrich von Bassewitz */
|
||||
/* (C) 2010-2011, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
@ -52,9 +52,12 @@
|
||||
|
||||
|
||||
|
||||
/* Use this for debugging - beware, lots of output */
|
||||
#define DEBUG 0
|
||||
|
||||
/* Version numbers of the debug format we understand */
|
||||
#define VER_MAJOR 1U
|
||||
#define VER_MINOR 0U
|
||||
#define VER_MINOR 1U
|
||||
|
||||
/* Dynamic strings */
|
||||
typedef struct StrBuf StrBuf;
|
||||
@ -78,6 +81,20 @@ struct Collection {
|
||||
/* Initializer for static collections */
|
||||
#define COLLECTION_INITIALIZER { 0, 0, 0 }
|
||||
|
||||
/* Line info management */
|
||||
typedef struct LineInfoListEntry LineInfoListEntry;
|
||||
struct LineInfoListEntry {
|
||||
cc65_addr Addr; /* Unique address */
|
||||
unsigned Count; /* Number of LineInfos for this address */
|
||||
void* Data; /* Either LineInfo* or LineInfo** */
|
||||
};
|
||||
|
||||
typedef struct LineInfoList LineInfoList;
|
||||
struct LineInfoList {
|
||||
unsigned Count; /* Number of entries */
|
||||
LineInfoListEntry* List; /* Dynamic array with entries */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Data structure containing information from the debug info file. A pointer
|
||||
@ -85,13 +102,14 @@ struct Collection {
|
||||
*/
|
||||
typedef struct DbgInfo DbgInfo;
|
||||
struct DbgInfo {
|
||||
Collection SegInfoByName; /* Segment infos sorted by name */
|
||||
Collection SegInfoById; /* Segment infos sorted by id */
|
||||
Collection FileInfoByName; /* File infos sorted by name */
|
||||
Collection FileInfoById; /* File infos sorted by id */
|
||||
Collection LineInfoByAddr; /* Line infos sorted by address */
|
||||
Collection SymInfoByName; /* Symbol infos sorted by name */
|
||||
Collection SymInfoByVal; /* Symbol infos sorted by value */
|
||||
Collection SegInfoByName; /* Segment infos sorted by name */
|
||||
Collection SegInfoById; /* Segment infos sorted by id */
|
||||
Collection FileInfoByName; /* File infos sorted by name */
|
||||
Collection FileInfoById; /* File infos sorted by id */
|
||||
Collection LineInfos; /* List of all line infos */
|
||||
LineInfoList LineInfoByAddr; /* Line infos sorted by unique address */
|
||||
Collection SymInfoByName; /* Symbol infos sorted by name */
|
||||
Collection SymInfoByVal; /* Symbol infos sorted by value */
|
||||
};
|
||||
|
||||
/* Input tokens */
|
||||
@ -111,6 +129,7 @@ typedef enum {
|
||||
|
||||
TOK_ABSOLUTE, /* ABSOLUTE keyword */
|
||||
TOK_ADDRSIZE, /* ADDRSIZE keyword */
|
||||
TOK_COUNT, /* COUNT keyword */
|
||||
TOK_EQUATE, /* EQUATE keyword */
|
||||
TOK_FILE, /* FILE keyword */
|
||||
TOK_ID, /* ID keyword */
|
||||
@ -175,9 +194,6 @@ struct FileInfo {
|
||||
unsigned Id; /* Id of file */
|
||||
unsigned long Size; /* Size of file */
|
||||
unsigned long MTime; /* Modification time */
|
||||
cc65_addr Start; /* Start address of line infos */
|
||||
cc65_addr End; /* End address of line infos */
|
||||
Collection LineInfoByAddr; /* Line infos sorted by address */
|
||||
Collection LineInfoByLine; /* Line infos sorted by line */
|
||||
char FileName[1]; /* Name of file with full path */
|
||||
};
|
||||
@ -196,6 +212,8 @@ struct LineInfo {
|
||||
unsigned Id; /* Id of segment */
|
||||
SegInfo* Info; /* Pointer to segment info */
|
||||
} Seg;
|
||||
cc65_line_type Type; /* Type of line */
|
||||
unsigned Count; /* Nesting counter for macros */
|
||||
};
|
||||
|
||||
/* Internally used symbol info struct */
|
||||
@ -470,6 +488,13 @@ static void DoneCollection (Collection* C)
|
||||
{
|
||||
/* Free the pointer array */
|
||||
xfree (C->Items);
|
||||
|
||||
/* Clear the fields, so the collection may be reused (or DoneCollection
|
||||
* called) again
|
||||
*/
|
||||
C->Count = 0;
|
||||
C->Size = 0;
|
||||
C->Items = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -562,18 +587,6 @@ static void* CollFirst (Collection* C)
|
||||
|
||||
|
||||
|
||||
static void* CollLast (Collection* C)
|
||||
/* Return the last item in a collection */
|
||||
{
|
||||
/* We must have at least one entry */
|
||||
assert (C->Count > 0);
|
||||
|
||||
/* Return the element */
|
||||
return C->Items[C->Count-1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CollDelete (Collection* C, unsigned Index)
|
||||
/* Remove the item with the given index from the collection. This will not
|
||||
* free the item itself, just the pointer. All items with higher indices
|
||||
@ -645,6 +658,99 @@ void CollSort (Collection* C, int (*Compare) (const void*, const void*))
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Debugging stuff */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#if DEBUG
|
||||
|
||||
/* Output */
|
||||
#define DBGPRINT(format, ...) printf ((format), __VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
static void DumpFileInfo (Collection* FileInfos)
|
||||
/* Dump a list of file infos */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* File info */
|
||||
for (I = 0; I < CollCount (FileInfos); ++I) {
|
||||
const FileInfo* FI = CollAt (FileInfos, I);
|
||||
printf ("File info %u:\n"
|
||||
" Name: %s\n"
|
||||
" Size: %lu\n"
|
||||
" MTime: %lu\n",
|
||||
FI->Id,
|
||||
FI->FileName,
|
||||
(unsigned long) FI->Size,
|
||||
(unsigned long) FI->MTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DumpOneLineInfo (unsigned Num, LineInfo* LI)
|
||||
/* Dump one line info entry */
|
||||
{
|
||||
printf (" Index: %u\n"
|
||||
" File: %s\n"
|
||||
" Line: %lu\n"
|
||||
" Range: 0x%06lX-0x%06lX\n"
|
||||
" Type: %u\n"
|
||||
" Count: %u\n",
|
||||
Num,
|
||||
LI->File.Info->FileName,
|
||||
(unsigned long) LI->Line,
|
||||
(unsigned long) LI->Start,
|
||||
(unsigned long) LI->End,
|
||||
LI->Type,
|
||||
LI->Count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DumpLineInfo (LineInfoList* L)
|
||||
/* Dump a list of line infos */
|
||||
{
|
||||
unsigned I, J;
|
||||
|
||||
/* Line info */
|
||||
for (I = 0; I < L->Count; ++I) {
|
||||
const LineInfoListEntry* E = &L->List[I];
|
||||
printf ("Addr: %lu\n", (unsigned long) E->Addr);
|
||||
if (E->Count == 1) {
|
||||
DumpOneLineInfo (0, E->Data);
|
||||
} else {
|
||||
for (J = 0; J < E->Count; ++J) {
|
||||
DumpOneLineInfo (J, ((LineInfo**) E->Data)[J]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DumpData (InputData* D)
|
||||
/* Dump internal data to stdout for debugging */
|
||||
{
|
||||
/* Dump data */
|
||||
DumpFileInfo (&D->Info->FileInfoById);
|
||||
DumpLineInfo (&D->Info->LineInfoByAddr);
|
||||
}
|
||||
#else
|
||||
|
||||
/* No output */
|
||||
#define DBGPRINT(format, ...)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Segment info */
|
||||
/*****************************************************************************/
|
||||
@ -720,7 +826,8 @@ static int CompareSegInfoById (const void* L, const void* R)
|
||||
|
||||
|
||||
static LineInfo* NewLineInfo (unsigned File, unsigned Seg, cc65_line Line,
|
||||
cc65_addr Start, cc65_addr End)
|
||||
cc65_addr Start, cc65_addr End,
|
||||
cc65_line_type Type, unsigned Count)
|
||||
/* Create a new LineInfo struct and return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
@ -732,6 +839,8 @@ static LineInfo* NewLineInfo (unsigned File, unsigned Seg, cc65_line Line,
|
||||
L->Line = Line;
|
||||
L->File.Id = File;
|
||||
L->Seg.Id = Seg;
|
||||
L->Type = Type;
|
||||
L->Count = Count;
|
||||
|
||||
/* Return it */
|
||||
return L;
|
||||
@ -748,13 +857,23 @@ static void FreeLineInfo (LineInfo* L)
|
||||
|
||||
|
||||
static int CompareLineInfoByAddr (const void* L, const void* R)
|
||||
/* Helper function to sort line infos in a collection by address */
|
||||
/* Helper function to sort line infos in a collection by address. Line infos
|
||||
* with smaller start address are considered smaller. If start addresses are
|
||||
* equal, line infos with smaller end address are considered smaller. This
|
||||
* means, that when CompareLineInfoByAddr is used for sorting, a range with
|
||||
* identical start addresses will have smaller ranges first, followed by
|
||||
* larger ranges.
|
||||
*/
|
||||
{
|
||||
/* Sort by start of range */
|
||||
if (((const LineInfo*) L)->Start > ((const LineInfo*) R)->Start) {
|
||||
return 1;
|
||||
} else if (((const LineInfo*) L)->Start < ((const LineInfo*) R)->Start) {
|
||||
return -1;
|
||||
} else if (((const LineInfo*) L)->End > ((const LineInfo*) R)->End) {
|
||||
return 1;
|
||||
} else if (((const LineInfo*) L)->End < ((const LineInfo*) R)->End) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -763,14 +882,16 @@ static int CompareLineInfoByAddr (const void* L, const void* R)
|
||||
|
||||
|
||||
static int CompareLineInfoByLine (const void* L, const void* R)
|
||||
/* Helper function to sort line infos in a collection by line */
|
||||
/* Helper function to sort line infos in a collection by line. If the line
|
||||
* is identical, sort by the address of the range.
|
||||
*/
|
||||
{
|
||||
if (((const LineInfo*) L)->Line > ((const LineInfo*) R)->Line) {
|
||||
return 1;
|
||||
} else if (((const LineInfo*) L)->Line < ((const LineInfo*) R)->Line) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
return CompareLineInfoByAddr (L, R);
|
||||
}
|
||||
}
|
||||
|
||||
@ -793,9 +914,6 @@ static FileInfo* NewFileInfo (const StrBuf* FileName, unsigned Id,
|
||||
F->Id = Id;
|
||||
F->Size = Size;
|
||||
F->MTime = MTime;
|
||||
F->Start = ~(cc65_addr)0;
|
||||
F->End = 0;
|
||||
InitCollection (&F->LineInfoByAddr);
|
||||
InitCollection (&F->LineInfoByLine);
|
||||
memcpy (F->FileName, SB_GetConstBuf (FileName), SB_GetLen (FileName) + 1);
|
||||
|
||||
@ -808,13 +926,7 @@ static FileInfo* NewFileInfo (const StrBuf* FileName, unsigned Id,
|
||||
static void FreeFileInfo (FileInfo* F)
|
||||
/* Free a FileInfo struct */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Walk through the collection with line infos and delete them */
|
||||
for (I = 0; I < CollCount (&F->LineInfoByAddr); ++I) {
|
||||
FreeLineInfo (CollAt (&F->LineInfoByAddr, I));
|
||||
}
|
||||
DoneCollection (&F->LineInfoByAddr);
|
||||
/* Delete the collection with the line infos */
|
||||
DoneCollection (&F->LineInfoByLine);
|
||||
|
||||
/* Free the file info structure itself */
|
||||
@ -905,6 +1017,197 @@ static int CompareSymInfoByVal (const void* L, const void* R)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* LineInfoList */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void InitLineInfoList (LineInfoList* L)
|
||||
/* Initialize a line info list */
|
||||
{
|
||||
L->Count = 0;
|
||||
L->List = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CreateLineInfoList (LineInfoList* L, Collection* LineInfos)
|
||||
/* Create a LineInfoList from a Collection with line infos. The collection
|
||||
* must be sorted by ascending start addresses.
|
||||
*/
|
||||
{
|
||||
unsigned I, J;
|
||||
LineInfo* LI;
|
||||
LineInfoListEntry* List;
|
||||
unsigned StartIndex;
|
||||
cc65_addr Start;
|
||||
cc65_addr Addr;
|
||||
cc65_addr End;
|
||||
|
||||
/* Initialize and check if there's something to do */
|
||||
L->Count = 0;
|
||||
L->List = 0;
|
||||
if (CollCount (LineInfos) == 0) {
|
||||
/* No entries */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Step 1: Determine the number of unique address entries needed */
|
||||
LI = CollFirst (LineInfos);
|
||||
L->Count += (LI->End - LI->Start) + 1;
|
||||
End = LI->End;
|
||||
for (I = 1; I < CollCount (LineInfos); ++I) {
|
||||
|
||||
/* Get next entry */
|
||||
LI = CollAt (LineInfos, I);
|
||||
|
||||
/* Check for additional unique addresses in this line info */
|
||||
if (LI->Start > End) {
|
||||
L->Count += (LI->End - LI->Start) + 1;
|
||||
End = LI->End;
|
||||
} else if (LI->End > End) {
|
||||
L->Count += (LI->End - End);
|
||||
End = LI->End;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Step 2: Allocate memory and initialize it */
|
||||
L->List = List = xmalloc (L->Count * sizeof (*List));
|
||||
for (I = 0; I < L->Count; ++I) {
|
||||
List[I].Count = 0;
|
||||
List[I].Data = 0;
|
||||
}
|
||||
|
||||
/* Step 3: Determine the number of entries per unique address */
|
||||
List = L->List;
|
||||
LI = CollFirst (LineInfos);
|
||||
StartIndex = 0;
|
||||
Start = LI->Start;
|
||||
End = LI->End;
|
||||
for (J = StartIndex, Addr = LI->Start; Addr <= LI->End; ++J, ++Addr) {
|
||||
List[J].Addr = Addr;
|
||||
++List[J].Count;
|
||||
}
|
||||
for (I = 1; I < CollCount (LineInfos); ++I) {
|
||||
|
||||
/* Get next entry */
|
||||
LI = CollAt (LineInfos, I);
|
||||
|
||||
/* Determine the start index of the next range. Line infos are sorted
|
||||
* by ascending start address, so the start address of the next entry
|
||||
* is always larger than the previous one - we don't need to check
|
||||
* that.
|
||||
*/
|
||||
if (LI->Start <= End) {
|
||||
/* Range starts within out already known linear range */
|
||||
StartIndex += (unsigned) (LI->Start - Start);
|
||||
Start = LI->Start;
|
||||
if (LI->End > End) {
|
||||
End = LI->End;
|
||||
}
|
||||
} else {
|
||||
/* Range starts after the already known */
|
||||
StartIndex += (unsigned) (End - Start) + 1;
|
||||
Start = LI->Start;
|
||||
End = LI->End;
|
||||
}
|
||||
for (J = StartIndex, Addr = LI->Start; Addr <= LI->End; ++J, ++Addr) {
|
||||
List[J].Addr = Addr;
|
||||
++List[J].Count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 4: Allocate memory for the indirect tables */
|
||||
for (I = 0, List = L->List; I < L->Count; ++I, ++List) {
|
||||
|
||||
/* For a count of 1, we store the pointer to the lineinfo for this
|
||||
* address in the Data pointer directly. For counts > 1, we allocate
|
||||
* an array of pointers and reset the counter, so we can use it as
|
||||
* an index later. This is dangerous programming since it disables
|
||||
* all possible checks!
|
||||
*/
|
||||
if (List->Count > 1) {
|
||||
List->Data = xmalloc (List->Count * sizeof (LineInfo*));
|
||||
List->Count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 5: Enter the data into the table */
|
||||
List = L->List;
|
||||
LI = CollFirst (LineInfos);
|
||||
StartIndex = 0;
|
||||
Start = LI->Start;
|
||||
End = LI->End;
|
||||
for (J = StartIndex, Addr = LI->Start; Addr <= LI->End; ++J, ++Addr) {
|
||||
assert (List[J].Addr = Addr);
|
||||
if (List[J].Count == 1 && List[J].Data == 0) {
|
||||
List[J].Data = LI;
|
||||
} else {
|
||||
((LineInfo**) List[J].Data)[List[J].Count++] = LI;
|
||||
}
|
||||
}
|
||||
for (I = 1; I < CollCount (LineInfos); ++I) {
|
||||
|
||||
/* Get next entry */
|
||||
LI = CollAt (LineInfos, I);
|
||||
|
||||
/* Determine the start index of the next range. Line infos are sorted
|
||||
* by ascending start address, so the start address of the next entry
|
||||
* is always larger than the previous one - we don't need to check
|
||||
* that.
|
||||
*/
|
||||
if (LI->Start <= End) {
|
||||
/* Range starts within out already known linear range */
|
||||
StartIndex += (unsigned) (LI->Start - Start);
|
||||
Start = LI->Start;
|
||||
if (LI->End > End) {
|
||||
End = LI->End;
|
||||
}
|
||||
} else {
|
||||
/* Range starts after the already known */
|
||||
StartIndex += (unsigned) (End - Start) + 1;
|
||||
Start = LI->Start;
|
||||
End = LI->End;
|
||||
}
|
||||
for (J = StartIndex, Addr = LI->Start; Addr <= LI->End; ++J, ++Addr) {
|
||||
assert (List[J].Addr = Addr);
|
||||
if (List[J].Count == 1 && List[J].Data == 0) {
|
||||
List[J].Data = LI;
|
||||
} else {
|
||||
((LineInfo**) List[J].Data)[List[J].Count++] = LI;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DoneLineInfoList (LineInfoList* L)
|
||||
/* Delete the contents of a line info list */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Delete the line info and the indirect data */
|
||||
for (I = 0; I < L->Count; ++I) {
|
||||
|
||||
/* Get a pointer to the entry */
|
||||
LineInfoListEntry* E = &L->List[I];
|
||||
|
||||
/* Check for indirect memory */
|
||||
if (E->Count > 1) {
|
||||
/* LineInfo addressed indirectly */
|
||||
xfree (E->Data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the list */
|
||||
xfree (L->List);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Debug info */
|
||||
/*****************************************************************************/
|
||||
@ -922,7 +1225,8 @@ static DbgInfo* NewDbgInfo (void)
|
||||
InitCollection (&Info->SegInfoById);
|
||||
InitCollection (&Info->FileInfoByName);
|
||||
InitCollection (&Info->FileInfoById);
|
||||
InitCollection (&Info->LineInfoByAddr);
|
||||
InitCollection (&Info->LineInfos);
|
||||
InitLineInfoList (&Info->LineInfoByAddr);
|
||||
InitCollection (&Info->SymInfoByName);
|
||||
InitCollection (&Info->SymInfoByVal);
|
||||
|
||||
@ -952,7 +1256,11 @@ static void FreeDbgInfo (DbgInfo* Info)
|
||||
DoneCollection (&Info->FileInfoById);
|
||||
|
||||
/* Free line info */
|
||||
DoneCollection (&Info->LineInfoByAddr);
|
||||
for (I = 0; I < CollCount (&Info->LineInfos); ++I) {
|
||||
FreeLineInfo (CollAt (&Info->LineInfos, I));
|
||||
}
|
||||
DoneCollection (&Info->LineInfos);
|
||||
DoneLineInfoList (&Info->LineInfoByAddr);
|
||||
|
||||
/* Free symbol info */
|
||||
for (I = 0; I < CollCount (&Info->SymInfoByName); ++I) {
|
||||
@ -991,6 +1299,8 @@ static void CopyLineInfo (cc65_linedata* D, const LineInfo* L)
|
||||
D->output_name = 0;
|
||||
D->output_offs = 0;
|
||||
}
|
||||
D->line_type = L->Type;
|
||||
D->count = L->Count;
|
||||
}
|
||||
|
||||
|
||||
@ -1139,6 +1449,7 @@ static void NextToken (InputData* D)
|
||||
} KeywordTable[] = {
|
||||
{ "absolute", TOK_ABSOLUTE },
|
||||
{ "addrsize", TOK_ADDRSIZE },
|
||||
{ "count", TOK_COUNT },
|
||||
{ "equate", TOK_EQUATE },
|
||||
{ "file", TOK_FILE },
|
||||
{ "id", TOK_ID },
|
||||
@ -1486,11 +1797,13 @@ ErrorExit:
|
||||
static void ParseLine (InputData* D)
|
||||
/* Parse a LINE line */
|
||||
{
|
||||
unsigned File;
|
||||
unsigned Segment;
|
||||
cc65_line Line;
|
||||
cc65_addr Start;
|
||||
cc65_addr End;
|
||||
unsigned File;
|
||||
unsigned Segment;
|
||||
cc65_line Line;
|
||||
cc65_addr Start;
|
||||
cc65_addr End;
|
||||
cc65_line_type Type = CC65_LINE_ASM;
|
||||
unsigned Count = 0;
|
||||
LineInfo* L;
|
||||
enum {
|
||||
ibNone = 0x00,
|
||||
@ -1498,6 +1811,8 @@ static void ParseLine (InputData* D)
|
||||
ibSegment = 0x02,
|
||||
ibLine = 0x04,
|
||||
ibRange = 0x08,
|
||||
ibType = 0x10,
|
||||
ibCount = 0x20,
|
||||
ibRequired = ibFile | ibSegment | ibLine | ibRange,
|
||||
} InfoBits = ibNone;
|
||||
|
||||
@ -1516,8 +1831,9 @@ static void ParseLine (InputData* D)
|
||||
}
|
||||
|
||||
/* Something we know? */
|
||||
if (D->Tok != TOK_FILE && D->Tok != TOK_LINE &&
|
||||
D->Tok != TOK_RANGE && D->Tok != TOK_SEGMENT) {
|
||||
if (D->Tok != TOK_COUNT && D->Tok != TOK_FILE &&
|
||||
D->Tok != TOK_LINE && D->Tok != TOK_RANGE &&
|
||||
D->Tok != TOK_SEGMENT && D->Tok != TOK_TYPE) {
|
||||
/* Done */
|
||||
break;
|
||||
}
|
||||
@ -1576,6 +1892,24 @@ static void ParseLine (InputData* D)
|
||||
NextToken (D);
|
||||
break;
|
||||
|
||||
case TOK_TYPE:
|
||||
if (!IntConstFollows (D)) {
|
||||
goto ErrorExit;
|
||||
}
|
||||
Type = (cc65_line_type) D->IVal;
|
||||
InfoBits |= ibType;
|
||||
NextToken (D);
|
||||
break;
|
||||
|
||||
case TOK_COUNT:
|
||||
if (!IntConstFollows (D)) {
|
||||
goto ErrorExit;
|
||||
}
|
||||
Count = D->IVal;
|
||||
InfoBits |= ibCount;
|
||||
NextToken (D);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* NOTREACHED */
|
||||
UnexpectedToken (D);
|
||||
@ -1604,8 +1938,8 @@ static void ParseLine (InputData* D)
|
||||
}
|
||||
|
||||
/* Create the line info and remember it */
|
||||
L = NewLineInfo (File, Segment, Line, Start, End);
|
||||
CollAppend (&D->Info->LineInfoByAddr, L);
|
||||
L = NewLineInfo (File, Segment, Line, Start, End, Type, Count);
|
||||
CollAppend (&D->Info->LineInfos, L);
|
||||
|
||||
ErrorExit:
|
||||
/* Entry point in case of errors */
|
||||
@ -2182,7 +2516,7 @@ static void ProcessLineInfo (InputData* D)
|
||||
/* Postprocess line infos */
|
||||
{
|
||||
/* Get pointers to the collections */
|
||||
Collection* LineInfos = &D->Info->LineInfoByAddr;
|
||||
Collection* LineInfos = &D->Info->LineInfos;
|
||||
Collection* FileInfos = &D->Info->FileInfoByName;
|
||||
|
||||
/* Walk over the line infos and replace the id numbers of file and segment
|
||||
@ -2257,7 +2591,6 @@ static void ProcessLineInfo (InputData* D)
|
||||
L->Seg.Info = S;
|
||||
|
||||
/* Add this line info to the file where it is defined */
|
||||
CollAppend (&F->LineInfoByAddr, L);
|
||||
CollAppend (&F->LineInfoByLine, L);
|
||||
|
||||
/* Next one */
|
||||
@ -2273,61 +2606,41 @@ static void ProcessLineInfo (InputData* D)
|
||||
FileInfo* F = CollAt (FileInfos, I);
|
||||
|
||||
/* Sort the line infos for this file */
|
||||
CollSort (&F->LineInfoByAddr, CompareLineInfoByAddr);
|
||||
CollSort (&F->LineInfoByLine, CompareLineInfoByLine);
|
||||
|
||||
/* If there are line info entries, place the first and last address
|
||||
* of into the FileInfo struct itself, so we can rule out a FileInfo
|
||||
* quickly when mapping an address to a line info.
|
||||
*/
|
||||
if (CollCount (&F->LineInfoByAddr) > 0) {
|
||||
F->Start = ((const LineInfo*) CollFirst (&F->LineInfoByAddr))->Start;
|
||||
F->End = ((const LineInfo*) CollLast (&F->LineInfoByAddr))->End;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the collection with all line infos by address */
|
||||
CollSort (LineInfos, CompareLineInfoByAddr);
|
||||
|
||||
/* Create the line info list from the line info collection */
|
||||
CreateLineInfoList (&D->Info->LineInfoByAddr, LineInfos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static LineInfo* FindLineInfoByAddr (FileInfo* F, cc65_addr Addr)
|
||||
/* Find the LineInfo for a given address */
|
||||
static LineInfoListEntry* FindLineInfoByAddr (const LineInfoList* L, cc65_addr Addr)
|
||||
/* Find the index of a LineInfo for a given address. Returns 0 if no such
|
||||
* lineinfo was found.
|
||||
*/
|
||||
{
|
||||
Collection* LineInfoByAddr;
|
||||
int Hi;
|
||||
int Lo;
|
||||
|
||||
|
||||
/* Each file info contains the first and last address for which line
|
||||
* info is available, so we can rule out non matching ones quickly.
|
||||
*/
|
||||
if (Addr < F->Start || Addr > F->End) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a pointer to the line info collection for this file */
|
||||
LineInfoByAddr = &F->LineInfoByAddr;
|
||||
|
||||
/* Do a binary search */
|
||||
Lo = 0;
|
||||
Hi = (int) CollCount (LineInfoByAddr) - 1;
|
||||
int Lo = 0;
|
||||
int Hi = (int) L->Count - 1;
|
||||
while (Lo <= Hi) {
|
||||
|
||||
/* Mid of range */
|
||||
int Cur = (Lo + Hi) / 2;
|
||||
|
||||
/* Get item */
|
||||
LineInfo* CurItem = CollAt (LineInfoByAddr, Cur);
|
||||
LineInfoListEntry* CurItem = &L->List[Cur];
|
||||
|
||||
/* Found? */
|
||||
if (Addr < CurItem->Start) {
|
||||
if (CurItem->Addr > Addr) {
|
||||
Hi = Cur - 1;
|
||||
} else if (Addr > CurItem->End) {
|
||||
} else if (CurItem->Addr < Addr) {
|
||||
Lo = Cur + 1;
|
||||
} else {
|
||||
/* Found! */
|
||||
/* Found */
|
||||
return CurItem;
|
||||
}
|
||||
}
|
||||
@ -2596,10 +2909,10 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
||||
if (D.Errors > 0) {
|
||||
/* Free allocated stuff */
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&D.Info->LineInfoByAddr); ++I) {
|
||||
FreeLineInfo (CollAt (&D.Info->LineInfoByAddr, I));
|
||||
for (I = 0; I < CollCount (&D.Info->LineInfos); ++I) {
|
||||
FreeLineInfo (CollAt (&D.Info->LineInfos, I));
|
||||
}
|
||||
DoneCollection (&D.Info->LineInfoByAddr);
|
||||
DoneCollection (&D.Info->LineInfos);
|
||||
FreeDbgInfo (D.Info);
|
||||
return 0;
|
||||
}
|
||||
@ -2612,6 +2925,11 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
|
||||
ProcessLineInfo (&D);
|
||||
ProcessSymInfo (&D);
|
||||
|
||||
#if DEBUG
|
||||
/* Debug output */
|
||||
DumpData (&D);
|
||||
#endif
|
||||
|
||||
/* Return the debug info struct that was created */
|
||||
return D.Info;
|
||||
}
|
||||
@ -2633,42 +2951,33 @@ cc65_lineinfo* cc65_lineinfo_byaddr (cc65_dbginfo Handle, unsigned long Addr)
|
||||
* if no line information was found.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
Collection* FileInfoByName;
|
||||
LineInfoListEntry* E;
|
||||
cc65_lineinfo* D = 0;
|
||||
|
||||
/* We will place a list of line infos in a collection */
|
||||
Collection LineInfos = COLLECTION_INITIALIZER;
|
||||
|
||||
/* Check the parameter */
|
||||
assert (Handle != 0);
|
||||
|
||||
/* Walk over all files and search for matching line infos */
|
||||
FileInfoByName = &((DbgInfo*) Handle)->FileInfoByName;
|
||||
for (I = 0; I < CollCount (FileInfoByName); ++I) {
|
||||
/* Check if the file contains line info for this address */
|
||||
LineInfo* L = FindLineInfoByAddr (CollAt (FileInfoByName, I), Addr);
|
||||
if (L != 0) {
|
||||
CollAppend (&LineInfos, L);
|
||||
}
|
||||
}
|
||||
/* Search in the line infos for address */
|
||||
E = FindLineInfoByAddr (&((DbgInfo*) Handle)->LineInfoByAddr, Addr);
|
||||
|
||||
/* Do we have line infos? */
|
||||
if (CollCount (&LineInfos) > 0) {
|
||||
if (E != 0) {
|
||||
|
||||
unsigned I;
|
||||
|
||||
/* Prepare the struct we will return to the caller */
|
||||
D = xmalloc (sizeof (*D) +
|
||||
(CollCount (&LineInfos) - 1) * sizeof (D->data[0]));
|
||||
D->count = CollCount (&LineInfos);
|
||||
for (I = 0; I < D->count; ++I) {
|
||||
/* Copy data */
|
||||
CopyLineInfo (D->data + I, CollAt (&LineInfos, I));
|
||||
D = xmalloc (sizeof (*D) + (E->Count - 1) * sizeof (D->data[0]));
|
||||
D->count = E->Count;
|
||||
if (E->Count == 1) {
|
||||
CopyLineInfo (D->data, E->Data);
|
||||
} else {
|
||||
for (I = 0; I < D->count; ++I) {
|
||||
/* Copy data */
|
||||
CopyLineInfo (D->data + I, ((LineInfo**) E->Data)[I]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the line info collection */
|
||||
DoneCollection (&LineInfos);
|
||||
|
||||
/* Return the struct we've created */
|
||||
return D;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2010, Ullrich von Bassewitz */
|
||||
/* (C) 2010-2011, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
@ -81,6 +81,13 @@ struct cc65_parseerror {
|
||||
/* Function that is called in case of parse errors */
|
||||
typedef void (*cc65_errorfunc) (const struct cc65_parseerror*);
|
||||
|
||||
/* Type of line */
|
||||
typedef enum {
|
||||
CC65_LINE_ASM, /* Assembler source */
|
||||
CC65_LINE_EXT, /* Externally supplied (= C) */
|
||||
CC65_LINE_MACRO, /* Macro expansion */
|
||||
} cc65_line_type;
|
||||
|
||||
/* Line information.
|
||||
* Notes:
|
||||
* - line_end is inclusive
|
||||
@ -99,6 +106,8 @@ struct cc65_linedata {
|
||||
cc65_addr line_end; /* End address for this line */
|
||||
const char* output_name; /* Output file */
|
||||
unsigned long output_offs; /* Offset in output file */
|
||||
cc65_line_type line_type; /* Type of line */
|
||||
unsigned count; /* Nesting counter for macros */
|
||||
};
|
||||
|
||||
typedef struct cc65_lineinfo cc65_lineinfo;
|
||||
|
@ -91,6 +91,20 @@ static void PrintLineData (const cc65_linedata* D)
|
||||
if (D->output_name) {
|
||||
printf (" [%s($%06lX)]", D->output_name, D->output_offs);
|
||||
}
|
||||
switch (D->line_type) {
|
||||
case CC65_LINE_ASM:
|
||||
printf (": Assembler source");
|
||||
break;
|
||||
case CC65_LINE_EXT:
|
||||
printf (": Externally supplied");
|
||||
break;
|
||||
case CC65_LINE_MACRO:
|
||||
printf (": Macro expansion (%u)", D->count);
|
||||
break;
|
||||
default:
|
||||
printf (": Unknown type %u (%u)", D->line_type, D->count);
|
||||
break;
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
@ -229,7 +243,7 @@ int main (int argc, char** argv)
|
||||
}
|
||||
|
||||
/* Print symbols for the next $100 bytes starting from main (or 0x800) */
|
||||
printf ("Requesting labels for $%04lX-$%04lX:\n",
|
||||
printf ("Requesting labels for $%04lX-$%04lX:\n",
|
||||
(unsigned long) Addr, (unsigned long) Addr + 0xFF);
|
||||
Symbols = cc65_symbol_inrange (Info, Addr, Addr + 0xFF);
|
||||
if (Symbols == 0) {
|
||||
@ -240,7 +254,7 @@ int main (int argc, char** argv)
|
||||
}
|
||||
|
||||
/* Free the debug info */
|
||||
cc65_free_dbginfo (Info);
|
||||
cc65_free_dbginfo (Info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user