toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc

changeset 0
6474c204b198
     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

mercurial