1 // Inferno utils/6l/list.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/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 static Prog* bigP;
37
38 void
39 listinit(void)
40 {
41
42 fmtinstall('R', Rconv);
43 fmtinstall('A', Aconv);
44 fmtinstall('D', Dconv);
45 fmtinstall('S', Sconv);
46 fmtinstall('P', Pconv);
47 fmtinstall('I', Iconv);
48 }
49
50 int
51 Pconv(Fmt *fp)
52 {
53 Prog *p;
54
55 p = va_arg(fp->args, Prog*);
56 bigP = p;
57 switch(p->as) {
58 case ATEXT:
59 if(p->from.scale) {
60 fmtprint(fp, "(%d) %A %D,%d,%D",
61 p->line, p->as, &p->from, p->from.scale, &p->to);
62 break;
63 }
64 default:
65 fmtprint(fp, "(%d) %A %D,%D",
66 p->line, p->as, &p->from, &p->to);
67 break;
68 case ADATA:
69 case AINIT_:
70 case ADYNT_:
71 fmtprint(fp, "(%d) %A %D/%d,%D",
72 p->line, p->as, &p->from, p->from.scale, &p->to);
73 break;
74 }
75 bigP = P;
76 return 0;
77 }
78
79 int
80 Aconv(Fmt *fp)
81 {
82 int i;
83
84 i = va_arg(fp->args, int);
85 return fmtstrcpy(fp, anames[i]);
86 }
87
88 int
89 Dconv(Fmt *fp)
90 {
91 char str[STRINGSZ], s[STRINGSZ];
92 Adr *a;
93 int i;
94
95 a = va_arg(fp->args, Adr*);
96 i = a->type;
97
98 if(fp->flags & FmtLong) {
99 if(i != D_CONST) {
100 // ATEXT dst is not constant
101 snprint(str, sizeof(str), "!!%D", a);
102 goto brk;
103 }
104 parsetextconst(a->offset);
105 if(textarg == 0) {
106 snprint(str, sizeof(str), "$%lld", textstksiz);
107 goto brk;
108 }
109 snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg);
110 goto brk;
111 }
112
113 if(i >= D_INDIR) {
114 if(a->offset)
115 snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
116 else
117 snprint(str, sizeof(str), "(%R)", i-D_INDIR);
118 goto brk;
119 }
120 switch(i) {
121
122 default:
123 if(a->offset)
124 snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
125 else
126 snprint(str, sizeof(str), "%R", i);
127 break;
128
129 case D_NONE:
130 str[0] = 0;
131 break;
132
133 case D_BRANCH:
134 if(bigP != P && bigP->pcond != P)
135 if(a->sym != S)
136 snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc,
137 a->sym->name);
138 else
139 snprint(str, sizeof(str), "%llux", bigP->pcond->pc);
140 else
141 snprint(str, sizeof(str), "%lld(PC)", a->offset);
142 break;
143
144 case D_EXTERN:
145 if(a->sym) {
146 snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset);
147 break;
148 }
149 snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset);
150 break;
151
152 case D_STATIC:
153 if(a->sym) {
154 snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name,
155 a->sym->version, a->offset);
156 break;
157 }
158 snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset);
159 break;
160
161 case D_AUTO:
162 if(a->sym) {
163 snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset);
164 break;
165 }
166 snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset);
167 break;
168
169 case D_PARAM:
170 if(a->sym) {
171 snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
172 break;
173 }
174 snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace);
175 break;
176
177 case D_CONST:
178 snprint(str, sizeof(str), "$%lld", a->offset);
179 break;
180
181 case D_FCONST:
182 snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
183 break;
184
185 case D_SCONST:
186 snprint(str, sizeof(str), "$\"%S\"", a->scon);
187 break;
188
189 case D_ADDR:
190 a->type = a->index;
191 a->index = D_NONE;
192 snprint(str, sizeof(str), "$%D", a);
193 a->index = a->type;
194 a->type = D_ADDR;
195 goto conv;
196 }
197 brk:
198 if(a->index != D_NONE) {
199 snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale);
200 strcat(str, s);
201 }
202 conv:
203 fmtstrcpy(fp, str);
204 // if(a->gotype)
205 // fmtprint(fp, "«%s»", a->gotype->name);
206 return 0;
207
208 }
209
210 char* regstr[] =
211 {
212 "AL", /* [D_AL] */
213 "CL",
214 "DL",
215 "BL",
216 "SPB",
217 "BPB",
218 "SIB",
219 "DIB",
220 "R8B",
221 "R9B",
222 "R10B",
223 "R11B",
224 "R12B",
225 "R13B",
226 "R14B",
227 "R15B",
228
229 "AX", /* [D_AX] */
230 "CX",
231 "DX",
232 "BX",
233 "SP",
234 "BP",
235 "SI",
236 "DI",
237 "R8",
238 "R9",
239 "R10",
240 "R11",
241 "R12",
242 "R13",
243 "R14",
244 "R15",
245
246 "AH",
247 "CH",
248 "DH",
249 "BH",
250
251 "F0", /* [D_F0] */
252 "F1",
253 "F2",
254 "F3",
255 "F4",
256 "F5",
257 "F6",
258 "F7",
259
260 "M0",
261 "M1",
262 "M2",
263 "M3",
264 "M4",
265 "M5",
266 "M6",
267 "M7",
268
269 "X0",
270 "X1",
271 "X2",
272 "X3",
273 "X4",
274 "X5",
275 "X6",
276 "X7",
277 "X8",
278 "X9",
279 "X10",
280 "X11",
281 "X12",
282 "X13",
283 "X14",
284 "X15",
285
286 "CS", /* [D_CS] */
287 "SS",
288 "DS",
289 "ES",
290 "FS",
291 "GS",
292
293 "GDTR", /* [D_GDTR] */
294 "IDTR", /* [D_IDTR] */
295 "LDTR", /* [D_LDTR] */
296 "MSW", /* [D_MSW] */
297 "TASK", /* [D_TASK] */
298
299 "CR0", /* [D_CR] */
300 "CR1",
301 "CR2",
302 "CR3",
303 "CR4",
304 "CR5",
305 "CR6",
306 "CR7",
307 "CR8",
308 "CR9",
309 "CR10",
310 "CR11",
311 "CR12",
312 "CR13",
313 "CR14",
314 "CR15",
315
316 "DR0", /* [D_DR] */
317 "DR1",
318 "DR2",
319 "DR3",
320 "DR4",
321 "DR5",
322 "DR6",
323 "DR7",
324
325 "TR0", /* [D_TR] */
326 "TR1",
327 "TR2",
328 "TR3",
329 "TR4",
330 "TR5",
331 "TR6",
332 "TR7",
333
334 "NONE", /* [D_NONE] */
335 };
336
337 int
338 Rconv(Fmt *fp)
339 {
340 char str[STRINGSZ];
341 int r;
342
343 r = va_arg(fp->args, int);
344 if(r >= D_AL && r <= D_NONE)
345 snprint(str, sizeof(str), "%s", regstr[r-D_AL]);
346 else
347 snprint(str, sizeof(str), "gok(%d)", r);
348
349 return fmtstrcpy(fp, str);
350 }
351
352 int
353 Sconv(Fmt *fp)
354 {
355 int i, c;
356 char str[STRINGSZ], *p, *a;
357
358 a = va_arg(fp->args, char*);
359 p = str;
360 for(i=0; i<sizeof(double); i++) {
361 c = a[i] & 0xff;
362 if(c >= 'a' && c <= 'z' ||
363 c >= 'A' && c <= 'Z' ||
364 c >= '0' && c <= '9') {
365 *p++ = c;
366 continue;
367 }
368 *p++ = '\\';
369 switch(c) {
370 default:
371 if(c < 040 || c >= 0177)
372 break; /* not portable */
373 p[-1] = c;
374 continue;
375 case 0:
376 *p++ = 'z';
377 continue;
378 case '\\':
379 case '"':
380 *p++ = c;
381 continue;
382 case '\n':
383 *p++ = 'n';
384 continue;
385 case '\t':
386 *p++ = 't';
387 continue;
388 }
389 *p++ = (c>>6) + '0';
390 *p++ = ((c>>3) & 7) + '0';
391 *p++ = (c & 7) + '0';
392 }
393 *p = 0;
394 return fmtstrcpy(fp, str);
395 }
396
397 int
398 Iconv(Fmt *fp)
399 {
400 int i, n;
401 uchar *p;
402 char *s;
403 Fmt fmt;
404
405 n = fp->prec;
406 fp->prec = 0;
407 if(!(fp->flags&FmtPrec) || n < 0)
408 return fmtstrcpy(fp, "%I");
409 fp->flags &= ~FmtPrec;
410 p = va_arg(fp->args, uchar*);
411
412 // format into temporary buffer and
413 // call fmtstrcpy to handle padding.
414 fmtstrinit(&fmt);
415 for(i=0; i<n; i++)
416 fmtprint(&fmt, "%.2ux", *p++);
417 s = fmtstrflush(&fmt);
418 fmtstrcpy(fp, s);
419 free(s);
420 return 0;
421 }
422
423 void
424 diag(char *fmt, ...)
425 {
426 char buf[STRINGSZ], *tn, *sep;
427 va_list arg;
428
429 tn = "";
430 sep = "";
431 if(cursym != S) {
432 tn = cursym->name;
433 sep = ": ";
434 }
435 va_start(arg, fmt);
436 vseprint(buf, buf+sizeof(buf), fmt, arg);
437 va_end(arg);
438 print("%s%s%s\n", tn, sep, buf);
439
440 nerrors++;
441 if(nerrors > 20) {
442 print("too many errors\n");
443 errorexit();
444 }
445 }
446
447 void
448 parsetextconst(vlong arg)
449 {
450 textstksiz = arg & 0xffffffffLL;
451 if(textstksiz & 0x80000000LL)
452 textstksiz = -(-textstksiz & 0xffffffffLL);
453
454 textarg = (arg >> 32) & 0xffffffffLL;
455 if(textarg & 0x80000000LL)
456 textarg = 0;
457 textarg = (textarg+7) & ~7LL;
458 }