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