1/*
2Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3Permission is hereby granted, free of charge, to any person
4obtaining a copy of this software and associated documentation
5files (the "Software"), to deal in the Software without
6restriction, including without limitation the rights to use,
7copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following
10conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23*/
24
25#include <stdlib.h>
26#include <string.h>
27#include <crt0.h>
28#include <dlfcn.h>
29#include <sys/uc_access.h>
30
31#include "uwx_env.h"
32#include "uwx_context.h"
33#include "uwx_trace.h"
34#include "uwx_self.h"
35#include "uwx_self_info.h"
36
37#define UWX_ABI_HPUX_SIGCONTEXT 0x0101	/* abi = HP-UX, context = 1 */
38
39void uwx_free_load_module_cache(struct uwx_self_info *info);
40
41int uwx_self_init_info_block(struct uwx_env *env, struct uwx_self_info *info)
42{
43    info->env = env;
44    info->ucontext = 0;
45    info->bspstore = 0;
46    info->sendsig_start = __load_info->li_sendsig_txt;
47    info->sendsig_end = __load_info->li_sendsig_txt +
48				__load_info->li_sendsig_tsz;
49    info->on_heap = 0;
50    info->trace = env->trace;
51    info->load_module_cache = NULL;
52
53    return UWX_OK;
54}
55
56struct uwx_self_info *uwx_self_init_info(struct uwx_env *env)
57{
58    struct uwx_self_info *info;
59
60    info = (struct uwx_self_info *)
61			(*env->allocate_cb)(sizeof(struct uwx_self_info));
62    if (info == 0)
63	return 0;
64
65    uwx_self_init_info_block(env, info);
66    info->on_heap = 1;
67    return info;
68}
69
70int uwx_self_free_info(struct uwx_self_info *info)
71{
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