// 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 #include #include #include 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, ""); 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: \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 HISTSZ) n = HISTSZ; for(i=0; iplist == nil) ctxt->plist = pl; else ctxt->plast->link = pl; ctxt->plast = pl; return pl; }