| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| #include <u.h> | |
| #include <libc.h> | |
| #include <bio.h> | |
| #include <link.h> | |
| enum | |
| { | |
| HISTSZ = 10, | |
| NSYM = 50, | |
| }; | |
| int | |
| linklinefmt(Link *ctxt, Fmt *fp) | |
| { | |
| struct | |
| { | |
| Hist* incl; /* start of this include file */ | |
| int32 idel; /* delta line number to apply to include */ | |
| Hist* line; /* start of this #line directive */ | |
| int32 ldel; /* delta line number to apply to #line */ | |
| } a[HISTSZ]; | |
| int32 lno, d; | |
| int i, n; | |
| Hist *h; | |
| lno = va_arg(fp->args, int32); | |
| n = 0; | |
| for(h=ctxt->hist; h!=nil; h=h->link) { | |
| if(h->offset < 0) | |
| continue; | |
| if(lno < h->line) | |
| break; | |
| if(h->name) { | |
| if(h->offset > 0) { | |
| // #line directive | |
| if(n > 0 && n < HISTSZ) { | |
| a[n-1].line = h; | |
| a[n-1].ldel = h->line - h->offset + 1; | |
| } | |
| } else { | |
| // beginning of file | |
| if(n < HISTSZ) { | |
| a[n].incl = h; | |
| a[n].idel = h->line; | |
| a[n].line = 0; | |
| } | |
| n++; | |
| } | |
| continue; | |
| } | |
| n--; | |
| if(n > 0 && n < HISTSZ) { | |
| d = h->line - a[n].incl->line; | |
| a[n-1].ldel += d; | |
| a[n-1].idel += d; | |
| } | |
| } | |
| if(n > HISTSZ) | |
| n = HISTSZ; | |
| for(i=n-1; i>=0; i--) { | |
| if(i != n-1) { | |
| if(fp->flags & ~(FmtWidth|FmtPrec)) | |
| break; | |
| fmtprint(fp, " "); | |
| } | |
| if(ctxt->debugline || (fp->flags&FmtLong)) | |
| fmtprint(fp, "%s/", ctxt->pathname); | |
| if(a[i].line) | |
| fmtprint(fp, "%s:%d[%s:%d]", | |
| a[i].line->name, lno-a[i].ldel+1, | |
| a[i].incl->name, lno-a[i].idel+1); | |
| else | |
| fmtprint(fp, "%s:%d", | |
| a[i].incl->name, lno-a[i].idel+1); | |
| lno = a[i].incl->line - 1; // now print out start of this file | |
| } | |
| if(n == 0) | |
| fmtprint(fp, "<unknown line number>"); | |
| return 0; | |
| } | |
| // This is a simplified copy of linklinefmt above. | |
| // It doesn't allow printing the full stack, and it returns the file name and line number separately. | |
| // TODO: Unify with linklinefmt somehow. | |
| void | |
| linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l) | |
| { | |
| struct | |
| { | |
| Hist* incl; /* start of this include file */ | |
| int32 idel; /* delta line number to apply to include */ | |
| Hist* line; /* start of this #line directive */ | |
| int32 ldel; /* delta line number to apply to #line */ | |
| } a[HISTSZ]; | |
| int32 lno, d, dlno; | |
| int n; | |
| Hist *h; | |
| char buf[1024], *file; | |
| lno = line; | |
| n = 0; | |
| for(h=ctxt->hist; h!=nil; h=h->link) { | |
| if(h->offset < 0) | |
| continue; | |
| if(lno < h->line) | |
| break; | |
| if(h->name) { | |
| if(h->offset > 0) { | |
| // #line directive | |
| if(n > 0 && n < HISTSZ) { | |
| a[n-1].line = h; | |
| a[n-1].ldel = h->line - h->offset + 1; | |
| } | |
| } else { | |
| // beginning of file | |
| if(n < HISTSZ) { | |
| a[n].incl = h; | |
| a[n].idel = h->line; | |
| a[n].line = 0; | |
| } | |
| n++; | |
| } | |
| continue; | |
| } | |
| n--; | |
| if(n > 0 && n < HISTSZ) { | |
| d = h->line - a[n].incl->line; | |
| a[n-1].ldel += d; | |
| a[n-1].idel += d; | |
| } | |
| } | |
| if(n > HISTSZ) | |
| n = HISTSZ; | |
| if(n <= 0) { | |
| *f = linklookup(ctxt, "??", HistVersion); | |
| *l = 0; | |
| return; | |
| } | |
| n--; | |
| if(a[n].line) { | |
| file = a[n].line->name; | |
| dlno = a[n].ldel-1; | |
| } else { | |
| file = a[n].incl->name; | |
| dlno = a[n].idel-1; | |
| } | |
| if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':')) | |
| snprint(buf, sizeof buf, "%s", file); | |
| else | |
| snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file); | |
| lno -= dlno; | |
| *f = linklookup(ctxt, buf, HistVersion); | |
| *l = lno; | |
| } | |
| void | |
| linklinehist(Link *ctxt, int lineno, char *f, int offset) | |
| { | |
| Hist *h; | |
| if(0) // debug['f'] | |
| if(f) { | |
| if(offset) | |
| print("%4d: %s (#line %d)\n", lineno, f, offset); | |
| else | |
| print("%4d: %s\n", lineno, f); | |
| } else | |
| print("%4d: <pop>\n", lineno); | |
| h = malloc(sizeof(Hist)); | |
| memset(h, 0, sizeof *h); | |
| h->name = f; | |
| h->line = lineno; | |
| h->offset = offset; | |
| h->link = nil; | |
| if(ctxt->ehist == nil) { | |
| ctxt->hist = h; | |
| ctxt->ehist = h; | |
| return; | |
| } | |
| ctxt->ehist->link = h; | |
| ctxt->ehist = h; | |
| } | |
| void | |
| linkprfile(Link *ctxt, int32 l) | |
| { | |
| int i, n; | |
| Hist a[HISTSZ], *h; | |
| int32 d; | |
| n = 0; | |
| for(h = ctxt->hist; h != nil; h = h->link) { | |
| if(l < h->line) | |
| break; | |
| if(h->name) { | |
| if(h->offset == 0) { | |
| if(n >= 0 && n < HISTSZ) | |
| a[n] = *h; | |
| n++; | |
| continue; | |
| } | |
| if(n > 0 && n < HISTSZ) | |
| if(a[n-1].offset == 0) { | |
| a[n] = *h; | |
| n++; | |
| } else | |
| a[n-1] = *h; | |
| continue; | |
| } | |
| n--; | |
| if(n >= 0 && n < HISTSZ) { | |
| d = h->line - a[n].line; | |
| for(i=0; i<n; i++) | |
| a[i].line += d; | |
| } | |
| } | |
| if(n > HISTSZ) | |
| n = HISTSZ; | |
| for(i=0; i<n; i++) | |
| print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1)); | |
| } | |
| /* | |
| * start a new Prog list. | |
| */ | |
| Plist* | |
| linknewplist(Link *ctxt) | |
| { | |
| Plist *pl; | |
| pl = malloc(sizeof(*pl)); | |
| memset(pl, 0, sizeof *pl); | |
| if(ctxt->plist == nil) | |
| ctxt->plist = pl; | |
| else | |
| ctxt->plast->link = pl; | |
| ctxt->plast = pl; | |
| return pl; | |
| } |