github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/libmach/machdata.c (about) 1 // Inferno libmach/machdata.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/libmach/machdata.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. 5 // Power PC support Copyright © 1995-2004 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 // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. 9 // Portions Copyright © 2009 The Go Authors. All rights reserved. 10 // 11 // Permission is hereby granted, free of charge, to any person obtaining a copy 12 // of this software and associated documentation files (the "Software"), to deal 13 // in the Software without restriction, including without limitation the rights 14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 // copies of the Software, and to permit persons to whom the Software is 16 // furnished to do so, subject to the following conditions: 17 // 18 // The above copyright notice and this permission notice shall be included in 19 // all copies or substantial portions of the Software. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 // THE SOFTWARE. 28 29 /* 30 * Debugger utilities shared by at least two architectures 31 */ 32 33 #include <u.h> 34 #include <libc.h> 35 #include <bio.h> 36 #include <mach.h> 37 38 #define STARTSYM "_main" 39 #define PROFSYM "_mainp" 40 #define FRAMENAME ".frame" 41 42 extern Machdata mipsmach; 43 44 int asstype = AMIPS; /* disassembler type */ 45 Machdata *machdata; /* machine-dependent functions */ 46 47 int 48 localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget) 49 { 50 Symbol s; 51 uvlong fp, pc, sp, link; 52 53 if (!lookup(fn, 0, &s)) { 54 werrstr("function not found"); 55 return -1; 56 } 57 pc = rget(map, mach->pc); 58 sp = rget(map, mach->sp); 59 if(mach->link) 60 link = rget(map, mach->link); 61 else 62 link = 0; 63 fp = machdata->findframe(map, s.value, pc, sp, link); 64 if (fp == 0) { 65 werrstr("stack frame not found"); 66 return -1; 67 } 68 69 if (!var || !var[0]) { 70 *r = fp; 71 return 1; 72 } 73 74 if (findlocal(&s, var, &s) == 0) { 75 werrstr("local variable not found"); 76 return -1; 77 } 78 79 switch (s.class) { 80 case CAUTO: 81 *r = fp - s.value; 82 break; 83 case CPARAM: /* assume address size is stack width */ 84 *r = fp + s.value + mach->szaddr; 85 break; 86 default: 87 werrstr("local variable not found: %d", s.class); 88 return -1; 89 } 90 return 1; 91 } 92 93 /* 94 * Print value v as s.name[+offset] if possible, or just v. 95 */ 96 int 97 symoff(char *buf, int n, uvlong v, int space) 98 { 99 Symbol s; 100 int r; 101 int32 delta; 102 103 r = delta = 0; /* to shut compiler up */ 104 if (v) { 105 r = findsym(v, space, &s); 106 if (r) 107 delta = v-s.value; 108 if (delta < 0) 109 delta = -delta; 110 } 111 if (v == 0 || r == 0) 112 return snprint(buf, n, "%llux", v); 113 if (s.type != 't' && s.type != 'T' && delta >= 4096) 114 return snprint(buf, n, "%llux", v); 115 else if (delta) 116 return snprint(buf, n, "%s+%#ux", s.name, delta); 117 else 118 return snprint(buf, n, "%s", s.name); 119 } 120 121 /* 122 * Format floating point registers 123 * 124 * Register codes in format field: 125 * 'X' - print as 32-bit hexadecimal value 126 * 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg 127 * 'f' - 32-bit ieee float 128 * '8' - big endian 80-bit ieee extended float 129 * '3' - little endian 80-bit ieee extended float with hole in bytes 8&9 130 */ 131 int 132 fpformat(Map *map, Reglist *rp, char *buf, int n, int modif) 133 { 134 char reg[12]; 135 uint32 r; 136 137 switch(rp->rformat) 138 { 139 case 'X': 140 if (get4(map, rp->roffs, &r) < 0) 141 return -1; 142 snprint(buf, n, "%ux", r); 143 break; 144 case 'F': /* first reg of double reg pair */ 145 if (modif == 'F') 146 if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) { 147 if (get1(map, rp->roffs, (uchar *)reg, 8) < 0) 148 return -1; 149 machdata->dftos(buf, n, reg); 150 if (rp->rformat == 'F') 151 return 1; 152 return 2; 153 } 154 /* treat it like 'f' */ 155 if (get1(map, rp->roffs, (uchar *)reg, 4) < 0) 156 return -1; 157 machdata->sftos(buf, n, reg); 158 break; 159 case 'f': /* 32 bit float */ 160 if (get1(map, rp->roffs, (uchar *)reg, 4) < 0) 161 return -1; 162 machdata->sftos(buf, n, reg); 163 break; 164 case '3': /* little endian ieee 80 with hole in bytes 8&9 */ 165 if (get1(map, rp->roffs, (uchar *)reg, 10) < 0) 166 return -1; 167 memmove(reg+10, reg+8, 2); /* open hole */ 168 memset(reg+8, 0, 2); /* fill it */ 169 leieee80ftos(buf, n, reg); 170 break; 171 case '8': /* big-endian ieee 80 */ 172 if (get1(map, rp->roffs, (uchar *)reg, 10) < 0) 173 return -1; 174 beieee80ftos(buf, n, reg); 175 break; 176 default: /* unknown */ 177 break; 178 } 179 return 1; 180 } 181 182 char * 183 _hexify(char *buf, uint32 p, int zeros) 184 { 185 uint32 d; 186 187 d = p/16; 188 if(d) 189 buf = _hexify(buf, d, zeros-1); 190 else 191 while(zeros--) 192 *buf++ = '0'; 193 *buf++ = "0123456789abcdef"[p&0x0f]; 194 return buf; 195 } 196 197 /* 198 * These routines assume that if the number is representable 199 * in IEEE floating point, it will be representable in the native 200 * double format. Naive but workable, probably. 201 */ 202 int 203 ieeedftos(char *buf, int n, uint32 h, uint32 l) 204 { 205 double fr; 206 int exp; 207 208 if (n <= 0) 209 return 0; 210 211 212 if(h & (1L<<31)){ 213 *buf++ = '-'; 214 h &= ~(1L<<31); 215 }else 216 *buf++ = ' '; 217 n--; 218 if(l == 0 && h == 0) 219 return snprint(buf, n, "0."); 220 exp = (h>>20) & ((1L<<11)-1L); 221 if(exp == 0) 222 return snprint(buf, n, "DeN(%.8ux%.8ux)", h, l); 223 if(exp == ((1L<<11)-1L)){ 224 if(l==0 && (h&((1L<<20)-1L)) == 0) 225 return snprint(buf, n, "Inf"); 226 else 227 return snprint(buf, n, "NaN(%.8ux%.8ux)", h&((1<<20)-1), l); 228 } 229 exp -= (1L<<10) - 2L; 230 fr = l & ((1L<<16)-1L); 231 fr /= 1L<<16; 232 fr += (l>>16) & ((1L<<16)-1L); 233 fr /= 1L<<16; 234 fr += (h & (1L<<20)-1L) | (1L<<20); 235 fr /= 1L<<21; 236 fr = ldexp(fr, exp); 237 return snprint(buf, n, "%.18g", fr); 238 } 239 240 int 241 ieeesftos(char *buf, int n, uint32 h) 242 { 243 double fr; 244 int exp; 245 246 if (n <= 0) 247 return 0; 248 249 if(h & (1L<<31)){ 250 *buf++ = '-'; 251 h &= ~(1L<<31); 252 }else 253 *buf++ = ' '; 254 n--; 255 if(h == 0) 256 return snprint(buf, n, "0."); 257 exp = (h>>23) & ((1L<<8)-1L); 258 if(exp == 0) 259 return snprint(buf, n, "DeN(%.8ux)", h); 260 if(exp == ((1L<<8)-1L)){ 261 if((h&((1L<<23)-1L)) == 0) 262 return snprint(buf, n, "Inf"); 263 else 264 return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L)); 265 } 266 exp -= (1L<<7) - 2L; 267 fr = (h & ((1L<<23)-1L)) | (1L<<23); 268 fr /= 1L<<24; 269 fr = ldexp(fr, exp); 270 return snprint(buf, n, "%.9g", fr); 271 } 272 273 int 274 beieeesftos(char *buf, int n, void *s) 275 { 276 return ieeesftos(buf, n, beswal(*(uint32*)s)); 277 } 278 279 int 280 beieeedftos(char *buf, int n, void *s) 281 { 282 return ieeedftos(buf, n, beswal(*(uint32*)s), beswal(((uint32*)(s))[1])); 283 } 284 285 int 286 leieeesftos(char *buf, int n, void *s) 287 { 288 return ieeesftos(buf, n, leswal(*(uint32*)s)); 289 } 290 291 int 292 leieeedftos(char *buf, int n, void *s) 293 { 294 return ieeedftos(buf, n, leswal(((uint32*)(s))[1]), leswal(*(uint32*)s)); 295 } 296 297 /* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/ 298 int 299 beieee80ftos(char *buf, int n, void *s) 300 { 301 uchar *reg = (uchar*)s; 302 int i; 303 uint32 x; 304 uchar ieee[8+8]; /* room for slop */ 305 uchar *p, *q; 306 307 memset(ieee, 0, sizeof(ieee)); 308 /* sign */ 309 if(reg[0] & 0x80) 310 ieee[0] |= 0x80; 311 312 /* exponent */ 313 x = ((reg[0]&0x7F)<<8) | reg[1]; 314 if(x == 0) /* number is ±0 */ 315 goto done; 316 if(x == 0x7FFF){ 317 if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */ 318 x = 2047; 319 }else{ /* NaN */ 320 x = 2047; 321 ieee[7] = 0x1; /* make sure */ 322 } 323 ieee[0] |= x>>4; 324 ieee[1] |= (x&0xF)<<4; 325 goto done; 326 } 327 x -= 0x3FFF; /* exponent bias */ 328 x += 1023; 329 if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0)) 330 return snprint(buf, n, "not in range"); 331 ieee[0] |= x>>4; 332 ieee[1] |= (x&0xF)<<4; 333 334 /* mantissa */ 335 p = reg+4; 336 q = ieee+1; 337 for(i=0; i<56; i+=8, p++, q++){ /* move one byte */ 338 x = (p[0]&0x7F) << 1; 339 if(p[1] & 0x80) 340 x |= 1; 341 q[0] |= x>>4; 342 q[1] |= (x&0xF)<<4; 343 } 344 done: 345 return beieeedftos(buf, n, (void*)ieee); 346 } 347 348 int 349 leieee80ftos(char *buf, int n, void *s) 350 { 351 int i; 352 char *cp; 353 char b[12]; 354 355 cp = (char*) s; 356 for(i=0; i<12; i++) 357 b[11-i] = *cp++; 358 return beieee80ftos(buf, n, b); 359 } 360 361 int 362 cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) 363 { 364 Symbol s; 365 int found, i; 366 uvlong opc, moved; 367 368 USED(link); 369 i = 0; 370 opc = 0; 371 while(pc && opc != pc) { 372 moved = pc2sp(pc); 373 if (moved == ~0) 374 break; 375 found = findsym(pc, CTEXT, &s); 376 if (!found) 377 break; 378 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) 379 break; 380 381 sp += moved; 382 opc = pc; 383 if (geta(map, sp, &pc) < 0) 384 break; 385 (*trace)(map, pc, sp, &s); 386 sp += mach->szaddr; /*assumes address size = stack width*/ 387 if(++i > 40) 388 break; 389 } 390 return i; 391 } 392 393 int 394 risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) 395 { 396 int i; 397 Symbol s, f; 398 uvlong oldpc; 399 400 i = 0; 401 while(findsym(pc, CTEXT, &s)) { 402 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) 403 break; 404 405 if(pc == s.value) /* at first instruction */ 406 f.value = 0; 407 else if(findlocal(&s, FRAMENAME, &f) == 0) 408 break; 409 410 oldpc = pc; 411 if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant) 412 pc = link; 413 else 414 if (geta(map, sp, &pc) < 0) 415 break; 416 417 if(pc == 0 || (pc == oldpc && f.value == 0)) 418 break; 419 420 sp += f.value; 421 (*trace)(map, pc-8, sp, &s); 422 423 if(++i > 40) 424 break; 425 } 426 return i; 427 } 428 429 uvlong 430 ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link) 431 { 432 Symbol s; 433 uvlong moved; 434 435 USED(link); 436 for(;;) { 437 moved = pc2sp(pc); 438 if (moved == ~0) 439 break; 440 sp += moved; 441 findsym(pc, CTEXT, &s); 442 if (addr == s.value) 443 return sp; 444 if (geta(map, sp, &pc) < 0) 445 break; 446 sp += mach->szaddr; /*assumes sizeof(addr) = stack width*/ 447 } 448 return 0; 449 } 450 451 uvlong 452 riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link) 453 { 454 Symbol s, f; 455 456 while (findsym(pc, CTEXT, &s)) { 457 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) 458 break; 459 460 if(pc == s.value) /* at first instruction */ 461 f.value = 0; 462 else 463 if(findlocal(&s, FRAMENAME, &f) == 0) 464 break; 465 466 sp += f.value; 467 if (s.value == addr) 468 return sp; 469 470 if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2) 471 pc = link; 472 else 473 if (geta(map, sp-f.value, &pc) < 0) 474 break; 475 } 476 return 0; 477 }