]> Cypherpunks.ru repositories - gostls13.git/blob - src/liblink/list9.c
[dev.cc] all: merge dev.power64 (f57928630b36) into dev.cc
[gostls13.git] / src / liblink / list9.c
1 // cmd/9l/list.c from Vita Nuova.
2 //
3 //      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
4 //      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
5 //      Portions Copyright © 1997-1999 Vita Nuova Limited
6 //      Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
7 //      Portions Copyright © 2004,2006 Bruce Ellis
8 //      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
9 //      Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
10 //      Portions Copyright © 2009 The Go Authors.  All rights reserved.
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
13 // of this software and associated documentation files (the "Software"), to deal
14 // in the Software without restriction, including without limitation the rights
15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 // copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be included in
20 // all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 // THE SOFTWARE.
29
30 #include <u.h>
31 #include <libc.h>
32 #include <bio.h>
33 #include <link.h>
34 #include "../cmd/9l/9.out.h"
35
36 enum
37 {
38         STRINGSZ        = 1000,
39 };
40
41 static int      Aconv(Fmt*);
42 static int      Dconv(Fmt*);
43 static int      Pconv(Fmt*);
44 static int      Rconv(Fmt*);
45 static int      DSconv(Fmt*);
46 static int      Mconv(Fmt*);
47 static int      DRconv(Fmt*);
48
49 //
50 // Format conversions
51 //      %A int          Opcodes (instruction mnemonics)
52 //
53 //      %D Addr*        Addresses (instruction operands)
54 //              Flags: "%lD": seperate the high and low words of a constant by "-"
55 //
56 //      %P Prog*        Instructions
57 //
58 //      %R int          Registers
59 //
60 //      %$ char*        String constant addresses (for internal use only)
61 //      %^ int          C_* classes (for liblink internal use)
62
63 #pragma varargck        type    "$"     char*
64 #pragma varargck        type    "M"     Addr*
65
66 void
67 listinit9(void)
68 {
69         fmtinstall('A', Aconv);
70         fmtinstall('D', Dconv);
71         fmtinstall('P', Pconv);
72         fmtinstall('R', Rconv);
73
74         // for liblink internal use
75         fmtinstall('^', DRconv);
76
77         // for internal use
78         fmtinstall('$', DSconv);
79         fmtinstall('M', Mconv);
80 }
81
82 static Prog*    bigP;
83
84 static int
85 Pconv(Fmt *fp)
86 {
87         char str[STRINGSZ], *s;
88         Prog *p;
89         int a;
90
91         p = va_arg(fp->args, Prog*);
92         bigP = p;
93         a = p->as;
94
95         if(fp->flags & FmtSharp) {
96                 s = str;
97                 s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, a);
98                 if(p->from.type != D_NONE)
99                         s += sprint(s, " from={%#D}", &p->from);
100                 if(p->reg)
101                         s += sprint(s, " reg=%d", p->reg);
102                 if(p->from3.type != D_NONE)
103                         s += sprint(s, " from3={%#D}", &p->from3);
104                 if(p->to.type != D_NONE)
105                         s += sprint(s, " to={%#D}", &p->to);
106                 return fmtstrcpy(fp, str);
107         }
108
109         if(a == ADATA || a == AINIT || a == ADYNT)
110                 sprint(str, "%.5lld (%L)        %A      %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
111         else if(a == ATEXT) {
112                 if(p->reg != 0)
113                         sprint(str, "%.5lld (%L)        %A      %D,%d,%lD", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
114                 else
115                         sprint(str, "%.5lld (%L)        %A      %D,%lD", p->pc, p->lineno, a, &p->from, &p->to);
116         } else if(a == AGLOBL) {
117                 if(p->reg != 0)
118                         sprint(str, "%.5lld (%L)        %A      %D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
119                 else
120                         sprint(str, "%.5lld (%L)        %A      %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
121         } else {
122                 s = str;
123                 if(p->mark & NOSCHED)
124                         s += sprint(s, "*");
125                 if(p->reg == NREG && p->from3.type == D_NONE)
126                         sprint(s, "%.5lld (%L)  %A      %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
127                 else
128                 if(a != ATEXT && p->from.type == D_OREG) {
129                         sprint(s, "%.5lld (%L)  %A      %lld(R%d+R%d),%D", p->pc, p->lineno, a,
130                                 p->from.offset, p->from.reg, p->reg, &p->to);
131                 } else
132                 if(p->to.type == D_OREG) {
133                         sprint(s, "%.5lld (%L)  %A      %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
134                                         &p->from, p->to.offset, p->to.reg, p->reg);
135                 } else {
136                         s += sprint(s, "%.5lld (%L)     %A      %D", p->pc, p->lineno, a, &p->from);
137                         if(p->reg != NREG)
138                                 s += sprint(s, ",%c%d", p->from.type==D_FREG?'F':'R', p->reg);
139                         if(p->from3.type != D_NONE)
140                                 s += sprint(s, ",%D", &p->from3);
141                         sprint(s, ",%D", &p->to);
142                 }
143                 if(p->spadj != 0)
144                         return fmtprint(fp, "%s # spadj=%d", str, p->spadj);
145         }
146         return fmtstrcpy(fp, str);
147 }
148
149 static int
150 Aconv(Fmt *fp)
151 {
152         char *s;
153         int a;
154
155         a = va_arg(fp->args, int);
156         s = "???";
157         if(a >= AXXX && a < ALAST)
158                 s = anames9[a];
159         return fmtstrcpy(fp, s);
160 }
161
162 static int
163 Dconv(Fmt *fp)
164 {
165         char str[STRINGSZ];
166         Addr *a;
167         int32 v;
168
169         a = va_arg(fp->args, Addr*);
170
171         if(fp->flags & FmtSharp) {
172                 char *s = str;
173                 if(a->type == D_NONE) {
174                         sprint(s, "type=NONE");
175                         goto ret;
176                 }
177                 if(a->type >= 0 && a->type < D_LAST && dnames9[a->type] != nil)
178                         s += sprint(s, "type=%s ", dnames9[a->type]);
179                 else
180                         s += sprint(s, "type=%d ", a->type);
181                 if(a->name >= 0 && a->name < D_LAST && dnames9[a->name] != nil)
182                         s += sprint(s, "name=%s ", dnames9[a->name]);
183                 else
184                         s += sprint(s, "name=%d ", a->name);
185                 s += sprint(s, "offset=%ld etype=%E width=%d", a->offset, a->etype, a->width);
186                 if(a->class != 0)
187                         s += sprint(s, " class=%s", cnames9[a->class]);
188                 if(a->reg != NREG)
189                         s += sprint(s, " reg=%d", a->reg);
190                 if(a->sym != nil)
191                         s += sprint(s, " sym=%s", a->sym->name);
192                 if(a->type == D_BRANCH && a->u.branch != nil)
193                         s += sprint(s, " branch=%.5lld", a->u.branch->pc);
194                 goto ret;
195         }
196
197         if(fp->flags & FmtLong) {
198                 if(a->type == D_CONST)
199                         sprint(str, "$%d-%d", (int32)a->offset, (int32)(a->offset>>32));
200                 else {
201                         // ATEXT dst is not constant
202                         sprint(str, "!!%D", a);
203                 }
204                 goto ret;
205         }
206
207         switch(a->type) {
208         default:
209                 sprint(str, "GOK-type(%d)", a->type);
210                 break;
211
212         case D_NONE:
213                 str[0] = 0;
214                 if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
215                         sprint(str, "%M(R%d)(NONE)", a, a->reg);
216                 break;
217
218         case D_CONST:
219         case D_DCONST:
220                 if(a->reg != NREG)
221                         sprint(str, "$%M(R%d)", a, a->reg);
222                 else
223                         sprint(str, "$%M", a);
224                 break;
225
226         case D_OREG:
227                 if(a->reg != NREG)
228                         sprint(str, "%M(R%d)", a, a->reg);
229                 else
230                         sprint(str, "%M", a);
231                 break;
232
233         case D_REG:
234                 sprint(str, "R%d", a->reg);
235                 if(a->name != D_NONE || a->sym != nil)
236                         sprint(str, "%M(R%d)(REG)", a, a->reg);
237                 break;
238
239         case D_FREG:
240                 sprint(str, "F%d", a->reg);
241                 if(a->name != D_NONE || a->sym != nil)
242                         sprint(str, "%M(F%d)(REG)", a, a->reg);
243                 break;
244
245         case D_CREG:
246                 if(a->reg == NREG)
247                         strcpy(str, "CR");
248                 else
249                         sprint(str, "CR%d", a->reg);
250                 if(a->name != D_NONE || a->sym != nil)
251                         sprint(str, "%M(C%d)(REG)", a, a->reg);
252                 break;
253
254         case D_SPR:
255                 if(a->name == D_NONE && a->sym == nil) {
256                         switch((ulong)a->offset) {
257                         case D_XER: sprint(str, "XER"); break;
258                         case D_LR: sprint(str, "LR"); break;
259                         case D_CTR: sprint(str, "CTR"); break;
260                         default: sprint(str, "SPR(%lld)", a->offset); break;
261                         }
262                         break;
263                 }
264                 sprint(str, "SPR-GOK(%d)", a->reg);
265                 if(a->name != D_NONE || a->sym != nil)
266                         sprint(str, "%M(SPR-GOK%d)(REG)", a, a->reg);
267                 break;
268
269         case D_DCR:
270                 if(a->name == D_NONE && a->sym == nil) {
271                         sprint(str, "DCR(%lld)", a->offset);
272                         break;
273                 }
274                 sprint(str, "DCR-GOK(%d)", a->reg);
275                 if(a->name != D_NONE || a->sym != nil)
276                         sprint(str, "%M(DCR-GOK%d)(REG)", a, a->reg);
277                 break;
278
279         case D_OPT:
280                 sprint(str, "OPT(%d)", a->reg);
281                 break;
282
283         case D_FPSCR:
284                 if(a->reg == NREG)
285                         strcpy(str, "FPSCR");
286                 else
287                         sprint(str, "FPSCR(%d)", a->reg);
288                 break;
289
290         case D_MSR:
291                 sprint(str, "MSR");
292                 break;
293
294         case D_BRANCH:
295                 if(bigP->pcond != nil) {
296                         v = bigP->pcond->pc;
297                         //if(v >= INITTEXT)
298                         //      v -= INITTEXT-HEADR;
299                         if(a->sym != nil)
300                                 sprint(str, "%s+%.5ux(BRANCH)", a->sym->name, v);
301                         else
302                                 sprint(str, "%.5ux(BRANCH)", v);
303                 } else if(a->u.branch != nil)
304                         sprint(str, "%lld", a->u.branch->pc);
305                 else if(a->sym != nil)
306                         sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
307                 else
308                         sprint(str, "%lld(APC)", a->offset);
309                 break;
310
311         case D_FCONST:
312                 //sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l);
313                 sprint(str, "$%.17g", a->u.dval);
314                 break;
315
316         case D_SCONST:
317                 sprint(str, "$\"%$\"", a->u.sval);
318                 break;
319         }
320
321 ret:
322         return fmtstrcpy(fp, str);
323 }
324
325 static int
326 Mconv(Fmt *fp)
327 {
328         char str[STRINGSZ];
329         Addr *a;
330         LSym *s;
331         int32 l;
332
333         a = va_arg(fp->args, Addr*);
334         s = a->sym;
335         //if(s == nil) {
336         //      l = a->offset;
337         //      if((vlong)l != a->offset)
338         //              sprint(str, "0x%llux", a->offset);
339         //      else
340         //              sprint(str, "%lld", a->offset);
341         //      goto out;
342         //}
343         switch(a->name) {
344         default:
345                 sprint(str, "GOK-name(%d)", a->name);
346                 break;
347
348         case D_NONE:
349                 l = a->offset;
350                 if((vlong)l != a->offset)
351                         sprint(str, "0x%llux", a->offset);
352                 else
353                         sprint(str, "%lld", a->offset);
354                 break;
355
356         case D_EXTERN:
357                 if(a->offset != 0)
358                         sprint(str, "%s+%lld(SB)", s->name, a->offset);
359                 else
360                         sprint(str, "%s(SB)", s->name);
361                 break;
362
363         case D_STATIC:
364                 sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
365                 break;
366
367         case D_AUTO:
368                 if(s == nil)
369                         sprint(str, "%lld(SP)", -a->offset);
370                 else
371                         sprint(str, "%s-%lld(SP)", s->name, -a->offset);
372                 break;
373
374         case D_PARAM:
375                 if(s == nil)
376                         sprint(str, "%lld(FP)", a->offset);
377                 else
378                         sprint(str, "%s+%lld(FP)", s->name, a->offset);
379                 break;
380         }
381 //out:
382         return fmtstrcpy(fp, str);
383 }
384
385 static int
386 Rconv(Fmt *fp)
387 {
388         char str[STRINGSZ];
389         int r;
390
391         r = va_arg(fp->args, int);
392         if(r < NREG)
393                 sprint(str, "r%d", r);
394         else
395                 sprint(str, "f%d", r-NREG);
396         return fmtstrcpy(fp, str);
397 }
398
399 static int
400 DRconv(Fmt *fp)
401 {
402         char *s;
403         int a;
404
405         a = va_arg(fp->args, int);
406         s = "C_??";
407         if(a >= C_NONE && a <= C_NCLASS)
408                 s = cnames9[a];
409         return fmtstrcpy(fp, s);
410 }
411
412 static int
413 DSconv(Fmt *fp)
414 {
415         int i, c;
416         char str[STRINGSZ], *p, *a;
417
418         a = va_arg(fp->args, char*);
419         p = str;
420         for(i=0; i<sizeof(int32); i++) {
421                 c = a[i] & 0xff;
422                 if(c >= 'a' && c <= 'z' ||
423                    c >= 'A' && c <= 'Z' ||
424                    c >= '0' && c <= '9' ||
425                    c == ' ' || c == '%') {
426                         *p++ = c;
427                         continue;
428                 }
429                 *p++ = '\\';
430                 switch(c) {
431                 case 0:
432                         *p++ = 'z';
433                         continue;
434                 case '\\':
435                 case '"':
436                         *p++ = c;
437                         continue;
438                 case '\n':
439                         *p++ = 'n';
440                         continue;
441                 case '\t':
442                         *p++ = 't';
443                         continue;
444                 }
445                 *p++ = (c>>6) + '0';
446                 *p++ = ((c>>3) & 7) + '0';
447                 *p++ = (c & 7) + '0';
448         }
449         *p = 0;
450         return fmtstrcpy(fp, str);
451 }