1115013Smarcel/*
2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3121642SmarcelPermission is hereby granted, free of charge, to any person
4121642Smarcelobtaining a copy of this software and associated documentation
5121642Smarcelfiles (the "Software"), to deal in the Software without
6121642Smarcelrestriction, including without limitation the rights to use,
7121642Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell
8121642Smarcelcopies of the Software, and to permit persons to whom the
9121642SmarcelSoftware is furnished to do so, subject to the following
10121642Smarcelconditions:
11115013Smarcel
12121642SmarcelThe above copyright notice and this permission notice shall be
13121642Smarcelincluded in all copies or substantial portions of the Software.
14121642Smarcel
15121642SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16121642SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17121642SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18121642SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19121642SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20121642SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21121642SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22121642SmarcelOTHER DEALINGS IN THE SOFTWARE.
23121642Smarcel*/
24121642Smarcel
25115013Smarcel#include <stdlib.h>
26160157Smarcel#include <string.h>
27115013Smarcel#include <crt0.h>
28115013Smarcel#include <dlfcn.h>
29115013Smarcel#include <sys/uc_access.h>
30115013Smarcel
31115013Smarcel#include "uwx_env.h"
32115013Smarcel#include "uwx_context.h"
33115013Smarcel#include "uwx_trace.h"
34115013Smarcel#include "uwx_self.h"
35160157Smarcel#include "uwx_self_info.h"
36115013Smarcel
37115013Smarcel#define UWX_ABI_HPUX_SIGCONTEXT 0x0101	/* abi = HP-UX, context = 1 */
38115013Smarcel
39160157Smarcelvoid uwx_free_load_module_cache(struct uwx_self_info *info);
40115013Smarcel
41160157Smarcelint uwx_self_init_info_block(struct uwx_env *env, struct uwx_self_info *info)
42160157Smarcel{
43160157Smarcel    info->env = env;
44160157Smarcel    info->ucontext = 0;
45160157Smarcel    info->bspstore = 0;
46160157Smarcel    info->sendsig_start = __load_info->li_sendsig_txt;
47160157Smarcel    info->sendsig_end = __load_info->li_sendsig_txt +
48160157Smarcel				__load_info->li_sendsig_tsz;
49160157Smarcel    info->on_heap = 0;
50160157Smarcel    info->trace = env->trace;
51160157Smarcel    info->load_module_cache = NULL;
52160157Smarcel
53160157Smarcel    return UWX_OK;
54160157Smarcel}
55160157Smarcel
56115013Smarcelstruct uwx_self_info *uwx_self_init_info(struct uwx_env *env)
57115013Smarcel{
58115013Smarcel    struct uwx_self_info *info;
59115013Smarcel
60160157Smarcel    info = (struct uwx_self_info *)
61115013Smarcel			(*env->allocate_cb)(sizeof(struct uwx_self_info));
62115013Smarcel    if (info == 0)
63115013Smarcel	return 0;
64115013Smarcel
65160157Smarcel    uwx_self_init_info_block(env, info);
66160157Smarcel    info->on_heap = 1;
67115013Smarcel    return info;
68115013Smarcel}
69115013Smarcel
70115013Smarcelint uwx_self_free_info(struct uwx_self_info *info)
71115013Smarcel{
72160157Smarcel    int i;
73160157Smarcel
74160157Smarcel    if (info->load_module_cache != NULL)
75160157Smarcel	uwx_free_load_module_cache(info);
76160157Smarcel    if (info->on_heap)
77160157Smarcel	(*info->env->free_cb)((void *)info);
78115013Smarcel    return UWX_OK;
79115013Smarcel}
80115013Smarcel
81115013Smarcelint uwx_self_init_from_sigcontext(
82115013Smarcel    struct uwx_env *env,
83115013Smarcel    struct uwx_self_info *info,
84115013Smarcel    ucontext_t *ucontext)
85115013Smarcel{
86115013Smarcel    int status;
87115013Smarcel    uint16_t reason;
88115013Smarcel    uint64_t ip;
89115013Smarcel    uint64_t sp;
90115013Smarcel    uint64_t bsp;
91115013Smarcel    uint64_t cfm;
92115013Smarcel    unsigned int nat;
93115013Smarcel    uint64_t ec;
94120925Smarcel    int adj;
95115013Smarcel
96115013Smarcel    info->ucontext = ucontext;
97115013Smarcel    status = __uc_get_reason(ucontext, &reason);
98160157Smarcel    if (status != 0)
99160157Smarcel	return UWX_ERR_UCACCESS;
100115013Smarcel    status = __uc_get_ip(ucontext, &ip);
101160157Smarcel    if (status != 0)
102160157Smarcel	return UWX_ERR_UCACCESS;
103115013Smarcel    status = __uc_get_grs(ucontext, 12, 1, &sp, &nat);
104160157Smarcel    if (status != 0)
105160157Smarcel	return UWX_ERR_UCACCESS;
106120925Smarcel    status = __uc_get_cfm(ucontext, &cfm);
107160157Smarcel    if (status != 0)
108160157Smarcel	return UWX_ERR_UCACCESS;
109120925Smarcel#ifdef NEW_UC_GET_AR
110120925Smarcel    status = __uc_get_ar_bsp(ucontext, &bsp);
111160157Smarcel    if (status != 0)
112160157Smarcel	return UWX_ERR_UCACCESS;
113120925Smarcel    status = __uc_get_ar_bspstore(ucontext, &info->bspstore);
114160157Smarcel    if (status != 0)
115160157Smarcel	return UWX_ERR_UCACCESS;
116120925Smarcel    status = __uc_get_ar_ec(ucontext, &ec);
117160157Smarcel    if (status != 0)
118160157Smarcel	return UWX_ERR_UCACCESS;
119120925Smarcel#else
120115013Smarcel    status = __uc_get_ar(ucontext, 17, &bsp);
121160157Smarcel    if (status != 0)
122160157Smarcel	return UWX_ERR_UCACCESS;
123115013Smarcel    status = __uc_get_ar(ucontext, 18, &info->bspstore);
124160157Smarcel    if (status != 0)
125160157Smarcel	return UWX_ERR_UCACCESS;
126115013Smarcel    status = __uc_get_ar(ucontext, 66, &ec);
127160157Smarcel    if (status != 0)
128160157Smarcel	return UWX_ERR_UCACCESS;
129120925Smarcel#endif
130120925Smarcel    /* The returned bsp needs to be adjusted. */
131120925Smarcel    /* For interrupt frames, where bsp was advanced by a cover */
132120925Smarcel    /* instruction, subtract sof (size of frame). For non-interrupt */
133120925Smarcel    /* frames, where bsp was advanced by br.call, subtract sol */
134120925Smarcel    /* (size of locals). */
135120925Smarcel    if (reason != 0)
136120925Smarcel	adj = (unsigned int)cfm & 0x7f;		/* interrupt frame */
137120925Smarcel    else
138120925Smarcel	adj = ((unsigned int)cfm >> 7) & 0x7f;	/* non-interrupt frame */
139120925Smarcel    bsp = uwx_add_to_bsp(bsp, -adj);
140115013Smarcel    cfm |= ec << 52;
141115013Smarcel    uwx_init_context(env, ip, sp, bsp, cfm);
142115013Smarcel    return UWX_OK;
143115013Smarcel}
144115013Smarcel
145115013Smarcelint uwx_self_do_context_frame(
146115013Smarcel    struct uwx_env *env,
147115013Smarcel    struct uwx_self_info *info)
148115013Smarcel{
149115013Smarcel    int abi_context;
150115013Smarcel    int status;
151115013Smarcel    uint64_t ucontext;
152115013Smarcel
153115013Smarcel    abi_context = uwx_get_abi_context_code(env);
154115013Smarcel    if (abi_context != UWX_ABI_HPUX_SIGCONTEXT)
155115013Smarcel	return UWX_SELF_ERR_BADABICONTEXT;
156115013Smarcel    status = uwx_get_reg(env, UWX_REG_GR(32), (uint64_t *)&ucontext);
157160157Smarcel    if (status != UWX_OK)
158115013Smarcel	return status;
159160157Smarcel    return uwx_self_init_from_sigcontext(env, info,
160160157Smarcel					(ucontext_t *)(intptr_t)ucontext);
161115013Smarcel}
162115013Smarcel
163115013Smarcelint uwx_self_copyin(
164115013Smarcel    int request,
165115013Smarcel    char *loc,
166115013Smarcel    uint64_t rem,
167115013Smarcel    int len,
168115013Smarcel    intptr_t tok)
169115013Smarcel{
170115013Smarcel    int status;
171115013Smarcel    int regid;
172115013Smarcel    unsigned int nat;
173115013Smarcel    struct uwx_self_info *info = (struct uwx_self_info *) tok;
174115013Smarcel    unsigned long *wp;
175115013Smarcel    uint64_t *dp;
176115013Smarcel
177129059Smarcel    status = -1;
178129059Smarcel
179115013Smarcel    dp = (uint64_t *) loc;
180115013Smarcel
181129059Smarcel    switch (request) {
182129059Smarcel	case UWX_COPYIN_UINFO:
183129059Smarcel	case UWX_COPYIN_MSTACK:
184129059Smarcel	    if (len == 4) {
185129059Smarcel		wp = (unsigned long *) loc;
186160157Smarcel		*wp = *(unsigned long *)(intptr_t)rem;
187129059Smarcel		TRACE_SELF_COPYIN4(rem, len, wp)
188129059Smarcel		status = 0;
189115013Smarcel	    }
190129059Smarcel	    else if (len == 8) {
191160157Smarcel		*dp = *(uint64_t *)(intptr_t)rem;
192129059Smarcel		TRACE_SELF_COPYIN8(rem, len, dp)
193129059Smarcel		status = 0;
194129059Smarcel	    }
195129059Smarcel	    break;
196129059Smarcel	case UWX_COPYIN_RSTACK:
197129059Smarcel	    if (len == 8) {
198129059Smarcel		if (info->ucontext == 0 && rem == (info->bspstore | 0x1f8)) {
199129059Smarcel		    *dp = info->env->context.special[UWX_REG_AR_RNAT];
200129059Smarcel		    status = 0;
201129059Smarcel		}
202129059Smarcel		else if (info->ucontext == 0 || rem < info->bspstore) {
203160157Smarcel		    *dp = *(uint64_t *)(intptr_t)rem;
204129059Smarcel		    TRACE_SELF_COPYIN8(rem, len, dp)
205129059Smarcel		    status = 0;
206129059Smarcel		}
207129059Smarcel		else {
208129059Smarcel		    status = __uc_get_rsebs(info->ucontext,
209160157Smarcel					    (uint64_t *)(intptr_t)rem, 1, dp);
210129059Smarcel		}
211129059Smarcel	    }
212129059Smarcel	    break;
213129059Smarcel	case UWX_COPYIN_REG:
214129059Smarcel	    regid = (int)rem;
215129059Smarcel	    if (info->ucontext != 0) {
216129059Smarcel		if (len == 8) {
217129059Smarcel		    if (rem == UWX_REG_PREDS)
218129059Smarcel			status = __uc_get_prs(info->ucontext, dp);
219129059Smarcel		    else if (rem == UWX_REG_AR_PFS)
220129059Smarcel			status = __uc_get_ar(info->ucontext, 64, dp);
221129059Smarcel		    else if (rem == UWX_REG_AR_RNAT)
222129059Smarcel			status = __uc_get_ar(info->ucontext, 19, dp);
223129059Smarcel		    else if (rem == UWX_REG_AR_UNAT)
224129059Smarcel			status = __uc_get_ar(info->ucontext, 36, dp);
225129059Smarcel		    else if (rem == UWX_REG_AR_FPSR)
226129059Smarcel			status = __uc_get_ar(info->ucontext, 40, dp);
227129059Smarcel		    else if (rem == UWX_REG_AR_LC)
228129059Smarcel			status = __uc_get_ar(info->ucontext, 65, dp);
229129059Smarcel		    else if (regid >= UWX_REG_GR(1) &&
230129059Smarcel						regid <= UWX_REG_GR(31))
231129059Smarcel			status = __uc_get_grs(info->ucontext,
232129059Smarcel					    regid - UWX_REG_GR(0), 1, dp, &nat);
233129059Smarcel		    else if (regid >= UWX_REG_BR(0) &&
234129059Smarcel						regid <= UWX_REG_BR(7))
235129059Smarcel			status = __uc_get_brs(info->ucontext,
236129059Smarcel					    regid - UWX_REG_BR(0), 1, dp);
237129059Smarcel		}
238129059Smarcel		else if (len == 16) {
239129059Smarcel		    if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) {
240129059Smarcel			status = __uc_get_frs(info->ucontext,
241129059Smarcel				regid - UWX_REG_FR(0), 1, (fp_regval_t *)dp);
242129059Smarcel		    }
243129059Smarcel		}
244129059Smarcel	    }
245129059Smarcel	    break;
246115013Smarcel    }
247129059Smarcel    if (status != 0)
248129059Smarcel	return 0;
249115013Smarcel    return len;
250115013Smarcel}
251115013Smarcel
252160157Smarcel#define MODULE_CACHE_SIZE 4
253115013Smarcel
254160157Smarcelstruct load_module_cache {
255160157Smarcel    int clock;
256160157Smarcel    char *names[MODULE_CACHE_SIZE];
257160157Smarcel    struct load_module_desc descs[MODULE_CACHE_SIZE];
258160157Smarcel    struct uwx_symbol_cache *symbol_cache;
259160157Smarcel};
260160157Smarcel
261160157Smarcelvoid uwx_free_load_module_cache(struct uwx_self_info *info)
262160157Smarcel{
263160157Smarcel    int i;
264160157Smarcel
265160157Smarcel    for (i = 0; i < MODULE_CACHE_SIZE; i++) {
266160157Smarcel	if (info->load_module_cache->names[i] != NULL)
267160157Smarcel	    (*info->env->free_cb)((void *)info->load_module_cache->names[i]);
268160157Smarcel    }
269160157Smarcel
270160157Smarcel    if (info->load_module_cache->symbol_cache != NULL)
271160157Smarcel	uwx_release_symbol_cache(info->env,
272160157Smarcel				    info->load_module_cache->symbol_cache);
273160157Smarcel
274160157Smarcel    (*info->env->free_cb)((void *)info->load_module_cache);
275160157Smarcel}
276160157Smarcel
277160157Smarcelstruct load_module_desc *uwx_get_modinfo(
278160157Smarcel    struct uwx_self_info *info,
279160157Smarcel    uint64_t ip,
280160157Smarcel    char **module_name_p)
281160157Smarcel{
282160157Smarcel    int i;
283160157Smarcel    UINT64 handle;
284160157Smarcel    struct load_module_cache *cache;
285160157Smarcel    struct load_module_desc *desc;
286160157Smarcel    char *module_name;
287160157Smarcel
288160157Smarcel    cache = info->load_module_cache;
289160157Smarcel    if (cache == NULL) {
290160157Smarcel	cache = (struct load_module_cache *)
291160157Smarcel		(*info->env->allocate_cb)(sizeof(struct load_module_cache));
292160157Smarcel	if (cache == NULL)
293160157Smarcel	    return NULL;
294160157Smarcel	for (i = 0; i < MODULE_CACHE_SIZE; i++) {
295160157Smarcel	    desc = &cache->descs[i];
296160157Smarcel	    desc->text_base = 0;
297160157Smarcel	    desc->text_size = 0;
298160157Smarcel	    cache->names[i] = NULL;
299160157Smarcel	}
300160157Smarcel	cache->clock = 0;
301160157Smarcel	cache->symbol_cache = NULL;
302160157Smarcel	info->load_module_cache = cache;
303160157Smarcel    }
304160157Smarcel    for (i = 0; i < MODULE_CACHE_SIZE; i++) {
305160157Smarcel	desc = &cache->descs[i];
306160157Smarcel	if (ip >= desc->text_base && ip < desc->text_base + desc->text_size)
307160157Smarcel	    break;
308160157Smarcel    }
309160157Smarcel    if (i >= MODULE_CACHE_SIZE) {
310160157Smarcel	i = cache->clock;
311160157Smarcel	cache->clock = (cache->clock + 1) % MODULE_CACHE_SIZE;
312160157Smarcel	desc = &cache->descs[i];
313160157Smarcel	handle = dlmodinfo(ip, desc, sizeof(*desc), 0, 0, 0);
314160157Smarcel	if (handle == 0)
315160157Smarcel	    return NULL;
316160157Smarcel	if (cache->names[i] != NULL)
317160157Smarcel	    (*info->env->free_cb)(cache->names[i]);
318160157Smarcel	cache->names[i] = NULL;
319160157Smarcel    }
320160157Smarcel    if (module_name_p != NULL) {
321160157Smarcel	if (cache->names[i] == NULL) {
322160157Smarcel	    module_name = dlgetname(desc, sizeof(*desc), 0, 0, 0);
323160157Smarcel	    if (module_name != NULL) {
324160157Smarcel		cache->names[i] = (char *)
325160157Smarcel			    (*info->env->allocate_cb)(strlen(module_name)+1);
326160157Smarcel		if (cache->names[i] != NULL)
327160157Smarcel		    strcpy(cache->names[i], module_name);
328160157Smarcel	    }
329160157Smarcel	}
330160157Smarcel	*module_name_p = cache->names[i];
331160157Smarcel    }
332160157Smarcel    return desc;
333160157Smarcel}
334160157Smarcel
335115013Smarcelint uwx_self_lookupip(
336115013Smarcel    int request,
337115013Smarcel    uint64_t ip,
338115013Smarcel    intptr_t tok,
339115013Smarcel    uint64_t **resultp)
340115013Smarcel{
341115013Smarcel    struct uwx_self_info *info = (struct uwx_self_info *) tok;
342115013Smarcel    UINT64 handle;
343160157Smarcel    struct load_module_desc *desc;
344115013Smarcel    uint64_t *unwind_base;
345115013Smarcel    uint64_t *rvec;
346160157Smarcel    char *module_name;
347160157Smarcel    char *func_name;
348160157Smarcel    uint64_t offset;
349115013Smarcel    int i;
350160157Smarcel    int status;
351115013Smarcel
352115013Smarcel    if (request == UWX_LKUP_LOOKUP) {
353115013Smarcel	TRACE_SELF_LOOKUP(ip)
354115013Smarcel	if (ip >= info->sendsig_start && ip < info->sendsig_end) {
355115013Smarcel	    i = 0;
356115013Smarcel	    rvec = info->rvec;
357115013Smarcel	    rvec[i++] = UWX_KEY_CONTEXT;
358115013Smarcel	    rvec[i++] = UWX_ABI_HPUX_SIGCONTEXT;
359160157Smarcel	    rvec[i++] = UWX_KEY_END;
360115013Smarcel	    rvec[i++] = 0;
361115013Smarcel	    *resultp = rvec;
362115013Smarcel	    return UWX_LKUP_FDESC;
363115013Smarcel	}
364115013Smarcel	else {
365160157Smarcel	    desc = uwx_get_modinfo(info, ip, NULL);
366160157Smarcel	    if (desc == NULL)
367115013Smarcel		return UWX_LKUP_ERR;
368160157Smarcel	    unwind_base = (uint64_t *) (intptr_t) desc->unwind_base;
369160157Smarcel	    TRACE_SELF_LOOKUP_DESC(desc->text_base,
370160157Smarcel					desc->linkage_ptr, unwind_base)
371115013Smarcel	    i = 0;
372115013Smarcel	    rvec = info->rvec;
373115013Smarcel	    rvec[i++] = UWX_KEY_TBASE;
374160157Smarcel	    rvec[i++] = desc->text_base;
375115013Smarcel	    rvec[i++] = UWX_KEY_UFLAGS;
376115013Smarcel	    rvec[i++] = unwind_base[0];
377115013Smarcel	    rvec[i++] = UWX_KEY_USTART;
378160157Smarcel	    rvec[i++] = desc->text_base + unwind_base[1];
379115013Smarcel	    rvec[i++] = UWX_KEY_UEND;
380160157Smarcel	    rvec[i++] = desc->text_base + unwind_base[2];
381160157Smarcel	    rvec[i++] = UWX_KEY_GP;
382160157Smarcel	    rvec[i++] = desc->linkage_ptr;
383160157Smarcel	    rvec[i++] = UWX_KEY_END;
384115013Smarcel	    rvec[i++] = 0;
385115013Smarcel	    *resultp = rvec;
386115013Smarcel	    return UWX_LKUP_UTABLE;
387115013Smarcel	}
388115013Smarcel    }
389115013Smarcel    else if (request == UWX_LKUP_FREE) {
390115013Smarcel	return 0;
391115013Smarcel    }
392160157Smarcel    else if (request == UWX_LKUP_MODULE) {
393160157Smarcel	desc = uwx_get_modinfo(info, ip, &module_name);
394160157Smarcel	if (desc == NULL)
395160157Smarcel	    return UWX_LKUP_ERR;
396160157Smarcel	if (module_name == NULL)
397160157Smarcel	    return UWX_LKUP_ERR;
398160157Smarcel	i = 0;
399160157Smarcel	rvec = info->rvec;
400160157Smarcel	rvec[i++] = UWX_KEY_MODULE;
401160157Smarcel	rvec[i++] = (uint64_t)(intptr_t)module_name;
402160157Smarcel	rvec[i++] = UWX_KEY_TBASE;
403160157Smarcel	rvec[i++] = desc->text_base;
404160157Smarcel	rvec[i++] = UWX_KEY_END;
405160157Smarcel	rvec[i++] = 0;
406160157Smarcel	*resultp = rvec;
407160157Smarcel	return UWX_LKUP_SYMINFO;
408160157Smarcel    }
409160157Smarcel    else if (request == UWX_LKUP_SYMBOLS) {
410160157Smarcel	rvec = *resultp;
411160157Smarcel	for (i = 0; rvec[i] != UWX_KEY_END; i += 2) {
412160157Smarcel	    if (rvec[i] == UWX_KEY_FUNCSTART)
413160157Smarcel		ip = rvec[i+1];
414160157Smarcel	}
415160157Smarcel	desc = uwx_get_modinfo(info, ip, &module_name);
416160157Smarcel	if (desc == NULL)
417160157Smarcel	    return UWX_LKUP_ERR;
418160157Smarcel	if (module_name == NULL)
419160157Smarcel	    return UWX_LKUP_ERR;
420160157Smarcel	status = uwx_find_symbol(info->env,
421160157Smarcel			&info->load_module_cache->symbol_cache,
422160157Smarcel			module_name, ip - desc->text_base,
423160157Smarcel			&func_name, &offset);
424160157Smarcel	i = 0;
425160157Smarcel	rvec = info->rvec;
426160157Smarcel	rvec[i++] = UWX_KEY_MODULE;
427160157Smarcel	rvec[i++] = (uint64_t)(intptr_t)module_name;
428160157Smarcel	rvec[i++] = UWX_KEY_TBASE;
429160157Smarcel	rvec[i++] = desc->text_base;
430160157Smarcel	if (status == UWX_OK) {
431160157Smarcel	    rvec[i++] = UWX_KEY_FUNC;
432160157Smarcel	    rvec[i++] = (uint64_t)(intptr_t)func_name;
433160157Smarcel	    rvec[i++] = UWX_KEY_FUNCSTART;
434160157Smarcel	    rvec[i++] = ip - offset;
435160157Smarcel	}
436160157Smarcel	rvec[i++] = UWX_KEY_END;
437160157Smarcel	rvec[i++] = 0;
438160157Smarcel	*resultp = rvec;
439160157Smarcel	return UWX_LKUP_SYMINFO;
440160157Smarcel    }
441160157Smarcel    return UWX_LKUP_ERR;
442115013Smarcel}
443