github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/liblink/list9.c (about) 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 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[(int)a->name] != nil) 182 s += sprint(s, "name=%s ", dnames9[(int)a->name]); 183 else 184 s += sprint(s, "name=%d ", a->name); 185 s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width); 186 if(a->class != 0) 187 s += sprint(s, " class=%s", cnames9[(int)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 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 }