1/* libunwind - a platform-independent unwind library 2 Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 5This file is part of libunwind. 6 7Permission is hereby granted, free of charge, to any person obtaining 8a copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sublicense, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice shall be 16included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25 26#include "dwarf_i.h" 27 28static inline int 29is_cie_id (unw_word_t val, int is_debug_frame) 30{ 31 /* The CIE ID is normally 0xffffffff (for 32-bit ELF) or 32 0xffffffffffffffff (for 64-bit ELF). However, .eh_frame 33 uses 0. */ 34 if (is_debug_frame) 35 return (val == - (unw_word_t) 1); 36 else 37 return (val == 0); 38} 39 40/* Note: we don't need to keep track of more than the first four 41 characters of the augmentation string, because we (a) ignore any 42 augmentation string contents once we find an unrecognized character 43 and (b) those characters that we do recognize, can't be 44 repeated. */ 45static inline int 46parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, 47 const unw_proc_info_t *pi, struct dwarf_cie_info *dci, 48 int is_debug_frame, void *arg) 49{ 50 uint8_t version, ch, augstr[5], fde_encoding, handler_encoding; 51 unw_word_t len, cie_end_addr, aug_size; 52 uint32_t u32val; 53 uint64_t u64val; 54 size_t i; 55 int ret; 56# define STR2(x) #x 57# define STR(x) STR2(x) 58 59 /* Pick appropriate default for FDE-encoding. DWARF spec says 60 start-IP (initial_location) and the code-size (address_range) are 61 "address-unit sized constants". The `R' augmentation can be used 62 to override this, but by default, we pick an address-sized unit 63 for fde_encoding. */ 64 switch (dwarf_addr_size (as)) 65 { 66 case 4: fde_encoding = DW_EH_PE_udata4; break; 67 case 8: fde_encoding = DW_EH_PE_udata8; break; 68 default: fde_encoding = DW_EH_PE_omit; break; 69 } 70 71 dci->lsda_encoding = DW_EH_PE_omit; 72 dci->handler = 0; 73 74 if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0) 75 return ret; 76 77 if (u32val != 0xffffffff) 78 { 79 /* the CIE is in the 32-bit DWARF format */ 80 uint32_t cie_id; 81 /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */ 82 const uint32_t expected_id = (is_debug_frame) ? 0xffffffff : 0; 83 84 len = u32val; 85 cie_end_addr = addr + len; 86 if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0) 87 return ret; 88 if (cie_id != expected_id) 89 { 90 Debug (1, "Unexpected CIE id %x\n", cie_id); 91 return -UNW_EINVAL; 92 } 93 } 94 else 95 { 96 /* the CIE is in the 64-bit DWARF format */ 97 uint64_t cie_id; 98 /* DWARF says CIE id should be 0xffffffffffffffff, but in 99 .eh_frame, it's 0 */ 100 const uint64_t expected_id = (is_debug_frame) ? 0xffffffffffffffffull : 0; 101 102 if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0) 103 return ret; 104 len = u64val; 105 cie_end_addr = addr + len; 106 if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0) 107 return ret; 108 if (cie_id != expected_id) 109 { 110 Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id); 111 return -UNW_EINVAL; 112 } 113 } 114 dci->cie_instr_end = cie_end_addr; 115 116 if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0) 117 return ret; 118 119 if (version != 1 && version != DWARF_CIE_VERSION) 120 { 121 Debug (1, "Got CIE version %u, expected version 1 or " 122 STR (DWARF_CIE_VERSION) "\n", version); 123 return -UNW_EBADVERSION; 124 } 125 126 /* read and parse the augmentation string: */ 127 memset (augstr, 0, sizeof (augstr)); 128 for (i = 0;;) 129 { 130 if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) 131 return ret; 132 133 if (!ch) 134 break; /* end of augmentation string */ 135 136 if (i < sizeof (augstr) - 1) 137 augstr[i++] = ch; 138 } 139 140 if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0 141 || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0) 142 return ret; 143 144 /* Read the return-address column either as a u8 or as a uleb128. */ 145 if (version == 1) 146 { 147 if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) 148 return ret; 149 dci->ret_addr_column = ch; 150 } 151 else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column, 152 arg)) < 0) 153 return ret; 154 155 i = 0; 156 if (augstr[0] == 'z') 157 { 158 dci->sized_augmentation = 1; 159 if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0) 160 return ret; 161 i++; 162 } 163 164 for (; i < sizeof (augstr) && augstr[i]; ++i) 165 switch (augstr[i]) 166 { 167 case 'L': 168 /* read the LSDA pointer-encoding format. */ 169 if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) 170 return ret; 171 dci->lsda_encoding = ch; 172 break; 173 174 case 'R': 175 /* read the FDE pointer-encoding format. */ 176 if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0) 177 return ret; 178 break; 179 180 case 'P': 181 /* read the personality-routine pointer-encoding format. */ 182 if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0) 183 return ret; 184 if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding, 185 pi, &dci->handler, arg)) < 0) 186 return ret; 187 break; 188 189 case 'S': 190 /* This is a signal frame. */ 191 dci->signal_frame = 1; 192 193 /* Temporarily set it to one so dwarf_parse_fde() knows that 194 it should fetch the actual ABI/TAG pair from the FDE. */ 195 dci->have_abi_marker = 1; 196 break; 197 198 default: 199 Debug (1, "Unexpected augmentation string `%s'\n", augstr); 200 if (dci->sized_augmentation) 201 /* If we have the size of the augmentation body, we can skip 202 over the parts that we don't understand, so we're OK. */ 203 goto done; 204 else 205 return -UNW_EINVAL; 206 } 207 done: 208 dci->fde_encoding = fde_encoding; 209 dci->cie_instr_start = addr; 210 Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n", 211 augstr, (long) dci->handler); 212 return 0; 213} 214 215/* Extract proc-info from the FDE starting at adress ADDR. 216 217 Pass BASE as zero for eh_frame behaviour, or a pointer to 218 debug_frame base for debug_frame behaviour. */ 219 220HIDDEN int 221dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, 222 unw_word_t *addrp, unw_proc_info_t *pi, 223 unw_word_t base, 224 int need_unwind_info, int is_debug_frame, 225 void *arg) 226{ 227 unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0; 228 unw_word_t start_ip, ip_range, aug_size, addr = *addrp; 229 int ret, ip_range_encoding; 230 struct dwarf_cie_info dci; 231 uint64_t u64val; 232 uint32_t u32val; 233 234 Debug (12, "FDE @ 0x%lx\n", (long) addr); 235 236 memset (&dci, 0, sizeof (dci)); 237 238 if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0) 239 return ret; 240 241 if (u32val != 0xffffffff) 242 { 243 int32_t cie_offset; 244 245 /* In some configurations, an FDE with a 0 length indicates the 246 end of the FDE-table. */ 247 if (u32val == 0) 248 return -UNW_ENOINFO; 249 250 /* the FDE is in the 32-bit DWARF format */ 251 252 *addrp = fde_end_addr = addr + u32val; 253 cie_offset_addr = addr; 254 255 if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0) 256 return ret; 257 258 if (is_cie_id (cie_offset, is_debug_frame)) 259 /* ignore CIEs (happens during linear searches) */ 260 return 0; 261 262 if (is_debug_frame) 263 cie_addr = base + cie_offset; 264 else 265 /* DWARF says that the CIE_pointer in the FDE is a 266 .debug_frame-relative offset, but the GCC-generated .eh_frame 267 sections instead store a "pcrelative" offset, which is just 268 as fine as it's self-contained. */ 269 cie_addr = cie_offset_addr - cie_offset; 270 } 271 else 272 { 273 int64_t cie_offset; 274 275 /* the FDE is in the 64-bit DWARF format */ 276 277 if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0) 278 return ret; 279 280 *addrp = fde_end_addr = addr + u64val; 281 cie_offset_addr = addr; 282 283 if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0) 284 return ret; 285 286 if (is_cie_id (cie_offset, is_debug_frame)) 287 /* ignore CIEs (happens during linear searches) */ 288 return 0; 289 290 if (is_debug_frame) 291 cie_addr = base + cie_offset; 292 else 293 /* DWARF says that the CIE_pointer in the FDE is a 294 .debug_frame-relative offset, but the GCC-generated .eh_frame 295 sections instead store a "pcrelative" offset, which is just 296 as fine as it's self-contained. */ 297 cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); 298 } 299 300 Debug (15, "looking for CIE at address %lx\n", (long) cie_addr); 301 302 if ((ret = parse_cie (as, a, cie_addr, pi, &dci, is_debug_frame, arg)) < 0) 303 return ret; 304 305 /* IP-range has same encoding as FDE pointers, except that it's 306 always an absolute value: */ 307 ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK; 308 309 if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding, 310 pi, &start_ip, arg)) < 0 311 || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding, 312 pi, &ip_range, arg)) < 0) 313 return ret; 314 pi->start_ip = start_ip; 315 pi->end_ip = start_ip + ip_range; 316 pi->handler = dci.handler; 317 318 if (dci.sized_augmentation) 319 { 320 if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0) 321 return ret; 322 aug_end_addr = addr + aug_size; 323 } 324 325 if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding, 326 pi, &pi->lsda, arg)) < 0) 327 return ret; 328 329 Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n", 330 (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda); 331 332 if (need_unwind_info) 333 { 334 pi->format = UNW_INFO_FORMAT_TABLE; 335 pi->unwind_info_size = sizeof (dci); 336 pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool); 337 if (!pi->unwind_info) 338 return -UNW_ENOMEM; 339 340 if (dci.have_abi_marker) 341 { 342 if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0 343 || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0) 344 return ret; 345 Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n", 346 dci.abi, dci.tag); 347 } 348 349 if (dci.sized_augmentation) 350 dci.fde_instr_start = aug_end_addr; 351 else 352 dci.fde_instr_start = addr; 353 dci.fde_instr_end = fde_end_addr; 354 355 memcpy (pi->unwind_info, &dci, sizeof (dci)); 356 } 357 return 0; 358} 359