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.cc: Implement google_breakpad::ElfCoreDump.
     31 // See elf_core_dump.h for details.
     32 
     33 #include "common/linux/elf_core_dump.h"
     34 
     35 #include <stddef.h>
     36 #include <string.h>
     37 
     38 namespace google_breakpad {
     39 
     40 // Implementation of ElfCoreDump::Note.
     41 
     42 ElfCoreDump::Note::Note() {}
     43 
     44 ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {}
     45 
     46 bool ElfCoreDump::Note::IsValid() const {
     47   return GetHeader() != NULL;
     48 }
     49 
     50 const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const {
     51   return content_.GetData<Nhdr>(0);
     52 }
     53 
     54 ElfCoreDump::Word ElfCoreDump::Note::GetType() const {
     55   const Nhdr* header = GetHeader();
     56   // 0 is not being used as a NOTE type.
     57   return header ? header->n_type : 0;
     58 }
     59 
     60 MemoryRange ElfCoreDump::Note::GetName() const {
     61   const Nhdr* header = GetHeader();
     62   if (header) {
     63       return content_.Subrange(sizeof(Nhdr), header->n_namesz);
     64   }
     65   return MemoryRange();
     66 }
     67 
     68 MemoryRange ElfCoreDump::Note::GetDescription() const {
     69   const Nhdr* header = GetHeader();
     70   if (header) {
     71     return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz),
     72                              header->n_descsz);
     73   }
     74   return MemoryRange();
     75 }
     76 
     77 ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const {
     78   MemoryRange next_content;
     79   const Nhdr* header = GetHeader();
     80   if (header) {
     81     size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz);
     82     next_offset = AlignedSize(next_offset + header->n_descsz);
     83     next_content =
     84         content_.Subrange(next_offset, content_.length() - next_offset);
     85   }
     86   return Note(next_content);
     87 }
     88 
     89 // static
     90 size_t ElfCoreDump::Note::AlignedSize(size_t size) {
     91   size_t mask = sizeof(Word) - 1;
     92   return (size + mask) & ~mask;
     93 }
     94 
     95 
     96 // Implementation of ElfCoreDump.
     97 
     98 ElfCoreDump::ElfCoreDump() {}
     99 
    100 ElfCoreDump::ElfCoreDump(const MemoryRange& content)
    101     : content_(content) {
    102 }
    103 
    104 void ElfCoreDump::SetContent(const MemoryRange& content) {
    105   content_ = content;
    106 }
    107 
    108 bool ElfCoreDump::IsValid() const {
    109   const Ehdr* header = GetHeader();
    110   return (header &&
    111           header->e_ident[0] == ELFMAG0 &&
    112           header->e_ident[1] == ELFMAG1 &&
    113           header->e_ident[2] == ELFMAG2 &&
    114           header->e_ident[3] == ELFMAG3 &&
    115           header->e_ident[4] == kClass &&
    116           header->e_version == EV_CURRENT &&
    117           header->e_type == ET_CORE);
    118 }
    119 
    120 const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const {
    121   return content_.GetData<Ehdr>(0);
    122 }
    123 
    124 const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const {
    125   const Ehdr* header = GetHeader();
    126   if (header) {
    127     return reinterpret_cast<const Phdr*>(content_.GetArrayElement(
    128         header->e_phoff, header->e_phentsize, index));
    129   }
    130   return NULL;
    131 }
    132 
    133 const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType(
    134     Word type) const {
    135   for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
    136     const Phdr* program = GetProgramHeader(i);
    137     if (program->p_type == type) {
    138       return program;
    139     }
    140   }
    141   return NULL;
    142 }
    143 
    144 unsigned ElfCoreDump::GetProgramHeaderCount() const {
    145   const Ehdr* header = GetHeader();
    146   return header ? header->e_phnum : 0;
    147 }
    148 
    149 bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) {
    150   for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
    151     const Phdr* program = GetProgramHeader(i);
    152     if (program->p_type != PT_LOAD)
    153       continue;
    154 
    155     size_t offset_in_segment = virtual_address - program->p_vaddr;
    156     if (virtual_address >= program->p_vaddr &&
    157         offset_in_segment < program->p_filesz) {
    158       const void* data =
    159           content_.GetData(program->p_offset + offset_in_segment, length);
    160       if (data) {
    161         memcpy(buffer, data, length);
    162         return true;
    163       }
    164     }
    165   }
    166   return false;
    167 }
    168 
    169 ElfCoreDump::Note ElfCoreDump::GetFirstNote() const {
    170   MemoryRange note_content;
    171   const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE);
    172   if (program_header) {
    173     note_content = content_.Subrange(program_header->p_offset,
    174                                      program_header->p_filesz);
    175   }
    176   return Note(note_content);
    177 }
    178 
    179 }  // namespace google_breakpad
    180