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 <stdlib.h> 26160157Smarcel#include <string.h> 27115013Smarcel#include <crt0.h> 28115013Smarcel#include <dlfcn.h> 29115013Smarcel#include <sys/uc_access.h> 30115013Smarcel 31115013Smarcel#include "uwx_env.h" 32115013Smarcel#include "uwx_context.h" 33115013Smarcel#include "uwx_trace.h" 34115013Smarcel#include "uwx_self.h" 35160157Smarcel#include "uwx_self_info.h" 36115013Smarcel 37115013Smarcel#define UWX_ABI_HPUX_SIGCONTEXT 0x0101 /* abi = HP-UX, context = 1 */ 38115013Smarcel 39160157Smarcelvoid uwx_free_load_module_cache(struct uwx_self_info *info); 40115013Smarcel 41160157Smarcelint uwx_self_init_info_block(struct uwx_env *env, struct uwx_self_info *info) 42160157Smarcel{ 43160157Smarcel info->env = env; 44160157Smarcel info->ucontext = 0; 45160157Smarcel info->bspstore = 0; 46160157Smarcel info->sendsig_start = __load_info->li_sendsig_txt; 47160157Smarcel info->sendsig_end = __load_info->li_sendsig_txt + 48160157Smarcel __load_info->li_sendsig_tsz; 49160157Smarcel info->on_heap = 0; 50160157Smarcel info->trace = env->trace; 51160157Smarcel info->load_module_cache = NULL; 52160157Smarcel 53160157Smarcel return UWX_OK; 54160157Smarcel} 55160157Smarcel 56115013Smarcelstruct uwx_self_info *uwx_self_init_info(struct uwx_env *env) 57115013Smarcel{ 58115013Smarcel struct uwx_self_info *info; 59115013Smarcel 60160157Smarcel info = (struct uwx_self_info *) 61115013Smarcel (*env->allocate_cb)(sizeof(struct uwx_self_info)); 62115013Smarcel if (info == 0) 63115013Smarcel return 0; 64115013Smarcel 65160157Smarcel uwx_self_init_info_block(env, info); 66160157Smarcel info->on_heap = 1; 67115013Smarcel return info; 68115013Smarcel} 69115013Smarcel 70115013Smarcelint uwx_self_free_info(struct uwx_self_info *info) 71115013Smarcel{ 72160157Smarcel int i; 73160157Smarcel 74160157Smarcel if (info->load_module_cache != NULL) 75160157Smarcel uwx_free_load_module_cache(info); 76160157Smarcel if (info->on_heap) 77160157Smarcel (*info->env->free_cb)((void *)info); 78115013Smarcel return UWX_OK; 79115013Smarcel} 80115013Smarcel 81115013Smarcelint uwx_self_init_from_sigcontext( 82115013Smarcel struct uwx_env *env, 83115013Smarcel struct uwx_self_info *info, 84115013Smarcel ucontext_t *ucontext) 85115013Smarcel{ 86115013Smarcel int status; 87115013Smarcel uint16_t reason; 88115013Smarcel uint64_t ip; 89115013Smarcel uint64_t sp; 90115013Smarcel uint64_t bsp; 91115013Smarcel uint64_t cfm; 92115013Smarcel unsigned int nat; 93115013Smarcel uint64_t ec; 94120925Smarcel int adj; 95115013Smarcel 96115013Smarcel info->ucontext = ucontext; 97115013Smarcel status = __uc_get_reason(ucontext, &reason); 98160157Smarcel if (status != 0) 99160157Smarcel return UWX_ERR_UCACCESS; 100115013Smarcel status = __uc_get_ip(ucontext, &ip); 101160157Smarcel if (status != 0) 102160157Smarcel return UWX_ERR_UCACCESS; 103115013Smarcel status = __uc_get_grs(ucontext, 12, 1, &sp, &nat); 104160157Smarcel if (status != 0) 105160157Smarcel return UWX_ERR_UCACCESS; 106120925Smarcel status = __uc_get_cfm(ucontext, &cfm); 107160157Smarcel if (status != 0) 108160157Smarcel return UWX_ERR_UCACCESS; 109120925Smarcel#ifdef NEW_UC_GET_AR 110120925Smarcel status = __uc_get_ar_bsp(ucontext, &bsp); 111160157Smarcel if (status != 0) 112160157Smarcel return UWX_ERR_UCACCESS; 113120925Smarcel status = __uc_get_ar_bspstore(ucontext, &info->bspstore); 114160157Smarcel if (status != 0) 115160157Smarcel return UWX_ERR_UCACCESS; 116120925Smarcel status = __uc_get_ar_ec(ucontext, &ec); 117160157Smarcel if (status != 0) 118160157Smarcel return UWX_ERR_UCACCESS; 119120925Smarcel#else 120115013Smarcel status = __uc_get_ar(ucontext, 17, &bsp); 121160157Smarcel if (status != 0) 122160157Smarcel return UWX_ERR_UCACCESS; 123115013Smarcel status = __uc_get_ar(ucontext, 18, &info->bspstore); 124160157Smarcel if (status != 0) 125160157Smarcel return UWX_ERR_UCACCESS; 126115013Smarcel status = __uc_get_ar(ucontext, 66, &ec); 127160157Smarcel if (status != 0) 128160157Smarcel return UWX_ERR_UCACCESS; 129120925Smarcel#endif 130120925Smarcel /* The returned bsp needs to be adjusted. */ 131120925Smarcel /* For interrupt frames, where bsp was advanced by a cover */ 132120925Smarcel /* instruction, subtract sof (size of frame). For non-interrupt */ 133120925Smarcel /* frames, where bsp was advanced by br.call, subtract sol */ 134120925Smarcel /* (size of locals). */ 135120925Smarcel if (reason != 0) 136120925Smarcel adj = (unsigned int)cfm & 0x7f; /* interrupt frame */ 137120925Smarcel else 138120925Smarcel adj = ((unsigned int)cfm >> 7) & 0x7f; /* non-interrupt frame */ 139120925Smarcel bsp = uwx_add_to_bsp(bsp, -adj); 140115013Smarcel cfm |= ec << 52; 141115013Smarcel uwx_init_context(env, ip, sp, bsp, cfm); 142115013Smarcel return UWX_OK; 143115013Smarcel} 144115013Smarcel 145115013Smarcelint uwx_self_do_context_frame( 146115013Smarcel struct uwx_env *env, 147115013Smarcel struct uwx_self_info *info) 148115013Smarcel{ 149115013Smarcel int abi_context; 150115013Smarcel int status; 151115013Smarcel uint64_t ucontext; 152115013Smarcel 153115013Smarcel abi_context = uwx_get_abi_context_code(env); 154115013Smarcel if (abi_context != UWX_ABI_HPUX_SIGCONTEXT) 155115013Smarcel return UWX_SELF_ERR_BADABICONTEXT; 156115013Smarcel status = uwx_get_reg(env, UWX_REG_GR(32), (uint64_t *)&ucontext); 157160157Smarcel if (status != UWX_OK) 158115013Smarcel return status; 159160157Smarcel return uwx_self_init_from_sigcontext(env, info, 160160157Smarcel (ucontext_t *)(intptr_t)ucontext); 161115013Smarcel} 162115013Smarcel 163115013Smarcelint uwx_self_copyin( 164115013Smarcel int request, 165115013Smarcel char *loc, 166115013Smarcel uint64_t rem, 167115013Smarcel int len, 168115013Smarcel intptr_t tok) 169115013Smarcel{ 170115013Smarcel int status; 171115013Smarcel int regid; 172115013Smarcel unsigned int nat; 173115013Smarcel struct uwx_self_info *info = (struct uwx_self_info *) tok; 174115013Smarcel unsigned long *wp; 175115013Smarcel uint64_t *dp; 176115013Smarcel 177129059Smarcel status = -1; 178129059Smarcel 179115013Smarcel dp = (uint64_t *) loc; 180115013Smarcel 181129059Smarcel switch (request) { 182129059Smarcel case UWX_COPYIN_UINFO: 183129059Smarcel case UWX_COPYIN_MSTACK: 184129059Smarcel if (len == 4) { 185129059Smarcel wp = (unsigned long *) loc; 186160157Smarcel *wp = *(unsigned long *)(intptr_t)rem; 187129059Smarcel TRACE_SELF_COPYIN4(rem, len, wp) 188129059Smarcel status = 0; 189115013Smarcel } 190129059Smarcel else if (len == 8) { 191160157Smarcel *dp = *(uint64_t *)(intptr_t)rem; 192129059Smarcel TRACE_SELF_COPYIN8(rem, len, dp) 193129059Smarcel status = 0; 194129059Smarcel } 195129059Smarcel break; 196129059Smarcel case UWX_COPYIN_RSTACK: 197129059Smarcel if (len == 8) { 198129059Smarcel if (info->ucontext == 0 && rem == (info->bspstore | 0x1f8)) { 199129059Smarcel *dp = info->env->context.special[UWX_REG_AR_RNAT]; 200129059Smarcel status = 0; 201129059Smarcel } 202129059Smarcel else if (info->ucontext == 0 || rem < info->bspstore) { 203160157Smarcel *dp = *(uint64_t *)(intptr_t)rem; 204129059Smarcel TRACE_SELF_COPYIN8(rem, len, dp) 205129059Smarcel status = 0; 206129059Smarcel } 207129059Smarcel else { 208129059Smarcel status = __uc_get_rsebs(info->ucontext, 209160157Smarcel (uint64_t *)(intptr_t)rem, 1, dp); 210129059Smarcel } 211129059Smarcel } 212129059Smarcel break; 213129059Smarcel case UWX_COPYIN_REG: 214129059Smarcel regid = (int)rem; 215129059Smarcel if (info->ucontext != 0) { 216129059Smarcel if (len == 8) { 217129059Smarcel if (rem == UWX_REG_PREDS) 218129059Smarcel status = __uc_get_prs(info->ucontext, dp); 219129059Smarcel else if (rem == UWX_REG_AR_PFS) 220129059Smarcel status = __uc_get_ar(info->ucontext, 64, dp); 221129059Smarcel else if (rem == UWX_REG_AR_RNAT) 222129059Smarcel status = __uc_get_ar(info->ucontext, 19, dp); 223129059Smarcel else if (rem == UWX_REG_AR_UNAT) 224129059Smarcel status = __uc_get_ar(info->ucontext, 36, dp); 225129059Smarcel else if (rem == UWX_REG_AR_FPSR) 226129059Smarcel status = __uc_get_ar(info->ucontext, 40, dp); 227129059Smarcel else if (rem == UWX_REG_AR_LC) 228129059Smarcel status = __uc_get_ar(info->ucontext, 65, dp); 229129059Smarcel else if (regid >= UWX_REG_GR(1) && 230129059Smarcel regid <= UWX_REG_GR(31)) 231129059Smarcel status = __uc_get_grs(info->ucontext, 232129059Smarcel regid - UWX_REG_GR(0), 1, dp, &nat); 233129059Smarcel else if (regid >= UWX_REG_BR(0) && 234129059Smarcel regid <= UWX_REG_BR(7)) 235129059Smarcel status = __uc_get_brs(info->ucontext, 236129059Smarcel regid - UWX_REG_BR(0), 1, dp); 237129059Smarcel } 238129059Smarcel else if (len == 16) { 239129059Smarcel if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) { 240129059Smarcel status = __uc_get_frs(info->ucontext, 241129059Smarcel regid - UWX_REG_FR(0), 1, (fp_regval_t *)dp); 242129059Smarcel } 243129059Smarcel } 244129059Smarcel } 245129059Smarcel break; 246115013Smarcel } 247129059Smarcel if (status != 0) 248129059Smarcel return 0; 249115013Smarcel return len; 250115013Smarcel} 251115013Smarcel 252160157Smarcel#define MODULE_CACHE_SIZE 4 253115013Smarcel 254160157Smarcelstruct load_module_cache { 255160157Smarcel int clock; 256160157Smarcel char *names[MODULE_CACHE_SIZE]; 257160157Smarcel struct load_module_desc descs[MODULE_CACHE_SIZE]; 258160157Smarcel struct uwx_symbol_cache *symbol_cache; 259160157Smarcel}; 260160157Smarcel 261160157Smarcelvoid uwx_free_load_module_cache(struct uwx_self_info *info) 262160157Smarcel{ 263160157Smarcel int i; 264160157Smarcel 265160157Smarcel for (i = 0; i < MODULE_CACHE_SIZE; i++) { 266160157Smarcel if (info->load_module_cache->names[i] != NULL) 267160157Smarcel (*info->env->free_cb)((void *)info->load_module_cache->names[i]); 268160157Smarcel } 269160157Smarcel 270160157Smarcel if (info->load_module_cache->symbol_cache != NULL) 271160157Smarcel uwx_release_symbol_cache(info->env, 272160157Smarcel info->load_module_cache->symbol_cache); 273160157Smarcel 274160157Smarcel (*info->env->free_cb)((void *)info->load_module_cache); 275160157Smarcel} 276160157Smarcel 277160157Smarcelstruct load_module_desc *uwx_get_modinfo( 278160157Smarcel struct uwx_self_info *info, 279160157Smarcel uint64_t ip, 280160157Smarcel char **module_name_p) 281160157Smarcel{ 282160157Smarcel int i; 283160157Smarcel UINT64 handle; 284160157Smarcel struct load_module_cache *cache; 285160157Smarcel struct load_module_desc *desc; 286160157Smarcel char *module_name; 287160157Smarcel 288160157Smarcel cache = info->load_module_cache; 289160157Smarcel if (cache == NULL) { 290160157Smarcel cache = (struct load_module_cache *) 291160157Smarcel (*info->env->allocate_cb)(sizeof(struct load_module_cache)); 292160157Smarcel if (cache == NULL) 293160157Smarcel return NULL; 294160157Smarcel for (i = 0; i < MODULE_CACHE_SIZE; i++) { 295160157Smarcel desc = &cache->descs[i]; 296160157Smarcel desc->text_base = 0; 297160157Smarcel desc->text_size = 0; 298160157Smarcel cache->names[i] = NULL; 299160157Smarcel } 300160157Smarcel cache->clock = 0; 301160157Smarcel cache->symbol_cache = NULL; 302160157Smarcel info->load_module_cache = cache; 303160157Smarcel } 304160157Smarcel for (i = 0; i < MODULE_CACHE_SIZE; i++) { 305160157Smarcel desc = &cache->descs[i]; 306160157Smarcel if (ip >= desc->text_base && ip < desc->text_base + desc->text_size) 307160157Smarcel break; 308160157Smarcel } 309160157Smarcel if (i >= MODULE_CACHE_SIZE) { 310160157Smarcel i = cache->clock; 311160157Smarcel cache->clock = (cache->clock + 1) % MODULE_CACHE_SIZE; 312160157Smarcel desc = &cache->descs[i]; 313160157Smarcel handle = dlmodinfo(ip, desc, sizeof(*desc), 0, 0, 0); 314160157Smarcel if (handle == 0) 315160157Smarcel return NULL; 316160157Smarcel if (cache->names[i] != NULL) 317160157Smarcel (*info->env->free_cb)(cache->names[i]); 318160157Smarcel cache->names[i] = NULL; 319160157Smarcel } 320160157Smarcel if (module_name_p != NULL) { 321160157Smarcel if (cache->names[i] == NULL) { 322160157Smarcel module_name = dlgetname(desc, sizeof(*desc), 0, 0, 0); 323160157Smarcel if (module_name != NULL) { 324160157Smarcel cache->names[i] = (char *) 325160157Smarcel (*info->env->allocate_cb)(strlen(module_name)+1); 326160157Smarcel if (cache->names[i] != NULL) 327160157Smarcel strcpy(cache->names[i], module_name); 328160157Smarcel } 329160157Smarcel } 330160157Smarcel *module_name_p = cache->names[i]; 331160157Smarcel } 332160157Smarcel return desc; 333160157Smarcel} 334160157Smarcel 335115013Smarcelint uwx_self_lookupip( 336115013Smarcel int request, 337115013Smarcel uint64_t ip, 338115013Smarcel intptr_t tok, 339115013Smarcel uint64_t **resultp) 340115013Smarcel{ 341115013Smarcel struct uwx_self_info *info = (struct uwx_self_info *) tok; 342115013Smarcel UINT64 handle; 343160157Smarcel struct load_module_desc *desc; 344115013Smarcel uint64_t *unwind_base; 345115013Smarcel uint64_t *rvec; 346160157Smarcel char *module_name; 347160157Smarcel char *func_name; 348160157Smarcel uint64_t offset; 349115013Smarcel int i; 350160157Smarcel int status; 351115013Smarcel 352115013Smarcel if (request == UWX_LKUP_LOOKUP) { 353115013Smarcel TRACE_SELF_LOOKUP(ip) 354115013Smarcel if (ip >= info->sendsig_start && ip < info->sendsig_end) { 355115013Smarcel i = 0; 356115013Smarcel rvec = info->rvec; 357115013Smarcel rvec[i++] = UWX_KEY_CONTEXT; 358115013Smarcel rvec[i++] = UWX_ABI_HPUX_SIGCONTEXT; 359160157Smarcel rvec[i++] = UWX_KEY_END; 360115013Smarcel rvec[i++] = 0; 361115013Smarcel *resultp = rvec; 362115013Smarcel return UWX_LKUP_FDESC; 363115013Smarcel } 364115013Smarcel else { 365160157Smarcel desc = uwx_get_modinfo(info, ip, NULL); 366160157Smarcel if (desc == NULL) 367115013Smarcel return UWX_LKUP_ERR; 368160157Smarcel unwind_base = (uint64_t *) (intptr_t) desc->unwind_base; 369160157Smarcel TRACE_SELF_LOOKUP_DESC(desc->text_base, 370160157Smarcel desc->linkage_ptr, unwind_base) 371115013Smarcel i = 0; 372115013Smarcel rvec = info->rvec; 373115013Smarcel rvec[i++] = UWX_KEY_TBASE; 374160157Smarcel rvec[i++] = desc->text_base; 375115013Smarcel rvec[i++] = UWX_KEY_UFLAGS; 376115013Smarcel rvec[i++] = unwind_base[0]; 377115013Smarcel rvec[i++] = UWX_KEY_USTART; 378160157Smarcel rvec[i++] = desc->text_base + unwind_base[1]; 379115013Smarcel rvec[i++] = UWX_KEY_UEND; 380160157Smarcel rvec[i++] = desc->text_base + unwind_base[2]; 381160157Smarcel rvec[i++] = UWX_KEY_GP; 382160157Smarcel rvec[i++] = desc->linkage_ptr; 383160157Smarcel rvec[i++] = UWX_KEY_END; 384115013Smarcel rvec[i++] = 0; 385115013Smarcel *resultp = rvec; 386115013Smarcel return UWX_LKUP_UTABLE; 387115013Smarcel } 388115013Smarcel } 389115013Smarcel else if (request == UWX_LKUP_FREE) { 390115013Smarcel return 0; 391115013Smarcel } 392160157Smarcel else if (request == UWX_LKUP_MODULE) { 393160157Smarcel desc = uwx_get_modinfo(info, ip, &module_name); 394160157Smarcel if (desc == NULL) 395160157Smarcel return UWX_LKUP_ERR; 396160157Smarcel if (module_name == NULL) 397160157Smarcel return UWX_LKUP_ERR; 398160157Smarcel i = 0; 399160157Smarcel rvec = info->rvec; 400160157Smarcel rvec[i++] = UWX_KEY_MODULE; 401160157Smarcel rvec[i++] = (uint64_t)(intptr_t)module_name; 402160157Smarcel rvec[i++] = UWX_KEY_TBASE; 403160157Smarcel rvec[i++] = desc->text_base; 404160157Smarcel rvec[i++] = UWX_KEY_END; 405160157Smarcel rvec[i++] = 0; 406160157Smarcel *resultp = rvec; 407160157Smarcel return UWX_LKUP_SYMINFO; 408160157Smarcel } 409160157Smarcel else if (request == UWX_LKUP_SYMBOLS) { 410160157Smarcel rvec = *resultp; 411160157Smarcel for (i = 0; rvec[i] != UWX_KEY_END; i += 2) { 412160157Smarcel if (rvec[i] == UWX_KEY_FUNCSTART) 413160157Smarcel ip = rvec[i+1]; 414160157Smarcel } 415160157Smarcel desc = uwx_get_modinfo(info, ip, &module_name); 416160157Smarcel if (desc == NULL) 417160157Smarcel return UWX_LKUP_ERR; 418160157Smarcel if (module_name == NULL) 419160157Smarcel return UWX_LKUP_ERR; 420160157Smarcel status = uwx_find_symbol(info->env, 421160157Smarcel &info->load_module_cache->symbol_cache, 422160157Smarcel module_name, ip - desc->text_base, 423160157Smarcel &func_name, &offset); 424160157Smarcel i = 0; 425160157Smarcel rvec = info->rvec; 426160157Smarcel rvec[i++] = UWX_KEY_MODULE; 427160157Smarcel rvec[i++] = (uint64_t)(intptr_t)module_name; 428160157Smarcel rvec[i++] = UWX_KEY_TBASE; 429160157Smarcel rvec[i++] = desc->text_base; 430160157Smarcel if (status == UWX_OK) { 431160157Smarcel rvec[i++] = UWX_KEY_FUNC; 432160157Smarcel rvec[i++] = (uint64_t)(intptr_t)func_name; 433160157Smarcel rvec[i++] = UWX_KEY_FUNCSTART; 434160157Smarcel rvec[i++] = ip - offset; 435160157Smarcel } 436160157Smarcel rvec[i++] = UWX_KEY_END; 437160157Smarcel rvec[i++] = 0; 438160157Smarcel *resultp = rvec; 439160157Smarcel return UWX_LKUP_SYMINFO; 440160157Smarcel } 441160157Smarcel return UWX_LKUP_ERR; 442115013Smarcel} 443