root/src/liblink/obj.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. linklinefmt
  2. haspathprefix
  3. linkgetline
  4. linklinehist
  5. linkprfile
  6. linknewplist

// 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;
}

/* [<][>][^][v][top][bottom][index][help] */