uwx_self.c revision 256281
1287225Simp/*
2287225SimpCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3287225SimpPermission is hereby granted, free of charge, to any person
4287225Simpobtaining a copy of this software and associated documentation
5287225Simpfiles (the "Software"), to deal in the Software without
6287225Simprestriction, including without limitation the rights to use,
7287225Simpcopy, modify, merge, publish, distribute, sublicense, and/or sell
8287225Simpcopies of the Software, and to permit persons to whom the
9287225SimpSoftware is furnished to do so, subject to the following
10287225Simpconditions:
11287225Simp
12287225SimpThe above copyright notice and this permission notice shall be
13287225Simpincluded in all copies or substantial portions of the Software.
14287225Simp
15287225SimpTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16287225SimpEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17287225SimpOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18287225SimpNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19287225SimpHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20287225SimpWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21287225SimpFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22287225SimpOTHER DEALINGS IN THE SOFTWARE.
23287225Simp*/
24287225Simp
25287225Simp#include <stdlib.h>
26287225Simp#include <string.h>
27287225Simp#include <crt0.h>
28287225Simp#include <dlfcn.h>
29287225Simp#include <sys/uc_access.h>
30287225Simp
31287225Simp#include "uwx_env.h"
32336346Skevans#include "uwx_context.h"
33336346Skevans#include "uwx_trace.h"
34336346Skevans#include "uwx_self.h"
35287225Simp#include "uwx_self_info.h"
36287225Simp
37287225Simp#define UWX_ABI_HPUX_SIGCONTEXT 0x0101	/* abi = HP-UX, context = 1 */
38287225Simp
39287225Simpvoid uwx_free_load_module_cache(struct uwx_self_info *info);
40287225Simp
41287225Simpint uwx_self_init_info_block(struct uwx_env *env, struct uwx_self_info *info)
42287225Simp{
43287225Simp    info->env = env;
44287225Simp    info->ucontext = 0;
45287225Simp    info->bspstore = 0;
46287225Simp    info->sendsig_start = __load_info->li_sendsig_txt;
47287225Simp    info->sendsig_end = __load_info->li_sendsig_txt +
48287225Simp				__load_info->li_sendsig_tsz;
49287225Simp    info->on_heap = 0;
50287225Simp    info->trace = env->trace;
51287225Simp    info->load_module_cache = NULL;
52287225Simp
53287225Simp    return UWX_OK;
54287225Simp}
55287225Simp
56287225Simpstruct uwx_self_info *uwx_self_init_info(struct uwx_env *env)
57287225Simp{
58287225Simp    struct uwx_self_info *info;
59287225Simp
60287225Simp    info = (struct uwx_self_info *)
61287225Simp			(*env->allocate_cb)(sizeof(struct uwx_self_info));
62287225Simp    if (info == 0)
63287225Simp	return 0;
64287225Simp
65287225Simp    uwx_self_init_info_block(env, info);
66287225Simp    info->on_heap = 1;
67287225Simp    return info;
68287225Simp}
69287225Simp
70287225Simpint uwx_self_free_info(struct uwx_self_info *info)
71287225Simp{
72287225Simp    int i;
73287225Simp
74287225Simp    if (info->load_module_cache != NULL)
75287225Simp	uwx_free_load_module_cache(info);
76287225Simp    if (info->on_heap)
77287225Simp	(*info->env->free_cb)((void *)info);
78287225Simp    return UWX_OK;
79287225Simp}
80287225Simp
81287225Simpint uwx_self_init_from_sigcontext(
82287225Simp    struct uwx_env *env,
83287225Simp    struct uwx_self_info *info,
84287225Simp    ucontext_t *ucontext)
85287225Simp{
86287225Simp    int status;
87287225Simp    uint16_t reason;
88287225Simp    uint64_t ip;
89287225Simp    uint64_t sp;
90287225Simp    uint64_t bsp;
91287225Simp    uint64_t cfm;
92287225Simp    unsigned int nat;
93287225Simp    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