186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// Copyright (c) 2011, Google Inc.
286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// All rights reserved.
386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org//
486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// Redistribution and use in source and binary forms, with or without
586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// modification, are permitted provided that the following conditions are
686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// met:
786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org//
886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org//     * Redistributions of source code must retain the above copyright
986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// notice, this list of conditions and the following disclaimer.
1086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org//     * Redistributions in binary form must reproduce the above
1186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// copyright notice, this list of conditions and the following disclaimer
1286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// in the documentation and/or other materials provided with the
1386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// distribution.
1486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org//     * Neither the name of Google Inc. nor the names of its
1586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// contributors may be used to endorse or promote products derived from
1686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// this software without specific prior written permission.
1786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org//
1886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
3086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// elf_core_dump.cc: Implement google_breakpad::ElfCoreDump.
3186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// See elf_core_dump.h for details.
3286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
3386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org#include "common/linux/elf_core_dump.h"
3486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
3586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org#include <stddef.h>
3686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org#include <string.h>
3786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
3886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgnamespace google_breakpad {
3986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
4086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// Implementation of ElfCoreDump::Note.
4186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
4286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::Note::Note() {}
4386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
4486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {}
4586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
4686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgbool ElfCoreDump::Note::IsValid() const {
4786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return GetHeader() != NULL;
4886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
4986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
5086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgconst ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const {
5186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return content_.GetData<Nhdr>(0);
5286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
5386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
5486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::Word ElfCoreDump::Note::GetType() const {
5586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Nhdr* header = GetHeader();
5686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  // 0 is not being used as a NOTE type.
5786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return header ? header->n_type : 0;
5886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
5986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
6086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgMemoryRange ElfCoreDump::Note::GetName() const {
6186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Nhdr* header = GetHeader();
6286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  if (header) {
6386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org      return content_.Subrange(sizeof(Nhdr), header->n_namesz);
6486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
6586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return MemoryRange();
6686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
6786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
6886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgMemoryRange ElfCoreDump::Note::GetDescription() const {
6986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Nhdr* header = GetHeader();
7086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  if (header) {
7186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz),
7286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org                             header->n_descsz);
7386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
7486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return MemoryRange();
7586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
7686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
7786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const {
7886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  MemoryRange next_content;
7986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Nhdr* header = GetHeader();
8086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  if (header) {
8186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz);
8286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    next_offset = AlignedSize(next_offset + header->n_descsz);
8386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    next_content =
8486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org        content_.Subrange(next_offset, content_.length() - next_offset);
8586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
8686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return Note(next_content);
8786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
8886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
8986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// static
9086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgsize_t ElfCoreDump::Note::AlignedSize(size_t size) {
9186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  size_t mask = sizeof(Word) - 1;
9286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return (size + mask) & ~mask;
9386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
9486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
9586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
9686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org// Implementation of ElfCoreDump.
9786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
9886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::ElfCoreDump() {}
9986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
10086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::ElfCoreDump(const MemoryRange& content)
10186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    : content_(content) {
10286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
10386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
10486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgvoid ElfCoreDump::SetContent(const MemoryRange& content) {
10586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  content_ = content;
10686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
10786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
10886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgbool ElfCoreDump::IsValid() const {
10986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Ehdr* header = GetHeader();
11086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return (header &&
11186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_ident[0] == ELFMAG0 &&
11286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_ident[1] == ELFMAG1 &&
11386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_ident[2] == ELFMAG2 &&
11486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_ident[3] == ELFMAG3 &&
11586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_ident[4] == kClass &&
11686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_version == EV_CURRENT &&
11786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          header->e_type == ET_CORE);
11886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
11986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
12086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgconst ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const {
12186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return content_.GetData<Ehdr>(0);
12286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
12386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
12486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgconst ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const {
12586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Ehdr* header = GetHeader();
12686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  if (header) {
12786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    return reinterpret_cast<const Phdr*>(content_.GetArrayElement(
12886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org        header->e_phoff, header->e_phentsize, index));
12986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
13086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return NULL;
13186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
13286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
13386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgconst ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType(
13486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    Word type) const {
13586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
13686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    const Phdr* program = GetProgramHeader(i);
13786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    if (program->p_type == type) {
13886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org      return program;
13986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    }
14086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
14186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return NULL;
14286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
14386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
14486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgunsigned ElfCoreDump::GetProgramHeaderCount() const {
14586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Ehdr* header = GetHeader();
14686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return header ? header->e_phnum : 0;
14786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
14886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
14986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgbool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) {
15086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
15186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    const Phdr* program = GetProgramHeader(i);
15286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    if (program->p_type != PT_LOAD)
15386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org      continue;
15486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
15586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    size_t offset_in_segment = virtual_address - program->p_vaddr;
15686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    if (virtual_address >= program->p_vaddr &&
15786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org        offset_in_segment < program->p_filesz) {
15886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org      const void* data =
15986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org          content_.GetData(program->p_offset + offset_in_segment, length);
16086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org      if (data) {
16186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org        memcpy(buffer, data, length);
16286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org        return true;
16386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org      }
16486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    }
16586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
16686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return false;
16786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
16886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
16986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.orgElfCoreDump::Note ElfCoreDump::GetFirstNote() const {
17086cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  MemoryRange note_content;
17186cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE);
17286cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  if (program_header) {
17386cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org    note_content = content_.Subrange(program_header->p_offset,
17486cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org                                     program_header->p_filesz);
17586cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  }
17686cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org  return Note(note_content);
17786cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}
17886cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org
17986cbb1e5cc967853dfc2b10f8fc8da43fc734c77benchan@chromium.org}  // namespace google_breakpad
180