uwx_self.c revision 129059
1/*
2Copyright (c) 2003 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 <crt0.h>
27#include <dlfcn.h>
28#include <sys/uc_access.h>
29
30#include "uwx_env.h"
31#include "uwx_context.h"
32#include "uwx_trace.h"
33#include "uwx_self.h"
34
35#define UWX_ABI_HPUX_SIGCONTEXT 0x0101	/* abi = HP-UX, context = 1 */
36
37struct uwx_self_info {
38    struct uwx_env *env;
39    ucontext_t *ucontext;
40    uint64_t bspstore;
41    uint64_t rvec[10];
42    uint64_t sendsig_start;
43    uint64_t sendsig_end;
44    alloc_cb allocate_cb;
45    free_cb free_cb;
46    int trace;
47};
48
49struct uwx_self_info *uwx_self_init_info(struct uwx_env *env)
50{
51    struct uwx_self_info *info;
52
53    if (env->allocate_cb == 0)
54	info = (struct uwx_self_info *)
55			malloc(sizeof(struct uwx_self_info));
56    else
57	info = (struct uwx_self_info *)
58			(*env->allocate_cb)(sizeof(struct uwx_self_info));
59    if (info == 0)
60	return 0;
61
62    info->env = env;
63    info->ucontext = 0;
64    info->bspstore = 0;
65    info->sendsig_start = __load_info->li_sendsig_txt;
66    info->sendsig_end = __load_info->li_sendsig_txt +
67				__load_info->li_sendsig_tsz;
68    info->allocate_cb = env->allocate_cb;
69    info->free_cb = env->free_cb;
70    info->trace = env->trace;
71    return info;
72}
73
74int uwx_self_free_info(struct uwx_self_info *info)
75{
76    if (info->free_cb == 0)
77	free((void *)info);
78    else
79	(*info->free_cb)((void *)info);
80    return UWX_OK;
81}
82
83int uwx_self_init_from_sigcontext(
84    struct uwx_env *env,
85    struct uwx_self_info *info,
86    ucontext_t *ucontext)
87{
88    int status;
89    uint16_t reason;
90    uint64_t ip;
91    uint64_t sp;
92    uint64_t bsp;
93    uint64_t cfm;
94    unsigned int nat;
95    uint64_t ec;
96    int adj;
97
98    info->ucontext = ucontext;
99    status = __uc_get_reason(ucontext, &reason);
100    status = __uc_get_ip(ucontext, &ip);
101    status = __uc_get_grs(ucontext, 12, 1, &sp, &nat);
102    status = __uc_get_cfm(ucontext, &cfm);
103#ifdef NEW_UC_GET_AR
104    status = __uc_get_ar_bsp(ucontext, &bsp);
105    status = __uc_get_ar_bspstore(ucontext, &info->bspstore);
106    status = __uc_get_ar_ec(ucontext, &ec);
107#else
108    status = __uc_get_ar(ucontext, 17, &bsp);
109    status = __uc_get_ar(ucontext, 18, &info->bspstore);
110    status = __uc_get_ar(ucontext, 66, &ec);
111#endif
112    /* The returned bsp needs to be adjusted. */
113    /* For interrupt frames, where bsp was advanced by a cover */
114    /* instruction, subtract sof (size of frame). For non-interrupt */
115    /* frames, where bsp was advanced by br.call, subtract sol */
116    /* (size of locals). */
117    if (reason != 0)
118	adj = (unsigned int)cfm & 0x7f;		/* interrupt frame */
119    else
120	adj = ((unsigned int)cfm >> 7) & 0x7f;	/* non-interrupt frame */
121    bsp = uwx_add_to_bsp(bsp, -adj);
122    cfm |= ec << 52;
123    uwx_init_context(env, ip, sp, bsp, cfm);
124    return UWX_OK;
125}
126
127int uwx_self_do_context_frame(
128    struct uwx_env *env,
129    struct uwx_self_info *info)
130{
131    int abi_context;
132    int status;
133    uint64_t ucontext;
134
135    abi_context = uwx_get_abi_context_code(env);
136    if (abi_context != UWX_ABI_HPUX_SIGCONTEXT)
137	return UWX_SELF_ERR_BADABICONTEXT;
138    status = uwx_get_reg(env, UWX_REG_GR(32), (uint64_t *)&ucontext);
139    if (status != 0)
140	return status;
141    return uwx_self_init_from_sigcontext(env, info, (ucontext_t *)ucontext);
142}
143
144int uwx_self_copyin(
145    int request,
146    char *loc,
147    uint64_t rem,
148    int len,
149    intptr_t tok)
150{
151    int status;
152    int regid;
153    unsigned int nat;
154    struct uwx_self_info *info = (struct uwx_self_info *) tok;
155    unsigned long *wp;
156    uint64_t *dp;
157
158    status = -1;
159
160    dp = (uint64_t *) loc;
161
162    switch (request) {
163	case UWX_COPYIN_UINFO:
164	case UWX_COPYIN_MSTACK:
165	    if (len == 4) {
166		wp = (unsigned long *) loc;
167		*wp = *(unsigned long *)rem;
168		TRACE_SELF_COPYIN4(rem, len, wp)
169		status = 0;
170	    }
171	    else if (len == 8) {
172		*dp = *(uint64_t *)rem;
173		TRACE_SELF_COPYIN8(rem, len, dp)
174		status = 0;
175	    }
176	    break;
177	case UWX_COPYIN_RSTACK:
178	    if (len == 8) {
179		if (info->ucontext == 0 && rem == (info->bspstore | 0x1f8)) {
180		    *dp = info->env->context.special[UWX_REG_AR_RNAT];
181		    status = 0;
182		}
183		else if (info->ucontext == 0 || rem < info->bspstore) {
184		    *dp = *(uint64_t *)rem;
185		    TRACE_SELF_COPYIN8(rem, len, dp)
186		    status = 0;
187		}
188		else {
189		    status = __uc_get_rsebs(info->ucontext,
190						(uint64_t *)rem, 1, dp);
191		}
192	    }
193	    break;
194	case UWX_COPYIN_REG:
195	    regid = (int)rem;
196	    if (info->ucontext != 0) {
197		if (len == 8) {
198		    if (rem == UWX_REG_PREDS)
199			status = __uc_get_prs(info->ucontext, dp);
200		    else if (rem == UWX_REG_AR_PFS)
201			status = __uc_get_ar(info->ucontext, 64, dp);
202		    else if (rem == UWX_REG_AR_RNAT)
203			status = __uc_get_ar(info->ucontext, 19, dp);
204		    else if (rem == UWX_REG_AR_UNAT)
205			status = __uc_get_ar(info->ucontext, 36, dp);
206		    else if (rem == UWX_REG_AR_FPSR)
207			status = __uc_get_ar(info->ucontext, 40, dp);
208		    else if (rem == UWX_REG_AR_LC)
209			status = __uc_get_ar(info->ucontext, 65, dp);
210		    else if (regid >= UWX_REG_GR(1) &&
211						regid <= UWX_REG_GR(31))
212			status = __uc_get_grs(info->ucontext,
213					    regid - UWX_REG_GR(0), 1, dp, &nat);
214		    else if (regid >= UWX_REG_BR(0) &&
215						regid <= UWX_REG_BR(7))
216			status = __uc_get_brs(info->ucontext,
217					    regid - UWX_REG_BR(0), 1, dp);
218		}
219		else if (len == 16) {
220		    if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) {
221			status = __uc_get_frs(info->ucontext,
222				regid - UWX_REG_FR(0), 1, (fp_regval_t *)dp);
223		    }
224		}
225	    }
226	    break;
227    }
228    if (status != 0)
229	return 0;
230    return len;
231}
232
233
234int uwx_self_lookupip(
235    int request,
236    uint64_t ip,
237    intptr_t tok,
238    uint64_t **resultp)
239{
240    struct uwx_self_info *info = (struct uwx_self_info *) tok;
241    UINT64 handle;
242    struct load_module_desc desc;
243    uint64_t *unwind_base;
244    uint64_t *rvec;
245    int i;
246
247    if (request == UWX_LKUP_LOOKUP) {
248	TRACE_SELF_LOOKUP(ip)
249	if (ip >= info->sendsig_start && ip < info->sendsig_end) {
250	    i = 0;
251	    rvec = info->rvec;
252	    rvec[i++] = UWX_KEY_CONTEXT;
253	    rvec[i++] = UWX_ABI_HPUX_SIGCONTEXT;
254	    rvec[i++] = 0;
255	    rvec[i++] = 0;
256	    *resultp = rvec;
257	    return UWX_LKUP_FDESC;
258	}
259	else {
260	    handle = dlmodinfo(ip, &desc, sizeof(desc), 0, 0, 0);
261	    if (handle == 0)
262		return UWX_LKUP_ERR;
263	    unwind_base = (uint64_t *) desc.unwind_base;
264	    TRACE_SELF_LOOKUP_DESC(desc.text_base, unwind_base)
265	    i = 0;
266	    rvec = info->rvec;
267	    rvec[i++] = UWX_KEY_TBASE;
268	    rvec[i++] = desc.text_base;
269	    rvec[i++] = UWX_KEY_UFLAGS;
270	    rvec[i++] = unwind_base[0];
271	    rvec[i++] = UWX_KEY_USTART;
272	    rvec[i++] = desc.text_base + unwind_base[1];
273	    rvec[i++] = UWX_KEY_UEND;
274	    rvec[i++] = desc.text_base + unwind_base[2];
275	    rvec[i++] = 0;
276	    rvec[i++] = 0;
277	    *resultp = rvec;
278	    return UWX_LKUP_UTABLE;
279	}
280    }
281    else if (request == UWX_LKUP_FREE) {
282	return 0;
283    }
284}
285