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