Home | History | Annotate | Download | only in linux
      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