2 * Copyright (c) 2003, 2004 Marcel Moolenaar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/queue.h>
37 #include <machine/frame.h>
38 #include <machine/md_var.h>
39 #include <machine/pcb.h>
40 #include <machine/unwind.h>
44 static MALLOC_DEFINE(M_UNWIND, "Unwind", "Unwind information");
47 uint64_t ue_start; /* procedure start */
48 uint64_t ue_end; /* procedure end */
49 uint64_t ue_info; /* offset to procedure descriptors */
53 LIST_ENTRY(unw_table) ut_link;
56 struct unw_entry *ut_start;
57 struct unw_entry *ut_end;
60 LIST_HEAD(unw_table_list, unw_table);
62 static struct unw_table_list unw_tables;
65 #define KDBHEAPSZ 8192
69 #define MSIG_FREE 0x65657246 /* "Free". */
70 #define MSIG_USED 0x64657355 /* "Used". */
76 static struct mhdr *kdbheap;
83 struct mhdr *hdr, *hfree;
88 while (hdr->sig != MSIG_FREE || hdr->size < sz) {
91 hdr = kdbheap + hdr->next;
93 if (hdr->size > sz + 1) {
95 hfree->sig = MSIG_FREE;
96 hfree->size = hdr->size - sz - 1;
97 hfree->prev = hdr - kdbheap;
98 hfree->next = hdr->next;
100 hdr->next = hfree - kdbheap;
101 if (hfree->next >= 0) {
102 hfree = kdbheap + hfree->next;
103 hfree->prev = hdr->next;
106 hdr->sig = MSIG_USED;
107 return (void*)(hdr + 1);
110 return (malloc(sz, M_UNWIND, M_NOWAIT));
117 struct mhdr *hdr, *hfree;
120 hdr = (struct mhdr*)p - 1;
121 if (hdr->sig != MSIG_USED)
123 hdr->sig = MSIG_FREE;
124 if (hdr->prev >= 0 && kdbheap[hdr->prev].sig == MSIG_FREE) {
125 hfree = kdbheap + hdr->prev;
126 hfree->size += hdr->size + 1;
127 hfree->next = hdr->next;
128 if (hdr->next >= 0) {
129 hfree = kdbheap + hdr->next;
130 hfree->prev = hdr->prev;
132 } else if (hdr->next >= 0 &&
133 kdbheap[hdr->next].sig == MSIG_FREE) {
134 hfree = kdbheap + hdr->next;
135 hdr->size += hfree->size + 1;
136 hdr->next = hfree->next;
137 if (hdr->next >= 0) {
138 hfree = kdbheap + hdr->next;
139 hfree->prev = hdr - kdbheap;
148 static struct unw_table *
149 unw_table_lookup(uint64_t ip)
151 struct unw_table *ut;
153 LIST_FOREACH(ut, &unw_tables, ut_link) {
154 if (ip >= ut->ut_base && ip < ut->ut_limit)
161 unw_copyin_from_frame(struct trapframe *tf, uint64_t from)
166 if (from == UWX_REG_AR_PFS)
167 val = tf->tf_special.pfs;
168 else if (from == UWX_REG_PREDS)
169 val = tf->tf_special.pr;
170 else if (from == UWX_REG_AR_RNAT)
171 val = tf->tf_special.rnat;
172 else if (from == UWX_REG_AR_UNAT)
173 val = tf->tf_special.unat;
174 else if (from >= UWX_REG_GR(0) && from <= UWX_REG_GR(127)) {
175 reg = from - UWX_REG_GR(0);
177 val = tf->tf_special.gp;
179 val = tf->tf_special.sp;
181 val = tf->tf_special.tp;
182 else if (reg >= 2 && reg <= 3)
183 val = (&tf->tf_scratch.gr2)[reg - 2];
184 else if (reg >= 8 && reg <= 11)
185 val = (&tf->tf_scratch.gr8)[reg - 8];
186 else if (reg >= 14 && reg <= 31)
187 val = (&tf->tf_scratch.gr14)[reg - 14];
190 } else if (from >= UWX_REG_BR(0) && from <= UWX_REG_BR(7)) {
191 reg = from - UWX_REG_BR(0);
193 val = tf->tf_special.rp;
194 else if (reg >= 6 && reg <= 7)
195 val = (&tf->tf_scratch.br6)[reg - 6];
203 printf("UNW: %s(%p, %lx)\n", __func__, tf, from);
208 unw_copyin_from_pcb(struct pcb *pcb, uint64_t from)
213 if (from == UWX_REG_AR_PFS)
214 val = pcb->pcb_special.pfs;
215 else if (from == UWX_REG_PREDS)
216 val = pcb->pcb_special.pr;
217 else if (from == UWX_REG_AR_RNAT)
218 val = pcb->pcb_special.rnat;
219 else if (from == UWX_REG_AR_UNAT)
220 val = pcb->pcb_special.unat;
221 else if (from >= UWX_REG_GR(0) && from <= UWX_REG_GR(127)) {
222 reg = from - UWX_REG_GR(0);
224 val = pcb->pcb_special.gp;
226 val = pcb->pcb_special.sp;
228 val = pcb->pcb_special.tp;
229 else if (reg >= 4 && reg <= 7)
230 val = (&pcb->pcb_preserved.gr4)[reg - 4];
233 } else if (from >= UWX_REG_BR(0) && from <= UWX_REG_BR(7)) {
234 reg = from - UWX_REG_BR(0);
236 val = pcb->pcb_special.rp;
237 else if (reg >= 1 && reg <= 5)
238 val = (&pcb->pcb_preserved.br1)[reg - 1];
246 printf("UNW: %s(%p, %lx)\n", __func__, pcb, from);
251 unw_cb_copyin(int req, char *to, uint64_t from, int len, intptr_t tok)
253 struct unw_regstate *rs = (void*)tok;
257 case UWX_COPYIN_UINFO:
259 case UWX_COPYIN_MSTACK:
260 *((uint64_t*)to) = *((uint64_t*)from);
262 case UWX_COPYIN_RSTACK:
263 *((uint64_t*)to) = *((uint64_t*)from);
266 if (rs->frame != NULL)
267 val = unw_copyin_from_frame(rs->frame, from);
268 else if (rs->pcb != NULL)
269 val = unw_copyin_from_pcb(rs->pcb, from);
272 *((uint64_t*)to) = val;
277 printf("UNW: %s(%d, %p, %lx, %d, %lx)\n", __func__, req, to, from,
283 unw_cb_lookup(int req, uint64_t ip, intptr_t tok, uint64_t **vec)
285 struct unw_regstate *rs = (void*)tok;
286 struct unw_table *ut;
289 case UWX_LKUP_LOOKUP:
290 ut = unw_table_lookup(ip);
292 return (UWX_LKUP_NOTFOUND);
293 rs->keyval[0] = UWX_KEY_TBASE;
294 rs->keyval[1] = ut->ut_base;
295 rs->keyval[2] = UWX_KEY_USTART;
296 rs->keyval[3] = (intptr_t)ut->ut_start;
297 rs->keyval[4] = UWX_KEY_UEND;
298 rs->keyval[5] = (intptr_t)ut->ut_end;
302 return (UWX_LKUP_UTABLE);
307 return (UWX_LKUP_ERR);
311 unw_create_from_frame(struct unw_regstate *rs, struct trapframe *tf)
318 rs->env = uwx_init();
322 uwxerr = uwx_register_callbacks(rs->env, (intptr_t)rs,
323 unw_cb_copyin, unw_cb_lookup);
325 return (EINVAL); /* XXX */
327 bsp = tf->tf_special.bspstore + tf->tf_special.ndirty;
328 bsp = ia64_bsp_adjust(bsp, -IA64_CFM_SOF(tf->tf_special.cfm));
329 ip = tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3);
331 uwxerr = uwx_init_context(rs->env, ip, tf->tf_special.sp, bsp,
334 return ((uwxerr) ? EINVAL : 0); /* XXX */
338 unw_create_from_pcb(struct unw_regstate *rs, struct pcb *pcb)
340 uint64_t bsp, cfm, ip;
345 rs->env = uwx_init();
349 uwxerr = uwx_register_callbacks(rs->env, (intptr_t)rs,
350 unw_cb_copyin, unw_cb_lookup);
352 return (EINVAL); /* XXX */
354 bsp = pcb->pcb_special.bspstore;
355 if (pcb->pcb_special.__spare == ~0UL) {
356 ip = pcb->pcb_special.iip + ((pcb->pcb_special.psr >> 41) & 3);
357 cfm = pcb->pcb_special.cfm;
358 bsp += pcb->pcb_special.ndirty;
359 bsp = ia64_bsp_adjust(bsp, -IA64_CFM_SOF(cfm));
361 ip = pcb->pcb_special.rp;
362 cfm = pcb->pcb_special.pfs;
363 bsp = ia64_bsp_adjust(bsp, -IA64_CFM_SOL(cfm));
365 uwxerr = uwx_init_context(rs->env, ip, pcb->pcb_special.sp, bsp, cfm);
367 return ((uwxerr) ? EINVAL : 0); /* XXX */
371 unw_delete(struct unw_regstate *rs)
379 unw_step(struct unw_regstate *rs)
383 switch (uwx_step(rs->env)) {
394 err = EINVAL; /* XXX */
401 unw_get_bsp(struct unw_regstate *s, uint64_t *r)
405 uwxerr = uwx_get_reg(s->env, UWX_REG_BSP, r);
406 return ((uwxerr) ? EINVAL : 0); /* XXX */
410 unw_get_cfm(struct unw_regstate *s, uint64_t *r)
414 uwxerr = uwx_get_reg(s->env, UWX_REG_CFM, r);
415 return ((uwxerr) ? EINVAL : 0); /* XXX */
419 unw_get_ip(struct unw_regstate *s, uint64_t *r)
423 uwxerr = uwx_get_reg(s->env, UWX_REG_IP, r);
424 return ((uwxerr) ? EINVAL : 0); /* XXX */
428 unw_get_sp(struct unw_regstate *s, uint64_t *r)
432 uwxerr = uwx_get_reg(s->env, UWX_REG_SP, r);
433 return ((uwxerr) ? EINVAL : 0); /* XXX */
437 unw_table_add(uint64_t base, uint64_t start, uint64_t end)
439 struct unw_table *ut;
441 ut = malloc(sizeof(struct unw_table), M_UNWIND, M_WAITOK);
443 ut->ut_start = (struct unw_entry*)start;
444 ut->ut_end = (struct unw_entry*)end;
445 ut->ut_limit = base + ut->ut_end[-1].ue_end;
446 LIST_INSERT_HEAD(&unw_tables, ut, ut_link);
449 printf("UNWIND: table added: base=%lx, start=%lx, end=%lx\n",
456 unw_table_remove(uint64_t base)
458 struct unw_table *ut;
460 ut = unw_table_lookup(base);
462 LIST_REMOVE(ut, ut_link);
465 printf("UNWIND: table removed: base=%lx\n", base);
470 unw_initialize(void *dummy __unused)
473 LIST_INIT(&unw_tables);
474 uwx_register_alloc_cb(unw_alloc, unw_free);
476 kdbheap = malloc(KDBHEAPSZ, M_UNWIND, M_WAITOK);
477 kdbheap->sig = MSIG_FREE;
478 kdbheap->size = (KDBHEAPSZ - sizeof(struct mhdr)) >> 4;
483 SYSINIT(unwind, SI_SUB_KMEM, SI_ORDER_ANY, unw_initialize, 0);