1f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org// Copyright (c) 2010, Google Inc.
2b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// All rights reserved.
3b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//
4b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// Redistribution and use in source and binary forms, with or without
5b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// modification, are permitted provided that the following conditions are
6b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// met:
7b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//
8b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     * Redistributions of source code must retain the above copyright
9b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// notice, this list of conditions and the following disclaimer.
10b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     * Redistributions in binary form must reproduce the above
11b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// copyright notice, this list of conditions and the following disclaimer
12b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// in the documentation and/or other materials provided with the
13b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// distribution.
14b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     * Neither the name of Google Inc. nor the names of its
15b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// contributors may be used to endorse or promote products derived from
16b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// this software without specific prior written permission.
17b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//
18b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
30b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// This code writes out minidump files:
31b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//   http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
32b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//
33b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// Minidumps are a Microsoft format which Breakpad uses for recording crash
34b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// dumps. This code has to run in a compromised environment (the address space
35b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// may have received SIGSEGV), thus the following rules apply:
36b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//   * You may not enter the dynamic linker. This means that we cannot call
37b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     any symbols in a shared library (inc libc). Because of this we replace
38b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     libc functions in linux_libc_support.h.
39b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//   * You may not call syscalls via the libc wrappers. This rule is a subset
40b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     of the first rule but it bears repeating. We have direct wrappers
41b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     around the system calls in linux_syscall_support.h.
42b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//   * You may not malloc. There's an alternative allocator in memory.h and
43b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     a canonical instance in the LinuxDumper object. We use the placement
44b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid//     new form to allocate objects and we don't delete them.
45b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
46e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org#include "client/linux/handler/minidump_descriptor.h"
47b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/linux/minidump_writer/minidump_writer.h"
48b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/minidump_file_writer-inl.h"
49b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
50aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include <ctype.h>
51b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <errno.h>
52b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <fcntl.h>
53f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org#include <link.h>
54b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <stdio.h>
555187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#if defined(__ANDROID__)
565187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#include <sys/system_properties.h>
575187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#endif
5829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org#include <sys/types.h>
59b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <sys/ucontext.h>
60b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <sys/user.h>
61b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <sys/utsname.h>
627b8a8fc5575624c97ff6659040e99ecf9d84e371thestig@chromium.org#include <time.h>
63aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include <unistd.h>
64b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
65f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org#include <algorithm>
66f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org
6730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org#include "client/linux/dump_writer_common/seccomp_unwinder.h"
6830f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org#include "client/linux/dump_writer_common/thread_info.h"
6930f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org#include "client/linux/dump_writer_common/ucontext_reader.h"
70b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/linux/handler/exception_handler.h"
71972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#include "client/linux/minidump_writer/cpu_set.h"
72b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/linux/minidump_writer/line_reader.h"
73de545c09d0363e6964822ec92529a80feaca152dnealsid#include "client/linux/minidump_writer/linux_dumper.h"
744fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
75972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
76aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include "client/minidump_file_writer.h"
77b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "common/linux/linux_libc_support.h"
78e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org#include "common/minidump_type_helper.h"
79aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include "google_breakpad/common/minidump_format.h"
800e3b7020b8f679259acfcfdbea4d39e1c13e6f19thestig@chromium.org#include "third_party/lss/linux_syscall_support.h"
81b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
82e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgnamespace {
83e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
8486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.comusing google_breakpad::AppMemoryList;
85e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::ExceptionHandler;
86972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.orgusing google_breakpad::CpuSet;
87e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::LineReader;
88e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::LinuxDumper;
89e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::LinuxPtraceDumper;
90e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.orgusing google_breakpad::MDTypeHelper;
91e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MappingEntry;
92e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MappingInfo;
93e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MappingList;
94e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MinidumpFileWriter;
95e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::PageAllocator;
96972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.orgusing google_breakpad::ProcCpuInfoReader;
9730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.orgusing google_breakpad::RawContextCPU;
9830f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.orgusing google_breakpad::SeccompUnwinder;
99e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::ThreadInfo;
100e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::TypedMDRVA;
10130f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.orgusing google_breakpad::UContextReader;
102e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::UntypedMDRVA;
103e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::wasteful_vector;
104e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
105e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.orgtypedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug;
106e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.orgtypedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap;
107b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
108b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsidclass MinidumpWriter {
109b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid public:
11029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // The following kLimit* constants are for when minidump_size_limit_ is set
11129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // and the minidump size might exceed it.
11229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  //
11329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // Estimate for how big each thread's stack will be (in bytes).
11429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  static const unsigned kLimitAverageThreadStackLength = 8 * 1024;
11529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // Number of threads whose stack size we don't want to limit.  These base
11629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // threads will simply be the first N threads returned by the dumper (although
11729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // the crashing thread will never be limited).  Threads beyond this count are
11829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // the extra threads.
11929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  static const unsigned kLimitBaseThreadCount = 20;
12029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // Maximum stack size to dump for any extra thread (in bytes).
12129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024;
12229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // Make sure this number of additional bytes can fit in the minidump
12329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // (exclude the stack data).
12429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024;
12529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org
126e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org  MinidumpWriter(const char* minidump_path,
127e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                 int minidump_fd,
128ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek                 const ExceptionHandler::CrashContext* context,
129e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org                 const MappingList& mappings,
13086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                 const AppMemoryList& appmem,
131e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org                 LinuxDumper* dumper)
132e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org      : fd_(minidump_fd),
133e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org        path_(minidump_path),
1344fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        ucontext_(context ? &context->context : NULL),
135b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#if !defined(__ARM_EABI__) && !defined(__mips__)
1364fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        float_state_(context ? &context->float_state : NULL),
137de545c09d0363e6964822ec92529a80feaca152dnealsid#endif
138e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org        dumper_(dumper),
13929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        minidump_size_limit_(-1),
140e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org        memory_blocks_(dumper_->allocator()),
14186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com        mapping_list_(mappings),
14286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com        app_memory_list_(appmem) {
143e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    // Assert there should be either a valid fd or a valid path, not both.
144e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    assert(fd_ != -1 || minidump_path);
145e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    assert(fd_ == -1 || !minidump_path);
146b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
147b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
148b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool Init() {
149e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    if (!dumper_->Init())
150e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org      return false;
151e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
152e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    if (fd_ != -1)
153e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org      minidump_writer_.SetFile(fd_);
154e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    else if (!minidump_writer_.Open(path_))
155e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org      return false;
156e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
157e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    return dumper_->ThreadsSuspend();
158b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
159b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
160b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  ~MinidumpWriter() {
161e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    // Don't close the file descriptor when it's been provided explicitly.
162e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    // Callers might still need to use it.
163e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org    if (fd_ == -1)
164e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org      minidump_writer_.Close();
165e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    dumper_->ThreadsResume();
166b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
167b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
168b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool Dump() {
169b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // A minidump file contains a number of tagged streams. This is the number
170b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // of stream which we write.
171693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    unsigned kNumWriters = 13;
172b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
173b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    TypedMDRVA<MDRawHeader> header(&minidump_writer_);
174b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
175b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!header.Allocate())
176b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
177b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!dir.AllocateArray(kNumWriters))
178b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
179ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org    my_memset(header.get(), 0, sizeof(MDRawHeader));
180b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
181b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    header.get()->signature = MD_HEADER_SIGNATURE;
182b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    header.get()->version = MD_HEADER_VERSION;
183b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    header.get()->time_date_stamp = time(NULL);
184b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    header.get()->stream_count = kNumWriters;
185b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    header.get()->stream_directory_rva = dir.position();
186b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
187b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    unsigned dir_index = 0;
188b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    MDRawDirectory dirent;
189b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
190b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!WriteThreadListStream(&dirent))
191b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
192b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
193b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
194b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!WriteMappings(&dirent))
195b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
196b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
197b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
19886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com    if (!WriteAppMemory())
19986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      return false;
20086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com
201efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    if (!WriteMemoryListStream(&dirent))
202efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek      return false;
203efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    dir.CopyIndex(dir_index++, &dirent);
204efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
205b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!WriteExceptionStream(&dirent))
206b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
207b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
208b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
209b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!WriteSystemInfoStream(&dirent))
210b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
211b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
212b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
213b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent.stream_type = MD_LINUX_CPU_INFO;
214b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
215b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
216b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
217b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
218b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent.stream_type = MD_LINUX_PROC_STATUS;
219e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
220b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
221b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
222b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
223b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent.stream_type = MD_LINUX_LSB_RELEASE;
224b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!WriteFile(&dirent.location, "/etc/lsb-release"))
225b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
226b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
227b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
228b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent.stream_type = MD_LINUX_CMD_LINE;
229e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
230b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
231b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
232b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
233b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent.stream_type = MD_LINUX_ENVIRON;
234e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
235b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
236b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
237b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
238b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent.stream_type = MD_LINUX_AUXV;
239e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
240b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
241b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
242b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
243f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    dirent.stream_type = MD_LINUX_MAPS;
244e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
245b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NullifyDirectoryEntry(&dirent);
246b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dir.CopyIndex(dir_index++, &dirent);
247b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
248693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    dirent.stream_type = MD_LINUX_DSO_DEBUG;
249693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    if (!WriteDSODebugStream(&dirent))
250693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      NullifyDirectoryEntry(&dirent);
251693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    dir.CopyIndex(dir_index++, &dirent);
252f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
253b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // If you add more directory entries, don't forget to update kNumWriters,
254b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // above.
255b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
256e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    dumper_->ThreadsResume();
257b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
258b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
259b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
260a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org  bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer,
26129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                       int max_stack_len, uint8_t** stack_copy) {
262a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    *stack_copy = NULL;
263a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    const void* stack;
264a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    size_t stack_len;
265a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
266a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      UntypedMDRVA memory(&minidump_writer_);
2672971a050754f48aaa807db47a29e0d0beddbdcf7ivan.penkov@gmail.com      if (max_stack_len >= 0 &&
2682971a050754f48aaa807db47a29e0d0beddbdcf7ivan.penkov@gmail.com          stack_len > static_cast<unsigned int>(max_stack_len)) {
26929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        stack_len = max_stack_len;
2702971a050754f48aaa807db47a29e0d0beddbdcf7ivan.penkov@gmail.com      }
271a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      if (!memory.Allocate(stack_len))
272a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        return false;
273a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
274a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack,
275a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org                               stack_len);
276a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      memory.Copy(*stack_copy, stack_len);
277a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      thread->stack.start_of_memory_range =
278a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org          reinterpret_cast<uintptr_t>(stack);
279a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      thread->stack.memory = memory.location();
280a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      memory_blocks_.push_back(thread->stack);
281a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    } else {
282a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      thread->stack.start_of_memory_range = stack_pointer;
283a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      thread->stack.memory.data_size = 0;
284a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      thread->stack.memory.rva = minidump_writer_.position();
285a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    }
286a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    return true;
287a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org  }
288a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org
289b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  // Write information about the threads.
290b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteThreadListStream(MDRawDirectory* dirent) {
291e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    const unsigned num_threads = dumper_->threads().size();
292b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
293b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    TypedMDRVA<uint32_t> list(&minidump_writer_);
294b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
295b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
296b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
297b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->stream_type = MD_THREAD_LIST_STREAM;
298b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->location = list.location();
299b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
300b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    *list.get() = num_threads;
301b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
30229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    // If there's a minidump size limit, check if it might be exceeded.  Since
30329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    // most of the space is filled with stack data, just check against that.
30429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    // If this expects to exceed the limit, set extra_thread_stack_len such
30529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    // that any thread beyond the first kLimitBaseThreadCount threads will
30629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    // have only kLimitMaxExtraThreadStackLen bytes dumped.
30729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    int extra_thread_stack_len = -1;  // default to no maximum
30829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    if (minidump_size_limit_ >= 0) {
30929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org      const unsigned estimated_total_stack_size = num_threads *
31029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org          kLimitAverageThreadStackLength;
31129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org      const off_t estimated_minidump_size = minidump_writer_.position() +
31229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org          estimated_total_stack_size + kLimitMinidumpFudgeFactor;
31329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org      if (estimated_minidump_size > minidump_size_limit_)
31429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        extra_thread_stack_len = kLimitMaxExtraThreadStackLen;
31529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    }
31629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org
317b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    for (unsigned i = 0; i < num_threads; ++i) {
318b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      MDRawThread thread;
319b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      my_memset(&thread, 0, sizeof(thread));
320e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org      thread.thread_id = dumper_->threads()[i];
321a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org
322b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      // We have a different source of information for the crashing thread. If
323b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      // we used the actual state of the thread we would find it running in the
324b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      // signal handler with the alternative stack, which would be deeply
325b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      // unhelpful.
3264fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
327f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com          ucontext_ &&
3284fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org          !dumper_->IsPostMortem()) {
329a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        uint8_t* stack_copy;
33030f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org        const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
33130f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org        if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy))
332b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          return false;
333efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
334efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        // Copy 256 bytes around crashing instruction pointer to minidump.
335efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        const size_t kIPMemorySize = 256;
33630f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org        uint64_t ip = UContextReader::GetInstructionPointer(ucontext_);
337efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        // Bound it to the upper and lower bounds of the memory map
338efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        // it's contained within. If it's not in mapped memory,
339efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        // don't bother trying to write it.
340efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        bool ip_is_mapped = false;
341efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        MDMemoryDescriptor ip_memory_d;
342e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org        for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
343e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org          const MappingInfo& mapping = *dumper_->mappings()[j];
344efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          if (ip >= mapping.start_addr &&
345efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek              ip < mapping.start_addr + mapping.size) {
346efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            ip_is_mapped = true;
347efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            // Try to get 128 bytes before and after the IP, but
348efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            // settle for whatever's available.
349efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            ip_memory_d.start_of_memory_range =
3504621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek              std::max(mapping.start_addr,
351efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek                       uintptr_t(ip - (kIPMemorySize / 2)));
352f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org            uintptr_t end_of_range =
3534621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek              std::min(uintptr_t(ip + (kIPMemorySize / 2)),
3544621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek                       uintptr_t(mapping.start_addr + mapping.size));
355efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            ip_memory_d.memory.data_size =
3564621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek              end_of_range - ip_memory_d.start_of_memory_range;
357efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            break;
358efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          }
359efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        }
360efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
361efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        if (ip_is_mapped) {
362efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          UntypedMDRVA ip_memory(&minidump_writer_);
363efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
364efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek            return false;
365efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          uint8_t* memory_copy =
366e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org              reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
367e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org          dumper_->CopyFromProcess(
368e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org              memory_copy,
369e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org              thread.thread_id,
370e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org              reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
371e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org              ip_memory_d.memory.data_size);
372efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
373efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          ip_memory_d.memory = ip_memory.location();
374efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek          memory_blocks_.push_back(ip_memory_d);
375efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek        }
376efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
377b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
378b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        if (!cpu.Allocate())
379b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          return false;
380b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        my_memset(cpu.get(), 0, sizeof(RawContextCPU));
381b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#if !defined(__ARM_EABI__) && !defined(__mips__)
38230f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org        UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_);
383b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#else
38430f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org        UContextReader::FillCPUContext(cpu.get(), ucontext_);
385b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#endif
386a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        if (stack_copy)
38730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org          SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy);
388b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        thread.thread_context = cpu.location();
389b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        crashing_thread_context_ = cpu.location();
390b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      } else {
391b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        ThreadInfo info;
392e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org        if (!dumper_->GetThreadInfoByIndex(i, &info))
393b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          return false;
394a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org
395a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        uint8_t* stack_copy;
39629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        int max_stack_len = -1;  // default to no maximum for this thread
39729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount)
39829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org          max_stack_len = extra_thread_stack_len;
39929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len,
40029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org            &stack_copy))
401b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          return false;
402efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
403b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
404b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        if (!cpu.Allocate())
405b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          return false;
406b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        my_memset(cpu.get(), 0, sizeof(RawContextCPU));
40730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org        info.FillCPUContext(cpu.get());
408a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        if (stack_copy)
40930f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org          SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy);
410b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        thread.thread_context = cpu.location();
4114fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        if (dumper_->threads()[i] == GetCrashThread()) {
4124fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org          crashing_thread_context_ = cpu.location();
413f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com          if (!dumper_->IsPostMortem()) {
414f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com            // This is the crashing thread of a live process, but
415f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com            // no context was provided, so set the crash address
416f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com            // while the instruction pointer is already here.
41730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org            dumper_->set_crash_address(info.GetInstructionPointer());
418f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com          }
4194fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org        }
420b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      }
421b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
422b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      list.CopyIndexAfterObject(i, &thread, sizeof(thread));
423b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
424b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
425b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
426b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
427b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
42886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  // Write application-provided memory regions.
42986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  bool WriteAppMemory() {
43086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com    for (AppMemoryList::const_iterator iter = app_memory_list_.begin();
43186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com         iter != app_memory_list_.end();
43286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com         ++iter) {
43386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      uint8_t* data_copy =
43486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com        reinterpret_cast<uint8_t*>(dumper_->allocator()->Alloc(iter->length));
43586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr,
43686f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                               iter->length);
43786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com
43886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      UntypedMDRVA memory(&minidump_writer_);
43986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      if (!memory.Allocate(iter->length)) {
44086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com        return false;
44186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      }
44286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      memory.Copy(data_copy, iter->length);
44386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      MDMemoryDescriptor desc;
44486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      desc.start_of_memory_range = reinterpret_cast<uintptr_t>(iter->ptr);
44586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      desc.memory = memory.location();
44686f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com      memory_blocks_.push_back(desc);
44786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com    }
44886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com
44986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com    return true;
45086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  }
45186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com
452b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  static bool ShouldIncludeMapping(const MappingInfo& mapping) {
453f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org    if (mapping.name[0] == 0 ||  // only want modules with filenames.
454dd5dd85f3795609723082a2b34f81e19b4f1679frmcilroy@chromium.org        // Only want to include one mapping per shared lib.
455dd5dd85f3795609723082a2b34f81e19b4f1679frmcilroy@chromium.org        // Avoid filtering executable mappings.
456dd5dd85f3795609723082a2b34f81e19b4f1679frmcilroy@chromium.org        (mapping.offset != 0 && !mapping.exec) ||
457b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        mapping.size < 4096) {  // too small to get a signature for.
458b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
459b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
460b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
461b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
462b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
463b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
464ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  // If there is caller-provided information about this mapping
465ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  // in the mapping_list_ list, return true. Otherwise, return false.
466ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  bool HaveMappingInfo(const MappingInfo& mapping) {
467ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    for (MappingList::const_iterator iter = mapping_list_.begin();
468ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek         iter != mapping_list_.end();
469ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek         ++iter) {
470ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      // Ignore any mappings that are wholly contained within
471ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      // mappings in the mapping_info_ list.
472ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      if (mapping.start_addr >= iter->first.start_addr &&
473ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek          (mapping.start_addr + mapping.size) <=
474ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek          (iter->first.start_addr + iter->first.size)) {
475ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek        return true;
476ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      }
477ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    }
478ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    return false;
479ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  }
480ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek
481b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  // Write information about the mappings in effect. Because we are using the
482b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  // minidump format, the information about the mappings is pretty limited.
483b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  // Because of this, we also include the full, unparsed, /proc/$x/maps file in
484b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  // another stream in the file.
485b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteMappings(MDRawDirectory* dirent) {
486e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    const unsigned num_mappings = dumper_->mappings().size();
487ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    unsigned num_output_mappings = mapping_list_.size();
488b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
489e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
490e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org      const MappingInfo& mapping = *dumper_->mappings()[i];
491ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
492b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        num_output_mappings++;
493b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
494b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
495b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    TypedMDRVA<uint32_t> list(&minidump_writer_);
496362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org    if (num_output_mappings) {
497362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org      if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
498362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org        return false;
499362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org    } else {
500362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org      // Still create the module list stream, although it will have zero
501362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org      // modules.
502362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org      if (!list.Allocate())
503362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org        return false;
504362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org    }
505b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
506b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->stream_type = MD_MODULE_LIST_STREAM;
507b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->location = list.location();
508b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    *list.get() = num_output_mappings;
509b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
510ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    // First write all the mappings from the dumper
511ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    unsigned int j = 0;
512ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    for (unsigned i = 0; i < num_mappings; ++i) {
513e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org      const MappingInfo& mapping = *dumper_->mappings()[i];
514ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
515b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        continue;
516b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
517b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      MDRawModule mod;
51823c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com      if (!FillRawModule(mapping, true, i, mod, NULL))
519b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        return false;
520ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
521ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    }
522ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    // Next write all the mappings provided by the caller
523ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    for (MappingList::const_iterator iter = mapping_list_.begin();
524ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek         iter != mapping_list_.end();
525ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek         ++iter) {
526ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      MDRawModule mod;
52723c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com      if (!FillRawModule(iter->first, false, 0, mod, iter->second))
528ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek        return false;
529ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
530ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    }
531b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
532ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    return true;
533ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  }
534b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
535ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  // Fill the MDRawModule |mod| with information about the provided
536ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  // |mapping|. If |identifier| is non-NULL, use it instead of calculating
53723c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com  // a file ID from the mapping.
538ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  bool FillRawModule(const MappingInfo& mapping,
53923c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com                     bool member,
54023c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com                     unsigned int mapping_id,
541ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek                     MDRawModule& mod,
5426162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com                     const uint8_t* identifier) {
543ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    my_memset(&mod, 0, MD_MODULE_SIZE);
544ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek
545ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    mod.base_of_image = mapping.start_addr;
546ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    mod.size_of_image = mapping.size;
547b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
548ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
549ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    uint8_t* cv_ptr = cv_buf;
550b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
551ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
552ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org    my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
553ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    cv_ptr += sizeof(cv_signature);
554ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    uint8_t* signature = cv_ptr;
555ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    cv_ptr += sizeof(MDGUID);
556ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    if (identifier) {
557ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      // GUID was provided by caller.
558ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org      my_memcpy(signature, identifier, sizeof(MDGUID));
559ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    } else {
56084c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org      // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
561e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org      dumper_->ElfFileIdentifierForMapping(mapping, member,
562e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org                                           mapping_id, signature);
563b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
564ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    my_memset(cv_ptr, 0, sizeof(uint32_t));  // Set age to 0 on Linux.
565ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    cv_ptr += sizeof(uint32_t);
566b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
56784c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    char file_name[NAME_MAX];
56884c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    char file_path[NAME_MAX];
56984c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    LinuxDumper::GetMappingEffectiveNameAndPath(
57084c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org        mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
57184c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org
57284c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    const size_t file_name_len = my_strlen(file_name);
57384c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    UntypedMDRVA cv(&minidump_writer_);
57484c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1))
57584c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org      return false;
57684c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org
577ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    // Write pdb_file_name
57884c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    my_memcpy(cv_ptr, file_name, file_name_len + 1);
57984c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1);
580ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek
581ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    mod.cv_record = cv.location();
582ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek
583ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    MDLocationDescriptor ld;
58484c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org    if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
585ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek      return false;
586ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek    mod.module_name_rva = ld.rva;
587b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
588b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
589b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
590efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek  bool WriteMemoryListStream(MDRawDirectory* dirent) {
591efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    TypedMDRVA<uint32_t> list(&minidump_writer_);
592a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    if (memory_blocks_.size()) {
593a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      if (!list.AllocateObjectAndArray(memory_blocks_.size(),
594a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org                                       sizeof(MDMemoryDescriptor)))
595a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        return false;
596a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    } else {
597a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      // Still create the memory list stream, although it will have zero
598a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      // memory blocks.
599a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org      if (!list.Allocate())
600a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org        return false;
601a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org    }
602efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
603efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    dirent->stream_type = MD_MEMORY_LIST_STREAM;
604efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    dirent->location = list.location();
605efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
606efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    *list.get() = memory_blocks_.size();
607efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
608efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    for (size_t i = 0; i < memory_blocks_.size(); ++i) {
609efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek      list.CopyIndexAfterObject(i, &memory_blocks_[i],
610efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek                                sizeof(MDMemoryDescriptor));
611efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    }
612efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek    return true;
613efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek  }
614efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek
615b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteExceptionStream(MDRawDirectory* dirent) {
616b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
617b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!exc.Allocate())
618b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
619b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
620b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
621b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->stream_type = MD_EXCEPTION_STREAM;
622b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->location = exc.location();
623b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
624e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    exc.get()->thread_id = GetCrashThread();
625e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    exc.get()->exception_record.exception_code = dumper_->crash_signal();
626e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    exc.get()->exception_record.exception_address = dumper_->crash_address();
627b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    exc.get()->thread_context = crashing_thread_context_;
628b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
629b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
630b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
631b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
632b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteSystemInfoStream(MDRawDirectory* dirent) {
633b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
634b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!si.Allocate())
635b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
636b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
637b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
638b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->stream_type = MD_SYSTEM_INFO_STREAM;
639b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->location = si.location();
640b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
641b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    WriteCPUInformation(si.get());
642b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    WriteOSInformation(si.get());
643b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
644b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
645b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
646b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
647693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com  bool WriteDSODebugStream(MDRawDirectory* dirent) {
648693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]);
649693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    char* base;
650693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    int phnum = dumper_->auxv()[AT_PHNUM];
651693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    if (!phnum || !phdr)
652693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      return false;
653693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com
654693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // Assume the program base is at the beginning of the same page as the PHDR
655693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
656693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com
657693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // Search for the program PT_DYNAMIC segment
658693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    ElfW(Addr) dyn_addr = 0;
659693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    for (; phnum >= 0; phnum--, phdr++) {
660693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      ElfW(Phdr) ph;
661e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org      if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph)))
662e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org        return false;
663e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org
664693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      // Adjust base address with the virtual address of the PT_LOAD segment
665693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      // corresponding to offset 0
666693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      if (ph.p_type == PT_LOAD && ph.p_offset == 0) {
667693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com        base -= ph.p_vaddr;
668693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      }
669693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      if (ph.p_type == PT_DYNAMIC) {
670693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com        dyn_addr = ph.p_vaddr;
671693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      }
672693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    }
673693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    if (!dyn_addr)
674693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      return false;
675693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com
676693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base);
677693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com
678693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // The dynamic linker makes information available that helps gdb find all
679693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // DSOs loaded into the program. If this information is indeed available,
680693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // dump it to a MD_LINUX_DSO_DEBUG stream.
681693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    struct r_debug* r_debug = NULL;
682693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    uint32_t dynamic_length = 0;
683693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com
684e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org    for (int i = 0; ; ++i) {
685693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      ElfW(Dyn) dyn;
686693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      dynamic_length += sizeof(dyn);
687e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org      if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i,
688e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org                                    sizeof(dyn))) {
689e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org        return false;
690e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org      }
691e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org
692693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      if (dyn.d_tag == DT_DEBUG) {
693693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com        r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
694693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com        continue;
695693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      } else if (dyn.d_tag == DT_NULL) {
696693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com        break;
697693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com      }
698693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    }
699693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com
700693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // The "r_map" field of that r_debug struct contains a linked list of all
701693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com    // loaded DSOs.
702f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // Our list of DSOs potentially is different from the ones in the crashing
703f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // process. So, we have to be careful to never dereference pointers
704f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // directly. Instead, we use CopyFromProcess() everywhere.
705f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // See <link.h> for a more detailed discussion of the how the dynamic
706f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // loader communicates with debuggers.
707f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
708f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // Count the number of loaded DSOs
709f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    int dso_count = 0;
710f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    struct r_debug debug_entry;
711e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org    if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
712e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org                                  sizeof(debug_entry))) {
713e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org      return false;
714e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org    }
715f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
716f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      struct link_map map;
717e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org      if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
718e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org        return false;
719e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org
720f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      ptr = map.l_next;
721f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      dso_count++;
722f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    }
723f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
724f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
725f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    if (dso_count > 0) {
726f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      // If we have at least one DSO, create an array of MDRawLinkMap
727f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      // entries in the minidump file.
728f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
729f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      if (!linkmap.AllocateArray(dso_count))
730f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        return false;
731f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      linkmap_rva = linkmap.location().rva;
732f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      int idx = 0;
733f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
734f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      // Iterate over DSOs and write their information to mini dump
735f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
736f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        struct link_map map;
737e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org        if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
738e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org          return  false;
739e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org
740f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        ptr = map.l_next;
741f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        char filename[257] = { 0 };
742f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        if (map.l_name) {
743e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org          dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
744e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org                                   sizeof(filename) - 1);
745f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        }
746f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        MDLocationDescriptor location;
747f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        if (!minidump_writer_.WriteString(filename, 0, &location))
748f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org          return false;
749f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        MDRawLinkMap entry;
750f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        entry.name = location.rva;
751e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org        entry.addr = map.l_addr;
752e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org        entry.ld = reinterpret_cast<uintptr_t>(map.l_ld);
753f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        linkmap.CopyIndex(idx++, &entry);
754f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      }
755f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    }
756f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
757f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    // Write MD_LINUX_DSO_DEBUG record
758f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
759f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    if (!debug.AllocateObjectAndArray(1, dynamic_length))
760f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      return false;
761f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    my_memset(debug.get(), 0, sizeof(MDRawDebug));
762f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    dirent->stream_type = MD_LINUX_DSO_DEBUG;
763f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    dirent->location = debug.location();
764f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
765f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    debug.get()->version = debug_entry.r_version;
766f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    debug.get()->map = linkmap_rva;
767f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    debug.get()->dso_count = dso_count;
768e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org    debug.get()->brk = debug_entry.r_brk;
769e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org    debug.get()->ldbase = debug_entry.r_ldbase;
770e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org    debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic);
771f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
7725eb7c9279928a6c65dc76949bd518e9167ca678eted.mielczarek@gmail.com    wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length);
773447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com    // The passed-in size to the constructor (above) is only a hint.
774447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com    // Must call .resize() to do actual initialization of the elements.
775447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com    dso_debug_data.resize(dynamic_length);
7765eb7c9279928a6c65dc76949bd518e9167ca678eted.mielczarek@gmail.com    dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic,
777e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org                             dynamic_length);
7785eb7c9279928a6c65dc76949bd518e9167ca678eted.mielczarek@gmail.com    debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length);
779f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
780f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    return true;
781f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org  }
782f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
78329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; }
78429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org
785b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid private:
786e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org  void* Alloc(unsigned bytes) {
787e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    return dumper_->allocator()->Alloc(bytes);
788e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org  }
789e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org
790e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org  pid_t GetCrashThread() const {
791e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    return dumper_->crash_thread();
792e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org  }
793e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org
794b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  void NullifyDirectoryEntry(MDRawDirectory* dirent) {
795b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->stream_type = 0;
796b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->location.data_size = 0;
797b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    dirent->location.rva = 0;
798b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
799b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
8005f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
801b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
802b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
803b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    static const char vendor_id_name[] = "vendor_id";
804b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
805b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    struct CpuInfoEntry {
806b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      const char* info_name;
807b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      int value;
808b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      bool found;
809b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    } cpu_info_table[] = {
810b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      { "processor", -1, false },
811952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__i386__) || defined(__x86_64__)
812b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      { "model", 0, false },
813b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      { "stepping",  0, false },
814096992fac73756cfa0974a94754329f30fd4e786nealsid      { "cpu family", 0, false },
8155f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#endif
816b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    };
817b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
818b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // processor_architecture should always be set, do this first
819b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_info->processor_architecture =
8205f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#if defined(__mips__)
8215f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com        MD_CPU_ARCHITECTURE_MIPS;
8225f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#elif defined(__i386__)
823b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        MD_CPU_ARCHITECTURE_X86;
824b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#else
825972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        MD_CPU_ARCHITECTURE_AMD64;
826b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#endif
827b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
828b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
829b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (fd < 0)
830b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
831b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
832b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    {
833b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      PageAllocator allocator;
834972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd);
835972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      const char* field;
836972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      while (reader->GetNextField(&field)) {
837b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        for (size_t i = 0;
838b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid             i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
839b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid             i++) {
840b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          CpuInfoEntry* entry = &cpu_info_table[i];
841972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (i > 0 && entry->found) {
842972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            // except for the 'processor' field, ignore repeated values.
843b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid            continue;
844972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          }
845972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (!my_strcmp(field, entry->info_name)) {
846972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            size_t value_len;
847972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            const char* value = reader->GetValueAndLen(&value_len);
848972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            if (value_len == 0)
849b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid              continue;
850b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
851ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org            uintptr_t val;
852d8511da723115e5e39117129ea518b6e9c0e09b4thestig@chromium.org            if (my_read_decimal_ptr(&val, value) == value)
853d8511da723115e5e39117129ea518b6e9c0e09b4thestig@chromium.org              continue;
854972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
855ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org            entry->value = static_cast<int>(val);
856b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid            entry->found = true;
857b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid          }
858b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        }
859b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
860b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        // special case for vendor_id
861972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        if (!my_strcmp(field, vendor_id_name)) {
862972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          size_t value_len;
863972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          const char* value = reader->GetValueAndLen(&value_len);
864972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (value_len > 0)
865f1e81b3b4a9b31a56c669950a97b71e9e7acaf4cthestig@chromium.org            my_strlcpy(vendor_id, value, sizeof(vendor_id));
866b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        }
867b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      }
868b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      sys_close(fd);
869b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
870b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
871b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // make sure we got everything we wanted
872b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    for (size_t i = 0;
873b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid         i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
874b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid         i++) {
875b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      if (!cpu_info_table[i].found) {
876b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        return false;
877b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      }
878b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
879972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo,
880972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // assuming this is the highest id, change it to the number of CPUs
881972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // by adding one.
882b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    cpu_info_table[0].value++;
883b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
884b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_info->number_of_processors = cpu_info_table[0].value;
885952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__i386__) || defined(__x86_64__)
886b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_info->processor_level      = cpu_info_table[3].value;
887b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_info->processor_revision   = cpu_info_table[1].value << 8 |
888b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid                                     cpu_info_table[2].value;
8895f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#endif
890b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
891b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (vendor_id[0] != '\0') {
892ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org      my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
893ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org                sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
894b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
895b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
896b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
897952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#elif defined(__arm__) || defined(__aarch64__)
898972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org  bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
899972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // The CPUID value is broken up in several entries in /proc/cpuinfo.
900972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // This table is used to rebuild it from the entries.
901972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    const struct CpuIdEntry {
902972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      const char* field;
903972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      char        format;
904972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      char        bit_lshift;
905972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      char        bit_length;
906972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    } cpu_id_entries[] = {
907972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "CPU implementer", 'x', 24, 8 },
908972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "CPU variant", 'x', 20, 4 },
909972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "CPU part", 'x', 4, 12 },
910972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "CPU revision", 'd', 0, 4 },
911972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    };
912972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
913972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // The ELF hwcaps are listed in the "Features" entry as textual tags.
914972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // This table is used to rebuild them.
915972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    const struct CpuFeaturesEntry {
916972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      const char* tag;
917972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      uint32_t hwcaps;
918972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    } cpu_features_entries[] = {
919952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__arm__)
920972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "swp",  MD_CPU_ARM_ELF_HWCAP_SWP },
921972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "half", MD_CPU_ARM_ELF_HWCAP_HALF },
922972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB },
923972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT },
924972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT },
925972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA },
926972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP },
927972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP },
928972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "java", MD_CPU_ARM_ELF_HWCAP_JAVA },
929972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT },
930972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH },
931972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE },
932972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "neon", MD_CPU_ARM_ELF_HWCAP_NEON },
933972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 },
934972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 },
935972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "tls", MD_CPU_ARM_ELF_HWCAP_TLS },
936972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 },
937972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA },
938972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT },
939972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT },
940952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#elif defined(__aarch64__)
941952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org      // No hwcaps on aarch64.
942952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#endif
943972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    };
944972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
945972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // processor_architecture should always be set, do this first
946952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org    sys_info->processor_architecture =
947952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__aarch64__)
948952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        MD_CPU_ARCHITECTURE_ARM64;
949952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#else
950952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        MD_CPU_ARCHITECTURE_ARM;
951952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#endif
952972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
953972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // /proc/cpuinfo is not readable under various sandboxed environments
954972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // (e.g. Android services with the android:isolatedProcess attribute)
955972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // prepare for this by setting default values now, which will be
956972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // returned when this happens.
957972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    //
958972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // Note: Bogus values are used to distinguish between failures (to
959972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    //       read /sys and /proc files) and really badly configured kernels.
960972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    sys_info->number_of_processors = 0;
961972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    sys_info->processor_level = 1U;  // There is no ARMv1
962972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    sys_info->processor_revision = 42;
963972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    sys_info->cpu.arm_cpu_info.cpuid = 0;
964972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    sys_info->cpu.arm_cpu_info.elf_hwcaps = 0;
965972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
966972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // Counting the number of CPUs involves parsing two sysfs files,
967972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // because the content of /proc/cpuinfo will only mirror the number
968972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // of 'online' cores, and thus will vary with time.
969972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // See http://www.kernel.org/doc/Documentation/cputopology.txt
970972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    {
971972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      CpuSet cpus_present;
972972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      CpuSet cpus_possible;
973972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
974972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0);
975972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      if (fd >= 0) {
976972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        cpus_present.ParseSysFile(fd);
977972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        sys_close(fd);
978972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
979972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0);
980972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        if (fd >= 0) {
981972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          cpus_possible.ParseSysFile(fd);
982972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          sys_close(fd);
983972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
984972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          cpus_present.IntersectWith(cpus_possible);
985972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          int cpu_count = cpus_present.GetCount();
986972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (cpu_count > 255)
987972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            cpu_count = 255;
988972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
989972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        }
990972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      }
991972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    }
992972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
993972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // Parse /proc/cpuinfo to reconstruct the CPUID value, as well
994972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // as the ELF hwcaps field. For the latter, it would be easier to
995972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // read /proc/self/auxv but unfortunately, this file is not always
996972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // readable from regular Android applications on later versions
997972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    // (>= 4.1) of the Android platform.
998972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
999972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    if (fd < 0) {
1000972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      // Do not return false here to allow the minidump generation
1001972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      // to happen properly.
1002972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      return true;
1003972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    }
1004972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
1005972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    {
1006972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      PageAllocator allocator;
1007972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      ProcCpuInfoReader* const reader =
1008972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          new(allocator) ProcCpuInfoReader(fd);
1009972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      const char* field;
1010972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      while (reader->GetNextField(&field)) {
1011972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        for (size_t i = 0;
1012972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org             i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]);
1013972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org             ++i) {
1014972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          const CpuIdEntry* entry = &cpu_id_entries[i];
1015972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (my_strcmp(entry->field, field) != 0)
1016972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            continue;
1017972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          uintptr_t result = 0;
1018972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          const char* value = reader->GetValue();
1019972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          const char* p = value;
1020972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (value[0] == '0' && value[1] == 'x') {
1021972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            p = my_read_hex_ptr(&result, value+2);
1022447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com          } else if (entry->format == 'x') {
1023972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            p = my_read_hex_ptr(&result, value);
1024447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com          } else {
1025972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            p = my_read_decimal_ptr(&result, value);
1026447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com          }
1027972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (p == value)
1028972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            continue;
1029972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
1030972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          result &= (1U << entry->bit_length)-1;
1031972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          result <<= entry->bit_lshift;
1032972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          sys_info->cpu.arm_cpu_info.cpuid |=
1033972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              static_cast<uint32_t>(result);
1034972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        }
1035952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__arm__)
1036972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        // Get the architecture version from the "Processor" field.
1037972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        // Note that it is also available in the "CPU architecture" field,
1038972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        // however, some existing kernels are misconfigured and will report
1039972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        // invalid values here (e.g. 6, while the CPU is ARMv7-A based).
1040972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        // The "Processor" field doesn't have this issue.
1041972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        if (!my_strcmp(field, "Processor")) {
1042952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          size_t value_len;
1043972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          const char* value = reader->GetValueAndLen(&value_len);
1044972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          // Expected format: <text> (v<level><endian>)
1045972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          // Where <text> is some text like "ARMv7 Processor rev 2"
1046972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          // and <level> is a decimal corresponding to the ARM
1047972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          // architecture number. <endian> is either 'l' or 'b'
1048972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          // and corresponds to the endianess, it is ignored here.
1049972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          while (value_len > 0 && my_isspace(value[value_len-1]))
1050972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            value_len--;
1051972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
1052972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          size_t nn = value_len;
1053972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          while (nn > 0 && value[nn-1] != '(')
1054972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            nn--;
1055972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          if (nn > 0 && value[nn] == 'v') {
1056972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            uintptr_t arch_level = 5;
1057972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            my_read_decimal_ptr(&arch_level, value + nn + 1);
1058972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            sys_info->processor_level = static_cast<uint16_t>(arch_level);
1059972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          }
1060972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        }
1061952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#elif defined(__aarch64__)
1062952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        // The aarch64 architecture does not provide the architecture level
1063952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        // in the Processor field, so we instead check the "CPU architecture"
1064952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        // field.
1065952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        if (!my_strcmp(field, "CPU architecture")) {
1066952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          uintptr_t arch_level = 0;
1067952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          const char* value = reader->GetValue();
1068952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          const char* p = value;
1069952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          p = my_read_decimal_ptr(&arch_level, value);
1070952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          if (p == value)
1071952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org            continue;
1072952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          sys_info->processor_level = static_cast<uint16_t>(arch_level);
1073952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org        }
1074952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#endif
1075972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        // Rebuild the ELF hwcaps from the 'Features' field.
1076972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        if (!my_strcmp(field, "Features")) {
1077952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org          size_t value_len;
1078972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          const char* value = reader->GetValueAndLen(&value_len);
1079972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
1080972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          // Parse each space-separated tag.
1081972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          while (value_len > 0) {
1082972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            const char* tag = value;
1083972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            size_t tag_len = value_len;
1084972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            const char* p = my_strchr(tag, ' ');
1085972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            if (p != NULL) {
1086972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              tag_len = static_cast<size_t>(p - tag);
1087972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              value += tag_len + 1;
1088972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              value_len -= tag_len + 1;
1089972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            } else {
1090972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              tag_len = strlen(tag);
1091972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              value_len = 0;
1092972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            }
1093972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            for (size_t i = 0;
1094972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org                i < sizeof(cpu_features_entries)/
1095972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org                    sizeof(cpu_features_entries[0]);
1096972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org                ++i) {
1097972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              const CpuFeaturesEntry* entry = &cpu_features_entries[i];
1098972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              if (tag_len == strlen(entry->tag) &&
1099972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org                  !memcmp(tag, entry->tag, tag_len)) {
1100972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org                sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry->hwcaps;
1101972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org                break;
1102972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org              }
1103972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org            }
1104972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org          }
1105972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org        }
1106972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      }
1107972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org      sys_close(fd);
1108972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    }
1109972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org
1110972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org    return true;
1111972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org  }
1112972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#else
1113972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#  error "Unsupported CPU"
1114972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#endif
1115b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1116b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteFile(MDLocationDescriptor* result, const char* filename) {
1117b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    const int fd = sys_open(filename, O_RDONLY, 0);
1118b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (fd < 0)
1119b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
1120b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1121b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // We can't stat the files because several of the files that we want to
1122b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // read are kernel seqfiles, which always have a length of zero. So we have
1123b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    // to read as much as we can into a buffer.
1124f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    static const unsigned kBufSize = 1024 - 2*sizeof(void*);
1125f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    struct Buffers {
1126e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org      Buffers* next;
1127f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      size_t len;
1128f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      uint8_t data[kBufSize];
1129e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1130f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    buffers->next = NULL;
1131f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    buffers->len = 0;
1132f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org
1133f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    size_t total = 0;
1134e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org    for (Buffers* bufptr = buffers;;) {
1135b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      ssize_t r;
1136b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      do {
1137f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
1138b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      } while (r == -1 && errno == EINTR);
1139b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1140b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      if (r < 1)
1141b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        break;
1142f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org
1143f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      total += r;
1144f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      bufptr->len += r;
1145f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      if (bufptr->len == kBufSize) {
1146e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org        bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1147f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        bufptr = bufptr->next;
1148f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        bufptr->next = NULL;
1149f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org        bufptr->len = 0;
1150f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      }
1151b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
1152b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_close(fd);
1153b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1154f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    if (!total)
1155b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
1156b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1157b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    UntypedMDRVA memory(&minidump_writer_);
1158f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    if (!memory.Allocate(total))
1159b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
1160f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
1161be55cc8cf05aace5e8769230e02b5948a0079496mmentovai      // Check for special case of a zero-length buffer.  This should only
1162be55cc8cf05aace5e8769230e02b5948a0079496mmentovai      // occur if a file's size happens to be a multiple of the buffer's
1163be55cc8cf05aace5e8769230e02b5948a0079496mmentovai      // size, in which case the final sys_read() will have resulted in
1164be55cc8cf05aace5e8769230e02b5948a0079496mmentovai      // zero bytes being read after the final buffer was just allocated.
1165be55cc8cf05aace5e8769230e02b5948a0079496mmentovai      if (buffers->len == 0) {
1166be55cc8cf05aace5e8769230e02b5948a0079496mmentovai        // This can only occur with final buffer.
1167be55cc8cf05aace5e8769230e02b5948a0079496mmentovai        assert(buffers->next == NULL);
1168be55cc8cf05aace5e8769230e02b5948a0079496mmentovai        continue;
1169be55cc8cf05aace5e8769230e02b5948a0079496mmentovai      }
1170f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      memory.Copy(pos, &buffers->data, buffers->len);
1171f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org      pos += buffers->len;
1172f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org    }
1173b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    *result = memory.location();
1174b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
1175b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
1176b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1177b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteOSInformation(MDRawSystemInfo* sys_info) {
11785187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#if defined(__ANDROID__)
11795187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org    sys_info->platform_id = MD_OS_ANDROID;
11805187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#else
1181b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_info->platform_id = MD_OS_LINUX;
11825187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#endif
1183b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1184b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    struct utsname uts;
1185b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (uname(&uts))
1186b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
1187b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1188b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    static const size_t buf_len = 512;
1189b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    char buf[buf_len] = {0};
1190b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    size_t space_left = buf_len - 1;
1191b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    const char* info_table[] = {
1192b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      uts.sysname,
1193b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      uts.release,
1194b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      uts.version,
1195b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      uts.machine,
1196b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      NULL
1197b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    };
1198b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    bool first_item = true;
1199b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    for (const char** cur_info = info_table; *cur_info; cur_info++) {
1200ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org      static const char separator[] = " ";
1201ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org      size_t separator_len = sizeof(separator) - 1;
1202ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org      size_t info_len = my_strlen(*cur_info);
1203b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      if (info_len == 0)
1204b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        continue;
1205b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1206b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      if (space_left < info_len + (first_item ? 0 : separator_len))
1207b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        break;
1208b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1209b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      if (!first_item) {
1210ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org        my_strlcat(buf, separator, sizeof(buf));
1211b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid        space_left -= separator_len;
1212b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      }
1213b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1214b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      first_item = false;
1215ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org      my_strlcat(buf, *cur_info, sizeof(buf));
1216b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      space_left -= info_len;
1217b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    }
1218b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1219b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    MDLocationDescriptor location;
1220b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    if (!minidump_writer_.WriteString(buf, 0, &location))
1221b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid      return false;
1222b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    sys_info->csd_version_rva = location.rva;
1223b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1224b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return true;
1225b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
1226b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1227b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
1228b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid                     const char* filename) {
1229b5dfa2834d37a669cce3ca62cb7a56b713d368a2kmixter@chromium.org    char buf[NAME_MAX];
12304fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    if (!dumper_->BuildProcPath(buf, pid, filename))
12314fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org      return false;
1232b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return WriteFile(result, buf);
1233b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  }
1234b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1235e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org  // Only one of the 2 member variables below should be set to a valid value.
1236e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org  const int fd_;  // File descriptor where the minidum should be written.
1237e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org  const char* path_;  // Path to the file where the minidum should be written.
1238e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1239b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  const struct ucontext* const ucontext_;  // also from the signal handler
1240b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#if !defined(__ARM_EABI__) && !defined(__mips__)
1241b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org  const google_breakpad::fpstate_t* const float_state_;  // ditto
1242b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#endif
1243e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org  LinuxDumper* dumper_;
1244b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  MinidumpFileWriter minidump_writer_;
124529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  off_t minidump_size_limit_;
1246b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  MDLocationDescriptor crashing_thread_context_;
1247efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek  // Blocks of memory written to the dump. These are all currently
1248efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek  // written while writing the thread list stream, but saved here
1249efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek  // so a memory list stream can be written afterwards.
1250efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek  wasteful_vector<MDMemoryDescriptor> memory_blocks_;
1251ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  // Additional information about some mappings provided by the caller.
1252ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek  const MappingList& mapping_list_;
125386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  // Additional memory regions to be included in the dump,
125486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  // provided by the caller.
125586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  const AppMemoryList& app_memory_list_;
1256b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid};
1257b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1258ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek
1259e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidumpImpl(const char* minidump_path,
1260e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                       int minidump_fd,
126129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                       off_t minidump_size_limit,
1262e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                       pid_t crashing_process,
1263e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                       const void* blob, size_t blob_size,
126486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                       const MappingList& mappings,
126586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                       const AppMemoryList& appmem) {
12664fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  LinuxPtraceDumper dumper(crashing_process);
126729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  const ExceptionHandler::CrashContext* context = NULL;
126829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  if (blob) {
126929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    if (blob_size != sizeof(ExceptionHandler::CrashContext))
127029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org      return false;
127129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
127229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    dumper.set_crash_address(
127329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org        reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
127429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    dumper.set_crash_signal(context->siginfo.si_signo);
127529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org    dumper.set_crash_thread(context->tid);
127629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  }
127786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  MinidumpWriter writer(minidump_path, minidump_fd, context, mappings,
127886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                        appmem, &dumper);
127929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  // Set desired limit for file size of minidump (-1 means no limit).
128029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  writer.set_minidump_size_limit(minidump_size_limit);
1281b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  if (!writer.Init())
1282b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid    return false;
1283b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid  return writer.Dump();
1284b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid}
1285b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid
1286e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org}  // namespace
1287e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1288e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgnamespace google_breakpad {
1289e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1290e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(const char* minidump_path, pid_t crashing_process,
1291e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                   const void* blob, size_t blob_size) {
129229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  return WriteMinidumpImpl(minidump_path, -1, -1,
129329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           crashing_process, blob, blob_size,
129486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                           MappingList(), AppMemoryList());
1295e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org}
1296e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1297e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(int minidump_fd, pid_t crashing_process,
1298e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                   const void* blob, size_t blob_size) {
129929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  return WriteMinidumpImpl(NULL, minidump_fd, -1,
130029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           crashing_process, blob, blob_size,
130186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                           MappingList(), AppMemoryList());
1302e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org}
1303e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1304f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.combool WriteMinidump(const char* minidump_path, pid_t process,
1305f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com                   pid_t process_blamed_thread) {
1306f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  LinuxPtraceDumper dumper(process);
1307f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  // MinidumpWriter will set crash address
1308f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED);
1309f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  dumper.set_crash_thread(process_blamed_thread);
1310f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  MinidumpWriter writer(minidump_path, -1, NULL, MappingList(),
1311f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com                        AppMemoryList(), &dumper);
1312f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  if (!writer.Init())
1313f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com    return false;
1314f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com  return writer.Dump();
1315f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com}
1316f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com
1317e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(const char* minidump_path, pid_t crashing_process,
1318e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                   const void* blob, size_t blob_size,
131986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                   const MappingList& mappings,
132086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                   const AppMemoryList& appmem) {
132129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process,
132229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           blob, blob_size,
132386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                           mappings, appmem);
1324e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org}
1325e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1326e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(int minidump_fd, pid_t crashing_process,
1327e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org                   const void* blob, size_t blob_size,
132886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                   const MappingList& mappings,
132986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                   const AppMemoryList& appmem) {
133029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process,
133129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           blob, blob_size,
133229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           mappings, appmem);
133329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org}
133429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org
133529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.orgbool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
133629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   pid_t crashing_process,
133729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   const void* blob, size_t blob_size,
133829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   const MappingList& mappings,
133929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   const AppMemoryList& appmem) {
134029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit,
134129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           crashing_process, blob, blob_size,
134229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           mappings, appmem);
134329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org}
134429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org
134529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.orgbool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
134629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   pid_t crashing_process,
134729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   const void* blob, size_t blob_size,
134829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   const MappingList& mappings,
134929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                   const AppMemoryList& appmem) {
135029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org  return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit,
135129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org                           crashing_process, blob, blob_size,
135286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                           mappings, appmem);
1353e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org}
1354e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org
1355aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.orgbool WriteMinidump(const char* filename,
1356aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org                   const MappingList& mappings,
135786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com                   const AppMemoryList& appmem,
1358aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org                   LinuxDumper* dumper) {
135986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com  MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper);
13604fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  if (!writer.Init())
13614fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org    return false;
13624fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org  return writer.Dump();
13634fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org}
13644fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org
1365b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid}  // namespace google_breakpad
1366