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