hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 1 | /* libunwind - a platform-independent unwind library |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 2 | Copyright (C) 2002-2003 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 */ |
| 78 | UNW_INFO_FORMAT_REMOTE_TABLE, /* unw_dyn_remote_table_t */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 79 | } |
| 80 | unw_dyn_info_format_t; |
| 81 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 82 | typedef struct unw_dyn_op |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 83 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 84 | int8_t tag; /* what operation? */ |
| 85 | int8_t qp; /* qualifying predicate register */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 86 | int16_t reg; /* what register */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 87 | int32_t when; /* when does it take effect? */ |
| 88 | unw_word_t val; /* auxiliary value */ |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 89 | } |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 90 | unw_dyn_op_t; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 91 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 92 | typedef struct unw_dyn_region_info |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 93 | { |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 94 | struct unw_dyn_region_info *next; /* linked list of regions */ |
mostang.com!davidm | e614405 | 2003-02-22 08:19:43 +0000 | [diff] [blame] | 95 | int32_t insn_count; /* region length (# of instructions) */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 96 | uint32_t op_count; /* length of op-array */ |
| 97 | unw_dyn_op_t op[1]; /* variable-length op-array */ |
| 98 | } |
| 99 | unw_dyn_region_info_t; |
| 100 | |
| 101 | typedef struct unw_dyn_proc_info |
| 102 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 103 | unw_word_t name_ptr; /* address of human-readable procedure name */ |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 104 | unw_word_t handler; /* address of personality routine */ |
| 105 | uint32_t flags; |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 106 | int32_t pad0; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 107 | unw_dyn_region_info_t *regions; |
| 108 | } |
| 109 | unw_dyn_proc_info_t; |
| 110 | |
| 111 | typedef struct unw_dyn_table_info |
| 112 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 113 | 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] | 114 | unw_word_t segbase; /* segment base */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 115 | unw_word_t table_len; /* must be a multiple of sizeof(unw_word_t)! */ |
| 116 | unw_word_t *table_data; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 117 | } |
| 118 | unw_dyn_table_info_t; |
| 119 | |
hp.com!davidm | dd8806c | 2003-11-25 22:33:49 +0000 | [diff] [blame^] | 120 | typedef struct unw_dyn_remote_table_info |
| 121 | { |
| 122 | unw_word_t name_ptr; /* addr. of table name (e.g., library name) */ |
| 123 | unw_word_t segbase; /* segment base */ |
| 124 | unw_word_t table_len; /* must be a multiple of sizeof(unw_word_t)! */ |
| 125 | unw_word_t table_data; |
| 126 | } |
| 127 | unw_dyn_remote_table_info_t; |
| 128 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 129 | typedef struct unw_dyn_info |
| 130 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 131 | /* doubly-linked list of dyn-info structures: */ |
| 132 | struct unw_dyn_info *next; |
| 133 | struct unw_dyn_info *prev; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 134 | unw_word_t start_ip; /* first IP covered by this entry */ |
| 135 | unw_word_t end_ip; /* first IP NOT covered by this entry */ |
| 136 | unw_word_t gp; /* global-pointer in effect for this entry */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 137 | int32_t format; /* real type: unw_dyn_info_format_t */ |
| 138 | int32_t pad; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 139 | union |
| 140 | { |
| 141 | unw_dyn_proc_info_t pi; |
| 142 | unw_dyn_table_info_t ti; |
hp.com!davidm | dd8806c | 2003-11-25 22:33:49 +0000 | [diff] [blame^] | 143 | unw_dyn_remote_table_info_t rti; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 144 | } |
| 145 | u; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 146 | } |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 147 | unw_dyn_info_t; |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 148 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 149 | typedef struct unw_dyn_info_list |
| 150 | { |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 151 | uint32_t version; |
| 152 | uint32_t generation; |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 153 | unw_dyn_info_t *first; |
| 154 | } |
| 155 | unw_dyn_info_list_t; |
| 156 | |
| 157 | /* 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] | 158 | hold OP_COUNT ops. */ |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 159 | #define _U_dyn_region_info_size(op_count) \ |
| 160 | ((char *) (((unw_dyn_region_info_t *) NULL)->op + (op_count)) \ |
| 161 | - (char *) NULL) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 162 | |
| 163 | /* Register the unwind info for a single procedure. |
| 164 | This routine is NOT signal-safe. */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 165 | extern void _U_dyn_register (unw_dyn_info_t *di); |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 166 | |
| 167 | /* Cancel the unwind info for a single procedure. |
| 168 | This routine is NOT signal-safe. */ |
mostang.com!davidm | 744b910 | 2002-12-12 09:17:41 +0000 | [diff] [blame] | 169 | extern void _U_dyn_cancel (unw_dyn_info_t *di); |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 170 | |
| 171 | |
| 172 | /* Convenience routines. */ |
| 173 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 174 | #define _U_dyn_op(_t, _q, _w, _r, _v) \ |
| 175 | ((unw_dyn_op_t) { \ |
| 176 | .tag = (_t), \ |
| 177 | .qp = (_q), \ |
| 178 | .when = (_w), \ |
| 179 | .reg = (_r), \ |
| 180 | .val = (_v) \ |
| 181 | }) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 182 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 183 | #define _U_dyn_op_save_reg(op, qp, when, reg, dst) \ |
| 184 | (*(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] | 185 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 186 | #define _U_dyn_op_spill_fp_rel(op, qp, when, reg, offset) \ |
| 187 | (*(op) = _U_dyn_op (UNW_DYN_SPILL_FP_REL, (qp), (when), (reg), \ |
| 188 | (offset))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 189 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 190 | #define _U_dyn_op_spill_sp_rel(op, qp, when, reg, offset) \ |
| 191 | (*(op) = _U_dyn_op (UNW_DYN_SPILL_SP_REL, (qp), (when), (reg), \ |
| 192 | (offset))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 193 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 194 | #define _U_dyn_op_add(op, qp, when, reg, value) \ |
| 195 | (*(op) = _U_dyn_op (UNW_DYN_ADD, (qp), (when), (reg), (value))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 196 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 197 | #define _U_dyn_op_pop_frames(op, qp, when, num_frames) \ |
hp.com!davidm | cf3b756 | 2003-02-26 08:33:57 +0000 | [diff] [blame] | 198 | (*(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] | 199 | |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 200 | #define _U_dyn_op_label_state(op, label) \ |
| 201 | (*(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] | 202 | |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 203 | #define _U_dyn_op_copy_state(op, label) \ |
| 204 | (*(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] | 205 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 206 | #define _U_dyn_op_alias(op, qp, when, addr) \ |
| 207 | (*(op) = _U_dyn_op (UNW_DYN_ALIAS, (qp), (when), 0, (addr))) |
hp.com!davidm | d7e9f75 | 2002-11-23 02:12:30 +0000 | [diff] [blame] | 208 | |
mostang.com!davidm | dfc08ea | 2002-12-03 08:19:58 +0000 | [diff] [blame] | 209 | #define _U_dyn_op_stop(op) \ |
mostang.com!davidm | 9430d35 | 2003-02-27 09:58:57 +0000 | [diff] [blame] | 210 | (*(op) = _U_dyn_op (UNW_DYN_STOP, _U_QP_TRUE, -1, 0, 0)) |
| 211 | |
| 212 | /* The target-dependent qualifying predicate which is always TRUE. On |
| 213 | IA-64, that's p0 (0), on non-predicated architectures, the value is |
| 214 | ignored. */ |
| 215 | #define _U_QP_TRUE _U_TDEP_QP_TRUE |