uwx_self.c revision 160157
194670Sdes/* 2115619SdesCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. 3267014SdelphijPermission is hereby granted, free of charge, to any person 494670Sdesobtaining a copy of this software and associated documentation 594670Sdesfiles (the "Software"), to deal in the Software without 694670Sdesrestriction, including without limitation the rights to use, 799158Sdescopy, modify, merge, publish, distribute, sublicense, and/or sell 899158Sdescopies of the Software, and to permit persons to whom the 999158SdesSoftware is furnished to do so, subject to the following 1094670Sdesconditions: 1194670Sdes 1294670SdesThe above copyright notice and this permission notice shall be 1394670Sdesincluded in all copies or substantial portions of the Software. 1494670Sdes 1594670SdesTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1694670SdesEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 1794670SdesOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1894670SdesNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 1994670SdesHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 2094670SdesWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2194670SdesFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2294670SdesOTHER DEALINGS IN THE SOFTWARE. 2394670Sdes*/ 2494670Sdes 2594670Sdes#include <stdlib.h> 2694670Sdes#include <string.h> 2794670Sdes#include <crt0.h> 2894670Sdes#include <dlfcn.h> 2994670Sdes#include <sys/uc_access.h> 3094670Sdes 3194670Sdes#include "uwx_env.h" 3294670Sdes#include "uwx_context.h" 3394670Sdes#include "uwx_trace.h" 3494670Sdes#include "uwx_self.h" 35271947Sdes#include "uwx_self_info.h" 3694670Sdes 3794670Sdes#define UWX_ABI_HPUX_SIGCONTEXT 0x0101 /* abi = HP-UX, context = 1 */ 38228690Sdes 39228690Sdesvoid uwx_free_load_module_cache(struct uwx_self_info *info); 40228690Sdes 41228690Sdesint uwx_self_init_info_block(struct uwx_env *env, struct uwx_self_info *info) 42236099Sdes{ 43236099Sdes info->env = env; 4494670Sdes info->ucontext = 0; 4594670Sdes info->bspstore = 0; 4694670Sdes info->sendsig_start = __load_info->li_sendsig_txt; 4794670Sdes info->sendsig_end = __load_info->li_sendsig_txt + 4894670Sdes __load_info->li_sendsig_tsz; 4994670Sdes info->on_heap = 0; 5094670Sdes info->trace = env->trace; 5194670Sdes info->load_module_cache = NULL; 52236099Sdes 53236099Sdes return UWX_OK; 54236099Sdes} 5594670Sdes 56228690Sdesstruct uwx_self_info *uwx_self_init_info(struct uwx_env *env) 5794670Sdes{ 58228690Sdes struct uwx_self_info *info; 59236099Sdes 60228690Sdes info = (struct uwx_self_info *) 61236099Sdes (*env->allocate_cb)(sizeof(struct uwx_self_info)); 62236099Sdes if (info == 0) 63236099Sdes return 0; 64228690Sdes 6594670Sdes uwx_self_init_info_block(env, info); 66236099Sdes info->on_heap = 1; 67115619Sdes return info; 68236099Sdes} 69115619Sdes 70236099Sdesint uwx_self_free_info(struct uwx_self_info *info) 71236099Sdes{ 72236099Sdes int i; 73236099Sdes 74236099Sdes if (info->load_module_cache != NULL) 75236099Sdes uwx_free_load_module_cache(info); 76236099Sdes if (info->on_heap) 77236099Sdes (*info->env->free_cb)((void *)info); 78236099Sdes return UWX_OK; 79236099Sdes} 80228690Sdes 81236099Sdesint uwx_self_init_from_sigcontext( 82115619Sdes struct uwx_env *env, 83115619Sdes struct uwx_self_info *info, 84115619Sdes ucontext_t *ucontext) 85228690Sdes{ 86228690Sdes int status; 87236099Sdes uint16_t reason; 88236099Sdes uint64_t ip; 89115619Sdes uint64_t sp; 90228690Sdes uint64_t bsp; 91236099Sdes uint64_t cfm; 92115619Sdes unsigned int nat; 93228690Sdes uint64_t ec; 94115619Sdes int adj; 95228690Sdes 96236099Sdes info->ucontext = ucontext; 97236099Sdes status = __uc_get_reason(ucontext, &reason); 98236099Sdes if (status != 0) 99115619Sdes return UWX_ERR_UCACCESS; 100115619Sdes status = __uc_get_ip(ucontext, &ip); 101115619Sdes if (status != 0) 102228690Sdes return UWX_ERR_UCACCESS; 103228690Sdes status = __uc_get_grs(ucontext, 12, 1, &sp, &nat); 104236099Sdes if (status != 0) 105236099Sdes return UWX_ERR_UCACCESS; 106228690Sdes status = __uc_get_cfm(ucontext, &cfm); 107228690Sdes if (status != 0) 108236099Sdes return UWX_ERR_UCACCESS; 109228690Sdes#ifdef NEW_UC_GET_AR 110228690Sdes status = __uc_get_ar_bsp(ucontext, &bsp); 111228690Sdes if (status != 0) 112228690Sdes return UWX_ERR_UCACCESS; 113236099Sdes status = __uc_get_ar_bspstore(ucontext, &info->bspstore); 114236099Sdes if (status != 0) 115236099Sdes return UWX_ERR_UCACCESS; 116228690Sdes status = __uc_get_ar_ec(ucontext, &ec); 117228690Sdes if (status != 0) 118228690Sdes return UWX_ERR_UCACCESS; 119236099Sdes#else 120228690Sdes status = __uc_get_ar(ucontext, 17, &bsp); 121236099Sdes if (status != 0) 122236099Sdes return UWX_ERR_UCACCESS; 123236099Sdes status = __uc_get_ar(ucontext, 18, &info->bspstore); 124228690Sdes if (status != 0) 125228690Sdes return UWX_ERR_UCACCESS; 126236099Sdes status = __uc_get_ar(ucontext, 66, &ec); 127228690Sdes if (status != 0) 128236099Sdes return UWX_ERR_UCACCESS; 129228690Sdes#endif 130236099Sdes /* The returned bsp needs to be adjusted. */ 131236099Sdes /* For interrupt frames, where bsp was advanced by a cover */ 132236099Sdes /* instruction, subtract sof (size of frame). For non-interrupt */ 133236099Sdes /* frames, where bsp was advanced by br.call, subtract sol */ 134236099Sdes /* (size of locals). */ 135228690Sdes if (reason != 0) 136236099Sdes adj = (unsigned int)cfm & 0x7f; /* interrupt frame */ 137236099Sdes else 138236099Sdes adj = ((unsigned int)cfm >> 7) & 0x7f; /* non-interrupt frame */ 139236099Sdes bsp = uwx_add_to_bsp(bsp, -adj); 140228690Sdes cfm |= ec << 52; 141236099Sdes uwx_init_context(env, ip, sp, bsp, cfm); 142115619Sdes return UWX_OK; 143115619Sdes} 144115619Sdes 145115619Sdesint uwx_self_do_context_frame( 146115619Sdes struct uwx_env *env, 147115619Sdes struct uwx_self_info *info) 148236099Sdes{ 149236099Sdes int abi_context; 150236099Sdes int status; 151236099Sdes uint64_t ucontext; 152115619Sdes 153115619Sdes abi_context = uwx_get_abi_context_code(env); 154228690Sdes if (abi_context != UWX_ABI_HPUX_SIGCONTEXT) 15594670Sdes return UWX_SELF_ERR_BADABICONTEXT; 156115619Sdes status = uwx_get_reg(env, UWX_REG_GR(32), (uint64_t *)&ucontext); 157236099Sdes if (status != UWX_OK) 15894670Sdes return status; 159115619Sdes return uwx_self_init_from_sigcontext(env, info, 16094670Sdes (ucontext_t *)(intptr_t)ucontext); 161115619Sdes} 162115619Sdes 163115619Sdesint uwx_self_copyin( 164236099Sdes int request, 165236099Sdes char *loc, 166236099Sdes uint64_t rem, 167236099Sdes int len, 16894670Sdes intptr_t tok) 169236099Sdes{ 170115619Sdes int status; 171228690Sdes int regid; 172228690Sdes unsigned int nat; 173236099Sdes struct uwx_self_info *info = (struct uwx_self_info *) tok; 174236099Sdes unsigned long *wp; 175236099Sdes uint64_t *dp; 176236099Sdes 177236099Sdes status = -1; 178236099Sdes 179236099Sdes dp = (uint64_t *) loc; 180115619Sdes 181236099Sdes switch (request) { 18294670Sdes case UWX_COPYIN_UINFO: 183236099Sdes case UWX_COPYIN_MSTACK: 184236099Sdes if (len == 4) { 185236099Sdes wp = (unsigned long *) loc; 186236099Sdes *wp = *(unsigned long *)(intptr_t)rem; 187236099Sdes TRACE_SELF_COPYIN4(rem, len, wp) 188236099Sdes status = 0; 189236099Sdes } 190236099Sdes else if (len == 8) { 191236099Sdes *dp = *(uint64_t *)(intptr_t)rem; 192236099Sdes TRACE_SELF_COPYIN8(rem, len, dp) 193228690Sdes status = 0; 194228690Sdes } 195228690Sdes break; 196267014Sdelphij case UWX_COPYIN_RSTACK: 197115619Sdes if (len == 8) { 198115619Sdes if (info->ucontext == 0 && rem == (info->bspstore | 0x1f8)) { 199115619Sdes *dp = info->env->context.special[UWX_REG_AR_RNAT]; 200236099Sdes status = 0; 20194670Sdes } 20294670Sdes else if (info->ucontext == 0 || rem < info->bspstore) { 20394670Sdes *dp = *(uint64_t *)(intptr_t)rem; 204228690Sdes TRACE_SELF_COPYIN8(rem, len, dp) 205236099Sdes status = 0; 206236099Sdes } 207236099Sdes else { 208236099Sdes status = __uc_get_rsebs(info->ucontext, 209228690Sdes (uint64_t *)(intptr_t)rem, 1, dp); 210236099Sdes } 211115619Sdes } 212267014Sdelphij break; 213228690Sdes case UWX_COPYIN_REG: 214228690Sdes regid = (int)rem; 215236099Sdes if (info->ucontext != 0) { 216228690Sdes if (len == 8) { 217228690Sdes if (rem == UWX_REG_PREDS) 218228690Sdes status = __uc_get_prs(info->ucontext, dp); 219267014Sdelphij else if (rem == UWX_REG_AR_PFS) 220228690Sdes status = __uc_get_ar(info->ucontext, 64, dp); 221228690Sdes else if (rem == UWX_REG_AR_RNAT) 222236099Sdes status = __uc_get_ar(info->ucontext, 19, dp); 223236099Sdes else if (rem == UWX_REG_AR_UNAT) 224267014Sdelphij status = __uc_get_ar(info->ucontext, 36, dp); 225267014Sdelphij else if (rem == UWX_REG_AR_FPSR) 226267014Sdelphij status = __uc_get_ar(info->ucontext, 40, dp); 227267014Sdelphij else if (rem == UWX_REG_AR_LC) 228267014Sdelphij status = __uc_get_ar(info->ucontext, 65, dp); 229267014Sdelphij else if (regid >= UWX_REG_GR(1) && 230267014Sdelphij regid <= UWX_REG_GR(31)) 231267014Sdelphij status = __uc_get_grs(info->ucontext, 232115619Sdes regid - UWX_REG_GR(0), 1, dp, &nat); 233267014Sdelphij else if (regid >= UWX_REG_BR(0) && 23494670Sdes regid <= UWX_REG_BR(7)) 23594670Sdes status = __uc_get_brs(info->ucontext, 23694670Sdes regid - UWX_REG_BR(0), 1, dp); 237228690Sdes } 238236099Sdes else if (len == 16) { 239236099Sdes if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) { 240228690Sdes status = __uc_get_frs(info->ucontext, 241228690Sdes regid - UWX_REG_FR(0), 1, (fp_regval_t *)dp); 242228690Sdes } 243267014Sdelphij } 244228690Sdes } 245228690Sdes break; 24694670Sdes } 247228690Sdes if (status != 0) 248236099Sdes return 0; 249236099Sdes return len; 25094670Sdes} 251228690Sdes 252228690Sdes#define MODULE_CACHE_SIZE 4 253267014Sdelphij 254115619Sdesstruct load_module_cache { 25594670Sdes int clock; 256228690Sdes char *names[MODULE_CACHE_SIZE]; 257228690Sdes struct load_module_desc descs[MODULE_CACHE_SIZE]; 258228690Sdes struct uwx_symbol_cache *symbol_cache; 259228690Sdes}; 260115619Sdes 26194670Sdesvoid uwx_free_load_module_cache(struct uwx_self_info *info) 262236099Sdes{ 263267014Sdelphij int i; 264267014Sdelphij 265267014Sdelphij for (i = 0; i < MODULE_CACHE_SIZE; i++) { 266115619Sdes if (info->load_module_cache->names[i] != NULL) 267267014Sdelphij (*info->env->free_cb)((void *)info->load_module_cache->names[i]); 268236099Sdes } 269236099Sdes 270236099Sdes if (info->load_module_cache->symbol_cache != NULL) 271236099Sdes uwx_release_symbol_cache(info->env, 272236099Sdes info->load_module_cache->symbol_cache); 273236099Sdes 274236099Sdes (*info->env->free_cb)((void *)info->load_module_cache); 275236099Sdes} 276236099Sdes 277236099Sdesstruct load_module_desc *uwx_get_modinfo( 278236099Sdes struct uwx_self_info *info, 279236124Sdes uint64_t ip, 280236124Sdes char **module_name_p) 281236099Sdes{ 282236099Sdes int i; 28394670Sdes UINT64 handle; 284236099Sdes struct load_module_cache *cache; 285236099Sdes struct load_module_desc *desc; 286236099Sdes char *module_name; 287228690Sdes 288115619Sdes cache = info->load_module_cache; 289115619Sdes if (cache == NULL) { 290115619Sdes cache = (struct load_module_cache *) 291115619Sdes (*info->env->allocate_cb)(sizeof(struct load_module_cache)); 292115619Sdes if (cache == NULL) 293115619Sdes return NULL; 294236099Sdes for (i = 0; i < MODULE_CACHE_SIZE; i++) { 29594670Sdes desc = &cache->descs[i]; 296236099Sdes desc->text_base = 0; 297236099Sdes desc->text_size = 0; 298236099Sdes cache->names[i] = NULL; 299236099Sdes } 300267014Sdelphij cache->clock = 0; 301267014Sdelphij cache->symbol_cache = NULL; 302267014Sdelphij info->load_module_cache = cache; 303267014Sdelphij } 304267014Sdelphij for (i = 0; i < MODULE_CACHE_SIZE; i++) { 305236099Sdes desc = &cache->descs[i]; 306236099Sdes if (ip >= desc->text_base && ip < desc->text_base + desc->text_size) 307236099Sdes break; 308115619Sdes } 309236099Sdes if (i >= MODULE_CACHE_SIZE) { 31094670Sdes i = cache->clock; 311236099Sdes cache->clock = (cache->clock + 1) % MODULE_CACHE_SIZE; 312228690Sdes desc = &cache->descs[i]; 313236099Sdes handle = dlmodinfo(ip, desc, sizeof(*desc), 0, 0, 0); 314115619Sdes if (handle == 0) 315236099Sdes return NULL; 316236099Sdes if (cache->names[i] != NULL) 317228690Sdes (*info->env->free_cb)(cache->names[i]); 318236099Sdes cache->names[i] = NULL; 319236099Sdes } 320236099Sdes if (module_name_p != NULL) { 321115619Sdes if (cache->names[i] == NULL) { 322236099Sdes module_name = dlgetname(desc, sizeof(*desc), 0, 0, 0); 323236099Sdes if (module_name != NULL) { 324228690Sdes cache->names[i] = (char *) 325115619Sdes (*info->env->allocate_cb)(strlen(module_name)+1); 326236099Sdes if (cache->names[i] != NULL) 327236099Sdes strcpy(cache->names[i], module_name); 32894670Sdes } 32994670Sdes } 330115619Sdes *module_name_p = cache->names[i]; 331236099Sdes } 332236099Sdes return desc; 333236099Sdes} 334236099Sdes 335236099Sdesint uwx_self_lookupip( 336236099Sdes int request, 337236099Sdes uint64_t ip, 338236099Sdes intptr_t tok, 339236099Sdes uint64_t **resultp) 340236099Sdes{ 341236099Sdes struct uwx_self_info *info = (struct uwx_self_info *) tok; 342236099Sdes UINT64 handle; 343236099Sdes struct load_module_desc *desc; 344236099Sdes uint64_t *unwind_base; 345236099Sdes uint64_t *rvec; 346236099Sdes char *module_name; 347236099Sdes char *func_name; 348236099Sdes uint64_t offset; 349236099Sdes int i; 350236099Sdes int status; 351236099Sdes 352236099Sdes if (request == UWX_LKUP_LOOKUP) { 353236099Sdes TRACE_SELF_LOOKUP(ip) 354236099Sdes if (ip >= info->sendsig_start && ip < info->sendsig_end) { 355236099Sdes i = 0; 356236099Sdes rvec = info->rvec; 357236099Sdes rvec[i++] = UWX_KEY_CONTEXT; 358236099Sdes rvec[i++] = UWX_ABI_HPUX_SIGCONTEXT; 359236099Sdes rvec[i++] = UWX_KEY_END; 360236099Sdes rvec[i++] = 0; 361236099Sdes *resultp = rvec; 362236099Sdes return UWX_LKUP_FDESC; 363236099Sdes } 364236099Sdes else { 365236099Sdes desc = uwx_get_modinfo(info, ip, NULL); 366236099Sdes if (desc == NULL) 367236099Sdes return UWX_LKUP_ERR; 368236099Sdes unwind_base = (uint64_t *) (intptr_t) desc->unwind_base; 369236099Sdes TRACE_SELF_LOOKUP_DESC(desc->text_base, 370236099Sdes desc->linkage_ptr, unwind_base) 371236099Sdes i = 0; 372236099Sdes rvec = info->rvec; 373236099Sdes rvec[i++] = UWX_KEY_TBASE; 374236099Sdes rvec[i++] = desc->text_base; 375236099Sdes rvec[i++] = UWX_KEY_UFLAGS; 376236099Sdes rvec[i++] = unwind_base[0]; 377236099Sdes rvec[i++] = UWX_KEY_USTART; 378115619Sdes rvec[i++] = desc->text_base + unwind_base[1]; 379115619Sdes rvec[i++] = UWX_KEY_UEND; 380236099Sdes rvec[i++] = desc->text_base + unwind_base[2]; 381236099Sdes rvec[i++] = UWX_KEY_GP; 382236099Sdes rvec[i++] = desc->linkage_ptr; 383236099Sdes rvec[i++] = UWX_KEY_END; 384115619Sdes rvec[i++] = 0; 38595908Sdes *resultp = rvec; 386115619Sdes return UWX_LKUP_UTABLE; 387115619Sdes } 388115619Sdes } 38994670Sdes else if (request == UWX_LKUP_FREE) { 390236099Sdes return 0; 391236099Sdes } 39294670Sdes else if (request == UWX_LKUP_MODULE) { 393236099Sdes desc = uwx_get_modinfo(info, ip, &module_name); 394228690Sdes if (desc == NULL) 39594670Sdes return UWX_LKUP_ERR; 396236099Sdes if (module_name == NULL) 397236099Sdes return UWX_LKUP_ERR; 398236099Sdes i = 0; 399236099Sdes rvec = info->rvec; 400236099Sdes rvec[i++] = UWX_KEY_MODULE; 401236099Sdes rvec[i++] = (uint64_t)(intptr_t)module_name; 402236099Sdes rvec[i++] = UWX_KEY_TBASE; 403236099Sdes rvec[i++] = desc->text_base; 404236099Sdes rvec[i++] = UWX_KEY_END; 405236099Sdes rvec[i++] = 0; 406236099Sdes *resultp = rvec; 407236099Sdes return UWX_LKUP_SYMINFO; 408236099Sdes } 409236099Sdes else if (request == UWX_LKUP_SYMBOLS) { 41094670Sdes rvec = *resultp; 411236099Sdes for (i = 0; rvec[i] != UWX_KEY_END; i += 2) { 412236099Sdes if (rvec[i] == UWX_KEY_FUNCSTART) 413236099Sdes ip = rvec[i+1]; 414236099Sdes } 415236099Sdes desc = uwx_get_modinfo(info, ip, &module_name); 416236099Sdes if (desc == NULL) 417236099Sdes return UWX_LKUP_ERR; 41894670Sdes if (module_name == NULL) 419236099Sdes return UWX_LKUP_ERR; 42094670Sdes status = uwx_find_symbol(info->env, 421236099Sdes &info->load_module_cache->symbol_cache, 42294670Sdes module_name, ip - desc->text_base, 423236099Sdes &func_name, &offset); 424236099Sdes i = 0; 425267014Sdelphij rvec = info->rvec; 426267014Sdelphij rvec[i++] = UWX_KEY_MODULE; 427267014Sdelphij rvec[i++] = (uint64_t)(intptr_t)module_name; 428236099Sdes rvec[i++] = UWX_KEY_TBASE; 429236099Sdes rvec[i++] = desc->text_base; 430236099Sdes if (status == UWX_OK) { 431236099Sdes rvec[i++] = UWX_KEY_FUNC; 432236099Sdes rvec[i++] = (uint64_t)(intptr_t)func_name; 433236099Sdes rvec[i++] = UWX_KEY_FUNCSTART; 43494670Sdes rvec[i++] = ip - offset; 435236099Sdes } 436236099Sdes rvec[i++] = UWX_KEY_END; 437267014Sdelphij rvec[i++] = 0; 438267014Sdelphij *resultp = rvec; 43994670Sdes return UWX_LKUP_SYMINFO; 44094670Sdes } 44194670Sdes return UWX_LKUP_ERR; 44295908Sdes} 44395908Sdes