initial dyninstAPI commit for code coverage
[dyninst.git] / dyninstAPI / src / LineInformation.C
1 #include <stdlib.h>
2
3 #include "dyninstAPI/src/LineInformation.h"
4 #include "dyninstAPI/src/util.h"
5
6
7 //this function implements binary search and returns the found element.
8 //besides the found element it returns the next bigger line numbered one
9 //The found element is the first same values element in the array in existence
10 //of many same values elements.
11 //in case it is not found it will RETURN NULL. if the next element
12 //is not available it will assign NULL to the reference.
13 //the next contains the entry with the first greater line number
14 tuple** binarySearchLineFirst(tuple element,tuple** array,int howMany,tuple**& next)
15 {
16         int low = 0;
17         int high = howMany-1;
18         int mid;
19         tuple** ret=NULL;
20         do{
21                 mid = (low+high)/2;
22                 if(element.lineNo < array[mid]->lineNo) 
23                         high = mid - 1;
24                 else if(element.lineNo > array[mid]->lineNo)
25                         low = mid + 1;
26                 else
27                         break;
28         }while(low <= high);
29
30         //if found then porepare to return and the next available
31         if(element.lineNo == array[mid]->lineNo){
32                 int index = mid;
33                 for(;(index >= 0)&&(array[index]->lineNo == element.lineNo);index--);
34                 ret = array+(index+1);
35                 index = mid;
36                 for(;(index < howMany)&&(array[index]->lineNo == element.lineNo);index++);
37                 if(index == howMany)
38                         next = NULL;
39                 else
40                         next = array+index;
41         }
42         else if(low == howMany)
43                 next = NULL;
44         else
45                 next = array+low;
46
47         return ret;
48 }
49 //this function implements binary search and returns the found element.
50 //besides the found element it returns the previous smaller address entry
51 //The found element is the first same values element in the array in existence
52 //of many same values elements.
53 //in case it is not found it will RETURN NULL. if the next element
54 //is not available it will assign NULL to the reference.
55 //the next contains the entry with the previous smaller address
56 tuple** binarySearchAddrFirst(tuple element,tuple** array,int howMany,tuple**& next)
57 {
58         int low = 0;
59         int high = howMany-1;
60         int mid;
61         tuple** ret=NULL;
62         do{
63                 mid = (low+high)/2;
64                 if(element.codeAddress < array[mid]->codeAddress) 
65                         high = mid - 1;
66                 else if(element.codeAddress > array[mid]->codeAddress)
67                         low = mid + 1;
68                 else
69                         break;
70         }while(low <= high);
71
72         ////if found then porepare to return and the next available
73         if(element.codeAddress == array[mid]->codeAddress){
74                 int index = mid;
75                 for(;(index>=0)&&(array[index]->codeAddress == element.codeAddress);index--);
76                 ret = array+(index+1);
77                 if(index == -1)
78                         next = NULL;
79                 else{
80                         Address addr = array[index]->codeAddress;
81                         for(;(index>=0) && (array[index]->codeAddress == addr);index--);
82                         next = array+(index+1);
83                 }
84         }
85         else if(high == -1)
86                 next = NULL;
87         else{
88                 Address addr = array[high]->codeAddress;
89                 for(;(high >=0) && (array[high]->codeAddress == addr);high--);
90                 next = array+(high+1);
91         }
92         return ret;
93 }
94
95 //constructor
96 FileLineInformation::FileLineInformation(string fileName)
97         : sourceFileName(fileName),
98           size(0),
99           lineToAddr(NULL),
100           addrToLine(NULL),
101           functionCount(0),
102           functionNameList(NULL),
103           lineInformationList(NULL) {}
104
105 //destructor
106 FileLineInformation::~FileLineInformation(){
107         int i;
108         for(i=0;i<size;i++)
109                 delete lineToAddr[i];
110         free(lineToAddr);
111         free(addrToLine);
112         for(i=0;i<functionCount;i++){
113                 delete lineInformationList[i];
114                 delete functionNameList[i];
115         }
116         free(functionNameList);
117         free(lineInformationList);
118 }
119
120 //returns the function info structure
121 FunctionInfo *FileLineInformation::findFunctionInfo(string functionName){
122         for(int i=0;i<functionCount;i++)
123                 if(functionName == *functionNameList[i])
124                         return lineInformationList[i];
125         return NULL;
126 }
127
128 //inserts function wntry to the mapping from function name to its info
129 void FileLineInformation::insertFunction(string functionName){
130         FunctionInfo* fInfo = findFunctionInfo(functionName);
131         if(!fInfo){
132                 functionNameList = (string**)(functionCount ? 
133                         realloc(functionNameList,(functionCount+1)*sizeof(string*)) : 
134                         malloc(sizeof(string*)));
135                 lineInformationList = (FunctionInfo**)(functionCount ? 
136                         realloc(lineInformationList,(functionCount+1)*sizeof(FunctionInfo*)) : 
137                         malloc(sizeof(FunctionInfo*)));
138                 functionNameList[functionCount] = new string(functionName);
139                 lineInformationList[functionCount] = new FunctionInfo();
140                 functionCount++;
141         }       
142 }
143
144 //returns true if the function has an entry in the mapping
145 bool FileLineInformation::findFunction(string functionName){
146         FunctionInfo* fInfo = findFunctionInfo(functionName);
147         if(!fInfo) return false;
148         return true;
149 }
150
151 //delete the records for function
152 void FileLineInformation::deleteFunction(string functionName){
153         int i = 0;
154         for(i=0;i<functionCount;i++)
155                 if(functionName == *functionNameList[i])
156                         break;
157         if(i >= functionCount)
158                 return;
159
160         functionCount--;
161         if(!functionCount){
162                 free(functionNameList);
163                 free(lineInformationList);
164                 functionNameList = NULL; 
165                 lineInformationList = NULL; 
166                 return;
167         }
168         delete functionNameList[i];
169
170         functionNameList[i] = functionNameList[functionCount];
171         functionNameList = 
172                 (string**)realloc(functionNameList,functionCount*sizeof(string*));
173         lineInformationList[i] = lineInformationList[functionCount];
174         lineInformationList = 
175                 (FunctionInfo**)realloc(lineInformationList,functionCount*sizeof(FunctionInfo*));
176 }
177
178 //updates records for a function
179 bool FileLineInformation::insertFunction(string functionName,Address baseAddr,
180                                          Address functionSize)
181 {
182         tuple toSearchBegin(0,baseAddr);
183         tuple toSearchEnd(0,baseAddr+functionSize-1);
184
185         tuple** next=NULL;
186         tuple** retBegin = binarySearchAddrFirst(toSearchBegin,
187                                         addrToLine,size,next);
188         if(retBegin){
189                 unsigned short beginLineIndex = retBegin[0]->linePtr;   
190                 unsigned short beginAddrIndex = retBegin[0]->addrPtr;   
191
192                 tuple** retEnd = binarySearchAddrFirst(toSearchEnd,
193                                         addrToLine,size,next);
194                 if(!retEnd && !next)
195                         return false;
196
197                 unsigned short endLineIndex;
198                 unsigned short endAddrIndex;
199                 if(retEnd){
200                         endLineIndex = retEnd[0]->linePtr;
201                         endAddrIndex = retEnd[0]->addrPtr;
202                 }
203                 else{
204                         endLineIndex = next[0]->linePtr;
205                         endAddrIndex = next[0]->addrPtr;
206                 }
207
208                 //cerr << "FOUND " << " LINE RANGE ( " 
209                 //     <<  beginLineIndex << "," << endLineIndex << " ) -- "
210                 //     << " ADDRESS RANGE ( " <<  beginAddrIndex << "," 
211                 //     << endAddrIndex << " )\n";
212                 functionNameList = (string**)(functionCount ?
213                         realloc(functionNameList,(functionCount+1)*sizeof(string*)) :
214                         malloc(sizeof(string*)));
215                 lineInformationList = (FunctionInfo**)(functionCount ?
216                         realloc(lineInformationList,(functionCount+1)*sizeof(FunctionInfo*)) :
217                         malloc(sizeof(FunctionInfo*)));
218                 functionNameList[functionCount] = new string(functionName);
219
220                 FunctionInfo* fInfo = new FunctionInfo();
221                 fInfo->startLinePtr = lineToAddr[beginLineIndex];
222                 fInfo->endLinePtr = lineToAddr[endLineIndex];
223                 fInfo->startAddrPtr = addrToLine[beginAddrIndex];
224                 fInfo->endAddrPtr = addrToLine[endAddrIndex];
225                 fInfo->validInfo = true;
226                 lineInformationList[functionCount] = fInfo;
227
228                 functionCount++;
229                 return true;
230         }
231         return false;
232 }
233
234 //insert a mapping from line number to address and address to line number
235 //to the corresponding structures and updates the records for the function
236 //given
237 void FileLineInformation::insertLineAddress(string functionName,
238                                             unsigned short lineNo,
239                                             Address codeAddress)
240 {
241
242         FunctionInfo* fInfo = findFunctionInfo(functionName);
243         if(!fInfo){
244                 cerr << "FATAL ERROR : Something wrong \n";
245                 return;
246         }
247
248         lineToAddr = !lineToAddr ? ((tuple**)malloc(sizeof(tuple*))) :
249                      ((tuple**)realloc(lineToAddr,sizeof(tuple*)*(size+1)));
250         addrToLine = !addrToLine ? ((tuple**)malloc(sizeof(tuple*))) :
251                      ((tuple**)realloc(addrToLine,sizeof(tuple*)*(size+1)));
252
253         //since the entries will come in oreder insertion sort is the best sort here
254         //to keep the list sorted and using binary search to find the entries.
255         //insertion sort comes here
256
257         tuple* newTuple = new tuple(lineNo,codeAddress);
258
259         short index1; 
260         for(index1=size-1;index1>=0;index1--)
261                 if(lineToAddr[index1]->lineNo > lineNo){
262                         lineToAddr[index1+1] = lineToAddr[index1];
263                         lineToAddr[index1+1]->linePtr = (unsigned)(index1+1);
264                 }
265                 else break;
266         index1++;
267         lineToAddr[index1] = newTuple;
268         lineToAddr[index1]->linePtr = (unsigned)index1; 
269
270         short index2; 
271         for(index2=size-1;index2>=0;index2--)
272                 if(addrToLine[index2]->codeAddress > codeAddress){
273                         addrToLine[index2+1] = addrToLine[index2];
274                         addrToLine[index2+1]->addrPtr = (unsigned)(index2+1);
275                 }
276                 else break;
277         index2++;
278         addrToLine[index2] = newTuple;
279         addrToLine[index2]->addrPtr = (unsigned)index2;
280
281         size++;
282
283         if(!fInfo->validInfo){
284                 fInfo->startLinePtr = lineToAddr[index1];
285                 fInfo->endLinePtr = lineToAddr[index1];
286                 fInfo->startAddrPtr = addrToLine[index2];
287                 fInfo->endAddrPtr = addrToLine[index2];
288                 fInfo->validInfo = true;
289                 return;
290         }
291         if(fInfo->startLinePtr->lineNo > lineNo)
292                 fInfo->startLinePtr = lineToAddr[index1];
293
294         if(fInfo->endLinePtr->lineNo <= lineNo)
295                 fInfo->endLinePtr = lineToAddr[index1];
296
297         if(fInfo->startAddrPtr->codeAddress > codeAddress)
298                 fInfo->startAddrPtr = addrToLine[index2];
299
300         if(fInfo->endAddrPtr->codeAddress <= codeAddress)
301                 fInfo->endAddrPtr = addrToLine[index2];
302 }
303  
304 //returns true in case of success, false otherwise.
305 //this method finds the line number corresponding to an address.
306 //if name of the function is supplied and isFile is false
307 //then function level search is being applied. Otherwise file level
308 //search is applied. If there are more than 1 line found than
309 //the maximum is being returned.
310 bool FileLineInformation::getLineFromAddr(string name,unsigned short& lineNo,
311                                           Address codeAddress,bool isFile,
312                                           bool isExactMatch)
313 {
314         BPatch_Set<unsigned short> lines;
315         if(!getLineFromAddr(name,lines,codeAddress,isFile,isExactMatch))
316                 return false;
317         lineNo = lines.maximum();
318         return true;
319 }
320 //returns true in case of success, false otherwise.
321 //this method finds the line numbers corresponding to an address.
322 //if name of the function is supplied and isFile is false
323 //then function level search is being applied. Otherwise file level
324 //search is applied. All the line numbers corresponding to the address
325 //is returned in a set of addresses.
326 bool FileLineInformation::getLineFromAddr(string name,
327                                           BPatch_Set<unsigned short>& lines,
328                                           Address codeAddress,bool isFile,
329                                           bool isExactMatch)
330 {
331         tuple** beginPtr;
332         tuple** endPtr;
333         int howMany;
334
335         if(!addrToLine)
336                 return false;
337         if(isFile){
338                 beginPtr = addrToLine;
339                 endPtr = (tuple**) (addrToLine+(size-1));
340                 howMany = size;
341         }
342         else{
343                 FunctionInfo* fInfo = findFunctionInfo(name);
344                 if(!fInfo)
345                         return false;
346                 if(!fInfo->validInfo)
347                         return false;
348                 beginPtr = (tuple**)(addrToLine+fInfo->startAddrPtr->addrPtr);
349                 endPtr = (tuple**)(addrToLine+fInfo->endAddrPtr->addrPtr);
350                 howMany = (fInfo->endAddrPtr->addrPtr - fInfo->startAddrPtr->addrPtr)+1;
351         }
352
353         if((codeAddress < (*beginPtr)->codeAddress) || 
354            ((*endPtr)->codeAddress < codeAddress))
355                 return false;
356
357         tuple toSearch(0,codeAddress);
358         tuple** next=NULL;
359         tuple** ret = binarySearchAddrFirst(toSearch,beginPtr,howMany,next);
360         if(!ret){
361                 if(isExactMatch)
362                         return false;
363                 if(!next)
364                         return false;
365                 ret = next;
366                 codeAddress = (*ret)->codeAddress;
367         }
368         do{
369                 lines += (*ret)->lineNo;
370                 ret++;
371         }while((ret <= endPtr) && ((*ret)->codeAddress == codeAddress));
372
373         return true;
374 }
375
376 //method that retuns set of addresses corresponding to a given line number
377 //the level of the search is file level if isFile flag is set.
378 //If isFile level is not set, it seraches in the given function
379 //in case of success it returns true otherwise false
380 bool FileLineInformation::getAddrFromLine(string name,
381                                           BPatch_Set<Address>& codeAddress,
382                                           unsigned short lineNo,bool isFile,
383                                           bool isExactMatch)
384 {
385         tuple** beginPtr;
386         tuple** endPtr;
387         int howMany;
388
389         if(!lineToAddr)
390                 return false;
391         if(isFile){
392                 beginPtr = lineToAddr;
393                 endPtr = (tuple**) (lineToAddr+(size-1));
394                 howMany = size;
395         }
396         else{
397                 FunctionInfo* fInfo = findFunctionInfo(name);
398                 if(!fInfo)
399                         return false;
400                 if(!fInfo->validInfo)
401                         return false;
402                 beginPtr = (tuple**)(lineToAddr+fInfo->startLinePtr->linePtr);
403                 endPtr = (tuple**)(lineToAddr+fInfo->endLinePtr->linePtr);
404                 howMany = (fInfo->endLinePtr->linePtr-fInfo->startLinePtr->linePtr)+1;
405         }
406         if(!isFile && 
407            (lineNo < (*beginPtr)->lineNo) || ((*endPtr)->lineNo < lineNo))
408                 return false;
409
410         tuple toSearch(lineNo,0);
411         tuple** next=NULL;
412         tuple** ret = binarySearchLineFirst(toSearch,beginPtr,howMany,next);
413         if(!ret){
414                 if(isExactMatch)
415                         return false;
416                 if(!next)
417                         return false;
418                 ret = next;
419                 lineNo = (*ret)->lineNo;
420         }
421         do{
422                 codeAddress += (*ret)->codeAddress;
423                 ret++;
424         }while((ret <= endPtr) && ((*ret)->lineNo == lineNo));
425
426         return true;
427 }
428
429 bool FileLineInformation::getMinMaxAddress(int n,Address& min,Address& max){
430         FunctionInfo* fi = lineInformationList[n];
431         if(!fi->validInfo)
432                 return false;
433         min = fi->startAddrPtr->codeAddress;
434         max = fi->endAddrPtr->codeAddress;
435         return true;
436 }
437
438 unsigned short FileLineInformation::getFunctionCount(){
439         return functionCount;
440 }
441
442 string** FileLineInformation::getFunctionNameList(){
443         return functionNameList;
444 }
445
446
447 //constructor whose argument is the name of the module name
448 LineInformation::LineInformation(string mName) 
449                 : moduleName(mName),
450                   sourceFileCount(0),
451                   sourceFileList(NULL),
452                   lineInformationList(NULL) {}
453
454
455 //desctructor
456 LineInformation::~LineInformation() {
457         for(int i=0;i<sourceFileCount;i++){
458                 delete sourceFileList[i];
459                 delete lineInformationList[i];
460         }
461         free(sourceFileList);
462         free(lineInformationList);
463 }
464
465 //method to insert entries for the given file name and function name
466 //it creates the necessary structures and inserts into the maps
467 void LineInformation::insertSourceFileName(string functionName,string fileName)
468 {
469         FileLineInformation* fInfo = getFileLineInformation(fileName);
470         if(!fInfo){
471                 fInfo = new FileLineInformation(fileName);
472                 sourceFileList = (string**)(sourceFileCount ? 
473                         realloc(sourceFileList,(sourceFileCount+1)*sizeof(string*)) : 
474                         malloc(sizeof(string*)));
475                 lineInformationList = (FileLineInformation**)(sourceFileCount ? 
476                         realloc(lineInformationList,(sourceFileCount+1)*sizeof(FileLineInformation*)) : 
477                         malloc(sizeof(FileLineInformation*)));
478                 sourceFileList[sourceFileCount] = new string(fileName);
479                 lineInformationList[sourceFileCount] = fInfo;
480                 sourceFileCount++;
481         }
482         fInfo->insertFunction(functionName);
483 }
484
485 //inserts line to address and address to line mapping to the line info
486 //object of the given filename. The records for function is also updated
487 void LineInformation::insertLineAddress(string functionName,
488                                         string fileName,
489                                         unsigned short lineNo,
490                                         Address codeAddress)
491 {
492         FileLineInformation* fInfo = getFileLineInformation(fileName);
493         if(!fInfo) return;
494         fInfo->insertLineAddress(functionName,lineNo,codeAddress);
495 }
496
497 //returns line number corresponding to the the given address
498 //if isFile is set the search is file level otherwsie function level.
499 bool LineInformation::getLineFromAddr(string name,
500                                       unsigned short& lineNo,
501                                       Address codeAddress,
502                                       bool isFile,
503                                       bool isExactMatch)
504 {
505         FileLineInformation* fInfo = NULL;
506         if(isFile) 
507                 fInfo = getFileLineInformation(name);
508         else
509                 fInfo = getFunctionLineInformation(name);
510                 
511         if(!fInfo) return false;
512         
513         return fInfo->getLineFromAddr(name,lineNo,codeAddress,isFile,isExactMatch);
514 }
515
516 //returns line number corresponding to the the given address
517 //if isFile is set the search is file level otherwsie function level.
518 bool LineInformation::getLineFromAddr(string name,
519                                       BPatch_Set<unsigned short>& lines,
520                                       Address codeAddress,
521                                       bool isFile,
522                                       bool isExactMatch)
523 {
524         FileLineInformation* fInfo = NULL;
525         if(isFile) 
526                 fInfo = getFileLineInformation(name);
527         else
528                 fInfo = getFunctionLineInformation(name);
529                 
530         if(!fInfo) return false;
531         
532         return fInfo->getLineFromAddr(name,lines,codeAddress,isFile,isExactMatch);
533 }
534
535 //returns address corresponding to the the given line 
536 //if isFile is set the search is file level otherwsie function level.
537 bool LineInformation::getAddrFromLine(string name,
538                                       BPatch_Set<Address>& codeAddress,
539                                       unsigned short lineNo,
540                                       bool isFile,
541                                       bool isExactMatch)
542 {
543         FileLineInformation* fInfo = NULL;
544         if(isFile) 
545                 fInfo = getFileLineInformation(name);
546         else
547                 fInfo = getFunctionLineInformation(name);
548                 
549         if(!fInfo) return false;
550
551         return fInfo->getAddrFromLine(name,codeAddress,lineNo,isFile,isExactMatch);
552 }
553
554 bool LineInformation::getAddrFromLine(BPatch_Set<Address>& codeAddress,
555                                       unsigned short lineNo,
556                                       bool isExactMatch)
557 {
558         FileLineInformation* fInfo = getFileLineInformation(moduleName);
559         if(!fInfo){ 
560 #ifdef DEBUG_LINE
561                 cerr << "Module " << moduleName << " is not source file name\n";
562 #endif
563                 return false;
564         }
565         return fInfo->getAddrFromLine(moduleName,codeAddress,
566                                       lineNo,true,isExactMatch);
567 }
568
569 //returns the line information for the given filename
570 FileLineInformation* LineInformation::getFileLineInformation(string fileName){
571         for(int j=0;j<sourceFileCount;j++)
572                 if(fileName == *sourceFileList[j])
573                         return lineInformationList[j];
574         for(int i=0;i<sourceFileCount;i++){
575                 char* name = new char[sourceFileList[i]->length()+1];
576                 strncpy(name,sourceFileList[i]->string_of(),
577                         sourceFileList[i]->length());
578                 name[sourceFileList[i]->length()] = '\0';
579                 char* p = strrchr(name,'/');
580                 if(!p) {
581                         delete[] name;
582                         continue;
583                 }
584                 p++;
585                 string sname(p);
586                 if(fileName == sname){
587                         delete[] name;
588                         return lineInformationList[i];
589                 }
590                 delete[] name;
591         }
592                 
593         return NULL;
594
595
596 //method retuns the file line information object which the function belongs to.
597 //if there is no entry than it retuns NULL
598 FileLineInformation* 
599 LineInformation::getFunctionLineInformation(string functionName){
600         for(int i=0;i<sourceFileCount;i++)
601                 if(lineInformationList[i]->findFunction(functionName))
602                         return lineInformationList[i];
603         return NULL;
604
605
606 //method that returns true if function belongs to this object
607 //false otherwise
608 bool LineInformation::findFunction(string functionName){
609         bool ret = false;
610         for(int i=0;!ret && (i<sourceFileCount);i++)
611                 ret = lineInformationList[i]->findFunction(functionName);
612         return ret;
613 }
614
615 //delete the records for function
616 void LineInformation::deleteFunction(string functionName){
617         for(int i=0;i<sourceFileCount;i++)
618                 lineInformationList[i]->deleteFunction(functionName);
619 }
620
621 //updates records for a function
622 void LineInformation::insertFunction(string functionName,Address baseAddr,
623                                      Address functionSize)
624 {
625         if(findFunction(functionName))
626                 return;
627         bool ret = false;
628         for(int i=0;!ret && (i<sourceFileCount);i++)
629                 ret = lineInformationList[i]->insertFunction(functionName,
630                                                        baseAddr,functionSize);
631 }
632
633 string** LineInformation::getSourceFileList(){
634         return sourceFileList;
635 }
636
637 unsigned short LineInformation::getSourceFileCount(){
638         return sourceFileCount;
639 }
640
641 FileLineInformation** LineInformation::getLineInformationList(){
642         return lineInformationList;
643 }
644
645 ostream& operator<<(ostream& os,FileLineInformation& linfo){
646
647         cerr << "\tLINE TO ADDRESS \t\t ADDRESS TO LINE:\n";
648         for(int j=0;j<linfo.size;j++){
649                 os << dec << j << "\t";
650                 os << dec << linfo.lineToAddr[j]->lineNo << " ----> ";
651                 os << hex << linfo.lineToAddr[j]->codeAddress << "\t\t";
652                 os << hex << linfo.addrToLine[j]->codeAddress  << " ----> ";
653                 os << dec << linfo.addrToLine[j]->lineNo << "\n";
654         }
655         for(int i=0;i<linfo.functionCount;i++){
656                 FunctionInfo* funcinfo = linfo.lineInformationList[i];
657                 os << "FUNCTION LINE : " << *(linfo.functionNameList[i]) << " : " ;
658                 if(!funcinfo->validInfo)
659                         continue;
660                 os << dec << funcinfo->startLinePtr->lineNo << " --- ";
661                 os << dec << funcinfo->endLinePtr->lineNo << "\t\t";
662                 os << hex << funcinfo->startAddrPtr->codeAddress << " --- ";
663                 os << hex << funcinfo->endAddrPtr->codeAddress << "\n";
664         }
665         return os;
666 }
667
668 ostream& operator<<(ostream& os,LineInformation& linfo){
669         os << "**********************************************\n";
670         os << "MODULE : " << linfo.moduleName << "\n";  
671         os << "**********************************************\n";
672         for(int i=0;i<linfo.sourceFileCount;i++){
673                 os << "FILE : " << *(linfo.sourceFileList[i]) << "\n";
674                 os << *(linfo.lineInformationList[i]);
675         }
676         return os;
677 }
678