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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2010, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo
michael@0 33
michael@0 34 #include <stdlib.h>
michael@0 35
michael@0 36 #include <string>
michael@0 37 #include <vector>
michael@0 38
michael@0 39 // The '.eh_frame' format, used by the Linux C++ ABI for exception
michael@0 40 // handling, is poorly specified. To help test our support for .eh_frame,
michael@0 41 // if you #define WRITE_ELF while compiling this file, and add the
michael@0 42 // 'include' directory from the binutils, gcc, or gdb source tree to the
michael@0 43 // #include path, then each test that calls the
michael@0 44 // PERHAPS_WRITE_DEBUG_FRAME_FILE or PERHAPS_WRITE_EH_FRAME_FILE will write
michael@0 45 // an ELF file containing a .debug_frame or .eh_frame section; you can then
michael@0 46 // use tools like readelf to examine the test data, and check the tools'
michael@0 47 // interpretation against the test's intentions. Each ELF file is named
michael@0 48 // "cfitest-TEST", where TEST identifies the particular test.
michael@0 49 #ifdef WRITE_ELF
michael@0 50 #include <errno.h>
michael@0 51 #include <stdio.h>
michael@0 52 #include <string.h>
michael@0 53 extern "C" {
michael@0 54 // To compile with WRITE_ELF, you should add the 'include' directory
michael@0 55 // of the binutils, gcc, or gdb source tree to your #include path;
michael@0 56 // that directory contains this header.
michael@0 57 #include "elf/common.h"
michael@0 58 }
michael@0 59 #endif
michael@0 60
michael@0 61 #include "breakpad_googletest_includes.h"
michael@0 62 #include "common/dwarf/bytereader-inl.h"
michael@0 63 #include "common/dwarf/cfi_assembler.h"
michael@0 64 #include "common/dwarf/dwarf2reader.h"
michael@0 65 #include "common/using_std_string.h"
michael@0 66 #include "google_breakpad/common/breakpad_types.h"
michael@0 67
michael@0 68 using google_breakpad::CFISection;
michael@0 69 using google_breakpad::test_assembler::Label;
michael@0 70 using google_breakpad::test_assembler::kBigEndian;
michael@0 71 using google_breakpad::test_assembler::kLittleEndian;
michael@0 72 using google_breakpad::test_assembler::Section;
michael@0 73
michael@0 74 using dwarf2reader::DwarfPointerEncoding;
michael@0 75 using dwarf2reader::ENDIANNESS_BIG;
michael@0 76 using dwarf2reader::ENDIANNESS_LITTLE;
michael@0 77 using dwarf2reader::ByteReader;
michael@0 78 using dwarf2reader::CallFrameInfo;
michael@0 79
michael@0 80 using std::vector;
michael@0 81 using testing::InSequence;
michael@0 82 using testing::Return;
michael@0 83 using testing::Sequence;
michael@0 84 using testing::Test;
michael@0 85 using testing::_;
michael@0 86
michael@0 87 #ifdef WRITE_ELF
michael@0 88 void WriteELFFrameSection(const char *filename, const char *section_name,
michael@0 89 const CFISection &section);
michael@0 90 #define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \
michael@0 91 WriteELFFrameSection("cfitest-" name, ".debug_frame", section);
michael@0 92 #define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \
michael@0 93 WriteELFFrameSection("cfitest-" name, ".eh_frame", section);
michael@0 94 #else
michael@0 95 #define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section)
michael@0 96 #define PERHAPS_WRITE_EH_FRAME_FILE(name, section)
michael@0 97 #endif
michael@0 98
michael@0 99 class MockCallFrameInfoHandler: public CallFrameInfo::Handler {
michael@0 100 public:
michael@0 101 MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length,
michael@0 102 uint8 version, const string &augmentation,
michael@0 103 unsigned return_address));
michael@0 104 MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg));
michael@0 105 MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg));
michael@0 106 MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register,
michael@0 107 long offset));
michael@0 108 MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register,
michael@0 109 long offset));
michael@0 110 MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register));
michael@0 111 MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg,
michael@0 112 const string &expression));
michael@0 113 MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg,
michael@0 114 const string &expression));
michael@0 115 MOCK_METHOD0(End, bool());
michael@0 116 MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect));
michael@0 117 MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect));
michael@0 118 MOCK_METHOD0(SignalHandler, bool());
michael@0 119 };
michael@0 120
michael@0 121 class MockCallFrameErrorReporter: public CallFrameInfo::Reporter {
michael@0 122 public:
michael@0 123 MockCallFrameErrorReporter() : Reporter("mock filename", "mock section") { }
michael@0 124 MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind));
michael@0 125 MOCK_METHOD1(EarlyEHTerminator, void(uint64));
michael@0 126 MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64));
michael@0 127 MOCK_METHOD2(BadCIEId, void(uint64, uint64));
michael@0 128 MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version));
michael@0 129 MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &));
michael@0 130 MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8));
michael@0 131 MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8));
michael@0 132 MOCK_METHOD2(RestoreInCIE, void(uint64, uint64));
michael@0 133 MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64));
michael@0 134 MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64));
michael@0 135 MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64));
michael@0 136 };
michael@0 137
michael@0 138 struct CFIFixture {
michael@0 139
michael@0 140 enum { kCFARegister = CallFrameInfo::Handler::kCFARegister };
michael@0 141
michael@0 142 CFIFixture() {
michael@0 143 // Default expectations for the data handler.
michael@0 144 //
michael@0 145 // - Leave Entry and End without expectations, as it's probably a
michael@0 146 // good idea to set those explicitly in each test.
michael@0 147 //
michael@0 148 // - Expect the *Rule functions to not be called,
michael@0 149 // so that each test can simply list the calls they expect.
michael@0 150 //
michael@0 151 // I gather I could use StrictMock for this, but the manual seems
michael@0 152 // to suggest using that only as a last resort, and this isn't so
michael@0 153 // bad.
michael@0 154 EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0);
michael@0 155 EXPECT_CALL(handler, SameValueRule(_, _)).Times(0);
michael@0 156 EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0);
michael@0 157 EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0);
michael@0 158 EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0);
michael@0 159 EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0);
michael@0 160 EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0);
michael@0 161 EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0);
michael@0 162 EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0);
michael@0 163 EXPECT_CALL(handler, SignalHandler()).Times(0);
michael@0 164
michael@0 165 // Default expectations for the error/warning reporer.
michael@0 166 EXPECT_CALL(reporter, Incomplete(_, _)).Times(0);
michael@0 167 EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0);
michael@0 168 EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0);
michael@0 169 EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0);
michael@0 170 EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0);
michael@0 171 EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0);
michael@0 172 EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0);
michael@0 173 EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0);
michael@0 174 EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0);
michael@0 175 EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0);
michael@0 176 EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0);
michael@0 177 EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0);
michael@0 178 }
michael@0 179
michael@0 180 MockCallFrameInfoHandler handler;
michael@0 181 MockCallFrameErrorReporter reporter;
michael@0 182 };
michael@0 183
michael@0 184 class CFI: public CFIFixture, public Test { };
michael@0 185
michael@0 186 TEST_F(CFI, EmptyRegion) {
michael@0 187 EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
michael@0 188 EXPECT_CALL(handler, End()).Times(0);
michael@0 189 static const char data[1] = { 42 };
michael@0 190
michael@0 191 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 192 CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter);
michael@0 193 EXPECT_TRUE(parser.Start());
michael@0 194 }
michael@0 195
michael@0 196 TEST_F(CFI, IncompleteLength32) {
michael@0 197 CFISection section(kBigEndian, 8);
michael@0 198 section
michael@0 199 // Not even long enough for an initial length.
michael@0 200 .D16(0xa0f)
michael@0 201 // Padding to keep valgrind happy. We subtract these off when we
michael@0 202 // construct the parser.
michael@0 203 .D16(0);
michael@0 204
michael@0 205 EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
michael@0 206 EXPECT_CALL(handler, End()).Times(0);
michael@0 207
michael@0 208 EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
michael@0 209 .WillOnce(Return());
michael@0 210
michael@0 211 string contents;
michael@0 212 ASSERT_TRUE(section.GetContents(&contents));
michael@0 213
michael@0 214 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 215 byte_reader.SetAddressSize(8);
michael@0 216 CallFrameInfo parser(contents.data(), contents.size() - 2,
michael@0 217 &byte_reader, &handler, &reporter);
michael@0 218 EXPECT_FALSE(parser.Start());
michael@0 219 }
michael@0 220
michael@0 221 TEST_F(CFI, IncompleteLength64) {
michael@0 222 CFISection section(kLittleEndian, 4);
michael@0 223 section
michael@0 224 // An incomplete 64-bit DWARF initial length.
michael@0 225 .D32(0xffffffff).D32(0x71fbaec2)
michael@0 226 // Padding to keep valgrind happy. We subtract these off when we
michael@0 227 // construct the parser.
michael@0 228 .D32(0);
michael@0 229
michael@0 230 EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
michael@0 231 EXPECT_CALL(handler, End()).Times(0);
michael@0 232
michael@0 233 EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
michael@0 234 .WillOnce(Return());
michael@0 235
michael@0 236 string contents;
michael@0 237 ASSERT_TRUE(section.GetContents(&contents));
michael@0 238
michael@0 239 ByteReader byte_reader(ENDIANNESS_LITTLE);
michael@0 240 byte_reader.SetAddressSize(4);
michael@0 241 CallFrameInfo parser(contents.data(), contents.size() - 4,
michael@0 242 &byte_reader, &handler, &reporter);
michael@0 243 EXPECT_FALSE(parser.Start());
michael@0 244 }
michael@0 245
michael@0 246 TEST_F(CFI, IncompleteId32) {
michael@0 247 CFISection section(kBigEndian, 8);
michael@0 248 section
michael@0 249 .D32(3) // Initial length, not long enough for id
michael@0 250 .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id
michael@0 251 .CIEHeader(8727, 3983, 8889, 3, "")
michael@0 252 .FinishEntry();
michael@0 253
michael@0 254 EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
michael@0 255 EXPECT_CALL(handler, End()).Times(0);
michael@0 256
michael@0 257 EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
michael@0 258 .WillOnce(Return());
michael@0 259
michael@0 260 string contents;
michael@0 261 ASSERT_TRUE(section.GetContents(&contents));
michael@0 262
michael@0 263 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 264 byte_reader.SetAddressSize(8);
michael@0 265 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 266 &byte_reader, &handler, &reporter);
michael@0 267 EXPECT_FALSE(parser.Start());
michael@0 268 }
michael@0 269
michael@0 270 TEST_F(CFI, BadId32) {
michael@0 271 CFISection section(kBigEndian, 8);
michael@0 272 section
michael@0 273 .D32(0x100) // Initial length
michael@0 274 .D32(0xe802fade) // bogus ID
michael@0 275 .Append(0x100 - 4, 0x42); // make the length true
michael@0 276 section
michael@0 277 .CIEHeader(1672, 9872, 8529, 3, "")
michael@0 278 .FinishEntry();
michael@0 279
michael@0 280 EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
michael@0 281 EXPECT_CALL(handler, End()).Times(0);
michael@0 282
michael@0 283 EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade))
michael@0 284 .WillOnce(Return());
michael@0 285
michael@0 286 string contents;
michael@0 287 ASSERT_TRUE(section.GetContents(&contents));
michael@0 288
michael@0 289 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 290 byte_reader.SetAddressSize(8);
michael@0 291 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 292 &byte_reader, &handler, &reporter);
michael@0 293 EXPECT_FALSE(parser.Start());
michael@0 294 }
michael@0 295
michael@0 296 // A lone CIE shouldn't cause any handler calls.
michael@0 297 TEST_F(CFI, SingleCIE) {
michael@0 298 CFISection section(kLittleEndian, 4);
michael@0 299 section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, "");
michael@0 300 section.Append(10, dwarf2reader::DW_CFA_nop);
michael@0 301 section.FinishEntry();
michael@0 302
michael@0 303 PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section);
michael@0 304
michael@0 305 EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
michael@0 306 EXPECT_CALL(handler, End()).Times(0);
michael@0 307
michael@0 308 string contents;
michael@0 309 EXPECT_TRUE(section.GetContents(&contents));
michael@0 310 ByteReader byte_reader(ENDIANNESS_LITTLE);
michael@0 311 byte_reader.SetAddressSize(4);
michael@0 312 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 313 &byte_reader, &handler, &reporter);
michael@0 314 EXPECT_TRUE(parser.Start());
michael@0 315 }
michael@0 316
michael@0 317 // One FDE, one CIE.
michael@0 318 TEST_F(CFI, OneFDE) {
michael@0 319 CFISection section(kBigEndian, 4);
michael@0 320 Label cie;
michael@0 321 section
michael@0 322 .Mark(&cie)
michael@0 323 .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "")
michael@0 324 .FinishEntry()
michael@0 325 .FDEHeader(cie, 0x7714740d, 0x3d5a10cd)
michael@0 326 .FinishEntry();
michael@0 327
michael@0 328 PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section);
michael@0 329
michael@0 330 {
michael@0 331 InSequence s;
michael@0 332 EXPECT_CALL(handler,
michael@0 333 Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87))
michael@0 334 .WillOnce(Return(true));
michael@0 335 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 336 }
michael@0 337
michael@0 338 string contents;
michael@0 339 EXPECT_TRUE(section.GetContents(&contents));
michael@0 340 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 341 byte_reader.SetAddressSize(4);
michael@0 342 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 343 &byte_reader, &handler, &reporter);
michael@0 344 EXPECT_TRUE(parser.Start());
michael@0 345 }
michael@0 346
michael@0 347 // Two FDEs share a CIE.
michael@0 348 TEST_F(CFI, TwoFDEsOneCIE) {
michael@0 349 CFISection section(kBigEndian, 4);
michael@0 350 Label cie;
michael@0 351 section
michael@0 352 // First FDE. readelf complains about this one because it makes
michael@0 353 // a forward reference to its CIE.
michael@0 354 .FDEHeader(cie, 0xa42744df, 0xa3b42121)
michael@0 355 .FinishEntry()
michael@0 356 // CIE.
michael@0 357 .Mark(&cie)
michael@0 358 .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "")
michael@0 359 .FinishEntry()
michael@0 360 // Second FDE.
michael@0 361 .FDEHeader(cie, 0x6057d391, 0x700f608d)
michael@0 362 .FinishEntry();
michael@0 363
michael@0 364 PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section);
michael@0 365
michael@0 366 {
michael@0 367 InSequence s;
michael@0 368 EXPECT_CALL(handler,
michael@0 369 Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59))
michael@0 370 .WillOnce(Return(true));
michael@0 371 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 372 }
michael@0 373 {
michael@0 374 InSequence s;
michael@0 375 EXPECT_CALL(handler,
michael@0 376 Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59))
michael@0 377 .WillOnce(Return(true));
michael@0 378 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 379 }
michael@0 380
michael@0 381 string contents;
michael@0 382 EXPECT_TRUE(section.GetContents(&contents));
michael@0 383 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 384 byte_reader.SetAddressSize(4);
michael@0 385 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 386 &byte_reader, &handler, &reporter);
michael@0 387 EXPECT_TRUE(parser.Start());
michael@0 388 }
michael@0 389
michael@0 390 // Two FDEs, two CIEs.
michael@0 391 TEST_F(CFI, TwoFDEsTwoCIEs) {
michael@0 392 CFISection section(kLittleEndian, 8);
michael@0 393 Label cie1, cie2;
michael@0 394 section
michael@0 395 // First CIE.
michael@0 396 .Mark(&cie1)
michael@0 397 .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "")
michael@0 398 .FinishEntry()
michael@0 399 // First FDE which cites second CIE. readelf complains about
michael@0 400 // this one because it makes a forward reference to its CIE.
michael@0 401 .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL)
michael@0 402 .FinishEntry()
michael@0 403 // Second FDE, which cites first CIE.
michael@0 404 .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL)
michael@0 405 .FinishEntry()
michael@0 406 // Second CIE.
michael@0 407 .Mark(&cie2)
michael@0 408 .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "")
michael@0 409 .FinishEntry();
michael@0 410
michael@0 411 PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section);
michael@0 412
michael@0 413 {
michael@0 414 InSequence s;
michael@0 415 EXPECT_CALL(handler,
michael@0 416 Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2,
michael@0 417 "", 0x61d2c581))
michael@0 418 .WillOnce(Return(true));
michael@0 419 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 420 }
michael@0 421 {
michael@0 422 InSequence s;
michael@0 423 EXPECT_CALL(handler,
michael@0 424 Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3,
michael@0 425 "", 0xbf45e65a))
michael@0 426 .WillOnce(Return(true));
michael@0 427 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 428 }
michael@0 429
michael@0 430 string contents;
michael@0 431 EXPECT_TRUE(section.GetContents(&contents));
michael@0 432 ByteReader byte_reader(ENDIANNESS_LITTLE);
michael@0 433 byte_reader.SetAddressSize(8);
michael@0 434 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 435 &byte_reader, &handler, &reporter);
michael@0 436 EXPECT_TRUE(parser.Start());
michael@0 437 }
michael@0 438
michael@0 439 // An FDE whose CIE specifies a version we don't recognize.
michael@0 440 TEST_F(CFI, BadVersion) {
michael@0 441 CFISection section(kBigEndian, 4);
michael@0 442 Label cie1, cie2;
michael@0 443 section
michael@0 444 .Mark(&cie1)
michael@0 445 .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "")
michael@0 446 .FinishEntry()
michael@0 447 // We should skip this entry, as its CIE specifies a version we
michael@0 448 // don't recognize.
michael@0 449 .FDEHeader(cie1, 0x08852292, 0x2204004a)
michael@0 450 .FinishEntry()
michael@0 451 // Despite the above, we should visit this entry.
michael@0 452 .Mark(&cie2)
michael@0 453 .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "")
michael@0 454 .FinishEntry()
michael@0 455 .FDEHeader(cie2, 0x2094735a, 0x6e875501)
michael@0 456 .FinishEntry();
michael@0 457
michael@0 458 PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section);
michael@0 459
michael@0 460 EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52))
michael@0 461 .WillOnce(Return());
michael@0 462
michael@0 463 {
michael@0 464 InSequence s;
michael@0 465 // We should see no mention of the first FDE, but we should get
michael@0 466 // a call to Entry for the second.
michael@0 467 EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "",
michael@0 468 0x96cb3264))
michael@0 469 .WillOnce(Return(true));
michael@0 470 EXPECT_CALL(handler, End())
michael@0 471 .WillOnce(Return(true));
michael@0 472 }
michael@0 473
michael@0 474 string contents;
michael@0 475 EXPECT_TRUE(section.GetContents(&contents));
michael@0 476 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 477 byte_reader.SetAddressSize(4);
michael@0 478 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 479 &byte_reader, &handler, &reporter);
michael@0 480 EXPECT_FALSE(parser.Start());
michael@0 481 }
michael@0 482
michael@0 483 // An FDE whose CIE specifies an augmentation we don't recognize.
michael@0 484 TEST_F(CFI, BadAugmentation) {
michael@0 485 CFISection section(kBigEndian, 4);
michael@0 486 Label cie1, cie2;
michael@0 487 section
michael@0 488 .Mark(&cie1)
michael@0 489 .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!")
michael@0 490 .FinishEntry()
michael@0 491 // We should skip this entry, as its CIE specifies an
michael@0 492 // augmentation we don't recognize.
michael@0 493 .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd)
michael@0 494 .FinishEntry()
michael@0 495 // Despite the above, we should visit this entry.
michael@0 496 .Mark(&cie2)
michael@0 497 .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "")
michael@0 498 .FinishEntry()
michael@0 499 .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8)
michael@0 500 .FinishEntry();
michael@0 501
michael@0 502 PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section);
michael@0 503
michael@0 504 EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!"))
michael@0 505 .WillOnce(Return());
michael@0 506
michael@0 507 {
michael@0 508 InSequence s;
michael@0 509 // We should see no mention of the first FDE, but we should get
michael@0 510 // a call to Entry for the second.
michael@0 511 EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "",
michael@0 512 0xf2f519b2))
michael@0 513 .WillOnce(Return(true));
michael@0 514 EXPECT_CALL(handler, End())
michael@0 515 .WillOnce(Return(true));
michael@0 516 }
michael@0 517
michael@0 518 string contents;
michael@0 519 EXPECT_TRUE(section.GetContents(&contents));
michael@0 520 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 521 byte_reader.SetAddressSize(4);
michael@0 522 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 523 &byte_reader, &handler, &reporter);
michael@0 524 EXPECT_FALSE(parser.Start());
michael@0 525 }
michael@0 526
michael@0 527 // The return address column field is a byte in CFI version 1
michael@0 528 // (DWARF2), but a ULEB128 value in version 3 (DWARF3).
michael@0 529 TEST_F(CFI, CIEVersion1ReturnColumn) {
michael@0 530 CFISection section(kBigEndian, 4);
michael@0 531 Label cie;
michael@0 532 section
michael@0 533 // CIE, using the version 1 format: return column is a ubyte.
michael@0 534 .Mark(&cie)
michael@0 535 // Use a value for the return column that is parsed differently
michael@0 536 // as a ubyte and as a ULEB128.
michael@0 537 .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "")
michael@0 538 .FinishEntry()
michael@0 539 // FDE, citing that CIE.
michael@0 540 .FDEHeader(cie, 0xb8d347b5, 0x825e55dc)
michael@0 541 .FinishEntry();
michael@0 542
michael@0 543 PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section);
michael@0 544
michael@0 545 {
michael@0 546 InSequence s;
michael@0 547 EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f))
michael@0 548 .WillOnce(Return(true));
michael@0 549 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 550 }
michael@0 551
michael@0 552 string contents;
michael@0 553 EXPECT_TRUE(section.GetContents(&contents));
michael@0 554 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 555 byte_reader.SetAddressSize(4);
michael@0 556 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 557 &byte_reader, &handler, &reporter);
michael@0 558 EXPECT_TRUE(parser.Start());
michael@0 559 }
michael@0 560
michael@0 561 // The return address column field is a byte in CFI version 1
michael@0 562 // (DWARF2), but a ULEB128 value in version 3 (DWARF3).
michael@0 563 TEST_F(CFI, CIEVersion3ReturnColumn) {
michael@0 564 CFISection section(kBigEndian, 4);
michael@0 565 Label cie;
michael@0 566 section
michael@0 567 // CIE, using the version 3 format: return column is a ULEB128.
michael@0 568 .Mark(&cie)
michael@0 569 // Use a value for the return column that is parsed differently
michael@0 570 // as a ubyte and as a ULEB128.
michael@0 571 .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "")
michael@0 572 .FinishEntry()
michael@0 573 // FDE, citing that CIE.
michael@0 574 .FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
michael@0 575 .FinishEntry();
michael@0 576
michael@0 577 PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section);
michael@0 578
michael@0 579 {
michael@0 580 InSequence s;
michael@0 581 EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89))
michael@0 582 .WillOnce(Return(true));
michael@0 583 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 584 }
michael@0 585
michael@0 586 string contents;
michael@0 587 EXPECT_TRUE(section.GetContents(&contents));
michael@0 588 ByteReader byte_reader(ENDIANNESS_BIG);
michael@0 589 byte_reader.SetAddressSize(4);
michael@0 590 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 591 &byte_reader, &handler, &reporter);
michael@0 592 EXPECT_TRUE(parser.Start());
michael@0 593 }
michael@0 594
michael@0 595 struct CFIInsnFixture: public CFIFixture {
michael@0 596 CFIInsnFixture() : CFIFixture() {
michael@0 597 data_factor = 0xb6f;
michael@0 598 return_register = 0x9be1ed9f;
michael@0 599 version = 3;
michael@0 600 cfa_base_register = 0x383a3aa;
michael@0 601 cfa_offset = 0xf748;
michael@0 602 }
michael@0 603
michael@0 604 // Prepare SECTION to receive FDE instructions.
michael@0 605 //
michael@0 606 // - Append a stock CIE header that establishes the fixture's
michael@0 607 // code_factor, data_factor, return_register, version, and
michael@0 608 // augmentation values.
michael@0 609 // - Have the CIE set up a CFA rule using cfa_base_register and
michael@0 610 // cfa_offset.
michael@0 611 // - Append a stock FDE header, referring to the above CIE, for the
michael@0 612 // fde_size bytes at fde_start. Choose fde_start and fde_size
michael@0 613 // appropriately for the section's address size.
michael@0 614 // - Set appropriate expectations on handler in sequence s for the
michael@0 615 // frame description entry and the CIE's CFA rule.
michael@0 616 //
michael@0 617 // On return, SECTION is ready to have FDE instructions appended to
michael@0 618 // it, and its FinishEntry member called.
michael@0 619 void StockCIEAndFDE(CFISection *section) {
michael@0 620 // Choose appropriate constants for our address size.
michael@0 621 if (section->AddressSize() == 4) {
michael@0 622 fde_start = 0xc628ecfbU;
michael@0 623 fde_size = 0x5dee04a2;
michael@0 624 code_factor = 0x60b;
michael@0 625 } else {
michael@0 626 assert(section->AddressSize() == 8);
michael@0 627 fde_start = 0x0005c57ce7806bd3ULL;
michael@0 628 fde_size = 0x2699521b5e333100ULL;
michael@0 629 code_factor = 0x01008e32855274a8ULL;
michael@0 630 }
michael@0 631
michael@0 632 // Create the CIE.
michael@0 633 (*section)
michael@0 634 .Mark(&cie_label)
michael@0 635 .CIEHeader(code_factor, data_factor, return_register, version,
michael@0 636 "")
michael@0 637 .D8(dwarf2reader::DW_CFA_def_cfa)
michael@0 638 .ULEB128(cfa_base_register)
michael@0 639 .ULEB128(cfa_offset)
michael@0 640 .FinishEntry();
michael@0 641
michael@0 642 // Create the FDE.
michael@0 643 section->FDEHeader(cie_label, fde_start, fde_size);
michael@0 644
michael@0 645 // Expect an Entry call for the FDE and a ValOffsetRule call for the
michael@0 646 // CIE's CFA rule.
michael@0 647 EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "",
michael@0 648 return_register))
michael@0 649 .InSequence(s)
michael@0 650 .WillOnce(Return(true));
michael@0 651 EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister,
michael@0 652 cfa_base_register, cfa_offset))
michael@0 653 .InSequence(s)
michael@0 654 .WillOnce(Return(true));
michael@0 655 }
michael@0 656
michael@0 657 // Run the contents of SECTION through a CallFrameInfo parser,
michael@0 658 // expecting parser.Start to return SUCCEEDS
michael@0 659 void ParseSection(CFISection *section, bool succeeds = true) {
michael@0 660 string contents;
michael@0 661 EXPECT_TRUE(section->GetContents(&contents));
michael@0 662 dwarf2reader::Endianness endianness;
michael@0 663 if (section->endianness() == kBigEndian)
michael@0 664 endianness = ENDIANNESS_BIG;
michael@0 665 else {
michael@0 666 assert(section->endianness() == kLittleEndian);
michael@0 667 endianness = ENDIANNESS_LITTLE;
michael@0 668 }
michael@0 669 ByteReader byte_reader(endianness);
michael@0 670 byte_reader.SetAddressSize(section->AddressSize());
michael@0 671 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 672 &byte_reader, &handler, &reporter);
michael@0 673 if (succeeds)
michael@0 674 EXPECT_TRUE(parser.Start());
michael@0 675 else
michael@0 676 EXPECT_FALSE(parser.Start());
michael@0 677 }
michael@0 678
michael@0 679 Label cie_label;
michael@0 680 Sequence s;
michael@0 681 uint64 code_factor;
michael@0 682 int data_factor;
michael@0 683 unsigned return_register;
michael@0 684 unsigned version;
michael@0 685 unsigned cfa_base_register;
michael@0 686 int cfa_offset;
michael@0 687 uint64 fde_start, fde_size;
michael@0 688 };
michael@0 689
michael@0 690 class CFIInsn: public CFIInsnFixture, public Test { };
michael@0 691
michael@0 692 TEST_F(CFIInsn, DW_CFA_set_loc) {
michael@0 693 CFISection section(kBigEndian, 4);
michael@0 694 StockCIEAndFDE(&section);
michael@0 695 section
michael@0 696 .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a)
michael@0 697 // Use DW_CFA_def_cfa to force a handler call that we can use to
michael@0 698 // check the effect of the DW_CFA_set_loc.
michael@0 699 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee)
michael@0 700 .FinishEntry();
michael@0 701
michael@0 702 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section);
michael@0 703
michael@0 704 EXPECT_CALL(handler,
michael@0 705 ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee))
michael@0 706 .InSequence(s)
michael@0 707 .WillOnce(Return(true));
michael@0 708 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 709
michael@0 710 ParseSection(&section);
michael@0 711 }
michael@0 712
michael@0 713 TEST_F(CFIInsn, DW_CFA_advance_loc) {
michael@0 714 CFISection section(kBigEndian, 8);
michael@0 715 StockCIEAndFDE(&section);
michael@0 716 section
michael@0 717 .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a)
michael@0 718 // Use DW_CFA_def_cfa to force a handler call that we can use to
michael@0 719 // check the effect of the DW_CFA_advance_loc.
michael@0 720 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf)
michael@0 721 .FinishEntry();
michael@0 722
michael@0 723 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section);
michael@0 724
michael@0 725 EXPECT_CALL(handler,
michael@0 726 ValOffsetRule(fde_start + 0x2a * code_factor,
michael@0 727 kCFARegister, 0x5bbb3715, 0x0186c7bf))
michael@0 728 .InSequence(s)
michael@0 729 .WillOnce(Return(true));
michael@0 730 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 731
michael@0 732 ParseSection(&section);
michael@0 733 }
michael@0 734
michael@0 735 TEST_F(CFIInsn, DW_CFA_advance_loc1) {
michael@0 736 CFISection section(kLittleEndian, 8);
michael@0 737 StockCIEAndFDE(&section);
michael@0 738 section
michael@0 739 .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8)
michael@0 740 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93)
michael@0 741 .FinishEntry();
michael@0 742
michael@0 743 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section);
michael@0 744
michael@0 745 EXPECT_CALL(handler,
michael@0 746 ValOffsetRule((fde_start + 0xd8 * code_factor),
michael@0 747 kCFARegister, 0x69d5696a, 0x1eb7fc93))
michael@0 748 .InSequence(s)
michael@0 749 .WillOnce(Return(true));
michael@0 750 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 751
michael@0 752 ParseSection(&section);
michael@0 753 }
michael@0 754
michael@0 755 TEST_F(CFIInsn, DW_CFA_advance_loc2) {
michael@0 756 CFISection section(kLittleEndian, 4);
michael@0 757 StockCIEAndFDE(&section);
michael@0 758 section
michael@0 759 .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb)
michael@0 760 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37)
michael@0 761 .FinishEntry();
michael@0 762
michael@0 763 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section);
michael@0 764
michael@0 765 EXPECT_CALL(handler,
michael@0 766 ValOffsetRule((fde_start + 0x3adb * code_factor),
michael@0 767 kCFARegister, 0x3a368bed, 0x3194ee37))
michael@0 768 .InSequence(s)
michael@0 769 .WillOnce(Return(true));
michael@0 770 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 771
michael@0 772 ParseSection(&section);
michael@0 773 }
michael@0 774
michael@0 775 TEST_F(CFIInsn, DW_CFA_advance_loc4) {
michael@0 776 CFISection section(kBigEndian, 8);
michael@0 777 StockCIEAndFDE(&section);
michael@0 778 section
michael@0 779 .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88)
michael@0 780 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb)
michael@0 781 .FinishEntry();
michael@0 782
michael@0 783 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section);
michael@0 784
michael@0 785 EXPECT_CALL(handler,
michael@0 786 ValOffsetRule((fde_start + 0x15813c88ULL * code_factor),
michael@0 787 kCFARegister, 0x135270c5, 0x24bad7cb))
michael@0 788 .InSequence(s)
michael@0 789 .WillOnce(Return(true));
michael@0 790 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 791
michael@0 792 ParseSection(&section);
michael@0 793 }
michael@0 794
michael@0 795 TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) {
michael@0 796 code_factor = 0x2d;
michael@0 797 CFISection section(kBigEndian, 8);
michael@0 798 StockCIEAndFDE(&section);
michael@0 799 section
michael@0 800 .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL)
michael@0 801 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f)
michael@0 802 .FinishEntry();
michael@0 803
michael@0 804 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section);
michael@0 805
michael@0 806 EXPECT_CALL(handler,
michael@0 807 ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor),
michael@0 808 kCFARegister, 0xe17ed602, 0x3d162e7f))
michael@0 809 .InSequence(s)
michael@0 810 .WillOnce(Return(true));
michael@0 811 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 812
michael@0 813 ParseSection(&section);
michael@0 814 }
michael@0 815
michael@0 816 TEST_F(CFIInsn, DW_CFA_def_cfa) {
michael@0 817 CFISection section(kLittleEndian, 4);
michael@0 818 StockCIEAndFDE(&section);
michael@0 819 section
michael@0 820 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7)
michael@0 821 .FinishEntry();
michael@0 822
michael@0 823 PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section);
michael@0 824
michael@0 825 EXPECT_CALL(handler,
michael@0 826 ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7))
michael@0 827 .InSequence(s).WillOnce(Return(true));
michael@0 828 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 829
michael@0 830 ParseSection(&section);
michael@0 831 }
michael@0 832
michael@0 833 TEST_F(CFIInsn, DW_CFA_def_cfa_sf) {
michael@0 834 CFISection section(kBigEndian, 4);
michael@0 835 StockCIEAndFDE(&section);
michael@0 836 section
michael@0 837 .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea)
michael@0 838 .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2)
michael@0 839 .FinishEntry();
michael@0 840
michael@0 841 EXPECT_CALL(handler,
michael@0 842 ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7,
michael@0 843 0x9ea * data_factor))
michael@0 844 .InSequence(s).WillOnce(Return(true));
michael@0 845 EXPECT_CALL(handler,
michael@0 846 ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da,
michael@0 847 -0x40a2 * data_factor))
michael@0 848 .InSequence(s).WillOnce(Return(true));
michael@0 849 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 850
michael@0 851 ParseSection(&section);
michael@0 852 }
michael@0 853
michael@0 854 TEST_F(CFIInsn, DW_CFA_def_cfa_register) {
michael@0 855 CFISection section(kLittleEndian, 8);
michael@0 856 StockCIEAndFDE(&section);
michael@0 857 section
michael@0 858 .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363)
michael@0 859 .FinishEntry();
michael@0 860
michael@0 861 EXPECT_CALL(handler,
michael@0 862 ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset))
michael@0 863 .InSequence(s).WillOnce(Return(true));
michael@0 864 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 865
michael@0 866 ParseSection(&section);
michael@0 867 }
michael@0 868
michael@0 869 // DW_CFA_def_cfa_register should have no effect when applied to a
michael@0 870 // non-base/offset rule.
michael@0 871 TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) {
michael@0 872 CFISection section(kBigEndian, 4);
michael@0 873 StockCIEAndFDE(&section);
michael@0 874 section
michael@0 875 .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack")
michael@0 876 .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49)
michael@0 877 .FinishEntry();
michael@0 878
michael@0 879 EXPECT_CALL(handler,
michael@0 880 ValExpressionRule(fde_start, kCFARegister,
michael@0 881 "needle in a haystack"))
michael@0 882 .WillRepeatedly(Return(true));
michael@0 883 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 884
michael@0 885 ParseSection(&section);
michael@0 886 }
michael@0 887
michael@0 888 TEST_F(CFIInsn, DW_CFA_def_cfa_offset) {
michael@0 889 CFISection section(kBigEndian, 4);
michael@0 890 StockCIEAndFDE(&section);
michael@0 891 section
michael@0 892 .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
michael@0 893 .FinishEntry();
michael@0 894
michael@0 895 EXPECT_CALL(handler,
michael@0 896 ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
michael@0 897 0x1e8e3b9b))
michael@0 898 .InSequence(s).WillOnce(Return(true));
michael@0 899 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 900
michael@0 901 ParseSection(&section);
michael@0 902 }
michael@0 903
michael@0 904 TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) {
michael@0 905 CFISection section(kLittleEndian, 4);
michael@0 906 StockCIEAndFDE(&section);
michael@0 907 section
michael@0 908 .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970)
michael@0 909 .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd)
michael@0 910 .FinishEntry();
michael@0 911
michael@0 912 EXPECT_CALL(handler,
michael@0 913 ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
michael@0 914 0x970 * data_factor))
michael@0 915 .InSequence(s).WillOnce(Return(true));
michael@0 916 EXPECT_CALL(handler,
michael@0 917 ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
michael@0 918 -0x2cd * data_factor))
michael@0 919 .InSequence(s).WillOnce(Return(true));
michael@0 920 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 921
michael@0 922 ParseSection(&section);
michael@0 923 }
michael@0 924
michael@0 925 // DW_CFA_def_cfa_offset should have no effect when applied to a
michael@0 926 // non-base/offset rule.
michael@0 927 TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) {
michael@0 928 CFISection section(kBigEndian, 4);
michael@0 929 StockCIEAndFDE(&section);
michael@0 930 section
michael@0 931 .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday")
michael@0 932 .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
michael@0 933 .FinishEntry();
michael@0 934
michael@0 935 EXPECT_CALL(handler,
michael@0 936 ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday"))
michael@0 937 .WillRepeatedly(Return(true));
michael@0 938 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 939
michael@0 940 ParseSection(&section);
michael@0 941 }
michael@0 942
michael@0 943 TEST_F(CFIInsn, DW_CFA_def_cfa_expression) {
michael@0 944 CFISection section(kLittleEndian, 8);
michael@0 945 StockCIEAndFDE(&section);
michael@0 946 section
michael@0 947 .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow")
michael@0 948 .FinishEntry();
michael@0 949
michael@0 950 EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister,
michael@0 951 "eating crow"))
michael@0 952 .InSequence(s).WillOnce(Return(true));
michael@0 953 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 954
michael@0 955 ParseSection(&section);
michael@0 956 }
michael@0 957
michael@0 958 TEST_F(CFIInsn, DW_CFA_undefined) {
michael@0 959 CFISection section(kLittleEndian, 4);
michael@0 960 StockCIEAndFDE(&section);
michael@0 961 section
michael@0 962 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d)
michael@0 963 .FinishEntry();
michael@0 964
michael@0 965 EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d))
michael@0 966 .InSequence(s).WillOnce(Return(true));
michael@0 967 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 968
michael@0 969 ParseSection(&section);
michael@0 970 }
michael@0 971
michael@0 972 TEST_F(CFIInsn, DW_CFA_same_value) {
michael@0 973 CFISection section(kLittleEndian, 4);
michael@0 974 StockCIEAndFDE(&section);
michael@0 975 section
michael@0 976 .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760)
michael@0 977 .FinishEntry();
michael@0 978
michael@0 979 EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760))
michael@0 980 .InSequence(s).WillOnce(Return(true));
michael@0 981 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 982
michael@0 983 ParseSection(&section);
michael@0 984 }
michael@0 985
michael@0 986 TEST_F(CFIInsn, DW_CFA_offset) {
michael@0 987 CFISection section(kBigEndian, 4);
michael@0 988 StockCIEAndFDE(&section);
michael@0 989 section
michael@0 990 .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6)
michael@0 991 .FinishEntry();
michael@0 992
michael@0 993 EXPECT_CALL(handler,
michael@0 994 OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor))
michael@0 995 .InSequence(s).WillOnce(Return(true));
michael@0 996 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 997
michael@0 998 ParseSection(&section);
michael@0 999 }
michael@0 1000
michael@0 1001 TEST_F(CFIInsn, DW_CFA_offset_extended) {
michael@0 1002 CFISection section(kBigEndian, 4);
michael@0 1003 StockCIEAndFDE(&section);
michael@0 1004 section
michael@0 1005 .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48)
michael@0 1006 .FinishEntry();
michael@0 1007
michael@0 1008 EXPECT_CALL(handler,
michael@0 1009 OffsetRule(fde_start, 0x402b, kCFARegister, 0xb48 * data_factor))
michael@0 1010 .InSequence(s).WillOnce(Return(true));
michael@0 1011 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1012
michael@0 1013 ParseSection(&section);
michael@0 1014 }
michael@0 1015
michael@0 1016 TEST_F(CFIInsn, DW_CFA_offset_extended_sf) {
michael@0 1017 CFISection section(kBigEndian, 8);
michael@0 1018 StockCIEAndFDE(&section);
michael@0 1019 section
michael@0 1020 .D8(dwarf2reader::DW_CFA_offset_extended_sf)
michael@0 1021 .ULEB128(0x997c23ee).LEB128(0x2d00)
michael@0 1022 .D8(dwarf2reader::DW_CFA_offset_extended_sf)
michael@0 1023 .ULEB128(0x9519eb82).LEB128(-0xa77)
michael@0 1024 .FinishEntry();
michael@0 1025
michael@0 1026 EXPECT_CALL(handler,
michael@0 1027 OffsetRule(fde_start, 0x997c23ee,
michael@0 1028 kCFARegister, 0x2d00 * data_factor))
michael@0 1029 .InSequence(s).WillOnce(Return(true));
michael@0 1030 EXPECT_CALL(handler,
michael@0 1031 OffsetRule(fde_start, 0x9519eb82,
michael@0 1032 kCFARegister, -0xa77 * data_factor))
michael@0 1033 .InSequence(s).WillOnce(Return(true));
michael@0 1034 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1035
michael@0 1036 ParseSection(&section);
michael@0 1037 }
michael@0 1038
michael@0 1039 TEST_F(CFIInsn, DW_CFA_val_offset) {
michael@0 1040 CFISection section(kBigEndian, 4);
michael@0 1041 StockCIEAndFDE(&section);
michael@0 1042 section
michael@0 1043 .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673)
michael@0 1044 .FinishEntry();
michael@0 1045
michael@0 1046 EXPECT_CALL(handler,
michael@0 1047 ValOffsetRule(fde_start, 0x623562fe,
michael@0 1048 kCFARegister, 0x673 * data_factor))
michael@0 1049 .InSequence(s).WillOnce(Return(true));
michael@0 1050 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1051
michael@0 1052 ParseSection(&section);
michael@0 1053 }
michael@0 1054
michael@0 1055 TEST_F(CFIInsn, DW_CFA_val_offset_sf) {
michael@0 1056 CFISection section(kBigEndian, 4);
michael@0 1057 StockCIEAndFDE(&section);
michael@0 1058 section
michael@0 1059 .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab)
michael@0 1060 .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2)
michael@0 1061 .FinishEntry();
michael@0 1062
michael@0 1063 EXPECT_CALL(handler,
michael@0 1064 ValOffsetRule(fde_start, 0x6f4f,
michael@0 1065 kCFARegister, 0xaab * data_factor))
michael@0 1066 .InSequence(s).WillOnce(Return(true));
michael@0 1067 EXPECT_CALL(handler,
michael@0 1068 ValOffsetRule(fde_start, 0x2483,
michael@0 1069 kCFARegister, -0x8a2 * data_factor))
michael@0 1070 .InSequence(s).WillOnce(Return(true));
michael@0 1071 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1072
michael@0 1073 ParseSection(&section);
michael@0 1074 }
michael@0 1075
michael@0 1076 TEST_F(CFIInsn, DW_CFA_register) {
michael@0 1077 CFISection section(kLittleEndian, 8);
michael@0 1078 StockCIEAndFDE(&section);
michael@0 1079 section
michael@0 1080 .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414)
michael@0 1081 .FinishEntry();
michael@0 1082
michael@0 1083 EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414))
michael@0 1084 .InSequence(s).WillOnce(Return(true));
michael@0 1085 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1086
michael@0 1087 ParseSection(&section);
michael@0 1088 }
michael@0 1089
michael@0 1090 TEST_F(CFIInsn, DW_CFA_expression) {
michael@0 1091 CFISection section(kBigEndian, 8);
michael@0 1092 StockCIEAndFDE(&section);
michael@0 1093 section
michael@0 1094 .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2)
michael@0 1095 .Block("plus ça change, plus c'est la même chose")
michael@0 1096 .FinishEntry();
michael@0 1097
michael@0 1098 EXPECT_CALL(handler,
michael@0 1099 ExpressionRule(fde_start, 0xa1619fb2,
michael@0 1100 "plus ça change, plus c'est la même chose"))
michael@0 1101 .InSequence(s).WillOnce(Return(true));
michael@0 1102 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1103
michael@0 1104 ParseSection(&section);
michael@0 1105 }
michael@0 1106
michael@0 1107 TEST_F(CFIInsn, DW_CFA_val_expression) {
michael@0 1108 CFISection section(kBigEndian, 4);
michael@0 1109 StockCIEAndFDE(&section);
michael@0 1110 section
michael@0 1111 .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3)
michael@0 1112 .Block("he who has the gold makes the rules")
michael@0 1113 .FinishEntry();
michael@0 1114
michael@0 1115 EXPECT_CALL(handler,
michael@0 1116 ValExpressionRule(fde_start, 0xc5e4a9e3,
michael@0 1117 "he who has the gold makes the rules"))
michael@0 1118 .InSequence(s).WillOnce(Return(true));
michael@0 1119 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1120
michael@0 1121 ParseSection(&section);
michael@0 1122 }
michael@0 1123
michael@0 1124 TEST_F(CFIInsn, DW_CFA_restore) {
michael@0 1125 CFISection section(kLittleEndian, 8);
michael@0 1126 code_factor = 0x01bd188a9b1fa083ULL;
michael@0 1127 data_factor = -0x1ac8;
michael@0 1128 return_register = 0x8c35b049;
michael@0 1129 version = 2;
michael@0 1130 fde_start = 0x2d70fe998298bbb1ULL;
michael@0 1131 fde_size = 0x46ccc2e63cf0b108ULL;
michael@0 1132 Label cie;
michael@0 1133 section
michael@0 1134 .Mark(&cie)
michael@0 1135 .CIEHeader(code_factor, data_factor, return_register, version,
michael@0 1136 "")
michael@0 1137 // Provide a CFA rule, because register rules require them.
michael@0 1138 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8)
michael@0 1139 // Provide an offset(N) rule for register 0x3c.
michael@0 1140 .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348)
michael@0 1141 .FinishEntry()
michael@0 1142 // In the FDE...
michael@0 1143 .FDEHeader(cie, fde_start, fde_size)
michael@0 1144 // At a second address, provide a new offset(N) rule for register 0x3c.
michael@0 1145 .D8(dwarf2reader::DW_CFA_advance_loc | 0x13)
michael@0 1146 .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50)
michael@0 1147 // At a third address, restore the original rule for register 0x3c.
michael@0 1148 .D8(dwarf2reader::DW_CFA_advance_loc | 0x01)
michael@0 1149 .D8(dwarf2reader::DW_CFA_restore | 0x3c)
michael@0 1150 .FinishEntry();
michael@0 1151
michael@0 1152 {
michael@0 1153 InSequence s;
michael@0 1154 EXPECT_CALL(handler,
michael@0 1155 Entry(_, fde_start, fde_size, version, "", return_register))
michael@0 1156 .WillOnce(Return(true));
michael@0 1157 // CIE's CFA rule.
michael@0 1158 EXPECT_CALL(handler,
michael@0 1159 ValOffsetRule(fde_start, kCFARegister, 0x6ca1d50e, 0x372e38e8))
michael@0 1160 .WillOnce(Return(true));
michael@0 1161 // CIE's rule for register 0x3c.
michael@0 1162 EXPECT_CALL(handler,
michael@0 1163 OffsetRule(fde_start, 0x3c, kCFARegister, 0xb348 * data_factor))
michael@0 1164 .WillOnce(Return(true));
michael@0 1165 // FDE's rule for register 0x3c.
michael@0 1166 EXPECT_CALL(handler,
michael@0 1167 OffsetRule(fde_start + 0x13 * code_factor, 0x3c,
michael@0 1168 kCFARegister, 0x9a50 * data_factor))
michael@0 1169 .WillOnce(Return(true));
michael@0 1170 // Restore CIE's rule for register 0x3c.
michael@0 1171 EXPECT_CALL(handler,
michael@0 1172 OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c,
michael@0 1173 kCFARegister, 0xb348 * data_factor))
michael@0 1174 .WillOnce(Return(true));
michael@0 1175 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1176 }
michael@0 1177
michael@0 1178 ParseSection(&section);
michael@0 1179 }
michael@0 1180
michael@0 1181 TEST_F(CFIInsn, DW_CFA_restoreNoRule) {
michael@0 1182 CFISection section(kBigEndian, 4);
michael@0 1183 code_factor = 0x005f78143c1c3b82ULL;
michael@0 1184 data_factor = 0x25d0;
michael@0 1185 return_register = 0xe8;
michael@0 1186 version = 1;
michael@0 1187 fde_start = 0x4062e30f;
michael@0 1188 fde_size = 0x5302a389;
michael@0 1189 Label cie;
michael@0 1190 section
michael@0 1191 .Mark(&cie)
michael@0 1192 .CIEHeader(code_factor, data_factor, return_register, version, "")
michael@0 1193 // Provide a CFA rule, because register rules require them.
michael@0 1194 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127)
michael@0 1195 .FinishEntry()
michael@0 1196 // In the FDE...
michael@0 1197 .FDEHeader(cie, fde_start, fde_size)
michael@0 1198 // At a second address, provide an offset(N) rule for register 0x2c.
michael@0 1199 .D8(dwarf2reader::DW_CFA_advance_loc | 0x7)
michael@0 1200 .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47)
michael@0 1201 // At a third address, restore the (missing) CIE rule for register 0x2c.
michael@0 1202 .D8(dwarf2reader::DW_CFA_advance_loc | 0xb)
michael@0 1203 .D8(dwarf2reader::DW_CFA_restore | 0x2c)
michael@0 1204 .FinishEntry();
michael@0 1205
michael@0 1206 {
michael@0 1207 InSequence s;
michael@0 1208 EXPECT_CALL(handler,
michael@0 1209 Entry(_, fde_start, fde_size, version, "", return_register))
michael@0 1210 .WillOnce(Return(true));
michael@0 1211 // CIE's CFA rule.
michael@0 1212 EXPECT_CALL(handler,
michael@0 1213 ValOffsetRule(fde_start, kCFARegister, 0x470aa334, 0x099ef127))
michael@0 1214 .WillOnce(Return(true));
michael@0 1215 // FDE's rule for register 0x2c.
michael@0 1216 EXPECT_CALL(handler,
michael@0 1217 OffsetRule(fde_start + 0x7 * code_factor, 0x2c,
michael@0 1218 kCFARegister, 0x1f47 * data_factor))
michael@0 1219 .WillOnce(Return(true));
michael@0 1220 // Restore CIE's (missing) rule for register 0x2c.
michael@0 1221 EXPECT_CALL(handler,
michael@0 1222 SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c))
michael@0 1223 .WillOnce(Return(true));
michael@0 1224 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1225 }
michael@0 1226
michael@0 1227 ParseSection(&section);
michael@0 1228 }
michael@0 1229
michael@0 1230 TEST_F(CFIInsn, DW_CFA_restore_extended) {
michael@0 1231 CFISection section(kBigEndian, 4);
michael@0 1232 code_factor = 0x126e;
michael@0 1233 data_factor = -0xd8b;
michael@0 1234 return_register = 0x77711787;
michael@0 1235 version = 3;
michael@0 1236 fde_start = 0x01f55a45;
michael@0 1237 fde_size = 0x452adb80;
michael@0 1238 Label cie;
michael@0 1239 section
michael@0 1240 .Mark(&cie)
michael@0 1241 .CIEHeader(code_factor, data_factor, return_register, version,
michael@0 1242 "", true /* dwarf64 */ )
michael@0 1243 // Provide a CFA rule, because register rules require them.
michael@0 1244 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5)
michael@0 1245 // Provide an offset(N) rule for register 0x0f9b8a1c.
michael@0 1246 .D8(dwarf2reader::DW_CFA_offset_extended)
michael@0 1247 .ULEB128(0x0f9b8a1c).ULEB128(0xc979)
michael@0 1248 .FinishEntry()
michael@0 1249 // In the FDE...
michael@0 1250 .FDEHeader(cie, fde_start, fde_size)
michael@0 1251 // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c.
michael@0 1252 .D8(dwarf2reader::DW_CFA_advance_loc | 0x3)
michael@0 1253 .D8(dwarf2reader::DW_CFA_offset_extended)
michael@0 1254 .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b)
michael@0 1255 // At a third address, restore the original rule for register 0x0f9b8a1c.
michael@0 1256 .D8(dwarf2reader::DW_CFA_advance_loc | 0x04)
michael@0 1257 .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c)
michael@0 1258 .FinishEntry();
michael@0 1259
michael@0 1260 {
michael@0 1261 InSequence s;
michael@0 1262 EXPECT_CALL(handler,
michael@0 1263 Entry(_, fde_start, fde_size, version, "", return_register))
michael@0 1264 .WillOnce(Return(true));
michael@0 1265 // CIE's CFA rule.
michael@0 1266 EXPECT_CALL(handler,
michael@0 1267 ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5))
michael@0 1268 .WillOnce(Return(true));
michael@0 1269 // CIE's rule for register 0x0f9b8a1c.
michael@0 1270 EXPECT_CALL(handler,
michael@0 1271 OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister,
michael@0 1272 0xc979 * data_factor))
michael@0 1273 .WillOnce(Return(true));
michael@0 1274 // FDE's rule for register 0x0f9b8a1c.
michael@0 1275 EXPECT_CALL(handler,
michael@0 1276 OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c,
michael@0 1277 kCFARegister, 0x3b7b * data_factor))
michael@0 1278 .WillOnce(Return(true));
michael@0 1279 // Restore CIE's rule for register 0x0f9b8a1c.
michael@0 1280 EXPECT_CALL(handler,
michael@0 1281 OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c,
michael@0 1282 kCFARegister, 0xc979 * data_factor))
michael@0 1283 .WillOnce(Return(true));
michael@0 1284 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1285 }
michael@0 1286
michael@0 1287 ParseSection(&section);
michael@0 1288 }
michael@0 1289
michael@0 1290 TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) {
michael@0 1291 CFISection section(kLittleEndian, 8);
michael@0 1292 StockCIEAndFDE(&section);
michael@0 1293
michael@0 1294 // We create a state, save it, modify it, and then restore. We
michael@0 1295 // refer to the state that is overridden the restore as the
michael@0 1296 // "outgoing" state, and the restored state the "incoming" state.
michael@0 1297 //
michael@0 1298 // Register outgoing incoming expect
michael@0 1299 // 1 offset(N) no rule new "same value" rule
michael@0 1300 // 2 register(R) offset(N) report changed rule
michael@0 1301 // 3 offset(N) offset(M) report changed offset
michael@0 1302 // 4 offset(N) offset(N) no report
michael@0 1303 // 5 offset(N) no rule new "same value" rule
michael@0 1304 section
michael@0 1305 // Create the "incoming" state, which we will save and later restore.
michael@0 1306 .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806)
michael@0 1307 .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d)
michael@0 1308 .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055)
michael@0 1309 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1310 // Advance to a new instruction; an implementation could legitimately
michael@0 1311 // ignore all but the final rule for a given register at a given address.
michael@0 1312 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1313 // Create the "outgoing" state, which we will discard.
michael@0 1314 .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a)
michael@0 1315 .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767)
michael@0 1316 .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29)
michael@0 1317 .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce)
michael@0 1318 // At a third address, restore the incoming state.
michael@0 1319 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1320 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1321 .FinishEntry();
michael@0 1322
michael@0 1323 uint64 addr = fde_start;
michael@0 1324
michael@0 1325 // Expect the incoming rules to be reported.
michael@0 1326 EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor))
michael@0 1327 .InSequence(s).WillOnce(Return(true));
michael@0 1328 EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor))
michael@0 1329 .InSequence(s).WillOnce(Return(true));
michael@0 1330 EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor))
michael@0 1331 .InSequence(s).WillOnce(Return(true));
michael@0 1332
michael@0 1333 addr += code_factor;
michael@0 1334
michael@0 1335 // After the save, we establish the outgoing rule set.
michael@0 1336 EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor))
michael@0 1337 .InSequence(s).WillOnce(Return(true));
michael@0 1338 EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767))
michael@0 1339 .InSequence(s).WillOnce(Return(true));
michael@0 1340 EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor))
michael@0 1341 .InSequence(s).WillOnce(Return(true));
michael@0 1342 EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor))
michael@0 1343 .InSequence(s).WillOnce(Return(true));
michael@0 1344
michael@0 1345 addr += code_factor;
michael@0 1346
michael@0 1347 // Finally, after the restore, expect to see the differences from
michael@0 1348 // the outgoing to the incoming rules reported.
michael@0 1349 EXPECT_CALL(handler, SameValueRule(addr, 1))
michael@0 1350 .InSequence(s).WillOnce(Return(true));
michael@0 1351 EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor))
michael@0 1352 .InSequence(s).WillOnce(Return(true));
michael@0 1353 EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor))
michael@0 1354 .InSequence(s).WillOnce(Return(true));
michael@0 1355 EXPECT_CALL(handler, SameValueRule(addr, 5))
michael@0 1356 .InSequence(s).WillOnce(Return(true));
michael@0 1357
michael@0 1358 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1359
michael@0 1360 ParseSection(&section);
michael@0 1361 }
michael@0 1362
michael@0 1363 // Check that restoring a rule set reports changes to the CFA rule.
michael@0 1364 TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) {
michael@0 1365 CFISection section(kBigEndian, 4);
michael@0 1366 StockCIEAndFDE(&section);
michael@0 1367
michael@0 1368 section
michael@0 1369 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1370 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1371 .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102)
michael@0 1372 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1373 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1374 .FinishEntry();
michael@0 1375
michael@0 1376 EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister,
michael@0 1377 cfa_base_register, 0x90481102))
michael@0 1378 .InSequence(s).WillOnce(Return(true));
michael@0 1379 EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister,
michael@0 1380 cfa_base_register, cfa_offset))
michael@0 1381 .InSequence(s).WillOnce(Return(true));
michael@0 1382
michael@0 1383 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1384
michael@0 1385 ParseSection(&section);
michael@0 1386 }
michael@0 1387
michael@0 1388 TEST_F(CFIInsn, DW_CFA_nop) {
michael@0 1389 CFISection section(kLittleEndian, 4);
michael@0 1390 StockCIEAndFDE(&section);
michael@0 1391 section
michael@0 1392 .D8(dwarf2reader::DW_CFA_nop)
michael@0 1393 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b)
michael@0 1394 .D8(dwarf2reader::DW_CFA_nop)
michael@0 1395 .FinishEntry();
michael@0 1396
michael@0 1397 EXPECT_CALL(handler,
michael@0 1398 ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b))
michael@0 1399 .InSequence(s).WillOnce(Return(true));
michael@0 1400 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1401
michael@0 1402 ParseSection(&section);
michael@0 1403 }
michael@0 1404
michael@0 1405 TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
michael@0 1406 CFISection section(kBigEndian, 4);
michael@0 1407 StockCIEAndFDE(&section);
michael@0 1408 section
michael@0 1409 .D8(dwarf2reader::DW_CFA_GNU_window_save)
michael@0 1410 .FinishEntry();
michael@0 1411
michael@0 1412 // Don't include all the rules in any particular sequence.
michael@0 1413
michael@0 1414 // The caller's %o0-%o7 have become the callee's %i0-%i7. This is
michael@0 1415 // the GCC register numbering.
michael@0 1416 for (int i = 8; i < 16; i++)
michael@0 1417 EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16))
michael@0 1418 .WillOnce(Return(true));
michael@0 1419 // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of
michael@0 1420 // its frame.
michael@0 1421 for (int i = 16; i < 32; i++)
michael@0 1422 EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4))
michael@0 1423 .WillOnce(Return(true));
michael@0 1424
michael@0 1425 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1426
michael@0 1427 ParseSection(&section);
michael@0 1428 }
michael@0 1429
michael@0 1430 TEST_F(CFIInsn, DW_CFA_GNU_args_size) {
michael@0 1431 CFISection section(kLittleEndian, 8);
michael@0 1432 StockCIEAndFDE(&section);
michael@0 1433 section
michael@0 1434 .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520)
michael@0 1435 // Verify that we see this, meaning we parsed the above properly.
michael@0 1436 .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269)
michael@0 1437 .FinishEntry();
michael@0 1438
michael@0 1439 EXPECT_CALL(handler,
michael@0 1440 OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor))
michael@0 1441 .InSequence(s).WillOnce(Return(true));
michael@0 1442 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1443
michael@0 1444 ParseSection(&section);
michael@0 1445 }
michael@0 1446
michael@0 1447 TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) {
michael@0 1448 CFISection section(kLittleEndian, 4);
michael@0 1449 StockCIEAndFDE(&section);
michael@0 1450 section
michael@0 1451 .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended)
michael@0 1452 .ULEB128(0x430cc87a).ULEB128(0x613)
michael@0 1453 .FinishEntry();
michael@0 1454
michael@0 1455 EXPECT_CALL(handler,
michael@0 1456 OffsetRule(fde_start, 0x430cc87a,
michael@0 1457 kCFARegister, -0x613 * data_factor))
michael@0 1458 .InSequence(s).WillOnce(Return(true));
michael@0 1459 EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
michael@0 1460
michael@0 1461 ParseSection(&section);
michael@0 1462 }
michael@0 1463
michael@0 1464 // Three FDEs: skip the second
michael@0 1465 TEST_F(CFIInsn, SkipFDE) {
michael@0 1466 CFISection section(kBigEndian, 4);
michael@0 1467 Label cie;
michael@0 1468 section
michael@0 1469 // CIE, used by all FDEs.
michael@0 1470 .Mark(&cie)
michael@0 1471 .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "")
michael@0 1472 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad)
michael@0 1473 .FinishEntry()
michael@0 1474 // First FDE.
michael@0 1475 .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4)
michael@0 1476 .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf)
michael@0 1477 .FinishEntry()
michael@0 1478 // Second FDE.
michael@0 1479 .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */)
michael@0 1480 .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18)
michael@0 1481 .FinishEntry()
michael@0 1482 // Third FDE.
michael@0 1483 .FDEHeader(cie, 0xf681cfc8, 0x7e4594e)
michael@0 1484 .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4)
michael@0 1485 .FinishEntry();
michael@0 1486
michael@0 1487 {
michael@0 1488 InSequence s;
michael@0 1489
michael@0 1490 // Process the first FDE.
michael@0 1491 EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849))
michael@0 1492 .WillOnce(Return(true));
michael@0 1493 EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister,
michael@0 1494 0x42ed390b, 0x98f43aad))
michael@0 1495 .WillOnce(Return(true));
michael@0 1496 EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf))
michael@0 1497 .WillOnce(Return(true));
michael@0 1498 EXPECT_CALL(handler, End())
michael@0 1499 .WillOnce(Return(true));
michael@0 1500
michael@0 1501 // Skip the second FDE.
michael@0 1502 EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849))
michael@0 1503 .WillOnce(Return(false));
michael@0 1504
michael@0 1505 // Process the third FDE.
michael@0 1506 EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849))
michael@0 1507 .WillOnce(Return(true));
michael@0 1508 EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister,
michael@0 1509 0x42ed390b, 0x98f43aad))
michael@0 1510 .WillOnce(Return(true));
michael@0 1511 EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4))
michael@0 1512 .WillOnce(Return(true));
michael@0 1513 EXPECT_CALL(handler, End())
michael@0 1514 .WillOnce(Return(true));
michael@0 1515 }
michael@0 1516
michael@0 1517 ParseSection(&section);
michael@0 1518 }
michael@0 1519
michael@0 1520 // Quit processing in the middle of an entry's instructions.
michael@0 1521 TEST_F(CFIInsn, QuitMidentry) {
michael@0 1522 CFISection section(kLittleEndian, 8);
michael@0 1523 StockCIEAndFDE(&section);
michael@0 1524 section
michael@0 1525 .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431)
michael@0 1526 .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat")
michael@0 1527 .FinishEntry();
michael@0 1528
michael@0 1529 EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431))
michael@0 1530 .InSequence(s).WillOnce(Return(false));
michael@0 1531 EXPECT_CALL(handler, End())
michael@0 1532 .InSequence(s).WillOnce(Return(true));
michael@0 1533
michael@0 1534 ParseSection(&section, false);
michael@0 1535 }
michael@0 1536
michael@0 1537 class CFIRestore: public CFIInsnFixture, public Test { };
michael@0 1538
michael@0 1539 TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) {
michael@0 1540 CFISection section(kLittleEndian, 4);
michael@0 1541 StockCIEAndFDE(&section);
michael@0 1542 section
michael@0 1543 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e)
michael@0 1544 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1545 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1546 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1547 .FinishEntry();
michael@0 1548
michael@0 1549 EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e))
michael@0 1550 .InSequence(s).WillOnce(Return(true));
michael@0 1551 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1552
michael@0 1553 ParseSection(&section);
michael@0 1554 }
michael@0 1555
michael@0 1556 TEST_F(CFIRestore, RestoreUndefinedRuleChanged) {
michael@0 1557 CFISection section(kLittleEndian, 4);
michael@0 1558 StockCIEAndFDE(&section);
michael@0 1559 section
michael@0 1560 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f)
michael@0 1561 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1562 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1563 .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f)
michael@0 1564 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1565 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1566 .FinishEntry();
michael@0 1567
michael@0 1568 EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f))
michael@0 1569 .InSequence(s).WillOnce(Return(true));
michael@0 1570 EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f))
michael@0 1571 .InSequence(s).WillOnce(Return(true));
michael@0 1572 EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f))
michael@0 1573 .InSequence(s).WillOnce(Return(true));
michael@0 1574 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1575
michael@0 1576 ParseSection(&section);
michael@0 1577 }
michael@0 1578
michael@0 1579 TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) {
michael@0 1580 CFISection section(kLittleEndian, 4);
michael@0 1581 StockCIEAndFDE(&section);
michael@0 1582 section
michael@0 1583 .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a)
michael@0 1584 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1585 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1586 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1587 .FinishEntry();
michael@0 1588
michael@0 1589 EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a))
michael@0 1590 .InSequence(s).WillOnce(Return(true));
michael@0 1591 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1592
michael@0 1593 ParseSection(&section);
michael@0 1594 }
michael@0 1595
michael@0 1596 TEST_F(CFIRestore, RestoreSameValueRuleChanged) {
michael@0 1597 CFISection section(kLittleEndian, 4);
michael@0 1598 StockCIEAndFDE(&section);
michael@0 1599 section
michael@0 1600 .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5)
michael@0 1601 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1602 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1603 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5)
michael@0 1604 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1605 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1606 .FinishEntry();
michael@0 1607
michael@0 1608 EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5))
michael@0 1609 .InSequence(s).WillOnce(Return(true));
michael@0 1610 EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5))
michael@0 1611 .InSequence(s).WillOnce(Return(true));
michael@0 1612 EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5))
michael@0 1613 .InSequence(s).WillOnce(Return(true));
michael@0 1614 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1615
michael@0 1616 ParseSection(&section);
michael@0 1617 }
michael@0 1618
michael@0 1619 TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) {
michael@0 1620 CFISection section(kLittleEndian, 4);
michael@0 1621 StockCIEAndFDE(&section);
michael@0 1622 section
michael@0 1623 .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f)
michael@0 1624 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1625 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1626 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1627 .FinishEntry();
michael@0 1628
michael@0 1629 EXPECT_CALL(handler, OffsetRule(fde_start, 0x14,
michael@0 1630 kCFARegister, 0xb6f * data_factor))
michael@0 1631 .InSequence(s).WillOnce(Return(true));
michael@0 1632 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1633
michael@0 1634 ParseSection(&section);
michael@0 1635 }
michael@0 1636
michael@0 1637 TEST_F(CFIRestore, RestoreOffsetRuleChanged) {
michael@0 1638 CFISection section(kLittleEndian, 4);
michael@0 1639 StockCIEAndFDE(&section);
michael@0 1640 section
michael@0 1641 .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7)
michael@0 1642 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1643 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1644 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21)
michael@0 1645 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1646 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1647 .FinishEntry();
michael@0 1648
michael@0 1649 EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
michael@0 1650 kCFARegister, 0xeb7 * data_factor))
michael@0 1651 .InSequence(s).WillOnce(Return(true));
michael@0 1652 EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21))
michael@0 1653 .InSequence(s).WillOnce(Return(true));
michael@0 1654 EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21,
michael@0 1655 kCFARegister, 0xeb7 * data_factor))
michael@0 1656 .InSequence(s).WillOnce(Return(true));
michael@0 1657 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1658
michael@0 1659 ParseSection(&section);
michael@0 1660 }
michael@0 1661
michael@0 1662 TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) {
michael@0 1663 CFISection section(kLittleEndian, 4);
michael@0 1664 StockCIEAndFDE(&section);
michael@0 1665 section
michael@0 1666 .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134)
michael@0 1667 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1668 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1669 .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f)
michael@0 1670 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1671 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1672 .FinishEntry();
michael@0 1673
michael@0 1674 EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
michael@0 1675 kCFARegister, 0x134 * data_factor))
michael@0 1676 .InSequence(s).WillOnce(Return(true));
michael@0 1677 EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21,
michael@0 1678 kCFARegister, 0xf4f * data_factor))
michael@0 1679 .InSequence(s).WillOnce(Return(true));
michael@0 1680 EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21,
michael@0 1681 kCFARegister, 0x134 * data_factor))
michael@0 1682 .InSequence(s).WillOnce(Return(true));
michael@0 1683 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1684
michael@0 1685 ParseSection(&section);
michael@0 1686 }
michael@0 1687
michael@0 1688 TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) {
michael@0 1689 CFISection section(kLittleEndian, 4);
michael@0 1690 StockCIEAndFDE(&section);
michael@0 1691 section
michael@0 1692 .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c)
michael@0 1693 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1694 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1695 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1696 .FinishEntry();
michael@0 1697
michael@0 1698 EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6,
michael@0 1699 kCFARegister, 0xe4c * data_factor))
michael@0 1700 .InSequence(s).WillOnce(Return(true));
michael@0 1701 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1702
michael@0 1703 ParseSection(&section);
michael@0 1704 }
michael@0 1705
michael@0 1706 TEST_F(CFIRestore, RestoreValOffsetRuleChanged) {
michael@0 1707 CFISection section(kLittleEndian, 4);
michael@0 1708 StockCIEAndFDE(&section);
michael@0 1709 section
michael@0 1710 .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7)
michael@0 1711 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1712 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1713 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6)
michael@0 1714 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1715 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1716 .FinishEntry();
michael@0 1717
michael@0 1718 EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6,
michael@0 1719 kCFARegister, 0xeb7 * data_factor))
michael@0 1720 .InSequence(s).WillOnce(Return(true));
michael@0 1721 EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6))
michael@0 1722 .InSequence(s).WillOnce(Return(true));
michael@0 1723 EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6,
michael@0 1724 kCFARegister, 0xeb7 * data_factor))
michael@0 1725 .InSequence(s).WillOnce(Return(true));
michael@0 1726 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1727
michael@0 1728 ParseSection(&section);
michael@0 1729 }
michael@0 1730
michael@0 1731 TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) {
michael@0 1732 CFISection section(kLittleEndian, 4);
michael@0 1733 StockCIEAndFDE(&section);
michael@0 1734 section
michael@0 1735 .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562)
michael@0 1736 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1737 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1738 .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88)
michael@0 1739 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1740 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1741 .FinishEntry();
michael@0 1742
michael@0 1743 EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b,
michael@0 1744 kCFARegister, 0x562 * data_factor))
michael@0 1745 .InSequence(s).WillOnce(Return(true));
michael@0 1746 EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b,
michael@0 1747 kCFARegister, 0xe88 * data_factor))
michael@0 1748 .InSequence(s).WillOnce(Return(true));
michael@0 1749 EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b,
michael@0 1750 kCFARegister, 0x562 * data_factor))
michael@0 1751 .InSequence(s).WillOnce(Return(true));
michael@0 1752 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1753
michael@0 1754 ParseSection(&section);
michael@0 1755 }
michael@0 1756
michael@0 1757 TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) {
michael@0 1758 CFISection section(kLittleEndian, 4);
michael@0 1759 StockCIEAndFDE(&section);
michael@0 1760 section
michael@0 1761 .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce)
michael@0 1762 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1763 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1764 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1765 .FinishEntry();
michael@0 1766
michael@0 1767 EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce))
michael@0 1768 .InSequence(s).WillOnce(Return(true));
michael@0 1769 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1770
michael@0 1771 ParseSection(&section);
michael@0 1772 }
michael@0 1773
michael@0 1774 TEST_F(CFIRestore, RestoreRegisterRuleChanged) {
michael@0 1775 CFISection section(kLittleEndian, 4);
michael@0 1776 StockCIEAndFDE(&section);
michael@0 1777 section
michael@0 1778 .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559)
michael@0 1779 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1780 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1781 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5)
michael@0 1782 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1783 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1784 .FinishEntry();
michael@0 1785
michael@0 1786 EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559))
michael@0 1787 .InSequence(s).WillOnce(Return(true));
michael@0 1788 EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5))
michael@0 1789 .InSequence(s).WillOnce(Return(true));
michael@0 1790 EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5,
michael@0 1791 0x095f1559))
michael@0 1792 .InSequence(s).WillOnce(Return(true));
michael@0 1793 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1794
michael@0 1795 ParseSection(&section);
michael@0 1796 }
michael@0 1797
michael@0 1798 TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) {
michael@0 1799 CFISection section(kLittleEndian, 4);
michael@0 1800 StockCIEAndFDE(&section);
michael@0 1801 section
michael@0 1802 .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a)
michael@0 1803 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1804 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1805 .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742)
michael@0 1806 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1807 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1808 .FinishEntry();
michael@0 1809
michael@0 1810 EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a))
michael@0 1811 .InSequence(s).WillOnce(Return(true));
michael@0 1812 EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1,
michael@0 1813 0xbabb4742))
michael@0 1814 .InSequence(s).WillOnce(Return(true));
michael@0 1815 EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1,
michael@0 1816 0x16607d6a))
michael@0 1817 .InSequence(s).WillOnce(Return(true));
michael@0 1818 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1819
michael@0 1820 ParseSection(&section);
michael@0 1821 }
michael@0 1822
michael@0 1823 TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) {
michael@0 1824 CFISection section(kLittleEndian, 4);
michael@0 1825 StockCIEAndFDE(&section);
michael@0 1826 section
michael@0 1827 .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf")
michael@0 1828 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1829 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1830 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1831 .FinishEntry();
michael@0 1832
michael@0 1833 EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf"))
michael@0 1834 .InSequence(s).WillOnce(Return(true));
michael@0 1835 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1836
michael@0 1837 ParseSection(&section);
michael@0 1838 }
michael@0 1839
michael@0 1840 TEST_F(CFIRestore, RestoreExpressionRuleChanged) {
michael@0 1841 CFISection section(kLittleEndian, 4);
michael@0 1842 StockCIEAndFDE(&section);
michael@0 1843 section
michael@0 1844 .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf")
michael@0 1845 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1846 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1847 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
michael@0 1848 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1849 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1850 .FinishEntry();
michael@0 1851
michael@0 1852 EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf"))
michael@0 1853 .InSequence(s).WillOnce(Return(true));
michael@0 1854 EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46))
michael@0 1855 .InSequence(s).WillOnce(Return(true));
michael@0 1856 EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46,
michael@0 1857 "elf"))
michael@0 1858 .InSequence(s).WillOnce(Return(true));
michael@0 1859 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1860
michael@0 1861 ParseSection(&section);
michael@0 1862 }
michael@0 1863
michael@0 1864 TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) {
michael@0 1865 CFISection section(kLittleEndian, 4);
michael@0 1866 StockCIEAndFDE(&section);
michael@0 1867 section
michael@0 1868 .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf")
michael@0 1869 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1870 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1871 .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc")
michael@0 1872 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1873 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1874 .FinishEntry();
michael@0 1875
michael@0 1876 EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf"))
michael@0 1877 .InSequence(s).WillOnce(Return(true));
michael@0 1878 EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739,
michael@0 1879 "orc"))
michael@0 1880 .InSequence(s).WillOnce(Return(true));
michael@0 1881 // Expectations are not wishes.
michael@0 1882 EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739,
michael@0 1883 "smurf"))
michael@0 1884 .InSequence(s).WillOnce(Return(true));
michael@0 1885 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1886
michael@0 1887 ParseSection(&section);
michael@0 1888 }
michael@0 1889
michael@0 1890 TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) {
michael@0 1891 CFISection section(kLittleEndian, 4);
michael@0 1892 StockCIEAndFDE(&section);
michael@0 1893 section
michael@0 1894 .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152)
michael@0 1895 .Block("hideous")
michael@0 1896 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1897 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1898 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1899 .FinishEntry();
michael@0 1900
michael@0 1901 EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous"))
michael@0 1902 .InSequence(s).WillOnce(Return(true));
michael@0 1903 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1904
michael@0 1905 ParseSection(&section);
michael@0 1906 }
michael@0 1907
michael@0 1908 TEST_F(CFIRestore, RestoreValExpressionRuleChanged) {
michael@0 1909 CFISection section(kLittleEndian, 4);
michael@0 1910 StockCIEAndFDE(&section);
michael@0 1911 section
michael@0 1912 .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46)
michael@0 1913 .Block("revolting")
michael@0 1914 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1915 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1916 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
michael@0 1917 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1918 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1919 .FinishEntry();
michael@0 1920
michael@0 1921 PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section);
michael@0 1922
michael@0 1923 EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting"))
michael@0 1924 .InSequence(s).WillOnce(Return(true));
michael@0 1925 EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46))
michael@0 1926 .InSequence(s).WillOnce(Return(true));
michael@0 1927 EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46,
michael@0 1928 "revolting"))
michael@0 1929 .InSequence(s).WillOnce(Return(true));
michael@0 1930 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1931
michael@0 1932 ParseSection(&section);
michael@0 1933 }
michael@0 1934
michael@0 1935 TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) {
michael@0 1936 CFISection section(kLittleEndian, 4);
michael@0 1937 StockCIEAndFDE(&section);
michael@0 1938 section
michael@0 1939 .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
michael@0 1940 .Block("repulsive")
michael@0 1941 .D8(dwarf2reader::DW_CFA_remember_state)
michael@0 1942 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1943 .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
michael@0 1944 .Block("nauseous")
michael@0 1945 .D8(dwarf2reader::DW_CFA_advance_loc | 1)
michael@0 1946 .D8(dwarf2reader::DW_CFA_restore_state)
michael@0 1947 .FinishEntry();
michael@0 1948
michael@0 1949 PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression",
michael@0 1950 section);
michael@0 1951
michael@0 1952 EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive"))
michael@0 1953 .InSequence(s).WillOnce(Return(true));
michael@0 1954 EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739,
michael@0 1955 "nauseous"))
michael@0 1956 .InSequence(s).WillOnce(Return(true));
michael@0 1957 // Expectations are not wishes.
michael@0 1958 EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739,
michael@0 1959 "repulsive"))
michael@0 1960 .InSequence(s).WillOnce(Return(true));
michael@0 1961 EXPECT_CALL(handler, End()).WillOnce(Return(true));
michael@0 1962
michael@0 1963 ParseSection(&section);
michael@0 1964 }
michael@0 1965
michael@0 1966 struct EHFrameFixture: public CFIInsnFixture {
michael@0 1967 EHFrameFixture()
michael@0 1968 : CFIInsnFixture(), section(kBigEndian, 4, true) {
michael@0 1969 encoded_pointer_bases.cfi = 0x7f496cb2;
michael@0 1970 encoded_pointer_bases.text = 0x540f67b6;
michael@0 1971 encoded_pointer_bases.data = 0xe3eab768;
michael@0 1972 section.SetEncodedPointerBases(encoded_pointer_bases);
michael@0 1973 }
michael@0 1974 CFISection section;
michael@0 1975 CFISection::EncodedPointerBases encoded_pointer_bases;
michael@0 1976
michael@0 1977 // Parse CFIInsnFixture::ParseSection, but parse the section as
michael@0 1978 // .eh_frame data, supplying stock base addresses.
michael@0 1979 void ParseEHFrameSection(CFISection *section, bool succeeds = true) {
michael@0 1980 EXPECT_TRUE(section->ContainsEHFrame());
michael@0 1981 string contents;
michael@0 1982 EXPECT_TRUE(section->GetContents(&contents));
michael@0 1983 dwarf2reader::Endianness endianness;
michael@0 1984 if (section->endianness() == kBigEndian)
michael@0 1985 endianness = ENDIANNESS_BIG;
michael@0 1986 else {
michael@0 1987 assert(section->endianness() == kLittleEndian);
michael@0 1988 endianness = ENDIANNESS_LITTLE;
michael@0 1989 }
michael@0 1990 ByteReader byte_reader(endianness);
michael@0 1991 byte_reader.SetAddressSize(section->AddressSize());
michael@0 1992 byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, contents.data());
michael@0 1993 byte_reader.SetTextBase(encoded_pointer_bases.text);
michael@0 1994 byte_reader.SetDataBase(encoded_pointer_bases.data);
michael@0 1995 CallFrameInfo parser(contents.data(), contents.size(),
michael@0 1996 &byte_reader, &handler, &reporter, true);
michael@0 1997 if (succeeds)
michael@0 1998 EXPECT_TRUE(parser.Start());
michael@0 1999 else
michael@0 2000 EXPECT_FALSE(parser.Start());
michael@0 2001 }
michael@0 2002
michael@0 2003 };
michael@0 2004
michael@0 2005 class EHFrame: public EHFrameFixture, public Test { };
michael@0 2006
michael@0 2007 // A simple CIE, an FDE, and a terminator.
michael@0 2008 TEST_F(EHFrame, Terminator) {
michael@0 2009 Label cie;
michael@0 2010 section
michael@0 2011 .Mark(&cie)
michael@0 2012 .CIEHeader(9968, 2466, 67, 1, "")
michael@0 2013 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372)
michael@0 2014 .FinishEntry()
michael@0 2015 .FDEHeader(cie, 0x848037a1, 0x7b30475e)
michael@0 2016 .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850)
michael@0 2017 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721)
michael@0 2018 .FinishEntry()
michael@0 2019 .D32(0) // Terminate the sequence.
michael@0 2020 // This FDE should be ignored.
michael@0 2021 .FDEHeader(cie, 0xf19629fe, 0x439fb09b)
michael@0 2022 .FinishEntry();
michael@0 2023
michael@0 2024 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section);
michael@0 2025
michael@0 2026 EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67))
michael@0 2027 .InSequence(s).WillOnce(Return(true));
michael@0 2028 EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372))
michael@0 2029 .InSequence(s).WillOnce(Return(true));
michael@0 2030 EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721))
michael@0 2031 .InSequence(s).WillOnce(Return(true));
michael@0 2032 EXPECT_CALL(handler, End())
michael@0 2033 .InSequence(s).WillOnce(Return(true));
michael@0 2034 EXPECT_CALL(reporter, EarlyEHTerminator(_))
michael@0 2035 .InSequence(s).WillOnce(Return());
michael@0 2036
michael@0 2037 ParseEHFrameSection(&section);
michael@0 2038 }
michael@0 2039
michael@0 2040 // The parser should recognize the Linux Standards Base 'z' augmentations.
michael@0 2041 TEST_F(EHFrame, SimpleFDE) {
michael@0 2042 DwarfPointerEncoding lsda_encoding =
michael@0 2043 DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect
michael@0 2044 | dwarf2reader::DW_EH_PE_datarel
michael@0 2045 | dwarf2reader::DW_EH_PE_sdata2);
michael@0 2046 DwarfPointerEncoding fde_encoding =
michael@0 2047 DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
michael@0 2048 | dwarf2reader::DW_EH_PE_udata2);
michael@0 2049
michael@0 2050 section.SetPointerEncoding(fde_encoding);
michael@0 2051 section.SetEncodedPointerBases(encoded_pointer_bases);
michael@0 2052 Label cie;
michael@0 2053 section
michael@0 2054 .Mark(&cie)
michael@0 2055 .CIEHeader(4873, 7012, 100, 1, "zSLPR")
michael@0 2056 .ULEB128(7) // Augmentation data length
michael@0 2057 .D8(lsda_encoding) // LSDA pointer format
michael@0 2058 .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format
michael@0 2059 .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value
michael@0 2060 .D8(fde_encoding) // FDE pointer format
michael@0 2061 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31)
michael@0 2062 .FinishEntry()
michael@0 2063 .FDEHeader(cie, 0x540f6b56, 0xf686)
michael@0 2064 .ULEB128(2) // Augmentation data length
michael@0 2065 .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed
michael@0 2066 .D8(dwarf2reader::DW_CFA_set_loc)
michael@0 2067 .EncodedPointer(0x540fa4ce, fde_encoding)
michael@0 2068 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e)
michael@0 2069 .FinishEntry()
michael@0 2070 .D32(0); // terminator
michael@0 2071
michael@0 2072 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section);
michael@0 2073
michael@0 2074 EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100))
michael@0 2075 .InSequence(s).WillOnce(Return(true));
michael@0 2076 EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false))
michael@0 2077 .InSequence(s).WillOnce(Return(true));
michael@0 2078 EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true))
michael@0 2079 .InSequence(s).WillOnce(Return(true));
michael@0 2080 EXPECT_CALL(handler, SignalHandler())
michael@0 2081 .InSequence(s).WillOnce(Return(true));
michael@0 2082 EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31))
michael@0 2083 .InSequence(s).WillOnce(Return(true));
michael@0 2084 EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e))
michael@0 2085 .InSequence(s).WillOnce(Return(true));
michael@0 2086 EXPECT_CALL(handler, End())
michael@0 2087 .InSequence(s).WillOnce(Return(true));
michael@0 2088
michael@0 2089 ParseEHFrameSection(&section);
michael@0 2090 }
michael@0 2091
michael@0 2092 // Check that we can handle an empty 'z' augmentation.
michael@0 2093 TEST_F(EHFrame, EmptyZ) {
michael@0 2094 Label cie;
michael@0 2095 section
michael@0 2096 .Mark(&cie)
michael@0 2097 .CIEHeader(5955, 5805, 228, 1, "z")
michael@0 2098 .ULEB128(0) // Augmentation data length
michael@0 2099 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247)
michael@0 2100 .FinishEntry()
michael@0 2101 .FDEHeader(cie, 0xda007738, 0xfb55c641)
michael@0 2102 .ULEB128(0) // Augmentation data length
michael@0 2103 .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11)
michael@0 2104 .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769)
michael@0 2105 .FinishEntry();
michael@0 2106
michael@0 2107 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section);
michael@0 2108
michael@0 2109 EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228))
michael@0 2110 .InSequence(s).WillOnce(Return(true));
michael@0 2111 EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247))
michael@0 2112 .InSequence(s).WillOnce(Return(true));
michael@0 2113 EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769))
michael@0 2114 .InSequence(s).WillOnce(Return(true));
michael@0 2115 EXPECT_CALL(handler, End())
michael@0 2116 .InSequence(s).WillOnce(Return(true));
michael@0 2117
michael@0 2118 ParseEHFrameSection(&section);
michael@0 2119 }
michael@0 2120
michael@0 2121 // Check that we recognize bad 'z' augmentation characters.
michael@0 2122 TEST_F(EHFrame, BadZ) {
michael@0 2123 Label cie;
michael@0 2124 section
michael@0 2125 .Mark(&cie)
michael@0 2126 .CIEHeader(6937, 1045, 142, 1, "zQ")
michael@0 2127 .ULEB128(0) // Augmentation data length
michael@0 2128 .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725)
michael@0 2129 .FinishEntry()
michael@0 2130 .FDEHeader(cie, 0x1293efa8, 0x236f53f2)
michael@0 2131 .ULEB128(0) // Augmentation data length
michael@0 2132 .D8(dwarf2reader::DW_CFA_advance_loc | 12)
michael@0 2133 .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462)
michael@0 2134 .FinishEntry();
michael@0 2135
michael@0 2136 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section);
michael@0 2137
michael@0 2138 EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ"))
michael@0 2139 .WillOnce(Return());
michael@0 2140
michael@0 2141 ParseEHFrameSection(&section, false);
michael@0 2142 }
michael@0 2143
michael@0 2144 TEST_F(EHFrame, zL) {
michael@0 2145 Label cie;
michael@0 2146 DwarfPointerEncoding lsda_encoding =
michael@0 2147 DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel
michael@0 2148 | dwarf2reader::DW_EH_PE_udata2);
michael@0 2149 section
michael@0 2150 .Mark(&cie)
michael@0 2151 .CIEHeader(9285, 9959, 54, 1, "zL")
michael@0 2152 .ULEB128(1) // Augmentation data length
michael@0 2153 .D8(lsda_encoding) // encoding for LSDA pointer in FDE
michael@0 2154
michael@0 2155 .FinishEntry()
michael@0 2156 .FDEHeader(cie, 0xd40091aa, 0x9aa6e746)
michael@0 2157 .ULEB128(2) // Augmentation data length
michael@0 2158 .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer
michael@0 2159 .FinishEntry()
michael@0 2160 .D32(0); // terminator
michael@0 2161
michael@0 2162 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section);
michael@0 2163
michael@0 2164 EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54))
michael@0 2165 .InSequence(s).WillOnce(Return(true));
michael@0 2166 EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false))
michael@0 2167 .InSequence(s).WillOnce(Return(true));
michael@0 2168 EXPECT_CALL(handler, End())
michael@0 2169 .InSequence(s).WillOnce(Return(true));
michael@0 2170
michael@0 2171 ParseEHFrameSection(&section);
michael@0 2172 }
michael@0 2173
michael@0 2174 TEST_F(EHFrame, zP) {
michael@0 2175 Label cie;
michael@0 2176 DwarfPointerEncoding personality_encoding =
michael@0 2177 DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel
michael@0 2178 | dwarf2reader::DW_EH_PE_udata2);
michael@0 2179 section
michael@0 2180 .Mark(&cie)
michael@0 2181 .CIEHeader(1097, 6313, 17, 1, "zP")
michael@0 2182 .ULEB128(3) // Augmentation data length
michael@0 2183 .D8(personality_encoding) // encoding for personality routine
michael@0 2184 .EncodedPointer(0xe3eaccac, personality_encoding) // value
michael@0 2185 .FinishEntry()
michael@0 2186 .FDEHeader(cie, 0x0c8350c9, 0xbef11087)
michael@0 2187 .ULEB128(0) // Augmentation data length
michael@0 2188 .FinishEntry()
michael@0 2189 .D32(0); // terminator
michael@0 2190
michael@0 2191 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section);
michael@0 2192
michael@0 2193 EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17))
michael@0 2194 .InSequence(s).WillOnce(Return(true));
michael@0 2195 EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false))
michael@0 2196 .InSequence(s).WillOnce(Return(true));
michael@0 2197 EXPECT_CALL(handler, End())
michael@0 2198 .InSequence(s).WillOnce(Return(true));
michael@0 2199
michael@0 2200 ParseEHFrameSection(&section);
michael@0 2201 }
michael@0 2202
michael@0 2203 TEST_F(EHFrame, zR) {
michael@0 2204 Label cie;
michael@0 2205 DwarfPointerEncoding pointer_encoding =
michael@0 2206 DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
michael@0 2207 | dwarf2reader::DW_EH_PE_sdata2);
michael@0 2208 section.SetPointerEncoding(pointer_encoding);
michael@0 2209 section
michael@0 2210 .Mark(&cie)
michael@0 2211 .CIEHeader(8011, 5496, 75, 1, "zR")
michael@0 2212 .ULEB128(1) // Augmentation data length
michael@0 2213 .D8(pointer_encoding) // encoding for FDE addresses
michael@0 2214 .FinishEntry()
michael@0 2215 .FDEHeader(cie, 0x540f9431, 0xbd0)
michael@0 2216 .ULEB128(0) // Augmentation data length
michael@0 2217 .FinishEntry()
michael@0 2218 .D32(0); // terminator
michael@0 2219
michael@0 2220 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section);
michael@0 2221
michael@0 2222 EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75))
michael@0 2223 .InSequence(s).WillOnce(Return(true));
michael@0 2224 EXPECT_CALL(handler, End())
michael@0 2225 .InSequence(s).WillOnce(Return(true));
michael@0 2226
michael@0 2227 ParseEHFrameSection(&section);
michael@0 2228 }
michael@0 2229
michael@0 2230 TEST_F(EHFrame, zS) {
michael@0 2231 Label cie;
michael@0 2232 section
michael@0 2233 .Mark(&cie)
michael@0 2234 .CIEHeader(9217, 7694, 57, 1, "zS")
michael@0 2235 .ULEB128(0) // Augmentation data length
michael@0 2236 .FinishEntry()
michael@0 2237 .FDEHeader(cie, 0xd40091aa, 0x9aa6e746)
michael@0 2238 .ULEB128(0) // Augmentation data length
michael@0 2239 .FinishEntry()
michael@0 2240 .D32(0); // terminator
michael@0 2241
michael@0 2242 PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section);
michael@0 2243
michael@0 2244 EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57))
michael@0 2245 .InSequence(s).WillOnce(Return(true));
michael@0 2246 EXPECT_CALL(handler, SignalHandler())
michael@0 2247 .InSequence(s).WillOnce(Return(true));
michael@0 2248 EXPECT_CALL(handler, End())
michael@0 2249 .InSequence(s).WillOnce(Return(true));
michael@0 2250
michael@0 2251 ParseEHFrameSection(&section);
michael@0 2252 }
michael@0 2253
michael@0 2254 // These tests require manual inspection of the test output.
michael@0 2255 struct CFIReporterFixture {
michael@0 2256 CFIReporterFixture() : reporter("test file name", "test section name") { }
michael@0 2257 CallFrameInfo::Reporter reporter;
michael@0 2258 };
michael@0 2259
michael@0 2260 class CFIReporter: public CFIReporterFixture, public Test { };
michael@0 2261
michael@0 2262 TEST_F(CFIReporter, Incomplete) {
michael@0 2263 reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown);
michael@0 2264 }
michael@0 2265
michael@0 2266 TEST_F(CFIReporter, EarlyEHTerminator) {
michael@0 2267 reporter.EarlyEHTerminator(0x0102030405060708ULL);
michael@0 2268 }
michael@0 2269
michael@0 2270 TEST_F(CFIReporter, CIEPointerOutOfRange) {
michael@0 2271 reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
michael@0 2272 }
michael@0 2273
michael@0 2274 TEST_F(CFIReporter, BadCIEId) {
michael@0 2275 reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
michael@0 2276 }
michael@0 2277
michael@0 2278 TEST_F(CFIReporter, UnrecognizedVersion) {
michael@0 2279 reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43);
michael@0 2280 }
michael@0 2281
michael@0 2282 TEST_F(CFIReporter, UnrecognizedAugmentation) {
michael@0 2283 reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles");
michael@0 2284 }
michael@0 2285
michael@0 2286 TEST_F(CFIReporter, InvalidPointerEncoding) {
michael@0 2287 reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42);
michael@0 2288 }
michael@0 2289
michael@0 2290 TEST_F(CFIReporter, UnusablePointerEncoding) {
michael@0 2291 reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42);
michael@0 2292 }
michael@0 2293
michael@0 2294 TEST_F(CFIReporter, RestoreInCIE) {
michael@0 2295 reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
michael@0 2296 }
michael@0 2297
michael@0 2298 TEST_F(CFIReporter, BadInstruction) {
michael@0 2299 reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE,
michael@0 2300 0xfedcba9876543210ULL);
michael@0 2301 }
michael@0 2302
michael@0 2303 TEST_F(CFIReporter, NoCFARule) {
michael@0 2304 reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE,
michael@0 2305 0xfedcba9876543210ULL);
michael@0 2306 }
michael@0 2307
michael@0 2308 TEST_F(CFIReporter, EmptyStateStack) {
michael@0 2309 reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator,
michael@0 2310 0xfedcba9876543210ULL);
michael@0 2311 }
michael@0 2312
michael@0 2313 TEST_F(CFIReporter, ClearingCFARule) {
michael@0 2314 reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE,
michael@0 2315 0xfedcba9876543210ULL);
michael@0 2316 }
michael@0 2317
michael@0 2318 #ifdef WRITE_ELF
michael@0 2319 // See comments at the top of the file mentioning WRITE_ELF for details.
michael@0 2320
michael@0 2321 using google_breakpad::test_assembler::Section;
michael@0 2322
michael@0 2323 struct ELFSectionHeader {
michael@0 2324 ELFSectionHeader(unsigned int set_type)
michael@0 2325 : type(set_type), flags(0), address(0), link(0), info(0),
michael@0 2326 alignment(1), entry_size(0) { }
michael@0 2327 Label name;
michael@0 2328 unsigned int type;
michael@0 2329 uint64_t flags;
michael@0 2330 uint64_t address;
michael@0 2331 Label file_offset;
michael@0 2332 Label file_size;
michael@0 2333 unsigned int link;
michael@0 2334 unsigned int info;
michael@0 2335 uint64_t alignment;
michael@0 2336 uint64_t entry_size;
michael@0 2337 };
michael@0 2338
michael@0 2339 void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) {
michael@0 2340 (*table)
michael@0 2341 .D32(header.name) // name, index in string tbl
michael@0 2342 .D32(header.type) // type
michael@0 2343 .Address(header.flags) // flags
michael@0 2344 .Address(header.address) // address in memory
michael@0 2345 .Address(header.file_offset) // offset in ELF file
michael@0 2346 .Address(header.file_size) // length in bytes
michael@0 2347 .D32(header.link) // link to related section
michael@0 2348 .D32(header.info) // miscellaneous
michael@0 2349 .Address(header.alignment) // alignment
michael@0 2350 .Address(header.entry_size); // entry size
michael@0 2351 }
michael@0 2352
michael@0 2353 void WriteELFFrameSection(const char *filename, const char *cfi_name,
michael@0 2354 const CFISection &cfi) {
michael@0 2355 int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64;
michael@0 2356 int elf_data = (cfi.endianness() == kBigEndian
michael@0 2357 ? ELFDATA2MSB : ELFDATA2LSB);
michael@0 2358 CFISection elf(cfi.endianness(), cfi.AddressSize());
michael@0 2359 Label elf_header_size, section_table_offset;
michael@0 2360 elf
michael@0 2361 .Append("\x7f" "ELF")
michael@0 2362 .D8(elf_class) // 32-bit or 64-bit ELF
michael@0 2363 .D8(elf_data) // endianness
michael@0 2364 .D8(1) // ELF version
michael@0 2365 .D8(ELFOSABI_LINUX) // Operating System/ABI indication
michael@0 2366 .D8(0) // ABI version
michael@0 2367 .Append(7, 0xda) // padding
michael@0 2368 .D16(ET_EXEC) // file type: executable file
michael@0 2369 .D16(EM_386) // architecture: Intel IA-32
michael@0 2370 .D32(EV_CURRENT); // ELF version
michael@0 2371 elf
michael@0 2372 .Address(0x0123456789abcdefULL) // program entry point
michael@0 2373 .Address(0) // program header offset
michael@0 2374 .Address(section_table_offset) // section header offset
michael@0 2375 .D32(0) // processor-specific flags
michael@0 2376 .D16(elf_header_size) // ELF header size in bytes */
michael@0 2377 .D16(elf_class == ELFCLASS32 ? 32 : 56) // program header entry size
michael@0 2378 .D16(0) // program header table entry count
michael@0 2379 .D16(elf_class == ELFCLASS32 ? 40 : 64) // section header entry size
michael@0 2380 .D16(3) // section count
michael@0 2381 .D16(1) // section name string table
michael@0 2382 .Mark(&elf_header_size);
michael@0 2383
michael@0 2384 // The null section. Every ELF file has one, as the first entry in
michael@0 2385 // the section header table.
michael@0 2386 ELFSectionHeader null_header(SHT_NULL);
michael@0 2387 null_header.file_offset = 0;
michael@0 2388 null_header.file_size = 0;
michael@0 2389
michael@0 2390 // The CFI section. The whole reason for writing out this ELF file
michael@0 2391 // is to put this in it so that we can run other dumping programs on
michael@0 2392 // it to check its contents.
michael@0 2393 ELFSectionHeader cfi_header(SHT_PROGBITS);
michael@0 2394 cfi_header.file_size = cfi.Size();
michael@0 2395
michael@0 2396 // The section holding the names of the sections. This is the
michael@0 2397 // section whose index appears in the e_shstrndx member of the ELF
michael@0 2398 // header.
michael@0 2399 ELFSectionHeader section_names_header(SHT_STRTAB);
michael@0 2400 CFISection section_names(cfi.endianness(), cfi.AddressSize());
michael@0 2401 section_names
michael@0 2402 .Mark(&null_header.name)
michael@0 2403 .AppendCString("")
michael@0 2404 .Mark(&section_names_header.name)
michael@0 2405 .AppendCString(".shstrtab")
michael@0 2406 .Mark(&cfi_header.name)
michael@0 2407 .AppendCString(cfi_name)
michael@0 2408 .Mark(&section_names_header.file_size);
michael@0 2409
michael@0 2410 // Create the section table. The ELF header's e_shoff member refers
michael@0 2411 // to this, and the e_shnum member gives the number of entries it
michael@0 2412 // contains.
michael@0 2413 CFISection section_table(cfi.endianness(), cfi.AddressSize());
michael@0 2414 AppendSectionHeader(&section_table, null_header);
michael@0 2415 AppendSectionHeader(&section_table, section_names_header);
michael@0 2416 AppendSectionHeader(&section_table, cfi_header);
michael@0 2417
michael@0 2418 // Append the section table and the section contents to the ELF file.
michael@0 2419 elf
michael@0 2420 .Mark(&section_table_offset)
michael@0 2421 .Append(section_table)
michael@0 2422 .Mark(&section_names_header.file_offset)
michael@0 2423 .Append(section_names)
michael@0 2424 .Mark(&cfi_header.file_offset)
michael@0 2425 .Append(cfi);
michael@0 2426
michael@0 2427 string contents;
michael@0 2428 if (!elf.GetContents(&contents)) {
michael@0 2429 fprintf(stderr, "failed to get ELF file contents\n");
michael@0 2430 exit(1);
michael@0 2431 }
michael@0 2432
michael@0 2433 FILE *out = fopen(filename, "w");
michael@0 2434 if (!out) {
michael@0 2435 fprintf(stderr, "error opening ELF file '%s': %s\n",
michael@0 2436 filename, strerror(errno));
michael@0 2437 exit(1);
michael@0 2438 }
michael@0 2439
michael@0 2440 if (fwrite(contents.data(), 1, contents.size(), out) != contents.size()) {
michael@0 2441 fprintf(stderr, "error writing ELF data to '%s': %s\n",
michael@0 2442 filename, strerror(errno));
michael@0 2443 exit(1);
michael@0 2444 }
michael@0 2445
michael@0 2446 if (fclose(out) == EOF) {
michael@0 2447 fprintf(stderr, "error closing ELF file '%s': %s\n",
michael@0 2448 filename, strerror(errno));
michael@0 2449 exit(1);
michael@0 2450 }
michael@0 2451 }
michael@0 2452 #endif

mercurial