uwx_self.c revision 160158
111195Svaleriep/*
216823SamluCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
311195SvaleriepPermission is hereby granted, free of charge, to any person
411195Svaleriepobtaining a copy of this software and associated documentation
511195Svaleriepfiles (the "Software"), to deal in the Software without
611195Svalerieprestriction, including without limitation the rights to use,
711195Svaleriepcopy, modify, merge, publish, distribute, sublicense, and/or sell
811195Svaleriepcopies of the Software, and to permit persons to whom the
911195SvaleriepSoftware is furnished to do so, subject to the following
1011195Svaleriepconditions:
1111195Svaleriep
1211195SvaleriepThe above copyright notice and this permission notice shall be
1311195Svaleriepincluded in all copies or substantial portions of the Software.
1411195Svaleriep
1511195SvaleriepTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1611195SvaleriepEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1711195SvaleriepOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1811195SvaleriepNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1911195SvaleriepHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
2011195SvaleriepWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2111195SvaleriepFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2211195SvaleriepOTHER DEALINGS IN THE SOFTWARE.
2311195Svaleriep*/
2411195Svaleriep
2511195Svaleriep#include <stdlib.h>
2611195Svaleriep#include <string.h>
2711195Svaleriep#include <crt0.h>
2816823Samlu#include <dlfcn.h>
2911195Svaleriep#include <sys/uc_access.h>
3011195Svaleriep
3111195Svaleriep#include "uwx_env.h"
3211195Svaleriep#include "uwx_context.h"
3311195Svaleriep#include "uwx_trace.h"
3411195Svaleriep#include "uwx_self.h"
3511195Svaleriep#include "uwx_self_info.h"
3611195Svaleriep
3711195Svaleriep#define UWX_ABI_HPUX_SIGCONTEXT 0x0101	/* abi = HP-UX, context = 1 */
3811195Svaleriep
3911195Svaleriepvoid uwx_free_load_module_cache(struct uwx_self_info *info);
4011195Svaleriep
4111195Svaleriepint uwx_self_init_info_block(struct uwx_env *env, struct uwx_self_info *info)
4211195Svaleriep{
4311195Svaleriep    info->env = env;
4411195Svaleriep    info->ucontext = 0;
4511195Svaleriep    info->bspstore = 0;
4611195Svaleriep    info->sendsig_start = __load_info->li_sendsig_txt;
4711195Svaleriep    info->sendsig_end = __load_info->li_sendsig_txt +
4811195Svaleriep				__load_info->li_sendsig_tsz;
4911195Svaleriep    info->on_heap = 0;
5011195Svaleriep    info->trace = env->trace;
5111195Svaleriep    info->load_module_cache = NULL;
5211195Svaleriep
5311195Svaleriep    return UWX_OK;
5411195Svaleriep}
5511195Svaleriep
5611195Svaleriepstruct uwx_self_info *uwx_self_init_info(struct uwx_env *env)
5711195Svaleriep{
5811195Svaleriep    struct uwx_self_info *info;
5911195Svaleriep
6011195Svaleriep    info = (struct uwx_self_info *)
6111195Svaleriep			(*env->allocate_cb)(sizeof(struct uwx_self_info));
6211195Svaleriep    if (info == 0)
6311195Svaleriep	return 0;
6411195Svaleriep
6511195Svaleriep    uwx_self_init_info_block(env, info);
6611195Svaleriep    info->on_heap = 1;
6711195Svaleriep    return info;
6811195Svaleriep}
6911195Svaleriep
7011195Svaleriepint uwx_self_free_info(struct uwx_self_info *info)
7111195Svaleriep{
72    int i;
73
74    if (info->load_module_cache != NULL)
75	uwx_free_load_module_cache(info);
76    if (info->on_heap)
77	(*info->env->free_cb)((void *)info);
78    return UWX_OK;
79}
80
81int uwx_self_init_from_sigcontext(
82    struct uwx_env *env,
83    struct uwx_self_info *info,
84    ucontext_t *ucontext)
85{
86    int status;
87    uint16_t reason;
88    uint64_t ip;
89    uint64_t sp;
90    uint64_t bsp;
91    uint64_t cfm;
92    unsigned int nat;
93    uint64_t ec;
94    int adj;
95
96    info->ucontext = ucontext;
97    status = __uc_get_reason(ucontext, &reason);
98    if (status != 0)
99	return UWX_ERR_UCACCESS;
100    status = __uc_get_ip(ucontext, &ip);
101    if (status != 0)
102	return UWX_ERR_UCACCESS;
103    status = __uc_get_grs(ucontext, 12, 1, &sp, &nat);
104    if (status != 0)
105	return UWX_ERR_UCACCESS;
106    status = __uc_get_cfm(ucontext, &cfm);
107    if (status != 0)
108	return UWX_ERR_UCACCESS;
109#ifdef NEW_UC_GET_AR
110    status = __uc_get_ar_bsp(ucontext, &bsp);
111    if (status != 0)
112	return UWX_ERR_UCACCESS;
113    status = __uc_get_ar_bspstore(ucontext, &info->bspstore);
114    if (status != 0)
115	return UWX_ERR_UCACCESS;
116    status = __uc_get_ar_ec(ucontext, &ec);
117    if (status != 0)
118	return UWX_ERR_UCACCESS;
119#else
120    status = __uc_get_ar(ucontext, 17, &bsp);
121    if (status != 0)
122	return UWX_ERR_UCACCESS;
123    status = __uc_get_ar(ucontext, 18, &info->bspstore);
124    if (status != 0)
125	return UWX_ERR_UCACCESS;
126    status = __uc_get_ar(ucontext, 66, &ec);
127    if (status != 0)
128	return UWX_ERR_UCACCESS;
129#endif
130    /* The returned bsp needs to be adjusted. */
131    /* For interrupt frames, where bsp was advanced by a cover */
132    /* instruction, subtract sof (size of frame). For non-interrupt */
133    /* frames, where bsp was advanced by br.call, subtract sol */
134    /* (size of locals). */
135    if (reason != 0)
136	adj = (unsigned int)cfm & 0x7f;		/* interrupt frame */
137    else
138	adj = ((unsigned int)cfm >> 7) & 0x7f;	/* non-interrupt frame */
139    bsp = uwx_add_to_bsp(bsp, -adj);
140    cfm |= ec << 52;
141    uwx_init_context(env, ip, sp, bsp, cfm);
142    return UWX_OK;
143}
144
145int uwx_self_do_context_frame(
146    struct uwx_env *env,
147    struct uwx_self_info *info)
148{
149    int abi_context;
150    int status;
151    uint64_t ucontext;
152
153    abi_context = uwx_get_abi_context_code(env);
154    if (abi_context != UWX_ABI_HPUX_SIGCONTEXT)
155	return UWX_SELF_ERR_BADABICONTEXT;
156    status = uwx_get_reg(env, UWX_REG_GR(32), (uint64_t *)&ucontext);
157    if (status != UWX_OK)
158	return status;
159    return uwx_self_init_from_sigcontext(env, info,
160					(ucontext_t *)(intptr_t)ucontext);
161}
162
163int uwx_self_copyin(
164    int request,
165    char *loc,
166    uint64_t rem,
167    int len,
168    intptr_t tok)
169{
170    int status;
171    int regid;
172    unsigned int nat;
173    struct uwx_self_info *info = (struct uwx_self_info *) tok;
174    unsigned long *wp;
175    uint64_t *dp;
176
177    status = -1;
178
179    dp = (uint64_t *) loc;
180
181    switch (request) {
182	case UWX_COPYIN_UINFO:
183	case UWX_COPYIN_MSTACK:
184	    if (len == 4) {
185		wp = (unsigned long *) loc;
186		*wp = *(unsigned long *)(intptr_t)rem;
187		TRACE_SELF_COPYIN4(rem, len, wp)
188		status = 0;
189	    }
190	    else if (len == 8) {
191		*dp = *(uint64_t *)(intptr_t)rem;
192		TRACE_SELF_COPYIN8(rem, len, dp)
193		status = 0;
194	    }
195	    break;
196	case UWX_COPYIN_RSTACK:
197	    if (len == 8) {
198		if (info->ucontext == 0 && rem == (info->bspstore | 0x1f8)) {
199		    *dp = info->env->context.special[UWX_REG_AR_RNAT];
200		    status = 0;
201		}
202		else if (info->ucontext == 0 || rem < info->bspstore) {
203		    *dp = *(uint64_t *)(intptr_t)rem;
204		    TRACE_SELF_COPYIN8(rem, len, dp)
205		    status = 0;
206		}
207		else {
208		    status = __uc_get_rsebs(info->ucontext,
209					    (uint64_t *)(intptr_t)rem, 1, dp);
210		}
211	    }
212	    break;
213	case UWX_COPYIN_REG:
214	    regid = (int)rem;
215	    if (info->ucontext != 0) {
216		if (len == 8) {
217		    if (rem == UWX_REG_PREDS)
218			status = __uc_get_prs(info->ucontext, dp);
219		    else if (rem == UWX_REG_AR_PFS)
220			status = __uc_get_ar(info->ucontext, 64, dp);
221		    else if (rem == UWX_REG_AR_RNAT)
222			status = __uc_get_ar(info->ucontext, 19, dp);
223		    else if (rem == UWX_REG_AR_UNAT)
224			status = __uc_get_ar(info->ucontext, 36, dp);
225		    else if (rem == UWX_REG_AR_FPSR)
226			status = __uc_get_ar(info->ucontext, 40, dp);
227		    else if (rem == UWX_REG_AR_LC)
228			status = __uc_get_ar(info->ucontext, 65, dp);
229		    else if (regid >= UWX_REG_GR(1) &&
230						regid <= UWX_REG_GR(31))
231			status = __uc_get_grs(info->ucontext,
232					    regid - UWX_REG_GR(0), 1, dp, &nat);
233		    else if (regid >= UWX_REG_BR(0) &&
234						regid <= UWX_REG_BR(7))
235			status = __uc_get_brs(info->ucontext,
236					    regid - UWX_REG_BR(0), 1, dp);
237		}
238		else if (len == 16) {
239		    if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) {
240			status = __uc_get_frs(info->ucontext,
241				regid - UWX_REG_FR(0), 1, (fp_regval_t *)dp);
242		    }
243		}
244	    }
245	    break;
246    }
247    if (status != 0)
248	return 0;
249    return len;
250}
251
252#define MODULE_CACHE_SIZE 4
253
254struct load_module_cache {
255    int clock;
256    char *names[MODULE_CACHE_SIZE];
257    struct load_module_desc descs[MODULE_CACHE_SIZE];
258    struct uwx_symbol_cache *symbol_cache;
259};
260
261void uwx_free_load_module_cache(struct uwx_self_info *info)
262{
263    int i;
264
265    for (i = 0; i < MODULE_CACHE_SIZE; i++) {
266	if (info->load_module_cache->names[i] != NULL)
267	    (*info->env->free_cb)((void *)info->load_module_cache->names[i]);
268    }
269
270    if (info->load_module_cache->symbol_cache != NULL)
271	uwx_release_symbol_cache(info->env,
272				    info->load_module_cache->symbol_cache);
273
274    (*info->env->free_cb)((void *)info->load_module_cache);
275}
276
277struct load_module_desc *uwx_get_modinfo(
278    struct uwx_self_info *info,
279    uint64_t ip,
280    char **module_name_p)
281{
282    int i;
283    UINT64 handle;
284    struct load_module_cache *cache;
285    struct load_module_desc *desc;
286    char *module_name;
287
288    cache = info->load_module_cache;
289    if (cache == NULL) {
290	cache = (struct load_module_cache *)
291		(*info->env->allocate_cb)(sizeof(struct load_module_cache));
292	if (cache == NULL)
293	    return NULL;
294	for (i = 0; i < MODULE_CACHE_SIZE; i++) {
295	    desc = &cache->descs[i];
296	    desc->text_base = 0;
297	    desc->text_size = 0;
298	    cache->names[i] = NULL;
299	}
300	cache->clock = 0;
301	cache->symbol_cache = NULL;
302	info->load_module_cache = cache;
303    }
304    for (i = 0; i < MODULE_CACHE_SIZE; i++) {
305	desc = &cache->descs[i];
306	if (ip >= desc->text_base && ip < desc->text_base + desc->text_size)
307	    break;
308    }
309    if (i >= MODULE_CACHE_SIZE) {
310	i = cache->clock;
311	cache->clock = (cache->clock + 1) % MODULE_CACHE_SIZE;
312	desc = &cache->descs[i];
313	handle = dlmodinfo(ip, desc, sizeof(*desc), 0, 0, 0);
314	if (handle == 0)
315	    return NULL;
316	if (cache->names[i] != NULL)
317	    (*info->env->free_cb)(cache->names[i]);
318	cache->names[i] = NULL;
319    }
320    if (module_name_p != NULL) {
321	if (cache->names[i] == NULL) {
322	    module_name = dlgetname(desc, sizeof(*desc), 0, 0, 0);
323	    if (module_name != NULL) {
324		cache->names[i] = (char *)
325			    (*info->env->allocate_cb)(strlen(module_name)+1);
326		if (cache->names[i] != NULL)
327		    strcpy(cache->names[i], module_name);
328	    }
329	}
330	*module_name_p = cache->names[i];
331    }
332    return desc;
333}
334
335int uwx_self_lookupip(
336    int request,
337    uint64_t ip,
338    intptr_t tok,
339    uint64_t **resultp)
340{
341    struct uwx_self_info *info = (struct uwx_self_info *) tok;
342    UINT64 handle;
343    struct load_module_desc *desc;
344    uint64_t *unwind_base;
345    uint64_t *rvec;
346    char *module_name;
347    char *func_name;
348    uint64_t offset;
349    int i;
350    int status;
351
352    if (request == UWX_LKUP_LOOKUP) {
353	TRACE_SELF_LOOKUP(ip)
354	if (ip >= info->sendsig_start && ip < info->sendsig_end) {
355	    i = 0;
356	    rvec = info->rvec;
357	    rvec[i++] = UWX_KEY_CONTEXT;
358	    rvec[i++] = UWX_ABI_HPUX_SIGCONTEXT;
359	    rvec[i++] = UWX_KEY_END;
360	    rvec[i++] = 0;
361	    *resultp = rvec;
362	    return UWX_LKUP_FDESC;
363	}
364	else {
365	    desc = uwx_get_modinfo(info, ip, NULL);
366	    if (desc == NULL)
367		return UWX_LKUP_ERR;
368	    unwind_base = (uint64_t *) (intptr_t) desc->unwind_base;
369	    TRACE_SELF_LOOKUP_DESC(desc->text_base,
370					desc->linkage_ptr, unwind_base)
371	    i = 0;
372	    rvec = info->rvec;
373	    rvec[i++] = UWX_KEY_TBASE;
374	    rvec[i++] = desc->text_base;
375	    rvec[i++] = UWX_KEY_UFLAGS;
376	    rvec[i++] = unwind_base[0];
377	    rvec[i++] = UWX_KEY_USTART;
378	    rvec[i++] = desc->text_base + unwind_base[1];
379	    rvec[i++] = UWX_KEY_UEND;
380	    rvec[i++] = desc->text_base + unwind_base[2];
381	    rvec[i++] = UWX_KEY_GP;
382	    rvec[i++] = desc->linkage_ptr;
383	    rvec[i++] = UWX_KEY_END;
384	    rvec[i++] = 0;
385	    *resultp = rvec;
386	    return UWX_LKUP_UTABLE;
387	}
388    }
389    else if (request == UWX_LKUP_FREE) {
390	return 0;
391    }
392    else if (request == UWX_LKUP_MODULE) {
393	desc = uwx_get_modinfo(info, ip, &module_name);
394	if (desc == NULL)
395	    return UWX_LKUP_ERR;
396	if (module_name == NULL)
397	    return UWX_LKUP_ERR;
398	i = 0;
399	rvec = info->rvec;
400	rvec[i++] = UWX_KEY_MODULE;
401	rvec[i++] = (uint64_t)(intptr_t)module_name;
402	rvec[i++] = UWX_KEY_TBASE;
403	rvec[i++] = desc->text_base;
404	rvec[i++] = UWX_KEY_END;
405	rvec[i++] = 0;
406	*resultp = rvec;
407	return UWX_LKUP_SYMINFO;
408    }
409    else if (request == UWX_LKUP_SYMBOLS) {
410	rvec = *resultp;
411	for (i = 0; rvec[i] != UWX_KEY_END; i += 2) {
412	    if (rvec[i] == UWX_KEY_FUNCSTART)
413		ip = rvec[i+1];
414	}
415	desc = uwx_get_modinfo(info, ip, &module_name);
416	if (desc == NULL)
417	    return UWX_LKUP_ERR;
418	if (module_name == NULL)
419	    return UWX_LKUP_ERR;
420	status = uwx_find_symbol(info->env,
421			&info->load_module_cache->symbol_cache,
422			module_name, ip - desc->text_base,
423			&func_name, &offset);
424	i = 0;
425	rvec = info->rvec;
426	rvec[i++] = UWX_KEY_MODULE;
427	rvec[i++] = (uint64_t)(intptr_t)module_name;
428	rvec[i++] = UWX_KEY_TBASE;
429	rvec[i++] = desc->text_base;
430	if (status == UWX_OK) {
431	    rvec[i++] = UWX_KEY_FUNC;
432	    rvec[i++] = (uint64_t)(intptr_t)func_name;
433	    rvec[i++] = UWX_KEY_FUNCSTART;
434	    rvec[i++] = ip - offset;
435	}
436	rvec[i++] = UWX_KEY_END;
437	rvec[i++] = 0;
438	*resultp = rvec;
439	return UWX_LKUP_SYMINFO;
440    }
441    return UWX_LKUP_ERR;
442}
443