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, ®s) == -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