blob: b1e5228442a570efa629db8e4de100a944c5bc10 [file] [log] [blame]
Daniel Jacobowitz3842dac2008-02-04 17:16:37 -07001/* libunwind - a platform-independent unwind library
2 Copyright (C) 2008 CodeSourcery
3
4This file is part of libunwind.
5
6Permission is hereby granted, free of charge, to any person obtaining
7a copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sublicense, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice shall be
15included in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
24
25#include <stdlib.h>
26#include <string.h>
27
28#include "unwind_i.h"
29
30#ifdef UNW_REMOTE_ONLY
31
32/* unw_local_addr_space is a NULL pointer in this case. */
33PROTECTED unw_addr_space_t unw_local_addr_space;
34
35#else /* !UNW_REMOTE_ONLY */
36
37static struct unw_addr_space local_addr_space;
38
39PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
40
41static inline void *
42uc_addr (ucontext_t *uc, int reg)
43{
44 void *addr;
45
46 switch (reg)
47 {
48 case UNW_ARM_R0: addr = &uc->uc_mcontext.arm_r0; break;
49 case UNW_ARM_R1: addr = &uc->uc_mcontext.arm_r1; break;
50 case UNW_ARM_R2: addr = &uc->uc_mcontext.arm_r2; break;
51 case UNW_ARM_R3: addr = &uc->uc_mcontext.arm_r3; break;
52 case UNW_ARM_R4: addr = &uc->uc_mcontext.arm_r4; break;
53 case UNW_ARM_R5: addr = &uc->uc_mcontext.arm_r5; break;
54 case UNW_ARM_R6: addr = &uc->uc_mcontext.arm_r6; break;
55 case UNW_ARM_R7: addr = &uc->uc_mcontext.arm_r7; break;
56 case UNW_ARM_R8: addr = &uc->uc_mcontext.arm_r8; break;
57 case UNW_ARM_R9: addr = &uc->uc_mcontext.arm_r9; break;
58 case UNW_ARM_R10: addr = &uc->uc_mcontext.arm_r10; break;
59 case UNW_ARM_R11: addr = &uc->uc_mcontext.arm_fp; break;
60 case UNW_ARM_R12: addr = &uc->uc_mcontext.arm_ip; break;
61 case UNW_ARM_R13: addr = &uc->uc_mcontext.arm_sp; break;
62 case UNW_ARM_R14: addr = &uc->uc_mcontext.arm_lr; break;
63 case UNW_ARM_R15: addr = &uc->uc_mcontext.arm_pc; break;
64
65 default:
66 addr = NULL;
67 }
68 return addr;
69}
70
71# ifdef UNW_LOCAL_ONLY
72
73HIDDEN void *
74tdep_uc_addr (ucontext_t *uc, int reg)
75{
76 return uc_addr (uc, reg);
77}
78
79# endif /* UNW_LOCAL_ONLY */
80
81HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
82
83/* XXX fix me: there is currently no way to locate the dyn-info list
84 by a remote unwinder. On ia64, this is done via a special
85 unwind-table entry. Perhaps something similar can be done with
86 DWARF2 unwind info. */
87
Daniel Jacobowitz3842dac2008-02-04 17:16:37 -070088static int
89get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
90 void *arg)
91{
92 *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
93 return 0;
94}
95
96static int
97access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
98 void *arg)
99{
100 if (write)
101 {
102 Debug (16, "mem[%x] <- %x\n", addr, *val);
103 *(unw_word_t *) addr = *val;
104 }
105 else
106 {
107 *val = *(unw_word_t *) addr;
108 Debug (16, "mem[%x] -> %x\n", addr, *val);
109 }
110 return 0;
111}
112
113static int
114access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
115 void *arg)
116{
117 unw_word_t *addr;
118 ucontext_t *uc = arg;
119
120 if (unw_is_fpreg (reg))
121 goto badreg;
122
123Debug (16, "reg = %s\n", unw_regname (reg));
124 if (!(addr = uc_addr (uc, reg)))
125 goto badreg;
126
127 if (write)
128 {
129 *(unw_word_t *) addr = *val;
130 Debug (12, "%s <- %x\n", unw_regname (reg), *val);
131 }
132 else
133 {
134 *val = *(unw_word_t *) addr;
135 Debug (12, "%s -> %x\n", unw_regname (reg), *val);
136 }
137 return 0;
138
139 badreg:
140 Debug (1, "bad register number %u\n", reg);
141 return -UNW_EBADREG;
142}
143
144static int
145access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
146 int write, void *arg)
147{
148 ucontext_t *uc = arg;
149 unw_fpreg_t *addr;
150
151 if (!unw_is_fpreg (reg))
152 goto badreg;
153
154 if (!(addr = uc_addr (uc, reg)))
155 goto badreg;
156
157 if (write)
158 {
159 Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
160 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
161 *(unw_fpreg_t *) addr = *val;
162 }
163 else
164 {
165 *val = *(unw_fpreg_t *) addr;
166 Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
167 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
168 }
169 return 0;
170
171 badreg:
172 Debug (1, "bad register number %u\n", reg);
173 /* attempt to access a non-preserved register */
174 return -UNW_EBADREG;
175}
176
177static int
178get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
179 char *buf, size_t buf_len, unw_word_t *offp,
180 void *arg)
181{
182 return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
183}
184
185HIDDEN void
186arm_local_addr_space_init (void)
187{
188 memset (&local_addr_space, 0, sizeof (local_addr_space));
189 local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
Ken Werner545023c2011-07-14 13:44:02 +0000190 local_addr_space.acc.find_proc_info = arm_find_proc_info;
191 local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
Daniel Jacobowitz3842dac2008-02-04 17:16:37 -0700192 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
193 local_addr_space.acc.access_mem = access_mem;
194 local_addr_space.acc.access_reg = access_reg;
195 local_addr_space.acc.access_fpreg = access_fpreg;
Ken Werner1e10c292011-04-21 15:52:51 +0200196 local_addr_space.acc.resume = arm_local_resume;
Daniel Jacobowitz3842dac2008-02-04 17:16:37 -0700197 local_addr_space.acc.get_proc_name = get_static_proc_name;
198 unw_flush_cache (&local_addr_space, 0, 0);
199}
200
201#endif /* !UNW_REMOTE_ONLY */