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 38namespace google_breakpad { 39 40// Implementation of ElfCoreDump::Note. 41 42ElfCoreDump::Note::Note() {} 43 44ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {} 45 46bool ElfCoreDump::Note::IsValid() const { 47 return GetHeader() != NULL; 48} 49 50const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const { 51 return content_.GetData<Nhdr>(0); 52} 53 54ElfCoreDump::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 60MemoryRange 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 68MemoryRange 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 77ElfCoreDump::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 90size_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 98ElfCoreDump::ElfCoreDump() {} 99 100ElfCoreDump::ElfCoreDump(const MemoryRange& content) 101 : content_(content) { 102} 103 104void ElfCoreDump::SetContent(const MemoryRange& content) { 105 content_ = content; 106} 107 108bool 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 120const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const { 121 return content_.GetData<Ehdr>(0); 122} 123 124const 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 133const 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 144unsigned ElfCoreDump::GetProgramHeaderCount() const { 145 const Ehdr* header = GetHeader(); 146 return header ? header->e_phnum : 0; 147} 148 149bool 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 169ElfCoreDump::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