H->AssertSize = Read32 (Obj);
H->ScopeOffs = Read32 (Obj);
H->ScopeSize = Read32 (Obj);
+ H->SpanOffs = Read32 (Obj);
+ H->SpanSize = Read32 (Obj);
}
/* End a line that is tracked by the given LineInfo structure */
{
/* Close the spans for the line */
- CloseSpans (&LI->OpenSpans);
+ CloseSpanList (&LI->OpenSpans);
/* Move the spans to the list of all spans for this line, then clear the
* list of open spans.
}
/* Open the spans for this line info */
- OpenSpans (&LI->OpenSpans);
+ OpenSpanList (&LI->OpenSpans);
/* Add the line info to the list of current line infos */
CollAppend (&CurLineInfo, LI);
{
unsigned I;
- Collection EmptySpans = STATIC_COLLECTION_INITIALIZER;
-
/* Tell the object file module that we're about to write line infos */
ObjStartLineInfos ();
/* Write the type and count of the line info */
ObjWriteVar (LI->Key.Type);
- /* Spans are only added to the debug file if debug information is
- * requested. Otherwise we write an empty list.
- */
- if (DbgSyms) {
- WriteSpans (&LI->Spans);
- } else {
- /* Write out an empty list */
- WriteSpans (&EmptySpans);
- }
+ /* Write the ids of the spans for this line */
+ WriteSpanList (&LI->Spans);
}
/* End of line infos */
ObjEndLineInfos ();
-
- /* For the sake of completeness, but not really necessary */
- DoneCollection (&EmptySpans);
}
#include "scanner.h"
#include "segment.h"
#include "sizeof.h"
+#include "span.h"
#include "spool.h"
#include "symbol.h"
#include "symtab.h"
static void OptVerbose (const char* Opt attribute ((unused)),
- const char* Arg attribute ((unused)))
+ const char* Arg attribute ((unused)))
/* Increase verbosity */
{
++Verbosity;
/* Write the assertions */
WriteAssertions ();
+ /* Write the spans */
+ WriteSpans ();
+
/* Write an updated header and close the file */
ObjClose ();
}
break;
case 'V':
- OptVersion (Arg, 0);
+ OptVersion (Arg, 0);
break;
case 'W':
/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
0, /* 32: Size of assertion table */
0, /* 32: Offset into scope table */
0, /* 32: Size of scope table */
+ 0, /* 32: Offset into span table */
+ 0, /* 32: Size of span table */
};
ObjWrite32 (Header.AssertSize);
ObjWrite32 (Header.ScopeOffs);
ObjWrite32 (Header.ScopeSize);
+ ObjWrite32 (Header.SpanOffs);
+ ObjWrite32 (Header.SpanSize);
}
* advance).
*/
ObjWriteVar (SB_GetLen (S));
- ObjWriteData (SB_GetConstBuf (S), SB_GetLen (S));
+ ObjWriteData (SB_GetConstBuf (S), SB_GetLen (S));
}
+void ObjStartSpans (void)
+/* Mark the start of the span table */
+{
+ Header.SpanOffs = ftell (F);
+}
+
+
+
+void ObjEndSpans (void)
+/* Mark the end of the span table */
+{
+ Header.SpanSize = ftell (F) - Header.SpanOffs;
+}
+
+
+
/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
void ObjEndScopes (void);
/* Mark the end of the scope table */
+void ObjStartSpans (void);
+/* Mark the start of the span table */
+
+void ObjEndSpans (void);
+/* Mark the end of the span table */
+
/* End of objfile.h */
/* common */
+#include "hashfunc.h"
+#include "hashtab.h"
#include "xmalloc.h"
/* ca65 */
+#include "global.h"
#include "objfile.h"
#include "segment.h"
#include "span.h"
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key);
+/* Generate the hash over a key. */
+
+static const void* HT_GetKey (const void* Entry);
+/* Given a pointer to the user entry data, return a pointer to the key */
+
+static int HT_Compare (const void* Key1, const void* Key2);
+/* Compare two keys. The function must return a value less than zero if
+ * Key1 is smaller than Key2, zero if both are equal, and a value greater
+ * than zero if Key1 is greater then Key2.
+ */
+
+
+
/*****************************************************************************/
/* Data */
/*****************************************************************************/
+/* Hash table functions */
+static const HashFunctions HashFunc = {
+ HT_GenHash,
+ HT_GetKey,
+ HT_Compare
+};
+
+/* Span hash table */
+static HashTable SpanTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
+
+
+
+/*****************************************************************************/
+/* Hash table functions */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key)
+/* Generate the hash over a key. */
+{
+ /* Key is a Span pointer */
+ const Span* S = Key;
+
+ /* Hash over a combination of segment number, start and end */
+ return HashInt ((S->Seg->Num << 28) ^ (S->Start << 14) ^ S->End);
+}
+
+
+
+static const void* HT_GetKey (const void* Entry)
+/* Given a pointer to the user entry data, return a pointer to the key */
+{
+ return Entry;
+}
+
+
+
+static int HT_Compare (const void* Key1, const void* Key2)
+/* Compare two keys. The function must return a value less than zero if
+ * Key1 is smaller than Key2, zero if both are equal, and a value greater
+ * than zero if Key1 is greater then Key2.
+ */
+{
+ /* Convert both parameters to Span pointers */
+ const Span* S1 = Key1;
+ const Span* S2 = Key2;
+
+ /* Compare segment number, then start and end */
+ int Res = (int)S2->Seg->Num - (int)S1->Seg->Num;
+ if (Res == 0) {
+ Res = (int)S2->Start - (int)S1->Start;
+ if (Res == 0) {
+ Res = (int)S2->End - (int)S1->End;
+ }
+ }
+
+ /* Done */
+ return Res;
+}
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
Span* S = xmalloc (sizeof (Span));
/* Initialize the struct */
+ InitHashNode (&S->Node);
+ S->Id = ~0U;
S->Seg = Seg;
S->Start = Start;
S->End = End;
+ S->Type = 0;
/* Return the new struct */
return S;
-void OpenSpans (Collection* Spans)
+static Span* MergeSpan (Span* S)
+/* Check if we have a span with the same data as S already. If so, free S and
+ * return the already existing one. If not, remember S and return it.
+ */
+{
+ /* Check if we have such a span already. If so use the existing
+ * one and free the one from the collection. If not, add the one to
+ * the hash table and return it.
+ */
+ Span* E = HT_Find (&SpanTab, S);
+ if (E) {
+ /* If S has a type and E not, move the type */
+ CHECK (E->Type == 0);
+ E->Type = S->Type;
+ S->Type = 0;
+ /* Free S and return E */
+ FreeSpan (S);
+ return E;
+ } else {
+ /* Assign the id, insert S, then return it */
+ S->Id = HT_GetCount (&SpanTab);
+ HT_Insert (&SpanTab, S);
+ return S;
+ }
+}
+
+
+
+Span* OpenSpan (void)
+/* Open a span for the active segment and return it. */
+{
+ return NewSpan (ActiveSeg, ActiveSeg->PC, ActiveSeg->PC);
+}
+
+
+
+Span* CloseSpan (Span* S)
+/* Close the given span. Be sure to replace the passed span by the one
+ * returned, since the span will get deleted if it is empty or may be
+ * replaced if a duplicate exists.
+ */
+{
+ /* Set the end offset */
+ if (S->Start == S->Seg->PC) {
+ /* Span is empty */
+ FreeSpan (S);
+ return 0;
+ } else {
+ /* Span is not empty */
+ S->End = S->Seg->PC;
+
+ /* Check if we have such a span already. If so use the existing
+ * one and free the one from the collection. If not, add the one to
+ * the hash table and return it.
+ */
+ return MergeSpan (S);
+ }
+}
+
+
+
+void OpenSpanList (Collection* Spans)
/* Open a list of spans for all existing segments to the given collection of
* spans. The currently active segment will be inserted first with all others
* following.
-void CloseSpans (Collection* Spans)
+void CloseSpanList (Collection* Spans)
/* Close a list of spans. This will add new segments to the list, mark the end
* of existing ones, and remove empty spans from the list.
*/
} else {
/* Span is not empty */
S->End = S->Seg->PC;
- CollReplace (Spans, S, J++);
+
+ /* Merge duplicate spans, then insert it at the new position */
+ CollReplace (Spans, MergeSpan (S), J++);
}
}
-static void WriteSpan (const Span* S)
-/* Write one span to the output file */
+void WriteSpanList (const Collection* Spans)
+/* Write a list of spans to the output file */
{
- /* Done accept empty spans */
- CHECK (S->End > S->Start);
+ unsigned I;
- /* Write data for the span We will write the size instead of the end
- * offset to save some bytes, since most spans are expected to be
- * rather small.
- */
- ObjWriteVar (S->Seg->Num);
- ObjWriteVar (S->Start);
- ObjWriteVar (S->End - S->Start);
+ /* We only write spans if debug info is enabled */
+ if (DbgSyms == 0) {
+ /* Number of spans is zero */
+ ObjWriteVar (0);
+ } else {
+ /* Write the number of spans */
+ ObjWriteVar (CollCount (Spans));
+
+ /* Write the spans */
+ for (I = 0; I < CollCount (Spans); ++I) {
+ /* Write the id of the next span */
+ ObjWriteVar (((const Span*)CollConstAt (Spans, I))->Id);
+ }
+ }
}
-void WriteSpans (const Collection* Spans)
-/* Write a list of spans to the output file */
+static int CollectSpans (void* Entry, void* Data)
+/* Collect all spans in a collection sorted by id */
{
- unsigned I;
+ /* Cast the pointers to real objects */
+ Span* S = Entry;
+ Collection* C = Data;
+
+ /* Place the entry into the collection */
+ CollReplaceExpand (C, S, S->Id);
+
+ /* Keep the span */
+ return 0;
+}
+
+
+
+void WriteSpans (void)
+/* Write all spans to the object file */
+{
+ /* Tell the object file module that we're about to start the spans */
+ ObjStartSpans ();
+
+ /* We will write scopes only if debug symbols are requested */
+ if (DbgSyms) {
+
+ unsigned I;
- /* Write the number of spans */
- ObjWriteVar (CollCount (Spans));
+ /* We must first collect all items in a collection sorted by id */
+ Collection SpanList = STATIC_COLLECTION_INITIALIZER;
+ CollGrow (&SpanList, HT_GetCount (&SpanTab));
+
+ /* Walk over the hash table and fill the span list */
+ HT_Walk (&SpanTab, CollectSpans, &SpanList);
+
+ /* Write the span count to the file */
+ ObjWriteVar (CollCount (&SpanList));
+
+ /* Write all spans */
+ for (I = 0; I < CollCount (&SpanList); ++I) {
+
+ /* Get the span and check it */
+ const Span* S = CollAtUnchecked (&SpanList, I);
+ CHECK (S->End > S->Start);
+
+ /* Write data for the span We will write the size instead of the
+ * end offset to save some bytes, since most spans are expected
+ * to be rather small.
+ */
+ ObjWriteVar (S->Seg->Num);
+ ObjWriteVar (S->Start);
+ ObjWriteVar (S->End - S->Start);
+ }
+
+ /* Free the collection with the spans */
+ DoneCollection (&SpanList);
+
+ } else {
+
+ /* No debug info requested */
+ ObjWriteVar (0);
- /* Write the spans */
- for (I = 0; I < CollCount (Spans); ++I) {
- /* Write the next span */
- WriteSpan (CollConstAt (Spans, I));
}
+
+ /* Done writing the spans */
+ ObjEndSpans ();
}
+
/* common */
#include "coll.h"
+#include "gentype.h"
+#include "hashtab.h"
#include "inline.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* Span definition */
typedef struct Span Span;
struct Span{
+ HashNode Node; /* Node for hash table */
+ unsigned Id; /* Id of span */
struct Segment* Seg; /* Pointer to segment */
- unsigned long Start; /* Start of range */
- unsigned long End; /* End of range */
+ unsigned Start; /* Start of range */
+ unsigned End; /* End of range */
+ unsigned Type; /* Type of data in span */
};
# define GetSpanSize(R) ((R)->End - (R)->Start)
#endif
-void OpenSpans (Collection* Spans);
+Span* OpenSpan (void);
+/* Open a span for the active segment and return it. */
+
+Span* CloseSpan (Span* S);
+/* Close the given span. Be sure to replace the passed span by the one
+ * returned, since the span will get deleted if it is empty or may be
+ * replaced if a duplicate exists.
+ */
+
+void OpenSpanList (Collection* Spans);
/* Open a list of spans for all existing segments to the given collection of
* spans. The currently active segment will be inserted first with all others
* following.
*/
-void CloseSpans (Collection* Spans);
+void CloseSpanList (Collection* Spans);
/* Close all open spans by setting PC to the current PC for the segment. */
-void WriteSpans (const Collection* Spans);
+void WriteSpanList (const Collection* Spans);
/* Write a list of spans to the output file */
+void WriteSpans (void);
+/* Write all spans to the object file */
+
/* End of span.h */
* space in any segment).
*/
if (CurrentScope->Type <= SCOPE_HAS_DATA) {
- OpenSpans (&CurrentScope->Spans);
+ OpenSpanList (&CurrentScope->Spans);
}
}
* open the spans.
*/
if (CurrentScope->Type <= SCOPE_HAS_DATA) {
- CloseSpans (&CurrentScope->Spans);
+ CloseSpanList (&CurrentScope->Spans);
}
/* If we have spans, the first one is the segment that was active, when the
}
/* Spans for this scope */
- WriteSpans (&S->Spans);
+ WriteSpanList (&S->Spans);
/* Next scope */
S = S->Next;
/* Defines for magic and version */
#define OBJ_MAGIC 0x616E7A55
-#define OBJ_VERSION 0x000E
+#define OBJ_VERSION 0x000F
/* Size of an object file header */
-#define OBJ_HDR_SIZE (22*4)
+#define OBJ_HDR_SIZE (24*4)
/* Flag bits */
#define OBJ_FLAGS_DBGINFO 0x0001 /* File has debug info */
unsigned long AssertSize; /* 32: Size of assertion table */
unsigned long ScopeOffs; /* 32: Offset into scope table */
unsigned long ScopeSize; /* 32: Size of scope table */
+ unsigned long SpanOffs; /* 32: Offset into span table */
+ unsigned long SpanSize; /* 32: Size of span table */
};
O->Header.AssertSize = Read32 (L->F);
O->Header.ScopeOffs = Read32 (L->F);
O->Header.ScopeSize = Read32 (L->F);
+ O->Header.SpanOffs = Read32 (L->F);
+ O->Header.SpanSize = Read32 (L->F);
}
O->Flags = Read16 (L->F);
O->MTime = Read32 (L->F);
O->Start = Read32 (L->F);
- Read32 (L->F); /* Skip Size */
+ Read32 (L->F); /* Skip Size */
/* Done */
return O;
/* Read the files list */
ObjReadFiles (L->F, O->Start + O->Header.FileOffs, O);
+ /* Read the spans */
+ ObjReadSpans (L->F, O->Start + O->Header.SpanOffs, O);
+
/* Read the line infos */
ObjReadLineInfos (L->F, O->Start + O->Header.LineInfoOffs, O);
LI->File = CollAt (&O->Files, ReadVar (F));
LI->Pos.Name = LI->File->Name;
LI->Type = ReadVar (F);
- ReadSpans (&LI->Spans, F, O);
+ ReadSpanList (&LI->Spans, F, O);
/* Return the struct read */
return LI;
H->AssertSize = Read32 (Obj);
H->ScopeOffs = Read32 (Obj);
H->ScopeSize = Read32 (Obj);
+ H->SpanOffs = Read32 (Obj);
+ H->SpanSize = Read32 (Obj);
}
+void ObjReadSpans (FILE* F, unsigned long Pos, ObjData* O)
+/* Read the span table from a file at the given offset */
+{
+ unsigned I;
+ unsigned SpanCount;
+
+ /* Seek to the correct position */
+ FileSetPos (F, Pos);
+
+ /* Read the data */
+ SpanCount = ReadVar (F);
+ CollGrow (&O->Spans, SpanCount);
+ for (I = 0; I < SpanCount; ++I) {
+ CollAppend (&O->Spans, ReadSpan (F, O, I));
+ }
+}
+
+
+
void ObjAdd (FILE* Obj, const char* Name)
/* Add an object file to the module list */
{
/* Read the files list from the object file */
ObjReadFiles (Obj, O->Header.FileOffs, O);
+ /* Read the spans from the object file */
+ ObjReadSpans (Obj, O->Header.SpanOffs, O);
+
/* Read the line infos from the object file */
ObjReadLineInfos (Obj, O->Header.LineInfoOffs, O);
/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
void ObjReadScopes (FILE* F, unsigned long Pos, ObjData* O);
/* Read the scope table from a file at the given offset */
+void ObjReadSpans (FILE* F, unsigned long Pos, ObjData* O);
+/* Read the span table from a file at the given offset */
+
void ObjAdd (FILE* F, const char* Name);
/* Add an object file to the module list */
}
/* Read the spans for this scope */
- ReadSpans (&S->Spans, F, Obj);
+ ReadSpanList (&S->Spans, F, Obj);
/* Return the new Scope */
return S;
/* common */
+#include "attrib.h"
#include "xmalloc.h"
/* ld65 */
-Span* NewSpan (ObjData* Obj, unsigned SecId, unsigned long Offs, unsigned long Size)
+static Span* NewSpan (unsigned Id, unsigned Sec, unsigned long Offs, unsigned long Size)
/* Create and return a new span */
{
/* Allocate memory */
Span* S = xmalloc (sizeof (*S));
/* Initialize the fields */
- S->Id = CollCount (&Obj->Spans);
- S->Sec = SecId;
+ S->Id = Id;
+ S->Sec = Sec;
S->Offs = Offs;
S->Size = Size;
- /* Insert it into the collection of all spans of this object file */
- CollAppend (&Obj->Spans, S);
-
/* Return the result */
return S;
}
-Span* ReadSpan (FILE* F, ObjData* O)
+Span* ReadSpan (FILE* F, ObjData* O attribute ((unused)), unsigned Id)
/* Read a Span from a file and return it */
{
/* Create a new Span and return it */
unsigned SecId = ReadVar (F);
unsigned long Offs = ReadVar (F);
unsigned Size = ReadVar (F);
- return NewSpan (O, SecId, Offs, Size);
+ return NewSpan (Id, SecId, Offs, Size);
}
-void ReadSpans (Collection* Spans, FILE* F, ObjData* O)
-/* Read a list of Spans from a file and return it */
+void ReadSpanList (Collection* Spans, FILE* F, ObjData* O)
+/* Read a list of span ids from a file and return the spans for the ids */
{
/* First is number of Spans */
unsigned Count = ReadVar (F);
/* Read the spans and add them */
while (Count--) {
- CollAppend (Spans, ReadSpan (F, O));
+ CollAppend (Spans, CollAt (&O->Spans, ReadVar (F)));
}
}
-Span* NewSpan (struct ObjData* Obj, unsigned SecId, unsigned long Offs,
- unsigned long Size);
-/* Create and return a new span */
-
-Span* ReadSpan (FILE* F, struct ObjData* O);
+Span* ReadSpan (FILE* F, struct ObjData* O, unsigned Id);
/* Read a Span from a file and return it */
-void ReadSpans (Collection* Spans, FILE* F, struct ObjData* O);
-/* Read a list of Spans from a file and return it */
+void ReadSpanList (Collection* Spans, FILE* F, struct ObjData* O);
+/* Read a list of span ids from a file and return the spans for the ids */
void FreeSpan (Span* S);
/* Free a span structure */
+static void SkipSpanList (FILE* F)
+/* Skip a span list from the given file */
+{
+ /* Count preceeds the list */
+ unsigned long Count = ReadVar (F);
+
+ /* Skip indices */
+ while (Count--) {
+ (void) ReadVar (F);
+ }
+}
+
+
+
static void SkipExpr (FILE* F)
/* Skip an expression from the given file */
{
for (I = 0; I < Count; ++I) {
FilePos Pos;
-
- /* Type of line info */
- unsigned Type = ReadVar (F);
+ unsigned Type;
/* File position of line info */
ReadFilePos (F, &Pos);
+ /* Type of line info */
+ Type = ReadVar (F);
+
+ /* Skip the spans */
+ SkipSpanList (F);
+
/* Print the header */
printf (" Index:%27u\n", I);
const char* Name;
unsigned Len;
- unsigned SpanCount;
- unsigned J;
/* Read the data */
unsigned ParentId = ReadVar (F);
printf (" Label id:%22u\n", LabelId);
}
- /* Spans */
- SpanCount = ReadVar (F);
- printf (" Segment spans:\n");
- printf (" Count:%23u\n", SpanCount);
-
- for (J = 0; J < SpanCount; ++J) {
- printf (" Index:%23u\n", J);
- printf (" Segment:%19lu\n", ReadVar (F));
- printf (" Start:%13s0x%06lX\n", "", ReadVar (F));
- printf (" Size:%14s0x%06lX\n", "", ReadVar (F));
- }
+ /* Skip the spans */
+ SkipSpanList (F);
}
/* Destroy the string pool */
/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
void FileSetPos (FILE* F, unsigned long Pos)
/* Seek to the given absolute position, fail on errors */
-{
+{
if (fseek (F, Pos, SEEK_SET) != 0) {
Error ("Cannot seek: %s", strerror (errno));
}
H->AssertSize = Read32 (F);
H->ScopeOffs = Read32 (F);
H->ScopeSize = Read32 (F);
+ H->SpanOffs = Read32 (F);
+ H->SpanSize = Read32 (F);
}