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 = §ions[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> ®isters, 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> ®isters, 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