toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2452 @@
     1.4 +// Copyright (c) 2010, Google Inc.
     1.5 +// All rights reserved.
     1.6 +//
     1.7 +// Redistribution and use in source and binary forms, with or without
     1.8 +// modification, are permitted provided that the following conditions are
     1.9 +// met:
    1.10 +//
    1.11 +//     * Redistributions of source code must retain the above copyright
    1.12 +// notice, this list of conditions and the following disclaimer.
    1.13 +//     * Redistributions in binary form must reproduce the above
    1.14 +// copyright notice, this list of conditions and the following disclaimer
    1.15 +// in the documentation and/or other materials provided with the
    1.16 +// distribution.
    1.17 +//     * Neither the name of Google Inc. nor the names of its
    1.18 +// contributors may be used to endorse or promote products derived from
    1.19 +// this software without specific prior written permission.
    1.20 +//
    1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.32 +
    1.33 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
    1.34 +
    1.35 +// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo
    1.36 +
    1.37 +#include <stdlib.h>
    1.38 +
    1.39 +#include <string>
    1.40 +#include <vector>
    1.41 +
    1.42 +// The '.eh_frame' format, used by the Linux C++ ABI for exception
    1.43 +// handling, is poorly specified. To help test our support for .eh_frame,
    1.44 +// if you #define WRITE_ELF while compiling this file, and add the
    1.45 +// 'include' directory from the binutils, gcc, or gdb source tree to the
    1.46 +// #include path, then each test that calls the
    1.47 +// PERHAPS_WRITE_DEBUG_FRAME_FILE or PERHAPS_WRITE_EH_FRAME_FILE will write
    1.48 +// an ELF file containing a .debug_frame or .eh_frame section; you can then
    1.49 +// use tools like readelf to examine the test data, and check the tools'
    1.50 +// interpretation against the test's intentions. Each ELF file is named
    1.51 +// "cfitest-TEST", where TEST identifies the particular test.
    1.52 +#ifdef WRITE_ELF
    1.53 +#include <errno.h>
    1.54 +#include <stdio.h>
    1.55 +#include <string.h>
    1.56 +extern "C" {
    1.57 +// To compile with WRITE_ELF, you should add the 'include' directory
    1.58 +// of the binutils, gcc, or gdb source tree to your #include path;
    1.59 +// that directory contains this header.
    1.60 +#include "elf/common.h"
    1.61 +}
    1.62 +#endif
    1.63 +
    1.64 +#include "breakpad_googletest_includes.h"
    1.65 +#include "common/dwarf/bytereader-inl.h"
    1.66 +#include "common/dwarf/cfi_assembler.h"
    1.67 +#include "common/dwarf/dwarf2reader.h"
    1.68 +#include "common/using_std_string.h"
    1.69 +#include "google_breakpad/common/breakpad_types.h"
    1.70 +
    1.71 +using google_breakpad::CFISection;
    1.72 +using google_breakpad::test_assembler::Label;
    1.73 +using google_breakpad::test_assembler::kBigEndian;
    1.74 +using google_breakpad::test_assembler::kLittleEndian;
    1.75 +using google_breakpad::test_assembler::Section;
    1.76 +
    1.77 +using dwarf2reader::DwarfPointerEncoding;
    1.78 +using dwarf2reader::ENDIANNESS_BIG;
    1.79 +using dwarf2reader::ENDIANNESS_LITTLE;
    1.80 +using dwarf2reader::ByteReader;
    1.81 +using dwarf2reader::CallFrameInfo;
    1.82 +
    1.83 +using std::vector;
    1.84 +using testing::InSequence;
    1.85 +using testing::Return;
    1.86 +using testing::Sequence;
    1.87 +using testing::Test;
    1.88 +using testing::_;
    1.89 +
    1.90 +#ifdef WRITE_ELF
    1.91 +void WriteELFFrameSection(const char *filename, const char *section_name,
    1.92 +                          const CFISection &section);
    1.93 +#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section)                   \
    1.94 +    WriteELFFrameSection("cfitest-" name, ".debug_frame", section);
    1.95 +#define PERHAPS_WRITE_EH_FRAME_FILE(name, section)                      \
    1.96 +    WriteELFFrameSection("cfitest-" name, ".eh_frame", section);
    1.97 +#else
    1.98 +#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section)
    1.99 +#define PERHAPS_WRITE_EH_FRAME_FILE(name, section)
   1.100 +#endif
   1.101 +
   1.102 +class MockCallFrameInfoHandler: public CallFrameInfo::Handler {
   1.103 + public:
   1.104 +  MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length,
   1.105 +                           uint8 version, const string &augmentation,
   1.106 +                           unsigned return_address));
   1.107 +  MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg));
   1.108 +  MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg));
   1.109 +  MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register,
   1.110 +                                long offset));
   1.111 +  MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register,
   1.112 +                                   long offset));
   1.113 +  MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register));
   1.114 +  MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg,
   1.115 +                                    const string &expression));
   1.116 +  MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg,
   1.117 +                                       const string &expression));
   1.118 +  MOCK_METHOD0(End, bool());
   1.119 +  MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect));
   1.120 +  MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect));
   1.121 +  MOCK_METHOD0(SignalHandler, bool());
   1.122 +};
   1.123 +
   1.124 +class MockCallFrameErrorReporter: public CallFrameInfo::Reporter {
   1.125 + public:
   1.126 +  MockCallFrameErrorReporter() : Reporter("mock filename", "mock section") { }
   1.127 +  MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind));
   1.128 +  MOCK_METHOD1(EarlyEHTerminator, void(uint64));
   1.129 +  MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64));
   1.130 +  MOCK_METHOD2(BadCIEId, void(uint64, uint64));
   1.131 +  MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version));
   1.132 +  MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &));
   1.133 +  MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8));
   1.134 +  MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8));
   1.135 +  MOCK_METHOD2(RestoreInCIE, void(uint64, uint64));
   1.136 +  MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64));
   1.137 +  MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64));
   1.138 +  MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64));
   1.139 +};
   1.140 +
   1.141 +struct CFIFixture {
   1.142 +
   1.143 +  enum { kCFARegister = CallFrameInfo::Handler::kCFARegister };
   1.144 +
   1.145 +  CFIFixture() {
   1.146 +    // Default expectations for the data handler.
   1.147 +    //
   1.148 +    // - Leave Entry and End without expectations, as it's probably a
   1.149 +    //   good idea to set those explicitly in each test.
   1.150 +    //
   1.151 +    // - Expect the *Rule functions to not be called, 
   1.152 +    //   so that each test can simply list the calls they expect.
   1.153 +    //
   1.154 +    // I gather I could use StrictMock for this, but the manual seems
   1.155 +    // to suggest using that only as a last resort, and this isn't so
   1.156 +    // bad.
   1.157 +    EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0);
   1.158 +    EXPECT_CALL(handler, SameValueRule(_, _)).Times(0);
   1.159 +    EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0);
   1.160 +    EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0);
   1.161 +    EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0);
   1.162 +    EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0);
   1.163 +    EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0);
   1.164 +    EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0);
   1.165 +    EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0);
   1.166 +    EXPECT_CALL(handler, SignalHandler()).Times(0);
   1.167 +
   1.168 +    // Default expectations for the error/warning reporer.
   1.169 +    EXPECT_CALL(reporter, Incomplete(_, _)).Times(0);
   1.170 +    EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0);
   1.171 +    EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0);
   1.172 +    EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0);
   1.173 +    EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0);
   1.174 +    EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0);
   1.175 +    EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0);
   1.176 +    EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0);
   1.177 +    EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0);
   1.178 +    EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0);
   1.179 +    EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0);
   1.180 +    EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0);
   1.181 +  }
   1.182 +
   1.183 +  MockCallFrameInfoHandler handler;
   1.184 +  MockCallFrameErrorReporter reporter;
   1.185 +};
   1.186 +
   1.187 +class CFI: public CFIFixture, public Test { };
   1.188 +
   1.189 +TEST_F(CFI, EmptyRegion) {
   1.190 +  EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
   1.191 +  EXPECT_CALL(handler, End()).Times(0);
   1.192 +  static const char data[1] = { 42 };
   1.193 +
   1.194 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.195 +  CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter);
   1.196 +  EXPECT_TRUE(parser.Start());
   1.197 +}
   1.198 +
   1.199 +TEST_F(CFI, IncompleteLength32) {
   1.200 +  CFISection section(kBigEndian, 8);
   1.201 +  section
   1.202 +      // Not even long enough for an initial length.
   1.203 +      .D16(0xa0f)
   1.204 +      // Padding to keep valgrind happy. We subtract these off when we
   1.205 +      // construct the parser.
   1.206 +      .D16(0);
   1.207 +
   1.208 +  EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
   1.209 +  EXPECT_CALL(handler, End()).Times(0);
   1.210 +
   1.211 +  EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
   1.212 +      .WillOnce(Return());
   1.213 +
   1.214 +  string contents;
   1.215 +  ASSERT_TRUE(section.GetContents(&contents));
   1.216 +
   1.217 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.218 +  byte_reader.SetAddressSize(8);
   1.219 +  CallFrameInfo parser(contents.data(), contents.size() - 2,
   1.220 +                       &byte_reader, &handler, &reporter);
   1.221 +  EXPECT_FALSE(parser.Start());
   1.222 +}
   1.223 +
   1.224 +TEST_F(CFI, IncompleteLength64) {
   1.225 +  CFISection section(kLittleEndian, 4);
   1.226 +  section
   1.227 +      // An incomplete 64-bit DWARF initial length.
   1.228 +      .D32(0xffffffff).D32(0x71fbaec2)
   1.229 +      // Padding to keep valgrind happy. We subtract these off when we
   1.230 +      // construct the parser.
   1.231 +      .D32(0);
   1.232 +
   1.233 +  EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
   1.234 +  EXPECT_CALL(handler, End()).Times(0);
   1.235 +
   1.236 +  EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
   1.237 +      .WillOnce(Return());
   1.238 +
   1.239 +  string contents;
   1.240 +  ASSERT_TRUE(section.GetContents(&contents));
   1.241 +
   1.242 +  ByteReader byte_reader(ENDIANNESS_LITTLE);
   1.243 +  byte_reader.SetAddressSize(4);
   1.244 +  CallFrameInfo parser(contents.data(), contents.size() - 4,
   1.245 +                       &byte_reader, &handler, &reporter);
   1.246 +  EXPECT_FALSE(parser.Start());
   1.247 +}
   1.248 +
   1.249 +TEST_F(CFI, IncompleteId32) {
   1.250 +  CFISection section(kBigEndian, 8);
   1.251 +  section
   1.252 +      .D32(3)                      // Initial length, not long enough for id
   1.253 +      .D8(0xd7).D8(0xe5).D8(0xf1)  // incomplete id
   1.254 +      .CIEHeader(8727, 3983, 8889, 3, "")
   1.255 +      .FinishEntry();
   1.256 +
   1.257 +  EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
   1.258 +  EXPECT_CALL(handler, End()).Times(0);
   1.259 +
   1.260 +  EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
   1.261 +      .WillOnce(Return());
   1.262 +
   1.263 +  string contents;
   1.264 +  ASSERT_TRUE(section.GetContents(&contents));
   1.265 +
   1.266 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.267 +  byte_reader.SetAddressSize(8);
   1.268 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.269 +                       &byte_reader, &handler, &reporter);
   1.270 +  EXPECT_FALSE(parser.Start());
   1.271 +}
   1.272 +
   1.273 +TEST_F(CFI, BadId32) {
   1.274 +  CFISection section(kBigEndian, 8);
   1.275 +  section
   1.276 +      .D32(0x100)                       // Initial length
   1.277 +      .D32(0xe802fade)                  // bogus ID
   1.278 +      .Append(0x100 - 4, 0x42);         // make the length true
   1.279 +  section
   1.280 +      .CIEHeader(1672, 9872, 8529, 3, "")
   1.281 +      .FinishEntry();
   1.282 +
   1.283 +  EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
   1.284 +  EXPECT_CALL(handler, End()).Times(0);
   1.285 +
   1.286 +  EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade))
   1.287 +      .WillOnce(Return());
   1.288 +
   1.289 +  string contents;
   1.290 +  ASSERT_TRUE(section.GetContents(&contents));
   1.291 +
   1.292 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.293 +  byte_reader.SetAddressSize(8);
   1.294 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.295 +                       &byte_reader, &handler, &reporter);
   1.296 +  EXPECT_FALSE(parser.Start());
   1.297 +}
   1.298 +
   1.299 +// A lone CIE shouldn't cause any handler calls.
   1.300 +TEST_F(CFI, SingleCIE) {
   1.301 +  CFISection section(kLittleEndian, 4);
   1.302 +  section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, "");
   1.303 +  section.Append(10, dwarf2reader::DW_CFA_nop);
   1.304 +  section.FinishEntry();
   1.305 +
   1.306 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section);
   1.307 +
   1.308 +  EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
   1.309 +  EXPECT_CALL(handler, End()).Times(0);
   1.310 +
   1.311 +  string contents;
   1.312 +  EXPECT_TRUE(section.GetContents(&contents));
   1.313 +  ByteReader byte_reader(ENDIANNESS_LITTLE);
   1.314 +  byte_reader.SetAddressSize(4);
   1.315 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.316 +                       &byte_reader, &handler, &reporter);
   1.317 +  EXPECT_TRUE(parser.Start());
   1.318 +}
   1.319 +
   1.320 +// One FDE, one CIE.
   1.321 +TEST_F(CFI, OneFDE) {
   1.322 +  CFISection section(kBigEndian, 4);
   1.323 +  Label cie;
   1.324 +  section
   1.325 +      .Mark(&cie)
   1.326 +      .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "")
   1.327 +      .FinishEntry()
   1.328 +      .FDEHeader(cie, 0x7714740d, 0x3d5a10cd)
   1.329 +      .FinishEntry();
   1.330 +
   1.331 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section);
   1.332 +
   1.333 +  {
   1.334 +    InSequence s;
   1.335 +    EXPECT_CALL(handler,
   1.336 +                Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87))
   1.337 +        .WillOnce(Return(true));
   1.338 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.339 +  }
   1.340 +
   1.341 +  string contents;
   1.342 +  EXPECT_TRUE(section.GetContents(&contents));
   1.343 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.344 +  byte_reader.SetAddressSize(4);
   1.345 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.346 +                       &byte_reader, &handler, &reporter);
   1.347 +  EXPECT_TRUE(parser.Start());
   1.348 +}
   1.349 +
   1.350 +// Two FDEs share a CIE.
   1.351 +TEST_F(CFI, TwoFDEsOneCIE) {
   1.352 +  CFISection section(kBigEndian, 4);
   1.353 +  Label cie;
   1.354 +  section
   1.355 +      // First FDE. readelf complains about this one because it makes
   1.356 +      // a forward reference to its CIE.
   1.357 +      .FDEHeader(cie, 0xa42744df, 0xa3b42121)
   1.358 +      .FinishEntry()
   1.359 +      // CIE.
   1.360 +      .Mark(&cie)
   1.361 +      .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "")
   1.362 +      .FinishEntry()
   1.363 +      // Second FDE.
   1.364 +      .FDEHeader(cie, 0x6057d391, 0x700f608d)
   1.365 +      .FinishEntry();
   1.366 +
   1.367 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section);
   1.368 +
   1.369 +  {
   1.370 +    InSequence s;
   1.371 +    EXPECT_CALL(handler,
   1.372 +                Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59))
   1.373 +        .WillOnce(Return(true));
   1.374 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.375 +  }
   1.376 +  {
   1.377 +    InSequence s;
   1.378 +    EXPECT_CALL(handler,
   1.379 +                Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59))
   1.380 +        .WillOnce(Return(true));
   1.381 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.382 +  }
   1.383 +
   1.384 +  string contents;
   1.385 +  EXPECT_TRUE(section.GetContents(&contents));
   1.386 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.387 +  byte_reader.SetAddressSize(4);
   1.388 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.389 +                       &byte_reader, &handler, &reporter);
   1.390 +  EXPECT_TRUE(parser.Start());
   1.391 +}
   1.392 +
   1.393 +// Two FDEs, two CIEs.
   1.394 +TEST_F(CFI, TwoFDEsTwoCIEs) {
   1.395 +  CFISection section(kLittleEndian, 8);
   1.396 +  Label cie1, cie2;
   1.397 +  section
   1.398 +      // First CIE.
   1.399 +      .Mark(&cie1)
   1.400 +      .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "")
   1.401 +      .FinishEntry()
   1.402 +      // First FDE which cites second CIE. readelf complains about
   1.403 +      // this one because it makes a forward reference to its CIE.
   1.404 +      .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL)
   1.405 +      .FinishEntry()
   1.406 +      // Second FDE, which cites first CIE.
   1.407 +      .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL)
   1.408 +      .FinishEntry()
   1.409 +      // Second CIE.
   1.410 +      .Mark(&cie2)
   1.411 +      .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "")
   1.412 +      .FinishEntry();
   1.413 +
   1.414 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section);
   1.415 +
   1.416 +  {
   1.417 +    InSequence s;
   1.418 +    EXPECT_CALL(handler,
   1.419 +                Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2,
   1.420 +                      "", 0x61d2c581))
   1.421 +        .WillOnce(Return(true));
   1.422 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.423 +  }
   1.424 +  {
   1.425 +    InSequence s;
   1.426 +    EXPECT_CALL(handler,
   1.427 +                Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3,
   1.428 +                      "", 0xbf45e65a))
   1.429 +        .WillOnce(Return(true));
   1.430 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.431 +  }
   1.432 +
   1.433 +  string contents;
   1.434 +  EXPECT_TRUE(section.GetContents(&contents));
   1.435 +  ByteReader byte_reader(ENDIANNESS_LITTLE);
   1.436 +  byte_reader.SetAddressSize(8);
   1.437 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.438 +                       &byte_reader, &handler, &reporter);
   1.439 +  EXPECT_TRUE(parser.Start());
   1.440 +}
   1.441 +
   1.442 +// An FDE whose CIE specifies a version we don't recognize.
   1.443 +TEST_F(CFI, BadVersion) {
   1.444 +  CFISection section(kBigEndian, 4);
   1.445 +  Label cie1, cie2;
   1.446 +  section
   1.447 +      .Mark(&cie1)
   1.448 +      .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "")
   1.449 +      .FinishEntry()
   1.450 +      // We should skip this entry, as its CIE specifies a version we
   1.451 +      // don't recognize.
   1.452 +      .FDEHeader(cie1, 0x08852292, 0x2204004a)
   1.453 +      .FinishEntry()
   1.454 +      // Despite the above, we should visit this entry.
   1.455 +      .Mark(&cie2)
   1.456 +      .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "")
   1.457 +      .FinishEntry()
   1.458 +      .FDEHeader(cie2, 0x2094735a, 0x6e875501)
   1.459 +      .FinishEntry();
   1.460 +
   1.461 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section);
   1.462 +
   1.463 +  EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52))
   1.464 +    .WillOnce(Return());
   1.465 +
   1.466 +  {
   1.467 +    InSequence s;
   1.468 +    // We should see no mention of the first FDE, but we should get
   1.469 +    // a call to Entry for the second.
   1.470 +    EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "",
   1.471 +                               0x96cb3264))
   1.472 +        .WillOnce(Return(true));
   1.473 +    EXPECT_CALL(handler, End())
   1.474 +        .WillOnce(Return(true));
   1.475 +  }
   1.476 +
   1.477 +  string contents;
   1.478 +  EXPECT_TRUE(section.GetContents(&contents));
   1.479 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.480 +  byte_reader.SetAddressSize(4);
   1.481 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.482 +                       &byte_reader, &handler, &reporter);
   1.483 +  EXPECT_FALSE(parser.Start());
   1.484 +}
   1.485 +
   1.486 +// An FDE whose CIE specifies an augmentation we don't recognize.
   1.487 +TEST_F(CFI, BadAugmentation) {
   1.488 +  CFISection section(kBigEndian, 4);
   1.489 +  Label cie1, cie2;
   1.490 +  section
   1.491 +      .Mark(&cie1)
   1.492 +      .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!")
   1.493 +      .FinishEntry()
   1.494 +      // We should skip this entry, as its CIE specifies an
   1.495 +      // augmentation we don't recognize.
   1.496 +      .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd)
   1.497 +      .FinishEntry()
   1.498 +      // Despite the above, we should visit this entry.
   1.499 +      .Mark(&cie2)
   1.500 +      .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "")
   1.501 +      .FinishEntry()
   1.502 +      .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8)
   1.503 +      .FinishEntry();
   1.504 +
   1.505 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section);
   1.506 +
   1.507 +  EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!"))
   1.508 +    .WillOnce(Return());
   1.509 +
   1.510 +  {
   1.511 +    InSequence s;
   1.512 +    // We should see no mention of the first FDE, but we should get
   1.513 +    // a call to Entry for the second.
   1.514 +    EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "",
   1.515 +                               0xf2f519b2))
   1.516 +        .WillOnce(Return(true));
   1.517 +    EXPECT_CALL(handler, End())
   1.518 +        .WillOnce(Return(true));
   1.519 +  }
   1.520 +
   1.521 +  string contents;
   1.522 +  EXPECT_TRUE(section.GetContents(&contents));
   1.523 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.524 +  byte_reader.SetAddressSize(4);
   1.525 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.526 +                       &byte_reader, &handler, &reporter);
   1.527 +  EXPECT_FALSE(parser.Start());
   1.528 +}
   1.529 +
   1.530 +// The return address column field is a byte in CFI version 1
   1.531 +// (DWARF2), but a ULEB128 value in version 3 (DWARF3).
   1.532 +TEST_F(CFI, CIEVersion1ReturnColumn) {
   1.533 +  CFISection section(kBigEndian, 4);
   1.534 +  Label cie;
   1.535 +  section
   1.536 +      // CIE, using the version 1 format: return column is a ubyte.
   1.537 +      .Mark(&cie)
   1.538 +      // Use a value for the return column that is parsed differently
   1.539 +      // as a ubyte and as a ULEB128.
   1.540 +      .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "")
   1.541 +      .FinishEntry()
   1.542 +      // FDE, citing that CIE.
   1.543 +      .FDEHeader(cie, 0xb8d347b5, 0x825e55dc)
   1.544 +      .FinishEntry();
   1.545 +
   1.546 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section);
   1.547 +
   1.548 +  {
   1.549 +    InSequence s;
   1.550 +    EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f))
   1.551 +        .WillOnce(Return(true));
   1.552 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.553 +  }
   1.554 +
   1.555 +  string contents;
   1.556 +  EXPECT_TRUE(section.GetContents(&contents));
   1.557 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.558 +  byte_reader.SetAddressSize(4);
   1.559 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.560 +                       &byte_reader, &handler, &reporter);
   1.561 +  EXPECT_TRUE(parser.Start());
   1.562 +}
   1.563 +
   1.564 +// The return address column field is a byte in CFI version 1
   1.565 +// (DWARF2), but a ULEB128 value in version 3 (DWARF3).
   1.566 +TEST_F(CFI, CIEVersion3ReturnColumn) {
   1.567 +  CFISection section(kBigEndian, 4);
   1.568 +  Label cie;
   1.569 +  section
   1.570 +      // CIE, using the version 3 format: return column is a ULEB128.
   1.571 +      .Mark(&cie)
   1.572 +      // Use a value for the return column that is parsed differently
   1.573 +      // as a ubyte and as a ULEB128.
   1.574 +      .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "")
   1.575 +      .FinishEntry()
   1.576 +      // FDE, citing that CIE.
   1.577 +      .FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
   1.578 +      .FinishEntry();
   1.579 +
   1.580 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section);
   1.581 +
   1.582 +  {
   1.583 +    InSequence s;
   1.584 +    EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89))
   1.585 +        .WillOnce(Return(true));
   1.586 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
   1.587 +  }
   1.588 +
   1.589 +  string contents;
   1.590 +  EXPECT_TRUE(section.GetContents(&contents));
   1.591 +  ByteReader byte_reader(ENDIANNESS_BIG);
   1.592 +  byte_reader.SetAddressSize(4);
   1.593 +  CallFrameInfo parser(contents.data(), contents.size(),
   1.594 +                       &byte_reader, &handler, &reporter);
   1.595 +  EXPECT_TRUE(parser.Start());
   1.596 +}
   1.597 +
   1.598 +struct CFIInsnFixture: public CFIFixture {
   1.599 +  CFIInsnFixture() : CFIFixture() {
   1.600 +    data_factor = 0xb6f;
   1.601 +    return_register = 0x9be1ed9f;
   1.602 +    version = 3;
   1.603 +    cfa_base_register = 0x383a3aa;
   1.604 +    cfa_offset = 0xf748;
   1.605 +  }
   1.606 +  
   1.607 +  // Prepare SECTION to receive FDE instructions.
   1.608 +  //
   1.609 +  // - Append a stock CIE header that establishes the fixture's
   1.610 +  //   code_factor, data_factor, return_register, version, and
   1.611 +  //   augmentation values.
   1.612 +  // - Have the CIE set up a CFA rule using cfa_base_register and
   1.613 +  //   cfa_offset.
   1.614 +  // - Append a stock FDE header, referring to the above CIE, for the
   1.615 +  //   fde_size bytes at fde_start. Choose fde_start and fde_size
   1.616 +  //   appropriately for the section's address size.
   1.617 +  // - Set appropriate expectations on handler in sequence s for the
   1.618 +  //   frame description entry and the CIE's CFA rule.
   1.619 +  //
   1.620 +  // On return, SECTION is ready to have FDE instructions appended to
   1.621 +  // it, and its FinishEntry member called.
   1.622 +  void StockCIEAndFDE(CFISection *section) {
   1.623 +    // Choose appropriate constants for our address size.
   1.624 +    if (section->AddressSize() == 4) {
   1.625 +      fde_start = 0xc628ecfbU;
   1.626 +      fde_size = 0x5dee04a2;
   1.627 +      code_factor = 0x60b;
   1.628 +    } else {
   1.629 +      assert(section->AddressSize() == 8);
   1.630 +      fde_start = 0x0005c57ce7806bd3ULL;
   1.631 +      fde_size = 0x2699521b5e333100ULL;
   1.632 +      code_factor = 0x01008e32855274a8ULL;
   1.633 +    }
   1.634 +
   1.635 +    // Create the CIE.
   1.636 +    (*section)
   1.637 +        .Mark(&cie_label)
   1.638 +        .CIEHeader(code_factor, data_factor, return_register, version,
   1.639 +                   "")
   1.640 +        .D8(dwarf2reader::DW_CFA_def_cfa)
   1.641 +        .ULEB128(cfa_base_register)
   1.642 +        .ULEB128(cfa_offset)
   1.643 +        .FinishEntry();
   1.644 +
   1.645 +    // Create the FDE.
   1.646 +    section->FDEHeader(cie_label, fde_start, fde_size);
   1.647 +
   1.648 +    // Expect an Entry call for the FDE and a ValOffsetRule call for the
   1.649 +    // CIE's CFA rule.
   1.650 +    EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "",
   1.651 +                               return_register))
   1.652 +        .InSequence(s)
   1.653 +        .WillOnce(Return(true));
   1.654 +    EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister,
   1.655 +                                       cfa_base_register, cfa_offset))
   1.656 +      .InSequence(s)
   1.657 +      .WillOnce(Return(true));
   1.658 +  }
   1.659 +
   1.660 +  // Run the contents of SECTION through a CallFrameInfo parser,
   1.661 +  // expecting parser.Start to return SUCCEEDS
   1.662 +  void ParseSection(CFISection *section, bool succeeds = true) {
   1.663 +    string contents;
   1.664 +    EXPECT_TRUE(section->GetContents(&contents));
   1.665 +    dwarf2reader::Endianness endianness;
   1.666 +    if (section->endianness() == kBigEndian)
   1.667 +      endianness = ENDIANNESS_BIG;
   1.668 +    else {
   1.669 +      assert(section->endianness() == kLittleEndian);
   1.670 +      endianness = ENDIANNESS_LITTLE;
   1.671 +    }
   1.672 +    ByteReader byte_reader(endianness);
   1.673 +    byte_reader.SetAddressSize(section->AddressSize());
   1.674 +    CallFrameInfo parser(contents.data(), contents.size(),
   1.675 +                         &byte_reader, &handler, &reporter);
   1.676 +    if (succeeds)
   1.677 +      EXPECT_TRUE(parser.Start());
   1.678 +    else
   1.679 +      EXPECT_FALSE(parser.Start());
   1.680 +  }
   1.681 +
   1.682 +  Label cie_label;
   1.683 +  Sequence s;
   1.684 +  uint64 code_factor;
   1.685 +  int data_factor;
   1.686 +  unsigned return_register;
   1.687 +  unsigned version;
   1.688 +  unsigned cfa_base_register;
   1.689 +  int cfa_offset;
   1.690 +  uint64 fde_start, fde_size;
   1.691 +};
   1.692 +
   1.693 +class CFIInsn: public CFIInsnFixture, public Test { };
   1.694 +
   1.695 +TEST_F(CFIInsn, DW_CFA_set_loc) {
   1.696 +  CFISection section(kBigEndian, 4);
   1.697 +  StockCIEAndFDE(&section);
   1.698 +  section
   1.699 +      .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a)
   1.700 +      // Use DW_CFA_def_cfa to force a handler call that we can use to
   1.701 +      // check the effect of the DW_CFA_set_loc.
   1.702 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee)
   1.703 +      .FinishEntry();
   1.704 +
   1.705 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section);
   1.706 +
   1.707 +  EXPECT_CALL(handler,
   1.708 +              ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee))
   1.709 +      .InSequence(s)
   1.710 +      .WillOnce(Return(true));
   1.711 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.712 +
   1.713 +  ParseSection(&section);
   1.714 +}
   1.715 +
   1.716 +TEST_F(CFIInsn, DW_CFA_advance_loc) {
   1.717 +  CFISection section(kBigEndian, 8);
   1.718 +  StockCIEAndFDE(&section);
   1.719 +  section
   1.720 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a)
   1.721 +      // Use DW_CFA_def_cfa to force a handler call that we can use to
   1.722 +      // check the effect of the DW_CFA_advance_loc.
   1.723 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf)
   1.724 +      .FinishEntry();
   1.725 +
   1.726 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section);
   1.727 +
   1.728 +  EXPECT_CALL(handler,
   1.729 +              ValOffsetRule(fde_start + 0x2a * code_factor,
   1.730 +                            kCFARegister, 0x5bbb3715, 0x0186c7bf))
   1.731 +        .InSequence(s)
   1.732 +        .WillOnce(Return(true));
   1.733 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.734 +
   1.735 +  ParseSection(&section);
   1.736 +}
   1.737 +
   1.738 +TEST_F(CFIInsn, DW_CFA_advance_loc1) {
   1.739 +  CFISection section(kLittleEndian, 8);
   1.740 +  StockCIEAndFDE(&section);
   1.741 +  section
   1.742 +      .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8)
   1.743 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93)
   1.744 +      .FinishEntry();
   1.745 +
   1.746 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section);
   1.747 +
   1.748 +  EXPECT_CALL(handler,
   1.749 +              ValOffsetRule((fde_start + 0xd8 * code_factor),
   1.750 +                            kCFARegister, 0x69d5696a, 0x1eb7fc93))
   1.751 +      .InSequence(s)
   1.752 +      .WillOnce(Return(true));
   1.753 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.754 +
   1.755 +  ParseSection(&section);
   1.756 +}
   1.757 +
   1.758 +TEST_F(CFIInsn, DW_CFA_advance_loc2) {
   1.759 +  CFISection section(kLittleEndian, 4);
   1.760 +  StockCIEAndFDE(&section);
   1.761 +  section
   1.762 +      .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb)
   1.763 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37)
   1.764 +      .FinishEntry();
   1.765 +
   1.766 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section);
   1.767 +
   1.768 +  EXPECT_CALL(handler,
   1.769 +              ValOffsetRule((fde_start + 0x3adb * code_factor),
   1.770 +                            kCFARegister, 0x3a368bed, 0x3194ee37))
   1.771 +      .InSequence(s)
   1.772 +      .WillOnce(Return(true));
   1.773 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.774 +
   1.775 +  ParseSection(&section);
   1.776 +}
   1.777 +
   1.778 +TEST_F(CFIInsn, DW_CFA_advance_loc4) {
   1.779 +  CFISection section(kBigEndian, 8);
   1.780 +  StockCIEAndFDE(&section);
   1.781 +  section
   1.782 +      .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88)
   1.783 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb)
   1.784 +      .FinishEntry();
   1.785 +
   1.786 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section);
   1.787 +
   1.788 +  EXPECT_CALL(handler,
   1.789 +              ValOffsetRule((fde_start + 0x15813c88ULL * code_factor),
   1.790 +                            kCFARegister, 0x135270c5, 0x24bad7cb))
   1.791 +      .InSequence(s)
   1.792 +      .WillOnce(Return(true));
   1.793 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.794 +
   1.795 +  ParseSection(&section);
   1.796 +}
   1.797 +
   1.798 +TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) {
   1.799 +  code_factor = 0x2d;
   1.800 +  CFISection section(kBigEndian, 8);
   1.801 +  StockCIEAndFDE(&section);
   1.802 +  section
   1.803 +      .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL)
   1.804 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f)
   1.805 +      .FinishEntry();
   1.806 +
   1.807 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section);
   1.808 +
   1.809 +  EXPECT_CALL(handler,
   1.810 +              ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor),
   1.811 +                            kCFARegister, 0xe17ed602, 0x3d162e7f))
   1.812 +      .InSequence(s)
   1.813 +      .WillOnce(Return(true));
   1.814 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.815 +
   1.816 +  ParseSection(&section);
   1.817 +}
   1.818 +
   1.819 +TEST_F(CFIInsn, DW_CFA_def_cfa) {
   1.820 +  CFISection section(kLittleEndian, 4);
   1.821 +  StockCIEAndFDE(&section);
   1.822 +  section
   1.823 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7)
   1.824 +      .FinishEntry();
   1.825 +
   1.826 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section);
   1.827 +
   1.828 +  EXPECT_CALL(handler,
   1.829 +              ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7))
   1.830 +      .InSequence(s).WillOnce(Return(true));
   1.831 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.832 +
   1.833 +  ParseSection(&section);
   1.834 +}
   1.835 +
   1.836 +TEST_F(CFIInsn, DW_CFA_def_cfa_sf) {
   1.837 +  CFISection section(kBigEndian, 4);
   1.838 +  StockCIEAndFDE(&section);
   1.839 +  section
   1.840 +      .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea)
   1.841 +      .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2)
   1.842 +      .FinishEntry();
   1.843 +
   1.844 +  EXPECT_CALL(handler,
   1.845 +              ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7,
   1.846 +                            0x9ea * data_factor))
   1.847 +      .InSequence(s).WillOnce(Return(true));
   1.848 +  EXPECT_CALL(handler,
   1.849 +              ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da,
   1.850 +                            -0x40a2 * data_factor))
   1.851 +      .InSequence(s).WillOnce(Return(true));
   1.852 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.853 +
   1.854 +  ParseSection(&section);
   1.855 +}
   1.856 +
   1.857 +TEST_F(CFIInsn, DW_CFA_def_cfa_register) {
   1.858 +  CFISection section(kLittleEndian, 8);
   1.859 +  StockCIEAndFDE(&section);
   1.860 +  section
   1.861 +      .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363)
   1.862 +      .FinishEntry();
   1.863 +
   1.864 +  EXPECT_CALL(handler,
   1.865 +              ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset))
   1.866 +      .InSequence(s).WillOnce(Return(true));
   1.867 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.868 +
   1.869 +  ParseSection(&section);
   1.870 +}
   1.871 +
   1.872 +// DW_CFA_def_cfa_register should have no effect when applied to a
   1.873 +// non-base/offset rule.
   1.874 +TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) {
   1.875 +  CFISection section(kBigEndian, 4);
   1.876 +  StockCIEAndFDE(&section);
   1.877 +  section
   1.878 +      .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack")
   1.879 +      .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49)
   1.880 +      .FinishEntry();
   1.881 +
   1.882 +  EXPECT_CALL(handler,
   1.883 +              ValExpressionRule(fde_start, kCFARegister,
   1.884 +                                "needle in a haystack"))
   1.885 +      .WillRepeatedly(Return(true));
   1.886 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.887 +
   1.888 +  ParseSection(&section);
   1.889 +}
   1.890 +
   1.891 +TEST_F(CFIInsn, DW_CFA_def_cfa_offset) {
   1.892 +  CFISection section(kBigEndian, 4);
   1.893 +  StockCIEAndFDE(&section);
   1.894 +  section
   1.895 +      .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
   1.896 +      .FinishEntry();
   1.897 +
   1.898 +  EXPECT_CALL(handler,
   1.899 +              ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
   1.900 +                            0x1e8e3b9b))
   1.901 +      .InSequence(s).WillOnce(Return(true));
   1.902 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.903 +
   1.904 +  ParseSection(&section);
   1.905 +}
   1.906 +
   1.907 +TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) {
   1.908 +  CFISection section(kLittleEndian, 4);
   1.909 +  StockCIEAndFDE(&section);
   1.910 +  section
   1.911 +      .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970)
   1.912 +      .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd)
   1.913 +      .FinishEntry();
   1.914 +
   1.915 +  EXPECT_CALL(handler,
   1.916 +              ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
   1.917 +                            0x970 * data_factor))
   1.918 +      .InSequence(s).WillOnce(Return(true));
   1.919 +  EXPECT_CALL(handler,
   1.920 +              ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
   1.921 +                            -0x2cd * data_factor))
   1.922 +      .InSequence(s).WillOnce(Return(true));
   1.923 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.924 +
   1.925 +  ParseSection(&section);
   1.926 +}
   1.927 +
   1.928 +// DW_CFA_def_cfa_offset should have no effect when applied to a
   1.929 +// non-base/offset rule.
   1.930 +TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) {
   1.931 +  CFISection section(kBigEndian, 4);
   1.932 +  StockCIEAndFDE(&section);
   1.933 +  section
   1.934 +      .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday")
   1.935 +      .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
   1.936 +      .FinishEntry();
   1.937 +
   1.938 +  EXPECT_CALL(handler,
   1.939 +              ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday"))
   1.940 +      .WillRepeatedly(Return(true));
   1.941 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.942 +
   1.943 +  ParseSection(&section);
   1.944 +}
   1.945 +
   1.946 +TEST_F(CFIInsn, DW_CFA_def_cfa_expression) {
   1.947 +  CFISection section(kLittleEndian, 8);
   1.948 +  StockCIEAndFDE(&section);
   1.949 +  section
   1.950 +      .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow")
   1.951 +      .FinishEntry();
   1.952 +
   1.953 +  EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister,
   1.954 +                                         "eating crow"))
   1.955 +      .InSequence(s).WillOnce(Return(true));
   1.956 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.957 +
   1.958 +  ParseSection(&section);
   1.959 +}
   1.960 +
   1.961 +TEST_F(CFIInsn, DW_CFA_undefined) {
   1.962 +  CFISection section(kLittleEndian, 4);
   1.963 +  StockCIEAndFDE(&section);
   1.964 +  section
   1.965 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d)
   1.966 +      .FinishEntry();
   1.967 +
   1.968 +  EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d))
   1.969 +      .InSequence(s).WillOnce(Return(true));
   1.970 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.971 +
   1.972 +  ParseSection(&section);
   1.973 +}
   1.974 +
   1.975 +TEST_F(CFIInsn, DW_CFA_same_value) {
   1.976 +  CFISection section(kLittleEndian, 4);
   1.977 +  StockCIEAndFDE(&section);
   1.978 +  section
   1.979 +      .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760)
   1.980 +      .FinishEntry();
   1.981 +
   1.982 +  EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760))
   1.983 +      .InSequence(s).WillOnce(Return(true));
   1.984 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
   1.985 +
   1.986 +  ParseSection(&section);
   1.987 +}
   1.988 +
   1.989 +TEST_F(CFIInsn, DW_CFA_offset) {
   1.990 +  CFISection section(kBigEndian, 4);
   1.991 +  StockCIEAndFDE(&section);
   1.992 +  section
   1.993 +      .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6)
   1.994 +      .FinishEntry();
   1.995 +
   1.996 +  EXPECT_CALL(handler,
   1.997 +              OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor))
   1.998 +      .InSequence(s).WillOnce(Return(true));
   1.999 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1000 +
  1.1001 +  ParseSection(&section);
  1.1002 +}
  1.1003 +
  1.1004 +TEST_F(CFIInsn, DW_CFA_offset_extended) {
  1.1005 +  CFISection section(kBigEndian, 4);
  1.1006 +  StockCIEAndFDE(&section);
  1.1007 +  section
  1.1008 +      .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48)
  1.1009 +      .FinishEntry();
  1.1010 +
  1.1011 +  EXPECT_CALL(handler,
  1.1012 +              OffsetRule(fde_start, 0x402b, kCFARegister, 0xb48 * data_factor))
  1.1013 +      .InSequence(s).WillOnce(Return(true));
  1.1014 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1015 +
  1.1016 +  ParseSection(&section);
  1.1017 +}
  1.1018 +
  1.1019 +TEST_F(CFIInsn, DW_CFA_offset_extended_sf) {
  1.1020 +  CFISection section(kBigEndian, 8);
  1.1021 +  StockCIEAndFDE(&section);
  1.1022 +  section
  1.1023 +      .D8(dwarf2reader::DW_CFA_offset_extended_sf)
  1.1024 +          .ULEB128(0x997c23ee).LEB128(0x2d00)
  1.1025 +      .D8(dwarf2reader::DW_CFA_offset_extended_sf)
  1.1026 +          .ULEB128(0x9519eb82).LEB128(-0xa77)
  1.1027 +      .FinishEntry();
  1.1028 +
  1.1029 +  EXPECT_CALL(handler,
  1.1030 +              OffsetRule(fde_start, 0x997c23ee,
  1.1031 +                         kCFARegister, 0x2d00 * data_factor))
  1.1032 +      .InSequence(s).WillOnce(Return(true));
  1.1033 +  EXPECT_CALL(handler,
  1.1034 +              OffsetRule(fde_start, 0x9519eb82,
  1.1035 +                         kCFARegister, -0xa77 * data_factor))
  1.1036 +      .InSequence(s).WillOnce(Return(true));
  1.1037 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1038 +
  1.1039 +  ParseSection(&section);
  1.1040 +}
  1.1041 +
  1.1042 +TEST_F(CFIInsn, DW_CFA_val_offset) {
  1.1043 +  CFISection section(kBigEndian, 4);
  1.1044 +  StockCIEAndFDE(&section);
  1.1045 +  section
  1.1046 +      .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673)
  1.1047 +      .FinishEntry();
  1.1048 +
  1.1049 +  EXPECT_CALL(handler,
  1.1050 +              ValOffsetRule(fde_start, 0x623562fe,
  1.1051 +                            kCFARegister, 0x673 * data_factor))
  1.1052 +      .InSequence(s).WillOnce(Return(true));
  1.1053 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1054 +
  1.1055 +  ParseSection(&section);
  1.1056 +}
  1.1057 +
  1.1058 +TEST_F(CFIInsn, DW_CFA_val_offset_sf) {
  1.1059 +  CFISection section(kBigEndian, 4);
  1.1060 +  StockCIEAndFDE(&section);
  1.1061 +  section
  1.1062 +      .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab)
  1.1063 +      .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2)
  1.1064 +      .FinishEntry();
  1.1065 +
  1.1066 +  EXPECT_CALL(handler,
  1.1067 +              ValOffsetRule(fde_start, 0x6f4f,
  1.1068 +                            kCFARegister, 0xaab * data_factor))
  1.1069 +      .InSequence(s).WillOnce(Return(true));
  1.1070 +  EXPECT_CALL(handler,
  1.1071 +              ValOffsetRule(fde_start, 0x2483,
  1.1072 +                            kCFARegister, -0x8a2 * data_factor))
  1.1073 +      .InSequence(s).WillOnce(Return(true));
  1.1074 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1075 +
  1.1076 +  ParseSection(&section);
  1.1077 +}
  1.1078 +
  1.1079 +TEST_F(CFIInsn, DW_CFA_register) {
  1.1080 +  CFISection section(kLittleEndian, 8);
  1.1081 +  StockCIEAndFDE(&section);
  1.1082 +  section
  1.1083 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414)
  1.1084 +      .FinishEntry();
  1.1085 +
  1.1086 +  EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414))
  1.1087 +      .InSequence(s).WillOnce(Return(true));
  1.1088 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1089 +
  1.1090 +  ParseSection(&section);
  1.1091 +}
  1.1092 +
  1.1093 +TEST_F(CFIInsn, DW_CFA_expression) {
  1.1094 +  CFISection section(kBigEndian, 8);
  1.1095 +  StockCIEAndFDE(&section);
  1.1096 +  section
  1.1097 +      .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2)
  1.1098 +      .Block("plus ça change, plus c'est la même chose")
  1.1099 +      .FinishEntry();
  1.1100 +
  1.1101 +  EXPECT_CALL(handler,
  1.1102 +              ExpressionRule(fde_start, 0xa1619fb2,
  1.1103 +                             "plus ça change, plus c'est la même chose"))
  1.1104 +      .InSequence(s).WillOnce(Return(true));
  1.1105 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1106 +
  1.1107 +  ParseSection(&section);
  1.1108 +}
  1.1109 +
  1.1110 +TEST_F(CFIInsn, DW_CFA_val_expression) {
  1.1111 +  CFISection section(kBigEndian, 4);
  1.1112 +  StockCIEAndFDE(&section);
  1.1113 +  section
  1.1114 +      .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3)
  1.1115 +      .Block("he who has the gold makes the rules")
  1.1116 +      .FinishEntry();
  1.1117 +
  1.1118 +  EXPECT_CALL(handler,
  1.1119 +              ValExpressionRule(fde_start, 0xc5e4a9e3,
  1.1120 +                                "he who has the gold makes the rules"))
  1.1121 +      .InSequence(s).WillOnce(Return(true));
  1.1122 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1123 +
  1.1124 +  ParseSection(&section);
  1.1125 +}
  1.1126 +
  1.1127 +TEST_F(CFIInsn, DW_CFA_restore) {
  1.1128 +  CFISection section(kLittleEndian, 8);
  1.1129 +  code_factor = 0x01bd188a9b1fa083ULL;
  1.1130 +  data_factor = -0x1ac8;
  1.1131 +  return_register = 0x8c35b049;
  1.1132 +  version = 2;
  1.1133 +  fde_start = 0x2d70fe998298bbb1ULL;
  1.1134 +  fde_size = 0x46ccc2e63cf0b108ULL;
  1.1135 +  Label cie;
  1.1136 +  section
  1.1137 +      .Mark(&cie)
  1.1138 +      .CIEHeader(code_factor, data_factor, return_register, version,
  1.1139 +                 "")
  1.1140 +      // Provide a CFA rule, because register rules require them.
  1.1141 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8)
  1.1142 +      // Provide an offset(N) rule for register 0x3c.
  1.1143 +      .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348)
  1.1144 +      .FinishEntry()
  1.1145 +      // In the FDE...
  1.1146 +      .FDEHeader(cie, fde_start, fde_size)
  1.1147 +      // At a second address, provide a new offset(N) rule for register 0x3c.
  1.1148 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0x13)
  1.1149 +      .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50)
  1.1150 +      // At a third address, restore the original rule for register 0x3c.
  1.1151 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0x01)
  1.1152 +      .D8(dwarf2reader::DW_CFA_restore | 0x3c)
  1.1153 +      .FinishEntry();
  1.1154 +
  1.1155 +  {
  1.1156 +    InSequence s;
  1.1157 +    EXPECT_CALL(handler,
  1.1158 +                Entry(_, fde_start, fde_size, version, "", return_register))
  1.1159 +        .WillOnce(Return(true));
  1.1160 +    // CIE's CFA rule.
  1.1161 +    EXPECT_CALL(handler,
  1.1162 +                ValOffsetRule(fde_start, kCFARegister, 0x6ca1d50e, 0x372e38e8))
  1.1163 +        .WillOnce(Return(true));
  1.1164 +    // CIE's rule for register 0x3c.
  1.1165 +    EXPECT_CALL(handler,
  1.1166 +                OffsetRule(fde_start, 0x3c, kCFARegister, 0xb348 * data_factor))
  1.1167 +        .WillOnce(Return(true));
  1.1168 +    // FDE's rule for register 0x3c.
  1.1169 +    EXPECT_CALL(handler,
  1.1170 +                OffsetRule(fde_start + 0x13 * code_factor, 0x3c,
  1.1171 +                           kCFARegister, 0x9a50 * data_factor))
  1.1172 +        .WillOnce(Return(true));
  1.1173 +    // Restore CIE's rule for register 0x3c.
  1.1174 +    EXPECT_CALL(handler,
  1.1175 +                OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c,
  1.1176 +                           kCFARegister, 0xb348 * data_factor))
  1.1177 +        .WillOnce(Return(true));
  1.1178 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1179 +  }
  1.1180 +    
  1.1181 +  ParseSection(&section);
  1.1182 +}
  1.1183 +
  1.1184 +TEST_F(CFIInsn, DW_CFA_restoreNoRule) {
  1.1185 +  CFISection section(kBigEndian, 4);
  1.1186 +  code_factor = 0x005f78143c1c3b82ULL;
  1.1187 +  data_factor = 0x25d0;
  1.1188 +  return_register = 0xe8;
  1.1189 +  version = 1;
  1.1190 +  fde_start = 0x4062e30f;
  1.1191 +  fde_size = 0x5302a389;
  1.1192 +  Label cie;
  1.1193 +  section
  1.1194 +      .Mark(&cie)
  1.1195 +      .CIEHeader(code_factor, data_factor, return_register, version, "")
  1.1196 +      // Provide a CFA rule, because register rules require them.
  1.1197 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127)
  1.1198 +      .FinishEntry()
  1.1199 +      // In the FDE...
  1.1200 +      .FDEHeader(cie, fde_start, fde_size)
  1.1201 +      // At a second address, provide an offset(N) rule for register 0x2c.
  1.1202 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0x7)
  1.1203 +      .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47)
  1.1204 +      // At a third address, restore the (missing) CIE rule for register 0x2c.
  1.1205 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0xb)
  1.1206 +      .D8(dwarf2reader::DW_CFA_restore | 0x2c)
  1.1207 +      .FinishEntry();
  1.1208 +
  1.1209 +  {
  1.1210 +    InSequence s;
  1.1211 +    EXPECT_CALL(handler,
  1.1212 +                Entry(_, fde_start, fde_size, version, "", return_register))
  1.1213 +        .WillOnce(Return(true));
  1.1214 +    // CIE's CFA rule.
  1.1215 +    EXPECT_CALL(handler,
  1.1216 +                ValOffsetRule(fde_start, kCFARegister, 0x470aa334, 0x099ef127))
  1.1217 +        .WillOnce(Return(true));
  1.1218 +    // FDE's rule for register 0x2c.
  1.1219 +    EXPECT_CALL(handler,
  1.1220 +                OffsetRule(fde_start + 0x7 * code_factor, 0x2c,
  1.1221 +                           kCFARegister, 0x1f47 * data_factor))
  1.1222 +        .WillOnce(Return(true));
  1.1223 +    // Restore CIE's (missing) rule for register 0x2c.
  1.1224 +    EXPECT_CALL(handler,
  1.1225 +                SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c))
  1.1226 +        .WillOnce(Return(true));
  1.1227 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1228 +  }
  1.1229 +    
  1.1230 +  ParseSection(&section);
  1.1231 +}
  1.1232 +
  1.1233 +TEST_F(CFIInsn, DW_CFA_restore_extended) {
  1.1234 +  CFISection section(kBigEndian, 4);
  1.1235 +  code_factor = 0x126e;
  1.1236 +  data_factor = -0xd8b;
  1.1237 +  return_register = 0x77711787;
  1.1238 +  version = 3;
  1.1239 +  fde_start = 0x01f55a45;
  1.1240 +  fde_size = 0x452adb80;
  1.1241 +  Label cie;
  1.1242 +  section
  1.1243 +      .Mark(&cie)
  1.1244 +      .CIEHeader(code_factor, data_factor, return_register, version,
  1.1245 +                 "", true /* dwarf64 */ )
  1.1246 +      // Provide a CFA rule, because register rules require them.
  1.1247 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5)
  1.1248 +      // Provide an offset(N) rule for register 0x0f9b8a1c.
  1.1249 +      .D8(dwarf2reader::DW_CFA_offset_extended)
  1.1250 +          .ULEB128(0x0f9b8a1c).ULEB128(0xc979)
  1.1251 +      .FinishEntry()
  1.1252 +      // In the FDE...
  1.1253 +      .FDEHeader(cie, fde_start, fde_size)
  1.1254 +      // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c.
  1.1255 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0x3)
  1.1256 +      .D8(dwarf2reader::DW_CFA_offset_extended)
  1.1257 +          .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b)
  1.1258 +      // At a third address, restore the original rule for register 0x0f9b8a1c.
  1.1259 +      .D8(dwarf2reader::DW_CFA_advance_loc | 0x04)
  1.1260 +      .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c)
  1.1261 +      .FinishEntry();
  1.1262 +
  1.1263 +  {
  1.1264 +    InSequence s;
  1.1265 +    EXPECT_CALL(handler,
  1.1266 +                Entry(_, fde_start, fde_size, version, "", return_register))
  1.1267 +        .WillOnce(Return(true));
  1.1268 +    // CIE's CFA rule.
  1.1269 +    EXPECT_CALL(handler,
  1.1270 +                ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5))
  1.1271 +        .WillOnce(Return(true));
  1.1272 +    // CIE's rule for register 0x0f9b8a1c.
  1.1273 +    EXPECT_CALL(handler,
  1.1274 +                OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister,
  1.1275 +                           0xc979 * data_factor))
  1.1276 +        .WillOnce(Return(true));
  1.1277 +    // FDE's rule for register 0x0f9b8a1c.
  1.1278 +    EXPECT_CALL(handler,
  1.1279 +                OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c,
  1.1280 +                           kCFARegister, 0x3b7b * data_factor))
  1.1281 +        .WillOnce(Return(true));
  1.1282 +    // Restore CIE's rule for register 0x0f9b8a1c.
  1.1283 +    EXPECT_CALL(handler,
  1.1284 +                OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c,
  1.1285 +                           kCFARegister, 0xc979 * data_factor))
  1.1286 +        .WillOnce(Return(true));
  1.1287 +    EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1288 +  }
  1.1289 +    
  1.1290 +  ParseSection(&section);
  1.1291 +}
  1.1292 +
  1.1293 +TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) {
  1.1294 +  CFISection section(kLittleEndian, 8);
  1.1295 +  StockCIEAndFDE(&section);
  1.1296 +
  1.1297 +  // We create a state, save it, modify it, and then restore. We
  1.1298 +  // refer to the state that is overridden the restore as the
  1.1299 +  // "outgoing" state, and the restored state the "incoming" state.
  1.1300 +  //
  1.1301 +  // Register         outgoing        incoming        expect
  1.1302 +  // 1                offset(N)       no rule         new "same value" rule
  1.1303 +  // 2                register(R)     offset(N)       report changed rule
  1.1304 +  // 3                offset(N)       offset(M)       report changed offset
  1.1305 +  // 4                offset(N)       offset(N)       no report
  1.1306 +  // 5                offset(N)       no rule         new "same value" rule
  1.1307 +  section
  1.1308 +      // Create the "incoming" state, which we will save and later restore.
  1.1309 +      .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806)
  1.1310 +      .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d)
  1.1311 +      .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055)
  1.1312 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1313 +      // Advance to a new instruction; an implementation could legitimately
  1.1314 +      // ignore all but the final rule for a given register at a given address.
  1.1315 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1316 +      // Create the "outgoing" state, which we will discard.
  1.1317 +      .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a)
  1.1318 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767)
  1.1319 +      .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29)
  1.1320 +      .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce)
  1.1321 +      // At a third address, restore the incoming state.
  1.1322 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1323 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1324 +      .FinishEntry();
  1.1325 +
  1.1326 +  uint64 addr = fde_start;
  1.1327 +
  1.1328 +  // Expect the incoming rules to be reported.
  1.1329 +  EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor))
  1.1330 +    .InSequence(s).WillOnce(Return(true));
  1.1331 +  EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor))
  1.1332 +    .InSequence(s).WillOnce(Return(true));
  1.1333 +  EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor))
  1.1334 +    .InSequence(s).WillOnce(Return(true));
  1.1335 +
  1.1336 +  addr += code_factor;
  1.1337 +
  1.1338 +  // After the save, we establish the outgoing rule set.
  1.1339 +  EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor))
  1.1340 +    .InSequence(s).WillOnce(Return(true));
  1.1341 +  EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767))
  1.1342 +    .InSequence(s).WillOnce(Return(true));
  1.1343 +  EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor))
  1.1344 +    .InSequence(s).WillOnce(Return(true));
  1.1345 +  EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor))
  1.1346 +    .InSequence(s).WillOnce(Return(true));
  1.1347 +
  1.1348 +  addr += code_factor;
  1.1349 +
  1.1350 +  // Finally, after the restore, expect to see the differences from
  1.1351 +  // the outgoing to the incoming rules reported.
  1.1352 +  EXPECT_CALL(handler, SameValueRule(addr, 1))
  1.1353 +      .InSequence(s).WillOnce(Return(true));
  1.1354 +  EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor))
  1.1355 +      .InSequence(s).WillOnce(Return(true));
  1.1356 +  EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor))
  1.1357 +      .InSequence(s).WillOnce(Return(true));
  1.1358 +  EXPECT_CALL(handler, SameValueRule(addr, 5))
  1.1359 +      .InSequence(s).WillOnce(Return(true));
  1.1360 +
  1.1361 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1362 +
  1.1363 +  ParseSection(&section);
  1.1364 +}
  1.1365 +
  1.1366 +// Check that restoring a rule set reports changes to the CFA rule.
  1.1367 +TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) {
  1.1368 +  CFISection section(kBigEndian, 4);
  1.1369 +  StockCIEAndFDE(&section);
  1.1370 +
  1.1371 +  section
  1.1372 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1373 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1374 +      .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102)
  1.1375 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1376 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1377 +      .FinishEntry();
  1.1378 +
  1.1379 +  EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister,
  1.1380 +                                     cfa_base_register, 0x90481102))
  1.1381 +      .InSequence(s).WillOnce(Return(true));
  1.1382 +  EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister,
  1.1383 +                                     cfa_base_register, cfa_offset))
  1.1384 +      .InSequence(s).WillOnce(Return(true));
  1.1385 +
  1.1386 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1387 +
  1.1388 +  ParseSection(&section);
  1.1389 +}
  1.1390 +
  1.1391 +TEST_F(CFIInsn, DW_CFA_nop) {
  1.1392 +  CFISection section(kLittleEndian, 4);
  1.1393 +  StockCIEAndFDE(&section);
  1.1394 +  section
  1.1395 +      .D8(dwarf2reader::DW_CFA_nop)
  1.1396 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b)
  1.1397 +      .D8(dwarf2reader::DW_CFA_nop)
  1.1398 +      .FinishEntry();
  1.1399 +
  1.1400 +  EXPECT_CALL(handler,
  1.1401 +              ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b))
  1.1402 +      .InSequence(s).WillOnce(Return(true));
  1.1403 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1404 +
  1.1405 +  ParseSection(&section);
  1.1406 +}
  1.1407 +
  1.1408 +TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
  1.1409 +  CFISection section(kBigEndian, 4);
  1.1410 +  StockCIEAndFDE(&section);
  1.1411 +  section
  1.1412 +      .D8(dwarf2reader::DW_CFA_GNU_window_save)
  1.1413 +      .FinishEntry();
  1.1414 +
  1.1415 +  // Don't include all the rules in any particular sequence.
  1.1416 +
  1.1417 +  // The caller's %o0-%o7 have become the callee's %i0-%i7. This is
  1.1418 +  // the GCC register numbering.
  1.1419 +  for (int i = 8; i < 16; i++)
  1.1420 +    EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16))
  1.1421 +        .WillOnce(Return(true));
  1.1422 +  // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of
  1.1423 +  // its frame.
  1.1424 +  for (int i = 16; i < 32; i++)
  1.1425 +    EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4))
  1.1426 +        .WillOnce(Return(true));
  1.1427 +
  1.1428 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1429 +
  1.1430 +  ParseSection(&section);
  1.1431 +}
  1.1432 +
  1.1433 +TEST_F(CFIInsn, DW_CFA_GNU_args_size) {
  1.1434 +  CFISection section(kLittleEndian, 8);
  1.1435 +  StockCIEAndFDE(&section);
  1.1436 +  section
  1.1437 +      .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520)
  1.1438 +      // Verify that we see this, meaning we parsed the above properly.
  1.1439 +      .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269)
  1.1440 +      .FinishEntry();
  1.1441 +
  1.1442 +  EXPECT_CALL(handler,
  1.1443 +              OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor))
  1.1444 +      .InSequence(s).WillOnce(Return(true));
  1.1445 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1446 +
  1.1447 +  ParseSection(&section);
  1.1448 +}
  1.1449 +
  1.1450 +TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) {
  1.1451 +  CFISection section(kLittleEndian, 4);
  1.1452 +  StockCIEAndFDE(&section);
  1.1453 +  section
  1.1454 +      .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended)
  1.1455 +      .ULEB128(0x430cc87a).ULEB128(0x613)
  1.1456 +      .FinishEntry();
  1.1457 +
  1.1458 +  EXPECT_CALL(handler,
  1.1459 +              OffsetRule(fde_start, 0x430cc87a,
  1.1460 +                         kCFARegister, -0x613 * data_factor))
  1.1461 +      .InSequence(s).WillOnce(Return(true));
  1.1462 +  EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
  1.1463 +
  1.1464 +  ParseSection(&section);
  1.1465 +}
  1.1466 +
  1.1467 +// Three FDEs: skip the second
  1.1468 +TEST_F(CFIInsn, SkipFDE) {
  1.1469 +  CFISection section(kBigEndian, 4);
  1.1470 +  Label cie;
  1.1471 +  section
  1.1472 +      // CIE, used by all FDEs.
  1.1473 +      .Mark(&cie)
  1.1474 +      .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "")
  1.1475 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad)
  1.1476 +      .FinishEntry()
  1.1477 +      // First FDE.
  1.1478 +      .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4)
  1.1479 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf)
  1.1480 +      .FinishEntry()
  1.1481 +      // Second FDE.
  1.1482 +      .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */)
  1.1483 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18)
  1.1484 +      .FinishEntry()
  1.1485 +      // Third FDE.
  1.1486 +      .FDEHeader(cie, 0xf681cfc8, 0x7e4594e)
  1.1487 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4)
  1.1488 +      .FinishEntry();
  1.1489 +
  1.1490 +  {
  1.1491 +    InSequence s;
  1.1492 +
  1.1493 +    // Process the first FDE.
  1.1494 +    EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849))
  1.1495 +        .WillOnce(Return(true));
  1.1496 +    EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister,
  1.1497 +                                       0x42ed390b, 0x98f43aad))
  1.1498 +        .WillOnce(Return(true));
  1.1499 +    EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf))
  1.1500 +        .WillOnce(Return(true));
  1.1501 +    EXPECT_CALL(handler, End())
  1.1502 +        .WillOnce(Return(true));
  1.1503 +
  1.1504 +    // Skip the second FDE.
  1.1505 +    EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849))
  1.1506 +        .WillOnce(Return(false));
  1.1507 +
  1.1508 +    // Process the third FDE.
  1.1509 +    EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849))
  1.1510 +        .WillOnce(Return(true));
  1.1511 +    EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister,
  1.1512 +                                       0x42ed390b, 0x98f43aad))
  1.1513 +        .WillOnce(Return(true));
  1.1514 +    EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4))
  1.1515 +        .WillOnce(Return(true));
  1.1516 +    EXPECT_CALL(handler, End())
  1.1517 +        .WillOnce(Return(true));
  1.1518 +  }
  1.1519 +
  1.1520 +  ParseSection(&section);
  1.1521 +}
  1.1522 +
  1.1523 +// Quit processing in the middle of an entry's instructions.
  1.1524 +TEST_F(CFIInsn, QuitMidentry) {
  1.1525 +  CFISection section(kLittleEndian, 8);
  1.1526 +  StockCIEAndFDE(&section);
  1.1527 +  section
  1.1528 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431)
  1.1529 +      .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat")
  1.1530 +      .FinishEntry();
  1.1531 +
  1.1532 +  EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431))
  1.1533 +      .InSequence(s).WillOnce(Return(false));
  1.1534 +  EXPECT_CALL(handler, End())
  1.1535 +      .InSequence(s).WillOnce(Return(true));
  1.1536 +  
  1.1537 +  ParseSection(&section, false);
  1.1538 +}
  1.1539 +
  1.1540 +class CFIRestore: public CFIInsnFixture, public Test { };
  1.1541 +
  1.1542 +TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) {
  1.1543 +  CFISection section(kLittleEndian, 4);
  1.1544 +  StockCIEAndFDE(&section);
  1.1545 +  section
  1.1546 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e)
  1.1547 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1548 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1549 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1550 +      .FinishEntry();
  1.1551 +
  1.1552 +  EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e))
  1.1553 +      .InSequence(s).WillOnce(Return(true));
  1.1554 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1555 +
  1.1556 +  ParseSection(&section);
  1.1557 +}
  1.1558 +
  1.1559 +TEST_F(CFIRestore, RestoreUndefinedRuleChanged) {
  1.1560 +  CFISection section(kLittleEndian, 4);
  1.1561 +  StockCIEAndFDE(&section);
  1.1562 +  section
  1.1563 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f)
  1.1564 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1565 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1566 +      .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f)
  1.1567 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1568 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1569 +      .FinishEntry();
  1.1570 +
  1.1571 +  EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f))
  1.1572 +      .InSequence(s).WillOnce(Return(true));
  1.1573 +  EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f))
  1.1574 +      .InSequence(s).WillOnce(Return(true));
  1.1575 +  EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f))
  1.1576 +      .InSequence(s).WillOnce(Return(true));
  1.1577 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1578 +
  1.1579 +  ParseSection(&section);
  1.1580 +}
  1.1581 +
  1.1582 +TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) {
  1.1583 +  CFISection section(kLittleEndian, 4);
  1.1584 +  StockCIEAndFDE(&section);
  1.1585 +  section
  1.1586 +      .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a)
  1.1587 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1588 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1589 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1590 +      .FinishEntry();
  1.1591 +
  1.1592 +  EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a))
  1.1593 +      .InSequence(s).WillOnce(Return(true));
  1.1594 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1595 +
  1.1596 +  ParseSection(&section);
  1.1597 +}
  1.1598 +
  1.1599 +TEST_F(CFIRestore, RestoreSameValueRuleChanged) {
  1.1600 +  CFISection section(kLittleEndian, 4);
  1.1601 +  StockCIEAndFDE(&section);
  1.1602 +  section
  1.1603 +      .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5)
  1.1604 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1605 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1606 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5)
  1.1607 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1608 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1609 +      .FinishEntry();
  1.1610 +
  1.1611 +  EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5))
  1.1612 +      .InSequence(s).WillOnce(Return(true));
  1.1613 +  EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5))
  1.1614 +      .InSequence(s).WillOnce(Return(true));
  1.1615 +  EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5))
  1.1616 +      .InSequence(s).WillOnce(Return(true));
  1.1617 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1618 +
  1.1619 +  ParseSection(&section);
  1.1620 +}
  1.1621 +
  1.1622 +TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) {
  1.1623 +  CFISection section(kLittleEndian, 4);
  1.1624 +  StockCIEAndFDE(&section);
  1.1625 +  section
  1.1626 +      .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f)
  1.1627 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1628 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1629 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1630 +      .FinishEntry();
  1.1631 +
  1.1632 +  EXPECT_CALL(handler, OffsetRule(fde_start, 0x14,
  1.1633 +                                  kCFARegister, 0xb6f * data_factor))
  1.1634 +      .InSequence(s).WillOnce(Return(true));
  1.1635 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1636 +
  1.1637 +  ParseSection(&section);
  1.1638 +}
  1.1639 +
  1.1640 +TEST_F(CFIRestore, RestoreOffsetRuleChanged) {
  1.1641 +  CFISection section(kLittleEndian, 4);
  1.1642 +  StockCIEAndFDE(&section);
  1.1643 +  section
  1.1644 +      .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7)
  1.1645 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1646 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1647 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21)
  1.1648 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1649 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1650 +      .FinishEntry();
  1.1651 +
  1.1652 +  EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
  1.1653 +                                  kCFARegister, 0xeb7 * data_factor))
  1.1654 +      .InSequence(s).WillOnce(Return(true));
  1.1655 +  EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21))
  1.1656 +      .InSequence(s).WillOnce(Return(true));
  1.1657 +  EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21,
  1.1658 +                                  kCFARegister, 0xeb7 * data_factor))
  1.1659 +      .InSequence(s).WillOnce(Return(true));
  1.1660 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1661 +
  1.1662 +  ParseSection(&section);
  1.1663 +}
  1.1664 +
  1.1665 +TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) {
  1.1666 +  CFISection section(kLittleEndian, 4);
  1.1667 +  StockCIEAndFDE(&section);
  1.1668 +  section
  1.1669 +      .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134)
  1.1670 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1671 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1672 +      .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f)
  1.1673 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1674 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1675 +      .FinishEntry();
  1.1676 +
  1.1677 +  EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
  1.1678 +                                  kCFARegister, 0x134 * data_factor))
  1.1679 +      .InSequence(s).WillOnce(Return(true));
  1.1680 +  EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21,
  1.1681 +                                  kCFARegister, 0xf4f * data_factor))
  1.1682 +      .InSequence(s).WillOnce(Return(true));
  1.1683 +  EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21,
  1.1684 +                                  kCFARegister, 0x134 * data_factor))
  1.1685 +      .InSequence(s).WillOnce(Return(true));
  1.1686 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1687 +
  1.1688 +  ParseSection(&section);
  1.1689 +}
  1.1690 +
  1.1691 +TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) {
  1.1692 +  CFISection section(kLittleEndian, 4);
  1.1693 +  StockCIEAndFDE(&section);
  1.1694 +  section
  1.1695 +      .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c)
  1.1696 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1697 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1698 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1699 +      .FinishEntry();
  1.1700 +
  1.1701 +  EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6,
  1.1702 +                                  kCFARegister, 0xe4c * data_factor))
  1.1703 +      .InSequence(s).WillOnce(Return(true));
  1.1704 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1705 +
  1.1706 +  ParseSection(&section);
  1.1707 +}
  1.1708 +
  1.1709 +TEST_F(CFIRestore, RestoreValOffsetRuleChanged) {
  1.1710 +  CFISection section(kLittleEndian, 4);
  1.1711 +  StockCIEAndFDE(&section);
  1.1712 +  section
  1.1713 +      .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7)
  1.1714 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1715 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1716 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6)
  1.1717 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1718 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1719 +      .FinishEntry();
  1.1720 +
  1.1721 +  EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6,
  1.1722 +                                  kCFARegister, 0xeb7 * data_factor))
  1.1723 +      .InSequence(s).WillOnce(Return(true));
  1.1724 +  EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6))
  1.1725 +      .InSequence(s).WillOnce(Return(true));
  1.1726 +  EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6,
  1.1727 +                                  kCFARegister, 0xeb7 * data_factor))
  1.1728 +      .InSequence(s).WillOnce(Return(true));
  1.1729 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1730 +
  1.1731 +  ParseSection(&section);
  1.1732 +}
  1.1733 +
  1.1734 +TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) {
  1.1735 +  CFISection section(kLittleEndian, 4);
  1.1736 +  StockCIEAndFDE(&section);
  1.1737 +  section
  1.1738 +      .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562)
  1.1739 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1740 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1741 +      .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88)
  1.1742 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1743 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1744 +      .FinishEntry();
  1.1745 +
  1.1746 +  EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b,
  1.1747 +                                  kCFARegister, 0x562 * data_factor))
  1.1748 +      .InSequence(s).WillOnce(Return(true));
  1.1749 +  EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b,
  1.1750 +                                  kCFARegister, 0xe88 * data_factor))
  1.1751 +      .InSequence(s).WillOnce(Return(true));
  1.1752 +  EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b,
  1.1753 +                                  kCFARegister, 0x562 * data_factor))
  1.1754 +      .InSequence(s).WillOnce(Return(true));
  1.1755 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1756 +
  1.1757 +  ParseSection(&section);
  1.1758 +}
  1.1759 +
  1.1760 +TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) {
  1.1761 +  CFISection section(kLittleEndian, 4);
  1.1762 +  StockCIEAndFDE(&section);
  1.1763 +  section
  1.1764 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce)
  1.1765 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1766 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1767 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1768 +      .FinishEntry();
  1.1769 +
  1.1770 +  EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce))
  1.1771 +      .InSequence(s).WillOnce(Return(true));
  1.1772 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1773 +
  1.1774 +  ParseSection(&section);
  1.1775 +}
  1.1776 +
  1.1777 +TEST_F(CFIRestore, RestoreRegisterRuleChanged) {
  1.1778 +  CFISection section(kLittleEndian, 4);
  1.1779 +  StockCIEAndFDE(&section);
  1.1780 +  section
  1.1781 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559)
  1.1782 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1783 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1784 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5)
  1.1785 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1786 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1787 +      .FinishEntry();
  1.1788 +
  1.1789 +  EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559))
  1.1790 +      .InSequence(s).WillOnce(Return(true));
  1.1791 +  EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5))
  1.1792 +      .InSequence(s).WillOnce(Return(true));
  1.1793 +  EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5,
  1.1794 +                                    0x095f1559))
  1.1795 +      .InSequence(s).WillOnce(Return(true));
  1.1796 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1797 +
  1.1798 +  ParseSection(&section);
  1.1799 +}
  1.1800 +
  1.1801 +TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) {
  1.1802 +  CFISection section(kLittleEndian, 4);
  1.1803 +  StockCIEAndFDE(&section);
  1.1804 +  section
  1.1805 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a)
  1.1806 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1807 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1808 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742)
  1.1809 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1810 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1811 +      .FinishEntry();
  1.1812 +
  1.1813 +  EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a))
  1.1814 +      .InSequence(s).WillOnce(Return(true));
  1.1815 +  EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1,
  1.1816 +                                    0xbabb4742))
  1.1817 +      .InSequence(s).WillOnce(Return(true));
  1.1818 +  EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1,
  1.1819 +                                    0x16607d6a))
  1.1820 +      .InSequence(s).WillOnce(Return(true));
  1.1821 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1822 +
  1.1823 +  ParseSection(&section);
  1.1824 +}
  1.1825 +
  1.1826 +TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) {
  1.1827 +  CFISection section(kLittleEndian, 4);
  1.1828 +  StockCIEAndFDE(&section);
  1.1829 +  section
  1.1830 +      .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf")
  1.1831 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1832 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1833 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1834 +      .FinishEntry();
  1.1835 +
  1.1836 +  EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf"))
  1.1837 +      .InSequence(s).WillOnce(Return(true));
  1.1838 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1839 +
  1.1840 +  ParseSection(&section);
  1.1841 +}
  1.1842 +
  1.1843 +TEST_F(CFIRestore, RestoreExpressionRuleChanged) {
  1.1844 +  CFISection section(kLittleEndian, 4);
  1.1845 +  StockCIEAndFDE(&section);
  1.1846 +  section
  1.1847 +      .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf")
  1.1848 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1849 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1850 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
  1.1851 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1852 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1853 +      .FinishEntry();
  1.1854 +
  1.1855 +  EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf"))
  1.1856 +      .InSequence(s).WillOnce(Return(true));
  1.1857 +  EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46))
  1.1858 +      .InSequence(s).WillOnce(Return(true));
  1.1859 +  EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46,
  1.1860 +                                      "elf"))
  1.1861 +      .InSequence(s).WillOnce(Return(true));
  1.1862 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1863 +
  1.1864 +  ParseSection(&section);
  1.1865 +}
  1.1866 +
  1.1867 +TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) {
  1.1868 +  CFISection section(kLittleEndian, 4);
  1.1869 +  StockCIEAndFDE(&section);
  1.1870 +  section
  1.1871 +      .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf")
  1.1872 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1873 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1874 +      .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc")
  1.1875 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1876 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1877 +      .FinishEntry();
  1.1878 +
  1.1879 +  EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf"))
  1.1880 +      .InSequence(s).WillOnce(Return(true));
  1.1881 +  EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739,
  1.1882 +                                      "orc"))
  1.1883 +      .InSequence(s).WillOnce(Return(true));
  1.1884 +  // Expectations are not wishes.
  1.1885 +  EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739,
  1.1886 +                                      "smurf"))
  1.1887 +      .InSequence(s).WillOnce(Return(true));
  1.1888 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1889 +
  1.1890 +  ParseSection(&section);
  1.1891 +}
  1.1892 +
  1.1893 +TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) {
  1.1894 +  CFISection section(kLittleEndian, 4);
  1.1895 +  StockCIEAndFDE(&section);
  1.1896 +  section
  1.1897 +      .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152)
  1.1898 +      .Block("hideous")
  1.1899 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1900 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1901 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1902 +      .FinishEntry();
  1.1903 +
  1.1904 +  EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous"))
  1.1905 +      .InSequence(s).WillOnce(Return(true));
  1.1906 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1907 +
  1.1908 +  ParseSection(&section);
  1.1909 +}
  1.1910 +
  1.1911 +TEST_F(CFIRestore, RestoreValExpressionRuleChanged) {
  1.1912 +  CFISection section(kLittleEndian, 4);
  1.1913 +  StockCIEAndFDE(&section);
  1.1914 +  section
  1.1915 +      .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46)
  1.1916 +      .Block("revolting")
  1.1917 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1918 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1919 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
  1.1920 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1921 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1922 +      .FinishEntry();
  1.1923 +
  1.1924 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section);
  1.1925 +
  1.1926 +  EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting"))
  1.1927 +      .InSequence(s).WillOnce(Return(true));
  1.1928 +  EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46))
  1.1929 +      .InSequence(s).WillOnce(Return(true));
  1.1930 +  EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46,
  1.1931 +                                      "revolting"))
  1.1932 +      .InSequence(s).WillOnce(Return(true));
  1.1933 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1934 +
  1.1935 +  ParseSection(&section);
  1.1936 +}
  1.1937 +
  1.1938 +TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) {
  1.1939 +  CFISection section(kLittleEndian, 4);
  1.1940 +  StockCIEAndFDE(&section);
  1.1941 +  section
  1.1942 +      .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
  1.1943 +      .Block("repulsive")
  1.1944 +      .D8(dwarf2reader::DW_CFA_remember_state)
  1.1945 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1946 +      .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
  1.1947 +      .Block("nauseous")
  1.1948 +      .D8(dwarf2reader::DW_CFA_advance_loc | 1)
  1.1949 +      .D8(dwarf2reader::DW_CFA_restore_state)
  1.1950 +      .FinishEntry();
  1.1951 +
  1.1952 +  PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression",
  1.1953 +                                 section);
  1.1954 +
  1.1955 +  EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive"))
  1.1956 +      .InSequence(s).WillOnce(Return(true));
  1.1957 +  EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739,
  1.1958 +                                      "nauseous"))
  1.1959 +      .InSequence(s).WillOnce(Return(true));
  1.1960 +  // Expectations are not wishes.
  1.1961 +  EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739,
  1.1962 +                                      "repulsive"))
  1.1963 +      .InSequence(s).WillOnce(Return(true));
  1.1964 +  EXPECT_CALL(handler, End()).WillOnce(Return(true));
  1.1965 +
  1.1966 +  ParseSection(&section);
  1.1967 +}
  1.1968 +
  1.1969 +struct EHFrameFixture: public CFIInsnFixture {
  1.1970 +  EHFrameFixture() 
  1.1971 +      : CFIInsnFixture(), section(kBigEndian, 4, true) {
  1.1972 +    encoded_pointer_bases.cfi  = 0x7f496cb2;
  1.1973 +    encoded_pointer_bases.text = 0x540f67b6;
  1.1974 +    encoded_pointer_bases.data = 0xe3eab768;
  1.1975 +    section.SetEncodedPointerBases(encoded_pointer_bases);
  1.1976 +  }
  1.1977 +  CFISection section;
  1.1978 +  CFISection::EncodedPointerBases encoded_pointer_bases;
  1.1979 +
  1.1980 +  // Parse CFIInsnFixture::ParseSection, but parse the section as
  1.1981 +  // .eh_frame data, supplying stock base addresses.
  1.1982 +  void ParseEHFrameSection(CFISection *section, bool succeeds = true) {
  1.1983 +    EXPECT_TRUE(section->ContainsEHFrame());
  1.1984 +    string contents;
  1.1985 +    EXPECT_TRUE(section->GetContents(&contents));
  1.1986 +    dwarf2reader::Endianness endianness;
  1.1987 +    if (section->endianness() == kBigEndian)
  1.1988 +      endianness = ENDIANNESS_BIG;
  1.1989 +    else {
  1.1990 +      assert(section->endianness() == kLittleEndian);
  1.1991 +      endianness = ENDIANNESS_LITTLE;
  1.1992 +    }
  1.1993 +    ByteReader byte_reader(endianness);
  1.1994 +    byte_reader.SetAddressSize(section->AddressSize());
  1.1995 +    byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, contents.data());
  1.1996 +    byte_reader.SetTextBase(encoded_pointer_bases.text);
  1.1997 +    byte_reader.SetDataBase(encoded_pointer_bases.data);
  1.1998 +    CallFrameInfo parser(contents.data(), contents.size(),
  1.1999 +                         &byte_reader, &handler, &reporter, true);
  1.2000 +    if (succeeds)
  1.2001 +      EXPECT_TRUE(parser.Start());
  1.2002 +    else
  1.2003 +      EXPECT_FALSE(parser.Start());
  1.2004 +  }
  1.2005 +
  1.2006 +};
  1.2007 +
  1.2008 +class EHFrame: public EHFrameFixture, public Test { };
  1.2009 +
  1.2010 +// A simple CIE, an FDE, and a terminator.
  1.2011 +TEST_F(EHFrame, Terminator) {
  1.2012 +  Label cie;
  1.2013 +  section
  1.2014 +      .Mark(&cie)
  1.2015 +      .CIEHeader(9968, 2466, 67, 1, "")
  1.2016 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372)
  1.2017 +      .FinishEntry()
  1.2018 +      .FDEHeader(cie, 0x848037a1, 0x7b30475e)
  1.2019 +      .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850)
  1.2020 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721)
  1.2021 +      .FinishEntry()
  1.2022 +      .D32(0)                           // Terminate the sequence.
  1.2023 +      // This FDE should be ignored.
  1.2024 +      .FDEHeader(cie, 0xf19629fe, 0x439fb09b)
  1.2025 +      .FinishEntry();
  1.2026 +
  1.2027 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section);
  1.2028 +
  1.2029 +  EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67))
  1.2030 +      .InSequence(s).WillOnce(Return(true));
  1.2031 +  EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372))
  1.2032 +      .InSequence(s).WillOnce(Return(true));
  1.2033 +  EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721))
  1.2034 +      .InSequence(s).WillOnce(Return(true));
  1.2035 +  EXPECT_CALL(handler, End())
  1.2036 +      .InSequence(s).WillOnce(Return(true));
  1.2037 +  EXPECT_CALL(reporter, EarlyEHTerminator(_))
  1.2038 +      .InSequence(s).WillOnce(Return());
  1.2039 +
  1.2040 +  ParseEHFrameSection(&section);
  1.2041 +}
  1.2042 +
  1.2043 +// The parser should recognize the Linux Standards Base 'z' augmentations.
  1.2044 +TEST_F(EHFrame, SimpleFDE) {
  1.2045 +  DwarfPointerEncoding lsda_encoding =
  1.2046 +      DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect
  1.2047 +                           | dwarf2reader::DW_EH_PE_datarel
  1.2048 +                           | dwarf2reader::DW_EH_PE_sdata2);
  1.2049 +  DwarfPointerEncoding fde_encoding =
  1.2050 +      DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
  1.2051 +                           | dwarf2reader::DW_EH_PE_udata2);
  1.2052 +  
  1.2053 +  section.SetPointerEncoding(fde_encoding);
  1.2054 +  section.SetEncodedPointerBases(encoded_pointer_bases);
  1.2055 +  Label cie;
  1.2056 +  section
  1.2057 +      .Mark(&cie)
  1.2058 +      .CIEHeader(4873, 7012, 100, 1, "zSLPR")
  1.2059 +      .ULEB128(7)                                // Augmentation data length
  1.2060 +      .D8(lsda_encoding)                         // LSDA pointer format
  1.2061 +      .D8(dwarf2reader::DW_EH_PE_pcrel)          // personality pointer format
  1.2062 +      .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value 
  1.2063 +      .D8(fde_encoding)                          // FDE pointer format
  1.2064 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31)
  1.2065 +      .FinishEntry()
  1.2066 +      .FDEHeader(cie, 0x540f6b56, 0xf686)
  1.2067 +      .ULEB128(2)                                // Augmentation data length
  1.2068 +      .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed
  1.2069 +      .D8(dwarf2reader::DW_CFA_set_loc)
  1.2070 +      .EncodedPointer(0x540fa4ce, fde_encoding)
  1.2071 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e)
  1.2072 +      .FinishEntry()
  1.2073 +      .D32(0);                                   // terminator
  1.2074 +
  1.2075 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section);
  1.2076 +
  1.2077 +  EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100))
  1.2078 +      .InSequence(s).WillOnce(Return(true));
  1.2079 +  EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false))
  1.2080 +      .InSequence(s).WillOnce(Return(true));
  1.2081 +  EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true))
  1.2082 +      .InSequence(s).WillOnce(Return(true));
  1.2083 +  EXPECT_CALL(handler, SignalHandler())
  1.2084 +      .InSequence(s).WillOnce(Return(true));
  1.2085 +  EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31))
  1.2086 +      .InSequence(s).WillOnce(Return(true));
  1.2087 +  EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e))
  1.2088 +      .InSequence(s).WillOnce(Return(true));
  1.2089 +  EXPECT_CALL(handler, End())
  1.2090 +      .InSequence(s).WillOnce(Return(true));
  1.2091 +
  1.2092 +  ParseEHFrameSection(&section);
  1.2093 +}
  1.2094 +
  1.2095 +// Check that we can handle an empty 'z' augmentation.
  1.2096 +TEST_F(EHFrame, EmptyZ) {
  1.2097 +  Label cie;
  1.2098 +  section
  1.2099 +      .Mark(&cie)
  1.2100 +      .CIEHeader(5955, 5805, 228, 1, "z")
  1.2101 +      .ULEB128(0)                                // Augmentation data length
  1.2102 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247)
  1.2103 +      .FinishEntry()
  1.2104 +      .FDEHeader(cie, 0xda007738, 0xfb55c641)
  1.2105 +      .ULEB128(0)                                // Augmentation data length
  1.2106 +      .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11)
  1.2107 +      .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769)
  1.2108 +      .FinishEntry();
  1.2109 +
  1.2110 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section);
  1.2111 +
  1.2112 +  EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228))
  1.2113 +      .InSequence(s).WillOnce(Return(true));
  1.2114 +  EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247))
  1.2115 +      .InSequence(s).WillOnce(Return(true));
  1.2116 +  EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769))
  1.2117 +      .InSequence(s).WillOnce(Return(true));
  1.2118 +  EXPECT_CALL(handler, End())
  1.2119 +      .InSequence(s).WillOnce(Return(true));
  1.2120 +
  1.2121 +  ParseEHFrameSection(&section);
  1.2122 +}
  1.2123 +
  1.2124 +// Check that we recognize bad 'z' augmentation characters.
  1.2125 +TEST_F(EHFrame, BadZ) {
  1.2126 +  Label cie;
  1.2127 +  section
  1.2128 +      .Mark(&cie)
  1.2129 +      .CIEHeader(6937, 1045, 142, 1, "zQ")
  1.2130 +      .ULEB128(0)                                // Augmentation data length
  1.2131 +      .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725)
  1.2132 +      .FinishEntry()
  1.2133 +      .FDEHeader(cie, 0x1293efa8, 0x236f53f2)
  1.2134 +      .ULEB128(0)                                // Augmentation data length
  1.2135 +      .D8(dwarf2reader::DW_CFA_advance_loc | 12)
  1.2136 +      .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462)
  1.2137 +      .FinishEntry();
  1.2138 +
  1.2139 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section);
  1.2140 +
  1.2141 +  EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ"))
  1.2142 +      .WillOnce(Return());
  1.2143 +
  1.2144 +  ParseEHFrameSection(&section, false);
  1.2145 +}
  1.2146 +
  1.2147 +TEST_F(EHFrame, zL) {
  1.2148 +  Label cie;
  1.2149 +  DwarfPointerEncoding lsda_encoding =
  1.2150 +      DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel
  1.2151 +                           | dwarf2reader::DW_EH_PE_udata2);
  1.2152 +  section
  1.2153 +      .Mark(&cie)
  1.2154 +      .CIEHeader(9285, 9959, 54, 1, "zL")
  1.2155 +      .ULEB128(1)                       // Augmentation data length
  1.2156 +      .D8(lsda_encoding)                // encoding for LSDA pointer in FDE
  1.2157 +
  1.2158 +      .FinishEntry()
  1.2159 +      .FDEHeader(cie, 0xd40091aa, 0x9aa6e746)
  1.2160 +      .ULEB128(2)                       // Augmentation data length
  1.2161 +      .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer
  1.2162 +      .FinishEntry()
  1.2163 +      .D32(0);                                   // terminator
  1.2164 +
  1.2165 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section);
  1.2166 +
  1.2167 +  EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54))
  1.2168 +      .InSequence(s).WillOnce(Return(true));
  1.2169 +  EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false))
  1.2170 +      .InSequence(s).WillOnce(Return(true));
  1.2171 +  EXPECT_CALL(handler, End())
  1.2172 +      .InSequence(s).WillOnce(Return(true));
  1.2173 +
  1.2174 +  ParseEHFrameSection(&section);
  1.2175 +}
  1.2176 +
  1.2177 +TEST_F(EHFrame, zP) {
  1.2178 +  Label cie;
  1.2179 +  DwarfPointerEncoding personality_encoding =
  1.2180 +      DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel
  1.2181 +                           | dwarf2reader::DW_EH_PE_udata2);
  1.2182 +  section
  1.2183 +      .Mark(&cie)
  1.2184 +      .CIEHeader(1097, 6313, 17, 1, "zP")
  1.2185 +      .ULEB128(3)                  // Augmentation data length
  1.2186 +      .D8(personality_encoding)    // encoding for personality routine
  1.2187 +      .EncodedPointer(0xe3eaccac, personality_encoding) // value
  1.2188 +      .FinishEntry()
  1.2189 +      .FDEHeader(cie, 0x0c8350c9, 0xbef11087)
  1.2190 +      .ULEB128(0)                       // Augmentation data length
  1.2191 +      .FinishEntry()
  1.2192 +      .D32(0);                                   // terminator
  1.2193 +
  1.2194 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section);
  1.2195 +
  1.2196 +  EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17))
  1.2197 +      .InSequence(s).WillOnce(Return(true));
  1.2198 +  EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false))
  1.2199 +      .InSequence(s).WillOnce(Return(true));
  1.2200 +  EXPECT_CALL(handler, End())
  1.2201 +      .InSequence(s).WillOnce(Return(true));
  1.2202 +
  1.2203 +  ParseEHFrameSection(&section);
  1.2204 +}
  1.2205 +
  1.2206 +TEST_F(EHFrame, zR) {
  1.2207 +  Label cie;
  1.2208 +  DwarfPointerEncoding pointer_encoding =
  1.2209 +      DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
  1.2210 +                           | dwarf2reader::DW_EH_PE_sdata2);
  1.2211 +  section.SetPointerEncoding(pointer_encoding);
  1.2212 +  section
  1.2213 +      .Mark(&cie)
  1.2214 +      .CIEHeader(8011, 5496, 75, 1, "zR")
  1.2215 +      .ULEB128(1)                       // Augmentation data length
  1.2216 +      .D8(pointer_encoding)             // encoding for FDE addresses
  1.2217 +      .FinishEntry()
  1.2218 +      .FDEHeader(cie, 0x540f9431, 0xbd0)
  1.2219 +      .ULEB128(0)                       // Augmentation data length
  1.2220 +      .FinishEntry()
  1.2221 +      .D32(0);                          // terminator
  1.2222 +
  1.2223 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section);
  1.2224 +
  1.2225 +  EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75))
  1.2226 +      .InSequence(s).WillOnce(Return(true));
  1.2227 +  EXPECT_CALL(handler, End())
  1.2228 +      .InSequence(s).WillOnce(Return(true));
  1.2229 +
  1.2230 +  ParseEHFrameSection(&section);
  1.2231 +}
  1.2232 +
  1.2233 +TEST_F(EHFrame, zS) {
  1.2234 +  Label cie;
  1.2235 +  section
  1.2236 +      .Mark(&cie)
  1.2237 +      .CIEHeader(9217, 7694, 57, 1, "zS")
  1.2238 +      .ULEB128(0)                                // Augmentation data length
  1.2239 +      .FinishEntry()
  1.2240 +      .FDEHeader(cie, 0xd40091aa, 0x9aa6e746)
  1.2241 +      .ULEB128(0)                                // Augmentation data length
  1.2242 +      .FinishEntry()
  1.2243 +      .D32(0);                                   // terminator
  1.2244 +
  1.2245 +  PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section);
  1.2246 +
  1.2247 +  EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57))
  1.2248 +      .InSequence(s).WillOnce(Return(true));
  1.2249 +  EXPECT_CALL(handler, SignalHandler())
  1.2250 +      .InSequence(s).WillOnce(Return(true));
  1.2251 +  EXPECT_CALL(handler, End())
  1.2252 +      .InSequence(s).WillOnce(Return(true));
  1.2253 +
  1.2254 +  ParseEHFrameSection(&section);
  1.2255 +}
  1.2256 +
  1.2257 +// These tests require manual inspection of the test output.
  1.2258 +struct CFIReporterFixture {
  1.2259 +  CFIReporterFixture() : reporter("test file name", "test section name") { }
  1.2260 +  CallFrameInfo::Reporter reporter;
  1.2261 +};
  1.2262 +
  1.2263 +class CFIReporter: public CFIReporterFixture, public Test { };
  1.2264 +
  1.2265 +TEST_F(CFIReporter, Incomplete) {
  1.2266 +  reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown);
  1.2267 +}
  1.2268 +
  1.2269 +TEST_F(CFIReporter, EarlyEHTerminator) {
  1.2270 +  reporter.EarlyEHTerminator(0x0102030405060708ULL);
  1.2271 +}
  1.2272 +
  1.2273 +TEST_F(CFIReporter, CIEPointerOutOfRange) {
  1.2274 +  reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
  1.2275 +}
  1.2276 +
  1.2277 +TEST_F(CFIReporter, BadCIEId) {
  1.2278 +  reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
  1.2279 +}
  1.2280 +
  1.2281 +TEST_F(CFIReporter, UnrecognizedVersion) {
  1.2282 +  reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43);
  1.2283 +}
  1.2284 +
  1.2285 +TEST_F(CFIReporter, UnrecognizedAugmentation) {
  1.2286 +  reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles");
  1.2287 +}
  1.2288 +
  1.2289 +TEST_F(CFIReporter, InvalidPointerEncoding) {
  1.2290 +  reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42);
  1.2291 +}
  1.2292 +
  1.2293 +TEST_F(CFIReporter, UnusablePointerEncoding) {
  1.2294 +  reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42);
  1.2295 +}
  1.2296 +
  1.2297 +TEST_F(CFIReporter, RestoreInCIE) {
  1.2298 +  reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
  1.2299 +}
  1.2300 +
  1.2301 +TEST_F(CFIReporter, BadInstruction) {
  1.2302 +  reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE,
  1.2303 +                          0xfedcba9876543210ULL);
  1.2304 +}
  1.2305 +
  1.2306 +TEST_F(CFIReporter, NoCFARule) {
  1.2307 +  reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE,
  1.2308 +                     0xfedcba9876543210ULL);
  1.2309 +}
  1.2310 +
  1.2311 +TEST_F(CFIReporter, EmptyStateStack) {
  1.2312 +  reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator,
  1.2313 +                           0xfedcba9876543210ULL);
  1.2314 +}
  1.2315 +
  1.2316 +TEST_F(CFIReporter, ClearingCFARule) {
  1.2317 +  reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE,
  1.2318 +                           0xfedcba9876543210ULL);
  1.2319 +}
  1.2320 +
  1.2321 +#ifdef WRITE_ELF
  1.2322 +// See comments at the top of the file mentioning WRITE_ELF for details.
  1.2323 +
  1.2324 +using google_breakpad::test_assembler::Section;
  1.2325 +
  1.2326 +struct ELFSectionHeader {
  1.2327 +  ELFSectionHeader(unsigned int set_type)
  1.2328 +      : type(set_type), flags(0), address(0), link(0), info(0),
  1.2329 +        alignment(1), entry_size(0) { }
  1.2330 +  Label name;
  1.2331 +  unsigned int type;
  1.2332 +  uint64_t flags;
  1.2333 +  uint64_t address;
  1.2334 +  Label file_offset;
  1.2335 +  Label file_size;
  1.2336 +  unsigned int link;
  1.2337 +  unsigned int info;
  1.2338 +  uint64_t alignment;
  1.2339 +  uint64_t entry_size;
  1.2340 +};
  1.2341 +
  1.2342 +void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) {
  1.2343 +  (*table)
  1.2344 +      .D32(header.name)                   // name, index in string tbl
  1.2345 +      .D32(header.type)                   // type
  1.2346 +      .Address(header.flags)              // flags
  1.2347 +      .Address(header.address)            // address in memory
  1.2348 +      .Address(header.file_offset)        // offset in ELF file
  1.2349 +      .Address(header.file_size)          // length in bytes
  1.2350 +      .D32(header.link)                   // link to related section
  1.2351 +      .D32(header.info)                   // miscellaneous
  1.2352 +      .Address(header.alignment)          // alignment
  1.2353 +      .Address(header.entry_size);        // entry size
  1.2354 +}
  1.2355 +
  1.2356 +void WriteELFFrameSection(const char *filename, const char *cfi_name,
  1.2357 +                          const CFISection &cfi) {
  1.2358 +  int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64;
  1.2359 +  int elf_data = (cfi.endianness() == kBigEndian
  1.2360 +                  ? ELFDATA2MSB : ELFDATA2LSB);
  1.2361 +  CFISection elf(cfi.endianness(), cfi.AddressSize());
  1.2362 +  Label elf_header_size, section_table_offset;
  1.2363 +  elf
  1.2364 +      .Append("\x7f" "ELF")
  1.2365 +      .D8(elf_class)              // 32-bit or 64-bit ELF
  1.2366 +      .D8(elf_data)               // endianness
  1.2367 +      .D8(1)                      // ELF version
  1.2368 +      .D8(ELFOSABI_LINUX)         // Operating System/ABI indication
  1.2369 +      .D8(0)                      // ABI version
  1.2370 +      .Append(7, 0xda)            // padding
  1.2371 +      .D16(ET_EXEC)               // file type: executable file
  1.2372 +      .D16(EM_386)                // architecture: Intel IA-32
  1.2373 +      .D32(EV_CURRENT);           // ELF version
  1.2374 +  elf
  1.2375 +      .Address(0x0123456789abcdefULL) // program entry point
  1.2376 +      .Address(0)                 // program header offset
  1.2377 +      .Address(section_table_offset) // section header offset
  1.2378 +      .D32(0)                     // processor-specific flags
  1.2379 +      .D16(elf_header_size)       // ELF header size in bytes */
  1.2380 +      .D16(elf_class == ELFCLASS32 ? 32 : 56) // program header entry size
  1.2381 +      .D16(0)                     // program header table entry count
  1.2382 +      .D16(elf_class == ELFCLASS32 ? 40 : 64) // section header entry size
  1.2383 +      .D16(3)                     // section  count
  1.2384 +      .D16(1)                     // section name string table
  1.2385 +      .Mark(&elf_header_size);
  1.2386 +
  1.2387 +  // The null section. Every ELF file has one, as the first entry in
  1.2388 +  // the section header table.
  1.2389 +  ELFSectionHeader null_header(SHT_NULL);
  1.2390 +  null_header.file_offset = 0;
  1.2391 +  null_header.file_size = 0;
  1.2392 +
  1.2393 +  // The CFI section. The whole reason for writing out this ELF file
  1.2394 +  // is to put this in it so that we can run other dumping programs on
  1.2395 +  // it to check its contents.
  1.2396 +  ELFSectionHeader cfi_header(SHT_PROGBITS);
  1.2397 +  cfi_header.file_size = cfi.Size();
  1.2398 +
  1.2399 +  // The section holding the names of the sections. This is the
  1.2400 +  // section whose index appears in the e_shstrndx member of the ELF
  1.2401 +  // header.
  1.2402 +  ELFSectionHeader section_names_header(SHT_STRTAB);
  1.2403 +  CFISection section_names(cfi.endianness(), cfi.AddressSize());
  1.2404 +  section_names
  1.2405 +      .Mark(&null_header.name)
  1.2406 +      .AppendCString("")
  1.2407 +      .Mark(&section_names_header.name)
  1.2408 +      .AppendCString(".shstrtab")
  1.2409 +      .Mark(&cfi_header.name)
  1.2410 +      .AppendCString(cfi_name)
  1.2411 +      .Mark(&section_names_header.file_size);
  1.2412 +  
  1.2413 +  // Create the section table. The ELF header's e_shoff member refers
  1.2414 +  // to this, and the e_shnum member gives the number of entries it
  1.2415 +  // contains.
  1.2416 +  CFISection section_table(cfi.endianness(), cfi.AddressSize());
  1.2417 +  AppendSectionHeader(&section_table, null_header);
  1.2418 +  AppendSectionHeader(&section_table, section_names_header);
  1.2419 +  AppendSectionHeader(&section_table, cfi_header);
  1.2420 +
  1.2421 +  // Append the section table and the section contents to the ELF file.
  1.2422 +  elf
  1.2423 +      .Mark(&section_table_offset)
  1.2424 +      .Append(section_table)
  1.2425 +      .Mark(&section_names_header.file_offset)
  1.2426 +      .Append(section_names)
  1.2427 +      .Mark(&cfi_header.file_offset)
  1.2428 +      .Append(cfi);
  1.2429 +
  1.2430 +  string contents;
  1.2431 +  if (!elf.GetContents(&contents)) {
  1.2432 +    fprintf(stderr, "failed to get ELF file contents\n");
  1.2433 +    exit(1);
  1.2434 +  }
  1.2435 +
  1.2436 +  FILE *out = fopen(filename, "w");
  1.2437 +  if (!out) {
  1.2438 +    fprintf(stderr, "error opening ELF file '%s': %s\n",
  1.2439 +            filename, strerror(errno));
  1.2440 +    exit(1);
  1.2441 +  }
  1.2442 +
  1.2443 +  if (fwrite(contents.data(), 1, contents.size(), out) != contents.size()) {
  1.2444 +    fprintf(stderr, "error writing ELF data to '%s': %s\n",
  1.2445 +            filename, strerror(errno));
  1.2446 +    exit(1);
  1.2447 +  }
  1.2448 +
  1.2449 +  if (fclose(out) == EOF) {
  1.2450 +    fprintf(stderr, "error closing ELF file '%s': %s\n",
  1.2451 +            filename, strerror(errno));
  1.2452 +    exit(1);
  1.2453 +  }
  1.2454 +}
  1.2455 +#endif

mercurial