1115013Smarcel/* 2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. 3121642SmarcelPermission is hereby granted, free of charge, to any person 4121642Smarcelobtaining a copy of this software and associated documentation 5121642Smarcelfiles (the "Software"), to deal in the Software without 6121642Smarcelrestriction, including without limitation the rights to use, 7121642Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell 8121642Smarcelcopies of the Software, and to permit persons to whom the 9121642SmarcelSoftware is furnished to do so, subject to the following 10121642Smarcelconditions: 11115013Smarcel 12121642SmarcelThe above copyright notice and this permission notice shall be 13121642Smarcelincluded in all copies or substantial portions of the Software. 14121642Smarcel 15121642SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16121642SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17121642SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18121642SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19121642SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20121642SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21121642SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22121642SmarcelOTHER DEALINGS IN THE SOFTWARE. 23121642Smarcel*/ 24121642Smarcel 25115013Smarcel#include "uwx_env.h" 26115013Smarcel#include "uwx_utable.h" 27115013Smarcel#include "uwx_uinfo.h" 28115013Smarcel#include "uwx_scoreboard.h" 29115013Smarcel#include "uwx_str.h" 30120925Smarcel#include "uwx_step.h" 31115013Smarcel#include "uwx_trace.h" 32115013Smarcel 33115013Smarcel/* 34115013Smarcel * uwx_step.c 35115013Smarcel * 36115013Smarcel * This file contains the routines for stepping from one frame 37115013Smarcel * into its callers frame. The context for the current frame 38115013Smarcel * is maintained inside the current unwind environment 39115013Smarcel * (struct uwx_env), and is updated with each call to 40115013Smarcel * uwx_step() to refer to the previous frame. 41115013Smarcel */ 42115013Smarcel 43115013Smarcel 44115013Smarcel/* Forward Declarations */ 45115013Smarcel 46115013Smarcelint uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate); 47115013Smarcelint uwx_restore_reg(struct uwx_env *env, uint64_t rstate, 48115013Smarcel uint64_t *valp, uint64_t *histp); 49120925Smarcelint uwx_restore_freg(struct uwx_env *env, uint64_t rstate, 50120925Smarcel uint64_t *valp, uint64_t *histp); 51115013Smarcelint uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat); 52115013Smarcel 53115013Smarcel 54129059Smarcel/* uwx_lookupip_hook: Hook routine so dynamic instrumentation */ 55129059Smarcel/* tools can intercept Lookup IP events. When not */ 56129059Smarcel/* intercepted, it just returns "Not found", so that */ 57129059Smarcel/* the callback routine is invoked. */ 58129059Smarcel 59129059Smarcel/*ARGSUSED*/ 60129059Smarcelint uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp, 61129059Smarcel size_t uvecsize) 62129059Smarcel{ 63129059Smarcel return UWX_LKUP_NOTFOUND; 64129059Smarcel} 65129059Smarcel 66129059Smarcel 67115013Smarcel/* uwx_get_frame_info: Gets unwind info for current frame */ 68160163Smarcelstatic 69115013Smarcelint uwx_get_frame_info(struct uwx_env *env) 70115013Smarcel{ 71115013Smarcel int i; 72115013Smarcel int status; 73115013Smarcel int cbstatus; 74129059Smarcel int cbcalled = 0; 75129059Smarcel uint64_t ip; 76115013Smarcel uint64_t *uvec; 77115013Smarcel uint64_t *rstate; 78115013Smarcel struct uwx_utable_entry uentry; 79129059Smarcel uint64_t uvecout[UVECSIZE]; 80115013Smarcel 81115013Smarcel if (env->copyin == 0 || env->lookupip == 0) 82115013Smarcel return UWX_ERR_NOCALLBACKS; 83115013Smarcel 84160157Smarcel env->ptr_size = DWORDSZ; 85160157Smarcel env->code_start = 0; 86115013Smarcel env->function_offset = -1LL; 87115013Smarcel env->function_name = 0; 88115013Smarcel env->module_name = 0; 89160157Smarcel env->abi_context = 0; 90115013Smarcel uwx_reset_str_pool(env); 91115013Smarcel 92115013Smarcel /* Use the lookup IP callback routine to find out about the */ 93115013Smarcel /* current IP. If the predicate registers are valid, pass them */ 94115013Smarcel /* in the uvec. */ 95115013Smarcel 96129059Smarcel /* When self-unwinding, we call a hook routine before the */ 97129059Smarcel /* callback. If the application is running under control of */ 98129059Smarcel /* a dynamic instrumentation tool, that tool will have an */ 99129059Smarcel /* opportunity to intercept lookup IP requests. */ 100129059Smarcel 101115013Smarcel i = 0; 102129059Smarcel uvecout[i++] = UWX_KEY_VERSION; 103129059Smarcel uvecout[i++] = UWX_VERSION; 104115013Smarcel if (env->context.valid_regs & (1 << UWX_REG_PREDS)) { 105115013Smarcel uvecout[i++] = UWX_KEY_PREDS; 106115013Smarcel uvecout[i++] = env->context.special[UWX_REG_PREDS]; 107115013Smarcel } 108115013Smarcel uvecout[i++] = UWX_KEY_END; 109115013Smarcel uvecout[i++] = 0; 110115013Smarcel uvec = uvecout; 111129059Smarcel cbstatus = UWX_LKUP_NOTFOUND; 112129059Smarcel ip = env->context.special[UWX_REG_IP]; 113129059Smarcel env->remapped_ip = ip; 114115013Smarcel 115129059Smarcel /* Call the hook routine. */ 116129059Smarcel 117129059Smarcel if (env->remote == 0) 118129059Smarcel cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec, 119129059Smarcel sizeof(uvecout)); 120129059Smarcel 121129059Smarcel /* If the hook routine remapped the IP, use the new IP for */ 122129059Smarcel /* the callback instead of the original IP. */ 123129059Smarcel 124129059Smarcel if (cbstatus == UWX_LKUP_REMAP) { 125129059Smarcel for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 126129059Smarcel switch ((int)uvec[i]) { 127129059Smarcel case UWX_KEY_NEWIP: 128129059Smarcel ip = uvec[i+1]; 129129059Smarcel break; 130129059Smarcel } 131129059Smarcel } 132129059Smarcel env->remapped_ip = ip; 133129059Smarcel } 134129059Smarcel 135129059Smarcel /* Now call the callback routine unless the hook routine gave */ 136129059Smarcel /* us all the info. */ 137129059Smarcel 138129059Smarcel if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) { 139129059Smarcel cbcalled = 1; 140129059Smarcel cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec); 141129059Smarcel } 142129059Smarcel 143129059Smarcel /* If the callback routine remapped the IP, call it one more time */ 144129059Smarcel /* with the new IP. */ 145129059Smarcel 146129059Smarcel if (cbstatus == UWX_LKUP_REMAP) { 147129059Smarcel for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 148129059Smarcel switch ((int)uvec[i]) { 149129059Smarcel case UWX_KEY_NEWIP: 150129059Smarcel ip = uvec[i+1]; 151129059Smarcel break; 152129059Smarcel } 153129059Smarcel } 154129059Smarcel env->remapped_ip = ip; 155129059Smarcel cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec); 156129059Smarcel } 157129059Smarcel 158115013Smarcel /* If NOTFOUND, there's nothing we can do but return an error. */ 159115013Smarcel 160115013Smarcel if (cbstatus == UWX_LKUP_NOTFOUND) { 161115013Smarcel status = UWX_ERR_IPNOTFOUND; 162115013Smarcel } 163115013Smarcel 164115013Smarcel /* If the callback returns an unwind table, we need to */ 165115013Smarcel /* search the table for an unwind entry that describes the */ 166115013Smarcel /* code region of interest, then decode the unwind information */ 167115013Smarcel /* associated with that unwind table entry, and store the */ 168115013Smarcel /* resulting register state array in the unwind environment */ 169115013Smarcel /* block. */ 170115013Smarcel 171115013Smarcel else if (cbstatus == UWX_LKUP_UTABLE) { 172129059Smarcel status = uwx_search_utable(env, ip, uvec, &uentry); 173129059Smarcel if (cbcalled) 174129059Smarcel (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 175160157Smarcel if (status == UWX_OK) { 176160157Smarcel env->ptr_size = uentry.ptr_size; 177160157Smarcel env->code_start = uentry.code_start; 178115013Smarcel status = uwx_decode_uinfo(env, &uentry, &rstate); 179160157Smarcel } 180160157Smarcel if (status == UWX_ERR_NOUENTRY || status == UWX_ERR_NOUDESC) 181115013Smarcel status = uwx_default_rstate(env, &rstate); 182115013Smarcel if (status == UWX_OK) 183115013Smarcel env->rstate = rstate; 184115013Smarcel } 185115013Smarcel 186129059Smarcel /* If the callback returns an unwind info block, we can */ 187129059Smarcel /* proceed directly to decoding the unwind information. */ 188129059Smarcel 189129059Smarcel else if (cbstatus == UWX_LKUP_UINFO) { 190160157Smarcel uentry.ptr_size = DWORDSZ; 191129059Smarcel uentry.code_start = 0; 192129059Smarcel uentry.code_end = 0; 193129059Smarcel uentry.unwind_info = 0; 194129059Smarcel uentry.unwind_flags = 0; 195129059Smarcel for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 196129059Smarcel switch ((int)uvec[i]) { 197129059Smarcel case UWX_KEY_UFLAGS: 198129059Smarcel uentry.unwind_flags = uvec[i+1]; 199160157Smarcel if (uentry.unwind_flags & UNWIND_TBL_32BIT) 200160157Smarcel uentry.ptr_size = WORDSZ; 201129059Smarcel break; 202129059Smarcel case UWX_KEY_UINFO: 203129059Smarcel uentry.unwind_info = uvec[i+1]; 204129059Smarcel break; 205160157Smarcel case UWX_KEY_GP: 206160157Smarcel uwx_set_reg(env, UWX_REG_GP, uvec[i+1]); 207160157Smarcel break; 208129059Smarcel case UWX_KEY_MODULE: 209129059Smarcel env->module_name = 210160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 211129059Smarcel break; 212129059Smarcel case UWX_KEY_FUNC: 213129059Smarcel env->function_name = 214160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 215129059Smarcel break; 216129059Smarcel case UWX_KEY_FUNCSTART: 217129059Smarcel uentry.code_start = uvec[i+1]; 218160157Smarcel env->code_start = uentry.code_start; 219129059Smarcel break; 220129059Smarcel } 221129059Smarcel } 222160157Smarcel env->ptr_size = uentry.ptr_size; 223129059Smarcel if (cbcalled) 224129059Smarcel (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 225129059Smarcel status = uwx_decode_uinfo(env, &uentry, &rstate); 226160157Smarcel if (status == UWX_ERR_NOUDESC) 227160157Smarcel status = uwx_default_rstate(env, &rstate); 228129059Smarcel if (status == UWX_OK) 229129059Smarcel env->rstate = rstate; 230129059Smarcel } 231129059Smarcel 232115013Smarcel /* If the callback returns a frame description (in the form */ 233115013Smarcel /* of an update vector), convert the update vector into a */ 234115013Smarcel /* register state array, then invoke the callback again to */ 235115013Smarcel /* let it free any memory it allocated. */ 236115013Smarcel 237115013Smarcel else if (cbstatus == UWX_LKUP_FDESC) { 238115013Smarcel status = uwx_decode_uvec(env, uvec, &rstate); 239129059Smarcel if (cbcalled) 240129059Smarcel (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 241115013Smarcel if (status == UWX_OK) 242115013Smarcel env->rstate = rstate; 243115013Smarcel } 244115013Smarcel 245115013Smarcel /* Any other return from the callback is an error. */ 246115013Smarcel 247115013Smarcel else { 248115013Smarcel status = UWX_ERR_LOOKUPERR; 249115013Smarcel } 250115013Smarcel return status; 251115013Smarcel} 252115013Smarcel 253115013Smarcel 254120925Smarcel/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */ 255120925Smarcel 256120925Smarcelint uwx_restore_markers(struct uwx_env *env) 257120925Smarcel{ 258120925Smarcel int status; 259120925Smarcel uint64_t val; 260120925Smarcel uint64_t hist; 261120925Smarcel 262120925Smarcel if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4) 263120925Smarcel return UWX_ERR_NOCONTEXT; 264120925Smarcel 265120925Smarcel /* If we haven't already obtained the frame info for the */ 266120925Smarcel /* current frame, get it now. */ 267120925Smarcel 268120925Smarcel if (env->rstate == 0) { 269120925Smarcel status = uwx_get_frame_info(env); 270120925Smarcel if (status != UWX_OK) 271120925Smarcel return status; 272120925Smarcel } 273120925Smarcel 274120925Smarcel TRACE_S_STEP(env->rstate) 275120925Smarcel 276120925Smarcel if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) { 277120925Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist); 278120925Smarcel if (status != UWX_OK) 279120925Smarcel return status; 280120925Smarcel env->context.special[UWX_REG_PSP] = val; 281120925Smarcel env->history.special[UWX_REG_PSP] = hist; 282120925Smarcel env->context.valid_regs |= 1 << UWX_REG_PSP; 283120925Smarcel TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val) 284120925Smarcel } 285120925Smarcel 286120925Smarcel if (env->rstate[SBREG_RP] != UWX_DISP_NONE) { 287120925Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist); 288120925Smarcel if (status != UWX_OK) 289120925Smarcel return status; 290120925Smarcel env->context.special[UWX_REG_RP] = val; 291120925Smarcel env->history.special[UWX_REG_RP] = hist; 292120925Smarcel env->context.valid_regs |= 1 << UWX_REG_RP; 293120925Smarcel TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val) 294120925Smarcel } 295120925Smarcel 296120925Smarcel if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) { 297120925Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist); 298120925Smarcel if (status != UWX_OK) 299120925Smarcel return status; 300120925Smarcel env->context.special[UWX_REG_PFS] = val; 301120925Smarcel env->history.special[UWX_REG_PFS] = hist; 302120925Smarcel env->context.valid_regs |= 1 << UWX_REG_PFS; 303120925Smarcel TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val) 304120925Smarcel } 305120925Smarcel 306120925Smarcel return UWX_OK; 307120925Smarcel} 308120925Smarcel 309160157Smarcel/* uwx_get_module_info: Gets module name and text base for current frame */ 310160157Smarcel 311160157Smarcelint uwx_get_module_info( 312160157Smarcel struct uwx_env *env, 313160157Smarcel char **modp, 314160157Smarcel uint64_t *text_base) 315160157Smarcel{ 316160157Smarcel int i; 317160157Smarcel int status; 318160157Smarcel int cbstatus; 319160157Smarcel uint64_t ip; 320160157Smarcel uint64_t *uvec; 321160157Smarcel uint64_t uvecout[UVECSIZE]; 322160157Smarcel 323160157Smarcel if (env == 0) 324160157Smarcel return UWX_ERR_NOENV; 325160157Smarcel 326160157Smarcel /* If we haven't already obtained the frame info for the */ 327160157Smarcel /* current frame, get it now. */ 328160157Smarcel 329160157Smarcel if (env->rstate == 0) { 330160157Smarcel status = uwx_get_frame_info(env); 331160157Smarcel if (status != UWX_OK) 332160157Smarcel return status; 333160157Smarcel } 334160157Smarcel 335160157Smarcel /* Get the module name from the lookup IP callback. */ 336160157Smarcel if (env->module_name == 0) { 337160157Smarcel ip = env->remapped_ip; 338160157Smarcel i = 0; 339160157Smarcel if (env->function_offset >= 0) { 340160157Smarcel uvecout[i++] = UWX_KEY_FUNCSTART; 341160157Smarcel uvecout[i++] = ip - env->function_offset; 342160157Smarcel } 343160157Smarcel uvecout[i++] = UWX_KEY_END; 344160157Smarcel uvecout[i++] = 0; 345160157Smarcel uvec = uvecout; 346160157Smarcel cbstatus = (*env->lookupip)(UWX_LKUP_MODULE, ip, env->cb_token, &uvec); 347160157Smarcel 348160157Smarcel if (cbstatus == UWX_LKUP_SYMINFO) { 349160157Smarcel for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 350160157Smarcel switch ((int)uvec[i]) { 351160157Smarcel case UWX_KEY_TBASE: 352160157Smarcel env->text_base = uvec[i+1]; 353160157Smarcel break; 354160157Smarcel case UWX_KEY_MODULE: 355160157Smarcel env->module_name = 356160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 357160157Smarcel break; 358160157Smarcel case UWX_KEY_FUNC: 359160157Smarcel env->function_name = 360160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 361160157Smarcel break; 362160157Smarcel case UWX_KEY_FUNCSTART: 363160157Smarcel env->function_offset = ip - uvec[i+1]; 364160157Smarcel break; 365160157Smarcel } 366160157Smarcel } 367160157Smarcel (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 368160157Smarcel } 369160157Smarcel } 370160157Smarcel 371160157Smarcel *modp = env->module_name; 372160157Smarcel *text_base = env->text_base; 373160157Smarcel 374160157Smarcel return UWX_OK; 375160157Smarcel} 376160157Smarcel 377160157Smarcel/* uwx_get_funcstart: Gets start address of function from current frame */ 378160157Smarcel 379160157Smarcelint uwx_get_funcstart( 380160157Smarcel struct uwx_env *env, 381160157Smarcel uint64_t *funcstart) 382160157Smarcel{ 383160157Smarcel int status; 384160157Smarcel 385160157Smarcel if (env == 0) 386160157Smarcel return UWX_ERR_NOENV; 387160157Smarcel 388160157Smarcel /* If we haven't already obtained the frame info for the */ 389160157Smarcel /* current frame, get it now. */ 390160157Smarcel 391160157Smarcel if (env->rstate == 0) { 392160157Smarcel status = uwx_get_frame_info(env); 393160157Smarcel if (status != UWX_OK) 394160157Smarcel return status; 395160157Smarcel } 396160157Smarcel 397160157Smarcel *funcstart = env->remapped_ip - env->function_offset; 398160157Smarcel 399160157Smarcel return UWX_OK; 400160157Smarcel} 401160157Smarcel 402115013Smarcel/* uwx_get_sym_info: Gets symbolic info from current frame */ 403160157Smarcel/* (Will make a UWX_LKUP_SYMBOLS callback if info */ 404160157Smarcel/* was not provided by UWX_LKUP_LOOKUP callback) */ 405120925Smarcel 406115013Smarcelint uwx_get_sym_info( 407115013Smarcel struct uwx_env *env, 408115013Smarcel char **modp, 409115013Smarcel char **symp, 410115013Smarcel uint64_t *offsetp) 411115013Smarcel{ 412115013Smarcel int status; 413115013Smarcel int cbstatus; 414115013Smarcel uint64_t ip; 415115013Smarcel uint64_t *uvec; 416160157Smarcel uint64_t uvecout[UVECSIZE]; 417115013Smarcel int i; 418115013Smarcel 419115013Smarcel if (env == 0) 420115013Smarcel return UWX_ERR_NOENV; 421115013Smarcel 422115013Smarcel /* If we haven't already obtained the frame info for the */ 423115013Smarcel /* current frame, get it now. */ 424115013Smarcel 425115013Smarcel if (env->rstate == 0) { 426115013Smarcel status = uwx_get_frame_info(env); 427115013Smarcel if (status != UWX_OK) 428115013Smarcel return status; 429115013Smarcel } 430115013Smarcel 431115013Smarcel /* Get the symbolic information from the lookup IP callback. */ 432115013Smarcel if (env->function_name == 0) { 433129059Smarcel ip = env->remapped_ip; 434115013Smarcel i = 0; 435115013Smarcel if (env->function_offset >= 0) { 436115013Smarcel uvecout[i++] = UWX_KEY_FUNCSTART; 437115013Smarcel uvecout[i++] = ip - env->function_offset; 438115013Smarcel } 439115013Smarcel uvecout[i++] = UWX_KEY_END; 440115013Smarcel uvecout[i++] = 0; 441115013Smarcel uvec = uvecout; 442129059Smarcel cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec); 443115013Smarcel 444115013Smarcel if (cbstatus == UWX_LKUP_SYMINFO) { 445115013Smarcel for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 446115013Smarcel switch ((int)uvec[i]) { 447115013Smarcel case UWX_KEY_MODULE: 448115013Smarcel env->module_name = 449160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 450115013Smarcel break; 451115013Smarcel case UWX_KEY_FUNC: 452115013Smarcel env->function_name = 453160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 454115013Smarcel break; 455115013Smarcel case UWX_KEY_FUNCSTART: 456115013Smarcel env->function_offset = ip - uvec[i+1]; 457115013Smarcel break; 458115013Smarcel } 459115013Smarcel } 460115013Smarcel (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); 461115013Smarcel } 462115013Smarcel } 463115013Smarcel 464115013Smarcel *modp = env->module_name; 465115013Smarcel *symp = env->function_name; 466115013Smarcel *offsetp = env->function_offset; 467115013Smarcel 468115013Smarcel return UWX_OK; 469115013Smarcel} 470115013Smarcel 471115013Smarcel 472115013Smarcel/* uwx_step: Steps from the current frame to the previous frame */ 473115013Smarcel 474115013Smarcelint uwx_step(struct uwx_env *env) 475115013Smarcel{ 476115013Smarcel int i; 477115013Smarcel int status; 478115013Smarcel int pfs_sol; 479115013Smarcel int dispcode; 480115013Smarcel uint64_t val; 481115013Smarcel uint64_t fval[2]; 482115013Smarcel uint64_t hist; 483115013Smarcel uint64_t tempgr[NPRESERVEDGR]; 484115013Smarcel int needpriunat; 485115013Smarcel int unat; 486115013Smarcel int tempnat; 487115013Smarcel 488115013Smarcel if (env == 0) 489115013Smarcel return UWX_ERR_NOENV; 490115013Smarcel 491115013Smarcel /* Complete the current context by restoring the current values */ 492115013Smarcel /* of psp, rp, and pfs. */ 493115013Smarcel 494120925Smarcel if (env->rstate == 0 || 495120925Smarcel (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) { 496120925Smarcel status = uwx_restore_markers(env); 497115013Smarcel if (status != UWX_OK) 498115013Smarcel return status; 499115013Smarcel } 500115013Smarcel 501115013Smarcel /* Check for bottom of stack (rp == 0). */ 502115013Smarcel 503115013Smarcel if (env->context.special[UWX_REG_RP] == 0) 504115013Smarcel return UWX_BOTTOM; 505115013Smarcel 506115013Smarcel /* Find where the primary unat is saved, get a copy. */ 507115013Smarcel /* Then, as we restore the GRs, we'll merge the NaT bits into the */ 508115013Smarcel /* priunat register in the context. */ 509115013Smarcel /* (Make sure we need it, though, before we try to get it, */ 510115013Smarcel /* because the attempt to get it might invoke the copy-in callback. */ 511115013Smarcel /* We don't need the priunat unless one of GR 4-7 was */ 512115013Smarcel /* saved to the memory stack.) */ 513115013Smarcel 514115013Smarcel needpriunat = 0; 515115013Smarcel for (i = 0; i < NSB_GR; i++) { 516115013Smarcel dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]); 517115013Smarcel if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0)) 518115013Smarcel needpriunat = 1; 519115013Smarcel } 520115013Smarcel unat = 0; 521115013Smarcel if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) { 522115013Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist); 523115013Smarcel if (status != UWX_OK) 524115013Smarcel return status; 525115013Smarcel unat = (int) val; 526115013Smarcel env->history.special[UWX_REG_PRIUNAT] = hist; 527115013Smarcel TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val) 528115013Smarcel } 529115013Smarcel 530115013Smarcel /* Retrieve saved values of the preserved GRs into temporaries. */ 531115013Smarcel 532115013Smarcel tempnat = (int) env->context.special[UWX_REG_PRIUNAT]; 533115013Smarcel for (i = 0; i < NSB_GR; i++) { 534115013Smarcel if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) { 535115013Smarcel status = uwx_restore_reg(env, 536115013Smarcel env->rstate[SBREG_GR + i], &val, &hist); 537115013Smarcel if (status != UWX_OK) 538115013Smarcel return status; 539115013Smarcel tempgr[i] = val; 540115013Smarcel if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat)) 541115013Smarcel tempnat |= 1 << i; 542115013Smarcel else 543115013Smarcel tempnat &= ~(1 << i); 544115013Smarcel env->history.gr[i] = hist; 545115013Smarcel env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT); 546115013Smarcel TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val) 547115013Smarcel } 548115013Smarcel } 549115013Smarcel 550115013Smarcel /* Now we have everything we need to step back to the previous frame. */ 551115013Smarcel 552115013Smarcel /* Restore preserved BRs. */ 553115013Smarcel 554115013Smarcel for (i = 0; i < NSB_BR; i++) { 555115013Smarcel if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) { 556115013Smarcel status = uwx_restore_reg(env, 557115013Smarcel env->rstate[SBREG_BR + i], &val, &hist); 558115013Smarcel if (status != UWX_OK) 559115013Smarcel return status; 560115013Smarcel env->context.br[i] = val; 561115013Smarcel env->history.br[i] = hist; 562115013Smarcel env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT); 563115013Smarcel TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val) 564115013Smarcel } 565115013Smarcel } 566115013Smarcel 567115013Smarcel /* Restore preserved FRs. */ 568115013Smarcel 569115013Smarcel if (env->nsbreg == NSBREG) { 570115013Smarcel for (i = 0; i < NSB_FR; i++) { 571115013Smarcel if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) { 572120925Smarcel status = uwx_restore_freg(env, 573115013Smarcel env->rstate[SBREG_FR + i], fval, &hist); 574115013Smarcel if (status != UWX_OK) 575115013Smarcel return status; 576115013Smarcel env->context.fr[i].part0 = fval[0]; 577115013Smarcel env->context.fr[i].part1 = fval[1]; 578115013Smarcel env->history.fr[i] = hist; 579115013Smarcel env->context.valid_frs |= 1 << i; 580115013Smarcel TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval) 581115013Smarcel } 582115013Smarcel } 583115013Smarcel } 584115013Smarcel 585115013Smarcel /* Restore other preserved regs. */ 586115013Smarcel 587115013Smarcel if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) { 588115013Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist); 589115013Smarcel if (status != UWX_OK) 590115013Smarcel return status; 591115013Smarcel env->context.special[UWX_REG_PREDS] = val; 592115013Smarcel env->history.special[UWX_REG_PREDS] = hist; 593115013Smarcel env->context.valid_regs |= 1 << UWX_REG_PREDS; 594115013Smarcel TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val) 595115013Smarcel } 596115013Smarcel if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) { 597115013Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist); 598115013Smarcel if (status != UWX_OK) 599115013Smarcel return status; 600120925Smarcel env->context.special[UWX_REG_AR_RNAT] = val; 601120925Smarcel env->history.special[UWX_REG_AR_RNAT] = hist; 602120925Smarcel env->context.valid_regs |= 1 << UWX_REG_AR_RNAT; 603115013Smarcel TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val) 604115013Smarcel } 605115013Smarcel if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) { 606115013Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist); 607115013Smarcel if (status != UWX_OK) 608115013Smarcel return status; 609120925Smarcel env->context.special[UWX_REG_AR_UNAT] = val; 610120925Smarcel env->history.special[UWX_REG_AR_UNAT] = hist; 611120925Smarcel env->context.valid_regs |= 1 << UWX_REG_AR_UNAT; 612115013Smarcel TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val) 613115013Smarcel } 614115013Smarcel if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) { 615115013Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist); 616115013Smarcel if (status != UWX_OK) 617115013Smarcel return status; 618120925Smarcel env->context.special[UWX_REG_AR_FPSR] = val; 619120925Smarcel env->history.special[UWX_REG_AR_FPSR] = hist; 620120925Smarcel env->context.valid_regs |= 1 << UWX_REG_AR_FPSR; 621115013Smarcel TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val) 622115013Smarcel } 623115013Smarcel if (env->rstate[SBREG_LC] != UWX_DISP_NONE) { 624115013Smarcel status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist); 625115013Smarcel if (status != UWX_OK) 626115013Smarcel return status; 627120925Smarcel env->context.special[UWX_REG_AR_LC] = val; 628120925Smarcel env->history.special[UWX_REG_AR_LC] = hist; 629120925Smarcel env->context.valid_regs |= 1 << UWX_REG_AR_LC; 630115013Smarcel TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val) 631115013Smarcel } 632115013Smarcel 633115013Smarcel /* Restore preserved GRs from temporaries. */ 634115013Smarcel 635115013Smarcel for (i = 0; i < NSB_GR; i++) { 636115013Smarcel if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) 637115013Smarcel env->context.gr[i] = tempgr[i]; 638115013Smarcel } 639115013Smarcel env->context.special[UWX_REG_PRIUNAT] = tempnat; 640115013Smarcel 641115013Smarcel /* Restore the frame markers. */ 642115013Smarcel 643115013Smarcel env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP]; 644115013Smarcel env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP]; 645115013Smarcel 646115013Smarcel env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP]; 647115013Smarcel env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP]; 648115013Smarcel 649115013Smarcel pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f; 650115013Smarcel env->context.special[UWX_REG_BSP] = uwx_add_to_bsp( 651115013Smarcel env->context.special[UWX_REG_BSP], 652115013Smarcel -pfs_sol); 653115013Smarcel 654115013Smarcel env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS]; 655115013Smarcel env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS]; 656115013Smarcel 657115013Smarcel env->context.special[UWX_REG_RP] = 0; 658115013Smarcel 659115013Smarcel /* The frame info for the new frame isn't yet available. */ 660115013Smarcel 661115013Smarcel env->rstate = 0; 662120925Smarcel env->context.valid_regs &= ~VALID_MARKERS; 663115013Smarcel 664115013Smarcel return UWX_OK; 665115013Smarcel} 666115013Smarcel 667115013Smarcel 668115013Smarcel/* uwx_decode_uvec: Converts the update vector into a register state array */ 669115013Smarcel 670115013Smarcelint uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate) 671115013Smarcel{ 672129059Smarcel int i; 673129059Smarcel int status; 674129059Smarcel 675129059Smarcel status = uwx_default_rstate(env, rstate); 676129059Smarcel if (status != UWX_OK) 677129059Smarcel return status; 678129059Smarcel 679129059Smarcel for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { 680129059Smarcel switch ((int)uvec[i]) { 681115013Smarcel case UWX_KEY_CONTEXT: 682129059Smarcel env->abi_context = (int)(uvec[i+1]); 683129059Smarcel status = UWX_ABI_FRAME; 684129059Smarcel break; 685160157Smarcel case UWX_KEY_GP: 686160157Smarcel uwx_set_reg(env, UWX_REG_GP, uvec[i+1]); 687160157Smarcel break; 688129059Smarcel case UWX_KEY_MODULE: 689129059Smarcel env->module_name = 690160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 691129059Smarcel break; 692129059Smarcel case UWX_KEY_FUNC: 693129059Smarcel env->function_name = 694160157Smarcel uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); 695129059Smarcel break; 696129059Smarcel case UWX_KEY_FUNCSTART: 697129059Smarcel env->function_offset = env->remapped_ip - uvec[i+1]; 698129059Smarcel break; 699115013Smarcel default: 700115013Smarcel return UWX_ERR_CANTUNWIND; 701115013Smarcel } 702115013Smarcel } 703129059Smarcel return status; 704115013Smarcel} 705115013Smarcel 706115013Smarcel 707115013Smarcel/* uwx_restore_reg: Restores a register according to the scoreboard */ 708115013Smarcel 709115013Smarcel#define COPYIN_MSTACK_8(dest, src) \ 710115013Smarcel (env->remote? \ 711115013Smarcel (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ 712115013Smarcel DWORDSZ, env->cb_token) : \ 713160157Smarcel (*(uint64_t *)(intptr_t)(dest) = \ 714160157Smarcel *(uint64_t *)(intptr_t)(src), DWORDSZ) ) 715115013Smarcel 716115013Smarcelint uwx_restore_reg(struct uwx_env *env, uint64_t rstate, 717115013Smarcel uint64_t *valp, uint64_t *histp) 718115013Smarcel{ 719115013Smarcel int status; 720115013Smarcel uint64_t p; 721115013Smarcel int n; 722115013Smarcel int regid; 723115013Smarcel 724115013Smarcel status = UWX_OK; 725115013Smarcel 726115013Smarcel switch (UWX_GET_DISP_CODE(rstate)) { 727115013Smarcel case UWX_DISP_SPPLUS(0): 728115013Smarcel *valp = env->context.special[UWX_REG_SP] + 729115013Smarcel UWX_GET_DISP_OFFSET(rstate); 730115013Smarcel *histp = UWX_DISP_NONE; 731115013Smarcel break; 732115013Smarcel case UWX_DISP_SPREL(0): 733115013Smarcel p = env->context.special[UWX_REG_SP] + 734115013Smarcel UWX_GET_DISP_OFFSET(rstate); 735115013Smarcel n = COPYIN_MSTACK_8((char *)valp, p); 736115013Smarcel if (n != DWORDSZ) 737115013Smarcel status = UWX_ERR_COPYIN_MSTK; 738115013Smarcel *histp = UWX_DISP_MSTK(p); 739115013Smarcel break; 740115013Smarcel case UWX_DISP_PSPREL(0): 741115013Smarcel p = env->context.special[UWX_REG_PSP] + 16 - 742115013Smarcel UWX_GET_DISP_OFFSET(rstate); 743115013Smarcel n = COPYIN_MSTACK_8((char *)valp, p); 744115013Smarcel if (n != DWORDSZ) 745115013Smarcel status = UWX_ERR_COPYIN_MSTK; 746115013Smarcel *histp = UWX_DISP_MSTK(p); 747115013Smarcel break; 748115013Smarcel case UWX_DISP_REG(0): 749115013Smarcel regid = UWX_GET_DISP_REGID(rstate); 750115013Smarcel status = uwx_get_reg(env, regid, valp); 751115013Smarcel (void) uwx_get_spill_loc(env, regid, histp); 752115013Smarcel break; 753115013Smarcel } 754115013Smarcel return status; 755115013Smarcel} 756115013Smarcel 757120925Smarcel#define COPYIN_MSTACK_16(dest, src) \ 758120925Smarcel (env->remote? \ 759120925Smarcel (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ 760120925Smarcel 2*DWORDSZ, env->cb_token) : \ 761160157Smarcel (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), \ 762160157Smarcel *(uint64_t *)(intptr_t)((dest)+8) = \ 763160157Smarcel *(uint64_t *)(intptr_t)((src)+8), \ 764160157Smarcel 2*DWORDSZ) ) 765120925Smarcel 766120925Smarcelint uwx_restore_freg(struct uwx_env *env, uint64_t rstate, 767120925Smarcel uint64_t *valp, uint64_t *histp) 768120925Smarcel{ 769120925Smarcel int status; 770120925Smarcel uint64_t p; 771120925Smarcel int n; 772120925Smarcel int regid; 773120925Smarcel 774120925Smarcel status = UWX_OK; 775120925Smarcel 776120925Smarcel switch (UWX_GET_DISP_CODE(rstate)) { 777120925Smarcel case UWX_DISP_SPREL(0): 778120925Smarcel p = env->context.special[UWX_REG_SP] + 779120925Smarcel UWX_GET_DISP_OFFSET(rstate); 780120925Smarcel n = COPYIN_MSTACK_16((char *)valp, p); 781120925Smarcel if (n != 2*DWORDSZ) 782120925Smarcel status = UWX_ERR_COPYIN_MSTK; 783120925Smarcel *histp = UWX_DISP_MSTK(p); 784120925Smarcel break; 785120925Smarcel case UWX_DISP_PSPREL(0): 786120925Smarcel p = env->context.special[UWX_REG_PSP] + 16 - 787120925Smarcel UWX_GET_DISP_OFFSET(rstate); 788120925Smarcel n = COPYIN_MSTACK_16((char *)valp, p); 789120925Smarcel if (n != 2*DWORDSZ) 790120925Smarcel status = UWX_ERR_COPYIN_MSTK; 791120925Smarcel *histp = UWX_DISP_MSTK(p); 792120925Smarcel break; 793120925Smarcel case UWX_DISP_REG(0): 794120925Smarcel regid = UWX_GET_DISP_REGID(rstate); 795120925Smarcel status = uwx_get_reg(env, regid, valp); 796120925Smarcel (void) uwx_get_spill_loc(env, regid, histp); 797120925Smarcel break; 798120925Smarcel } 799120925Smarcel return status; 800120925Smarcel} 801120925Smarcel 802115013Smarcel/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */ 803115013Smarcel 804115013Smarcelint uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat) 805115013Smarcel{ 806115013Smarcel int nat; 807115013Smarcel uint64_t p; 808115013Smarcel 809115013Smarcel nat = 0; 810115013Smarcel switch (UWX_GET_DISP_CODE(rstate)) { 811115013Smarcel case UWX_DISP_SPREL(0): 812115013Smarcel p = env->context.special[UWX_REG_SP] + 813115013Smarcel UWX_GET_DISP_OFFSET(rstate); 814115013Smarcel nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; 815115013Smarcel break; 816115013Smarcel case UWX_DISP_PSPREL(0): 817115013Smarcel p = env->context.special[UWX_REG_PSP] + 16 - 818115013Smarcel UWX_GET_DISP_OFFSET(rstate); 819115013Smarcel nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; 820115013Smarcel break; 821115013Smarcel case UWX_DISP_REG(0): 822115013Smarcel (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat); 823115013Smarcel break; 824115013Smarcel } 825115013Smarcel return nat; 826115013Smarcel} 827115013Smarcel 828