1 // Inferno utils/5l/list.h
2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/list.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 // Portions Copyright © 1997-1999 Vita Nuova Limited
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 // Portions Copyright © 2004,2006 Bruce Ellis
9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 // Portions Copyright © 2009 The Go Authors. All rights reserved.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 // THE SOFTWARE.
30
31 // Printing.
32
33 #include "l.h"
34 #include "../ld/lib.h"
35
36 void
37 listinit(void)
38 {
39
40 fmtinstall('A', Aconv);
41 fmtinstall('C', Cconv);
42 fmtinstall('D', Dconv);
43 fmtinstall('P', Pconv);
44 fmtinstall('S', Sconv);
45 fmtinstall('N', Nconv);
46 fmtinstall('O', Oconv); // C_type constants
47 fmtinstall('I', Iconv);
48 }
49
50 void
51 prasm(Prog *p)
52 {
53 print("%P\n", p);
54 }
55
56 int
57 Pconv(Fmt *fp)
58 {
59 Prog *p;
60 int a;
61
62 p = va_arg(fp->args, Prog*);
63 curp = p;
64 a = p->as;
65 switch(a) {
66 default:
67 fmtprint(fp, "(%d)", p->line);
68 if(p->reg == NREG)
69 fmtprint(fp, " %A%C %D,%D",
70 a, p->scond, &p->from, &p->to);
71 else
72 if(p->from.type != D_FREG)
73 fmtprint(fp, " %A%C %D,R%d,%D",
74 a, p->scond, &p->from, p->reg, &p->to);
75 else
76 fmtprint(fp, " %A%C %D,F%d,%D",
77 a, p->scond, &p->from, p->reg, &p->to);
78 break;
79
80 case ASWPW:
81 case ASWPBU:
82 fmtprint(fp, "(%d) %A%C R%d,%D,%D",
83 p->line, a, p->scond, p->reg, &p->from, &p->to);
84 break;
85
86 case ADATA:
87 case AINIT_:
88 case ADYNT_:
89 fmtprint(fp, "(%d) %A%C %D/%d,%D",
90 p->line, a, p->scond, &p->from, p->reg, &p->to);
91 break;
92
93 case AWORD:
94 fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
95 break;
96
97 case ADWORD:
98 fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
99 break;
100 }
101
102 if(p->spadj)
103 fmtprint(fp, " (spadj%+d)", p->spadj);
104
105 return 0;
106 }
107
108 int
109 Aconv(Fmt *fp)
110 {
111 char *s;
112 int a;
113
114 a = va_arg(fp->args, int);
115 s = "???";
116 if(a >= AXXX && a < ALAST)
117 s = anames[a];
118 return fmtstrcpy(fp, s);
119 }
120
121 char* strcond[16] =
122 {
123 ".EQ",
124 ".NE",
125 ".HS",
126 ".LO",
127 ".MI",
128 ".PL",
129 ".VS",
130 ".VC",
131 ".HI",
132 ".LS",
133 ".GE",
134 ".LT",
135 ".GT",
136 ".LE",
137 "",
138 ".NV"
139 };
140
141 int
142 Cconv(Fmt *fp)
143 {
144 char s[20];
145 int c;
146
147 c = va_arg(fp->args, int);
148 strcpy(s, strcond[c & C_SCOND]);
149 if(c & C_SBIT)
150 strcat(s, ".S");
151 if(c & C_PBIT)
152 strcat(s, ".P");
153 if(c & C_WBIT)
154 strcat(s, ".W");
155 if(c & C_UBIT) /* ambiguous with FBIT */
156 strcat(s, ".U");
157 return fmtstrcpy(fp, s);
158 }
159
160 int
161 Dconv(Fmt *fp)
162 {
163 char str[STRINGSZ];
164 char *op;
165 Adr *a;
166 int32 v;
167
168 a = va_arg(fp->args, Adr*);
169 switch(a->type) {
170
171 default:
172 snprint(str, sizeof str, "GOK-type(%d)", a->type);
173 break;
174
175 case D_NONE:
176 str[0] = 0;
177 if(a->name != D_NONE || a->reg != NREG || a->sym != S)
178 snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
179 break;
180
181 case D_CONST:
182 if(a->reg == NREG)
183 snprint(str, sizeof str, "$%N", a);
184 else
185 snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
186 break;
187
188 case D_CONST2:
189 snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
190 break;
191
192 case D_SHIFT:
193 v = a->offset;
194 op = "<<>>->@>" + (((v>>5) & 3) << 1);
195 if(v & (1<<4))
196 snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
197 else
198 snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
199 if(a->reg != NREG)
200 seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
201 break;
202
203 case D_OCONST:
204 snprint(str, sizeof str, "$*$%N", a);
205 if(a->reg != NREG)
206 snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
207 break;
208
209 case D_OREG:
210 if(a->reg != NREG)
211 snprint(str, sizeof str, "%N(R%d)", a, a->reg);
212 else
213 snprint(str, sizeof str, "%N", a);
214 break;
215
216 case D_REG:
217 snprint(str, sizeof str, "R%d", a->reg);
218 if(a->name != D_NONE || a->sym != S)
219 snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
220 break;
221
222 case D_REGREG:
223 snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
224 if(a->name != D_NONE || a->sym != S)
225 snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
226 break;
227
228 case D_FREG:
229 snprint(str, sizeof str, "F%d", a->reg);
230 if(a->name != D_NONE || a->sym != S)
231 snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
232 break;
233
234 case D_PSR:
235 switch(a->reg) {
236 case 0:
237 snprint(str, sizeof str, "CPSR");
238 break;
239 case 1:
240 snprint(str, sizeof str, "SPSR");
241 break;
242 default:
243 snprint(str, sizeof str, "PSR%d", a->reg);
244 break;
245 }
246 if(a->name != D_NONE || a->sym != S)
247 snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
248 break;
249
250 case D_FPCR:
251 switch(a->reg){
252 case 0:
253 snprint(str, sizeof str, "FPSR");
254 break;
255 case 1:
256 snprint(str, sizeof str, "FPCR");
257 break;
258 default:
259 snprint(str, sizeof str, "FCR%d", a->reg);
260 break;
261 }
262 if(a->name != D_NONE || a->sym != S)
263 snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
264
265 break;
266
267 case D_BRANCH: /* botch */
268 if(curp->cond != P) {
269 v = curp->cond->pc;
270 if(a->sym != S)
271 snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
272 else
273 snprint(str, sizeof str, "%.5ux(BRANCH)", v);
274 } else
275 if(a->sym != S)
276 snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
277 else
278 snprint(str, sizeof str, "%d(APC)", a->offset);
279 break;
280
281 case D_FCONST:
282 snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
283 break;
284
285 case D_SCONST:
286 snprint(str, sizeof str, "$\"%S\"", a->sval);
287 break;
288 }
289 return fmtstrcpy(fp, str);
290 }
291
292 int
293 Nconv(Fmt *fp)
294 {
295 char str[STRINGSZ];
296 Adr *a;
297 Sym *s;
298
299 a = va_arg(fp->args, Adr*);
300 s = a->sym;
301 switch(a->name) {
302 default:
303 sprint(str, "GOK-name(%d)", a->name);
304 break;
305
306 case D_NONE:
307 sprint(str, "%d", a->offset);
308 break;
309
310 case D_EXTERN:
311 if(s == S)
312 sprint(str, "%d(SB)", a->offset);
313 else
314 sprint(str, "%s+%d(SB)", s->name, a->offset);
315 break;
316
317 case D_STATIC:
318 if(s == S)
319 sprint(str, "<>+%d(SB)", a->offset);
320 else
321 sprint(str, "%s<>+%d(SB)", s->name, a->offset);
322 break;
323
324 case D_AUTO:
325 if(s == S)
326 sprint(str, "%d(SP)", a->offset);
327 else
328 sprint(str, "%s-%d(SP)", s->name, -a->offset);
329 break;
330
331 case D_PARAM:
332 if(s == S)
333 sprint(str, "%d(FP)", a->offset);
334 else
335 sprint(str, "%s+%d(FP)", s->name, a->offset);
336 break;
337 }
338 return fmtstrcpy(fp, str);
339 }
340
341 int
342 Sconv(Fmt *fp)
343 {
344 int i, c;
345 char str[STRINGSZ], *p, *a;
346
347 a = va_arg(fp->args, char*);
348 p = str;
349 for(i=0; i<sizeof(int32); i++) {
350 c = a[i] & 0xff;
351 if(c >= 'a' && c <= 'z' ||
352 c >= 'A' && c <= 'Z' ||
353 c >= '0' && c <= '9' ||
354 c == ' ' || c == '%') {
355 *p++ = c;
356 continue;
357 }
358 *p++ = '\\';
359 switch(c) {
360 case 0:
361 *p++ = 'z';
362 continue;
363 case '\\':
364 case '"':
365 *p++ = c;
366 continue;
367 case '\n':
368 *p++ = 'n';
369 continue;
370 case '\t':
371 *p++ = 't';
372 continue;
373 }
374 *p++ = (c>>6) + '0';
375 *p++ = ((c>>3) & 7) + '0';
376 *p++ = (c & 7) + '0';
377 }
378 *p = 0;
379 return fmtstrcpy(fp, str);
380 }
381
382 int
383 Iconv(Fmt *fp)
384 {
385 int i, n;
386 uint32 *p;
387 char *s;
388 Fmt fmt;
389
390 n = fp->prec;
391 fp->prec = 0;
392 if(!(fp->flags&FmtPrec) || n < 0)
393 return fmtstrcpy(fp, "%I");
394 fp->flags &= ~FmtPrec;
395 p = va_arg(fp->args, uint32*);
396
397 // format into temporary buffer and
398 // call fmtstrcpy to handle padding.
399 fmtstrinit(&fmt);
400 for(i=0; i<n/4; i++) {
401 if(i > 0)
402 fmtprint(&fmt, " ");
403 fmtprint(&fmt, "%.8ux", *p++);
404 }
405 s = fmtstrflush(&fmt);
406 fmtstrcpy(fp, s);
407 free(s);
408 return 0;
409 }
410
411 static char*
412 cnames[] =
413 {
414 [C_ADDR] = "C_ADDR",
415 [C_FAUTO] = "C_FAUTO",
416 [C_ZFCON] = "C_SFCON",
417 [C_SFCON] = "C_SFCON",
418 [C_LFCON] = "C_LFCON",
419 [C_FCR] = "C_FCR",
420 [C_FOREG] = "C_FOREG",
421 [C_FREG] = "C_FREG",
422 [C_GOK] = "C_GOK",
423 [C_HAUTO] = "C_HAUTO",
424 [C_HFAUTO] = "C_HFAUTO",
425 [C_HFOREG] = "C_HFOREG",
426 [C_HOREG] = "C_HOREG",
427 [C_HREG] = "C_HREG",
428 [C_LACON] = "C_LACON",
429 [C_LAUTO] = "C_LAUTO",
430 [C_LBRA] = "C_LBRA",
431 [C_LCON] = "C_LCON",
432 [C_LOREG] = "C_LOREG",
433 [C_NCON] = "C_NCON",
434 [C_NONE] = "C_NONE",
435 [C_PC] = "C_PC",
436 [C_PSR] = "C_PSR",
437 [C_RACON] = "C_RACON",
438 [C_RCON] = "C_RCON",
439 [C_REG] = "C_REG",
440 [C_REGREG] = "C_REGREG",
441 [C_ROREG] = "C_ROREG",
442 [C_SAUTO] = "C_SAUTO",
443 [C_SBRA] = "C_SBRA",
444 [C_SCON] = "C_SCON",
445 [C_SHIFT] = "C_SHIFT",
446 [C_SOREG] = "C_SOREG",
447 [C_SP] = "C_SP",
448 [C_SROREG] = "C_SROREG"
449 };
450
451 int
452 Oconv(Fmt *fp)
453 {
454 char buf[500];
455 int o;
456
457 o = va_arg(fp->args, int);
458 if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) {
459 snprint(buf, sizeof(buf), "C_%d", o);
460 return fmtstrcpy(fp, buf);
461 }
462 return fmtstrcpy(fp, cnames[o]);
463 }
464
465 void
466 diag(char *fmt, ...)
467 {
468 char buf[STRINGSZ], *tn, *sep;
469 va_list arg;
470
471 tn = "";
472 sep = "";
473 if(cursym != S) {
474 tn = cursym->name;
475 sep = ": ";
476 }
477 va_start(arg, fmt);
478 vseprint(buf, buf+sizeof(buf), fmt, arg);
479 va_end(arg);
480 print("%s%s%s\n", tn, sep, buf);
481
482 nerrors++;
483 if(nerrors > 20) {
484 print("too many errors\n");
485 errorexit();
486 }
487 }