summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/symtab.goc
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/symtab.goc')
-rw-r--r--src/pkg/runtime/symtab.goc332
1 files changed, 332 insertions, 0 deletions
diff --git a/src/pkg/runtime/symtab.goc b/src/pkg/runtime/symtab.goc
new file mode 100644
index 000000000..15e1d28fa
--- /dev/null
+++ b/src/pkg/runtime/symtab.goc
@@ -0,0 +1,332 @@
+// 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.
+
+// Runtime symbol table parsing.
+// See http://golang.org/s/go12symtab for an overview.
+
+package runtime
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "funcdata.h"
+
+typedef struct Ftab Ftab;
+struct Ftab
+{
+ uintptr entry;
+ uintptr funcoff;
+};
+
+extern byte pclntab[];
+
+static Ftab *ftab;
+static uintptr nftab;
+static uint32 *filetab;
+static uint32 nfiletab;
+
+static String end = { (uint8*)"end", 3 };
+
+void
+runtime·symtabinit(void)
+{
+ int32 i, j;
+ Func *f1, *f2;
+
+ // See golang.org/s/go12symtab for header: 0xfffffffb,
+ // two zero bytes, a byte giving the PC quantum,
+ // and a byte giving the pointer width in bytes.
+ if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) {
+ runtime·printf("runtime: function symbol table header: %x %x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
+ runtime·throw("invalid function symbol table\n");
+ }
+
+ nftab = *(uintptr*)(pclntab+8);
+ ftab = (Ftab*)(pclntab+8+sizeof(void*));
+ for(i=0; i<nftab; i++) {
+ // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
+ if(ftab[i].entry > ftab[i+1].entry) {
+ f1 = (Func*)(pclntab + ftab[i].funcoff);
+ f2 = (Func*)(pclntab + ftab[i+1].funcoff);
+ runtime·printf("function symbol table not sorted by program counter: %p %s > %p %s", ftab[i].entry, runtime·funcname(f1), ftab[i+1].entry, i+1 == nftab ? "end" : runtime·funcname(f2));
+ for(j=0; j<=i; j++)
+ runtime·printf("\t%p %s\n", ftab[j].entry, runtime·funcname((Func*)(pclntab + ftab[j].funcoff)));
+ runtime·throw("invalid runtime symbol table");
+ }
+ }
+
+ filetab = (uint32*)(pclntab + *(uint32*)&ftab[nftab].funcoff);
+ nfiletab = filetab[0];
+}
+
+static uint32
+readvarint(byte **pp)
+{
+ byte *p;
+ uint32 v;
+ int32 shift;
+
+ v = 0;
+ p = *pp;
+ for(shift = 0;; shift += 7) {
+ v |= (*p & 0x7F) << shift;
+ if(!(*p++ & 0x80))
+ break;
+ }
+ *pp = p;
+ return v;
+}
+
+void*
+runtime·funcdata(Func *f, int32 i)
+{
+ byte *p;
+
+ if(i < 0 || i >= f->nfuncdata)
+ return nil;
+ p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
+ if(sizeof(void*) == 8 && ((uintptr)p & 4)) {
+ if(((uintptr)f & 4))
+ runtime·printf("misaligned func %p\n", f);
+ p += 4;
+ }
+ return ((void**)p)[i];
+}
+
+static bool
+step(byte **pp, uintptr *pc, int32 *value, bool first)
+{
+ uint32 uvdelta, pcdelta;
+ int32 vdelta;
+
+ uvdelta = readvarint(pp);
+ if(uvdelta == 0 && !first)
+ return 0;
+ if(uvdelta&1)
+ uvdelta = ~(uvdelta>>1);
+ else
+ uvdelta >>= 1;
+ vdelta = (int32)uvdelta;
+ pcdelta = readvarint(pp) * PCQuantum;
+ *value += vdelta;
+ *pc += pcdelta;
+ return 1;
+}
+
+// Return associated data value for targetpc in func f.
+// (Source file is f->src.)
+static int32
+pcvalue(Func *f, int32 off, uintptr targetpc, bool strict)
+{
+ byte *p;
+ uintptr pc;
+ int32 value;
+
+ enum {
+ debug = 0
+ };
+
+ // The table is a delta-encoded sequence of (value, pc) pairs.
+ // Each pair states the given value is in effect up to pc.
+ // The value deltas are signed, zig-zag encoded.
+ // The pc deltas are unsigned.
+ // The starting value is -1, the starting pc is the function entry.
+ // The table ends at a value delta of 0 except in the first pair.
+ if(off == 0)
+ return -1;
+ p = pclntab + off;
+ pc = f->entry;
+ value = -1;
+
+ if(debug && !runtime·panicking)
+ runtime·printf("pcvalue start f=%s [%p] pc=%p targetpc=%p value=%d tab=%p\n",
+ runtime·funcname(f), f, pc, targetpc, value, p);
+
+ while(step(&p, &pc, &value, pc == f->entry)) {
+ if(debug)
+ runtime·printf("\tvalue=%d until pc=%p\n", value, pc);
+ if(targetpc < pc)
+ return value;
+ }
+
+ // If there was a table, it should have covered all program counters.
+ // If not, something is wrong.
+ if(runtime·panicking || !strict)
+ return -1;
+ runtime·printf("runtime: invalid pc-encoded table f=%s pc=%p targetpc=%p tab=%p\n",
+ runtime·funcname(f), pc, targetpc, p);
+ p = (byte*)f + off;
+ pc = f->entry;
+ value = -1;
+
+ while(step(&p, &pc, &value, pc == f->entry))
+ runtime·printf("\tvalue=%d until pc=%p\n", value, pc);
+
+ runtime·throw("invalid runtime symbol table");
+ return -1;
+}
+
+static String unknown = { (uint8*)"?", 1 };
+
+int8*
+runtime·funcname(Func *f)
+{
+ if(f == nil || f->nameoff == 0)
+ return nil;
+ return (int8*)(pclntab + f->nameoff);
+}
+
+static int32
+funcline(Func *f, uintptr targetpc, String *file, bool strict)
+{
+ int32 line;
+ int32 fileno;
+
+ *file = unknown;
+ fileno = pcvalue(f, f->pcfile, targetpc, strict);
+ line = pcvalue(f, f->pcln, targetpc, strict);
+ if(fileno == -1 || line == -1 || fileno >= nfiletab) {
+ // runtime·printf("looking for %p in %S got file=%d line=%d\n", targetpc, *f->name, fileno, line);
+ return 0;
+ }
+ *file = runtime·gostringnocopy(pclntab + filetab[fileno]);
+ return line;
+}
+
+int32
+runtime·funcline(Func *f, uintptr targetpc, String *file)
+{
+ return funcline(f, targetpc, file, true);
+}
+
+int32
+runtime·funcspdelta(Func *f, uintptr targetpc)
+{
+ int32 x;
+
+ x = pcvalue(f, f->pcsp, targetpc, true);
+ if(x&(sizeof(void*)-1))
+ runtime·printf("invalid spdelta %d %d\n", f->pcsp, x);
+ return x;
+}
+
+int32
+runtime·pcdatavalue(Func *f, int32 table, uintptr targetpc)
+{
+ if(table < 0 || table >= f->npcdata)
+ return -1;
+ return pcvalue(f, (&f->nfuncdata)[1+table], targetpc, true);
+}
+
+int32
+runtime·funcarglen(Func *f, uintptr targetpc)
+{
+ if(targetpc == f->entry)
+ return 0;
+ return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum);
+}
+
+func funcline_go(f *Func, targetpc uintptr) (retfile String, retline int) {
+ // Pass strict=false here, because anyone can call this function,
+ // and they might just be wrong about targetpc belonging to f.
+ retline = funcline(f, targetpc, &retfile, false);
+}
+
+func funcname_go(f *Func) (ret String) {
+ ret = runtime·gostringnocopy((uint8*)runtime·funcname(f));
+}
+
+func funcentry_go(f *Func) (ret uintptr) {
+ ret = f->entry;
+}
+
+Func*
+runtime·findfunc(uintptr addr)
+{
+ Ftab *f;
+ int32 nf, n;
+
+ if(nftab == 0)
+ return nil;
+ if(addr < ftab[0].entry || addr >= ftab[nftab].entry)
+ return nil;
+
+ // binary search to find func with entry <= addr.
+ f = ftab;
+ nf = nftab;
+ while(nf > 0) {
+ n = nf/2;
+ if(f[n].entry <= addr && addr < f[n+1].entry)
+ return (Func*)(pclntab + f[n].funcoff);
+ 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.
+ runtime·prints("findfunc unreachable\n");
+ return nil;
+}
+
+func FuncForPC(pc uintptr) (ret *Func) {
+ ret = runtime·findfunc(pc);
+}
+
+static bool
+hasprefix(String s, int8 *p)
+{
+ int32 i;
+
+ for(i=0; i<s.len; i++) {
+ if(p[i] == 0)
+ return 1;
+ if(p[i] != s.str[i])
+ return 0;
+ }
+ return p[i] == 0;
+}
+
+static bool
+contains(String s, int8 *p)
+{
+ int32 i;
+
+ if(p[0] == 0)
+ return 1;
+ for(i=0; i<s.len; i++) {
+ if(s.str[i] != p[0])
+ continue;
+ if(hasprefix((String){s.str + i, s.len - i}, p))
+ return 1;
+ }
+ return 0;
+}
+
+bool
+runtime·showframe(Func *f, G *gp)
+{
+ static int32 traceback = -1;
+ String name;
+
+ if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig))
+ return 1;
+ if(traceback < 0)
+ traceback = runtime·gotraceback(nil);
+ name = runtime·gostringnocopy((uint8*)runtime·funcname(f));
+
+ // Special case: always show runtime.panic frame, so that we can
+ // see where a panic started in the middle of a stack trace.
+ // See golang.org/issue/5832.
+ if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
+ return 1;
+
+ return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");
+}