blob: 3b206a3ee757379df174e255fdf5bfc4d924aae3 [file] [log] [blame]
homeip.net!davidm588192d2004-08-17 15:34:28 +00001/* libunwind - a platform-independent unwind library
2 Copyright (C) 2002 Hewlett-Packard Co
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
26#include <stdlib.h>
27#include <string.h>
28
29#include "unwind_i.h"
30
31#ifdef UNW_REMOTE_ONLY
32
33/* unw_local_addr_space is a NULL pointer in this case. */
34PROTECTED unw_addr_space_t unw_local_addr_space;
35
36#else /* !UNW_REMOTE_ONLY */
37
38static struct unw_addr_space local_addr_space;
39
40PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
41
42static inline void *
43uc_addr (ucontext_t *uc, int reg)
44{
45 void *addr;
46
47 switch (reg)
48 {
49 case UNW_X86_GS: addr = &uc->uc_mcontext.gregs[REG_GS]; break;
50 case UNW_X86_FS: addr = &uc->uc_mcontext.gregs[REG_FS]; break;
51 case UNW_X86_ES: addr = &uc->uc_mcontext.gregs[REG_ES]; break;
52 case UNW_X86_DS: addr = &uc->uc_mcontext.gregs[REG_DS]; break;
53 case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break;
54 case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break;
55 case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break;
56 case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break;
57 case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break;
58 case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break;
59 case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break;
60 case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break;
61 case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break;
62 case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break;
63 case UNW_X86_CS: addr = &uc->uc_mcontext.gregs[REG_CS]; break;
64 case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.gregs[REG_EFL]; break;
65 case UNW_X86_SS: addr = &uc->uc_mcontext.gregs[REG_SS]; break;
66
67 default:
68 addr = NULL;
69 }
70 return addr;
71}
72
73# ifdef UNW_LOCAL_ONLY
74
75HIDDEN void *
76tdep_uc_addr (ucontext_t *uc, int reg)
77{
78 return uc_addr (uc, reg);
79}
80
81# endif /* UNW_LOCAL_ONLY */
82
83HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
84
85/* XXX fix me: there is currently no way to locate the dyn-info list
86 by a remote unwinder. On ia64, this is done via a special
87 unwind-table entry. Perhaps something similar can be done with
88 DWARF2 unwind info. */
89
90static void
91put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
92{
93 /* it's a no-op */
94}
95
96static int
97get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
98 void *arg)
99{
100 *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
101 return 0;
102}
103
104static int
105access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
106 void *arg)
107{
108 if (write)
109 {
110 Debug (16, "mem[%x] <- %x\n", addr, *val);
111 *(unw_word_t *) addr = *val;
112 }
113 else
114 {
115 *val = *(unw_word_t *) addr;
116 Debug (16, "mem[%x] -> %x\n", addr, *val);
117 }
118 return 0;
119}
120
121static int
122access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
123 void *arg)
124{
125 unw_word_t *addr;
126 ucontext_t *uc = arg;
127
128 if (unw_is_fpreg (reg))
129 goto badreg;
130
homeip.net!davidm588192d2004-08-17 15:34:28 +0000131 if (!(addr = uc_addr (uc, reg)))
132 goto badreg;
133
134 if (write)
135 {
136 *(unw_word_t *) addr = *val;
137 Debug (12, "%s <- %x\n", unw_regname (reg), *val);
138 }
139 else
140 {
141 *val = *(unw_word_t *) addr;
142 Debug (12, "%s -> %x\n", unw_regname (reg), *val);
143 }
144 return 0;
145
146 badreg:
147 Debug (1, "bad register number %u\n", reg);
148 return -UNW_EBADREG;
149}
150
151static int
152access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
153 int write, void *arg)
154{
155 ucontext_t *uc = arg;
156 unw_fpreg_t *addr;
157
158 if (!unw_is_fpreg (reg))
159 goto badreg;
160
161 if (!(addr = uc_addr (uc, reg)))
162 goto badreg;
163
164 if (write)
165 {
166 Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
167 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
168 *(unw_fpreg_t *) addr = *val;
169 }
170 else
171 {
172 *val = *(unw_fpreg_t *) addr;
173 Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
174 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
175 }
176 return 0;
177
178 badreg:
179 Debug (1, "bad register number %u\n", reg);
180 /* attempt to access a non-preserved register */
181 return -UNW_EBADREG;
182}
183
184static int
185get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
186 char *buf, size_t buf_len, unw_word_t *offp,
187 void *arg)
188{
189 return _Uelf32_get_proc_name (getpid (), ip, buf, buf_len, offp);
190}
191
192HIDDEN void
193x86_local_addr_space_init (void)
194{
195 memset (&local_addr_space, 0, sizeof (local_addr_space));
196 local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
197 local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
198 local_addr_space.acc.put_unwind_info = put_unwind_info;
199 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
200 local_addr_space.acc.access_mem = access_mem;
201 local_addr_space.acc.access_reg = access_reg;
202 local_addr_space.acc.access_fpreg = access_fpreg;
203 local_addr_space.acc.resume = x86_local_resume;
204 local_addr_space.acc.get_proc_name = get_static_proc_name;
205 unw_flush_cache (&local_addr_space, 0, 0);
206}
207
208#endif /* !UNW_REMOTE_ONLY */