]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/ia64/libuwx/src/uwx_self.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / ia64 / libuwx / src / uwx_self.c
1 /*
2 Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
10 conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER 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
39 void uwx_free_load_module_cache(struct uwx_self_info *info);
40
41 int 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
56 struct 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
70 int 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
81 int 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
145 int 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
163 int 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
254 struct 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
261 void 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
277 struct 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
335 int 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 }