hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 1 | /* libunwind - a platform-independent unwind library |
mostang.com!davidm | 64854d0 | 2004-01-21 01:05:07 +0000 | [diff] [blame] | 2 | Copyright (C) 2002-2004 Hewlett-Packard Co |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 3 | Contributed by David Mosberger-Tang <davidm@hpl.hp.com> |
| 4 | |
| 5 | This file is part of libunwind. |
| 6 | |
| 7 | Permission is hereby granted, free of charge, to any person obtaining |
| 8 | a copy of this software and associated documentation files (the |
| 9 | "Software"), to deal in the Software without restriction, including |
| 10 | without limitation the rights to use, copy, modify, merge, publish, |
| 11 | distribute, sublicense, and/or sell copies of the Software, and to |
| 12 | permit persons to whom the Software is furnished to do so, subject to |
| 13 | the following conditions: |
| 14 | |
| 15 | The above copyright notice and this permission notice shall be |
| 16 | included in all copies or substantial portions of the Software. |
| 17 | |
| 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 25 | |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 26 | /* This file defines the runtime-support routines for dynamically |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 27 | generated code. Even though it is implemented as part of libunwind, |
| 28 | it is logically separate from the interface to perform the actual |
| 29 | unwinding. In particular, this interface is always used in the |
| 30 | context of the unwind target, whereas the rest of the unwind API is |
| 31 | used in context of the process that is doing the unwind (which may be |
| 32 | a debugger running on another machine, for example). |
| 33 | |
| 34 | Note that the data-structures declared here server a dual purpose: |
| 35 | when a program registers a dynamically generated procedure, it uses |
| 36 | these structures directly. On the other hand, with remote-unwinding, |
| 37 | the data-structures are read from the remote process's memory and |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 38 | translated into internalized versions. To facilitate remote-access, |
| 39 | the following rules should be followed in declaring these structures: |
| 40 | |
| 41 | (1) Declare a member as a pointer only if the the information the |
| 42 | member points to needs to be internalized as well (e.g., a |
| 43 | string representing a procedure name should be declared as |
| 44 | "const char *", but the instruction pointer should be declared |
| 45 | as unw_word_t). |
| 46 | |
| 47 | (2) Provide sufficient padding to ensure that no implicit padding |
| 48 | will be needed on any of the supported target architectures. For |
| 49 | the time being, padding data structures with the assumption that |
| 50 | sizeof (unw_word_t) == 8 should be sufficient. (Note: it's not |
| 51 | impossible to internalize structures with internal padding, but |
| 52 | it does make the process a bit harder). |
| 53 | |
| 54 | (3) Don't declare members that contain bitfields or floating-point |
| 55 | values. |
| 56 | |
| 57 | (4) Don't declare members with enumeration types. Declare them as |
| 58 | int32_t instead. */ |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 59 | |
| 60 | typedef enum |
| 61 | { |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 62 | UNW_DYN_STOP = 0, /* end-of-unwind-info marker */ |
| 63 | UNW_DYN_SAVE_REG, /* save register to another register */ |
| 64 | UNW_DYN_SPILL_FP_REL, /* frame-pointer-relative register spill */ |
| 65 | UNW_DYN_SPILL_SP_REL, /* stack-pointer-relative register spill */ |
| 66 | UNW_DYN_ADD, /* add constant value to a register */ |
| 67 | UNW_DYN_POP_FRAMES, /* drop one or more stack frames */ |
| 68 | UNW_DYN_LABEL_STATE, /* name the current state */ |
| 69 | UNW_DYN_COPY_STATE, /* set the region's entry-state */ |
| 70 | UNW_DYN_ALIAS /* get unwind info from an alias */ |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 71 | } |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 72 | unw_dyn_operation_t; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 73 | |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 74 | typedef enum |
| 75 | { |
hp.com!davidm | dd8806c | 2003-11-25 22:33:49 +0000 | [diff] [blame] | 76 | UNW_INFO_FORMAT_DYNAMIC, /* unw_dyn_proc_info_t */ |
| 77 | UNW_INFO_FORMAT_TABLE, /* unw_dyn_table_t */ |
Ken Werner | 545023c | 2011-07-14 13:44:02 +0000 | [diff] [blame] | 78 | UNW_INFO_FORMAT_REMOTE_TABLE, /* unw_dyn_remote_table_t */ |
| 79 | UNW_INFO_FORMAT_ARM_EXIDX /* ARM specific unwind info */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 80 | } |
| 81 | unw_dyn_info_format_t; |
| 82 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 83 | typedef struct unw_dyn_op |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 84 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 85 | int8_t tag; /* what operation? */ |
| 86 | int8_t qp; /* qualifying predicate register */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 87 | int16_t reg; /* what register */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 88 | int32_t when; /* when does it take effect? */ |
| 89 | unw_word_t val; /* auxiliary value */ |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 90 | } |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 91 | unw_dyn_op_t; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 92 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 93 | typedef struct unw_dyn_region_info |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 94 | { |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 95 | struct unw_dyn_region_info *next; /* linked list of regions */ |
mostang.com!davidm | e614405 | 2003-02-22 08:19:43 +0000 | [diff] [blame] | 96 | int32_t insn_count; /* region length (# of instructions) */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 97 | uint32_t op_count; /* length of op-array */ |
| 98 | unw_dyn_op_t op[1]; /* variable-length op-array */ |
| 99 | } |
| 100 | unw_dyn_region_info_t; |
| 101 | |
| 102 | typedef struct unw_dyn_proc_info |
| 103 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 104 | unw_word_t name_ptr; /* address of human-readable procedure name */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 105 | unw_word_t handler; /* address of personality routine */ |
| 106 | uint32_t flags; |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 107 | int32_t pad0; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 108 | unw_dyn_region_info_t *regions; |
| 109 | } |
| 110 | unw_dyn_proc_info_t; |
| 111 | |
| 112 | typedef struct unw_dyn_table_info |
| 113 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 114 | unw_word_t name_ptr; /* addr. of table name (e.g., library name) */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 115 | unw_word_t segbase; /* segment base */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 116 | unw_word_t table_len; /* must be a multiple of sizeof(unw_word_t)! */ |
| 117 | unw_word_t *table_data; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 118 | } |
| 119 | unw_dyn_table_info_t; |
| 120 | |
hp.com!davidm | dd8806c | 2003-11-25 22:33:49 +0000 | [diff] [blame] | 121 | typedef struct unw_dyn_remote_table_info |
| 122 | { |
| 123 | unw_word_t name_ptr; /* addr. of table name (e.g., library name) */ |
| 124 | unw_word_t segbase; /* segment base */ |
| 125 | unw_word_t table_len; /* must be a multiple of sizeof(unw_word_t)! */ |
| 126 | unw_word_t table_data; |
| 127 | } |
| 128 | unw_dyn_remote_table_info_t; |
| 129 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 130 | typedef struct unw_dyn_info |
| 131 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 132 | /* doubly-linked list of dyn-info structures: */ |
| 133 | struct unw_dyn_info *next; |
| 134 | struct unw_dyn_info *prev; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 135 | unw_word_t start_ip; /* first IP covered by this entry */ |
| 136 | unw_word_t end_ip; /* first IP NOT covered by this entry */ |
| 137 | unw_word_t gp; /* global-pointer in effect for this entry */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 138 | int32_t format; /* real type: unw_dyn_info_format_t */ |
| 139 | int32_t pad; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 140 | union |
| 141 | { |
| 142 | unw_dyn_proc_info_t pi; |
| 143 | unw_dyn_table_info_t ti; |
hp.com!davidm | dd8806c | 2003-11-25 22:33:49 +0000 | [diff] [blame] | 144 | unw_dyn_remote_table_info_t rti; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 145 | } |
| 146 | u; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 147 | } |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 148 | unw_dyn_info_t; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 149 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 150 | typedef struct unw_dyn_info_list |
| 151 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 152 | uint32_t version; |
| 153 | uint32_t generation; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 154 | unw_dyn_info_t *first; |
| 155 | } |
| 156 | unw_dyn_info_list_t; |
| 157 | |
| 158 | /* Return the size (in bytes) of an unw_dyn_region_info_t structure that can |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 159 | hold OP_COUNT ops. */ |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 160 | #define _U_dyn_region_info_size(op_count) \ |
| 161 | ((char *) (((unw_dyn_region_info_t *) NULL)->op + (op_count)) \ |
| 162 | - (char *) NULL) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 163 | |
| 164 | /* Register the unwind info for a single procedure. |
| 165 | This routine is NOT signal-safe. */ |
mostang.com!davidm | 64854d0 | 2004-01-21 01:05:07 +0000 | [diff] [blame] | 166 | extern void _U_dyn_register (unw_dyn_info_t *); |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 167 | |
| 168 | /* Cancel the unwind info for a single procedure. |
| 169 | This routine is NOT signal-safe. */ |
mostang.com!davidm | 64854d0 | 2004-01-21 01:05:07 +0000 | [diff] [blame] | 170 | extern void _U_dyn_cancel (unw_dyn_info_t *); |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 171 | |
| 172 | |
| 173 | /* Convenience routines. */ |
| 174 | |
mostang.com!davidm | c5c4fc9 | 2004-04-28 01:24:34 +0000 | [diff] [blame] | 175 | #define _U_dyn_op(_tag, _qp, _when, _reg, _val) \ |
| 176 | ((unw_dyn_op_t) { (_tag), (_qp), (_reg), (_when), (_val) }) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 177 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 178 | #define _U_dyn_op_save_reg(op, qp, when, reg, dst) \ |
| 179 | (*(op) = _U_dyn_op (UNW_DYN_SAVE_REG, (qp), (when), (reg), (dst))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 180 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 181 | #define _U_dyn_op_spill_fp_rel(op, qp, when, reg, offset) \ |
| 182 | (*(op) = _U_dyn_op (UNW_DYN_SPILL_FP_REL, (qp), (when), (reg), \ |
| 183 | (offset))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 184 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 185 | #define _U_dyn_op_spill_sp_rel(op, qp, when, reg, offset) \ |
| 186 | (*(op) = _U_dyn_op (UNW_DYN_SPILL_SP_REL, (qp), (when), (reg), \ |
| 187 | (offset))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 188 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 189 | #define _U_dyn_op_add(op, qp, when, reg, value) \ |
| 190 | (*(op) = _U_dyn_op (UNW_DYN_ADD, (qp), (when), (reg), (value))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 191 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 192 | #define _U_dyn_op_pop_frames(op, qp, when, num_frames) \ |
hp.com!davidm | cf3b756 | 2003-02-26 08:33:57 +0000 | [diff] [blame] | 193 | (*(op) = _U_dyn_op (UNW_DYN_POP_FRAMES, (qp), (when), 0, (num_frames))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 194 | |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 195 | #define _U_dyn_op_label_state(op, label) \ |
| 196 | (*(op) = _U_dyn_op (UNW_DYN_LABEL_STATE, _U_QP_TRUE, -1, 0, (label))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 197 | |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 198 | #define _U_dyn_op_copy_state(op, label) \ |
| 199 | (*(op) = _U_dyn_op (UNW_DYN_COPY_STATE, _U_QP_TRUE, -1, 0, (label))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 200 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 201 | #define _U_dyn_op_alias(op, qp, when, addr) \ |
| 202 | (*(op) = _U_dyn_op (UNW_DYN_ALIAS, (qp), (when), 0, (addr))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 203 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 204 | #define _U_dyn_op_stop(op) \ |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 205 | (*(op) = _U_dyn_op (UNW_DYN_STOP, _U_QP_TRUE, -1, 0, 0)) |
| 206 | |
| 207 | /* The target-dependent qualifying predicate which is always TRUE. On |
| 208 | IA-64, that's p0 (0), on non-predicated architectures, the value is |
| 209 | ignored. */ |
| 210 | #define _U_QP_TRUE _U_TDEP_QP_TRUE |