summaryrefslogtreecommitdiff
path: root/src/libmach/sym.c
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2013-03-04 21:27:36 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-03-04 21:27:36 +0100
commit04b08da9af0c450d645ab7389d1467308cfc2db8 (patch)
treedb247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/libmach/sym.c
parent917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff)
downloadgolang-upstream/1.1_hg20130304.tar.gz
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/libmach/sym.c')
-rw-r--r--src/libmach/sym.c169
1 files changed, 132 insertions, 37 deletions
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
index 1512d7a4f..120328d09 100644
--- a/src/libmach/sym.c
+++ b/src/libmach/sym.c
@@ -1,11 +1,11 @@
// Inferno libmach/sym.c
// http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -112,13 +112,19 @@ syminit(int fd, Fhdr *fp)
int32 i, l, size;
vlong vl;
Biobuf b;
- int svalsz;
+ int svalsz, newformat, shift;
+ uvlong (*swav)(uvlong);
+ uint32 (*swal)(uint32);
+ uchar buf[8], c;
if(fp->symsz == 0)
return 0;
if(fp->type == FNONE)
return 0;
+ swav = beswav;
+ swal = beswal;
+
cleansyms();
textseg(fp->txtaddr, fp);
/* minimum symbol record size = 4+1+2 bytes */
@@ -129,40 +135,128 @@ syminit(int fd, Fhdr *fp)
}
Binit(&b, fd, OREAD);
Bseek(&b, fp->symoff, 0);
+ memset(buf, 0, sizeof buf);
+ Bread(&b, buf, sizeof buf);
+ newformat = 0;
+ if(memcmp(buf, "\xfd\xff\xff\xff\x00\x00\x00", 7) == 0) {
+ swav = leswav;
+ swal = leswal;
+ newformat = 1;
+ } else if(memcmp(buf, "\xff\xff\xff\xfd\x00\x00\x00", 7) == 0) {
+ newformat = 1;
+ } else if(memcmp(buf, "\xfe\xff\xff\xff\x00\x00", 6) == 0) {
+ // Table format used between Go 1.0 and Go 1.1:
+ // little-endian but otherwise same as the old Go 1.0 table.
+ // Not likely to be seen much in practice, but easy to handle.
+ swav = leswav;
+ swal = leswal;
+ Bseek(&b, fp->symoff+6, 0);
+ } else {
+ Bseek(&b, fp->symoff, 0);
+ }
+ svalsz = 0;
+ if(newformat) {
+ svalsz = buf[7];
+ if(svalsz != 4 && svalsz != 8) {
+ werrstr("invalid word size %d bytes", svalsz);
+ return -1;
+ }
+ }
+
nsym = 0;
size = 0;
for(p = symbols; size < fp->symsz; p++, nsym++) {
- if(fp->_magic && (fp->magic & HDR_MAGIC)){
- svalsz = 8;
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->value = beswav(vl);
- }
- else{
- svalsz = 4;
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->value = (u32int)beswal(l);
- }
- if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
- return symerrmsg(sizeof(p->value), "symbol");
-
- i = decodename(&b, p);
- if(i < 0)
- return -1;
- size += i+svalsz+sizeof(p->type);
-
- if(svalsz == 8){
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->gotype = beswav(vl);
- }
- else{
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->gotype = (u32int)beswal(l);
+ if(newformat) {
+ // Go 1.1 format. See comment at top of ../pkg/runtime/symtab.c.
+ if(Bread(&b, &c, 1) != 1)
+ return symerrmsg(1, "symbol");
+ if((c&0x3F) < 26)
+ p->type = (c&0x3F)+ 'A';
+ else
+ p->type = (c&0x3F) - 26 + 'a';
+ size++;
+
+ if(c&0x40) {
+ // Fixed-width address.
+ if(svalsz == 8) {
+ if(Bread(&b, &vl, 8) != 8)
+ return symerrmsg(8, "symbol");
+ p->value = swav(vl);
+ } else {
+ if(Bread(&b, &l, 4) != 4)
+ return symerrmsg(4, "symbol");
+ p->value = (u32int)swal(l);
+ }
+ size += svalsz;
+ } else {
+ // Varint address.
+ shift = 0;
+ p->value = 0;
+ for(;;) {
+ if(Bread(&b, buf, 1) != 1)
+ return symerrmsg(1, "symbol");
+ p->value |= (uint64)(buf[0]&0x7F)<<shift;
+ shift += 7;
+ size++;
+ if((buf[0]&0x80) == 0)
+ break;
+ }
+ }
+ p->gotype = 0;
+ if(c&0x80) {
+ // Has Go type. Fixed-width address.
+ if(svalsz == 8) {
+ if(Bread(&b, &vl, 8) != 8)
+ return symerrmsg(8, "symbol");
+ p->gotype = swav(vl);
+ } else {
+ if(Bread(&b, &l, 4) != 4)
+ return symerrmsg(4, "symbol");
+ p->gotype = (u32int)swal(l);
+ }
+ size += svalsz;
+ }
+
+ // Name.
+ p->type |= 0x80; // for decodename
+ i = decodename(&b, p);
+ if(i < 0)
+ return -1;
+ size += i;
+ } else {
+ // Go 1.0 format: Plan 9 format + go type symbol.
+ if(fp->_magic && (fp->magic & HDR_MAGIC)){
+ svalsz = 8;
+ if(Bread(&b, &vl, 8) != 8)
+ return symerrmsg(8, "symbol");
+ p->value = swav(vl);
+ }
+ else{
+ svalsz = 4;
+ if(Bread(&b, &l, 4) != 4)
+ return symerrmsg(4, "symbol");
+ p->value = (u32int)swal(l);
+ }
+ if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
+ return symerrmsg(sizeof(p->value), "symbol");
+
+ i = decodename(&b, p);
+ if(i < 0)
+ return -1;
+ size += i+svalsz+sizeof(p->type);
+
+ if(svalsz == 8){
+ if(Bread(&b, &vl, 8) != 8)
+ return symerrmsg(8, "symbol");
+ p->gotype = swav(vl);
+ }
+ else{
+ if(Bread(&b, &l, 4) != 4)
+ return symerrmsg(4, "symbol");
+ p->gotype = (u32int)swal(l);
+ }
+ size += svalsz;
}
- size += svalsz;
/* count global & auto vars, text symbols, and file names */
switch (p->type) {
@@ -576,7 +670,8 @@ lookup(char *fn, char *var, Symbol *s)
* strcmp, but allow '_' to match center dot (rune 00b7 == bytes c2 b7)
*/
int
-cdotstrcmp(char *sym, char *user) {
+cdotstrcmp(char *sym, char *user)
+{
for (;;) {
while (*sym == *user) {
if (*sym++ == '\0')