Initial import
[external/libunwind.git] / include / tdep-ppc64 / libunwind_i.h
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2006-2007 IBM
3    Contributed by
4      Corey Ashford <cjashfor@us.ibm.com>
5      Jose Flavio Aguilar Paulino <jflavio@br.ibm.com> <joseflavio@gmail.com>
6
7    Copied from libunwind-x86_64.h, modified slightly for building
8    frysk successfully on ppc64, by Wu Zhou <woodzltc@cn.ibm.com>
9    Will be replaced when libunwind is ready on ppc64 platform.
10
11 This file is part of libunwind.
12
13 Permission is hereby granted, free of charge, to any person obtaining
14 a copy of this software and associated documentation files (the
15 "Software"), to deal in the Software without restriction, including
16 without limitation the rights to use, copy, modify, merge, publish,
17 distribute, sublicense, and/or sell copies of the Software, and to
18 permit persons to whom the Software is furnished to do so, subject to
19 the following conditions:
20
21 The above copyright notice and this permission notice shall be
22 included in all copies or substantial portions of the Software.
23
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
31
32 #ifndef PPC64_LIBUNWIND_I_H
33 #define PPC64_LIBUNWIND_I_H
34
35 /* Target-dependent definitions that are internal to libunwind but need
36    to be shared with target-independent code.  */
37
38 #include <stdlib.h>
39 #include <libunwind.h>
40
41 #include "elf64.h"
42 #include "mempool.h"
43 #include "dwarf.h"
44
45 typedef struct
46   {
47     /* no ppc64-specific fast trace */
48   }
49 unw_tdep_frame_t;
50
51 struct unw_addr_space
52 {
53   struct unw_accessors acc;
54   unw_caching_policy_t caching_policy;
55 #ifdef HAVE_ATOMIC_OPS_H
56   AO_t cache_generation;
57 #else
58   uint32_t cache_generation;
59 #endif
60   unw_word_t dyn_generation;    /* see dyn-common.h */
61   unw_word_t dyn_info_list_addr;        /* (cached) dyn_info_list_addr */
62   struct dwarf_rs_cache global_cache;
63   struct unw_debug_frame_list *debug_frames;
64   int validate;
65 };
66
67 struct cursor
68 {
69   struct dwarf_cursor dwarf;    /* must be first */
70
71   /* Format of sigcontext structure and address at which it is
72      stored: */
73   enum
74   {
75     PPC_SCF_NONE,               /* no signal frame encountered */
76     PPC_SCF_LINUX_RT_SIGFRAME   /* POSIX ucontext_t */
77   }
78   sigcontext_format;
79   unw_word_t sigcontext_addr;
80 };
81
82 #define DWARF_GET_LOC(l)        ((l).val)
83
84 #ifdef UNW_LOCAL_ONLY
85 # define DWARF_NULL_LOC         DWARF_LOC (0, 0)
86 # define DWARF_IS_NULL_LOC(l)   (DWARF_GET_LOC (l) == 0)
87 # define DWARF_LOC(r, t)        ((dwarf_loc_t) { .val = (r) })
88 # define DWARF_IS_REG_LOC(l)    0
89 # define DWARF_IS_FP_LOC(l)     0
90 # define DWARF_IS_V_LOC(l)      0
91 # define DWARF_MEM_LOC(c,m)     DWARF_LOC ((m), 0)
92 # define DWARF_REG_LOC(c,r)     (DWARF_LOC((unw_word_t)                      \
93                                  tdep_uc_addr((c)->as_arg, (r)), 0))
94 # define DWARF_FPREG_LOC(c,r)   (DWARF_LOC((unw_word_t)                      \
95                                  tdep_uc_addr((c)->as_arg, (r)), 0))
96 # define DWARF_VREG_LOC(c,r)    (DWARF_LOC((unw_word_t)                      \
97                                  tdep_uc_addr((c)->as_arg, (r)), 0))
98 #else /* !UNW_LOCAL_ONLY */
99
100 # define DWARF_LOC_TYPE_FP      (1 << 0)
101 # define DWARF_LOC_TYPE_REG     (1 << 1)
102 # define DWARF_LOC_TYPE_V       (1 << 2)
103 # define DWARF_NULL_LOC         DWARF_LOC (0, 0)
104 # define DWARF_IS_NULL_LOC(l)                                           \
105                 ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; })
106 # define DWARF_LOC(r, t)        ((dwarf_loc_t) { .val = (r), .type = (t) })
107 # define DWARF_IS_REG_LOC(l)    (((l).type & DWARF_LOC_TYPE_REG) != 0)
108 # define DWARF_IS_FP_LOC(l)     (((l).type & DWARF_LOC_TYPE_FP) != 0)
109 # define DWARF_IS_V_LOC(l)      (((l).type & DWARF_LOC_TYPE_V) != 0)
110 # define DWARF_MEM_LOC(c,m)     DWARF_LOC ((m), 0)
111 # define DWARF_REG_LOC(c,r)     DWARF_LOC((r), DWARF_LOC_TYPE_REG)
112 # define DWARF_FPREG_LOC(c,r)   DWARF_LOC((r), (DWARF_LOC_TYPE_REG      \
113                                                 | DWARF_LOC_TYPE_FP))
114 # define DWARF_VREG_LOC(c,r)    DWARF_LOC((r), (DWARF_LOC_TYPE_REG      \
115                                                 | DWARF_LOC_TYPE_V))
116
117 #endif /* !UNW_LOCAL_ONLY */
118
119 static inline int
120 dwarf_getvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val)
121 {
122   unw_word_t *valp = (unw_word_t *) val;
123   unw_word_t addr;
124   int ret;
125
126   if (DWARF_IS_NULL_LOC (loc))
127     return -UNW_EBADREG;
128
129   assert (DWARF_IS_V_LOC (loc));
130   assert (!DWARF_IS_FP_LOC (loc));
131
132   if (DWARF_IS_REG_LOC (loc))
133     return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
134                                       val, 0, c->as_arg);
135
136   addr = DWARF_GET_LOC (loc);
137
138   if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, valp,
139                                        0, c->as_arg)) < 0)
140     return ret;
141
142   return (*c->as->acc.access_mem) (c->as, addr + 8, valp + 1, 0, c->as_arg);
143 }
144
145 static inline int
146 dwarf_putvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
147 {
148   unw_word_t *valp = (unw_word_t *) & val;
149   unw_word_t addr;
150   int ret;
151
152   if (DWARF_IS_NULL_LOC (loc))
153     return -UNW_EBADREG;
154
155   assert (DWARF_IS_V_LOC (loc));
156   assert (!DWARF_IS_FP_LOC (loc));
157
158   if (DWARF_IS_REG_LOC (loc))
159     return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
160                                       &val, 1, c->as_arg);
161
162   addr = DWARF_GET_LOC (loc);
163   if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, valp,
164                                        1, c->as_arg)) < 0)
165     return ret;
166
167   return (*c->as->acc.access_mem) (c->as, addr + 8, valp + 1, 1, c->as_arg);
168 }
169
170 static inline int
171 dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val)
172 {
173   unw_word_t *valp = (unw_word_t *) val;
174   unw_word_t addr;
175
176   if (DWARF_IS_NULL_LOC (loc))
177     return -UNW_EBADREG;
178
179   assert (DWARF_IS_FP_LOC (loc));
180   assert (!DWARF_IS_V_LOC (loc));
181
182   if (DWARF_IS_REG_LOC (loc))
183     return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
184                                        val, 0, c->as_arg);
185
186   addr = DWARF_GET_LOC (loc);
187   return (*c->as->acc.access_mem) (c->as, addr + 0, valp, 0, c->as_arg);
188
189 }
190
191 static inline int
192 dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
193 {
194   unw_word_t *valp = (unw_word_t *) & val;
195   unw_word_t addr;
196
197   if (DWARF_IS_NULL_LOC (loc))
198     return -UNW_EBADREG;
199
200   assert (DWARF_IS_FP_LOC (loc));
201   assert (!DWARF_IS_V_LOC (loc));
202
203   if (DWARF_IS_REG_LOC (loc))
204     return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
205                                        &val, 1, c->as_arg);
206
207   addr = DWARF_GET_LOC (loc);
208
209   return (*c->as->acc.access_mem) (c->as, addr + 0, valp, 1, c->as_arg);
210 }
211
212 static inline int
213 dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t * val)
214 {
215   if (DWARF_IS_NULL_LOC (loc))
216     return -UNW_EBADREG;
217
218   /* If a code-generator were to save a value of type unw_word_t in a
219      floating-point register, we would have to support this case.  I
220      suppose it could happen with MMX registers, but does it really
221      happen?  */
222   assert (!DWARF_IS_FP_LOC (loc));
223   assert (!DWARF_IS_V_LOC (loc));
224
225   if (DWARF_IS_REG_LOC (loc))
226     return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val,
227                                      0, c->as_arg);
228   else
229     return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
230                                      0, c->as_arg);
231 }
232
233 static inline int
234 dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
235 {
236   if (DWARF_IS_NULL_LOC (loc))
237     return -UNW_EBADREG;
238
239   /* If a code-generator were to save a value of type unw_word_t in a
240      floating-point register, we would have to support this case.  I
241      suppose it could happen with MMX registers, but does it really
242      happen?  */
243   assert (!DWARF_IS_FP_LOC (loc));
244   assert (!DWARF_IS_V_LOC (loc));
245
246   if (DWARF_IS_REG_LOC (loc))
247     return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val,
248                                      1, c->as_arg);
249   else
250     return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
251                                      1, c->as_arg);
252 }
253
254 #define tdep_getcontext_trace           unw_getcontext
255 #define tdep_init_done                  UNW_OBJ(init_done)
256 #define tdep_init                       UNW_OBJ(init)
257 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
258    tdep_search_unwind_table.  */
259 #define tdep_search_unwind_table        dwarf_search_unwind_table
260 #define tdep_find_unwind_table          dwarf_find_unwind_table
261 #define tdep_uc_addr                    UNW_ARCH_OBJ(uc_addr)
262 #define tdep_get_elf_image              UNW_ARCH_OBJ(get_elf_image)
263 #define tdep_access_reg                 UNW_OBJ(access_reg)
264 #define tdep_access_fpreg               UNW_OBJ(access_fpreg)
265 #define tdep_fetch_frame(c,ip,n)        do {} while(0)
266 #define tdep_cache_frame(c,rs)          do {} while(0)
267 #define tdep_reuse_frame(c,rs)          do {} while(0)
268 #define tdep_stash_frame(c,rs)          do {} while(0)
269 #define tdep_trace(cur,addr,n)          (-UNW_ENOINFO)
270 #define tdep_get_func_addr              UNW_OBJ(get_func_addr)
271
272 #ifdef UNW_LOCAL_ONLY
273 # define tdep_find_proc_info(c,ip,n)                            \
274         dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n),      \
275                                        (c)->as_arg)
276 # define tdep_put_unwind_info(as,pi,arg)                \
277         dwarf_put_unwind_info((as), (pi), (arg))
278 #else
279 # define tdep_find_proc_info(c,ip,n)                                    \
280         (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n),    \
281                                        (c)->as_arg)
282 # define tdep_put_unwind_info(as,pi,arg)                        \
283         (*(as)->acc.put_unwind_info)((as), (pi), (arg))
284 #endif
285
286 extern int tdep_fetch_proc_info_post (struct dwarf_cursor *c, unw_word_t ip,
287                                       int need_unwind_info);
288
289 #define tdep_get_as(c)                  ((c)->dwarf.as)
290 #define tdep_get_as_arg(c)              ((c)->dwarf.as_arg)
291 #define tdep_get_ip(c)                  ((c)->dwarf.ip)
292 #define tdep_big_endian(as)             1
293
294 extern int tdep_init_done;
295
296 extern void tdep_init (void);
297 extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
298                                      unw_dyn_info_t * di,
299                                      unw_proc_info_t * pi,
300                                      int need_unwind_info, void *arg);
301 extern void *tdep_uc_addr (ucontext_t * uc, int reg);
302 extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
303                                unsigned long *segbase, unsigned long *mapoff,
304                                char *path, size_t pathlen);
305 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
306                             unw_word_t * valp, int write);
307 extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
308                               unw_fpreg_t * valp, int write);
309 extern int tdep_get_func_addr (unw_addr_space_t as, unw_word_t addr,
310                                unw_word_t *entry_point);
311
312 #endif /* PPC64_LIBUNWIND_I_H */