summaryrefslogtreecommitdiff
path: root/src/liblink/list5.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/liblink/list5.c')
-rw-r--r--src/liblink/list5.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/src/liblink/list5.c b/src/liblink/list5.c
new file mode 100644
index 000000000..4a4e8c71f
--- /dev/null
+++ b/src/liblink/list5.c
@@ -0,0 +1,356 @@
+// Inferno utils/5c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 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
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+
+enum
+{
+ STRINGSZ = 1000
+};
+
+static int Aconv(Fmt *fp);
+static int Dconv(Fmt *fp);
+static int Mconv(Fmt *fp);
+static int Pconv(Fmt *fp);
+static int Rconv(Fmt *fp);
+static int RAconv(Fmt *fp);
+static int DSconv(Fmt *fp);
+
+#pragma varargck type "$" char*
+#pragma varargck type "M" Addr*
+#pragma varargck type "@" Addr*
+
+void
+listinit5(void)
+{
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('R', Rconv);
+
+ // for internal use
+ fmtinstall('$', DSconv);
+ fmtinstall('M', Mconv);
+ fmtinstall('@', RAconv);
+}
+
+static char *extra [] = {
+ ".EQ", ".NE", ".CS", ".CC",
+ ".MI", ".PL", ".VS", ".VC",
+ ".HI", ".LS", ".GE", ".LT",
+ ".GT", ".LE", "", ".NV",
+};
+
+static Prog* bigP;
+
+static int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], sc[20];
+ Prog *p;
+ int a, s;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ a = p->as;
+ s = p->scond;
+ strcpy(sc, extra[s & C_SCOND]);
+ if(s & C_SBIT)
+ strcat(sc, ".S");
+ if(s & C_PBIT)
+ strcat(sc, ".P");
+ if(s & C_WBIT)
+ strcat(sc, ".W");
+ if(s & C_UBIT) /* ambiguous with FBIT */
+ strcat(sc, ".U");
+ if(a == AMOVM) {
+ if(p->from.type == D_CONST)
+ sprint(str, "%.5lld (%L) %A%s %@,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ else
+ if(p->to.type == D_CONST)
+ sprint(str, "%.5lld (%L) %A%s %D,%@", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ else
+ sprint(str, "%.5lld (%L) %A%s %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ } else
+ if(a == ADATA)
+ sprint(str, "%.5lld (%L) %A %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, "%.5lld (%L) %A %D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, "%.5lld (%L) %A%s %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, "%.5lld (%L) %A%s %D,R%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+ else
+ sprint(str, "%.5lld (%L) %A%s %D,F%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+ bigP = nil;
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames5[a];
+ return fmtstrcpy(fp, s);
+}
+
+static int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ const char *op;
+ int v;
+
+ a = va_arg(fp->args, Addr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
+ sprint(str, "%M(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%M(R%d)", a, a->reg);
+ else
+ sprint(str, "$%M", a);
+ break;
+
+ case D_CONST2:
+ sprint(str, "$%lld-%d", a->offset, a->offset2);
+ break;
+
+ case D_SHIFT:
+ v = a->offset;
+ op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
+ if(v & (1<<4))
+ sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+ else
+ sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+ if(a->reg != NREG)
+ sprint(str+strlen(str), "(R%d)", a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%M(R%d)", a, a->reg);
+ else
+ sprint(str, "%M", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ sprint(str, "PSR");
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(PSR)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ if(a->sym != nil)
+ sprint(str, "%s(SB)", a->sym->name);
+ else if(bigP != nil && bigP->pcond != nil)
+ sprint(str, "%lld", bigP->pcond->pc);
+ else if(a->u.branch != nil)
+ sprint(str, "%lld", a->u.branch->pc);
+ else
+ sprint(str, "%lld(PC)", a->offset/*-pc*/);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17g", a->u.dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%$\"", a->u.sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+static int
+RAconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ int i, v;
+
+ a = va_arg(fp->args, Addr*);
+ sprint(str, "GOK-reglist");
+ switch(a->type) {
+ case D_CONST:
+ case D_CONST2:
+ if(a->reg != NREG)
+ break;
+ if(a->sym != nil)
+ break;
+ v = a->offset;
+ strcpy(str, "");
+ for(i=0; i<NREG; i++) {
+ if(v & (1<<i)) {
+ if(str[0] == 0)
+ strcat(str, "[R");
+ else
+ strcat(str, ",R");
+ sprint(strchr(str, 0), "%d", i);
+ }
+ }
+ strcat(str, "]");
+ }
+ return fmtstrcpy(fp, str);
+}
+
+static int
+DSconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Rconv(Fmt *fp)
+{
+ int r;
+ char str[STRINGSZ];
+
+ r = va_arg(fp->args, int);
+ sprint(str, "R%d", r);
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Mconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ LSym *s;
+
+ a = va_arg(fp->args, Addr*);
+ s = a->sym;
+ if(s == nil) {
+ sprint(str, "%d", (int)a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%lld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%d(SB)", s->name, (int)a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%d(SB)", s->name, (int)a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%d(SP)", s->name, (int)-a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%d(FP)", s->name, (int)a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}