]> git.sur5r.net Git - cc65/commitdiff
Redid the whole line info stuff, because the old data structures weren't able
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 3 Feb 2011 17:08:20 +0000 (17:08 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 3 Feb 2011 17:08:20 +0000 (17:08 +0000)
to manage the new information.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4961 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/dbginfo/dbginfo.c
src/dbginfo/dbginfo.h
src/dbginfo/dbgtest.c

index a7897240878653e683dec2058c978ffc313157d0..1d8d1ca0feadb4c78f7eed9c6a61fea75936ebee 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2010,      Ullrich von Bassewitz                                      */
+/* (C) 2010-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
 
 
 
+/* 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;
 }
index 92d06216c6f88ddf8ad4dd3fd4e7667ca4da7770..7a5c5f3b61d999c747f646cbaa476bd40b5847d3 100644 (file)
@@ -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;
index da4af88200bb7aa5877dfc5bf6937b6b3d12eb03..54c188bf53e678ff38f0f690e50240e80eb5872c 100644 (file)
@@ -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;
 }