/thirdparty/breakpad/client/linux/minidump_writer/minidump_writer.cc

http://github.com/tomahawk-player/tomahawk · C++ · 1349 lines · 1029 code · 171 blank · 149 comment · 140 complexity · 2727c7e250cf00f39f471e45993a31d8 MD5 · raw file

  1. // Copyright (c) 2010, Google Inc.
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. // This code writes out minidump files:
  30. // http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
  31. //
  32. // Minidumps are a Microsoft format which Breakpad uses for recording crash
  33. // dumps. This code has to run in a compromised environment (the address space
  34. // may have received SIGSEGV), thus the following rules apply:
  35. // * You may not enter the dynamic linker. This means that we cannot call
  36. // any symbols in a shared library (inc libc). Because of this we replace
  37. // libc functions in linux_libc_support.h.
  38. // * You may not call syscalls via the libc wrappers. This rule is a subset
  39. // of the first rule but it bears repeating. We have direct wrappers
  40. // around the system calls in linux_syscall_support.h.
  41. // * You may not malloc. There's an alternative allocator in memory.h and
  42. // a canonical instance in the LinuxDumper object. We use the placement
  43. // new form to allocate objects and we don't delete them.
  44. #include "client/linux/minidump_writer/minidump_writer.h"
  45. #include "client/minidump_file_writer-inl.h"
  46. #include <ctype.h>
  47. #include <errno.h>
  48. #include <fcntl.h>
  49. #if !defined(__ANDROID__)
  50. #include <link.h>
  51. #endif
  52. #include <stdio.h>
  53. #if !defined(__ANDROID__)
  54. #include <sys/ucontext.h>
  55. #include <sys/user.h>
  56. #endif
  57. #include <sys/utsname.h>
  58. #include <unistd.h>
  59. #include <algorithm>
  60. #include "client/minidump_file_writer.h"
  61. #include "google_breakpad/common/minidump_format.h"
  62. #if defined(__ANDROID__)
  63. #include "client/linux/android_link.h"
  64. #include "client/linux/android_ucontext.h"
  65. #endif
  66. #include "client/linux/handler/exception_handler.h"
  67. #include "client/linux/minidump_writer/line_reader.h"
  68. #include "client/linux/minidump_writer/linux_dumper.h"
  69. #include "client/linux/minidump_writer/linux_ptrace_dumper.h"
  70. #include "client/linux/minidump_writer/minidump_extension_linux.h"
  71. #include "client/minidump_file_writer.h"
  72. #include "common/linux/linux_libc_support.h"
  73. #include "google_breakpad/common/minidump_format.h"
  74. #include "third_party/lss/linux_syscall_support.h"
  75. // Minidump defines register structures which are different from the raw
  76. // structures which we get from the kernel. These are platform specific
  77. // functions to juggle the ucontext and user structures into minidump format.
  78. #if defined(__i386)
  79. typedef MDRawContextX86 RawContextCPU;
  80. // Write a uint16_t to memory
  81. // out: memory location to write to
  82. // v: value to write.
  83. static void U16(void* out, uint16_t v) {
  84. memcpy(out, &v, sizeof(v));
  85. }
  86. // Write a uint32_t to memory
  87. // out: memory location to write to
  88. // v: value to write.
  89. static void U32(void* out, uint32_t v) {
  90. memcpy(out, &v, sizeof(v));
  91. }
  92. // Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
  93. // out: the minidump structure
  94. // info: the collection of register structures.
  95. static void CPUFillFromThreadInfo(MDRawContextX86 *out,
  96. const google_breakpad::ThreadInfo &info) {
  97. out->context_flags = MD_CONTEXT_X86_ALL;
  98. out->dr0 = info.dregs[0];
  99. out->dr1 = info.dregs[1];
  100. out->dr2 = info.dregs[2];
  101. out->dr3 = info.dregs[3];
  102. // 4 and 5 deliberatly omitted because they aren't included in the minidump
  103. // format.
  104. out->dr6 = info.dregs[6];
  105. out->dr7 = info.dregs[7];
  106. out->gs = info.regs.xgs;
  107. out->fs = info.regs.xfs;
  108. out->es = info.regs.xes;
  109. out->ds = info.regs.xds;
  110. out->edi = info.regs.edi;
  111. out->esi = info.regs.esi;
  112. out->ebx = info.regs.ebx;
  113. out->edx = info.regs.edx;
  114. out->ecx = info.regs.ecx;
  115. out->eax = info.regs.eax;
  116. out->ebp = info.regs.ebp;
  117. out->eip = info.regs.eip;
  118. out->cs = info.regs.xcs;
  119. out->eflags = info.regs.eflags;
  120. out->esp = info.regs.esp;
  121. out->ss = info.regs.xss;
  122. out->float_save.control_word = info.fpregs.cwd;
  123. out->float_save.status_word = info.fpregs.swd;
  124. out->float_save.tag_word = info.fpregs.twd;
  125. out->float_save.error_offset = info.fpregs.fip;
  126. out->float_save.error_selector = info.fpregs.fcs;
  127. out->float_save.data_offset = info.fpregs.foo;
  128. out->float_save.data_selector = info.fpregs.fos;
  129. // 8 registers * 10 bytes per register.
  130. memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
  131. // This matches the Intel fpsave format.
  132. U16(out->extended_registers + 0, info.fpregs.cwd);
  133. U16(out->extended_registers + 2, info.fpregs.swd);
  134. U16(out->extended_registers + 4, info.fpregs.twd);
  135. U16(out->extended_registers + 6, info.fpxregs.fop);
  136. U32(out->extended_registers + 8, info.fpxregs.fip);
  137. U16(out->extended_registers + 12, info.fpxregs.fcs);
  138. U32(out->extended_registers + 16, info.fpregs.foo);
  139. U16(out->extended_registers + 20, info.fpregs.fos);
  140. U32(out->extended_registers + 24, info.fpxregs.mxcsr);
  141. memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
  142. memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
  143. }
  144. // Juggle an x86 ucontext into minidump format
  145. // out: the minidump structure
  146. // info: the collection of register structures.
  147. static void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
  148. const struct _libc_fpstate* fp) {
  149. const greg_t* regs = uc->uc_mcontext.gregs;
  150. out->context_flags = MD_CONTEXT_X86_FULL |
  151. MD_CONTEXT_X86_FLOATING_POINT;
  152. out->gs = regs[REG_GS];
  153. out->fs = regs[REG_FS];
  154. out->es = regs[REG_ES];
  155. out->ds = regs[REG_DS];
  156. out->edi = regs[REG_EDI];
  157. out->esi = regs[REG_ESI];
  158. out->ebx = regs[REG_EBX];
  159. out->edx = regs[REG_EDX];
  160. out->ecx = regs[REG_ECX];
  161. out->eax = regs[REG_EAX];
  162. out->ebp = regs[REG_EBP];
  163. out->eip = regs[REG_EIP];
  164. out->cs = regs[REG_CS];
  165. out->eflags = regs[REG_EFL];
  166. out->esp = regs[REG_UESP];
  167. out->ss = regs[REG_SS];
  168. out->float_save.control_word = fp->cw;
  169. out->float_save.status_word = fp->sw;
  170. out->float_save.tag_word = fp->tag;
  171. out->float_save.error_offset = fp->ipoff;
  172. out->float_save.error_selector = fp->cssel;
  173. out->float_save.data_offset = fp->dataoff;
  174. out->float_save.data_selector = fp->datasel;
  175. // 8 registers * 10 bytes per register.
  176. memcpy(out->float_save.register_area, fp->_st, 10 * 8);
  177. }
  178. #elif defined(__x86_64)
  179. typedef MDRawContextAMD64 RawContextCPU;
  180. static void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
  181. const google_breakpad::ThreadInfo &info) {
  182. out->context_flags = MD_CONTEXT_AMD64_FULL |
  183. MD_CONTEXT_AMD64_SEGMENTS;
  184. out->cs = info.regs.cs;
  185. out->ds = info.regs.ds;
  186. out->es = info.regs.es;
  187. out->fs = info.regs.fs;
  188. out->gs = info.regs.gs;
  189. out->ss = info.regs.ss;
  190. out->eflags = info.regs.eflags;
  191. out->dr0 = info.dregs[0];
  192. out->dr1 = info.dregs[1];
  193. out->dr2 = info.dregs[2];
  194. out->dr3 = info.dregs[3];
  195. // 4 and 5 deliberatly omitted because they aren't included in the minidump
  196. // format.
  197. out->dr6 = info.dregs[6];
  198. out->dr7 = info.dregs[7];
  199. out->rax = info.regs.rax;
  200. out->rcx = info.regs.rcx;
  201. out->rdx = info.regs.rdx;
  202. out->rbx = info.regs.rbx;
  203. out->rsp = info.regs.rsp;
  204. out->rbp = info.regs.rbp;
  205. out->rsi = info.regs.rsi;
  206. out->rdi = info.regs.rdi;
  207. out->r8 = info.regs.r8;
  208. out->r9 = info.regs.r9;
  209. out->r10 = info.regs.r10;
  210. out->r11 = info.regs.r11;
  211. out->r12 = info.regs.r12;
  212. out->r13 = info.regs.r13;
  213. out->r14 = info.regs.r14;
  214. out->r15 = info.regs.r15;
  215. out->rip = info.regs.rip;
  216. out->flt_save.control_word = info.fpregs.cwd;
  217. out->flt_save.status_word = info.fpregs.swd;
  218. out->flt_save.tag_word = info.fpregs.ftw;
  219. out->flt_save.error_opcode = info.fpregs.fop;
  220. out->flt_save.error_offset = info.fpregs.rip;
  221. out->flt_save.error_selector = 0; // We don't have this.
  222. out->flt_save.data_offset = info.fpregs.rdp;
  223. out->flt_save.data_selector = 0; // We don't have this.
  224. out->flt_save.mx_csr = info.fpregs.mxcsr;
  225. out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
  226. memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
  227. memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
  228. }
  229. static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
  230. const struct _libc_fpstate* fpregs) {
  231. const greg_t* regs = uc->uc_mcontext.gregs;
  232. out->context_flags = MD_CONTEXT_AMD64_FULL;
  233. out->cs = regs[REG_CSGSFS] & 0xffff;
  234. out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
  235. out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
  236. out->eflags = regs[REG_EFL];
  237. out->rax = regs[REG_RAX];
  238. out->rcx = regs[REG_RCX];
  239. out->rdx = regs[REG_RDX];
  240. out->rbx = regs[REG_RBX];
  241. out->rsp = regs[REG_RSP];
  242. out->rbp = regs[REG_RBP];
  243. out->rsi = regs[REG_RSI];
  244. out->rdi = regs[REG_RDI];
  245. out->r8 = regs[REG_R8];
  246. out->r9 = regs[REG_R9];
  247. out->r10 = regs[REG_R10];
  248. out->r11 = regs[REG_R11];
  249. out->r12 = regs[REG_R12];
  250. out->r13 = regs[REG_R13];
  251. out->r14 = regs[REG_R14];
  252. out->r15 = regs[REG_R15];
  253. out->rip = regs[REG_RIP];
  254. out->flt_save.control_word = fpregs->cwd;
  255. out->flt_save.status_word = fpregs->swd;
  256. out->flt_save.tag_word = fpregs->ftw;
  257. out->flt_save.error_opcode = fpregs->fop;
  258. out->flt_save.error_offset = fpregs->rip;
  259. out->flt_save.data_offset = fpregs->rdp;
  260. out->flt_save.error_selector = 0; // We don't have this.
  261. out->flt_save.data_selector = 0; // We don't have this.
  262. out->flt_save.mx_csr = fpregs->mxcsr;
  263. out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
  264. memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
  265. memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
  266. }
  267. #elif defined(__ARMEL__)
  268. typedef MDRawContextARM RawContextCPU;
  269. static void CPUFillFromThreadInfo(MDRawContextARM *out,
  270. const google_breakpad::ThreadInfo &info) {
  271. out->context_flags = MD_CONTEXT_ARM_FULL;
  272. for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
  273. out->iregs[i] = info.regs.uregs[i];
  274. // No CPSR register in ThreadInfo(it's not accessible via ptrace)
  275. out->cpsr = 0;
  276. #if !defined(__ANDROID__)
  277. out->float_save.fpscr = info.fpregs.fpsr |
  278. (static_cast<u_int64_t>(info.fpregs.fpcr) << 32);
  279. // TODO: sort this out, actually collect floating point registers
  280. memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
  281. memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
  282. #endif
  283. }
  284. static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
  285. const struct _libc_fpstate* fpregs) {
  286. out->context_flags = MD_CONTEXT_ARM_FULL;
  287. out->iregs[0] = uc->uc_mcontext.arm_r0;
  288. out->iregs[1] = uc->uc_mcontext.arm_r1;
  289. out->iregs[2] = uc->uc_mcontext.arm_r2;
  290. out->iregs[3] = uc->uc_mcontext.arm_r3;
  291. out->iregs[4] = uc->uc_mcontext.arm_r4;
  292. out->iregs[5] = uc->uc_mcontext.arm_r5;
  293. out->iregs[6] = uc->uc_mcontext.arm_r6;
  294. out->iregs[7] = uc->uc_mcontext.arm_r7;
  295. out->iregs[8] = uc->uc_mcontext.arm_r8;
  296. out->iregs[9] = uc->uc_mcontext.arm_r9;
  297. out->iregs[10] = uc->uc_mcontext.arm_r10;
  298. out->iregs[11] = uc->uc_mcontext.arm_fp;
  299. out->iregs[12] = uc->uc_mcontext.arm_ip;
  300. out->iregs[13] = uc->uc_mcontext.arm_sp;
  301. out->iregs[14] = uc->uc_mcontext.arm_lr;
  302. out->iregs[15] = uc->uc_mcontext.arm_pc;
  303. out->cpsr = uc->uc_mcontext.arm_cpsr;
  304. // TODO: fix this after fixing ExceptionHandler
  305. out->float_save.fpscr = 0;
  306. memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
  307. memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
  308. }
  309. #else
  310. #error "This code has not been ported to your platform yet."
  311. #endif
  312. namespace google_breakpad {
  313. class MinidumpWriter {
  314. public:
  315. MinidumpWriter(const char* filename,
  316. const ExceptionHandler::CrashContext* context,
  317. const MappingList& mappings,
  318. LinuxDumper* dumper)
  319. : filename_(filename),
  320. ucontext_(context ? &context->context : NULL),
  321. #if !defined(__ARM_EABI__)
  322. float_state_(context ? &context->float_state : NULL),
  323. #else
  324. // TODO: fix this after fixing ExceptionHandler
  325. float_state_(NULL),
  326. #endif
  327. dumper_(dumper),
  328. memory_blocks_(dumper_->allocator()),
  329. mapping_list_(mappings) {
  330. }
  331. bool Init() {
  332. return dumper_->Init() && minidump_writer_.Open(filename_) &&
  333. dumper_->ThreadsSuspend();
  334. }
  335. ~MinidumpWriter() {
  336. minidump_writer_.Close();
  337. dumper_->ThreadsResume();
  338. }
  339. bool Dump() {
  340. // The dynamic linker makes information available that helps gdb find all
  341. // DSOs loaded into the program. If we can access this information, we dump
  342. // it to a MD_LINUX_DSO_DEBUG stream.
  343. struct r_debug* r_debug = NULL;
  344. uint32_t dynamic_length = 0;
  345. #if !defined(__ANDROID__)
  346. // This code assumes the crashing process is the same as this process and
  347. // may hang or take a long time to complete if not so.
  348. // Thus, we skip this code for a post-mortem based dump.
  349. if (!dumper_->IsPostMortem()) {
  350. // The Android NDK is missing structure definitions for most of this.
  351. // For now, it's simpler just to skip it.
  352. for (int i = 0;;) {
  353. ElfW(Dyn) dyn;
  354. dynamic_length += sizeof(dyn);
  355. // NOTE: Use of _DYNAMIC assumes this is the same process as the
  356. // crashing process. This loop will go forever if it's out of bounds.
  357. dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
  358. sizeof(dyn));
  359. if (dyn.d_tag == DT_DEBUG) {
  360. r_debug = (struct r_debug*)dyn.d_un.d_ptr;
  361. continue;
  362. } else if (dyn.d_tag == DT_NULL) {
  363. break;
  364. }
  365. }
  366. }
  367. #endif
  368. // A minidump file contains a number of tagged streams. This is the number
  369. // of stream which we write.
  370. unsigned kNumWriters = 12;
  371. if (r_debug)
  372. ++kNumWriters;
  373. TypedMDRVA<MDRawHeader> header(&minidump_writer_);
  374. TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
  375. if (!header.Allocate())
  376. return false;
  377. if (!dir.AllocateArray(kNumWriters))
  378. return false;
  379. memset(header.get(), 0, sizeof(MDRawHeader));
  380. header.get()->signature = MD_HEADER_SIGNATURE;
  381. header.get()->version = MD_HEADER_VERSION;
  382. header.get()->time_date_stamp = time(NULL);
  383. header.get()->stream_count = kNumWriters;
  384. header.get()->stream_directory_rva = dir.position();
  385. unsigned dir_index = 0;
  386. MDRawDirectory dirent;
  387. if (!WriteThreadListStream(&dirent))
  388. return false;
  389. dir.CopyIndex(dir_index++, &dirent);
  390. if (!WriteMappings(&dirent))
  391. return false;
  392. dir.CopyIndex(dir_index++, &dirent);
  393. if (!WriteMemoryListStream(&dirent))
  394. return false;
  395. dir.CopyIndex(dir_index++, &dirent);
  396. if (!WriteExceptionStream(&dirent))
  397. return false;
  398. dir.CopyIndex(dir_index++, &dirent);
  399. if (!WriteSystemInfoStream(&dirent))
  400. return false;
  401. dir.CopyIndex(dir_index++, &dirent);
  402. dirent.stream_type = MD_LINUX_CPU_INFO;
  403. if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
  404. NullifyDirectoryEntry(&dirent);
  405. dir.CopyIndex(dir_index++, &dirent);
  406. dirent.stream_type = MD_LINUX_PROC_STATUS;
  407. if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
  408. NullifyDirectoryEntry(&dirent);
  409. dir.CopyIndex(dir_index++, &dirent);
  410. dirent.stream_type = MD_LINUX_LSB_RELEASE;
  411. if (!WriteFile(&dirent.location, "/etc/lsb-release"))
  412. NullifyDirectoryEntry(&dirent);
  413. dir.CopyIndex(dir_index++, &dirent);
  414. dirent.stream_type = MD_LINUX_CMD_LINE;
  415. if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
  416. NullifyDirectoryEntry(&dirent);
  417. dir.CopyIndex(dir_index++, &dirent);
  418. dirent.stream_type = MD_LINUX_ENVIRON;
  419. if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
  420. NullifyDirectoryEntry(&dirent);
  421. dir.CopyIndex(dir_index++, &dirent);
  422. dirent.stream_type = MD_LINUX_AUXV;
  423. if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
  424. NullifyDirectoryEntry(&dirent);
  425. dir.CopyIndex(dir_index++, &dirent);
  426. dirent.stream_type = MD_LINUX_MAPS;
  427. if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
  428. NullifyDirectoryEntry(&dirent);
  429. dir.CopyIndex(dir_index++, &dirent);
  430. if (r_debug) {
  431. dirent.stream_type = MD_LINUX_DSO_DEBUG;
  432. if (!WriteDSODebugStream(&dirent, r_debug, dynamic_length))
  433. NullifyDirectoryEntry(&dirent);
  434. dir.CopyIndex(dir_index++, &dirent);
  435. }
  436. // If you add more directory entries, don't forget to update kNumWriters,
  437. // above.
  438. dumper_->ThreadsResume();
  439. return true;
  440. }
  441. // Check if the top of the stack is part of a system call that has been
  442. // redirected by the seccomp sandbox. If so, try to pop the stack frames
  443. // all the way back to the point where the interception happened.
  444. void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread,
  445. uint8_t* stack_copy) {
  446. #if defined(__x86_64)
  447. u_int64_t bp = cpu->rbp;
  448. u_int64_t top = thread.stack.start_of_memory_range;
  449. for (int i = 4; i--; ) {
  450. if (bp < top ||
  451. bp + sizeof(bp) > thread.stack.start_of_memory_range +
  452. thread.stack.memory.data_size ||
  453. bp & 1) {
  454. break;
  455. }
  456. uint64_t old_top = top;
  457. top = bp;
  458. u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
  459. memcpy(&bp, bp_addr, sizeof(bp));
  460. if (bp == 0xDEADBEEFDEADBEEFull) {
  461. struct {
  462. uint64_t r15;
  463. uint64_t r14;
  464. uint64_t r13;
  465. uint64_t r12;
  466. uint64_t r11;
  467. uint64_t r10;
  468. uint64_t r9;
  469. uint64_t r8;
  470. uint64_t rdi;
  471. uint64_t rsi;
  472. uint64_t rdx;
  473. uint64_t rcx;
  474. uint64_t rbx;
  475. uint64_t deadbeef;
  476. uint64_t rbp;
  477. uint64_t fakeret;
  478. uint64_t ret;
  479. /* char redzone[128]; */
  480. } seccomp_stackframe;
  481. if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
  482. top - offsetof(typeof(seccomp_stackframe), deadbeef) +
  483. sizeof(seccomp_stackframe) >
  484. thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
  485. break;
  486. }
  487. memcpy(&seccomp_stackframe,
  488. bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
  489. sizeof(seccomp_stackframe));
  490. cpu->rbx = seccomp_stackframe.rbx;
  491. cpu->rcx = seccomp_stackframe.rcx;
  492. cpu->rdx = seccomp_stackframe.rdx;
  493. cpu->rsi = seccomp_stackframe.rsi;
  494. cpu->rdi = seccomp_stackframe.rdi;
  495. cpu->rbp = seccomp_stackframe.rbp;
  496. cpu->rsp = top + 4*sizeof(uint64_t) + 128;
  497. cpu->r8 = seccomp_stackframe.r8;
  498. cpu->r9 = seccomp_stackframe.r9;
  499. cpu->r10 = seccomp_stackframe.r10;
  500. cpu->r11 = seccomp_stackframe.r11;
  501. cpu->r12 = seccomp_stackframe.r12;
  502. cpu->r13 = seccomp_stackframe.r13;
  503. cpu->r14 = seccomp_stackframe.r14;
  504. cpu->r15 = seccomp_stackframe.r15;
  505. cpu->rip = seccomp_stackframe.fakeret;
  506. return;
  507. }
  508. }
  509. #elif defined(__i386)
  510. u_int32_t bp = cpu->ebp;
  511. u_int32_t top = thread.stack.start_of_memory_range;
  512. for (int i = 4; i--; ) {
  513. if (bp < top ||
  514. bp + sizeof(bp) > thread.stack.start_of_memory_range +
  515. thread.stack.memory.data_size ||
  516. bp & 1) {
  517. break;
  518. }
  519. uint32_t old_top = top;
  520. top = bp;
  521. u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
  522. memcpy(&bp, bp_addr, sizeof(bp));
  523. if (bp == 0xDEADBEEFu) {
  524. struct {
  525. uint32_t edi;
  526. uint32_t esi;
  527. uint32_t edx;
  528. uint32_t ecx;
  529. uint32_t ebx;
  530. uint32_t deadbeef;
  531. uint32_t ebp;
  532. uint32_t fakeret;
  533. uint32_t ret;
  534. } seccomp_stackframe;
  535. if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
  536. top - offsetof(typeof(seccomp_stackframe), deadbeef) +
  537. sizeof(seccomp_stackframe) >
  538. thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
  539. break;
  540. }
  541. memcpy(&seccomp_stackframe,
  542. bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
  543. sizeof(seccomp_stackframe));
  544. cpu->ebx = seccomp_stackframe.ebx;
  545. cpu->ecx = seccomp_stackframe.ecx;
  546. cpu->edx = seccomp_stackframe.edx;
  547. cpu->esi = seccomp_stackframe.esi;
  548. cpu->edi = seccomp_stackframe.edi;
  549. cpu->ebp = seccomp_stackframe.ebp;
  550. cpu->esp = top + 4*sizeof(void*);
  551. cpu->eip = seccomp_stackframe.fakeret;
  552. return;
  553. }
  554. }
  555. #endif
  556. }
  557. // Write information about the threads.
  558. bool WriteThreadListStream(MDRawDirectory* dirent) {
  559. const unsigned num_threads = dumper_->threads().size();
  560. TypedMDRVA<uint32_t> list(&minidump_writer_);
  561. if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
  562. return false;
  563. dirent->stream_type = MD_THREAD_LIST_STREAM;
  564. dirent->location = list.location();
  565. *list.get() = num_threads;
  566. for (unsigned i = 0; i < num_threads; ++i) {
  567. MDRawThread thread;
  568. my_memset(&thread, 0, sizeof(thread));
  569. thread.thread_id = dumper_->threads()[i];
  570. // We have a different source of information for the crashing thread. If
  571. // we used the actual state of the thread we would find it running in the
  572. // signal handler with the alternative stack, which would be deeply
  573. // unhelpful.
  574. if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
  575. !dumper_->IsPostMortem()) {
  576. const void* stack;
  577. size_t stack_len;
  578. if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
  579. return false;
  580. UntypedMDRVA memory(&minidump_writer_);
  581. if (!memory.Allocate(stack_len))
  582. return false;
  583. uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
  584. dumper_->CopyFromProcess(stack_copy, thread.thread_id, stack,
  585. stack_len);
  586. memory.Copy(stack_copy, stack_len);
  587. thread.stack.start_of_memory_range = (uintptr_t) (stack);
  588. thread.stack.memory = memory.location();
  589. memory_blocks_.push_back(thread.stack);
  590. // Copy 256 bytes around crashing instruction pointer to minidump.
  591. const size_t kIPMemorySize = 256;
  592. u_int64_t ip = GetInstructionPointer();
  593. // Bound it to the upper and lower bounds of the memory map
  594. // it's contained within. If it's not in mapped memory,
  595. // don't bother trying to write it.
  596. bool ip_is_mapped = false;
  597. MDMemoryDescriptor ip_memory_d;
  598. for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
  599. const MappingInfo& mapping = *dumper_->mappings()[j];
  600. if (ip >= mapping.start_addr &&
  601. ip < mapping.start_addr + mapping.size) {
  602. ip_is_mapped = true;
  603. // Try to get 128 bytes before and after the IP, but
  604. // settle for whatever's available.
  605. ip_memory_d.start_of_memory_range =
  606. std::max(mapping.start_addr,
  607. uintptr_t(ip - (kIPMemorySize / 2)));
  608. uintptr_t end_of_range =
  609. std::min(uintptr_t(ip + (kIPMemorySize / 2)),
  610. uintptr_t(mapping.start_addr + mapping.size));
  611. ip_memory_d.memory.data_size =
  612. end_of_range - ip_memory_d.start_of_memory_range;
  613. break;
  614. }
  615. }
  616. if (ip_is_mapped) {
  617. UntypedMDRVA ip_memory(&minidump_writer_);
  618. if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
  619. return false;
  620. uint8_t* memory_copy =
  621. reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
  622. dumper_->CopyFromProcess(
  623. memory_copy,
  624. thread.thread_id,
  625. reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
  626. ip_memory_d.memory.data_size);
  627. ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
  628. ip_memory_d.memory = ip_memory.location();
  629. memory_blocks_.push_back(ip_memory_d);
  630. }
  631. TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
  632. if (!cpu.Allocate())
  633. return false;
  634. my_memset(cpu.get(), 0, sizeof(RawContextCPU));
  635. CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
  636. PopSeccompStackFrame(cpu.get(), thread, stack_copy);
  637. thread.thread_context = cpu.location();
  638. crashing_thread_context_ = cpu.location();
  639. } else {
  640. ThreadInfo info;
  641. if (!dumper_->GetThreadInfoByIndex(i, &info))
  642. return false;
  643. UntypedMDRVA memory(&minidump_writer_);
  644. if (!memory.Allocate(info.stack_len))
  645. return false;
  646. uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(info.stack_len));
  647. dumper_->CopyFromProcess(stack_copy, thread.thread_id, info.stack,
  648. info.stack_len);
  649. memory.Copy(stack_copy, info.stack_len);
  650. thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
  651. thread.stack.memory = memory.location();
  652. memory_blocks_.push_back(thread.stack);
  653. TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
  654. if (!cpu.Allocate())
  655. return false;
  656. my_memset(cpu.get(), 0, sizeof(RawContextCPU));
  657. CPUFillFromThreadInfo(cpu.get(), info);
  658. PopSeccompStackFrame(cpu.get(), thread, stack_copy);
  659. thread.thread_context = cpu.location();
  660. if (dumper_->threads()[i] == GetCrashThread()) {
  661. assert(dumper_->IsPostMortem());
  662. crashing_thread_context_ = cpu.location();
  663. }
  664. }
  665. list.CopyIndexAfterObject(i, &thread, sizeof(thread));
  666. }
  667. return true;
  668. }
  669. static bool ShouldIncludeMapping(const MappingInfo& mapping) {
  670. if (mapping.name[0] == 0 || // only want modules with filenames.
  671. mapping.offset || // only want to include one mapping per shared lib.
  672. mapping.size < 4096) { // too small to get a signature for.
  673. return false;
  674. }
  675. return true;
  676. }
  677. // If there is caller-provided information about this mapping
  678. // in the mapping_list_ list, return true. Otherwise, return false.
  679. bool HaveMappingInfo(const MappingInfo& mapping) {
  680. for (MappingList::const_iterator iter = mapping_list_.begin();
  681. iter != mapping_list_.end();
  682. ++iter) {
  683. // Ignore any mappings that are wholly contained within
  684. // mappings in the mapping_info_ list.
  685. if (mapping.start_addr >= iter->first.start_addr &&
  686. (mapping.start_addr + mapping.size) <=
  687. (iter->first.start_addr + iter->first.size)) {
  688. return true;
  689. }
  690. }
  691. return false;
  692. }
  693. // Write information about the mappings in effect. Because we are using the
  694. // minidump format, the information about the mappings is pretty limited.
  695. // Because of this, we also include the full, unparsed, /proc/$x/maps file in
  696. // another stream in the file.
  697. bool WriteMappings(MDRawDirectory* dirent) {
  698. const unsigned num_mappings = dumper_->mappings().size();
  699. unsigned num_output_mappings = mapping_list_.size();
  700. for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
  701. const MappingInfo& mapping = *dumper_->mappings()[i];
  702. if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
  703. num_output_mappings++;
  704. }
  705. TypedMDRVA<uint32_t> list(&minidump_writer_);
  706. if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
  707. return false;
  708. dirent->stream_type = MD_MODULE_LIST_STREAM;
  709. dirent->location = list.location();
  710. *list.get() = num_output_mappings;
  711. // First write all the mappings from the dumper
  712. unsigned int j = 0;
  713. for (unsigned i = 0; i < num_mappings; ++i) {
  714. const MappingInfo& mapping = *dumper_->mappings()[i];
  715. if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
  716. continue;
  717. MDRawModule mod;
  718. if (!FillRawModule(mapping, true, i, mod, NULL))
  719. return false;
  720. list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
  721. }
  722. // Next write all the mappings provided by the caller
  723. for (MappingList::const_iterator iter = mapping_list_.begin();
  724. iter != mapping_list_.end();
  725. ++iter) {
  726. MDRawModule mod;
  727. if (!FillRawModule(iter->first, false, 0, mod, iter->second))
  728. return false;
  729. list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
  730. }
  731. return true;
  732. }
  733. // Fill the MDRawModule |mod| with information about the provided
  734. // |mapping|. If |identifier| is non-NULL, use it instead of calculating
  735. // a file ID from the mapping.
  736. bool FillRawModule(const MappingInfo& mapping,
  737. bool member,
  738. unsigned int mapping_id,
  739. MDRawModule& mod,
  740. const u_int8_t* identifier) {
  741. my_memset(&mod, 0, MD_MODULE_SIZE);
  742. mod.base_of_image = mapping.start_addr;
  743. mod.size_of_image = mapping.size;
  744. const size_t filepath_len = my_strlen(mapping.name);
  745. // Figure out file name from path
  746. const char* filename_ptr = mapping.name + filepath_len - 1;
  747. while (filename_ptr >= mapping.name) {
  748. if (*filename_ptr == '/')
  749. break;
  750. filename_ptr--;
  751. }
  752. filename_ptr++;
  753. const size_t filename_len = mapping.name + filepath_len - filename_ptr;
  754. uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
  755. uint8_t* cv_ptr = cv_buf;
  756. UntypedMDRVA cv(&minidump_writer_);
  757. if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
  758. return false;
  759. const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
  760. memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
  761. cv_ptr += sizeof(cv_signature);
  762. uint8_t* signature = cv_ptr;
  763. cv_ptr += sizeof(MDGUID);
  764. if (identifier) {
  765. // GUID was provided by caller.
  766. memcpy(signature, identifier, sizeof(MDGUID));
  767. } else {
  768. dumper_->ElfFileIdentifierForMapping(mapping, member,
  769. mapping_id, signature);
  770. }
  771. my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
  772. cv_ptr += sizeof(uint32_t);
  773. // Write pdb_file_name
  774. memcpy(cv_ptr, filename_ptr, filename_len + 1);
  775. cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
  776. mod.cv_record = cv.location();
  777. MDLocationDescriptor ld;
  778. if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
  779. return false;
  780. mod.module_name_rva = ld.rva;
  781. return true;
  782. }
  783. bool WriteMemoryListStream(MDRawDirectory* dirent) {
  784. TypedMDRVA<uint32_t> list(&minidump_writer_);
  785. if (!list.AllocateObjectAndArray(memory_blocks_.size(),
  786. sizeof(MDMemoryDescriptor)))
  787. return false;
  788. dirent->stream_type = MD_MEMORY_LIST_STREAM;
  789. dirent->location = list.location();
  790. *list.get() = memory_blocks_.size();
  791. for (size_t i = 0; i < memory_blocks_.size(); ++i) {
  792. list.CopyIndexAfterObject(i, &memory_blocks_[i],
  793. sizeof(MDMemoryDescriptor));
  794. }
  795. return true;
  796. }
  797. bool WriteExceptionStream(MDRawDirectory* dirent) {
  798. TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
  799. if (!exc.Allocate())
  800. return false;
  801. my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
  802. dirent->stream_type = MD_EXCEPTION_STREAM;
  803. dirent->location = exc.location();
  804. exc.get()->thread_id = GetCrashThread();
  805. exc.get()->exception_record.exception_code = dumper_->crash_signal();
  806. exc.get()->exception_record.exception_address = dumper_->crash_address();
  807. exc.get()->thread_context = crashing_thread_context_;
  808. return true;
  809. }
  810. bool WriteSystemInfoStream(MDRawDirectory* dirent) {
  811. TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
  812. if (!si.Allocate())
  813. return false;
  814. my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
  815. dirent->stream_type = MD_SYSTEM_INFO_STREAM;
  816. dirent->location = si.location();
  817. WriteCPUInformation(si.get());
  818. WriteOSInformation(si.get());
  819. return true;
  820. }
  821. bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
  822. uint32_t dynamic_length) {
  823. #if defined(__ANDROID__)
  824. return false;
  825. #else
  826. // The caller provided us with a pointer to "struct r_debug". We can
  827. // look up the "r_map" field to get a linked list of all loaded DSOs.
  828. // Our list of DSOs potentially is different from the ones in the crashing
  829. // process. So, we have to be careful to never dereference pointers
  830. // directly. Instead, we use CopyFromProcess() everywhere.
  831. // See <link.h> for a more detailed discussion of the how the dynamic
  832. // loader communicates with debuggers.
  833. // Count the number of loaded DSOs
  834. int dso_count = 0;
  835. struct r_debug debug_entry;
  836. dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
  837. sizeof(debug_entry));
  838. for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
  839. struct link_map map;
  840. dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
  841. ptr = map.l_next;
  842. dso_count++;
  843. }
  844. MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
  845. if (dso_count > 0) {
  846. // If we have at least one DSO, create an array of MDRawLinkMap
  847. // entries in the minidump file.
  848. TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
  849. if (!linkmap.AllocateArray(dso_count))
  850. return false;
  851. linkmap_rva = linkmap.location().rva;
  852. int idx = 0;
  853. // Iterate over DSOs and write their information to mini dump
  854. for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
  855. struct link_map map;
  856. dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
  857. ptr = map.l_next;
  858. char filename[257] = { 0 };
  859. if (map.l_name) {
  860. dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
  861. sizeof(filename) - 1);
  862. }
  863. MDLocationDescriptor location;
  864. if (!minidump_writer_.WriteString(filename, 0, &location))
  865. return false;
  866. MDRawLinkMap entry;
  867. entry.name = location.rva;
  868. entry.addr = (void*)map.l_addr;
  869. entry.ld = (void*)map.l_ld;
  870. linkmap.CopyIndex(idx++, &entry);
  871. }
  872. }
  873. // Write MD_LINUX_DSO_DEBUG record
  874. TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
  875. if (!debug.AllocateObjectAndArray(1, dynamic_length))
  876. return false;
  877. my_memset(debug.get(), 0, sizeof(MDRawDebug));
  878. dirent->stream_type = MD_LINUX_DSO_DEBUG;
  879. dirent->location = debug.location();
  880. debug.get()->version = debug_entry.r_version;
  881. debug.get()->map = linkmap_rva;
  882. debug.get()->dso_count = dso_count;
  883. debug.get()->brk = (void*)debug_entry.r_brk;
  884. debug.get()->ldbase = (void*)debug_entry.r_ldbase;
  885. debug.get()->dynamic = (void*)&_DYNAMIC;
  886. char *dso_debug_data = new char[dynamic_length];
  887. dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), &_DYNAMIC,
  888. dynamic_length);
  889. debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
  890. delete[] dso_debug_data;
  891. return true;
  892. #endif
  893. }
  894. private:
  895. void* Alloc(unsigned bytes) {
  896. return dumper_->allocator()->Alloc(bytes);
  897. }
  898. pid_t GetCrashThread() const {
  899. return dumper_->crash_thread();
  900. }
  901. #if defined(__i386)
  902. uintptr_t GetStackPointer() {
  903. return ucontext_->uc_mcontext.gregs[REG_ESP];
  904. }
  905. uintptr_t GetInstructionPointer() {
  906. return ucontext_->uc_mcontext.gregs[REG_EIP];
  907. }
  908. #elif defined(__x86_64)
  909. uintptr_t GetStackPointer() {
  910. return ucontext_->uc_mcontext.gregs[REG_RSP];
  911. }
  912. uintptr_t GetInstructionPointer() {
  913. return ucontext_->uc_mcontext.gregs[REG_RIP];
  914. }
  915. #elif defined(__ARM_EABI__)
  916. uintptr_t GetStackPointer() {
  917. return ucontext_->uc_mcontext.arm_sp;
  918. }
  919. uintptr_t GetInstructionPointer() {
  920. return ucontext_->uc_mcontext.arm_ip;
  921. }
  922. #else
  923. #error "This code has not been ported to your platform yet."
  924. #endif
  925. void NullifyDirectoryEntry(MDRawDirectory* dirent) {
  926. dirent->stream_type = 0;
  927. dirent->location.data_size = 0;
  928. dirent->location.rva = 0;
  929. }
  930. bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
  931. char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
  932. static const char vendor_id_name[] = "vendor_id";
  933. static const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
  934. struct CpuInfoEntry {
  935. const char* info_name;
  936. int value;
  937. bool found;
  938. } cpu_info_table[] = {
  939. { "processor", -1, false },
  940. { "model", 0, false },
  941. { "stepping", 0, false },
  942. { "cpu family", 0, false },
  943. };
  944. // processor_architecture should always be set, do this first
  945. sys_info->processor_architecture =
  946. #if defined(__i386)
  947. MD_CPU_ARCHITECTURE_X86;
  948. #elif defined(__x86_64)
  949. MD_CPU_ARCHITECTURE_AMD64;
  950. #elif defined(__arm__)
  951. MD_CPU_ARCHITECTURE_ARM;
  952. #else
  953. #error "Unknown CPU arch"
  954. #endif
  955. const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
  956. if (fd < 0)
  957. return false;
  958. {
  959. PageAllocator allocator;
  960. LineReader* const line_reader = new(allocator) LineReader(fd);
  961. const char* line;
  962. unsigned line_len;
  963. while (line_reader->GetNextLine(&line, &line_len)) {
  964. for (size_t i = 0;
  965. i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
  966. i++) {
  967. CpuInfoEntry* entry = &cpu_info_table[i];
  968. if (entry->found && i)
  969. continue;
  970. if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
  971. const char* value = strchr(line, ':');
  972. if (!value)
  973. continue;
  974. // the above strncmp only matches the prefix, it might be the wrong
  975. // line. i.e. we matched "model name" instead of "model".
  976. // check and make sure there is only spaces between the prefix and
  977. // the colon.
  978. const char* space_ptr = line + strlen(entry->info_name);
  979. for (; space_ptr < value; space_ptr++) {
  980. if (!isspace(*space_ptr)) {
  981. break;
  982. }
  983. }
  984. if (space_ptr != value)
  985. continue;
  986. sscanf(++value, " %d", &(entry->value));
  987. entry->found = true;
  988. }
  989. }
  990. // special case for vendor_id
  991. if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
  992. const char* value = strchr(line, ':');
  993. if (!value)
  994. goto popline;
  995. // skip ':" and all the spaces that follows
  996. do {
  997. value++;
  998. } while (isspace(*value));
  999. if (*value) {
  1000. size_t length = strlen(value);
  1001. if (length == 0)
  1002. goto popline;
  1003. // we don't want the trailing newline
  1004. if (value[length - 1] == '\n')
  1005. length--;
  1006. // ensure we have space for the value
  1007. if (length < sizeof(vendor_id))
  1008. strncpy(vendor_id, value, length);
  1009. }
  1010. }
  1011. popline:
  1012. line_reader->PopLine(line_len);
  1013. }
  1014. sys_close(fd);
  1015. }
  1016. // make sure we got everything we wanted
  1017. for (size_t i = 0;
  1018. i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
  1019. i++) {
  1020. if (!cpu_info_table[i].found) {
  1021. return false;
  1022. }
  1023. }
  1024. // /proc/cpuinfo contains cpu id, change it into number by adding one.
  1025. cpu_info_table[0].value++;
  1026. sys_info->number_of_processors = cpu_info_table[0].value;
  1027. sys_info->processor_level = cpu_info_table[3].value;
  1028. sys_info->processor_revision = cpu_info_table[1].value << 8 |
  1029. cpu_info_table[2].value;
  1030. if (vendor_id[0] != '\0') {
  1031. memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
  1032. sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
  1033. }
  1034. return true;
  1035. }
  1036. bool WriteFile(MDLocationDescriptor* result, const char* filename) {
  1037. const int fd = sys_open(filename, O_RDONLY, 0);
  1038. if (fd < 0)
  1039. return false;
  1040. // We can't stat the files because several of the files that we want to
  1041. // read are kernel seqfiles, which always have a length of zero. So we have
  1042. // to read as much as we can into a buffer.
  1043. static const unsigned kBufSize = 1024 - 2*sizeof(void*);
  1044. struct Buffers {
  1045. Buffers* next;
  1046. size_t len;
  1047. uint8_t data[kBufSize];
  1048. } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
  1049. buffers->next = NULL;
  1050. buffers->len = 0;
  1051. size_t total = 0;
  1052. for (Buffers* bufptr = buffers;;) {
  1053. ssize_t r;
  1054. do {
  1055. r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
  1056. } while (r == -1 && errno == EINTR);
  1057. if (r < 1)
  1058. break;
  1059. total += r;
  1060. bufptr->len += r;
  1061. if (bufptr->len == kBufSize) {
  1062. bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
  1063. bufptr = bufptr->next;
  1064. bufptr->next = NULL;
  1065. bufptr->len = 0;
  1066. }
  1067. }
  1068. sys_close(fd);
  1069. if (!total)
  1070. return false;
  1071. UntypedMDRVA memory(&minidump_writer_);
  1072. if (!memory.Allocate(total))
  1073. return false;
  1074. for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
  1075. // Check for special case of a zero-length buffer. This should only
  1076. // occur if a file's size happens to be a multiple of the buffer's
  1077. // size, in which case the final sys_read() will have resulted in
  1078. // zero bytes being read after the final buffer was just allocated.
  1079. if (buffers->len == 0) {
  1080. // This can only occur with final buffer.
  1081. assert(buffers->next == NULL);
  1082. continue;
  1083. }
  1084. memory.Copy(pos, &buffers->data, buffers->len);
  1085. pos += buffers->len;
  1086. }
  1087. *result = memory.location();
  1088. return true;
  1089. }
  1090. bool WriteOSInformation(MDRawSystemInfo* sys_info) {
  1091. sys_info->platform_id = MD_OS_LINUX;
  1092. struct utsname uts;
  1093. if (uname(&uts))
  1094. return false;
  1095. static const size_t buf_len = 512;
  1096. char buf[buf_len] = {0};
  1097. size_t space_left = buf_len - 1;
  1098. const char* info_table[] = {
  1099. uts.sysname,
  1100. uts.release,
  1101. uts.version,
  1102. uts.machine,
  1103. NULL
  1104. };
  1105. bool first_item = true;
  1106. for (const char** cur_info = info_table; *cur_info; cur_info++) {
  1107. static const char* separator = " ";
  1108. size_t separator_len = strlen(separator);
  1109. size_t info_len = strlen(*cur_info);
  1110. if (info_len == 0)
  1111. continue;
  1112. if (space_left < info_len + (first_item ? 0 : separator_len))
  1113. break;
  1114. if (!first_item) {
  1115. strcat(buf, separator);
  1116. space_left -= separator_len;
  1117. }
  1118. first_item = false;
  1119. strcat(buf, *cur_info);
  1120. space_left -= info_len;
  1121. }
  1122. MDLocationDescriptor location;
  1123. if (!minidump_writer_.WriteString(buf, 0, &location))
  1124. return false;
  1125. sys_info->csd_version_rva = location.rva;
  1126. return true;
  1127. }
  1128. bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
  1129. const char* filename) {
  1130. char buf[NAME_MAX];
  1131. if (!dumper_->BuildProcPath(buf, pid, filename))
  1132. return false;
  1133. return WriteFile(result, buf);
  1134. }
  1135. const char* const filename_; // output filename
  1136. const struct ucontext* const ucontext_; // also from the signal handler
  1137. const struct _libc_fpstate* const float_state_; // ditto
  1138. LinuxDumper* dumper_;
  1139. MinidumpFileWriter minidump_writer_;
  1140. MDLocationDescriptor crashing_thread_context_;
  1141. // Blocks of memory written to the dump. These are all currently
  1142. // written while writing the thread list stream, but saved here
  1143. // so a memory list stream can be written afterwards.
  1144. wasteful_vector<MDMemoryDescriptor> memory_blocks_;
  1145. // Additional information about some mappings provided by the caller.
  1146. const MappingList& mapping_list_;
  1147. };
  1148. bool WriteMinidump(const char* filename, pid_t crashing_process,
  1149. const void* blob, size_t blob_size) {
  1150. MappingList m;
  1151. return WriteMinidump(filename, crashing_process, blob, blob_size, m);
  1152. }
  1153. bool WriteMinidump(const char* filename, pid_t crashing_process,
  1154. const void* blob, size_t blob_size,
  1155. const MappingList& mappings) {
  1156. if (blob_size != sizeof(ExceptionHandler::CrashContext))
  1157. return false;
  1158. const ExceptionHandler::CrashContext* context =
  1159. reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
  1160. LinuxPtraceDumper dumper(crashing_process);
  1161. dumper.set_crash_address(
  1162. reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
  1163. dumper.set_crash_signal(context->siginfo.si_signo);
  1164. dumper.set_crash_thread(context->tid);
  1165. MinidumpWriter writer(filename, context, mappings, &dumper);
  1166. if (!writer.Init())
  1167. return false;
  1168. return writer.Dump();
  1169. }
  1170. bool WriteMinidump(const char* filename,
  1171. const MappingList& mappings,
  1172. LinuxDumper* dumper) {
  1173. MinidumpWriter writer(filename, NULL, mappings, dumper);
  1174. if (!writer.Init())
  1175. return false;
  1176. return writer.Dump();
  1177. }
  1178. } // namespace google_breakpad