1/* 2Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. 3Permission is hereby granted, free of charge, to any person 4obtaining a copy of this software and associated documentation 5files (the "Software"), to deal in the Software without 6restriction, including without limitation the rights to use, 7copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following 10conditions: 11 12The above copyright notice and this permission notice shall be 13included in all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23*/ 24 25#include "uwx_env.h" 26#include "uwx_utable.h" 27#include "uwx_uinfo.h" 28#include "uwx_scoreboard.h" 29#include "uwx_str.h" 30#include "uwx_step.h" 31#include "uwx_trace.h" 32 33/* 34 * uwx_step.c 35 * 36 * This file contains the routines for stepping from one frame 37 * into its callers frame. The context for the current frame 38 * is maintained inside the current unwind environment 39 * (struct uwx_env), and is updated with each call to 40 * uwx_step() to refer to the previous frame. 41 */ 42 43 44/* Forward Declarations */ 45 46int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate); 47int uwx_restore_reg(struct uwx_env *env, uint64_t rstate, 48 uint64_t *valp, uint64_t *histp); 49int uwx_restore_freg(struct uwx_env *env, uint64_t rstate, 50 uint64_t *valp, uint64_t *histp); 51int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat); 52 53 54/* uwx_lookupip_hook: Hook routine so dynamic instrumentation */ 55/* tools can intercept Lookup IP events. When not */ 56/* intercepted, it just returns "Not found", so that */ 57/* the callback routine is invoked. */ 58 59/*ARGSUSED*/ 60int uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp, 61 size_t uvecsize) 62{ 63 return UWX_LKUP_NOTFOUND; 64} 65 66 67/* uwx_get_frame_info: Gets unwind info for current frame */ 68static 69int uwx_get_frame_info(struct uwx_env *env) 70{ 71 int i; 72 int status; 73 int cbstatus; 74 int cbcalled = 0; 75 uint64_t ip; 76 uint64_t *uvec; 77 uint64_t *rstate; 78 struct uwx_utable_entry uentry; 79 uint64_t uvecout[UVECSIZE]; 80 81 if (env->copyin == 0 || env->lookupip == 0) 82 return UWX_ERR_NOCALLBACKS; 83 84 env->ptr_size = DWORDSZ; 85 env->code_start = 0; 86 env->function_offset = -1LL; 87 env->function_name = 0; 88 env->module_name = 0; 89 env->abi_context = 0; 90 uwx_reset_str_pool(env); 91 92 /* Use the lookup IP callback routine to find out about the */ 93 /* current IP. If the predicate registers are valid, pass them */ 94 /* in the uvec. */ 95 96 /* When self-unwinding, we call a hook routine before the */ 97 /* callback. If the application is running under control of */ 98 /* a dynamic instrumentation tool, that tool will have an */ 99 /* opportunity to intercept lookup IP requests. */ 100 101 i = 0; 102 uvecout[i++] = UWX_KEY_VERSION; 103 uvecout[i++] = UWX_VERSION; 104 if (env->context.valid_regs & (1 << UWX_REG_PREDS)) { 105 uvecout[i++] = UWX_KEY_PREDS; 106 uvecout[i++] = env->context.special[UWX_REG_PREDS]; 107 } 108 uvecout[i++] = UWX_KEY_END; 109 uvecout[i++] = 0; 110 uvec = uvecout; 111 cbstatus = UWX_LKUP_NOTFOUND; 112 ip = env->context.special[UWX_REG_IP]; 113 env->remapped_ip = ip; 114 115 /* Call the hook routine. */ 116 117 if (env->remote == 0) 118 cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec, 119 sizeof(uvecout)); 120 121 /* If the hook routine remapped the IP, use the new IP for */ 122 /* the callback instead of the original IP. */ 123 124 if (cbstatus == UWX_LKUP_REMAP) { 125 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 126 switch ((int)uvec[i]) { 127 case UWX_KEY_NEWIP: 128 ip = uvec[i+1]; 129 break; 130 } 131 } 132 env->remapped_ip = ip; 133 } 134 135 /* Now call the callback routine unless the hook routine gave */ 136 /* us all the info. */ 137 138 if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) { 139 cbcalled = 1; 140 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec); 141 } 142 143 /* If the callback routine remapped the IP, call it one more time */ 144 /* with the new IP. */ 145 146 if (cbstatus == UWX_LKUP_REMAP) { 147 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 148 switch ((int)uvec[i]) { 149 case UWX_KEY_NEWIP: 150 ip = uvec[i+1]; 151 break; 152 } 153 } 154 env->remapped_ip = ip; 155 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec); 156 } 157 158 /* If NOTFOUND, there's nothing we can do but return an error. */ 159 160 if (cbstatus == UWX_LKUP_NOTFOUND) { 161 status = UWX_ERR_IPNOTFOUND; 162 } 163 164 /* If the callback returns an unwind table, we need to */ 165 /* search the table for an unwind entry that describes the */ 166 /* code region of interest, then decode the unwind information */ 167 /* associated with that unwind table entry, and store the */ 168 /* resulting register state array in the unwind environment */ 169 /* block. */ 170 171 else if (cbstatus == UWX_LKUP_UTABLE) { 172 status = uwx_search_utable(env, ip, uvec, &uentry); 173 if (cbcalled) 174 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 175 if (status == UWX_OK) { 176 env->ptr_size = uentry.ptr_size; 177 env->code_start = uentry.code_start; 178 status = uwx_decode_uinfo(env, &uentry, &rstate); 179 } 180 if (status == UWX_ERR_NOUENTRY || status == UWX_ERR_NOUDESC) 181 status = uwx_default_rstate(env, &rstate); 182 if (status == UWX_OK) 183 env->rstate = rstate; 184 } 185 186 /* If the callback returns an unwind info block, we can */ 187 /* proceed directly to decoding the unwind information. */ 188 189 else if (cbstatus == UWX_LKUP_UINFO) { 190 uentry.ptr_size = DWORDSZ; 191 uentry.code_start = 0; 192 uentry.code_end = 0; 193 uentry.unwind_info = 0; 194 uentry.unwind_flags = 0; 195 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 196 switch ((int)uvec[i]) { 197 case UWX_KEY_UFLAGS: 198 uentry.unwind_flags = uvec[i+1]; 199 if (uentry.unwind_flags & UNWIND_TBL_32BIT) 200 uentry.ptr_size = WORDSZ; 201 break; 202 case UWX_KEY_UINFO: 203 uentry.unwind_info = uvec[i+1]; 204 break; 205 case UWX_KEY_GP: 206 uwx_set_reg(env, UWX_REG_GP, uvec[i+1]); 207 break; 208 case UWX_KEY_MODULE: 209 env->module_name = 210 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 211 break; 212 case UWX_KEY_FUNC: 213 env->function_name = 214 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 215 break; 216 case UWX_KEY_FUNCSTART: 217 uentry.code_start = uvec[i+1]; 218 env->code_start = uentry.code_start; 219 break; 220 } 221 } 222 env->ptr_size = uentry.ptr_size; 223 if (cbcalled) 224 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 225 status = uwx_decode_uinfo(env, &uentry, &rstate); 226 if (status == UWX_ERR_NOUDESC) 227 status = uwx_default_rstate(env, &rstate); 228 if (status == UWX_OK) 229 env->rstate = rstate; 230 } 231 232 /* If the callback returns a frame description (in the form */ 233 /* of an update vector), convert the update vector into a */ 234 /* register state array, then invoke the callback again to */ 235 /* let it free any memory it allocated. */ 236 237 else if (cbstatus == UWX_LKUP_FDESC) { 238 status = uwx_decode_uvec(env, uvec, &rstate); 239 if (cbcalled) 240 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 241 if (status == UWX_OK) 242 env->rstate = rstate; 243 } 244 245 /* Any other return from the callback is an error. */ 246 247 else { 248 status = UWX_ERR_LOOKUPERR; 249 } 250 return status; 251} 252 253 254/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */ 255 256int uwx_restore_markers(struct uwx_env *env) 257{ 258 int status; 259 uint64_t val; 260 uint64_t hist; 261 262 if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4) 263 return UWX_ERR_NOCONTEXT; 264 265 /* If we haven't already obtained the frame info for the */ 266 /* current frame, get it now. */ 267 268 if (env->rstate == 0) { 269 status = uwx_get_frame_info(env); 270 if (status != UWX_OK) 271 return status; 272 } 273 274 TRACE_S_STEP(env->rstate) 275 276 if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) { 277 status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist); 278 if (status != UWX_OK) 279 return status; 280 env->context.special[UWX_REG_PSP] = val; 281 env->history.special[UWX_REG_PSP] = hist; 282 env->context.valid_regs |= 1 << UWX_REG_PSP; 283 TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val) 284 } 285 286 if (env->rstate[SBREG_RP] != UWX_DISP_NONE) { 287 status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist); 288 if (status != UWX_OK) 289 return status; 290 env->context.special[UWX_REG_RP] = val; 291 env->history.special[UWX_REG_RP] = hist; 292 env->context.valid_regs |= 1 << UWX_REG_RP; 293 TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val) 294 } 295 296 if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) { 297 status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist); 298 if (status != UWX_OK) 299 return status; 300 env->context.special[UWX_REG_PFS] = val; 301 env->history.special[UWX_REG_PFS] = hist; 302 env->context.valid_regs |= 1 << UWX_REG_PFS; 303 TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val) 304 } 305 306 return UWX_OK; 307} 308 309/* uwx_get_module_info: Gets module name and text base for current frame */ 310 311int uwx_get_module_info( 312 struct uwx_env *env, 313 char **modp, 314 uint64_t *text_base) 315{ 316 int i; 317 int status; 318 int cbstatus; 319 uint64_t ip; 320 uint64_t *uvec; 321 uint64_t uvecout[UVECSIZE]; 322 323 if (env == 0) 324 return UWX_ERR_NOENV; 325 326 /* If we haven't already obtained the frame info for the */ 327 /* current frame, get it now. */ 328 329 if (env->rstate == 0) { 330 status = uwx_get_frame_info(env); 331 if (status != UWX_OK) 332 return status; 333 } 334 335 /* Get the module name from the lookup IP callback. */ 336 if (env->module_name == 0) { 337 ip = env->remapped_ip; 338 i = 0; 339 if (env->function_offset >= 0) { 340 uvecout[i++] = UWX_KEY_FUNCSTART; 341 uvecout[i++] = ip - env->function_offset; 342 } 343 uvecout[i++] = UWX_KEY_END; 344 uvecout[i++] = 0; 345 uvec = uvecout; 346 cbstatus = (*env->lookupip)(UWX_LKUP_MODULE, ip, env->cb_token, &uvec); 347 348 if (cbstatus == UWX_LKUP_SYMINFO) { 349 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 350 switch ((int)uvec[i]) { 351 case UWX_KEY_TBASE: 352 env->text_base = uvec[i+1]; 353 break; 354 case UWX_KEY_MODULE: 355 env->module_name = 356 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 357 break; 358 case UWX_KEY_FUNC: 359 env->function_name = 360 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 361 break; 362 case UWX_KEY_FUNCSTART: 363 env->function_offset = ip - uvec[i+1]; 364 break; 365 } 366 } 367 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 368 } 369 } 370 371 *modp = env->module_name; 372 *text_base = env->text_base; 373 374 return UWX_OK; 375} 376 377/* uwx_get_funcstart: Gets start address of function from current frame */ 378 379int uwx_get_funcstart( 380 struct uwx_env *env, 381 uint64_t *funcstart) 382{ 383 int status; 384 385 if (env == 0) 386 return UWX_ERR_NOENV; 387 388 /* If we haven't already obtained the frame info for the */ 389 /* current frame, get it now. */ 390 391 if (env->rstate == 0) { 392 status = uwx_get_frame_info(env); 393 if (status != UWX_OK) 394 return status; 395 } 396 397 *funcstart = env->remapped_ip - env->function_offset; 398 399 return UWX_OK; 400} 401 402/* uwx_get_sym_info: Gets symbolic info from current frame */ 403/* (Will make a UWX_LKUP_SYMBOLS callback if info */ 404/* was not provided by UWX_LKUP_LOOKUP callback) */ 405 406int uwx_get_sym_info( 407 struct uwx_env *env, 408 char **modp, 409 char **symp, 410 uint64_t *offsetp) 411{ 412 int status; 413 int cbstatus; 414 uint64_t ip; 415 uint64_t *uvec; 416 uint64_t uvecout[UVECSIZE]; 417 int i; 418 419 if (env == 0) 420 return UWX_ERR_NOENV; 421 422 /* If we haven't already obtained the frame info for the */ 423 /* current frame, get it now. */ 424 425 if (env->rstate == 0) { 426 status = uwx_get_frame_info(env); 427 if (status != UWX_OK) 428 return status; 429 } 430 431 /* Get the symbolic information from the lookup IP callback. */ 432 if (env->function_name == 0) { 433 ip = env->remapped_ip; 434 i = 0; 435 if (env->function_offset >= 0) { 436 uvecout[i++] = UWX_KEY_FUNCSTART; 437 uvecout[i++] = ip - env->function_offset; 438 } 439 uvecout[i++] = UWX_KEY_END; 440 uvecout[i++] = 0; 441 uvec = uvecout; 442 cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec); 443 444 if (cbstatus == UWX_LKUP_SYMINFO) { 445 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 446 switch ((int)uvec[i]) { 447 case UWX_KEY_MODULE: 448 env->module_name = 449 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 450 break; 451 case UWX_KEY_FUNC: 452 env->function_name = 453 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 454 break; 455 case UWX_KEY_FUNCSTART: 456 env->function_offset = ip - uvec[i+1]; 457 break; 458 } 459 } 460 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 461 } 462 } 463 464 *modp = env->module_name; 465 *symp = env->function_name; 466 *offsetp = env->function_offset; 467 468 return UWX_OK; 469} 470 471 472/* uwx_step: Steps from the current frame to the previous frame */ 473 474int uwx_step(struct uwx_env *env) 475{ 476 int i; 477 int status; 478 int pfs_sol; 479 int dispcode; 480 uint64_t val; 481 uint64_t fval[2]; 482 uint64_t hist; 483 uint64_t tempgr[NPRESERVEDGR]; 484 int needpriunat; 485 int unat; 486 int tempnat; 487 488 if (env == 0) 489 return UWX_ERR_NOENV; 490 491 /* Complete the current context by restoring the current values */ 492 /* of psp, rp, and pfs. */ 493 494 if (env->rstate == 0 || 495 (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) { 496 status = uwx_restore_markers(env); 497 if (status != UWX_OK) 498 return status; 499 } 500 501 /* Check for bottom of stack (rp == 0). */ 502 503 if (env->context.special[UWX_REG_RP] == 0) 504 return UWX_BOTTOM; 505 506 /* Find where the primary unat is saved, get a copy. */ 507 /* Then, as we restore the GRs, we'll merge the NaT bits into the */ 508 /* priunat register in the context. */ 509 /* (Make sure we need it, though, before we try to get it, */ 510 /* because the attempt to get it might invoke the copy-in callback. */ 511 /* We don't need the priunat unless one of GR 4-7 was */ 512 /* saved to the memory stack.) */ 513 514 needpriunat = 0; 515 for (i = 0; i < NSB_GR; i++) { 516 dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]); 517 if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0)) 518 needpriunat = 1; 519 } 520 unat = 0; 521 if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) { 522 status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist); 523 if (status != UWX_OK) 524 return status; 525 unat = (int) val; 526 env->history.special[UWX_REG_PRIUNAT] = hist; 527 TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val) 528 } 529 530 /* Retrieve saved values of the preserved GRs into temporaries. */ 531 532 tempnat = (int) env->context.special[UWX_REG_PRIUNAT]; 533 for (i = 0; i < NSB_GR; i++) { 534 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) { 535 status = uwx_restore_reg(env, 536 env->rstate[SBREG_GR + i], &val, &hist); 537 if (status != UWX_OK) 538 return status; 539 tempgr[i] = val; 540 if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat)) 541 tempnat |= 1 << i; 542 else 543 tempnat &= ~(1 << i); 544 env->history.gr[i] = hist; 545 env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT); 546 TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val) 547 } 548 } 549 550 /* Now we have everything we need to step back to the previous frame. */ 551 552 /* Restore preserved BRs. */ 553 554 for (i = 0; i < NSB_BR; i++) { 555 if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) { 556 status = uwx_restore_reg(env, 557 env->rstate[SBREG_BR + i], &val, &hist); 558 if (status != UWX_OK) 559 return status; 560 env->context.br[i] = val; 561 env->history.br[i] = hist; 562 env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT); 563 TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val) 564 } 565 } 566 567 /* Restore preserved FRs. */ 568 569 if (env->nsbreg == NSBREG) { 570 for (i = 0; i < NSB_FR; i++) { 571 if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) { 572 status = uwx_restore_freg(env, 573 env->rstate[SBREG_FR + i], fval, &hist); 574 if (status != UWX_OK) 575 return status; 576 env->context.fr[i].part0 = fval[0]; 577 env->context.fr[i].part1 = fval[1]; 578 env->history.fr[i] = hist; 579 env->context.valid_frs |= 1 << i; 580 TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval) 581 } 582 } 583 } 584 585 /* Restore other preserved regs. */ 586 587 if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) { 588 status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist); 589 if (status != UWX_OK) 590 return status; 591 env->context.special[UWX_REG_PREDS] = val; 592 env->history.special[UWX_REG_PREDS] = hist; 593 env->context.valid_regs |= 1 << UWX_REG_PREDS; 594 TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val) 595 } 596 if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) { 597 status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist); 598 if (status != UWX_OK) 599 return status; 600 env->context.special[UWX_REG_AR_RNAT] = val; 601 env->history.special[UWX_REG_AR_RNAT] = hist; 602 env->context.valid_regs |= 1 << UWX_REG_AR_RNAT; 603 TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val) 604 } 605 if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) { 606 status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist); 607 if (status != UWX_OK) 608 return status; 609 env->context.special[UWX_REG_AR_UNAT] = val; 610 env->history.special[UWX_REG_AR_UNAT] = hist; 611 env->context.valid_regs |= 1 << UWX_REG_AR_UNAT; 612 TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val) 613 } 614 if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) { 615 status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist); 616 if (status != UWX_OK) 617 return status; 618 env->context.special[UWX_REG_AR_FPSR] = val; 619 env->history.special[UWX_REG_AR_FPSR] = hist; 620 env->context.valid_regs |= 1 << UWX_REG_AR_FPSR; 621 TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val) 622 } 623 if (env->rstate[SBREG_LC] != UWX_DISP_NONE) { 624 status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist); 625 if (status != UWX_OK) 626 return status; 627 env->context.special[UWX_REG_AR_LC] = val; 628 env->history.special[UWX_REG_AR_LC] = hist; 629 env->context.valid_regs |= 1 << UWX_REG_AR_LC; 630 TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val) 631 } 632 633 /* Restore preserved GRs from temporaries. */ 634 635 for (i = 0; i < NSB_GR; i++) { 636 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) 637 env->context.gr[i] = tempgr[i]; 638 } 639 env->context.special[UWX_REG_PRIUNAT] = tempnat; 640 641 /* Restore the frame markers. */ 642 643 env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP]; 644 env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP]; 645 646 env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP]; 647 env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP]; 648 649 pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f; 650 env->context.special[UWX_REG_BSP] = uwx_add_to_bsp( 651 env->context.special[UWX_REG_BSP], 652 -pfs_sol); 653 654 env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS]; 655 env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS]; 656 657 env->context.special[UWX_REG_RP] = 0; 658 659 /* The frame info for the new frame isn't yet available. */ 660 661 env->rstate = 0; 662 env->context.valid_regs &= ~VALID_MARKERS; 663 664 return UWX_OK; 665} 666 667 668/* uwx_decode_uvec: Converts the update vector into a register state array */ 669 670int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate) 671{ 672 int i; 673 int status; 674 675 status = uwx_default_rstate(env, rstate); 676 if (status != UWX_OK) 677 return status; 678 679 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 680 switch ((int)uvec[i]) { 681 case UWX_KEY_CONTEXT: 682 env->abi_context = (int)(uvec[i+1]); 683 status = UWX_ABI_FRAME; 684 break; 685 case UWX_KEY_GP: 686 uwx_set_reg(env, UWX_REG_GP, uvec[i+1]); 687 break; 688 case UWX_KEY_MODULE: 689 env->module_name = 690 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 691 break; 692 case UWX_KEY_FUNC: 693 env->function_name = 694 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 695 break; 696 case UWX_KEY_FUNCSTART: 697 env->function_offset = env->remapped_ip - uvec[i+1]; 698 break; 699 default: 700 return UWX_ERR_CANTUNWIND; 701 } 702 } 703 return status; 704} 705 706 707/* uwx_restore_reg: Restores a register according to the scoreboard */ 708 709#define COPYIN_MSTACK_8(dest, src) \ 710 (env->remote? \ 711 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ 712 DWORDSZ, env->cb_token) : \ 713 (*(uint64_t *)(intptr_t)(dest) = \ 714 *(uint64_t *)(intptr_t)(src), DWORDSZ) ) 715 716int uwx_restore_reg(struct uwx_env *env, uint64_t rstate, 717 uint64_t *valp, uint64_t *histp) 718{ 719 int status; 720 uint64_t p; 721 int n; 722 int regid; 723 724 status = UWX_OK; 725 726 switch (UWX_GET_DISP_CODE(rstate)) { 727 case UWX_DISP_SPPLUS(0): 728 *valp = env->context.special[UWX_REG_SP] + 729 UWX_GET_DISP_OFFSET(rstate); 730 *histp = UWX_DISP_NONE; 731 break; 732 case UWX_DISP_SPREL(0): 733 p = env->context.special[UWX_REG_SP] + 734 UWX_GET_DISP_OFFSET(rstate); 735 n = COPYIN_MSTACK_8((char *)valp, p); 736 if (n != DWORDSZ) 737 status = UWX_ERR_COPYIN_MSTK; 738 *histp = UWX_DISP_MSTK(p); 739 break; 740 case UWX_DISP_PSPREL(0): 741 p = env->context.special[UWX_REG_PSP] + 16 - 742 UWX_GET_DISP_OFFSET(rstate); 743 n = COPYIN_MSTACK_8((char *)valp, p); 744 if (n != DWORDSZ) 745 status = UWX_ERR_COPYIN_MSTK; 746 *histp = UWX_DISP_MSTK(p); 747 break; 748 case UWX_DISP_REG(0): 749 regid = UWX_GET_DISP_REGID(rstate); 750 status = uwx_get_reg(env, regid, valp); 751 (void) uwx_get_spill_loc(env, regid, histp); 752 break; 753 } 754 return status; 755} 756 757#define COPYIN_MSTACK_16(dest, src) \ 758 (env->remote? \ 759 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ 760 2*DWORDSZ, env->cb_token) : \ 761 (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), \ 762 *(uint64_t *)(intptr_t)((dest)+8) = \ 763 *(uint64_t *)(intptr_t)((src)+8), \ 764 2*DWORDSZ) ) 765 766int uwx_restore_freg(struct uwx_env *env, uint64_t rstate, 767 uint64_t *valp, uint64_t *histp) 768{ 769 int status; 770 uint64_t p; 771 int n; 772 int regid; 773 774 status = UWX_OK; 775 776 switch (UWX_GET_DISP_CODE(rstate)) { 777 case UWX_DISP_SPREL(0): 778 p = env->context.special[UWX_REG_SP] + 779 UWX_GET_DISP_OFFSET(rstate); 780 n = COPYIN_MSTACK_16((char *)valp, p); 781 if (n != 2*DWORDSZ) 782 status = UWX_ERR_COPYIN_MSTK; 783 *histp = UWX_DISP_MSTK(p); 784 break; 785 case UWX_DISP_PSPREL(0): 786 p = env->context.special[UWX_REG_PSP] + 16 - 787 UWX_GET_DISP_OFFSET(rstate); 788 n = COPYIN_MSTACK_16((char *)valp, p); 789 if (n != 2*DWORDSZ) 790 status = UWX_ERR_COPYIN_MSTK; 791 *histp = UWX_DISP_MSTK(p); 792 break; 793 case UWX_DISP_REG(0): 794 regid = UWX_GET_DISP_REGID(rstate); 795 status = uwx_get_reg(env, regid, valp); 796 (void) uwx_get_spill_loc(env, regid, histp); 797 break; 798 } 799 return status; 800} 801 802/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */ 803 804int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat) 805{ 806 int nat; 807 uint64_t p; 808 809 nat = 0; 810 switch (UWX_GET_DISP_CODE(rstate)) { 811 case UWX_DISP_SPREL(0): 812 p = env->context.special[UWX_REG_SP] + 813 UWX_GET_DISP_OFFSET(rstate); 814 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; 815 break; 816 case UWX_DISP_PSPREL(0): 817 p = env->context.special[UWX_REG_PSP] + 16 - 818 UWX_GET_DISP_OFFSET(rstate); 819 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; 820 break; 821 case UWX_DISP_REG(0): 822 (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat); 823 break; 824 } 825 return nat; 826} 827 828