1
0
mirror of https://github.com/cc65/cc65.git synced 2024-10-03 12:55:56 +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:
uz 2011-02-03 17:08:20 +00:00
parent 6cbbe66c87
commit bcfa2c31cf
3 changed files with 446 additions and 114 deletions

View File

@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2010, Ullrich von Bassewitz */ /* (C) 2010-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* 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 */ /* Version numbers of the debug format we understand */
#define VER_MAJOR 1U #define VER_MAJOR 1U
#define VER_MINOR 0U #define VER_MINOR 1U
/* Dynamic strings */ /* Dynamic strings */
typedef struct StrBuf StrBuf; typedef struct StrBuf StrBuf;
@ -78,6 +81,20 @@ struct Collection {
/* Initializer for static collections */ /* Initializer for static collections */
#define COLLECTION_INITIALIZER { 0, 0, 0 } #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 /* Data structure containing information from the debug info file. A pointer
@ -85,13 +102,14 @@ struct Collection {
*/ */
typedef struct DbgInfo DbgInfo; typedef struct DbgInfo DbgInfo;
struct DbgInfo { struct DbgInfo {
Collection SegInfoByName; /* Segment infos sorted by name */ Collection SegInfoByName; /* Segment infos sorted by name */
Collection SegInfoById; /* Segment infos sorted by id */ Collection SegInfoById; /* Segment infos sorted by id */
Collection FileInfoByName; /* File infos sorted by name */ Collection FileInfoByName; /* File infos sorted by name */
Collection FileInfoById; /* File infos sorted by id */ Collection FileInfoById; /* File infos sorted by id */
Collection LineInfoByAddr; /* Line infos sorted by address */ Collection LineInfos; /* List of all line infos */
Collection SymInfoByName; /* Symbol infos sorted by name */ LineInfoList LineInfoByAddr; /* Line infos sorted by unique address */
Collection SymInfoByVal; /* Symbol infos sorted by value */ Collection SymInfoByName; /* Symbol infos sorted by name */
Collection SymInfoByVal; /* Symbol infos sorted by value */
}; };
/* Input tokens */ /* Input tokens */
@ -111,6 +129,7 @@ typedef enum {
TOK_ABSOLUTE, /* ABSOLUTE keyword */ TOK_ABSOLUTE, /* ABSOLUTE keyword */
TOK_ADDRSIZE, /* ADDRSIZE keyword */ TOK_ADDRSIZE, /* ADDRSIZE keyword */
TOK_COUNT, /* COUNT keyword */
TOK_EQUATE, /* EQUATE keyword */ TOK_EQUATE, /* EQUATE keyword */
TOK_FILE, /* FILE keyword */ TOK_FILE, /* FILE keyword */
TOK_ID, /* ID keyword */ TOK_ID, /* ID keyword */
@ -175,9 +194,6 @@ struct FileInfo {
unsigned Id; /* Id of file */ unsigned Id; /* Id of file */
unsigned long Size; /* Size of file */ unsigned long Size; /* Size of file */
unsigned long MTime; /* Modification time */ 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 */ Collection LineInfoByLine; /* Line infos sorted by line */
char FileName[1]; /* Name of file with full path */ char FileName[1]; /* Name of file with full path */
}; };
@ -196,6 +212,8 @@ struct LineInfo {
unsigned Id; /* Id of segment */ unsigned Id; /* Id of segment */
SegInfo* Info; /* Pointer to segment info */ SegInfo* Info; /* Pointer to segment info */
} Seg; } Seg;
cc65_line_type Type; /* Type of line */
unsigned Count; /* Nesting counter for macros */
}; };
/* Internally used symbol info struct */ /* Internally used symbol info struct */
@ -470,6 +488,13 @@ static void DoneCollection (Collection* C)
{ {
/* Free the pointer array */ /* Free the pointer array */
xfree (C->Items); 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) static void CollDelete (Collection* C, unsigned Index)
/* Remove the item with the given index from the collection. This will not /* 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 * 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 */ /* 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, 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 */ /* Create a new LineInfo struct and return it */
{ {
/* Allocate memory */ /* Allocate memory */
@ -732,6 +839,8 @@ static LineInfo* NewLineInfo (unsigned File, unsigned Seg, cc65_line Line,
L->Line = Line; L->Line = Line;
L->File.Id = File; L->File.Id = File;
L->Seg.Id = Seg; L->Seg.Id = Seg;
L->Type = Type;
L->Count = Count;
/* Return it */ /* Return it */
return L; return L;
@ -748,13 +857,23 @@ static void FreeLineInfo (LineInfo* L)
static int CompareLineInfoByAddr (const void* L, const void* R) 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 */ /* Sort by start of range */
if (((const LineInfo*) L)->Start > ((const LineInfo*) R)->Start) { if (((const LineInfo*) L)->Start > ((const LineInfo*) R)->Start) {
return 1; return 1;
} else if (((const LineInfo*) L)->Start < ((const LineInfo*) R)->Start) { } else if (((const LineInfo*) L)->Start < ((const LineInfo*) R)->Start) {
return -1; 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 { } else {
return 0; return 0;
} }
@ -763,14 +882,16 @@ static int CompareLineInfoByAddr (const void* L, const void* R)
static int CompareLineInfoByLine (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) { if (((const LineInfo*) L)->Line > ((const LineInfo*) R)->Line) {
return 1; return 1;
} else if (((const LineInfo*) L)->Line < ((const LineInfo*) R)->Line) { } else if (((const LineInfo*) L)->Line < ((const LineInfo*) R)->Line) {
return -1; return -1;
} else { } else {
return 0; return CompareLineInfoByAddr (L, R);
} }
} }
@ -793,9 +914,6 @@ static FileInfo* NewFileInfo (const StrBuf* FileName, unsigned Id,
F->Id = Id; F->Id = Id;
F->Size = Size; F->Size = Size;
F->MTime = MTime; F->MTime = MTime;
F->Start = ~(cc65_addr)0;
F->End = 0;
InitCollection (&F->LineInfoByAddr);
InitCollection (&F->LineInfoByLine); InitCollection (&F->LineInfoByLine);
memcpy (F->FileName, SB_GetConstBuf (FileName), SB_GetLen (FileName) + 1); 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) static void FreeFileInfo (FileInfo* F)
/* Free a FileInfo struct */ /* Free a FileInfo struct */
{ {
unsigned I; /* Delete the collection with the line infos */
/* 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);
DoneCollection (&F->LineInfoByLine); DoneCollection (&F->LineInfoByLine);
/* Free the file info structure itself */ /* 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 */ /* Debug info */
/*****************************************************************************/ /*****************************************************************************/
@ -922,7 +1225,8 @@ static DbgInfo* NewDbgInfo (void)
InitCollection (&Info->SegInfoById); InitCollection (&Info->SegInfoById);
InitCollection (&Info->FileInfoByName); InitCollection (&Info->FileInfoByName);
InitCollection (&Info->FileInfoById); InitCollection (&Info->FileInfoById);
InitCollection (&Info->LineInfoByAddr); InitCollection (&Info->LineInfos);
InitLineInfoList (&Info->LineInfoByAddr);
InitCollection (&Info->SymInfoByName); InitCollection (&Info->SymInfoByName);
InitCollection (&Info->SymInfoByVal); InitCollection (&Info->SymInfoByVal);
@ -952,7 +1256,11 @@ static void FreeDbgInfo (DbgInfo* Info)
DoneCollection (&Info->FileInfoById); DoneCollection (&Info->FileInfoById);
/* Free line info */ /* 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 */ /* Free symbol info */
for (I = 0; I < CollCount (&Info->SymInfoByName); ++I) { 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_name = 0;
D->output_offs = 0; D->output_offs = 0;
} }
D->line_type = L->Type;
D->count = L->Count;
} }
@ -1139,6 +1449,7 @@ static void NextToken (InputData* D)
} KeywordTable[] = { } KeywordTable[] = {
{ "absolute", TOK_ABSOLUTE }, { "absolute", TOK_ABSOLUTE },
{ "addrsize", TOK_ADDRSIZE }, { "addrsize", TOK_ADDRSIZE },
{ "count", TOK_COUNT },
{ "equate", TOK_EQUATE }, { "equate", TOK_EQUATE },
{ "file", TOK_FILE }, { "file", TOK_FILE },
{ "id", TOK_ID }, { "id", TOK_ID },
@ -1486,11 +1797,13 @@ ErrorExit:
static void ParseLine (InputData* D) static void ParseLine (InputData* D)
/* Parse a LINE line */ /* Parse a LINE line */
{ {
unsigned File; unsigned File;
unsigned Segment; unsigned Segment;
cc65_line Line; cc65_line Line;
cc65_addr Start; cc65_addr Start;
cc65_addr End; cc65_addr End;
cc65_line_type Type = CC65_LINE_ASM;
unsigned Count = 0;
LineInfo* L; LineInfo* L;
enum { enum {
ibNone = 0x00, ibNone = 0x00,
@ -1498,6 +1811,8 @@ static void ParseLine (InputData* D)
ibSegment = 0x02, ibSegment = 0x02,
ibLine = 0x04, ibLine = 0x04,
ibRange = 0x08, ibRange = 0x08,
ibType = 0x10,
ibCount = 0x20,
ibRequired = ibFile | ibSegment | ibLine | ibRange, ibRequired = ibFile | ibSegment | ibLine | ibRange,
} InfoBits = ibNone; } InfoBits = ibNone;
@ -1516,8 +1831,9 @@ static void ParseLine (InputData* D)
} }
/* Something we know? */ /* Something we know? */
if (D->Tok != TOK_FILE && D->Tok != TOK_LINE && if (D->Tok != TOK_COUNT && D->Tok != TOK_FILE &&
D->Tok != TOK_RANGE && D->Tok != TOK_SEGMENT) { D->Tok != TOK_LINE && D->Tok != TOK_RANGE &&
D->Tok != TOK_SEGMENT && D->Tok != TOK_TYPE) {
/* Done */ /* Done */
break; break;
} }
@ -1576,6 +1892,24 @@ static void ParseLine (InputData* D)
NextToken (D); NextToken (D);
break; 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: default:
/* NOTREACHED */ /* NOTREACHED */
UnexpectedToken (D); UnexpectedToken (D);
@ -1604,8 +1938,8 @@ static void ParseLine (InputData* D)
} }
/* Create the line info and remember it */ /* Create the line info and remember it */
L = NewLineInfo (File, Segment, Line, Start, End); L = NewLineInfo (File, Segment, Line, Start, End, Type, Count);
CollAppend (&D->Info->LineInfoByAddr, L); CollAppend (&D->Info->LineInfos, L);
ErrorExit: ErrorExit:
/* Entry point in case of errors */ /* Entry point in case of errors */
@ -2182,7 +2516,7 @@ static void ProcessLineInfo (InputData* D)
/* Postprocess line infos */ /* Postprocess line infos */
{ {
/* Get pointers to the collections */ /* Get pointers to the collections */
Collection* LineInfos = &D->Info->LineInfoByAddr; Collection* LineInfos = &D->Info->LineInfos;
Collection* FileInfos = &D->Info->FileInfoByName; Collection* FileInfos = &D->Info->FileInfoByName;
/* Walk over the line infos and replace the id numbers of file and segment /* 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; L->Seg.Info = S;
/* Add this line info to the file where it is defined */ /* Add this line info to the file where it is defined */
CollAppend (&F->LineInfoByAddr, L);
CollAppend (&F->LineInfoByLine, L); CollAppend (&F->LineInfoByLine, L);
/* Next one */ /* Next one */
@ -2273,61 +2606,41 @@ static void ProcessLineInfo (InputData* D)
FileInfo* F = CollAt (FileInfos, I); FileInfo* F = CollAt (FileInfos, I);
/* Sort the line infos for this file */ /* Sort the line infos for this file */
CollSort (&F->LineInfoByAddr, CompareLineInfoByAddr);
CollSort (&F->LineInfoByLine, CompareLineInfoByLine); 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 */ /* Sort the collection with all line infos by address */
CollSort (LineInfos, CompareLineInfoByAddr); 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) static LineInfoListEntry* FindLineInfoByAddr (const LineInfoList* L, cc65_addr Addr)
/* Find the LineInfo for a given address */ /* 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 */ /* Do a binary search */
Lo = 0; int Lo = 0;
Hi = (int) CollCount (LineInfoByAddr) - 1; int Hi = (int) L->Count - 1;
while (Lo <= Hi) { while (Lo <= Hi) {
/* Mid of range */ /* Mid of range */
int Cur = (Lo + Hi) / 2; int Cur = (Lo + Hi) / 2;
/* Get item */ /* Get item */
LineInfo* CurItem = CollAt (LineInfoByAddr, Cur); LineInfoListEntry* CurItem = &L->List[Cur];
/* Found? */ /* Found? */
if (Addr < CurItem->Start) { if (CurItem->Addr > Addr) {
Hi = Cur - 1; Hi = Cur - 1;
} else if (Addr > CurItem->End) { } else if (CurItem->Addr < Addr) {
Lo = Cur + 1; Lo = Cur + 1;
} else { } else {
/* Found! */ /* Found */
return CurItem; return CurItem;
} }
} }
@ -2596,10 +2909,10 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
if (D.Errors > 0) { if (D.Errors > 0) {
/* Free allocated stuff */ /* Free allocated stuff */
unsigned I; unsigned I;
for (I = 0; I < CollCount (&D.Info->LineInfoByAddr); ++I) { for (I = 0; I < CollCount (&D.Info->LineInfos); ++I) {
FreeLineInfo (CollAt (&D.Info->LineInfoByAddr, I)); FreeLineInfo (CollAt (&D.Info->LineInfos, I));
} }
DoneCollection (&D.Info->LineInfoByAddr); DoneCollection (&D.Info->LineInfos);
FreeDbgInfo (D.Info); FreeDbgInfo (D.Info);
return 0; return 0;
} }
@ -2612,6 +2925,11 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
ProcessLineInfo (&D); ProcessLineInfo (&D);
ProcessSymInfo (&D); ProcessSymInfo (&D);
#if DEBUG
/* Debug output */
DumpData (&D);
#endif
/* Return the debug info struct that was created */ /* Return the debug info struct that was created */
return D.Info; return D.Info;
} }
@ -2633,42 +2951,33 @@ cc65_lineinfo* cc65_lineinfo_byaddr (cc65_dbginfo Handle, unsigned long Addr)
* if no line information was found. * if no line information was found.
*/ */
{ {
unsigned I; LineInfoListEntry* E;
Collection* FileInfoByName;
cc65_lineinfo* D = 0; cc65_lineinfo* D = 0;
/* We will place a list of line infos in a collection */
Collection LineInfos = COLLECTION_INITIALIZER;
/* Check the parameter */ /* Check the parameter */
assert (Handle != 0); assert (Handle != 0);
/* Walk over all files and search for matching line infos */ /* Search in the line infos for address */
FileInfoByName = &((DbgInfo*) Handle)->FileInfoByName; E = FindLineInfoByAddr (&((DbgInfo*) Handle)->LineInfoByAddr, Addr);
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);
}
}
/* Do we have line infos? */ /* Do we have line infos? */
if (CollCount (&LineInfos) > 0) { if (E != 0) {
unsigned I;
/* Prepare the struct we will return to the caller */ /* Prepare the struct we will return to the caller */
D = xmalloc (sizeof (*D) + D = xmalloc (sizeof (*D) + (E->Count - 1) * sizeof (D->data[0]));
(CollCount (&LineInfos) - 1) * sizeof (D->data[0])); D->count = E->Count;
D->count = CollCount (&LineInfos); if (E->Count == 1) {
for (I = 0; I < D->count; ++I) { CopyLineInfo (D->data, E->Data);
/* Copy data */ } else {
CopyLineInfo (D->data + I, CollAt (&LineInfos, I)); 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 the struct we've created */
return D; return D;
} }

View File

@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2010, Ullrich von Bassewitz */ /* (C) 2010-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
@ -81,6 +81,13 @@ 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*);
/* 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. /* Line information.
* Notes: * Notes:
* - line_end is inclusive * - line_end is inclusive
@ -99,6 +106,8 @@ struct cc65_linedata {
cc65_addr line_end; /* End address for this line */ cc65_addr line_end; /* End address for this line */
const char* output_name; /* Output file */ const char* output_name; /* Output file */
unsigned long output_offs; /* Offset in 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; typedef struct cc65_lineinfo cc65_lineinfo;

View File

@ -91,6 +91,20 @@ static void PrintLineData (const cc65_linedata* D)
if (D->output_name) { if (D->output_name) {
printf (" [%s($%06lX)]", D->output_name, D->output_offs); 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'); putchar ('\n');
} }
@ -229,7 +243,7 @@ int main (int argc, char** argv)
} }
/* Print symbols for the next $100 bytes starting from main (or 0x800) */ /* 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); (unsigned long) Addr, (unsigned long) Addr + 0xFF);
Symbols = cc65_symbol_inrange (Info, Addr, Addr + 0xFF); Symbols = cc65_symbol_inrange (Info, Addr, Addr + 0xFF);
if (Symbols == 0) { if (Symbols == 0) {
@ -240,7 +254,7 @@ int main (int argc, char** argv)
} }
/* Free the debug info */ /* Free the debug info */
cc65_free_dbginfo (Info); cc65_free_dbginfo (Info);
return 0; return 0;
} }