toolkit/crashreporter/breakpad-patches/12-bug863475.patch

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/breakpad-patches/12-bug863475.patch	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1305 @@
     1.4 +# HG changeset patch
     1.5 +# User Julian Seward <jseward@acm.org>
     1.6 +# Date 1371190160 -7200
     1.7 +#      Fri Jun 14 08:09:20 2013 +0200
     1.8 +# Node ID e74de3db7dd27ffda8f4772f892cfb52c5c35649
     1.9 +# Parent  4dcd4220c31068e116d88a58e5b396fbb01719dd
    1.10 +Bug 863475 - integrate ARM EXIDX unwind parsing into Breakpad.  r=glandium,ted
    1.11 +
    1.12 +diff --git a/Makefile.am b/Makefile.am
    1.13 +--- a/Makefile.am
    1.14 ++++ b/Makefile.am
    1.15 +@@ -428,16 +428,18 @@ src_tools_linux_dump_syms_dump_syms_SOUR
    1.16 + 	src/common/dwarf_line_to_module.cc \
    1.17 + 	src/common/language.cc \
    1.18 + 	src/common/module.cc \
    1.19 + 	src/common/stabs_reader.cc \
    1.20 + 	src/common/stabs_to_module.cc \
    1.21 + 	src/common/dwarf/bytereader.cc \
    1.22 + 	src/common/dwarf/dwarf2diehandler.cc \
    1.23 + 	src/common/dwarf/dwarf2reader.cc \
    1.24 ++        src/common/arm_ex_reader.cc \
    1.25 ++        src/common/arm_ex_to_module.cc \
    1.26 + 	src/common/linux/dump_symbols.cc \
    1.27 + 	src/common/linux/elf_symbols_to_module.cc \
    1.28 + 	src/common/linux/elfutils.cc \
    1.29 + 	src/common/linux/file_id.cc \
    1.30 + 	src/common/linux/linux_libc_support.cc \
    1.31 + 	src/common/linux/memory_mapped_file.cc \
    1.32 + 	src/common/linux/safe_readlink.cc \
    1.33 + 	src/tools/linux/dump_syms/dump_syms.cc
    1.34 +@@ -1010,16 +1012,20 @@ EXTRA_DIST = \
    1.35 + 	src/client/windows/handler/exception_handler.vcproj \
    1.36 + 	src/client/windows/sender/crash_report_sender.cc \
    1.37 + 	src/client/windows/sender/crash_report_sender.h \
    1.38 + 	src/client/windows/sender/crash_report_sender.vcproj \
    1.39 + 	src/common/convert_UTF.c \
    1.40 + 	src/common/convert_UTF.h \
    1.41 + 	src/common/linux/dump_symbols.cc \
    1.42 + 	src/common/linux/dump_symbols.h \
    1.43 ++        src/common/arm_ex_reader.cc \
    1.44 ++        src/common/arm_ex_reader.h \
    1.45 ++        src/common/arm_ex_to_module.cc \
    1.46 ++        src/common/arm_ex_to_module.h \
    1.47 + 	src/common/linux/elf_symbols_to_module.cc \
    1.48 + 	src/common/linux/elf_symbols_to_module.h \
    1.49 + 	src/common/linux/elfutils.cc \
    1.50 + 	src/common/linux/elfutils.h \
    1.51 + 	src/common/linux/file_id.cc \
    1.52 + 	src/common/linux/file_id.h \
    1.53 + 	src/common/linux/guid_creator.cc \
    1.54 + 	src/common/linux/guid_creator.h \
    1.55 +diff --git a/src/common/arm_ex_reader.cc b/src/common/arm_ex_reader.cc
    1.56 +new file mode 100644
    1.57 +--- /dev/null
    1.58 ++++ b/src/common/arm_ex_reader.cc
    1.59 +@@ -0,0 +1,502 @@
    1.60 ++
    1.61 ++/* libunwind - a platform-independent unwind library
    1.62 ++   Copyright 2011 Linaro Limited
    1.63 ++
    1.64 ++This file is part of libunwind.
    1.65 ++
    1.66 ++Permission is hereby granted, free of charge, to any person obtaining
    1.67 ++a copy of this software and associated documentation files (the
    1.68 ++"Software"), to deal in the Software without restriction, including
    1.69 ++without limitation the rights to use, copy, modify, merge, publish,
    1.70 ++distribute, sublicense, and/or sell copies of the Software, and to
    1.71 ++permit persons to whom the Software is furnished to do so, subject to
    1.72 ++the following conditions:
    1.73 ++
    1.74 ++The above copyright notice and this permission notice shall be
    1.75 ++included in all copies or substantial portions of the Software.
    1.76 ++
    1.77 ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    1.78 ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    1.79 ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    1.80 ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    1.81 ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    1.82 ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    1.83 ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    1.84 ++
    1.85 ++// Copyright (c) 2010 Google Inc.
    1.86 ++// All rights reserved.
    1.87 ++//
    1.88 ++// Redistribution and use in source and binary forms, with or without
    1.89 ++// modification, are permitted provided that the following conditions are
    1.90 ++// met:
    1.91 ++//
    1.92 ++//     * Redistributions of source code must retain the above copyright
    1.93 ++// notice, this list of conditions and the following disclaimer.
    1.94 ++//     * Redistributions in binary form must reproduce the above
    1.95 ++// copyright notice, this list of conditions and the following disclaimer
    1.96 ++// in the documentation and/or other materials provided with the
    1.97 ++// distribution.
    1.98 ++//     * Neither the name of Google Inc. nor the names of its
    1.99 ++// contributors may be used to endorse or promote products derived from
   1.100 ++// this software without specific prior written permission.
   1.101 ++//
   1.102 ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   1.103 ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   1.104 ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   1.105 ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   1.106 ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   1.107 ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   1.108 ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   1.109 ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   1.110 ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   1.111 ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   1.112 ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.113 ++
   1.114 ++
   1.115 ++// Derived from libunwind, with extensive modifications.
   1.116 ++
   1.117 ++
   1.118 ++#include "common/arm_ex_reader.h"
   1.119 ++#include "common/logging.h"
   1.120 ++
   1.121 ++#include <assert.h>
   1.122 ++
   1.123 ++// This file, in conjunction with arm_ex_to_module.cc, translates
   1.124 ++// EXIDX unwind information into the same format that Breakpad uses
   1.125 ++// for CFI information.  Hence Breakpad's CFI unwinding abilities
   1.126 ++// also become usable for EXIDX.
   1.127 ++//
   1.128 ++// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A
   1.129 ++// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
   1.130 ++
   1.131 ++// EXIDX data is presented in two parts:
   1.132 ++//
   1.133 ++// * an index table.  This contains two words per routine,
   1.134 ++//   the first of which identifies the routine, and the second
   1.135 ++//   of which is a reference to the unwind bytecode.  If the
   1.136 ++//   bytecode is very compact -- 3 bytes or less -- it can be
   1.137 ++//   stored directly in the second word.
   1.138 ++//
   1.139 ++// * an area containing the unwind bytecodes.
   1.140 ++
   1.141 ++// General flow is: ExceptionTableInfo::Start iterates over all
   1.142 ++// of the index table entries (pairs).  For each entry, it:
   1.143 ++//
   1.144 ++// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode
   1.145 ++//   out into an intermediate buffer.
   1.146 ++
   1.147 ++// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate
   1.148 ++//   buffer.  Each bytecode instruction is bundled into a
   1.149 ++//   arm_ex_to_module::extab_data structure, and handed to ..
   1.150 ++//
   1.151 ++// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to
   1.152 ++//   ARMExToModule::TranslateCmd, and that generates the pseudo-CFI
   1.153 ++//   records that Breakpad stores.
   1.154 ++
   1.155 ++#define ARM_EXIDX_CANT_UNWIND 0x00000001
   1.156 ++#define ARM_EXIDX_COMPACT     0x80000000
   1.157 ++#define ARM_EXTBL_OP_FINISH   0xb0
   1.158 ++#define ARM_EXIDX_TABLE_LIMIT (255*4)
   1.159 ++
   1.160 ++namespace arm_ex_reader {
   1.161 ++
   1.162 ++using arm_ex_to_module::ARM_EXIDX_CMD_FINISH;
   1.163 ++using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP;
   1.164 ++using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP;
   1.165 ++using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP;
   1.166 ++using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP;
   1.167 ++using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP;
   1.168 ++using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP;
   1.169 ++using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP;
   1.170 ++using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED;
   1.171 ++using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED;
   1.172 ++using arm_ex_to_module::exidx_entry;
   1.173 ++using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16;
   1.174 ++using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD;
   1.175 ++using google_breakpad::MemoryRange;
   1.176 ++
   1.177 ++
   1.178 ++static void* Prel31ToAddr(const void* addr) 
   1.179 ++{
   1.180 ++  uint32_t offset32 = *reinterpret_cast<const uint32_t*>(addr);
   1.181 ++  // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions
   1.182 ++  // 63:31 inclusive.
   1.183 ++  uint64_t offset64 = offset32;
   1.184 ++  if (offset64 & (1ULL << 30))
   1.185 ++    offset64 |= 0xFFFFFFFF80000000ULL;
   1.186 ++  else
   1.187 ++    offset64 &= 0x000000007FFFFFFFULL;
   1.188 ++  return ((char*)addr) + (uintptr_t)offset64;
   1.189 ++}
   1.190 ++
   1.191 ++
   1.192 ++// Extract unwind bytecode for the function denoted by |entry| into |buf|,
   1.193 ++// and return the number of bytes of |buf| written, along with a code
   1.194 ++// indicating the outcome.
   1.195 ++
   1.196 ++ExceptionTableInfo::ExExtractResult
   1.197 ++ExceptionTableInfo::ExtabEntryExtract(const struct exidx_entry* entry,
   1.198 ++                                      uint8_t* buf, size_t buf_size,
   1.199 ++                                      /*OUT*/size_t* buf_used)
   1.200 ++{
   1.201 ++  MemoryRange mr_out(buf, buf_size);
   1.202 ++
   1.203 ++  *buf_used = 0;
   1.204 ++
   1.205 ++# define PUT_BUF_U8(_byte) \
   1.206 ++  do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \
   1.207 ++       buf[(*buf_used)++] = (_byte); } while (0)
   1.208 ++
   1.209 ++# define GET_EX_U32(_lval, _addr, _sec_mr) \
   1.210 ++  do { if (!(_sec_mr).Covers(reinterpret_cast<const uint8_t*>(_addr) \
   1.211 ++                             - (_sec_mr).data(), 4)) \
   1.212 ++         return ExInBufOverflow; \
   1.213 ++       (_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0)
   1.214 ++
   1.215 ++# define GET_EXIDX_U32(_lval, _addr) \
   1.216 ++            GET_EX_U32(_lval, _addr, mr_exidx_)
   1.217 ++# define GET_EXTAB_U32(_lval, _addr) \
   1.218 ++            GET_EX_U32(_lval, _addr, mr_extab_)
   1.219 ++
   1.220 ++  uint32_t data;
   1.221 ++  GET_EXIDX_U32(data, &entry->data);
   1.222 ++
   1.223 ++  // A function can be marked CANT_UNWIND if (eg) it is known to be
   1.224 ++  // at the bottom of the stack.
   1.225 ++  if (data == ARM_EXIDX_CANT_UNWIND)
   1.226 ++    return ExCantUnwind;
   1.227 ++
   1.228 ++  uint32_t  pers;          // personality number
   1.229 ++  uint32_t  extra;         // number of extra data words required
   1.230 ++  uint32_t  extra_allowed; // number of extra data words allowed
   1.231 ++  uint32_t* extbl_data;    // the handler entry, if not inlined
   1.232 ++
   1.233 ++  if (data & ARM_EXIDX_COMPACT) {
   1.234 ++    // The handler table entry has been inlined into the index table entry.
   1.235 ++    // In this case it can only be an ARM-defined compact model, since
   1.236 ++    // bit 31 is 1.  Only personalities 0, 1 and 2 are defined for the
   1.237 ++    // ARM compact model, but 1 and 2 are "Long format" and may require
   1.238 ++    // extra data words.  Hence the allowable personalities here are:
   1.239 ++    //   personality 0, in which case 'extra' has no meaning
   1.240 ++    //   personality 1, with zero extra words
   1.241 ++    //   personality 2, with zero extra words
   1.242 ++    extbl_data = NULL;
   1.243 ++    pers  = (data >> 24) & 0x0F;
   1.244 ++    extra = (data >> 16) & 0xFF;
   1.245 ++    extra_allowed = 0;
   1.246 ++  }
   1.247 ++  else {
   1.248 ++    // The index table entry is a pointer to the handler entry.  Note
   1.249 ++    // that Prel31ToAddr will read the given address, but we already
   1.250 ++    // range-checked above.
   1.251 ++    extbl_data = reinterpret_cast<uint32_t*>(Prel31ToAddr(&entry->data));
   1.252 ++    GET_EXTAB_U32(data, extbl_data);
   1.253 ++    if (!(data & ARM_EXIDX_COMPACT)) {
   1.254 ++      // This denotes a "generic model" handler.  That will involve
   1.255 ++      // executing arbitary machine code, which is something we
   1.256 ++      // can't represent here; hence reject it.
   1.257 ++      return ExCantRepresent;
   1.258 ++    }
   1.259 ++    // So we have a compact model representation.  Again, 3 possible
   1.260 ++    // personalities, but this time up to 255 allowable extra words.
   1.261 ++    pers  = (data >> 24) & 0x0F;
   1.262 ++    extra = (data >> 16) & 0xFF;
   1.263 ++    extra_allowed = 255;
   1.264 ++    extbl_data++;
   1.265 ++  }
   1.266 ++
   1.267 ++  // Now look at the the handler table entry.  The first word is
   1.268 ++  // |data| and subsequent words start at |*extbl_data|.  The number
   1.269 ++  // of extra words to use is |extra|, provided that the personality
   1.270 ++  // allows extra words.  Even if it does, none may be available --
   1.271 ++  // extra_allowed is the maximum number of extra words allowed. */
   1.272 ++  if (pers == 0) {
   1.273 ++    // "Su16" in the documentation -- 3 unwinding insn bytes
   1.274 ++    // |extra| has no meaning here; instead that byte is an unwind-info byte
   1.275 ++    PUT_BUF_U8(data >> 16);
   1.276 ++    PUT_BUF_U8(data >> 8);
   1.277 ++    PUT_BUF_U8(data);
   1.278 ++  }
   1.279 ++  else if ((pers == 1 || pers == 2) && extra <= extra_allowed) {
   1.280 ++    // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes,
   1.281 ++    // and up to 255 extra words.
   1.282 ++    PUT_BUF_U8(data >> 8);
   1.283 ++    PUT_BUF_U8(data);
   1.284 ++    for (uint32_t j = 0; j < extra; j++) {
   1.285 ++      GET_EXTAB_U32(data, extbl_data);
   1.286 ++      extbl_data++;
   1.287 ++      PUT_BUF_U8(data >> 24);
   1.288 ++      PUT_BUF_U8(data >> 16);
   1.289 ++      PUT_BUF_U8(data >> 8);
   1.290 ++      PUT_BUF_U8(data >> 0);
   1.291 ++    }
   1.292 ++  }
   1.293 ++  else {
   1.294 ++    // The entry is invalid.
   1.295 ++    return ExInvalid;
   1.296 ++  }
   1.297 ++
   1.298 ++  // Make sure the entry is terminated with "FINISH"
   1.299 ++  if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH)
   1.300 ++    PUT_BUF_U8(ARM_EXTBL_OP_FINISH);
   1.301 ++
   1.302 ++  return ExSuccess;
   1.303 ++
   1.304 ++# undef GET_EXTAB_U32
   1.305 ++# undef GET_EXIDX_U32
   1.306 ++# undef GET_U32
   1.307 ++# undef PUT_BUF_U8
   1.308 ++}
   1.309 ++
   1.310 ++
   1.311 ++// Take the unwind information extracted by ExtabEntryExtract
   1.312 ++// and parse it into frame-unwind instructions.  These are as
   1.313 ++// specified in "Table 4, ARM-defined frame-unwinding instructions"
   1.314 ++// in the specification document detailed in comments at the top
   1.315 ++// of this file.
   1.316 ++//
   1.317 ++// This reads from |buf[0, +data_size)|.  It checks for overruns of
   1.318 ++// the input buffer and returns a negative value if that happens, or
   1.319 ++// for any other failure cases.  It returns zero in case of success.
   1.320 ++int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size)
   1.321 ++{
   1.322 ++  if (buf == NULL || buf_size == 0)
   1.323 ++    return -1;
   1.324 ++
   1.325 ++  MemoryRange mr_in(buf, buf_size);
   1.326 ++  const uint8_t* buf_initially = buf;
   1.327 ++
   1.328 ++# define GET_BUF_U8(_lval) \
   1.329 ++  do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \
   1.330 ++       (_lval) = *(buf++); } while (0)
   1.331 ++
   1.332 ++  const uint8_t* end = buf + buf_size;
   1.333 ++
   1.334 ++  while (buf < end) {
   1.335 ++    struct arm_ex_to_module::extab_data edata;
   1.336 ++    memset(&edata, 0, sizeof(edata));
   1.337 ++
   1.338 ++    uint8_t op;
   1.339 ++    GET_BUF_U8(op);
   1.340 ++    if ((op & 0xc0) == 0x00) {
   1.341 ++      // vsp = vsp + (xxxxxx << 2) + 4
   1.342 ++      edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP;
   1.343 ++      edata.data = (((int)op & 0x3f) << 2) + 4;
   1.344 ++    }
   1.345 ++    else if ((op & 0xc0) == 0x40) {
   1.346 ++      // vsp = vsp - (xxxxxx << 2) - 4
   1.347 ++      edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP;
   1.348 ++      edata.data = (((int)op & 0x3f) << 2) + 4;
   1.349 ++    }
   1.350 ++    else if ((op & 0xf0) == 0x80) {
   1.351 ++      uint8_t op2;
   1.352 ++      GET_BUF_U8(op2);
   1.353 ++      if (op == 0x80 && op2 == 0x00) {
   1.354 ++        // Refuse to unwind
   1.355 ++        edata.cmd = ARM_EXIDX_CMD_REFUSED;
   1.356 ++      } else {
   1.357 ++        // Pop up to 12 integer registers under masks {r15-r12},{r11-r4}
   1.358 ++        edata.cmd = ARM_EXIDX_CMD_REG_POP;
   1.359 ++        edata.data = ((op & 0xf) << 8) | op2;
   1.360 ++        edata.data = edata.data << 4;
   1.361 ++      }
   1.362 ++    }
   1.363 ++    else if ((op & 0xf0) == 0x90) {
   1.364 ++      if (op == 0x9d || op == 0x9f) {
   1.365 ++        // 9d: Reserved as prefix for ARM register to register moves
   1.366 ++        // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves
   1.367 ++        edata.cmd = ARM_EXIDX_CMD_RESERVED;
   1.368 ++      } else {
   1.369 ++        // Set vsp = r[nnnn]
   1.370 ++        edata.cmd = ARM_EXIDX_CMD_REG_TO_SP;
   1.371 ++        edata.data = op & 0x0f;
   1.372 ++      }
   1.373 ++    }
   1.374 ++    else if ((op & 0xf0) == 0xa0) {
   1.375 ++      // Pop r4 to r[4+nnn],          or
   1.376 ++      // Pop r4 to r[4+nnn] and r14   or
   1.377 ++      unsigned end = (op & 0x07);
   1.378 ++      edata.data = (1 << (end + 1)) - 1;
   1.379 ++      edata.data = edata.data << 4;
   1.380 ++      if (op & 0x08) edata.data |= 1 << 14;
   1.381 ++      edata.cmd = ARM_EXIDX_CMD_REG_POP;
   1.382 ++    }
   1.383 ++    else if (op == ARM_EXTBL_OP_FINISH) {
   1.384 ++      // Finish
   1.385 ++      edata.cmd = ARM_EXIDX_CMD_FINISH;
   1.386 ++      buf = end;
   1.387 ++    }
   1.388 ++    else if (op == 0xb1) {
   1.389 ++      uint8_t op2;
   1.390 ++      GET_BUF_U8(op2);
   1.391 ++      if (op2 == 0 || (op2 & 0xf0)) {
   1.392 ++        // Spare
   1.393 ++        edata.cmd = ARM_EXIDX_CMD_RESERVED;
   1.394 ++      } else {
   1.395 ++        // Pop integer registers under mask {r3,r2,r1,r0}
   1.396 ++        edata.cmd = ARM_EXIDX_CMD_REG_POP;
   1.397 ++        edata.data = op2 & 0x0f;
   1.398 ++      }
   1.399 ++    }
   1.400 ++    else if (op == 0xb2) {
   1.401 ++      // vsp = vsp + 0x204 + (uleb128 << 2)
   1.402 ++      uint64_t offset = 0;
   1.403 ++      uint8_t byte, shift = 0;
   1.404 ++      do {
   1.405 ++        GET_BUF_U8(byte);
   1.406 ++        offset |= (byte & 0x7f) << shift;
   1.407 ++        shift += 7;
   1.408 ++      } while ((byte & 0x80) && buf < end);
   1.409 ++      edata.data = offset * 4 + 0x204;
   1.410 ++      edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP;
   1.411 ++    }
   1.412 ++    else if (op == 0xb3 || op == 0xc8 || op == 0xc9) {
   1.413 ++      // b3: Pop VFP regs D[ssss]    to D[ssss+cccc],    FSTMFDX-ishly
   1.414 ++      // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly
   1.415 ++      // c9: Pop VFP regs D[ssss]    to D[ssss+cccc],    FSTMFDD-ishly
   1.416 ++      edata.cmd = ARM_EXIDX_CMD_VFP_POP;
   1.417 ++      GET_BUF_U8(edata.data);
   1.418 ++      if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16;
   1.419 ++      if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD;
   1.420 ++    }
   1.421 ++    else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) {
   1.422 ++      // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly
   1.423 ++      // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly
   1.424 ++      edata.cmd = ARM_EXIDX_CMD_VFP_POP;
   1.425 ++      edata.data = 0x80 | (op & 0x07);
   1.426 ++      if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD;
   1.427 ++    }
   1.428 ++    else if (op >= 0xc0 && op <= 0xc5) {
   1.429 ++      // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7
   1.430 ++      edata.cmd = ARM_EXIDX_CMD_WREG_POP;
   1.431 ++      edata.data = 0xa0 | (op & 0x07);
   1.432 ++    }
   1.433 ++    else if (op == 0xc6) {
   1.434 ++      // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc]
   1.435 ++      edata.cmd = ARM_EXIDX_CMD_WREG_POP;
   1.436 ++      GET_BUF_U8(edata.data);
   1.437 ++    }
   1.438 ++    else if (op == 0xc7) {
   1.439 ++      uint8_t op2;
   1.440 ++      GET_BUF_U8(op2);
   1.441 ++      if (op2 == 0 || (op2 & 0xf0)) {
   1.442 ++        // Spare
   1.443 ++        edata.cmd = ARM_EXIDX_CMD_RESERVED;
   1.444 ++      } else {
   1.445 ++        // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
   1.446 ++        edata.cmd = ARM_EXIDX_CMD_WCGR_POP;
   1.447 ++        edata.data = op2 & 0x0f;
   1.448 ++      }
   1.449 ++    }
   1.450 ++    else {
   1.451 ++      // Spare
   1.452 ++      edata.cmd = ARM_EXIDX_CMD_RESERVED;
   1.453 ++    }
   1.454 ++
   1.455 ++    int ret = handler_->ImproveStackFrame(&edata);
   1.456 ++    if (ret < 0) return ret;
   1.457 ++  }
   1.458 ++  return 0;
   1.459 ++
   1.460 ++# undef GET_BUF_U8
   1.461 ++}
   1.462 ++
   1.463 ++void ExceptionTableInfo::Start()
   1.464 ++{
   1.465 ++  const struct exidx_entry* start
   1.466 ++    = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data());
   1.467 ++  const struct exidx_entry* end
   1.468 ++    = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()
   1.469 ++                                                  + mr_exidx_.length());
   1.470 ++
   1.471 ++  // Iterate over each of the EXIDX entries (pairs of 32-bit words).
   1.472 ++  // These occupy the entire .exidx section.
   1.473 ++  for (const struct exidx_entry* entry = start; entry < end; ++entry) {
   1.474 ++
   1.475 ++    // Figure out the code address range that this table entry is
   1.476 ++    // associated with.
   1.477 ++    uint32_t addr = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr))
   1.478 ++                     - mapping_addr_ + loading_addr_) & 0x7fffffff;
   1.479 ++    uint32_t next_addr;
   1.480 ++    if (entry < end - 1)
   1.481 ++      next_addr = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr)))
   1.482 ++                   - mapping_addr_ + loading_addr_) & 0x7fffffff;
   1.483 ++    else {
   1.484 ++      // This is the last EXIDX entry in the sequence, so we don't
   1.485 ++      // have an address for the start of the next function, to limit
   1.486 ++      // this one.  Instead use the address of the last byte of the
   1.487 ++      // text section associated with this .exidx section, that we
   1.488 ++      // have been given.  So as to avoid junking up the CFI unwind
   1.489 ++      // tables with absurdly large address ranges in the case where
   1.490 ++      // text_last_svma_ is wrong, only use the value if it is nonzero
   1.491 ++      // and within one page of |addr|.  Otherwise assume a length of 1.
   1.492 ++      //
   1.493 ++      // In some cases, gcc has been observed to finish the exidx
   1.494 ++      // section with an entry of length 1 marked CANT_UNWIND,
   1.495 ++      // presumably exactly for the purpose of giving a definite
   1.496 ++      // length for the last real entry, without having to look at
   1.497 ++      // text segment boundaries.
   1.498 ++      bool plausible = false;
   1.499 ++      next_addr = addr + 1;
   1.500 ++      if (text_last_svma_ != 0) {
   1.501 ++        uint32_t maybe_next_addr = text_last_svma_ + 1;
   1.502 ++        if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) {
   1.503 ++          next_addr = maybe_next_addr;
   1.504 ++          plausible = true;
   1.505 ++        }
   1.506 ++      }
   1.507 ++      if (!plausible)
   1.508 ++        BPLOG(INFO) << "ExceptionTableInfo: implausible EXIDX last entry size "
   1.509 ++                    << (int32_t)(text_last_svma_ - addr)
   1.510 ++                    << "; using 1 instead.";
   1.511 ++    }
   1.512 ++
   1.513 ++    // Extract the unwind info into |buf|.  This might fail for
   1.514 ++    // various reasons.  It involves reading both the .exidx and
   1.515 ++    // .extab sections.  All accesses to those sections are
   1.516 ++    // bounds-checked.
   1.517 ++    uint8_t buf[ARM_EXIDX_TABLE_LIMIT];
   1.518 ++    size_t buf_used = 0;
   1.519 ++    ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used);
   1.520 ++    if (res != ExSuccess) {
   1.521 ++      // Couldn't extract the unwind info, for some reason.  Move on.
   1.522 ++      switch (res) {
   1.523 ++        case ExInBufOverflow:
   1.524 ++          BPLOG(INFO) << "ExtabEntryExtract: .exidx/.extab section overrun";
   1.525 ++          break;
   1.526 ++        case ExOutBufOverflow:
   1.527 ++          BPLOG(INFO) << "ExtabEntryExtract: bytecode buffer overflow";
   1.528 ++          break;
   1.529 ++        case ExCantUnwind:
   1.530 ++          BPLOG(INFO) << "ExtabEntryExtract: function is marked CANT_UNWIND";
   1.531 ++          break;
   1.532 ++        case ExCantRepresent:
   1.533 ++          BPLOG(INFO) << "ExtabEntryExtract: bytecode can't be represented";
   1.534 ++          break;
   1.535 ++        case ExInvalid:
   1.536 ++          BPLOG(INFO) << "ExtabEntryExtract: index table entry is invalid";
   1.537 ++          break;
   1.538 ++        default:
   1.539 ++          BPLOG(INFO) << "ExtabEntryExtract: unknown error: " << (int)res;
   1.540 ++          break;
   1.541 ++      }
   1.542 ++      continue;
   1.543 ++    }
   1.544 ++
   1.545 ++    // Finally, work through the unwind instructions in |buf| and
   1.546 ++    // create CFI entries that Breakpad can use.  This can also fail.
   1.547 ++    // First, add a new stack frame entry, into which ExtabEntryDecode
   1.548 ++    // will write the CFI entries.
   1.549 ++    handler_->AddStackFrame(addr, next_addr - addr);
   1.550 ++    int ret = ExtabEntryDecode(buf, buf_used);
   1.551 ++    if (ret < 0) {
   1.552 ++      handler_->DeleteStackFrame();
   1.553 ++      BPLOG(INFO) << "ExtabEntryDecode: failed with error code: " << ret;
   1.554 ++      continue;
   1.555 ++    }
   1.556 ++    handler_->SubmitStackFrame();
   1.557 ++
   1.558 ++  } /* iterating over .exidx */
   1.559 ++}
   1.560 ++
   1.561 ++} // arm_ex_reader
   1.562 +diff --git a/src/common/arm_ex_reader.h b/src/common/arm_ex_reader.h
   1.563 +new file mode 100644
   1.564 +--- /dev/null
   1.565 ++++ b/src/common/arm_ex_reader.h
   1.566 +@@ -0,0 +1,115 @@
   1.567 ++
   1.568 ++/* libunwind - a platform-independent unwind library
   1.569 ++   Copyright 2011 Linaro Limited
   1.570 ++
   1.571 ++This file is part of libunwind.
   1.572 ++
   1.573 ++Permission is hereby granted, free of charge, to any person obtaining
   1.574 ++a copy of this software and associated documentation files (the
   1.575 ++"Software"), to deal in the Software without restriction, including
   1.576 ++without limitation the rights to use, copy, modify, merge, publish,
   1.577 ++distribute, sublicense, and/or sell copies of the Software, and to
   1.578 ++permit persons to whom the Software is furnished to do so, subject to
   1.579 ++the following conditions:
   1.580 ++
   1.581 ++The above copyright notice and this permission notice shall be
   1.582 ++included in all copies or substantial portions of the Software.
   1.583 ++
   1.584 ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   1.585 ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   1.586 ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   1.587 ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
   1.588 ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
   1.589 ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   1.590 ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
   1.591 ++
   1.592 ++// Copyright (c) 2010 Google Inc.
   1.593 ++// All rights reserved.
   1.594 ++//
   1.595 ++// Redistribution and use in source and binary forms, with or without
   1.596 ++// modification, are permitted provided that the following conditions are
   1.597 ++// met:
   1.598 ++//
   1.599 ++//     * Redistributions of source code must retain the above copyright
   1.600 ++// notice, this list of conditions and the following disclaimer.
   1.601 ++//     * Redistributions in binary form must reproduce the above
   1.602 ++// copyright notice, this list of conditions and the following disclaimer
   1.603 ++// in the documentation and/or other materials provided with the
   1.604 ++// distribution.
   1.605 ++//     * Neither the name of Google Inc. nor the names of its
   1.606 ++// contributors may be used to endorse or promote products derived from
   1.607 ++// this software without specific prior written permission.
   1.608 ++//
   1.609 ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   1.610 ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   1.611 ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   1.612 ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   1.613 ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   1.614 ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   1.615 ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   1.616 ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   1.617 ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   1.618 ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   1.619 ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.620 ++
   1.621 ++
   1.622 ++// Derived from libunwind, with extensive modifications.
   1.623 ++
   1.624 ++#ifndef COMMON_ARM_EX_READER_H__
   1.625 ++#define COMMON_ARM_EX_READER_H__
   1.626 ++
   1.627 ++#include "common/arm_ex_to_module.h"
   1.628 ++#include "common/memory_range.h"
   1.629 ++
   1.630 ++namespace arm_ex_reader {
   1.631 ++
   1.632 ++// This class is a reader for ARM unwind information
   1.633 ++// from .ARM.exidx and .ARM.extab sections.
   1.634 ++class ExceptionTableInfo {
   1.635 ++ public:
   1.636 ++  ExceptionTableInfo(const char* exidx, size_t exidx_size,
   1.637 ++                     const char* extab, size_t extab_size,
   1.638 ++                     uint32_t text_last_svma,
   1.639 ++                     arm_ex_to_module::ARMExToModule* handler,
   1.640 ++                     const char* mapping_addr,
   1.641 ++                     uint32_t loading_addr)
   1.642 ++      : mr_exidx_(google_breakpad::MemoryRange(exidx, exidx_size)),
   1.643 ++        mr_extab_(google_breakpad::MemoryRange(extab, extab_size)),
   1.644 ++        text_last_svma_(text_last_svma),
   1.645 ++        handler_(handler), mapping_addr_(mapping_addr),
   1.646 ++        loading_addr_(loading_addr) { }
   1.647 ++
   1.648 ++  ~ExceptionTableInfo() { }
   1.649 ++
   1.650 ++  // Parses the entries in .ARM.exidx and possibly
   1.651 ++  // in .ARM.extab tables, reports what we find to
   1.652 ++  // arm_ex_to_module::ARMExToModule.
   1.653 ++  void Start();
   1.654 ++
   1.655 ++ private:
   1.656 ++  google_breakpad::MemoryRange mr_exidx_;
   1.657 ++  google_breakpad::MemoryRange mr_extab_;
   1.658 ++  uint32_t text_last_svma_;
   1.659 ++  arm_ex_to_module::ARMExToModule* handler_;
   1.660 ++  const char* mapping_addr_;
   1.661 ++  uint32_t loading_addr_;
   1.662 ++
   1.663 ++  enum ExExtractResult {
   1.664 ++    ExSuccess,        // success
   1.665 ++    ExInBufOverflow,  // out-of-range while reading .exidx
   1.666 ++    ExOutBufOverflow, // output buffer is too small
   1.667 ++    ExCantUnwind,     // this function is marked CANT_UNWIND
   1.668 ++    ExCantRepresent,  // entry valid, but we can't represent it
   1.669 ++    ExInvalid         // entry is invalid
   1.670 ++  };
   1.671 ++  ExExtractResult
   1.672 ++    ExtabEntryExtract(const struct arm_ex_to_module::exidx_entry* entry,
   1.673 ++                      uint8_t* buf, size_t buf_size,
   1.674 ++                      /*OUT*/size_t* buf_used);
   1.675 ++
   1.676 ++  int ExtabEntryDecode(const uint8_t* buf, size_t buf_size);
   1.677 ++};
   1.678 ++
   1.679 ++} // namespace arm_ex_reader
   1.680 ++
   1.681 ++#endif // COMMON_ARM_EX_READER_H__
   1.682 +diff --git a/src/common/arm_ex_to_module.cc b/src/common/arm_ex_to_module.cc
   1.683 +new file mode 100644
   1.684 +--- /dev/null
   1.685 ++++ b/src/common/arm_ex_to_module.cc
   1.686 +@@ -0,0 +1,206 @@
   1.687 ++
   1.688 ++/* libunwind - a platform-independent unwind library
   1.689 ++   Copyright 2011 Linaro Limited
   1.690 ++
   1.691 ++This file is part of libunwind.
   1.692 ++
   1.693 ++Permission is hereby granted, free of charge, to any person obtaining
   1.694 ++a copy of this software and associated documentation files (the
   1.695 ++"Software"), to deal in the Software without restriction, including
   1.696 ++without limitation the rights to use, copy, modify, merge, publish,
   1.697 ++distribute, sublicense, and/or sell copies of the Software, and to
   1.698 ++permit persons to whom the Software is furnished to do so, subject to
   1.699 ++the following conditions:
   1.700 ++
   1.701 ++The above copyright notice and this permission notice shall be
   1.702 ++included in all copies or substantial portions of the Software.
   1.703 ++
   1.704 ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   1.705 ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   1.706 ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   1.707 ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
   1.708 ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
   1.709 ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   1.710 ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
   1.711 ++
   1.712 ++// Copyright (c) 2010 Google Inc.
   1.713 ++// All rights reserved.
   1.714 ++//
   1.715 ++// Redistribution and use in source and binary forms, with or without
   1.716 ++// modification, are permitted provided that the following conditions are
   1.717 ++// met:
   1.718 ++//
   1.719 ++//     * Redistributions of source code must retain the above copyright
   1.720 ++// notice, this list of conditions and the following disclaimer.
   1.721 ++//     * Redistributions in binary form must reproduce the above
   1.722 ++// copyright notice, this list of conditions and the following disclaimer
   1.723 ++// in the documentation and/or other materials provided with the
   1.724 ++// distribution.
   1.725 ++//     * Neither the name of Google Inc. nor the names of its
   1.726 ++// contributors may be used to endorse or promote products derived from
   1.727 ++// this software without specific prior written permission.
   1.728 ++//
   1.729 ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   1.730 ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   1.731 ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   1.732 ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   1.733 ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   1.734 ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   1.735 ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   1.736 ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   1.737 ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   1.738 ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   1.739 ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.740 ++
   1.741 ++
   1.742 ++// Derived from libunwind, with extensive modifications.
   1.743 ++
   1.744 ++#include "common/unique_string.h"
   1.745 ++#include "common/arm_ex_to_module.h"
   1.746 ++
   1.747 ++#include <stdio.h>
   1.748 ++#include <assert.h>
   1.749 ++
   1.750 ++// For big-picture comments on how the EXIDX reader works, 
   1.751 ++// see arm_ex_reader.cc.
   1.752 ++
   1.753 ++#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
   1.754 ++#define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
   1.755 ++#define ARM_EXBUF_END(x)   (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
   1.756 ++
   1.757 ++using google_breakpad::ustr__pc;
   1.758 ++using google_breakpad::ustr__lr;
   1.759 ++using google_breakpad::ustr__sp;
   1.760 ++using google_breakpad::Module;
   1.761 ++using google_breakpad::ToUniqueString;
   1.762 ++using google_breakpad::UniqueString;
   1.763 ++
   1.764 ++namespace arm_ex_to_module {
   1.765 ++
   1.766 ++// Translate command from extab_data to command for Module.
   1.767 ++int ARMExToModule::TranslateCmd(const struct extab_data* edata,
   1.768 ++                                Module::StackFrameEntry* entry, string& vsp) {
   1.769 ++  int ret = 0;
   1.770 ++  switch (edata->cmd) {
   1.771 ++    case ARM_EXIDX_CMD_FINISH:
   1.772 ++      /* Copy LR to PC if there isn't currently a rule for PC in force. */
   1.773 ++      if (entry->initial_rules.find(ustr__pc())
   1.774 ++          == entry->initial_rules.end()) {
   1.775 ++        if (entry->initial_rules.find(ustr__lr())
   1.776 ++            == entry->initial_rules.end()) {
   1.777 ++          entry->initial_rules[ustr__pc()] = Module::Expr("lr");
   1.778 ++        } else {
   1.779 ++          entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()];
   1.780 ++        }
   1.781 ++      }
   1.782 ++      break;
   1.783 ++    case ARM_EXIDX_CMD_SUB_FROM_VSP:
   1.784 ++      {
   1.785 ++        char c[16];
   1.786 ++        sprintf(c, " %d -", edata->data);
   1.787 ++        vsp += c;
   1.788 ++      }
   1.789 ++      break;
   1.790 ++    case ARM_EXIDX_CMD_ADD_TO_VSP:
   1.791 ++      {
   1.792 ++        char c[16];
   1.793 ++        sprintf(c, " %d +", edata->data);
   1.794 ++        vsp += c;
   1.795 ++      }
   1.796 ++      break;
   1.797 ++    case ARM_EXIDX_CMD_REG_POP:
   1.798 ++      for (unsigned int i = 0; i < 16; i++) {
   1.799 ++        if (edata->data & (1 << i)) {
   1.800 ++          entry->initial_rules[ToUniqueString(regnames[i])]
   1.801 ++            = Module::Expr(vsp + " ^");
   1.802 ++          vsp += " 4 +";
   1.803 ++        }
   1.804 ++      }
   1.805 ++      /* Set cfa in case the SP got popped. */
   1.806 ++      if (edata->data & (1 << 13)) {
   1.807 ++        Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()];
   1.808 ++        // It must be a postfix expression (we don't generate anything
   1.809 ++        // else here), so return -1 to fail out if it isn't.
   1.810 ++        if (!vsp_expr.isExprPostfix()) {
   1.811 ++          ret = -1;
   1.812 ++          break;
   1.813 ++        };
   1.814 ++        vsp = vsp_expr.getExprPostfix();
   1.815 ++      }
   1.816 ++      break;
   1.817 ++    case ARM_EXIDX_CMD_REG_TO_SP: {
   1.818 ++      assert (edata->data < 16);
   1.819 ++      const char* const regname = regnames[edata->data];
   1.820 ++      const UniqueString* regname_us = ToUniqueString(regname);
   1.821 ++      if (entry->initial_rules.find(regname_us) == entry->initial_rules.end()) {
   1.822 ++        entry->initial_rules[ustr__sp()] = Module::Expr(regname);
   1.823 ++      } else {
   1.824 ++        entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us];
   1.825 ++      }
   1.826 ++      Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()];
   1.827 ++      if (!vsp_expr.isExprPostfix()) {
   1.828 ++        ret = -1;
   1.829 ++        break;
   1.830 ++      };
   1.831 ++      vsp = vsp_expr.getExprPostfix();
   1.832 ++      break;
   1.833 ++    }
   1.834 ++    case ARM_EXIDX_CMD_VFP_POP:
   1.835 ++      /* Don't recover VFP registers, but be sure to adjust the stack
   1.836 ++         pointer. */
   1.837 ++      for (unsigned int i = ARM_EXBUF_START(edata->data);
   1.838 ++           i <= ARM_EXBUF_END(edata->data); i++) {
   1.839 ++        vsp += " 8 +";
   1.840 ++      }
   1.841 ++      if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
   1.842 ++        vsp += " 4 +";
   1.843 ++      }
   1.844 ++      break;
   1.845 ++    case ARM_EXIDX_CMD_WREG_POP:
   1.846 ++      for (unsigned int i = ARM_EXBUF_START(edata->data);
   1.847 ++           i <= ARM_EXBUF_END(edata->data); i++) {
   1.848 ++        vsp += " 8 +";
   1.849 ++      }
   1.850 ++      break;
   1.851 ++    case ARM_EXIDX_CMD_WCGR_POP:
   1.852 ++      // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
   1.853 ++      for (unsigned int i = 0; i < 4; i++) {
   1.854 ++        if (edata->data & (1 << i)) {
   1.855 ++          vsp += " 4 +";
   1.856 ++        }
   1.857 ++      }
   1.858 ++      break;
   1.859 ++    case ARM_EXIDX_CMD_REFUSED:
   1.860 ++    case ARM_EXIDX_CMD_RESERVED:
   1.861 ++      ret = -1;
   1.862 ++      break;
   1.863 ++  }
   1.864 ++  return ret;
   1.865 ++}
   1.866 ++
   1.867 ++void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) {
   1.868 ++  stack_frame_entry_ = new Module::StackFrameEntry;
   1.869 ++  stack_frame_entry_->address = addr;
   1.870 ++  stack_frame_entry_->size = size;
   1.871 ++  stack_frame_entry_->initial_rules[ToUniqueString(kCFA)] = Module::Expr("sp");
   1.872 ++  vsp_ = "sp";
   1.873 ++}
   1.874 ++
   1.875 ++int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) {
   1.876 ++  return TranslateCmd(edata, stack_frame_entry_, vsp_) ;
   1.877 ++}
   1.878 ++
   1.879 ++void ARMExToModule::DeleteStackFrame() {
   1.880 ++  delete stack_frame_entry_;
   1.881 ++}
   1.882 ++
   1.883 ++void ARMExToModule::SubmitStackFrame() {
   1.884 ++  // return address always winds up in pc
   1.885 ++  stack_frame_entry_->initial_rules[ToUniqueString(kRA)]
   1.886 ++    = stack_frame_entry_->initial_rules[ustr__pc()];
   1.887 ++  // the final value of vsp is the new value of sp
   1.888 ++  stack_frame_entry_->initial_rules[ustr__sp()] = vsp_;
   1.889 ++  module_->AddStackFrameEntry(stack_frame_entry_);
   1.890 ++}
   1.891 ++
   1.892 ++} // namespace arm_ex_to_module
   1.893 +diff --git a/src/common/arm_ex_to_module.h b/src/common/arm_ex_to_module.h
   1.894 +new file mode 100644
   1.895 +--- /dev/null
   1.896 ++++ b/src/common/arm_ex_to_module.h
   1.897 +@@ -0,0 +1,129 @@
   1.898 ++
   1.899 ++/* libunwind - a platform-independent unwind library
   1.900 ++   Copyright 2011 Linaro Limited
   1.901 ++
   1.902 ++This file is part of libunwind.
   1.903 ++
   1.904 ++Permission is hereby granted, free of charge, to any person obtaining
   1.905 ++a copy of this software and associated documentation files (the
   1.906 ++"Software"), to deal in the Software without restriction, including
   1.907 ++without limitation the rights to use, copy, modify, merge, publish,
   1.908 ++distribute, sublicense, and/or sell copies of the Software, and to
   1.909 ++permit persons to whom the Software is furnished to do so, subject to
   1.910 ++the following conditions:
   1.911 ++
   1.912 ++The above copyright notice and this permission notice shall be
   1.913 ++included in all copies or substantial portions of the Software.
   1.914 ++
   1.915 ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   1.916 ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   1.917 ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   1.918 ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
   1.919 ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
   1.920 ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   1.921 ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
   1.922 ++
   1.923 ++// Copyright (c) 2010 Google Inc.
   1.924 ++// All rights reserved.
   1.925 ++//
   1.926 ++// Redistribution and use in source and binary forms, with or without
   1.927 ++// modification, are permitted provided that the following conditions are
   1.928 ++// met:
   1.929 ++//
   1.930 ++//     * Redistributions of source code must retain the above copyright
   1.931 ++// notice, this list of conditions and the following disclaimer.
   1.932 ++//     * Redistributions in binary form must reproduce the above
   1.933 ++// copyright notice, this list of conditions and the following disclaimer
   1.934 ++// in the documentation and/or other materials provided with the
   1.935 ++// distribution.
   1.936 ++//     * Neither the name of Google Inc. nor the names of its
   1.937 ++// contributors may be used to endorse or promote products derived from
   1.938 ++// this software without specific prior written permission.
   1.939 ++//
   1.940 ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   1.941 ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   1.942 ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   1.943 ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   1.944 ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   1.945 ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   1.946 ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   1.947 ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   1.948 ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   1.949 ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   1.950 ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.951 ++
   1.952 ++
   1.953 ++// Derived from libunwind, with extensive modifications.
   1.954 ++
   1.955 ++#ifndef COMMON_ARM_EX_TO_MODULE__
   1.956 ++#define COMMON_ARM_EX_TO_MODULE__
   1.957 ++
   1.958 ++#include "common/module.h"
   1.959 ++
   1.960 ++#include <string.h>
   1.961 ++
   1.962 ++namespace arm_ex_to_module {
   1.963 ++
   1.964 ++using google_breakpad::Module;
   1.965 ++
   1.966 ++typedef enum extab_cmd {
   1.967 ++  ARM_EXIDX_CMD_FINISH,
   1.968 ++  ARM_EXIDX_CMD_SUB_FROM_VSP,
   1.969 ++  ARM_EXIDX_CMD_ADD_TO_VSP,
   1.970 ++  ARM_EXIDX_CMD_REG_POP,
   1.971 ++  ARM_EXIDX_CMD_REG_TO_SP,
   1.972 ++  ARM_EXIDX_CMD_VFP_POP,
   1.973 ++  ARM_EXIDX_CMD_WREG_POP,
   1.974 ++  ARM_EXIDX_CMD_WCGR_POP,
   1.975 ++  ARM_EXIDX_CMD_RESERVED,
   1.976 ++  ARM_EXIDX_CMD_REFUSED,
   1.977 ++} extab_cmd_t;
   1.978 ++
   1.979 ++struct exidx_entry {
   1.980 ++  uint32_t addr;
   1.981 ++  uint32_t data;
   1.982 ++};
   1.983 ++
   1.984 ++struct extab_data {
   1.985 ++  extab_cmd_t cmd;
   1.986 ++  uint32_t data;
   1.987 ++};
   1.988 ++
   1.989 ++enum extab_cmd_flags {
   1.990 ++  ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
   1.991 ++  ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX
   1.992 ++};
   1.993 ++
   1.994 ++const string kRA = ".ra";
   1.995 ++const string kCFA = ".cfa";
   1.996 ++
   1.997 ++static const char* const regnames[] = {
   1.998 ++ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
   1.999 ++ "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
  1.1000 ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
  1.1001 ++ "fps", "cpsr"
  1.1002 ++};
  1.1003 ++
  1.1004 ++// Receives information from arm_ex_reader::ExceptionTableInfo
  1.1005 ++// and adds it to the Module object
  1.1006 ++class ARMExToModule {
  1.1007 ++ public:
  1.1008 ++  ARMExToModule(Module* module)
  1.1009 ++      : module_(module) { }
  1.1010 ++  ~ARMExToModule() { }
  1.1011 ++  void AddStackFrame(uintptr_t addr, size_t size);
  1.1012 ++  int ImproveStackFrame(const struct extab_data* edata);
  1.1013 ++  void DeleteStackFrame();
  1.1014 ++  void SubmitStackFrame();
  1.1015 ++ private:
  1.1016 ++  Module* module_;
  1.1017 ++  Module::StackFrameEntry* stack_frame_entry_;
  1.1018 ++  string vsp_;
  1.1019 ++  int TranslateCmd(const struct extab_data* edata,
  1.1020 ++                   Module::StackFrameEntry* entry,
  1.1021 ++                   string& vsp);
  1.1022 ++};
  1.1023 ++
  1.1024 ++} // namespace arm_ex_to_module
  1.1025 ++
  1.1026 ++#endif // COMMON_ARM_EX_TO_MODULE__
  1.1027 +diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
  1.1028 +--- a/src/common/linux/dump_symbols.cc
  1.1029 ++++ b/src/common/linux/dump_symbols.cc
  1.1030 +@@ -47,16 +47,17 @@
  1.1031 + #include <unistd.h>
  1.1032 + 
  1.1033 + #include <iostream>
  1.1034 + #include <set>
  1.1035 + #include <string>
  1.1036 + #include <utility>
  1.1037 + #include <vector>
  1.1038 + 
  1.1039 ++#include "common/arm_ex_reader.h"
  1.1040 + #include "common/dwarf/bytereader-inl.h"
  1.1041 + #include "common/dwarf/dwarf2diehandler.h"
  1.1042 + #include "common/dwarf_cfi_to_module.h"
  1.1043 + #include "common/dwarf_cu_to_module.h"
  1.1044 + #include "common/dwarf_line_to_module.h"
  1.1045 + #include "common/linux/elfutils.h"
  1.1046 + #include "common/linux/elfutils-inl.h"
  1.1047 + #include "common/linux/elf_symbols_to_module.h"
  1.1048 +@@ -65,16 +66,20 @@
  1.1049 + #include "common/scoped_ptr.h"
  1.1050 + #ifndef NO_STABS_SUPPORT
  1.1051 + #include "common/stabs_reader.h"
  1.1052 + #include "common/stabs_to_module.h"
  1.1053 + #endif
  1.1054 + #include "common/using_std_string.h"
  1.1055 + #include "common/logging.h"
  1.1056 + 
  1.1057 ++#if defined(__ANDROID__) && !defined(SHT_ARM_EXIDX)
  1.1058 ++# define SHT_ARM_EXIDX (SHT_LOPROC + 1)
  1.1059 ++#endif
  1.1060 ++
  1.1061 + // This namespace contains helper functions.
  1.1062 + namespace {
  1.1063 + 
  1.1064 + using google_breakpad::DwarfCFIToModule;
  1.1065 + using google_breakpad::DwarfCUToModule;
  1.1066 + using google_breakpad::DwarfLineToModule;
  1.1067 + using google_breakpad::ElfClass;
  1.1068 + using google_breakpad::ElfClass32;
  1.1069 +@@ -340,16 +345,62 @@ bool LoadDwarfCFI(const string& dwarf_fi
  1.1070 +                                                        section_name);
  1.1071 +   dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
  1.1072 +                                      &byte_reader, &handler, &dwarf_reporter,
  1.1073 +                                      eh_frame);
  1.1074 +   parser.Start();
  1.1075 +   return true;
  1.1076 + }
  1.1077 + 
  1.1078 ++template<typename ElfClass>
  1.1079 ++bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header,
  1.1080 ++                  const typename ElfClass::Shdr* exidx_section,
  1.1081 ++                  const typename ElfClass::Shdr* extab_section,
  1.1082 ++                  uint32_t loading_addr,
  1.1083 ++                  Module* module) {
  1.1084 ++  // To do this properly we need to know:
  1.1085 ++  // * the bounds of the .ARM.exidx section in the mapped image
  1.1086 ++  // * the bounds of the .ARM.extab section in the mapped image
  1.1087 ++  // * the vma of the last byte in the text section associated with the .exidx
  1.1088 ++  // The first two are easy.  The third is a bit tricky.  If we can't
  1.1089 ++  // figure out what it is, just pass in zero.
  1.1090 ++  const char *exidx_img
  1.1091 ++    = GetOffset<ElfClass, char>(elf_header, exidx_section->sh_offset);
  1.1092 ++  size_t exidx_size = exidx_section->sh_size;
  1.1093 ++  const char *extab_img
  1.1094 ++    = GetOffset<ElfClass, char>(elf_header, extab_section->sh_offset);
  1.1095 ++  size_t extab_size = extab_section->sh_size;
  1.1096 ++
  1.1097 ++  // The sh_link field of the exidx section gives the section number
  1.1098 ++  // for the associated text section.
  1.1099 ++  uint32_t exidx_text_last_svma = 0;
  1.1100 ++  int exidx_text_sno = exidx_section->sh_link;
  1.1101 ++  typedef typename ElfClass::Shdr Shdr;
  1.1102 ++  // |sections| points to the section header table
  1.1103 ++  const Shdr* sections
  1.1104 ++    = GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
  1.1105 ++  const int num_sections = elf_header->e_shnum;
  1.1106 ++  if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) {
  1.1107 ++    const Shdr* exidx_text_shdr = &sections[exidx_text_sno];
  1.1108 ++    if (exidx_text_shdr->sh_size > 0) {
  1.1109 ++      exidx_text_last_svma
  1.1110 ++        = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1;
  1.1111 ++    }
  1.1112 ++  }
  1.1113 ++
  1.1114 ++  arm_ex_to_module::ARMExToModule handler(module);
  1.1115 ++  arm_ex_reader::ExceptionTableInfo
  1.1116 ++    parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma,
  1.1117 ++           &handler,
  1.1118 ++           reinterpret_cast<const char*>(elf_header),
  1.1119 ++           loading_addr);
  1.1120 ++  parser.Start();
  1.1121 ++  return true;
  1.1122 ++}
  1.1123 ++
  1.1124 + bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper,
  1.1125 +              void** elf_header) {
  1.1126 +   int obj_fd = open(obj_file.c_str(), O_RDONLY);
  1.1127 +   if (obj_fd < 0) {
  1.1128 +     fprintf(stderr, "Failed to open ELF file '%s': %s\n",
  1.1129 +             obj_file.c_str(), strerror(errno));
  1.1130 +     return false;
  1.1131 +   }
  1.1132 +@@ -629,16 +680,39 @@ bool LoadSymbols(const string& obj_file,
  1.1133 +                                  eh_frame_section, true,
  1.1134 +                                  got_section, text_section, big_endian, module);
  1.1135 +       found_usable_info = found_usable_info || result;
  1.1136 +       if (result)
  1.1137 +         BPLOG(INFO) << "LoadSymbols:   read CFI from .eh_frame";
  1.1138 +     }
  1.1139 +   }
  1.1140 + 
  1.1141 ++  // ARM has special unwind tables that can be used.
  1.1142 ++  const Shdr* arm_exidx_section =
  1.1143 ++      FindElfSectionByName<ElfClass>(".ARM.exidx", SHT_ARM_EXIDX,
  1.1144 ++                                     sections, names, names_end,
  1.1145 ++                                     elf_header->e_shnum);
  1.1146 ++  const Shdr* arm_extab_section =
  1.1147 ++      FindElfSectionByName<ElfClass>(".ARM.extab", SHT_PROGBITS,
  1.1148 ++                                     sections, names, names_end,
  1.1149 ++                                     elf_header->e_shnum);
  1.1150 ++  // Only load information from this section if there isn't a .debug_info
  1.1151 ++  // section.
  1.1152 ++  if (!found_debug_info_section
  1.1153 ++      && arm_exidx_section && arm_extab_section && symbol_data != NO_CFI) {
  1.1154 ++    info->LoadedSection(".ARM.exidx");
  1.1155 ++    info->LoadedSection(".ARM.extab");
  1.1156 ++    bool result = LoadARMexidx<ElfClass>(elf_header,
  1.1157 ++                                         arm_exidx_section, arm_extab_section,
  1.1158 ++                                         loading_addr, module);
  1.1159 ++    found_usable_info = found_usable_info || result;
  1.1160 ++    if (result)
  1.1161 ++      BPLOG(INFO) << "LoadSymbols:   read EXIDX from .ARM.{exidx,extab}";
  1.1162 ++  }
  1.1163 ++
  1.1164 +   if (!found_debug_info_section && symbol_data != ONLY_CFI) {
  1.1165 +     fprintf(stderr, "%s: file contains no debugging information"
  1.1166 +             " (no \".stab\" or \".debug_info\" sections)\n",
  1.1167 +             obj_file.c_str());
  1.1168 + 
  1.1169 +     // Failed, but maybe there's a .gnu_debuglink section?
  1.1170 +     if (read_gnu_debug_link) {
  1.1171 +       const Shdr* gnu_debuglink_section
  1.1172 +diff --git a/src/common/module.cc b/src/common/module.cc
  1.1173 +--- a/src/common/module.cc
  1.1174 ++++ b/src/common/module.cc
  1.1175 +@@ -253,17 +253,17 @@ void Module::AssignSourceIds() {
  1.1176 + 
  1.1177 + bool Module::ReportError() {
  1.1178 +   fprintf(stderr, "error writing symbol file: %s\n",
  1.1179 +           strerror(errno));
  1.1180 +   return false;
  1.1181 + }
  1.1182 + 
  1.1183 + std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) {
  1.1184 +-  assert(!expr.invalid());
  1.1185 ++  assert(!expr.isExprInvalid());
  1.1186 +   switch (expr.how_) {
  1.1187 +     case Module::kExprSimple:
  1.1188 +       stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " +";
  1.1189 +       break;
  1.1190 +     case Module::kExprSimpleMem:
  1.1191 +       stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " + ^";
  1.1192 +       break;
  1.1193 +     case Module::kExprPostfix:
  1.1194 +diff --git a/src/common/module.h b/src/common/module.h
  1.1195 +--- a/src/common/module.h
  1.1196 ++++ b/src/common/module.h
  1.1197 +@@ -160,17 +160,24 @@ class Module {
  1.1198 +     }
  1.1199 +     // Construct an invalid expression
  1.1200 +     Expr() {
  1.1201 +       postfix_ = "";
  1.1202 +       ident_ = NULL;
  1.1203 +       offset_ = 0;
  1.1204 +       how_ = kExprInvalid;
  1.1205 +     }
  1.1206 +-    bool invalid() const { return how_ == kExprInvalid; }
  1.1207 ++    bool isExprInvalid() const { return how_ == kExprInvalid; }
  1.1208 ++    bool isExprPostfix() const { return how_ == kExprPostfix; }
  1.1209 ++
  1.1210 ++    // Return the postfix expression string.  This is only
  1.1211 ++    // meaningful on Exprs for which isExprPostfix returns true.
  1.1212 ++    // In all other cases it returns an empty string.
  1.1213 ++    string getExprPostfix() const { return postfix_; }
  1.1214 ++
  1.1215 +     bool operator==(const Expr& other) const {
  1.1216 +       return how_ == other.how_ &&
  1.1217 +           ident_ == other.ident_ &&
  1.1218 +           offset_ == other.offset_ &&
  1.1219 +           postfix_ == other.postfix_;
  1.1220 +     }
  1.1221 + 
  1.1222 +     // The identifier that gives the starting value for simple expressions.
  1.1223 +diff --git a/src/common/unique_string.h b/src/common/unique_string.h
  1.1224 +--- a/src/common/unique_string.h
  1.1225 ++++ b/src/common/unique_string.h
  1.1226 +@@ -230,16 +230,37 @@ inline static const UniqueString* ustr__
  1.1227 + 
  1.1228 + // ".ra"
  1.1229 + inline static const UniqueString* ustr__ZDra() {
  1.1230 +   static const UniqueString* us = NULL;
  1.1231 +   if (!us) us = ToUniqueString(".ra");
  1.1232 +   return us;
  1.1233 + }
  1.1234 + 
  1.1235 ++// "pc"
  1.1236 ++inline static const UniqueString* ustr__pc() {
  1.1237 ++  static const UniqueString* us = NULL;
  1.1238 ++  if (!us) us = ToUniqueString("pc");
  1.1239 ++  return us;
  1.1240 ++}
  1.1241 ++
  1.1242 ++// "lr"
  1.1243 ++inline static const UniqueString* ustr__lr() {
  1.1244 ++  static const UniqueString* us = NULL;
  1.1245 ++  if (!us) us = ToUniqueString("lr");
  1.1246 ++  return us;
  1.1247 ++}
  1.1248 ++
  1.1249 ++// "sp"
  1.1250 ++inline static const UniqueString* ustr__sp() {
  1.1251 ++  static const UniqueString* us = NULL;
  1.1252 ++  if (!us) us = ToUniqueString("sp");
  1.1253 ++  return us;
  1.1254 ++}
  1.1255 ++
  1.1256 + template <typename ValueType>
  1.1257 + class UniqueStringMap
  1.1258 + {
  1.1259 +  private:
  1.1260 +   static const int N_FIXED = 10;
  1.1261 + 
  1.1262 +  public:
  1.1263 +   UniqueStringMap() : n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0) {};
  1.1264 +diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
  1.1265 +--- a/src/processor/cfi_frame_info.cc
  1.1266 ++++ b/src/processor/cfi_frame_info.cc
  1.1267 +@@ -49,17 +49,17 @@ namespace google_breakpad {
  1.1268 + #endif
  1.1269 + 
  1.1270 + template<typename V>
  1.1271 + bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
  1.1272 +                                   const MemoryRegion &memory,
  1.1273 +                                   RegisterValueMap<V> *caller_registers) const {
  1.1274 +   // If there are not rules for both .ra and .cfa in effect at this address,
  1.1275 +   // don't use this CFI data for stack walking.
  1.1276 +-  if (cfa_rule_.invalid() || ra_rule_.invalid())
  1.1277 ++  if (cfa_rule_.isExprInvalid() || ra_rule_.isExprInvalid())
  1.1278 +     return false;
  1.1279 + 
  1.1280 +   RegisterValueMap<V> working;
  1.1281 +   PostfixEvaluator<V> evaluator(&working, &memory);
  1.1282 + 
  1.1283 +   caller_registers->clear();
  1.1284 + 
  1.1285 +   // First, compute the CFA.
  1.1286 +@@ -100,20 +100,20 @@ template bool CFIFrameInfo::FindCallerRe
  1.1287 + template bool CFIFrameInfo::FindCallerRegs<uint64_t>(
  1.1288 +     const RegisterValueMap<uint64_t> &registers,
  1.1289 +     const MemoryRegion &memory,
  1.1290 +     RegisterValueMap<uint64_t> *caller_registers) const;
  1.1291 + 
  1.1292 + string CFIFrameInfo::Serialize() const {
  1.1293 +   std::ostringstream stream;
  1.1294 + 
  1.1295 +-  if (!cfa_rule_.invalid()) {
  1.1296 ++  if (!cfa_rule_.isExprInvalid()) {
  1.1297 +     stream << ".cfa: " << cfa_rule_;
  1.1298 +   }
  1.1299 +-  if (!ra_rule_.invalid()) {
  1.1300 ++  if (!ra_rule_.isExprInvalid()) {
  1.1301 +     if (static_cast<std::streamoff>(stream.tellp()) != 0)
  1.1302 +       stream << " ";
  1.1303 +     stream << ".ra: " << ra_rule_;
  1.1304 +   }
  1.1305 + 
  1.1306 +   // Visit the register rules in alphabetical order.  Because
  1.1307 +   // register_rules_ has the elements in some arbitrary order,
  1.1308 +   // get the names out into a vector, sort them, and visit in

mercurial