// Copyright (c) 2011, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. // See elf_core_dump.h for details. #include "common/linux/elf_core_dump.h" #include #include namespace google_breakpad { // Implementation of ElfCoreDump::Note. ElfCoreDump::Note::Note() {} ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {} bool ElfCoreDump::Note::IsValid() const { return GetHeader() != NULL; } const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const { return content_.GetData(0); } ElfCoreDump::Word ElfCoreDump::Note::GetType() const { const Nhdr* header = GetHeader(); // 0 is not being used as a NOTE type. return header ? header->n_type : 0; } MemoryRange ElfCoreDump::Note::GetName() const { const Nhdr* header = GetHeader(); if (header) { return content_.Subrange(sizeof(Nhdr), header->n_namesz); } return MemoryRange(); } MemoryRange ElfCoreDump::Note::GetDescription() const { const Nhdr* header = GetHeader(); if (header) { return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz), header->n_descsz); } return MemoryRange(); } ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const { MemoryRange next_content; const Nhdr* header = GetHeader(); if (header) { size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz); next_offset = AlignedSize(next_offset + header->n_descsz); next_content = content_.Subrange(next_offset, content_.length() - next_offset); } return Note(next_content); } // static size_t ElfCoreDump::Note::AlignedSize(size_t size) { size_t mask = sizeof(Word) - 1; return (size + mask) & ~mask; } // Implementation of ElfCoreDump. ElfCoreDump::ElfCoreDump() {} ElfCoreDump::ElfCoreDump(const MemoryRange& content) : content_(content) { } void ElfCoreDump::SetContent(const MemoryRange& content) { content_ = content; } bool ElfCoreDump::IsValid() const { const Ehdr* header = GetHeader(); return (header && header->e_ident[0] == ELFMAG0 && header->e_ident[1] == ELFMAG1 && header->e_ident[2] == ELFMAG2 && header->e_ident[3] == ELFMAG3 && header->e_ident[4] == kClass && header->e_version == EV_CURRENT && header->e_type == ET_CORE); } const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const { return content_.GetData(0); } const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const { const Ehdr* header = GetHeader(); if (header) { return reinterpret_cast(content_.GetArrayElement( header->e_phoff, header->e_phentsize, index)); } return NULL; } const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType( Word type) const { for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) { const Phdr* program = GetProgramHeader(i); if (program->p_type == type) { return program; } } return NULL; } unsigned ElfCoreDump::GetProgramHeaderCount() const { const Ehdr* header = GetHeader(); return header ? header->e_phnum : 0; } bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) { for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) { const Phdr* program = GetProgramHeader(i); if (program->p_type != PT_LOAD) continue; size_t offset_in_segment = virtual_address - program->p_vaddr; if (virtual_address >= program->p_vaddr && offset_in_segment < program->p_filesz) { const void* data = content_.GetData(program->p_offset + offset_in_segment, length); if (data) { memcpy(buffer, data, length); return true; } } } return false; } ElfCoreDump::Note ElfCoreDump::GetFirstNote() const { MemoryRange note_content; const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE); if (program_header) { note_content = content_.Subrange(program_header->p_offset, program_header->p_filesz); } return Note(note_content); } } // namespace google_breakpad