blob: 949bf28f849c7ee3dceac7c1b1ac62eb11ca50ea [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
David Mosberger-Tange6b9f352007-08-22 13:02:09 -06003 Copyright (C) 2007 David Mosberger-Tang
4 Contributed by David Mosberger-Tang <dmosberger@gmail.com>
homeip.net!davidm588192d2004-08-17 15:34:28 +00005
6This file is part of libunwind.
7
8Permission is hereby granted, free of charge, to any person obtaining
9a copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sublicense, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice shall be
17included in all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
26
27#include <stdlib.h>
28#include <string.h>
29
30#include "unwind_i.h"
31
32#ifdef UNW_REMOTE_ONLY
33
34/* unw_local_addr_space is a NULL pointer in this case. */
35PROTECTED unw_addr_space_t unw_local_addr_space;
36
37#else /* !UNW_REMOTE_ONLY */
38
39static struct unw_addr_space local_addr_space;
40
41PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
42
homeip.net!davidm588192d2004-08-17 15:34:28 +000043# ifdef UNW_LOCAL_ONLY
44
45HIDDEN void *
46tdep_uc_addr (ucontext_t *uc, int reg)
47{
Konstantin Belousov0dbeeeb2010-04-05 22:42:23 +030048 return x86_r_uc_addr (uc, reg);
homeip.net!davidm588192d2004-08-17 15:34:28 +000049}
50
51# endif /* UNW_LOCAL_ONLY */
52
53HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
54
55/* XXX fix me: there is currently no way to locate the dyn-info list
56 by a remote unwinder. On ia64, this is done via a special
57 unwind-table entry. Perhaps something similar can be done with
58 DWARF2 unwind info. */
59
60static void
61put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
62{
63 /* it's a no-op */
64}
65
66static int
67get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
68 void *arg)
69{
70 *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
71 return 0;
72}
73
Arun Sharmaff0ae702009-03-16 11:06:26 -070074#define PAGE_SIZE 4096
75#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
76
77/* Cache of already validated addresses */
78#define NLGA 4
79static unw_word_t last_good_addr[NLGA];
80static int lga_victim;
81
82static int
83validate_mem (unw_word_t addr)
84{
85 int i, victim;
86
87 addr = PAGE_START(addr);
88
Paul Pluzhnikov0cf76ed2009-12-01 13:59:45 -080089 if (addr == 0)
90 return -1;
91
Arun Sharmaff0ae702009-03-16 11:06:26 -070092 for (i = 0; i < NLGA; i++)
93 {
94 if (last_good_addr[i] && (addr == last_good_addr[i]))
95 return 0;
96 }
97
Arun Sharma3468a6b2010-02-23 10:35:47 -080098 if (msync ((void *) addr, 1, MS_ASYNC) == -1)
Arun Sharmaff0ae702009-03-16 11:06:26 -070099 return -1;
100
101 victim = lga_victim;
102 for (i = 0; i < NLGA; i++) {
103 if (!last_good_addr[victim]) {
104 last_good_addr[victim++] = addr;
105 return 0;
106 }
107 victim = (victim + 1) % NLGA;
108 }
109
110 /* All slots full. Evict the victim. */
111 last_good_addr[victim] = addr;
112 victim = (victim + 1) % NLGA;
113 lga_victim = victim;
114
115 return 0;
116}
117
homeip.net!davidm588192d2004-08-17 15:34:28 +0000118static int
119access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
120 void *arg)
121{
122 if (write)
123 {
124 Debug (16, "mem[%x] <- %x\n", addr, *val);
125 *(unw_word_t *) addr = *val;
126 }
127 else
128 {
Arun Sharmaff0ae702009-03-16 11:06:26 -0700129 /* validate address */
130 const struct cursor *c = (const struct cursor *)arg;
131 if (c && c->validate && validate_mem(addr))
132 return -1;
homeip.net!davidm588192d2004-08-17 15:34:28 +0000133 *val = *(unw_word_t *) addr;
134 Debug (16, "mem[%x] -> %x\n", addr, *val);
135 }
136 return 0;
137}
138
139static int
140access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
141 void *arg)
142{
143 unw_word_t *addr;
Arun Sharmaff0ae702009-03-16 11:06:26 -0700144 ucontext_t *uc = ((struct cursor *)arg)->uc;
homeip.net!davidm588192d2004-08-17 15:34:28 +0000145
146 if (unw_is_fpreg (reg))
147 goto badreg;
148
Konstantin Belousov0dbeeeb2010-04-05 22:42:23 +0300149 if (!(addr = x86_r_uc_addr (uc, reg)))
homeip.net!davidm588192d2004-08-17 15:34:28 +0000150 goto badreg;
151
152 if (write)
153 {
154 *(unw_word_t *) addr = *val;
155 Debug (12, "%s <- %x\n", unw_regname (reg), *val);
156 }
157 else
158 {
159 *val = *(unw_word_t *) addr;
160 Debug (12, "%s -> %x\n", unw_regname (reg), *val);
161 }
162 return 0;
163
164 badreg:
165 Debug (1, "bad register number %u\n", reg);
166 return -UNW_EBADREG;
167}
168
169static int
170access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
171 int write, void *arg)
172{
Arun Sharmaff0ae702009-03-16 11:06:26 -0700173 ucontext_t *uc = ((struct cursor *)arg)->uc;
homeip.net!davidm588192d2004-08-17 15:34:28 +0000174 unw_fpreg_t *addr;
175
176 if (!unw_is_fpreg (reg))
177 goto badreg;
178
Konstantin Belousov0dbeeeb2010-04-05 22:42:23 +0300179 if (!(addr = x86_r_uc_addr (uc, reg)))
homeip.net!davidm588192d2004-08-17 15:34:28 +0000180 goto badreg;
181
182 if (write)
183 {
184 Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
185 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
186 *(unw_fpreg_t *) addr = *val;
187 }
188 else
189 {
190 *val = *(unw_fpreg_t *) addr;
191 Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
192 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
193 }
194 return 0;
195
196 badreg:
197 Debug (1, "bad register number %u\n", reg);
198 /* attempt to access a non-preserved register */
199 return -UNW_EBADREG;
200}
201
202static int
203get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
204 char *buf, size_t buf_len, unw_word_t *offp,
205 void *arg)
206{
David Mosberger-Tange6b9f352007-08-22 13:02:09 -0600207 return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
homeip.net!davidm588192d2004-08-17 15:34:28 +0000208}
209
210HIDDEN void
211x86_local_addr_space_init (void)
212{
213 memset (&local_addr_space, 0, sizeof (local_addr_space));
214 local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
215 local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
216 local_addr_space.acc.put_unwind_info = put_unwind_info;
217 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
218 local_addr_space.acc.access_mem = access_mem;
219 local_addr_space.acc.access_reg = access_reg;
220 local_addr_space.acc.access_fpreg = access_fpreg;
221 local_addr_space.acc.resume = x86_local_resume;
222 local_addr_space.acc.get_proc_name = get_static_proc_name;
223 unw_flush_cache (&local_addr_space, 0, 0);
224}
225
226#endif /* !UNW_REMOTE_ONLY */