mirror of
https://github.com/golang/go
synced 2024-11-20 10:54:49 -07:00
9b976f5f03
Before we used line 1 of the first source file. This should be clearer. Fixes #4388. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/92250044
297 lines
5.8 KiB
C
297 lines
5.8 KiB
C
// 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;
|
|
}
|