in favor of using in-memory copy of symbol table.
$ ls -l pretty pretty.big
-rwxr-xr-x 1 rsc eng 439516 Nov 21 16:43 pretty
-rwxr-xr-x 1 rsc eng 580984 Nov 21 16:20 pretty.big
$
R=r
DELTA=446 (238 added, 178 deleted, 30 changed)
OCL=19851
CL=19884
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
-#define SOFmark "\xa7\xf1\xd9\x2a\x82\xc8\xd8\xfe"
/*
* amd64
doprof1();
else
doprof2();
- addstackmark();
span();
doinit();
asmb();
return p;
}
-void
-markstk(Prog *l)
-{
- Prog *p0, *p, *q, *r;
- int32 i, n, line;
- Sym *s;
-
- version++;
- s = lookup(l->from.sym->name, version);
- s->type = STEXT;
- line = l->line;
-
- // start with fake copy of ATEXT
- p0 = prg();
- p = p0;
- *p = *l; // note this gets p->pcond and p->line
-
- p->from.type = D_STATIC;
- p->from.sym = s;
- p->to.offset = 0;
-
- // put out magic sequence
- n = strlen(SOFmark);
- for(i=0; i<n; i++) {
- q = byteq(SOFmark[i]);
- q->line = line;
- p->link = q;
- p = q;
- }
-
- // put out stack offset
- n = l->to.offset;
- if(n < 0)
- n = 0;
- for(i=0; i<3; i++) {
- q = byteq(n);
- q->line = line;
- p->link = q;
- p = q;
- n = n>>8;
- }
-
- // put out null terminated name
- for(i=0;; i++) {
- n = s->name[i];
- q = byteq(n);
- q->line = line;
- p->link = q;
- p = q;
- if(n == 0)
- break;
- }
-
- // put out return instruction
- q = prg();
- q->as = ARET;
- q->line = line;
- p->link = q;
- p = q;
-
- r = l->pcond;
- l->pcond = p0;
- p->link = r;
- p0->pcond = r;
-
- // hard part is linking end of
- // the text body to my fake ATEXT
- for(p=l;; p=q) {
- q = p->link;
- if(q == r) {
- p->link = p0;
- return;
- }
- }
-}
-
-void
-addstackmark(void)
-{
- Prog *p;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f stkmark\n", cputime());
- Bflush(&bso);
-
- for(p=textp; p!=P; p=p->pcond) {
- markstk(p); // splice in new body
- p = p->pcond; // skip the one we just put in
- }
-
-// for(p=textp; p!=P; p=p->pcond)
-// print("%P\n", p);
-}
-
int
relinv(int a)
{
rune.$O\
proc.$O\
string.$O\
+ symtab.$O\
sys_file.$O\
OFILES=$(RT0OFILES) $(LIBOFILES)
runtime.acid: runtime.h proc.c
$(CC) -a proc.c >runtime.acid
+
void
sys·reflect(Map *im, void *it, uint64 retit, string rettype)
{
- string s;
- int32 n;
- byte *type;
-
if(im == nil) {
retit = 0;
rettype = nil;
} else {
retit = (uint64)it;
- type = im->sigt->name;
- n = findnull((int8*)type);
- s = mal(sizeof *s + n + 1);
- s->len = n;
- mcpy(s->str, type, n);
- rettype = s;
+ rettype = gostring(im->sigt->name);
}
FLUSH(&retit);
FLUSH(&rettype);
void
prints(int8 *s)
{
- sys·write(1, s, findnull(s));
+ sys·write(1, s, findnull((byte*)s));
}
void
extern int32 debug;
-static int8 spmark[] = "\xa7\xf1\xd9\x2a\x82\xc8\xd8\xfe";
-
extern uint8 end;
void
uint8* callpc;
int32 counter;
int32 i;
- int8* name;
+ string name;
+ Func *f;
G g;
Stktop *stktop;
}
counter = 0;
- name = "panic";
+ name = gostring((byte*)"panic");
for(;;){
callpc = pc;
if((uint8*)retfromnewstack == pc) {
sp += 16; // two irrelevant calls on stack - morestack, plus the call morestack made
continue;
}
- /* find SP offset by stepping back through instructions to SP offset marker */
- while(pc > (uint8*)0x1000+sizeof spmark-1) {
- if(pc >= &end)
- return;
- for(spp = spmark; *spp != '\0' && *pc++ == (uint8)*spp++; )
- ;
- if(*spp == '\0'){
- spoff = *pc++;
- spoff += *pc++ << 8;
- spoff += *pc++ << 16;
- name = (int8*)pc;
- sp += spoff + 8;
- break;
- }
- }
+ f = findfunc((uint64)callpc);
+ if(f == nil)
+ return;
+ name = f->name;
+ sp += f->frame;
if(counter++ > 100){
prints("stack trace terminated\n");
break;
sys·printpointer(callpc - 1); // -1 to get to CALL instr.
prints("?zi\n");
prints("\t");
- prints(name);
+ sys·printstring(name);
prints("(");
for(i = 0; i < 3; i++){
if(i != 0)
}
prints(", ...)\n");
prints("\t");
- prints(name);
+ sys·printstring(name);
prints("(");
for(i = 0; i < 3; i++){
if(i != 0)
}
}
+byte*
+mchr(byte *p, byte c, byte *ep)
+{
+ for(; p < ep; p++)
+ if(*p == c)
+ return p;
+ return nil;
+}
+
uint32
rnd(uint32 n, uint32 m)
{
byte *v, *bs;
bs = (byte*)s;
- len = findnull(s);
+ len = findnull(bs);
for(i=0; i<envc; i++){
v = envv[i];
for(j=0; j<len; j++)
void
sys·argv(int32 i, string s)
{
- uint8* str;
- int32 l;
-
- if(i < 0 || i >= argc) {
+ if(i >= 0 && i < argc)
+ s = gostring(argv[i]);
+ else
s = emptystring;
- goto out;
- }
-
- str = argv[i];
- l = findnull((int8*)str);
- s = mal(sizeof(s->len)+l);
- s->len = l;
- mcpy(s->str, str, l);
-
-out:
FLUSH(&s);
}
void
sys·envv(int32 i, string s)
{
- uint8* str;
- int32 l;
-
- if(i < 0 || i >= envc) {
+ if(i >= 0 && i < envc)
+ s = gostring(envv[i]);
+ else
s = emptystring;
- goto out;
- }
-
- str = envv[i];
- l = findnull((int8*)str);
- s = mal(sizeof(s->len)+l);
- s->len = l;
- mcpy(s->str, str, l);
-
-out:
FLUSH(&s);
}
{ memhash, memequal, memprint, memcopy }, // 2 - treat pointers as ints
};
-
-// Return a pointer to a byte array containing the symbol table segment.
-//
-// NOTE(rsc): I expect that we will clean up both the method of getting
-// at the symbol table and the exact format of the symbol table at some
-// point in the future. It probably needs to be better integrated with
-// the type strings table too. This is just a quick way to get started
-// and figure out what we want from/can do with it.
-void
-sys·symdat(Array *symtab, Array *pclntab)
-{
- Array *a;
- int32 *v;
-
- v = (int32*)(0x99LL<<32); /* known to 6l */
-
- a = mal(sizeof *a);
- a->nel = v[0];
- a->cap = a->nel;
- a->array = (byte*)&v[2];
- symtab = a;
- FLUSH(&symtab);
-
- a = mal(sizeof *a);
- a->nel = v[1];
- a->cap = a->nel;
- a->array = (byte*)&v[2] + v[0];
- pclntab = a;
- FLUSH(&pclntab);
-}
/*
* get rid of C types
+ * the / / / forces a syntax error immediately,
+ * which will show "last name: XXunsigned".
*/
-#define unsigned XXunsigned
-#define signed XXsigned
-#define char XXchar
-#define short XXshort
-#define int XXint
-#define long XXlong
-#define float XXfloat
-#define double XXdouble
+#define unsigned XXunsigned / / /
+#define signed XXsigned / / /
+#define char XXchar / / /
+#define short XXshort / / /
+#define int XXint / / /
+#define long XXlong / / /
+#define float XXfloat / / /
+#define double XXdouble / / /
/*
* defined types
*/
typedef uint8 bool;
typedef uint8 byte;
-typedef struct String *string;
+typedef struct Alg Alg;
typedef struct Array Array;
-typedef struct Gobuf Gobuf;
+typedef struct Func Func;
typedef struct G G;
-typedef struct M M;
-typedef struct Stktop Stktop;
-typedef struct Alg Alg;
+typedef struct Gobuf Gobuf;
typedef struct Lock Lock;
-typedef union Note Note;
+typedef struct M M;
typedef struct Mem Mem;
-typedef struct Usema Usema;
+typedef union Note Note;
+typedef struct Stktop Stktop;
+typedef struct String *string;
+typedef struct Usema Usema;
/*
* per cpu declaration
int8 *name;
};
+// (will be) shared with go; edit ../cmd/6g/sys.go too.
+// should move out of sys.go eventually.
+// also eventually, the loaded symbol table should
+// be closer to this form.
+struct Func
+{
+ string name;
+ string type;
+ uint64 entry;
+ int64 frame;
+};
+
/*
* defined macros
* you need super-goru privilege
* common functions and data
*/
int32 strcmp(byte*, byte*);
-int32 findnull(int8*);
+int32 findnull(byte*);
void dump(byte*, int32);
int32 runetochar(byte*, int32);
int32 chartorune(uint32*, byte*);
void throw(int8*);
uint32 rnd(uint32, uint32);
void prints(int8*);
+byte* mchr(byte*, byte, byte*);
void mcpy(byte*, byte*, uint32);
void mmov(byte*, byte*, uint32);
void* mal(uint32);
uint32 cmpstring(string, string);
+string gostring(byte*);
void initsig(void);
int32 gotraceback(void);
void traceback(uint8 *pc, uint8 *sp, G* gp);
void signalstack(byte*, int32);
G* malg(int32);
void minit(void);
+Func* findfunc(uint64);
/*
* mutual exclusion locks. in the uncontended case,
string emptystring = (string)∅
int32
-findnull(int8 *s)
+findnull(byte *s)
{
int32 l;
return l;
}
+string
+gostring(byte *str)
+{
+ int32 l;
+ string s;
+
+ l = findnull(str);
+ s = mal(sizeof(s->len)+l+1);
+ s->len = l;
+ mcpy(s->str, str, l+1);
+ return s;
+}
+
void
sys·catstring(string s1, string s2, string s3)
{
--- /dev/null
+// 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 "runtime.h"
+
+// Runtime symbol table access.
+// Very much a work in progress.
+
+#define SYMCOUNTS ((int32*)(0x99LL<<32)) // known to 6l
+#define SYMDATA ((byte*)(0x99LL<<32) + 8)
+
+// Return a pointer to a byte array containing the symbol table segment.
+//
+// NOTE(rsc): I expect that we will clean up both the method of getting
+// at the symbol table and the exact format of the symbol table at some
+// point in the future. It probably needs to be better integrated with
+// the type strings table too. This is just a quick way to get started
+// and figure out what we want from/can do with it.
+void
+sys·symdat(Array *symtab, Array *pclntab)
+{
+ Array *a;
+ int32 *v;
+
+ v = SYMCOUNTS;
+
+ a = mal(sizeof *a);
+ a->nel = v[0];
+ a->cap = a->nel;
+ a->array = SYMDATA;
+ symtab = a;
+ FLUSH(&symtab);
+
+ a = mal(sizeof *a);
+ a->nel = v[1];
+ a->cap = a->nel;
+ a->array = SYMDATA + v[0];
+ pclntab = a;
+ FLUSH(&pclntab);
+}
+
+typedef struct Sym Sym;
+struct Sym
+{
+ uint64 value;
+ byte symtype;
+ byte *name;
+ byte *gotype;
+};
+
+// Walk over symtab, calling fn(&s) for each symbol.
+void
+walksymtab(void (*fn)(Sym*))
+{
+ int32 *v;
+ byte *p, *ep, *q;
+ Sym s;
+
+ v = SYMCOUNTS;
+ p = SYMDATA;
+ ep = p + v[0];
+ while(p < ep) {
+ if(p + 7 > ep)
+ break;
+ s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
+ if(!(p[4]&0x80))
+ break;
+ s.symtype = p[4] & ~0x80;
+ p += 5;
+ if(s.symtype == 'z' || s.symtype == 'Z') {
+ // path reference string - skip first byte,
+ // then 2-byte pairs ending at two zeros.
+ // for now, just skip over it and ignore it.
+ q = p+1;
+ for(;;) {
+ if(q+2 > ep)
+ return;
+ if(q[0] == '\0' && q[1] == '\0')
+ break;
+ q += 2;
+ }
+ p = q+2;
+ s.name = nil;
+ }else{
+ q = mchr(p, '\0', ep);
+ if(q == nil)
+ break;
+ s.name = p;
+ p = q+1;
+ }
+ q = mchr(p, '\0', ep);
+ if(q == nil)
+ break;
+ s.gotype = p;
+ p = q+1;
+ fn(&s);
+ }
+}
+
+// Symtab walker; accumulates info about functions.
+
+Func *func;
+int32 nfunc;
+
+static void
+dofunc(Sym *sym)
+{
+ static byte *lastfuncname;
+ static Func *lastfunc;
+ Func *f;
+
+ if(lastfunc && sym->symtype == 'm') {
+ lastfunc->frame = sym->value;
+ return;
+ }
+ if(sym->symtype != 'T' && sym->symtype != 't')
+ return;
+ if(strcmp(sym->name, (byte*)"etext") == 0)
+ return;
+ if(func == nil) {
+ nfunc++;
+ return;
+ }
+
+ f = &func[nfunc++];
+ f->name = gostring(sym->name);
+ f->entry = sym->value;
+ lastfunc = f;
+}
+
+static void
+buildfuncs(void)
+{
+ extern byte etext[];
+
+ if(func != nil)
+ return;
+ nfunc = 0;
+ walksymtab(dofunc);
+ func = mal((nfunc+1)*sizeof func[0]);
+ nfunc = 0;
+ walksymtab(dofunc);
+ func[nfunc].entry = (uint64)etext;
+}
+
+Func*
+findfunc(uint64 addr)
+{
+ Func *f;
+ int32 i, nf, n;
+
+ if(func == nil)
+ buildfuncs();
+ if(nfunc == 0)
+ return nil;
+ if(addr < func[0].entry || addr >= func[nfunc].entry)
+ return nil;
+
+ // linear search, for debugging
+ if(0) {
+ for(i=0; i<nfunc; i++) {
+ if(func[i].entry <= addr && addr < func[i+1].entry)
+ return &func[i];
+ }
+ return nil;
+ }
+
+ // binary search to find func with entry <= addr.
+ f = func;
+ nf = nfunc;
+ while(nf > 0) {
+ n = nf/2;
+ if(f[n].entry <= addr && addr < f[n+1].entry)
+ return &f[n];
+ else if(addr < f[n].entry)
+ nf = n;
+ else {
+ f += n+1;
+ nf -= n+1;
+ }
+ }
+
+ // can't get here -- we already checked above
+ // that the address was in the table bounds.
+ // this can only happen if the table isn't sorted
+ // by address or if the binary search above is buggy.
+ prints("findfunc unreachable\n");
+ return nil;
+}