| // 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; |
| } |
| |
| // Does s have t as a path prefix? |
| // That is, does s == t or does s begin with t followed by a slash? |
| // For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true. |
| // Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true. |
| static int |
| haspathprefix(char *s, char *t) |
| { |
| int i, cs, ct; |
| |
| if(t == nil) |
| return 0; |
| for(i=0; t[i]; i++) { |
| cs = s[i]; |
| ct = t[i]; |
| if('A' <= cs && cs <= 'Z') |
| cs += 'a' - 'A'; |
| if('A' <= ct && ct <= 'Z') |
| ct += 'a' - 'A'; |
| if(cs == '\\') |
| cs = '/'; |
| if(ct == '\\') |
| ct = '/'; |
| if(cs != ct) |
| return 0; |
| } |
| return s[i] == '\0' || s[i] == '/' || s[i] == '\\'; |
| } |
| |
| // 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], buf1[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] == ':') || file[0] == '<') |
| snprint(buf, sizeof buf, "%s", file); |
| else |
| snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file); |
| |
| // Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL. |
| if(haspathprefix(buf, ctxt->trimpath)) { |
| if(strlen(buf) == strlen(ctxt->trimpath)) |
| strcpy(buf, "??"); |
| else { |
| snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1); |
| if(buf1[0] == '\0') |
| strcpy(buf1, "??"); |
| strcpy(buf, buf1); |
| } |
| } else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) { |
| snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot)); |
| strcpy(buf, buf1); |
| } |
| |
| 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; |
| } |