1 // Copyright (c) 2012, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com> 31 32 // dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit 33 34 #include <stdlib.h> 35 36 #include <iostream> 37 #include <string> 38 #include <vector> 39 40 #include "breakpad_googletest_includes.h" 41 #include "common/dwarf/bytereader-inl.h" 42 #include "common/dwarf/dwarf2reader_test_common.h" 43 #include "common/dwarf/dwarf2reader.h" 44 #include "common/using_std_string.h" 45 #include "google_breakpad/common/breakpad_types.h" 46 47 using google_breakpad::test_assembler::Endianness; 48 using google_breakpad::test_assembler::Label; 49 using google_breakpad::test_assembler::Section; 50 using google_breakpad::test_assembler::kBigEndian; 51 using google_breakpad::test_assembler::kLittleEndian; 52 53 using dwarf2reader::ByteReader; 54 using dwarf2reader::CompilationUnit; 55 using dwarf2reader::Dwarf2Handler; 56 using dwarf2reader::DwarfAttribute; 57 using dwarf2reader::DwarfForm; 58 using dwarf2reader::DwarfHasChild; 59 using dwarf2reader::DwarfTag; 60 using dwarf2reader::ENDIANNESS_BIG; 61 using dwarf2reader::ENDIANNESS_LITTLE; 62 using dwarf2reader::SectionMap; 63 64 using std::vector; 65 using testing::InSequence; 66 using testing::Pointee; 67 using testing::Return; 68 using testing::Sequence; 69 using testing::Test; 70 using testing::TestWithParam; 71 using testing::_; 72 73 class MockDwarf2Handler: public Dwarf2Handler { 74 public: 75 MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size, 76 uint8 offset_size, uint64 cu_length, 77 uint8 dwarf_version)); 78 MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag)); 79 MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset, 80 DwarfAttribute attr, 81 enum DwarfForm form, 82 uint64 data)); 83 MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset, 84 enum DwarfAttribute attr, 85 enum DwarfForm form, 86 int64 data)); 87 MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset, 88 enum DwarfAttribute attr, 89 enum DwarfForm form, 90 uint64 data)); 91 MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset, 92 enum DwarfAttribute attr, 93 enum DwarfForm form, 94 const char* data, 95 uint64 len)); 96 MOCK_METHOD4(ProcessAttributeString, void(uint64 offset, 97 enum DwarfAttribute attr, 98 enum DwarfForm form, 99 const string& data)); 100 MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset, 101 DwarfAttribute attr, 102 enum DwarfForm form, 103 uint64 signature)); 104 MOCK_METHOD1(EndDIE, void(uint64 offset)); 105 }; 106 107 struct DIEFixture { 108 109 DIEFixture() { 110 // Fix the initial offset of the .debug_info and .debug_abbrev sections. 111 info.start() = 0; 112 abbrevs.start() = 0; 113 114 // Default expectations for the data handler. 115 EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0); 116 EXPECT_CALL(handler, StartDIE(_, _)).Times(0); 117 EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0); 118 EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0); 119 EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0); 120 EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0); 121 EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0); 122 EXPECT_CALL(handler, EndDIE(_)).Times(0); 123 } 124 125 // Return a reference to a section map whose .debug_info section refers 126 // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This 127 // function returns a reference to the same SectionMap each time; new 128 // calls wipe out maps established by earlier calls. 129 const SectionMap &MakeSectionMap() { 130 // Copy the sections' contents into strings that will live as long as 131 // the map itself. 132 assert(info.GetContents(&info_contents)); 133 assert(abbrevs.GetContents(&abbrevs_contents)); 134 section_map.clear(); 135 section_map[".debug_info"].first = info_contents.data(); 136 section_map[".debug_info"].second = info_contents.size(); 137 section_map[".debug_abbrev"].first = abbrevs_contents.data(); 138 section_map[".debug_abbrev"].second = abbrevs_contents.size(); 139 return section_map; 140 } 141 142 TestCompilationUnit info; 143 TestAbbrevTable abbrevs; 144 MockDwarf2Handler handler; 145 string abbrevs_contents, info_contents; 146 SectionMap section_map; 147 }; 148 149 struct DwarfHeaderParams { 150 DwarfHeaderParams(Endianness endianness, size_t format_size, 151 int version, size_t address_size) 152 : endianness(endianness), format_size(format_size), 153 version(version), address_size(address_size) { } 154 Endianness endianness; 155 size_t format_size; // 4-byte or 8-byte DWARF offsets 156 int version; 157 size_t address_size; 158 }; 159 160 class DwarfHeader: public DIEFixture, 161 public TestWithParam<DwarfHeaderParams> { }; 162 163 TEST_P(DwarfHeader, Header) { 164 Label abbrev_table = abbrevs.Here(); 165 abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, 166 dwarf2reader::DW_children_yes) 167 .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string) 168 .EndAbbrev() 169 .EndTable(); 170 171 info.set_format_size(GetParam().format_size); 172 info.set_endianness(GetParam().endianness); 173 174 info.Header(GetParam().version, abbrev_table, GetParam().address_size) 175 .ULEB128(1) // DW_TAG_compile_unit, with children 176 .AppendCString("sam") // DW_AT_name, DW_FORM_string 177 .D8(0); // end of children 178 info.Finish(); 179 180 { 181 InSequence s; 182 EXPECT_CALL(handler, 183 StartCompilationUnit(0, GetParam().address_size, 184 GetParam().format_size, _, 185 GetParam().version)) 186 .WillOnce(Return(true)); 187 EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) 188 .WillOnce(Return(true)); 189 EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, 190 dwarf2reader::DW_FORM_string, 191 "sam")) 192 .WillOnce(Return()); 193 EXPECT_CALL(handler, EndDIE(_)) 194 .WillOnce(Return()); 195 } 196 197 ByteReader byte_reader(GetParam().endianness == kLittleEndian ? 198 ENDIANNESS_LITTLE : ENDIANNESS_BIG); 199 CompilationUnit parser(MakeSectionMap(), 0, &byte_reader, &handler); 200 EXPECT_EQ(parser.Start(), info_contents.size()); 201 } 202 203 INSTANTIATE_TEST_CASE_P( 204 HeaderVariants, DwarfHeader, 205 ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), 206 DwarfHeaderParams(kLittleEndian, 4, 2, 8), 207 DwarfHeaderParams(kLittleEndian, 4, 3, 4), 208 DwarfHeaderParams(kLittleEndian, 4, 3, 8), 209 DwarfHeaderParams(kLittleEndian, 4, 4, 4), 210 DwarfHeaderParams(kLittleEndian, 4, 4, 8), 211 DwarfHeaderParams(kLittleEndian, 8, 2, 4), 212 DwarfHeaderParams(kLittleEndian, 8, 2, 8), 213 DwarfHeaderParams(kLittleEndian, 8, 3, 4), 214 DwarfHeaderParams(kLittleEndian, 8, 3, 8), 215 DwarfHeaderParams(kLittleEndian, 8, 4, 4), 216 DwarfHeaderParams(kLittleEndian, 8, 4, 8), 217 DwarfHeaderParams(kBigEndian, 4, 2, 4), 218 DwarfHeaderParams(kBigEndian, 4, 2, 8), 219 DwarfHeaderParams(kBigEndian, 4, 3, 4), 220 DwarfHeaderParams(kBigEndian, 4, 3, 8), 221 DwarfHeaderParams(kBigEndian, 4, 4, 4), 222 DwarfHeaderParams(kBigEndian, 4, 4, 8), 223 DwarfHeaderParams(kBigEndian, 8, 2, 4), 224 DwarfHeaderParams(kBigEndian, 8, 2, 8), 225 DwarfHeaderParams(kBigEndian, 8, 3, 4), 226 DwarfHeaderParams(kBigEndian, 8, 3, 8), 227 DwarfHeaderParams(kBigEndian, 8, 4, 4), 228 DwarfHeaderParams(kBigEndian, 8, 4, 8))); 229 230 struct DwarfFormsFixture: public DIEFixture { 231 // Start a compilation unit, as directed by |params|, containing one 232 // childless DIE of the given tag, with one attribute of the given name 233 // and form. The 'info' fixture member is left just after the abbrev 234 // code, waiting for the attribute value to be appended. 235 void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms, 236 DwarfTag tag, DwarfAttribute name, 237 DwarfForm form) { 238 // Create the abbreviation table. 239 Label abbrev_table = abbrevs.Here(); 240 abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no) 241 .Attribute(name, form) 242 .EndAbbrev() 243 .EndTable(); 244 245 // Create the compilation unit, up to the attribute value. 246 info.set_format_size(params.format_size); 247 info.set_endianness(params.endianness); 248 info.Header(params.version, abbrev_table, params.address_size) 249 .ULEB128(1); // abbrev code 250 } 251 252 // Set up handler to expect a compilation unit matching |params|, 253 // containing one childless DIE of the given tag, in the sequence s. Stop 254 // just before the expectations. 255 void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms, 256 DwarfTag tag, uint64 offset=0) { 257 EXPECT_CALL(handler, 258 StartCompilationUnit(offset, params.address_size, 259 params.format_size, _, 260 params.version)) 261 .InSequence(s) 262 .WillOnce(Return(true)); 263 EXPECT_CALL(handler, StartDIE(_, tag)) 264 .InSequence(s) 265 .WillOnce(Return(true)); 266 } 267 268 void ExpectEndCompilationUnit() { 269 EXPECT_CALL(handler, EndDIE(_)) 270 .InSequence(s) 271 .WillOnce(Return()); 272 } 273 274 void ParseCompilationUnit(const DwarfHeaderParams ¶ms, uint64 offset=0) { 275 ByteReader byte_reader(params.endianness == kLittleEndian ? 276 ENDIANNESS_LITTLE : ENDIANNESS_BIG); 277 CompilationUnit parser(MakeSectionMap(), offset, &byte_reader, &handler); 278 EXPECT_EQ(offset + parser.Start(), info_contents.size()); 279 } 280 281 // The sequence to which the fixture's methods append expectations. 282 Sequence s; 283 }; 284 285 struct DwarfForms: public DwarfFormsFixture, 286 public TestWithParam<DwarfHeaderParams> { }; 287 288 TEST_P(DwarfForms, addr) { 289 StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit, 290 dwarf2reader::DW_AT_low_pc, 291 dwarf2reader::DW_FORM_addr); 292 uint64_t value; 293 if (GetParam().address_size == 4) { 294 value = 0xc8e9ffcc; 295 info.D32(value); 296 } else { 297 value = 0xe942517fc2768564ULL; 298 info.D64(value); 299 } 300 info.Finish(); 301 302 ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); 303 EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, 304 dwarf2reader::DW_FORM_addr, 305 value)) 306 .InSequence(s) 307 .WillOnce(Return()); 308 ExpectEndCompilationUnit(); 309 310 ParseCompilationUnit(GetParam()); 311 } 312 313 TEST_P(DwarfForms, block2_empty) { 314 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, 315 (DwarfAttribute) 0xe52c4463, 316 dwarf2reader::DW_FORM_block2); 317 info.D16(0); 318 info.Finish(); 319 320 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); 321 EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, 322 dwarf2reader::DW_FORM_block2, 323 _, 0)) 324 .InSequence(s) 325 .WillOnce(Return()); 326 ExpectEndCompilationUnit(); 327 328 ParseCompilationUnit(GetParam()); 329 } 330 331 TEST_P(DwarfForms, block2) { 332 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, 333 (DwarfAttribute) 0xe52c4463, 334 dwarf2reader::DW_FORM_block2); 335 unsigned char data[258]; 336 memset(data, '*', sizeof(data)); 337 info.D16(sizeof(data)) 338 .Append(data, sizeof(data)); 339 info.Finish(); 340 341 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); 342 EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, 343 dwarf2reader::DW_FORM_block2, 344 Pointee('*'), 258)) 345 .InSequence(s) 346 .WillOnce(Return()); 347 ExpectEndCompilationUnit(); 348 349 ParseCompilationUnit(GetParam()); 350 } 351 352 TEST_P(DwarfForms, flag_present) { 353 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, 354 (DwarfAttribute) 0x359d1972, 355 dwarf2reader::DW_FORM_flag_present); 356 // DW_FORM_flag_present occupies no space in the DIE. 357 info.Finish(); 358 359 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2); 360 EXPECT_CALL(handler, 361 ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972, 362 dwarf2reader::DW_FORM_flag_present, 363 1)) 364 .InSequence(s) 365 .WillOnce(Return()); 366 ExpectEndCompilationUnit(); 367 368 ParseCompilationUnit(GetParam()); 369 } 370 371 TEST_P(DwarfForms, sec_offset) { 372 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, 373 (DwarfAttribute) 0xa060bfd1, 374 dwarf2reader::DW_FORM_sec_offset); 375 uint64_t value; 376 if (GetParam().format_size == 4) { 377 value = 0xacc9c388; 378 info.D32(value); 379 } else { 380 value = 0xcffe5696ffe3ed0aULL; 381 info.D64(value); 382 } 383 info.Finish(); 384 385 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689); 386 EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1, 387 dwarf2reader::DW_FORM_sec_offset, 388 value)) 389 .InSequence(s) 390 .WillOnce(Return()); 391 ExpectEndCompilationUnit(); 392 393 ParseCompilationUnit(GetParam()); 394 } 395 396 TEST_P(DwarfForms, exprloc) { 397 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, 398 (DwarfAttribute) 0xba3ae5cb, 399 dwarf2reader::DW_FORM_exprloc); 400 info.ULEB128(29) 401 .Append(29, 173); 402 info.Finish(); 403 404 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb); 405 EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb, 406 dwarf2reader::DW_FORM_exprloc, 407 Pointee(173), 29)) 408 .InSequence(s) 409 .WillOnce(Return()); 410 ExpectEndCompilationUnit(); 411 412 ParseCompilationUnit(GetParam()); 413 } 414 415 TEST_P(DwarfForms, ref_sig8) { 416 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, 417 (DwarfAttribute) 0xd708d908, 418 dwarf2reader::DW_FORM_ref_sig8); 419 info.D64(0xf72fa0cb6ddcf9d6ULL); 420 info.Finish(); 421 422 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); 423 EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, 424 dwarf2reader::DW_FORM_ref_sig8, 425 0xf72fa0cb6ddcf9d6ULL)) 426 .InSequence(s) 427 .WillOnce(Return()); 428 ExpectEndCompilationUnit(); 429 430 ParseCompilationUnit(GetParam()); 431 } 432 433 // A value passed to ProcessAttributeSignature is just an absolute number, 434 // not an offset within the compilation unit as most of the other 435 // DW_FORM_ref forms are. Check that the reader doesn't try to apply any 436 // offset to the signature, by reading it from a compilation unit that does 437 // not start at the beginning of the section. 438 TEST_P(DwarfForms, ref_sig8_not_first) { 439 info.Append(98, '*'); 440 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, 441 (DwarfAttribute) 0xd708d908, 442 dwarf2reader::DW_FORM_ref_sig8); 443 info.D64(0xf72fa0cb6ddcf9d6ULL); 444 info.Finish(); 445 446 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98); 447 EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, 448 dwarf2reader::DW_FORM_ref_sig8, 449 0xf72fa0cb6ddcf9d6ULL)) 450 .InSequence(s) 451 .WillOnce(Return()); 452 ExpectEndCompilationUnit(); 453 454 ParseCompilationUnit(GetParam(), 98); 455 } 456 457 // Tests for the other attribute forms could go here. 458 459 INSTANTIATE_TEST_CASE_P( 460 HeaderVariants, DwarfForms, 461 ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), 462 DwarfHeaderParams(kLittleEndian, 4, 2, 8), 463 DwarfHeaderParams(kLittleEndian, 4, 3, 4), 464 DwarfHeaderParams(kLittleEndian, 4, 3, 8), 465 DwarfHeaderParams(kLittleEndian, 4, 4, 4), 466 DwarfHeaderParams(kLittleEndian, 4, 4, 8), 467 DwarfHeaderParams(kLittleEndian, 8, 2, 4), 468 DwarfHeaderParams(kLittleEndian, 8, 2, 8), 469 DwarfHeaderParams(kLittleEndian, 8, 3, 4), 470 DwarfHeaderParams(kLittleEndian, 8, 3, 8), 471 DwarfHeaderParams(kLittleEndian, 8, 4, 4), 472 DwarfHeaderParams(kLittleEndian, 8, 4, 8), 473 DwarfHeaderParams(kBigEndian, 4, 2, 4), 474 DwarfHeaderParams(kBigEndian, 4, 2, 8), 475 DwarfHeaderParams(kBigEndian, 4, 3, 4), 476 DwarfHeaderParams(kBigEndian, 4, 3, 8), 477 DwarfHeaderParams(kBigEndian, 4, 4, 4), 478 DwarfHeaderParams(kBigEndian, 4, 4, 8), 479 DwarfHeaderParams(kBigEndian, 8, 2, 4), 480 DwarfHeaderParams(kBigEndian, 8, 2, 8), 481 DwarfHeaderParams(kBigEndian, 8, 3, 4), 482 DwarfHeaderParams(kBigEndian, 8, 3, 8), 483 DwarfHeaderParams(kBigEndian, 8, 4, 4), 484 DwarfHeaderParams(kBigEndian, 8, 4, 8))); 485