1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,502 @@ 1.4 + 1.5 +/* libunwind - a platform-independent unwind library 1.6 + Copyright 2011 Linaro Limited 1.7 + 1.8 +This file is part of libunwind. 1.9 + 1.10 +Permission is hereby granted, free of charge, to any person obtaining 1.11 +a copy of this software and associated documentation files (the 1.12 +"Software"), to deal in the Software without restriction, including 1.13 +without limitation the rights to use, copy, modify, merge, publish, 1.14 +distribute, sublicense, and/or sell copies of the Software, and to 1.15 +permit persons to whom the Software is furnished to do so, subject to 1.16 +the following conditions: 1.17 + 1.18 +The above copyright notice and this permission notice shall be 1.19 +included in all copies or substantial portions of the Software. 1.20 + 1.21 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1.22 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1.23 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1.24 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 1.25 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 1.26 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1.27 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 1.28 + 1.29 +// Copyright (c) 2010 Google Inc. 1.30 +// All rights reserved. 1.31 +// 1.32 +// Redistribution and use in source and binary forms, with or without 1.33 +// modification, are permitted provided that the following conditions are 1.34 +// met: 1.35 +// 1.36 +// * Redistributions of source code must retain the above copyright 1.37 +// notice, this list of conditions and the following disclaimer. 1.38 +// * Redistributions in binary form must reproduce the above 1.39 +// copyright notice, this list of conditions and the following disclaimer 1.40 +// in the documentation and/or other materials provided with the 1.41 +// distribution. 1.42 +// * Neither the name of Google Inc. nor the names of its 1.43 +// contributors may be used to endorse or promote products derived from 1.44 +// this software without specific prior written permission. 1.45 +// 1.46 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.47 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.48 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.49 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.50 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.51 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.52 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.53 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.54 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.55 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.56 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.57 + 1.58 + 1.59 +// Derived from libunwind, with extensive modifications. 1.60 + 1.61 + 1.62 +#include "common/arm_ex_reader.h" 1.63 +#include "common/logging.h" 1.64 + 1.65 +#include <assert.h> 1.66 + 1.67 +// This file, in conjunction with arm_ex_to_module.cc, translates 1.68 +// EXIDX unwind information into the same format that Breakpad uses 1.69 +// for CFI information. Hence Breakpad's CFI unwinding abilities 1.70 +// also become usable for EXIDX. 1.71 +// 1.72 +// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A 1.73 +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf 1.74 + 1.75 +// EXIDX data is presented in two parts: 1.76 +// 1.77 +// * an index table. This contains two words per routine, 1.78 +// the first of which identifies the routine, and the second 1.79 +// of which is a reference to the unwind bytecode. If the 1.80 +// bytecode is very compact -- 3 bytes or less -- it can be 1.81 +// stored directly in the second word. 1.82 +// 1.83 +// * an area containing the unwind bytecodes. 1.84 + 1.85 +// General flow is: ExceptionTableInfo::Start iterates over all 1.86 +// of the index table entries (pairs). For each entry, it: 1.87 +// 1.88 +// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode 1.89 +// out into an intermediate buffer. 1.90 + 1.91 +// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate 1.92 +// buffer. Each bytecode instruction is bundled into a 1.93 +// arm_ex_to_module::extab_data structure, and handed to .. 1.94 +// 1.95 +// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to 1.96 +// ARMExToModule::TranslateCmd, and that generates the pseudo-CFI 1.97 +// records that Breakpad stores. 1.98 + 1.99 +#define ARM_EXIDX_CANT_UNWIND 0x00000001 1.100 +#define ARM_EXIDX_COMPACT 0x80000000 1.101 +#define ARM_EXTBL_OP_FINISH 0xb0 1.102 +#define ARM_EXIDX_TABLE_LIMIT (255*4) 1.103 + 1.104 +namespace arm_ex_reader { 1.105 + 1.106 +using arm_ex_to_module::ARM_EXIDX_CMD_FINISH; 1.107 +using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP; 1.108 +using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP; 1.109 +using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP; 1.110 +using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP; 1.111 +using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP; 1.112 +using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP; 1.113 +using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP; 1.114 +using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED; 1.115 +using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED; 1.116 +using arm_ex_to_module::exidx_entry; 1.117 +using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16; 1.118 +using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD; 1.119 +using google_breakpad::MemoryRange; 1.120 + 1.121 + 1.122 +static void* Prel31ToAddr(const void* addr) 1.123 +{ 1.124 + uint32_t offset32 = *reinterpret_cast<const uint32_t*>(addr); 1.125 + // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions 1.126 + // 63:31 inclusive. 1.127 + uint64_t offset64 = offset32; 1.128 + if (offset64 & (1ULL << 30)) 1.129 + offset64 |= 0xFFFFFFFF80000000ULL; 1.130 + else 1.131 + offset64 &= 0x000000007FFFFFFFULL; 1.132 + return ((char*)addr) + (uintptr_t)offset64; 1.133 +} 1.134 + 1.135 + 1.136 +// Extract unwind bytecode for the function denoted by |entry| into |buf|, 1.137 +// and return the number of bytes of |buf| written, along with a code 1.138 +// indicating the outcome. 1.139 + 1.140 +ExceptionTableInfo::ExExtractResult 1.141 +ExceptionTableInfo::ExtabEntryExtract(const struct exidx_entry* entry, 1.142 + uint8_t* buf, size_t buf_size, 1.143 + /*OUT*/size_t* buf_used) 1.144 +{ 1.145 + MemoryRange mr_out(buf, buf_size); 1.146 + 1.147 + *buf_used = 0; 1.148 + 1.149 +# define PUT_BUF_U8(_byte) \ 1.150 + do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \ 1.151 + buf[(*buf_used)++] = (_byte); } while (0) 1.152 + 1.153 +# define GET_EX_U32(_lval, _addr, _sec_mr) \ 1.154 + do { if (!(_sec_mr).Covers(reinterpret_cast<const uint8_t*>(_addr) \ 1.155 + - (_sec_mr).data(), 4)) \ 1.156 + return ExInBufOverflow; \ 1.157 + (_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0) 1.158 + 1.159 +# define GET_EXIDX_U32(_lval, _addr) \ 1.160 + GET_EX_U32(_lval, _addr, mr_exidx_) 1.161 +# define GET_EXTAB_U32(_lval, _addr) \ 1.162 + GET_EX_U32(_lval, _addr, mr_extab_) 1.163 + 1.164 + uint32_t data; 1.165 + GET_EXIDX_U32(data, &entry->data); 1.166 + 1.167 + // A function can be marked CANT_UNWIND if (eg) it is known to be 1.168 + // at the bottom of the stack. 1.169 + if (data == ARM_EXIDX_CANT_UNWIND) 1.170 + return ExCantUnwind; 1.171 + 1.172 + uint32_t pers; // personality number 1.173 + uint32_t extra; // number of extra data words required 1.174 + uint32_t extra_allowed; // number of extra data words allowed 1.175 + uint32_t* extbl_data; // the handler entry, if not inlined 1.176 + 1.177 + if (data & ARM_EXIDX_COMPACT) { 1.178 + // The handler table entry has been inlined into the index table entry. 1.179 + // In this case it can only be an ARM-defined compact model, since 1.180 + // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the 1.181 + // ARM compact model, but 1 and 2 are "Long format" and may require 1.182 + // extra data words. Hence the allowable personalities here are: 1.183 + // personality 0, in which case 'extra' has no meaning 1.184 + // personality 1, with zero extra words 1.185 + // personality 2, with zero extra words 1.186 + extbl_data = NULL; 1.187 + pers = (data >> 24) & 0x0F; 1.188 + extra = (data >> 16) & 0xFF; 1.189 + extra_allowed = 0; 1.190 + } 1.191 + else { 1.192 + // The index table entry is a pointer to the handler entry. Note 1.193 + // that Prel31ToAddr will read the given address, but we already 1.194 + // range-checked above. 1.195 + extbl_data = reinterpret_cast<uint32_t*>(Prel31ToAddr(&entry->data)); 1.196 + GET_EXTAB_U32(data, extbl_data); 1.197 + if (!(data & ARM_EXIDX_COMPACT)) { 1.198 + // This denotes a "generic model" handler. That will involve 1.199 + // executing arbitary machine code, which is something we 1.200 + // can't represent here; hence reject it. 1.201 + return ExCantRepresent; 1.202 + } 1.203 + // So we have a compact model representation. Again, 3 possible 1.204 + // personalities, but this time up to 255 allowable extra words. 1.205 + pers = (data >> 24) & 0x0F; 1.206 + extra = (data >> 16) & 0xFF; 1.207 + extra_allowed = 255; 1.208 + extbl_data++; 1.209 + } 1.210 + 1.211 + // Now look at the the handler table entry. The first word is 1.212 + // |data| and subsequent words start at |*extbl_data|. The number 1.213 + // of extra words to use is |extra|, provided that the personality 1.214 + // allows extra words. Even if it does, none may be available -- 1.215 + // extra_allowed is the maximum number of extra words allowed. */ 1.216 + if (pers == 0) { 1.217 + // "Su16" in the documentation -- 3 unwinding insn bytes 1.218 + // |extra| has no meaning here; instead that byte is an unwind-info byte 1.219 + PUT_BUF_U8(data >> 16); 1.220 + PUT_BUF_U8(data >> 8); 1.221 + PUT_BUF_U8(data); 1.222 + } 1.223 + else if ((pers == 1 || pers == 2) && extra <= extra_allowed) { 1.224 + // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes, 1.225 + // and up to 255 extra words. 1.226 + PUT_BUF_U8(data >> 8); 1.227 + PUT_BUF_U8(data); 1.228 + for (uint32_t j = 0; j < extra; j++) { 1.229 + GET_EXTAB_U32(data, extbl_data); 1.230 + extbl_data++; 1.231 + PUT_BUF_U8(data >> 24); 1.232 + PUT_BUF_U8(data >> 16); 1.233 + PUT_BUF_U8(data >> 8); 1.234 + PUT_BUF_U8(data >> 0); 1.235 + } 1.236 + } 1.237 + else { 1.238 + // The entry is invalid. 1.239 + return ExInvalid; 1.240 + } 1.241 + 1.242 + // Make sure the entry is terminated with "FINISH" 1.243 + if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH) 1.244 + PUT_BUF_U8(ARM_EXTBL_OP_FINISH); 1.245 + 1.246 + return ExSuccess; 1.247 + 1.248 +# undef GET_EXTAB_U32 1.249 +# undef GET_EXIDX_U32 1.250 +# undef GET_U32 1.251 +# undef PUT_BUF_U8 1.252 +} 1.253 + 1.254 + 1.255 +// Take the unwind information extracted by ExtabEntryExtract 1.256 +// and parse it into frame-unwind instructions. These are as 1.257 +// specified in "Table 4, ARM-defined frame-unwinding instructions" 1.258 +// in the specification document detailed in comments at the top 1.259 +// of this file. 1.260 +// 1.261 +// This reads from |buf[0, +data_size)|. It checks for overruns of 1.262 +// the input buffer and returns a negative value if that happens, or 1.263 +// for any other failure cases. It returns zero in case of success. 1.264 +int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size) 1.265 +{ 1.266 + if (buf == NULL || buf_size == 0) 1.267 + return -1; 1.268 + 1.269 + MemoryRange mr_in(buf, buf_size); 1.270 + const uint8_t* buf_initially = buf; 1.271 + 1.272 +# define GET_BUF_U8(_lval) \ 1.273 + do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \ 1.274 + (_lval) = *(buf++); } while (0) 1.275 + 1.276 + const uint8_t* end = buf + buf_size; 1.277 + 1.278 + while (buf < end) { 1.279 + struct arm_ex_to_module::extab_data edata; 1.280 + memset(&edata, 0, sizeof(edata)); 1.281 + 1.282 + uint8_t op; 1.283 + GET_BUF_U8(op); 1.284 + if ((op & 0xc0) == 0x00) { 1.285 + // vsp = vsp + (xxxxxx << 2) + 4 1.286 + edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; 1.287 + edata.data = (((int)op & 0x3f) << 2) + 4; 1.288 + } 1.289 + else if ((op & 0xc0) == 0x40) { 1.290 + // vsp = vsp - (xxxxxx << 2) - 4 1.291 + edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP; 1.292 + edata.data = (((int)op & 0x3f) << 2) + 4; 1.293 + } 1.294 + else if ((op & 0xf0) == 0x80) { 1.295 + uint8_t op2; 1.296 + GET_BUF_U8(op2); 1.297 + if (op == 0x80 && op2 == 0x00) { 1.298 + // Refuse to unwind 1.299 + edata.cmd = ARM_EXIDX_CMD_REFUSED; 1.300 + } else { 1.301 + // Pop up to 12 integer registers under masks {r15-r12},{r11-r4} 1.302 + edata.cmd = ARM_EXIDX_CMD_REG_POP; 1.303 + edata.data = ((op & 0xf) << 8) | op2; 1.304 + edata.data = edata.data << 4; 1.305 + } 1.306 + } 1.307 + else if ((op & 0xf0) == 0x90) { 1.308 + if (op == 0x9d || op == 0x9f) { 1.309 + // 9d: Reserved as prefix for ARM register to register moves 1.310 + // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves 1.311 + edata.cmd = ARM_EXIDX_CMD_RESERVED; 1.312 + } else { 1.313 + // Set vsp = r[nnnn] 1.314 + edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; 1.315 + edata.data = op & 0x0f; 1.316 + } 1.317 + } 1.318 + else if ((op & 0xf0) == 0xa0) { 1.319 + // Pop r4 to r[4+nnn], or 1.320 + // Pop r4 to r[4+nnn] and r14 or 1.321 + unsigned end = (op & 0x07); 1.322 + edata.data = (1 << (end + 1)) - 1; 1.323 + edata.data = edata.data << 4; 1.324 + if (op & 0x08) edata.data |= 1 << 14; 1.325 + edata.cmd = ARM_EXIDX_CMD_REG_POP; 1.326 + } 1.327 + else if (op == ARM_EXTBL_OP_FINISH) { 1.328 + // Finish 1.329 + edata.cmd = ARM_EXIDX_CMD_FINISH; 1.330 + buf = end; 1.331 + } 1.332 + else if (op == 0xb1) { 1.333 + uint8_t op2; 1.334 + GET_BUF_U8(op2); 1.335 + if (op2 == 0 || (op2 & 0xf0)) { 1.336 + // Spare 1.337 + edata.cmd = ARM_EXIDX_CMD_RESERVED; 1.338 + } else { 1.339 + // Pop integer registers under mask {r3,r2,r1,r0} 1.340 + edata.cmd = ARM_EXIDX_CMD_REG_POP; 1.341 + edata.data = op2 & 0x0f; 1.342 + } 1.343 + } 1.344 + else if (op == 0xb2) { 1.345 + // vsp = vsp + 0x204 + (uleb128 << 2) 1.346 + uint64_t offset = 0; 1.347 + uint8_t byte, shift = 0; 1.348 + do { 1.349 + GET_BUF_U8(byte); 1.350 + offset |= (byte & 0x7f) << shift; 1.351 + shift += 7; 1.352 + } while ((byte & 0x80) && buf < end); 1.353 + edata.data = offset * 4 + 0x204; 1.354 + edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; 1.355 + } 1.356 + else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { 1.357 + // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly 1.358 + // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly 1.359 + // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly 1.360 + edata.cmd = ARM_EXIDX_CMD_VFP_POP; 1.361 + GET_BUF_U8(edata.data); 1.362 + if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16; 1.363 + if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD; 1.364 + } 1.365 + else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) { 1.366 + // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly 1.367 + // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly 1.368 + edata.cmd = ARM_EXIDX_CMD_VFP_POP; 1.369 + edata.data = 0x80 | (op & 0x07); 1.370 + if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD; 1.371 + } 1.372 + else if (op >= 0xc0 && op <= 0xc5) { 1.373 + // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7 1.374 + edata.cmd = ARM_EXIDX_CMD_WREG_POP; 1.375 + edata.data = 0xa0 | (op & 0x07); 1.376 + } 1.377 + else if (op == 0xc6) { 1.378 + // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc] 1.379 + edata.cmd = ARM_EXIDX_CMD_WREG_POP; 1.380 + GET_BUF_U8(edata.data); 1.381 + } 1.382 + else if (op == 0xc7) { 1.383 + uint8_t op2; 1.384 + GET_BUF_U8(op2); 1.385 + if (op2 == 0 || (op2 & 0xf0)) { 1.386 + // Spare 1.387 + edata.cmd = ARM_EXIDX_CMD_RESERVED; 1.388 + } else { 1.389 + // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} 1.390 + edata.cmd = ARM_EXIDX_CMD_WCGR_POP; 1.391 + edata.data = op2 & 0x0f; 1.392 + } 1.393 + } 1.394 + else { 1.395 + // Spare 1.396 + edata.cmd = ARM_EXIDX_CMD_RESERVED; 1.397 + } 1.398 + 1.399 + int ret = handler_->ImproveStackFrame(&edata); 1.400 + if (ret < 0) return ret; 1.401 + } 1.402 + return 0; 1.403 + 1.404 +# undef GET_BUF_U8 1.405 +} 1.406 + 1.407 +void ExceptionTableInfo::Start() 1.408 +{ 1.409 + const struct exidx_entry* start 1.410 + = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()); 1.411 + const struct exidx_entry* end 1.412 + = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data() 1.413 + + mr_exidx_.length()); 1.414 + 1.415 + // Iterate over each of the EXIDX entries (pairs of 32-bit words). 1.416 + // These occupy the entire .exidx section. 1.417 + for (const struct exidx_entry* entry = start; entry < end; ++entry) { 1.418 + 1.419 + // Figure out the code address range that this table entry is 1.420 + // associated with. 1.421 + uint32_t addr = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr)) 1.422 + - mapping_addr_ + loading_addr_) & 0x7fffffff; 1.423 + uint32_t next_addr; 1.424 + if (entry < end - 1) 1.425 + next_addr = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr))) 1.426 + - mapping_addr_ + loading_addr_) & 0x7fffffff; 1.427 + else { 1.428 + // This is the last EXIDX entry in the sequence, so we don't 1.429 + // have an address for the start of the next function, to limit 1.430 + // this one. Instead use the address of the last byte of the 1.431 + // text section associated with this .exidx section, that we 1.432 + // have been given. So as to avoid junking up the CFI unwind 1.433 + // tables with absurdly large address ranges in the case where 1.434 + // text_last_svma_ is wrong, only use the value if it is nonzero 1.435 + // and within one page of |addr|. Otherwise assume a length of 1. 1.436 + // 1.437 + // In some cases, gcc has been observed to finish the exidx 1.438 + // section with an entry of length 1 marked CANT_UNWIND, 1.439 + // presumably exactly for the purpose of giving a definite 1.440 + // length for the last real entry, without having to look at 1.441 + // text segment boundaries. 1.442 + bool plausible = false; 1.443 + next_addr = addr + 1; 1.444 + if (text_last_svma_ != 0) { 1.445 + uint32_t maybe_next_addr = text_last_svma_ + 1; 1.446 + if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) { 1.447 + next_addr = maybe_next_addr; 1.448 + plausible = true; 1.449 + } 1.450 + } 1.451 + if (!plausible) 1.452 + BPLOG(INFO) << "ExceptionTableInfo: implausible EXIDX last entry size " 1.453 + << (int32_t)(text_last_svma_ - addr) 1.454 + << "; using 1 instead."; 1.455 + } 1.456 + 1.457 + // Extract the unwind info into |buf|. This might fail for 1.458 + // various reasons. It involves reading both the .exidx and 1.459 + // .extab sections. All accesses to those sections are 1.460 + // bounds-checked. 1.461 + uint8_t buf[ARM_EXIDX_TABLE_LIMIT]; 1.462 + size_t buf_used = 0; 1.463 + ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used); 1.464 + if (res != ExSuccess) { 1.465 + // Couldn't extract the unwind info, for some reason. Move on. 1.466 + switch (res) { 1.467 + case ExInBufOverflow: 1.468 + BPLOG(INFO) << "ExtabEntryExtract: .exidx/.extab section overrun"; 1.469 + break; 1.470 + case ExOutBufOverflow: 1.471 + BPLOG(INFO) << "ExtabEntryExtract: bytecode buffer overflow"; 1.472 + break; 1.473 + case ExCantUnwind: 1.474 + BPLOG(INFO) << "ExtabEntryExtract: function is marked CANT_UNWIND"; 1.475 + break; 1.476 + case ExCantRepresent: 1.477 + BPLOG(INFO) << "ExtabEntryExtract: bytecode can't be represented"; 1.478 + break; 1.479 + case ExInvalid: 1.480 + BPLOG(INFO) << "ExtabEntryExtract: index table entry is invalid"; 1.481 + break; 1.482 + default: 1.483 + BPLOG(INFO) << "ExtabEntryExtract: unknown error: " << (int)res; 1.484 + break; 1.485 + } 1.486 + continue; 1.487 + } 1.488 + 1.489 + // Finally, work through the unwind instructions in |buf| and 1.490 + // create CFI entries that Breakpad can use. This can also fail. 1.491 + // First, add a new stack frame entry, into which ExtabEntryDecode 1.492 + // will write the CFI entries. 1.493 + handler_->AddStackFrame(addr, next_addr - addr); 1.494 + int ret = ExtabEntryDecode(buf, buf_used); 1.495 + if (ret < 0) { 1.496 + handler_->DeleteStackFrame(); 1.497 + BPLOG(INFO) << "ExtabEntryDecode: failed with error code: " << ret; 1.498 + continue; 1.499 + } 1.500 + handler_->SubmitStackFrame(); 1.501 + 1.502 + } /* iterating over .exidx */ 1.503 +} 1.504 + 1.505 +} // arm_ex_reader