14fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Copyright (c) 2012, Google Inc.
24fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// All rights reserved.
34fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org//
44fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Redistribution and use in source and binary forms, with or without
54fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// modification, are permitted provided that the following conditions are
64fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// met:
74fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org//
84fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org//     * Redistributions of source code must retain the above copyright
94fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// notice, this list of conditions and the following disclaimer.
104fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org//     * Redistributions in binary form must reproduce the above
114fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// copyright notice, this list of conditions and the following disclaimer
124fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// in the documentation and/or other materials provided with the
134fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// distribution.
144fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org//     * Neither the name of Google Inc. nor the names of its
154fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// contributors may be used to endorse or promote products derived from
164fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// this software without specific prior written permission.
174fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org//
184fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
194fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
204fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
214fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
224fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
234fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
244fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
254fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
264fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
274fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
284fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
294fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
304fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper.
314fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// See linux_ptrace_dumper.h for detals.
324fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// This class was originally splitted from google_breakpad::LinuxDumper.
334fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
344fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// This code deals with the mechanics of getting information about a crashed
354fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// process. Since this code may run in a compromised address space, the same
364fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// rules apply as detailed at the top of minidump_writer.h: no libc calls and
374fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// use the alternative allocator.
384fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
394fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
404fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
414fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <asm/ptrace.h>
424fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <assert.h>
434fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <errno.h>
444fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <fcntl.h>
454fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <limits.h>
464fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <stddef.h>
474fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <stdlib.h>
484fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <string.h>
494fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <sys/ptrace.h>
502eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org#include <sys/uio.h>
514fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include <sys/wait.h>
524fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
53f605532926a303b4ba7a68fe1864d7a2f4c16f9emcgrathr@chromium.org#if defined(__i386)
54f605532926a303b4ba7a68fe1864d7a2f4c16f9emcgrathr@chromium.org#include <cpuid.h>
55f605532926a303b4ba7a68fe1864d7a2f4c16f9emcgrathr@chromium.org#endif
56f605532926a303b4ba7a68fe1864d7a2f4c16f9emcgrathr@chromium.org
574fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "client/linux/minidump_writer/directory_reader.h"
584fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "client/linux/minidump_writer/line_reader.h"
594fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "common/linux/linux_libc_support.h"
604fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "third_party/lss/linux_syscall_support.h"
614fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
624fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Suspends a thread by attaching to it.
634fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgstatic bool SuspendThread(pid_t pid) {
644fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // This may fail if the thread has just died or debugged.
654fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  errno = 0;
664fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
674fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      errno != 0) {
684fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
694fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
704fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  while (sys_waitpid(pid, NULL, __WALL) < 0) {
714fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (errno != EINTR) {
724fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
734fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      return false;
744fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    }
754fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
764fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#if defined(__i386) || defined(__x86_64)
774fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // On x86, the stack pointer is NULL or -1, when executing trusted code in
784fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // the seccomp sandbox. Not only does this cause difficulties down the line
794fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // when trying to dump the thread's stack, it also results in the minidumps
804fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // containing information about the trusted threads. This information is
814fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // generally completely meaningless and just pollutes the minidumps.
824fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // We thus test the stack pointer and exclude any threads that are part of
834fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // the seccomp sandbox's trusted code.
844fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  user_regs_struct regs;
854fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
864fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#if defined(__i386)
874fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      !regs.esp
884fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#elif defined(__x86_64)
894fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      !regs.rsp
904fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#endif
914fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      ) {
924fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
934fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
944fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
954fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#endif
964fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return true;
974fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
984fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
994fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Resumes a thread by detaching from it.
1004fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgstatic bool ResumeThread(pid_t pid) {
1014fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
1024fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
1034fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1044fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgnamespace google_breakpad {
1054fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1064fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgLinuxPtraceDumper::LinuxPtraceDumper(pid_t pid)
1074fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    : LinuxDumper(pid),
1084fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      threads_suspended_(false) {
1094fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
1104fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1114fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgbool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
1124fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org                                      const char* node) const {
1134fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (!path || !node || pid <= 0)
1144fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1154fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1164fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  size_t node_len = my_strlen(node);
1174fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (node_len == 0)
1184fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1194fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
12019a0944bad3791f94fc84d0e5fa2c38cd7b6b88dted.mielczarek@gmail.com  const unsigned pid_len = my_uint_len(pid);
1214fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  const size_t total_length = 6 + pid_len + 1 + node_len;
1224fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (total_length >= NAME_MAX)
1234fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1244fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
125ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org  my_memcpy(path, "/proc/", 6);
12619a0944bad3791f94fc84d0e5fa2c38cd7b6b88dted.mielczarek@gmail.com  my_uitos(path + 6, pid, pid_len);
1274fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  path[6 + pid_len] = '/';
128ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org  my_memcpy(path + 6 + pid_len + 1, node, node_len);
1294fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  path[total_length] = '\0';
1304fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return true;
1314fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
1324fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
133e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.orgbool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
1344fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org                                        const void* src, size_t length) {
1354fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  unsigned long tmp = 55;
1364fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  size_t done = 0;
1374fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  static const size_t word_size = sizeof(tmp);
1384fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  uint8_t* const local = (uint8_t*) dest;
1394fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  uint8_t* const remote = (uint8_t*) src;
1404fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1414fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  while (done < length) {
1424fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    const size_t l = (length - done > word_size) ? word_size : (length - done);
1434fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
1444fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      tmp = 0;
1454fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    }
146ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org    my_memcpy(local + done, &tmp, l);
1474fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    done += l;
1484fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
149e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org  return true;
1504fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
1514fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1524fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Read thread info from /proc/$pid/status.
1534fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
1544fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// these members are set to -1. Returns true iff all three members are
1554fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// available.
1564fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgbool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
1574fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (index >= threads_.size())
1584fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1594fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1604fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  pid_t tid = threads_[index];
1614fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1624fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  assert(info != NULL);
1634fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  char status_path[NAME_MAX];
1644fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (!BuildProcPath(status_path, tid, "status"))
1654fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1664fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1674fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  const int fd = sys_open(status_path, O_RDONLY, 0);
1684fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (fd < 0)
1694fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1704fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1714fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  LineReader* const line_reader = new(allocator_) LineReader(fd);
1724fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  const char* line;
1734fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  unsigned line_len;
1744fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1754fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  info->ppid = info->tgid = -1;
1764fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1774fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  while (line_reader->GetNextLine(&line, &line_len)) {
1784fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (my_strncmp("Tgid:\t", line, 6) == 0) {
1794fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      my_strtoui(&info->tgid, line + 6);
1804fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    } else if (my_strncmp("PPid:\t", line, 6) == 0) {
1814fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      my_strtoui(&info->ppid, line + 6);
1824fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    }
1834fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1844fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    line_reader->PopLine(line_len);
1854fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
1866c99f614cc8e27353c4eafaeefd8a57d584b97e0benchan@chromium.org  sys_close(fd);
1874fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1884fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (info->ppid == -1 || info->tgid == -1)
1894fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
1904fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1912eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org#ifdef PTRACE_GETREGSET
1922eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  struct iovec io;
1932eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  io.iov_base = &info->regs;
1942eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  io.iov_len = sizeof(info->regs);
1952eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
1962eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org    return false;
1972eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  }
1982eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org
1992eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  io.iov_base = &info->fpregs;
2002eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  io.iov_len = sizeof(info->fpregs);
2012eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
2022eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org    return false;
2032eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  }
2042eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org#else
2054fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
2064fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
2074fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
2084fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2094fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
2104fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
2114fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
2122eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org#endif
2134fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2144fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#if defined(__i386)
2157c6c2a73159a296b603dd01258a0337b255674ddthestig@chromium.org#if !defined(bit_FXSAVE)  // e.g. Clang
2167c6c2a73159a296b603dd01258a0337b255674ddthestig@chromium.org#define bit_FXSAVE bit_FXSR
2177c6c2a73159a296b603dd01258a0337b255674ddthestig@chromium.org#endif
218ea279814568875959e4b6a7aaa997401cc173940thestig@chromium.org  // Detect if the CPU supports the FXSAVE/FXRSTOR instructions
219ea279814568875959e4b6a7aaa997401cc173940thestig@chromium.org  int eax, ebx, ecx, edx;
220ea279814568875959e4b6a7aaa997401cc173940thestig@chromium.org  __cpuid(1, eax, ebx, ecx, edx);
221ea279814568875959e4b6a7aaa997401cc173940thestig@chromium.org  if (edx & bit_FXSAVE) {
22282f9cb743eaced71cbf241d9ea9ab327182f9eb4thestig@chromium.org    if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) {
22382f9cb743eaced71cbf241d9ea9ab327182f9eb4thestig@chromium.org      return false;
22482f9cb743eaced71cbf241d9ea9ab327182f9eb4thestig@chromium.org    }
22582f9cb743eaced71cbf241d9ea9ab327182f9eb4thestig@chromium.org  } else {
226ea279814568875959e4b6a7aaa997401cc173940thestig@chromium.org    memset(&info->fpxregs, 0, sizeof(info->fpxregs));
22782f9cb743eaced71cbf241d9ea9ab327182f9eb4thestig@chromium.org  }
2287c6c2a73159a296b603dd01258a0337b255674ddthestig@chromium.org#endif  // defined(__i386)
2294fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2304fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#if defined(__i386) || defined(__x86_64)
2314fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
2324fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (sys_ptrace(
2334fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        PTRACE_PEEKUSER, tid,
2344fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        reinterpret_cast<void*> (offsetof(struct user,
2354fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org                                          u_debugreg[0]) + i *
2364fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org                                 sizeof(debugreg_t)),
2374fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        &info->dregs[i]) == -1) {
2384fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      return false;
2394fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    }
2404fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
2414fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#endif
2424fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2435f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#if defined(__mips__)
2445f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com  for (int i = 0; i < 3; ++i) {
2455f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com    sys_ptrace(PTRACE_PEEKUSER, tid,
2465f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com               reinterpret_cast<void*>(DSP_BASE + (i * 2)), &info->hi[i]);
2475f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com    sys_ptrace(PTRACE_PEEKUSER, tid,
2485f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com               reinterpret_cast<void*>(DSP_BASE + (i * 2) + 1), &info->lo[i]);
2495f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com  }
2505f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com  sys_ptrace(PTRACE_PEEKUSER, tid,
2515f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com             reinterpret_cast<void*>(DSP_CONTROL), &info->dsp_control);
2525f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#endif
2535f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com
2544fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  const uint8_t* stack_pointer;
2554fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#if defined(__i386)
256ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org  my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
2574fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#elif defined(__x86_64)
258ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org  my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
2594fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#elif defined(__ARM_EABI__)
260ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org  my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
2612eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org#elif defined(__aarch64__)
2622eedc625759a8943d72711769a84fce05a23ecd0rmcilroy@chromium.org  my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
2635f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#elif defined(__mips__)
2645f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com  stack_pointer =
2655f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com      reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]);
2664fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#else
2674fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#error "This code hasn't been ported to your platform yet."
2684fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#endif
269a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org  info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
2704fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
271a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org  return true;
2724fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
2734fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2744fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgbool LinuxPtraceDumper::IsPostMortem() const {
2754fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return false;
2764fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
2774fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2784fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgbool LinuxPtraceDumper::ThreadsSuspend() {
2794fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (threads_suspended_)
2804fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return true;
2814fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  for (size_t i = 0; i < threads_.size(); ++i) {
2824fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (!SuspendThread(threads_[i])) {
2834fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      // If the thread either disappeared before we could attach to it, or if
2844fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      // it was part of the seccomp sandbox's trusted code, it is OK to
2854fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      // silently drop it from the minidump.
286dd884635de9a820578753d2839937784ef232b26hashimoto@chromium.org      if (i < threads_.size() - 1) {
287dd884635de9a820578753d2839937784ef232b26hashimoto@chromium.org        my_memmove(&threads_[i], &threads_[i + 1],
288dd884635de9a820578753d2839937784ef232b26hashimoto@chromium.org                   (threads_.size() - i - 1) * sizeof(threads_[i]));
289dd884635de9a820578753d2839937784ef232b26hashimoto@chromium.org      }
2904fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      threads_.resize(threads_.size() - 1);
2914fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      --i;
2924fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    }
2934fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
2944fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  threads_suspended_ = true;
2954fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return threads_.size() > 0;
2964fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
2974fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
2984fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgbool LinuxPtraceDumper::ThreadsResume() {
2994fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (!threads_suspended_)
3004fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
3014fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  bool good = true;
3024fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  for (size_t i = 0; i < threads_.size(); ++i)
3034fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    good &= ResumeThread(threads_[i]);
3044fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  threads_suspended_ = false;
3054fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return good;
3064fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
3074fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
3084fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// Parse /proc/$pid/task to list all the threads of the process identified by
3094fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org// pid.
3104fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.orgbool LinuxPtraceDumper::EnumerateThreads() {
3114fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  char task_path[NAME_MAX];
3124fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (!BuildProcPath(task_path, pid_, "task"))
3134fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
3144fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
3154fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
3164fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (fd < 0)
3174fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
3184fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
3194fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
3204fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // The directory may contain duplicate entries which we filter by assuming
3214fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  // that they are consecutive.
3224fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  int last_tid = -1;
3234fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  const char* dent_name;
3244fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  while (dir_reader->GetNextEntry(&dent_name)) {
3254fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (my_strcmp(dent_name, ".") &&
3264fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        my_strcmp(dent_name, "..")) {
3274fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      int tid = 0;
3284fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      if (my_strtoui(&tid, dent_name) &&
3294fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org          last_tid != tid) {
3304fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        last_tid = tid;
3314fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        threads_.push_back(tid);
3324fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      }
3334fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    }
3344fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    dir_reader->PopEntry();
3354fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  }
3364fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
3374fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  sys_close(fd);
3384fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return true;
3394fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
3404fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
3414fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}  // namespace google_breakpad
342