1 // Copyright (c) 2011, 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 // elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. 31 32 #include <sys/procfs.h> 33 34 #include <set> 35 #include <string> 36 37 #include "breakpad_googletest_includes.h" 38 #include "common/linux/elf_core_dump.h" 39 #include "common/linux/memory_mapped_file.h" 40 #include "common/tests/file_utils.h" 41 #include "common/linux/tests/crash_generator.h" 42 #include "common/using_std_string.h" 43 44 using google_breakpad::AutoTempDir; 45 using google_breakpad::CrashGenerator; 46 using google_breakpad::ElfCoreDump; 47 using google_breakpad::MemoryMappedFile; 48 using google_breakpad::MemoryRange; 49 using google_breakpad::WriteFile; 50 using std::set; 51 52 TEST(ElfCoreDumpTest, DefaultConstructor) { 53 ElfCoreDump core; 54 EXPECT_FALSE(core.IsValid()); 55 EXPECT_EQ(NULL, core.GetHeader()); 56 EXPECT_EQ(0U, core.GetProgramHeaderCount()); 57 EXPECT_EQ(NULL, core.GetProgramHeader(0)); 58 EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); 59 EXPECT_FALSE(core.GetFirstNote().IsValid()); 60 } 61 62 TEST(ElfCoreDumpTest, TestElfHeader) { 63 ElfCoreDump::Ehdr header; 64 memset(&header, 0, sizeof(header)); 65 66 AutoTempDir temp_dir; 67 string core_path = temp_dir.path() + "/core"; 68 const char* core_file = core_path.c_str(); 69 MemoryMappedFile mapped_core_file; 70 ElfCoreDump core; 71 72 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1)); 73 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 74 core.SetContent(mapped_core_file.content()); 75 EXPECT_FALSE(core.IsValid()); 76 EXPECT_EQ(NULL, core.GetHeader()); 77 EXPECT_EQ(0U, core.GetProgramHeaderCount()); 78 EXPECT_EQ(NULL, core.GetProgramHeader(0)); 79 EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); 80 EXPECT_FALSE(core.GetFirstNote().IsValid()); 81 82 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 83 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 84 core.SetContent(mapped_core_file.content()); 85 EXPECT_FALSE(core.IsValid()); 86 87 header.e_ident[0] = ELFMAG0; 88 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 89 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 90 core.SetContent(mapped_core_file.content()); 91 EXPECT_FALSE(core.IsValid()); 92 93 header.e_ident[1] = ELFMAG1; 94 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 95 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 96 core.SetContent(mapped_core_file.content()); 97 EXPECT_FALSE(core.IsValid()); 98 99 header.e_ident[2] = ELFMAG2; 100 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 101 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 102 core.SetContent(mapped_core_file.content()); 103 EXPECT_FALSE(core.IsValid()); 104 105 header.e_ident[3] = ELFMAG3; 106 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 107 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 108 core.SetContent(mapped_core_file.content()); 109 EXPECT_FALSE(core.IsValid()); 110 111 header.e_ident[4] = ElfCoreDump::kClass; 112 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 113 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 114 core.SetContent(mapped_core_file.content()); 115 EXPECT_FALSE(core.IsValid()); 116 117 header.e_version = EV_CURRENT; 118 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 119 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 120 core.SetContent(mapped_core_file.content()); 121 EXPECT_FALSE(core.IsValid()); 122 123 header.e_type = ET_CORE; 124 ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); 125 ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); 126 core.SetContent(mapped_core_file.content()); 127 EXPECT_TRUE(core.IsValid()); 128 } 129 130 TEST(ElfCoreDumpTest, ValidCoreFile) { 131 CrashGenerator crash_generator; 132 if (!crash_generator.HasDefaultCorePattern()) { 133 fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " 134 "due to non-default core pattern"); 135 return; 136 } 137 138 const unsigned kNumOfThreads = 3; 139 const unsigned kCrashThread = 1; 140 const int kCrashSignal = SIGABRT; 141 ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, 142 kCrashSignal, NULL)); 143 pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread); 144 set<pid_t> expected_thread_ids; 145 for (unsigned i = 0; i < kNumOfThreads; ++i) { 146 expected_thread_ids.insert(crash_generator.GetThreadId(i)); 147 } 148 149 #if defined(__ANDROID__) 150 struct stat st; 151 if (stat(crash_generator.GetCoreFilePath().c_str(), &st) != 0) { 152 fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " 153 "due to no core file being generated"); 154 return; 155 } 156 #endif 157 158 MemoryMappedFile mapped_core_file; 159 ASSERT_TRUE( 160 mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str(), 0)); 161 162 ElfCoreDump core; 163 core.SetContent(mapped_core_file.content()); 164 EXPECT_TRUE(core.IsValid()); 165 166 // Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are 167 // ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific): 168 // Thread Name Type 169 // ------------------------------------------------------------------- 170 // 1st thread CORE NT_PRSTATUS 171 // process-wide CORE NT_PRPSINFO 172 // process-wide CORE NT_AUXV 173 // 1st thread CORE NT_FPREGSET 174 // 1st thread LINUX NT_PRXFPREG 175 // 1st thread LINUX NT_386_TLS 176 // 177 // 2nd thread CORE NT_PRSTATUS 178 // 2nd thread CORE NT_FPREGSET 179 // 2nd thread LINUX NT_PRXFPREG 180 // 2nd thread LINUX NT_386_TLS 181 // 182 // 3rd thread CORE NT_PRSTATUS 183 // 3rd thread CORE NT_FPREGSET 184 // 3rd thread LINUX NT_PRXFPREG 185 // 3rd thread LINUX NT_386_TLS 186 187 size_t num_nt_prpsinfo = 0; 188 size_t num_nt_prstatus = 0; 189 size_t num_pr_fpvalid = 0; 190 #if defined(__i386__) || defined(__x86_64__) 191 size_t num_nt_fpregset = 0; 192 #endif 193 #if defined(__i386__) 194 size_t num_nt_prxfpreg = 0; 195 #endif 196 set<pid_t> actual_thread_ids; 197 ElfCoreDump::Note note = core.GetFirstNote(); 198 while (note.IsValid()) { 199 MemoryRange name = note.GetName(); 200 MemoryRange description = note.GetDescription(); 201 EXPECT_FALSE(name.IsEmpty()); 202 EXPECT_FALSE(description.IsEmpty()); 203 204 switch (note.GetType()) { 205 case NT_PRPSINFO: { 206 EXPECT_TRUE(description.data() != NULL); 207 EXPECT_EQ(sizeof(elf_prpsinfo), description.length()); 208 ++num_nt_prpsinfo; 209 break; 210 } 211 case NT_PRSTATUS: { 212 EXPECT_TRUE(description.data() != NULL); 213 EXPECT_EQ(sizeof(elf_prstatus), description.length()); 214 const elf_prstatus* status = description.GetData<elf_prstatus>(0); 215 actual_thread_ids.insert(status->pr_pid); 216 if (num_nt_prstatus == 0) { 217 EXPECT_EQ(expected_crash_thread_id, status->pr_pid); 218 EXPECT_EQ(kCrashSignal, status->pr_info.si_signo); 219 } 220 ++num_nt_prstatus; 221 if (status->pr_fpvalid) 222 ++num_pr_fpvalid; 223 break; 224 } 225 #if defined(__i386__) || defined(__x86_64__) 226 case NT_FPREGSET: { 227 EXPECT_TRUE(description.data() != NULL); 228 EXPECT_EQ(sizeof(user_fpregs_struct), description.length()); 229 ++num_nt_fpregset; 230 break; 231 } 232 #endif 233 #if defined(__i386__) 234 case NT_PRXFPREG: { 235 EXPECT_TRUE(description.data() != NULL); 236 EXPECT_EQ(sizeof(user_fpxregs_struct), description.length()); 237 ++num_nt_prxfpreg; 238 break; 239 } 240 #endif 241 default: 242 break; 243 } 244 note = note.GetNextNote(); 245 } 246 247 EXPECT_TRUE(expected_thread_ids == actual_thread_ids); 248 EXPECT_EQ(1U, num_nt_prpsinfo); 249 EXPECT_EQ(kNumOfThreads, num_nt_prstatus); 250 #if defined(__i386__) || defined(__x86_64__) 251 EXPECT_EQ(num_pr_fpvalid, num_nt_fpregset); 252 #endif 253 #if defined(__i386__) 254 EXPECT_EQ(num_pr_fpvalid, num_nt_prxfpreg); 255 #endif 256 } 257