uwx_step.c revision 121642
1/* 2Copyright (c) 2003 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_context.h" 27#include "uwx_utable.h" 28#include "uwx_uinfo.h" 29#include "uwx_scoreboard.h" 30#include "uwx_str.h" 31#include "uwx_step.h" 32#include "uwx_trace.h" 33 34/* 35 * uwx_step.c 36 * 37 * This file contains the routines for stepping from one frame 38 * into its callers frame. The context for the current frame 39 * is maintained inside the current unwind environment 40 * (struct uwx_env), and is updated with each call to 41 * uwx_step() to refer to the previous frame. 42 */ 43 44 45/* Forward Declarations */ 46 47int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate); 48int uwx_restore_reg(struct uwx_env *env, uint64_t rstate, 49 uint64_t *valp, uint64_t *histp); 50int uwx_restore_freg(struct uwx_env *env, uint64_t rstate, 51 uint64_t *valp, uint64_t *histp); 52int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat); 53 54 55/* uwx_get_frame_info: Gets unwind info for current frame */ 56static 57int uwx_get_frame_info(struct uwx_env *env) 58{ 59 int i; 60 int status; 61 int cbstatus; 62 uint64_t *uvec; 63 uint64_t *rstate; 64 struct uwx_utable_entry uentry; 65 uint64_t uvecout[4]; 66 67 if (env->copyin == 0 || env->lookupip == 0) 68 return UWX_ERR_NOCALLBACKS; 69 70 env->function_offset = -1LL; 71 env->function_name = 0; 72 env->module_name = 0; 73 uwx_reset_str_pool(env); 74 75 /* Use the lookup IP callback routine to find out about the */ 76 /* current IP. If the predicate registers are valid, pass them */ 77 /* in the uvec. */ 78 79 i = 0; 80 if (env->context.valid_regs & (1 << UWX_REG_PREDS)) { 81 uvecout[i++] = UWX_KEY_PREDS; 82 uvecout[i++] = env->context.special[UWX_REG_PREDS]; 83 } 84 uvecout[i++] = UWX_KEY_END; 85 uvecout[i++] = 0; 86 uvec = uvecout; 87 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, 88 env->context.special[UWX_REG_IP], env->cb_token, &uvec); 89 90 /* If NOTFOUND, there's nothing we can do but return an error. */ 91 92 if (cbstatus == UWX_LKUP_NOTFOUND) { 93 status = UWX_ERR_IPNOTFOUND; 94 } 95 96 /* If the callback returns an unwind table, we need to */ 97 /* search the table for an unwind entry that describes the */ 98 /* code region of interest, then decode the unwind information */ 99 /* associated with that unwind table entry, and store the */ 100 /* resulting register state array in the unwind environment */ 101 /* block. */ 102 103 else if (cbstatus == UWX_LKUP_UTABLE) { 104 status = uwx_search_utable(env, uvec, &uentry); 105 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 106 if (status == UWX_OK) 107 status = uwx_decode_uinfo(env, &uentry, &rstate); 108 else if (status == UWX_ERR_NOUENTRY) 109 status = uwx_default_rstate(env, &rstate); 110 if (status == UWX_OK) 111 env->rstate = rstate; 112 } 113 114 /* If the callback returns a frame description (in the form */ 115 /* of an update vector), convert the update vector into a */ 116 /* register state array, then invoke the callback again to */ 117 /* let it free any memory it allocated. */ 118 119 else if (cbstatus == UWX_LKUP_FDESC) { 120 status = uwx_decode_uvec(env, uvec, &rstate); 121 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 122 if (status == UWX_OK) 123 env->rstate = rstate; 124 } 125 126 /* Any other return from the callback is an error. */ 127 128 else { 129 status = UWX_ERR_LOOKUPERR; 130 } 131 return status; 132} 133 134 135/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */ 136 137int uwx_restore_markers(struct uwx_env *env) 138{ 139 int status; 140 uint64_t val; 141 uint64_t hist; 142 143 if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4) 144 return UWX_ERR_NOCONTEXT; 145 146 /* If we haven't already obtained the frame info for the */ 147 /* current frame, get it now. */ 148 149 if (env->rstate == 0) { 150 status = uwx_get_frame_info(env); 151 if (status != UWX_OK) 152 return status; 153 } 154 155 TRACE_S_STEP(env->rstate) 156 157 if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) { 158 status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist); 159 if (status != UWX_OK) 160 return status; 161 env->context.special[UWX_REG_PSP] = val; 162 env->history.special[UWX_REG_PSP] = hist; 163 env->context.valid_regs |= 1 << UWX_REG_PSP; 164 TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val) 165 } 166 167 if (env->rstate[SBREG_RP] != UWX_DISP_NONE) { 168 status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist); 169 if (status != UWX_OK) 170 return status; 171 env->context.special[UWX_REG_RP] = val; 172 env->history.special[UWX_REG_RP] = hist; 173 env->context.valid_regs |= 1 << UWX_REG_RP; 174 TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val) 175 } 176 177 if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) { 178 status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist); 179 if (status != UWX_OK) 180 return status; 181 env->context.special[UWX_REG_PFS] = val; 182 env->history.special[UWX_REG_PFS] = hist; 183 env->context.valid_regs |= 1 << UWX_REG_PFS; 184 TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val) 185 } 186 187 return UWX_OK; 188} 189 190/* uwx_get_sym_info: Gets symbolic info from current frame */ 191 192int uwx_get_sym_info( 193 struct uwx_env *env, 194 char **modp, 195 char **symp, 196 uint64_t *offsetp) 197{ 198 int status; 199 int cbstatus; 200 uint64_t ip; 201 uint64_t *uvec; 202 uint64_t uvecout[2]; 203 int i; 204 205 if (env == 0) 206 return UWX_ERR_NOENV; 207 208 /* If we haven't already obtained the frame info for the */ 209 /* current frame, get it now. */ 210 211 if (env->rstate == 0) { 212 status = uwx_get_frame_info(env); 213 if (status != UWX_OK) 214 return status; 215 } 216 217 /* Get the symbolic information from the lookup IP callback. */ 218 if (env->function_name == 0) { 219 ip = env->context.special[UWX_REG_IP]; 220 i = 0; 221 if (env->function_offset >= 0) { 222 uvecout[i++] = UWX_KEY_FUNCSTART; 223 uvecout[i++] = ip - env->function_offset; 224 } 225 uvecout[i++] = UWX_KEY_END; 226 uvecout[i++] = 0; 227 uvec = uvecout; 228 cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, 229 env->context.special[UWX_REG_IP], env->cb_token, &uvec); 230 231 if (cbstatus == UWX_LKUP_SYMINFO) { 232 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 233 switch ((int)uvec[i]) { 234 case UWX_KEY_MODULE: 235 env->module_name = 236 uwx_alloc_str(env, (char *)(uvec[i+1])); 237 break; 238 case UWX_KEY_FUNC: 239 env->function_name = 240 uwx_alloc_str(env, (char *)(uvec[i+1])); 241 break; 242 case UWX_KEY_FUNCSTART: 243 env->function_offset = ip - uvec[i+1]; 244 break; 245 } 246 } 247 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 248 } 249 } 250 251 *modp = env->module_name; 252 *symp = env->function_name; 253 *offsetp = env->function_offset; 254 255 return UWX_OK; 256} 257 258 259/* uwx_step: Steps from the current frame to the previous frame */ 260 261int uwx_step(struct uwx_env *env) 262{ 263 int i; 264 int status; 265 int pfs_sol; 266 int dispcode; 267 uint64_t val; 268 uint64_t fval[2]; 269 uint64_t hist; 270 uint64_t tempgr[NPRESERVEDGR]; 271 int needpriunat; 272 int unat; 273 int tempnat; 274 275 if (env == 0) 276 return UWX_ERR_NOENV; 277 278 /* Complete the current context by restoring the current values */ 279 /* of psp, rp, and pfs. */ 280 281 if (env->rstate == 0 || 282 (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) { 283 status = uwx_restore_markers(env); 284 if (status != UWX_OK) 285 return status; 286 } 287 288 /* Check for bottom of stack (rp == 0). */ 289 290 if (env->context.special[UWX_REG_RP] == 0) 291 return UWX_BOTTOM; 292 293 /* Find where the primary unat is saved, get a copy. */ 294 /* Then, as we restore the GRs, we'll merge the NaT bits into the */ 295 /* priunat register in the context. */ 296 /* (Make sure we need it, though, before we try to get it, */ 297 /* because the attempt to get it might invoke the copy-in callback. */ 298 /* We don't need the priunat unless one of GR 4-7 was */ 299 /* saved to the memory stack.) */ 300 301 needpriunat = 0; 302 for (i = 0; i < NSB_GR; i++) { 303 dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]); 304 if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0)) 305 needpriunat = 1; 306 } 307 unat = 0; 308 if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) { 309 status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist); 310 if (status != UWX_OK) 311 return status; 312 unat = (int) val; 313 env->history.special[UWX_REG_PRIUNAT] = hist; 314 TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val) 315 } 316 317 /* Retrieve saved values of the preserved GRs into temporaries. */ 318 319 tempnat = (int) env->context.special[UWX_REG_PRIUNAT]; 320 for (i = 0; i < NSB_GR; i++) { 321 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) { 322 status = uwx_restore_reg(env, 323 env->rstate[SBREG_GR + i], &val, &hist); 324 if (status != UWX_OK) 325 return status; 326 tempgr[i] = val; 327 if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat)) 328 tempnat |= 1 << i; 329 else 330 tempnat &= ~(1 << i); 331 env->history.gr[i] = hist; 332 env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT); 333 TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val) 334 } 335 } 336 337 /* Now we have everything we need to step back to the previous frame. */ 338 339 /* Restore preserved BRs. */ 340 341 for (i = 0; i < NSB_BR; i++) { 342 if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) { 343 status = uwx_restore_reg(env, 344 env->rstate[SBREG_BR + i], &val, &hist); 345 if (status != UWX_OK) 346 return status; 347 env->context.br[i] = val; 348 env->history.br[i] = hist; 349 env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT); 350 TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val) 351 } 352 } 353 354 /* Restore preserved FRs. */ 355 356 if (env->nsbreg == NSBREG) { 357 for (i = 0; i < NSB_FR; i++) { 358 if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) { 359 status = uwx_restore_freg(env, 360 env->rstate[SBREG_FR + i], fval, &hist); 361 if (status != UWX_OK) 362 return status; 363 env->context.fr[i].part0 = fval[0]; 364 env->context.fr[i].part1 = fval[1]; 365 env->history.fr[i] = hist; 366 env->context.valid_frs |= 1 << i; 367 TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval) 368 } 369 } 370 } 371 372 /* Restore other preserved regs. */ 373 374 if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) { 375 status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist); 376 if (status != UWX_OK) 377 return status; 378 env->context.special[UWX_REG_PREDS] = val; 379 env->history.special[UWX_REG_PREDS] = hist; 380 env->context.valid_regs |= 1 << UWX_REG_PREDS; 381 TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val) 382 } 383 if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) { 384 status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist); 385 if (status != UWX_OK) 386 return status; 387 env->context.special[UWX_REG_AR_RNAT] = val; 388 env->history.special[UWX_REG_AR_RNAT] = hist; 389 env->context.valid_regs |= 1 << UWX_REG_AR_RNAT; 390 TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val) 391 } 392 if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) { 393 status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist); 394 if (status != UWX_OK) 395 return status; 396 env->context.special[UWX_REG_AR_UNAT] = val; 397 env->history.special[UWX_REG_AR_UNAT] = hist; 398 env->context.valid_regs |= 1 << UWX_REG_AR_UNAT; 399 TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val) 400 } 401 if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) { 402 status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist); 403 if (status != UWX_OK) 404 return status; 405 env->context.special[UWX_REG_AR_FPSR] = val; 406 env->history.special[UWX_REG_AR_FPSR] = hist; 407 env->context.valid_regs |= 1 << UWX_REG_AR_FPSR; 408 TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val) 409 } 410 if (env->rstate[SBREG_LC] != UWX_DISP_NONE) { 411 status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist); 412 if (status != UWX_OK) 413 return status; 414 env->context.special[UWX_REG_AR_LC] = val; 415 env->history.special[UWX_REG_AR_LC] = hist; 416 env->context.valid_regs |= 1 << UWX_REG_AR_LC; 417 TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val) 418 } 419 420 /* Restore preserved GRs from temporaries. */ 421 422 for (i = 0; i < NSB_GR; i++) { 423 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) 424 env->context.gr[i] = tempgr[i]; 425 } 426 env->context.special[UWX_REG_PRIUNAT] = tempnat; 427 428 /* Restore the frame markers. */ 429 430 env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP]; 431 env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP]; 432 433 env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP]; 434 env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP]; 435 436 pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f; 437 env->context.special[UWX_REG_BSP] = uwx_add_to_bsp( 438 env->context.special[UWX_REG_BSP], 439 -pfs_sol); 440 441 env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS]; 442 env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS]; 443 444 env->context.special[UWX_REG_RP] = 0; 445 446 /* The frame info for the new frame isn't yet available. */ 447 448 env->rstate = 0; 449 env->context.valid_regs &= ~VALID_MARKERS; 450 451 return UWX_OK; 452} 453 454 455/* uwx_decode_uvec: Converts the update vector into a register state array */ 456 457int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate) 458{ 459 while (*uvec != 0) { 460 switch ((int)*uvec++) { 461 case UWX_KEY_CONTEXT: 462 env->abi_context = (int)(*uvec++); 463 return UWX_ABI_FRAME; 464 default: 465 return UWX_ERR_CANTUNWIND; 466 } 467 } 468 return UWX_OK; 469} 470 471 472/* uwx_restore_reg: Restores a register according to the scoreboard */ 473 474#define COPYIN_MSTACK_8(dest, src) \ 475 (env->remote? \ 476 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ 477 DWORDSZ, env->cb_token) : \ 478 (*(uint64_t *)(dest) = *(uint64_t *)(src), DWORDSZ) ) 479 480int uwx_restore_reg(struct uwx_env *env, uint64_t rstate, 481 uint64_t *valp, uint64_t *histp) 482{ 483 int status; 484 uint64_t p; 485 int n; 486 int regid; 487 488 status = UWX_OK; 489 490 switch (UWX_GET_DISP_CODE(rstate)) { 491 case UWX_DISP_SPPLUS(0): 492 *valp = env->context.special[UWX_REG_SP] + 493 UWX_GET_DISP_OFFSET(rstate); 494 *histp = UWX_DISP_NONE; 495 break; 496 case UWX_DISP_SPREL(0): 497 p = env->context.special[UWX_REG_SP] + 498 UWX_GET_DISP_OFFSET(rstate); 499 n = COPYIN_MSTACK_8((char *)valp, p); 500 if (n != DWORDSZ) 501 status = UWX_ERR_COPYIN_MSTK; 502 *histp = UWX_DISP_MSTK(p); 503 break; 504 case UWX_DISP_PSPREL(0): 505 p = env->context.special[UWX_REG_PSP] + 16 - 506 UWX_GET_DISP_OFFSET(rstate); 507 n = COPYIN_MSTACK_8((char *)valp, p); 508 if (n != DWORDSZ) 509 status = UWX_ERR_COPYIN_MSTK; 510 *histp = UWX_DISP_MSTK(p); 511 break; 512 case UWX_DISP_REG(0): 513 regid = UWX_GET_DISP_REGID(rstate); 514 status = uwx_get_reg(env, regid, valp); 515 (void) uwx_get_spill_loc(env, regid, histp); 516 break; 517 } 518 return status; 519} 520 521#define COPYIN_MSTACK_16(dest, src) \ 522 (env->remote? \ 523 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ 524 2*DWORDSZ, env->cb_token) : \ 525 (*(uint64_t *)(dest) = *(uint64_t *)(src), \ 526 *(uint64_t *)((dest)+8) = *(uint64_t *)((src)+8), \ 527 2*DWORDSZ) ) 528 529int uwx_restore_freg(struct uwx_env *env, uint64_t rstate, 530 uint64_t *valp, uint64_t *histp) 531{ 532 int status; 533 uint64_t p; 534 int n; 535 int regid; 536 537 status = UWX_OK; 538 539 switch (UWX_GET_DISP_CODE(rstate)) { 540 case UWX_DISP_SPREL(0): 541 p = env->context.special[UWX_REG_SP] + 542 UWX_GET_DISP_OFFSET(rstate); 543 n = COPYIN_MSTACK_16((char *)valp, p); 544 if (n != 2*DWORDSZ) 545 status = UWX_ERR_COPYIN_MSTK; 546 *histp = UWX_DISP_MSTK(p); 547 break; 548 case UWX_DISP_PSPREL(0): 549 p = env->context.special[UWX_REG_PSP] + 16 - 550 UWX_GET_DISP_OFFSET(rstate); 551 n = COPYIN_MSTACK_16((char *)valp, p); 552 if (n != 2*DWORDSZ) 553 status = UWX_ERR_COPYIN_MSTK; 554 *histp = UWX_DISP_MSTK(p); 555 break; 556 case UWX_DISP_REG(0): 557 regid = UWX_GET_DISP_REGID(rstate); 558 status = uwx_get_reg(env, regid, valp); 559 (void) uwx_get_spill_loc(env, regid, histp); 560 break; 561 } 562 return status; 563} 564 565/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */ 566 567int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat) 568{ 569 int nat; 570 uint64_t p; 571 572 nat = 0; 573 switch (UWX_GET_DISP_CODE(rstate)) { 574 case UWX_DISP_SPREL(0): 575 p = env->context.special[UWX_REG_SP] + 576 UWX_GET_DISP_OFFSET(rstate); 577 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; 578 break; 579 case UWX_DISP_PSPREL(0): 580 p = env->context.special[UWX_REG_PSP] + 16 - 581 UWX_GET_DISP_OFFSET(rstate); 582 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; 583 break; 584 case UWX_DISP_REG(0): 585 (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat); 586 break; 587 } 588 return nat; 589} 590 591