1 /*
2  * Copyright (c) Yiftach Tzori 2009-2012.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  */
9 #include <config.h>
10 #include "globals.h"
11 #include <gtk/gtk.h>
12 #include <gdk/gdkkeysyms.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include "gtk12compat.h"
16 #include "analyzer.h"
17 #include "tree.h"
18 #include "symbol.h"
19 #include "vcd.h"
20 #include "lx2.h"
21 #include "busy.h"
22 #include "debug.h"
23 #include "hierpack.h"
24 #include "tcl_helper.h"
25 #include "tcl_support_commands.h"
26 
27 /* **
28  * Search for a tree node that is associated with the hierarchical path
29  * return pointer to this node or NULL
30  */
SST_find_node_by_path(GtkCTreeRow * root,char * path)31 GtkCTreeNode *SST_find_node_by_path(GtkCTreeRow *root, char *path) {
32   char *s = strdup_2(path) ;
33   char *p = s ;
34   char *p1 ;
35   GtkCTreeRow *gctr = root ;
36   GtkCTreeNode *node = gctr->parent ;
37   struct tree *t ;
38   int i ;
39   /* in the cases of path that where generated inside a `generate-for' block
40    * path name will contain '[]'. This will prompt TCL to soround PATH with
41    * '{' and '}'
42    */
43   if (*p == '{' && (p1 = strrchr(p, '}'))) {
44     p++ ;
45     *p1 = '\0' ;
46   }
47   while (gctr)  {
48     if ((p1 = strchr(p, '.')))
49       *p1 = '\0' ;
50     t = (struct tree *)(gctr->row.data) ;
51     i = 0 ;
52     while (strcmp(t->name, p)) { /* name mis-match */
53       if (!(node = gctr->sibling)) { /* no more siblings */
54 	gctr = NULL ;
55 	break ;
56       } else {
57 	gctr = GTK_CTREE_ROW(node);
58 	t = (struct tree *)(gctr->row.data) ;
59       }
60       i++ ;
61     }
62     if (gctr) {			/* normal exit from the above */
63       if(!p1) {/* first/last in chain */
64 	if(i == 0)		/* first */
65 	  if(gctr->children)
66 	    node = GTK_CTREE_ROW(gctr->children)->parent ;
67 	break ;
68       } else {			/* keep going down the hierarchy */
69 	if (!(node = gctr->children))
70 	  break ;
71 	else {
72 	  gctr = GTK_CTREE_ROW(gctr->children) ;
73 	  p = p1 + 1 ;
74 	}
75       }
76     }
77   }
78   free_2(s) ;
79   return node ;
80 }
81 
82 /* **
83  * Open the hierarchy tree, starting from 'node' up to the root
84  */
SST_open_path(GtkCTree * ctree,GtkCTreeNode * node)85 int SST_open_path(GtkCTree *ctree, GtkCTreeNode *node) {
86   GtkCTreeRow *row ;
87   for(row = GTK_CTREE_ROW(node) ; row->parent; row = GTK_CTREE_ROW(row->parent)) {
88     if(row->parent)
89       gtk_ctree_expand(ctree, row->parent);
90     else
91       break ;
92   }
93   return 0 ;
94 }
95 
96 /* **
97  * Main function called by gtkwavetcl_forceOpenTreeNode
98  * Inputs:
99  *   char *name :: hierachical path to open
100  * Output:
101  *   One of:
102  *     SST_NODE_FOUND - if path is in the dump file
103  *     SST_NODE_NOT_EXIST - is path is not in the dump
104  *     SST_TREE_NOT_EXIST - is Tree widget does not exist
105  * Side effects:
106  *    If  path is in the dump then its tree is opened and scrolled
107  *    to be it to display. Node is selected and associated signals
108  *    are displayed.
109  *    No change in any other case
110   */
111 
SST_open_node(char * name)112 int SST_open_node(char *name) {
113   int rv ;
114 #ifdef WAVE_USE_GTK2
115    GtkCTree *ctree = GLOBALS->ctree_main;
116    if (ctree) {
117      GtkCTreeRow *gctr;
118      GtkCTreeNode *target_node ;
119      for(gctr = GTK_CTREE_ROW(GLOBALS->any_tree_node); gctr->parent;
120 	 gctr = GTK_CTREE_ROW(gctr->parent)) ;
121      if ((target_node = SST_find_node_by_path(gctr, name))) {
122        struct tree *t ;
123        rv = SST_NODE_FOUND ;
124        gtk_ctree_collapse_recursive(ctree, gctr->parent) ;
125        SST_open_path(ctree, target_node) ;
126        gtk_ctree_node_moveto(ctree, target_node, 0, 0.5, 0.5);
127        gtk_ctree_select(ctree, target_node);
128        gctr = GTK_CTREE_ROW(target_node) ;
129        t = (struct tree *)(gctr->row.data) ;
130        GLOBALS->sig_root_treesearch_gtk2_c_1 = t->child;
131        fill_sig_store ();
132      } else {
133        rv = SST_NODE_NOT_EXIST ;
134      }
135    } else {
136      rv = SST_TREE_NOT_EXIST ;
137    }
138 #else
139 (void)name;
140   rv = SST_TREE_NOT_EXIST ;
141 #endif
142 
143    return rv ;
144 }
145 /* ===== Double link lists */
llist_new(llist_u v,ll_elem_type type,int arg)146 llist_p *llist_new(llist_u v, ll_elem_type type, int arg) {
147   llist_p *p = (llist_p *)malloc_2(sizeof(llist_p)) ;
148   p->next = p->prev = NULL ;
149   switch(type) {
150   case LL_INT: p->u.i = v.i ; break ;
151   case LL_UINT: p->u.u = v.u ; break ;
152   case LL_TIMETYPE: p->u.tt = v.tt ; break ;
153   case LL_CHAR: p->u.c = v.c ; break ;
154   case LL_SHORT: p->u.s = v.s ; break ;
155   case LL_STR:
156     if(arg == -1)
157       p->u.str = strdup_2(v.str) ;
158     else {
159       p->u.str = (char *)malloc_2(arg) ;
160       strncpy(p->u.str, v.str, arg) ;
161       p->u.str[arg] = '\0' ;
162     }
163     break ;
164   case LL_VOID_P: p->u.p = v.p ; break ;
165   default:
166 	fprintf(stderr, "Internal error in llist_new(), type: %d\n", type);
167 	exit(255);
168   }
169   return p ;
170 }
171 
172 /*
173 * append llist_p element ELEM to the of the list whose first member is HEAD amd
174 * last is TAIL. and return the head of the list.
175 * if HEAD is NULL ELEM is returned.
176 * if TAIL is defined then ELEM is chained to it and TAIL is set to point to
177 * ELEM
178 */
179 
llist_append(llist_p * head,llist_p * elem,llist_p ** tail)180 llist_p *llist_append(llist_p *head, llist_p *elem, llist_p **tail) {
181   llist_p *p ;
182   if (*tail) {
183     p = tail[0] ;
184     p->next = elem ;
185     elem->prev = p ;
186     tail[0] = elem ;
187   } else {
188     if (head) {
189       for(p = head ; p->next; p = p->next) ;
190       p->next = elem ;
191       elem ->prev = p ;
192     } else {
193       head = elem ;
194     }
195   }
196   return head ;
197 }
198 /*
199 * Remove the last element from list whose first member is HEAD
200 * if TYPE is LL_STR the memory allocated for this string is freed.
201 * if the TYPE is LL_VOID_P that the caller supplied function pointer F() is
202 *  is executed (if not NULL)
203 * HEAD and TAIL are updated.
204  */
205 
llist_remove_last(llist_p * head,llist_p ** tail,ll_elem_type type,void * f (void *))206 llist_p *llist_remove_last(llist_p *head, llist_p **tail, ll_elem_type type, void *f(void *) ) {
207   if (head) {
208     llist_p *p = tail[0] ;
209     switch(type) {
210     case LL_STR: free_2(p->u.str) ; break ;
211     case LL_VOID_P:
212       if (f)
213 	f(p->u.p) ;
214       break ;
215     default:
216       fprintf(stderr, "Internal error in llist_remove_last(), type: %d\n", type);
217       exit(255);
218     }
219     if (p->prev) {
220       tail[0] = p->prev ;
221     } else {
222       head = tail[0] = NULL ;
223     }
224     free_2(p) ;
225   }
226   return head ;
227 }
228 
229 /* Destroy the list whose first member is HEAD
230 * function pointer F() is called in type is LL_VOID_P
231 * if TYPE is LL_STR then string is freed
232 */
llist_free(llist_p * head,ll_elem_type type,void * f (void *))233 void llist_free(llist_p *head, ll_elem_type type, void *f(void *)) {
234   llist_p *p = head, *p1 ;
235   while(p) {
236     p1 = p->next ;
237     switch(type) {
238     case LL_STR: free_2(p->u.str) ; break ;
239     case LL_VOID_P:
240       if (f)
241 	f(p->u.p) ;
242       break ;
243     default:
244       fprintf(stderr, "Internal error in llist_free(), type: %d\n", type);
245       exit(255);
246     }
247     free_2(p) ;
248     p = p1 ;
249   }
250 }
251 /* ===================================================== */
252 /* Create a Trptr structure that contains the bit-vector VEC
253 * This is based on the function AddVector()
254  */
BitVector_to_Trptr(bvptr vec)255 Trptr BitVector_to_Trptr(bvptr vec) {
256   Trptr  t;
257   int    n;
258 
259   GLOBALS->signalwindow_width_dirty=1;
260 
261   n = vec->nbits;
262   t = (Trptr) calloc_2(1, sizeof( TraceEnt ) );
263   if( t == NULL ) {
264     fprintf( stderr, "Out of memory, can't add %s to analyzer\n",
265 	     vec->bvname );
266     return( 0 );
267   }
268 
269   t->name = vec->bvname;
270 
271   if(GLOBALS->hier_max_level)
272     t->name = hier_extract(t->name, GLOBALS->hier_max_level);
273 
274   t->flags = ( n > 3 ) ? TR_HEX|TR_RJUSTIFY : TR_BIN|TR_RJUSTIFY;
275   t->vector = TRUE;
276   t->n.vec = vec;
277   /* AddTrace( t ); */
278   return( t );
279 }
280 
find_first_highlighted_trace(void)281 Trptr find_first_highlighted_trace(void) {
282   Trptr t=GLOBALS->traces.first;
283   while(t) {
284     if(t->flags&TR_HIGHLIGHT) {
285       if(!(t->flags&(TR_BLANK|TR_ANALOG_BLANK_STRETCH))) {
286 	break;
287       }
288     }
289     t=t->t_next;
290   }
291   return(t);
292 }
293 
294 /* Find is signal named NAME is on display and return is Trptr value
295 * or NULL
296 * NAME is a full hierarchical name, but may not in include range '[..:..]'
297 *  information.
298  */
is_signal_displayed(char * name)299 Trptr is_signal_displayed(char *name) {
300   Trptr t=GLOBALS->traces.first ;
301   char *p = strchr(name, '['), *p1 ;
302   unsigned int len, len1 ;
303   if(p)
304     *p = '\0' ;
305   len = strlen(name) ;
306   while(t) {
307     int was_packed = HIER_DEPACK_ALLOC;
308     int cc;
309     if(t->vector)
310 	{
311 	p = t->n.vec->bvname;
312 	}
313 	else
314 	{
315 	if(t->n.vec)
316 		{
317 		p = hier_decompress_flagged(t->n.nd->nname, &was_packed);
318 		}
319 		else
320 		{
321 		p = NULL;
322 		}
323 	}
324 
325     if(p) {
326       p1 = strchr(p,'[') ;
327       len1 = (p1) ? (unsigned int)(p1 - p) : strlen(p) ;
328       cc = ((len == len1) && !strncmp(name, p, len));
329       if(was_packed) free_2(p);
330       if(cc)
331 	break ;
332     }
333     t = t->t_next ;
334   }
335   return t ;
336 }
337 
338 /* Create a Trptr structure for ND and return its value
339 * This is based on the function AddNodeTraceReturn()
340 */
Node_to_Trptr(nptr nd)341 Trptr Node_to_Trptr(nptr nd)
342 {
343   Trptr  t = NULL;
344   hptr histpnt;
345   hptr *harray;
346   int histcount;
347   int i;
348 
349   if(nd->mv.mvlfac) import_trace(nd);
350 
351   GLOBALS->signalwindow_width_dirty=1;
352 
353   if( (t = (Trptr) calloc_2( 1, sizeof( TraceEnt ))) == NULL ) {
354     fprintf( stderr, "Out of memory, can't add to analyzer\n" );
355     return( 0 );
356   }
357 
358   if(!nd->harray) { /* make quick array lookup for aet display */
359     histpnt=&(nd->head);
360     histcount=0;
361 
362     while(histpnt) {
363       histcount++;
364       histpnt=histpnt->next;
365     }
366 
367     nd->numhist=histcount;
368 
369     if(!(nd->harray=harray=(hptr *)malloc_2(histcount*sizeof(hptr)))) {
370       fprintf( stderr, "Out of memory, can't add to analyzer\n" );
371       free_2(t);
372       return(0);
373     }
374 
375     histpnt=&(nd->head);
376     for(i=0;i<histcount;i++) {
377       *harray=histpnt;
378       harray++;
379       histpnt=histpnt->next;
380     }
381   }
382 
383   if(!GLOBALS->hier_max_level) {
384     int flagged = HIER_DEPACK_ALLOC;
385 
386     t->name = hier_decompress_flagged(nd->nname, &flagged);
387     t->is_depacked = (flagged != 0);
388   }
389   else {
390     int flagged = HIER_DEPACK_ALLOC;
391     char *tbuff = hier_decompress_flagged(nd->nname, &flagged);
392     if(!flagged) {
393       t->name = hier_extract(nd->nname, GLOBALS->hier_max_level);
394     }
395     else {
396       t->name = strdup_2(hier_extract(tbuff, GLOBALS->hier_max_level));
397       free_2(tbuff);
398       t->is_depacked = 1;
399     }
400   }
401 
402   if(nd->extvals) { /* expansion vectors */
403     int n;
404 
405     n = nd->msi - nd->lsi;
406     if(n<0)n=-n;
407     n++;
408 
409     t->flags = (( n > 3 )||( n < -3 )) ? TR_HEX|TR_RJUSTIFY :
410       TR_BIN|TR_RJUSTIFY;
411   }
412   else {
413     t->flags |= TR_BIN;	/* binary */
414   }
415   t->vector = FALSE;
416   t->n.nd = nd;
417   /* if(tret) *tret = t;		... for expand */
418   return t ;
419 }
420 /*
421 * Search for the signal named (full path) NAME in the signal data base and
422 * create a Trptr structure for it
423 * NAME is a full hierarchy name, but may not include range information.
424 * Return the structure created or NULL
425 */
sig_name_to_Trptr(char * name)426 Trptr sig_name_to_Trptr(char *name) {
427   Trptr t = NULL ;
428   int was_packed = HIER_DEPACK_ALLOC;
429   int i, name_len;
430   char *hfacname = NULL;
431   struct symbol *s = NULL, *s2 ;
432   int len = 0 ;
433   bvptr v = NULL;
434   bptr b = NULL;
435   int pre_import = 0;
436 
437   if(name)
438 	{
439 	name_len = strlen(name);
440 	for(i=0;i<GLOBALS->numfacs;i++)
441 		{
442 		hfacname = hier_decompress_flagged(GLOBALS->facs[i]->name,  &was_packed);
443 		if(!strcmp(name, hfacname) || ((!strncmp(name, hfacname, name_len) && hfacname[name_len] == '[')))
444 			{
445 			s = GLOBALS->facs[i];
446 			if((s2 = s->vec_root))
447 				{
448 				s = s2;
449 				}
450 				else
451 				{
452 				s2 = s;
453 				}
454 
455 			if(GLOBALS->is_lx2)
456 				{
457 				while(s2)
458 					{
459 	                                if(s2->n->mv.mvlfac)	/* the node doesn't exist yet! */
460 	                                        {
461 	                                        lx2_set_fac_process_mask(s2->n);
462 	                                        pre_import++;
463 	                                        }
464 
465 					s2 = s2->vec_chain;
466 					len++;
467 					}
468 				}
469 				else
470 				{
471 				while(s2)
472 					{
473 					s2 = s2->vec_chain;
474 					len++;
475 					}
476 				}
477 
478 			if(was_packed) { free_2(hfacname); }
479 			break;
480 			}
481 		if(was_packed) { free_2(hfacname); }
482 		s = NULL;
483 		}
484 
485 	if(s)
486 		{
487 	        if(pre_import)
488         	        {
489         	        lx2_import_masked();		/* import any missing nodes */
490         	        }
491 
492 		if(len > 1)
493 			{
494 			if ((b = makevec_chain(NULL, s, len)))
495 				{
496 				if((v=bits2vector(b)))
497 					{
498 					t = BitVector_to_Trptr(v) ;
499 					}
500 			                else
501 			                {
502 			                free_2(b->name);
503 			                if(b->attribs) free_2(b->attribs);
504 			                free_2(b);
505 			                }
506 				}
507 			}
508 			else
509 			{
510 			nptr node = s->n ;
511 			t = Node_to_Trptr(node) ;
512 			}
513 		}
514 
515 	}
516 
517   return t ;
518 }
519 
520 /* Return the base prefix for the signal value */
signal_value_prefix(TraceFlagsType flags)521 char *signal_value_prefix(TraceFlagsType flags) {
522   if(flags & TR_BIN) return "0b" ;
523   if(flags & TR_HEX) return "0x" ;
524   if(flags & TR_OCT) return "0" ;
525   return "" ;
526 }
527 
528 /* ===================================================== */
529 
signal_change_list(char * sig_name,int dir,TimeType start_time,TimeType end_time,int max_elements)530 llist_p *signal_change_list(char *sig_name, int dir, TimeType start_time,
531 		       TimeType end_time, int max_elements) {
532   llist_p *l0_head = NULL, *l0_tail = NULL, *l1_head = NULL,*l_elem, *lp ;
533   llist_p *l1_tail = NULL ;
534   char *s, s1[1024] ;
535   hptr h_ptr ;
536   Trptr t = NULL ;
537   Trptr t_created = NULL;
538   if(!sig_name) {
539     t = (Trptr)find_first_highlighted_trace();
540   } else {
541     /* case of sig name, find the representing Trptr structure */
542     if (!(t = is_signal_displayed(sig_name)))
543       t = t_created = sig_name_to_Trptr(sig_name) ;
544   }
545   if (t) {			/* we have a signal */
546     /* create a list of value change structs (hptrs or vptrs */
547     int nelem = 0 /* , bw = -1 */ ; /* scan-build */
548     TimeType tstart = (dir == STRACE_FORWARD) ? start_time : end_time ;
549     TimeType tend = (dir == STRACE_FORWARD) ? end_time : start_time ;
550     if ((dir == STRACE_BACKWARD) && (max_elements == 1))
551 	{
552 	max_elements++;
553 	}
554     if (!t->vector) {
555       hptr h, h1;
556       int len = 0  ;
557       /* scan-build :
558       if(t->n.nd->extvals) {
559 	bw = abs(t->n.nd->msi - t->n.nd->lsi) + 1 ;
560       }
561       */
562       h = bsearch_node(t->n.nd, tstart - t->shift) ;
563       for(h1 = h; h1; h1 = h1->next) {
564 	if (h1->time <= tend) {
565 	  if (len++ < max_elements) {
566 	    llist_u llp; llp.p = h1;
567 	    l_elem = llist_new(llp, LL_VOID_P, -1) ;
568 	    l0_head = llist_append(l0_head, l_elem, &l0_tail) ;
569 	    if(!l0_tail) l0_tail = l0_head ;
570 	  } else {
571 	    if(dir == STRACE_FORWARD)
572 	      break ;
573 	    else {
574 	      if(!l0_head) /* null pointer deref found by scan-build */
575 			{
576 		        llist_u llp; llp.p = h1;
577 		        l_elem = llist_new(llp, LL_VOID_P, -1) ;
578 		        l0_head = llist_append(l0_head, l_elem, &l0_tail) ;
579 		        if(!l0_tail) l0_tail = l0_head ;
580 			}
581 	      l_elem = l0_head ;
582 	      l0_head = l0_head->next ; /* what scan-build flagged as null */
583 	      l0_head->prev = NULL ;
584 	      l_elem->u.p = (void *)h1 ;
585 	      l_elem->next = NULL ;
586 	      l_elem->prev = l0_tail ;
587 	      l0_tail->next = l_elem ;
588 	      l0_tail = l_elem ;
589 	    }
590 	  }
591 	}
592       }
593     } else {
594       vptr v, v1;
595       v = bsearch_vector(t->n.vec, tstart - t->shift) ;
596       for(v1 = v; v1; v1 = v1->next) {
597 	if (v1->time <= tend) {
598 	  llist_u llp; llp.p = v1;
599 	  l_elem = llist_new(llp, LL_VOID_P, -1) ;
600 	  l0_head = llist_append(l0_head, l_elem, &l0_tail) ;
601 	  if(!l0_tail) l0_tail = l0_head ;
602 	}
603       }
604     }
605     lp = (start_time < end_time) ? l0_head : l0_tail ;
606     /* now create a linked list of time,value.. */
607     while (lp && (nelem++ < max_elements)) {
608       llist_u llp; llp.tt = ((t->vector) ? ((vptr)lp->u.p)->time: ((hptr)lp->u.p)->time);
609       l_elem = llist_new(llp, LL_TIMETYPE, -1) ;
610       l1_head = llist_append(l1_head, l_elem, &l1_tail) ;
611       if(!l1_tail) l1_tail = l1_head ;
612       if(t->vector == 0) {
613 	if(!t->n.nd->extvals) {	/* really single bit */
614 	  switch(((hptr)lp->u.p)->v.h_val) {
615 	  case '0':
616 	  case AN_0: llp.str = "0"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
617 
618 	  case '1':
619 	  case AN_1: llp.str = "1"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
620 
621 	  case 'x':
622 	  case 'X':
623 	  case AN_X: llp.str = "x"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
624 
625 	  case 'z':
626 	  case 'Z':
627 	  case AN_Z: llp.str = "z"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
628 
629 	  case 'h':
630 	  case 'H':
631 	  case AN_H: llp.str = "h"; l_elem = llist_new(llp, LL_STR, -1) ; break ; /* added for GHW... */
632 
633 	  case 'u':
634 	  case 'U':
635 	  case AN_U: llp.str = "u"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
636 
637 	  case 'w':
638 	  case 'W':
639 	  case AN_W: llp.str = "w"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
640 
641 	  case 'l':
642 	  case 'L':
643 	  case AN_L: llp.str = "l"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
644 
645 	  case '-':
646 	  case AN_DASH: llp.str = "-"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
647 
648 	  default:      llp.str = "?"; l_elem = llist_new(llp, LL_STR, -1) ; break ; /* ...added for GHW */
649 	  }
650 	} else {		/* this is still an array */
651 	  h_ptr = (hptr)lp->u.p ;
652 	  if(h_ptr->flags&HIST_REAL) {
653 	    if(!(h_ptr->flags&HIST_STRING)) {
654 #ifdef WAVE_HAS_H_DOUBLE
655 	      s=convert_ascii_real(t, &h_ptr->v.h_double);
656 #else
657 	      s=convert_ascii_real(t, (double *)h_ptr->v.h_vector);
658 #endif
659 	    } else {
660 	      s=convert_ascii_string((char *)h_ptr->v.h_vector);
661 	    }
662 	  } else {
663 	    s=convert_ascii_vec(t,h_ptr->v.h_vector);
664 	  }
665 	  if(s) {
666 	    sprintf(s1,"%s%s", signal_value_prefix(t->flags), s) ;
667 	    llp.str = s1;
668 	    l_elem = llist_new(llp, LL_STR, -1) ;
669 	  } else {
670 	    l1_head = llist_remove_last(l1_head, &l1_tail, LL_INT, NULL) ;
671 	  }
672 	}
673       } else {
674         sprintf(s1, "%s%s", signal_value_prefix(t->flags),
675 		convert_ascii(t, (vptr)lp->u.p)) ;
676         llp.str = s1 ;
677 	l_elem = llist_new(llp, LL_STR, -1) ;
678       }
679       l1_head = llist_append(l1_head, l_elem, &l1_tail) ;
680       lp = (start_time < end_time) ? lp->next : lp->prev ;
681     }
682     llist_free(l0_head, LL_VOID_P, NULL) ;
683   }
684 
685   if(t_created)
686 	{
687 	FreeTrace(t_created);
688 	}
689 
690   return l1_head ;
691 }
692