/thirdparty/breakpad/processor/synth_minidump.cc

http://github.com/tomahawk-player/tomahawk · C++ · 349 lines · 270 code · 32 blank · 47 comment · 20 complexity · 21dcf30cd9ee9517136d202a3406055b 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. // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
  30. // synth_minidump.cc: Implementation of SynthMinidump. See synth_minidump.h
  31. #include "processor/synth_minidump.h"
  32. namespace google_breakpad {
  33. namespace SynthMinidump {
  34. Section::Section(const Dump &dump)
  35. : test_assembler::Section(dump.endianness()) { }
  36. void Section::CiteLocationIn(test_assembler::Section *section) const {
  37. if (this)
  38. (*section).D32(size_).D32(file_offset_);
  39. else
  40. (*section).D32(0).D32(0);
  41. }
  42. void Stream::CiteStreamIn(test_assembler::Section *section) const {
  43. section->D32(type_);
  44. CiteLocationIn(section);
  45. }
  46. SystemInfo::SystemInfo(const Dump &dump,
  47. const MDRawSystemInfo &system_info,
  48. const String &csd_version)
  49. : Stream(dump, MD_SYSTEM_INFO_STREAM) {
  50. D16(system_info.processor_architecture);
  51. D16(system_info.processor_level);
  52. D16(system_info.processor_revision);
  53. D8(system_info.number_of_processors);
  54. D8(system_info.product_type);
  55. D32(system_info.major_version);
  56. D32(system_info.minor_version);
  57. D32(system_info.build_number);
  58. D32(system_info.platform_id);
  59. csd_version.CiteStringIn(this);
  60. D16(system_info.suite_mask);
  61. D16(system_info.reserved2); // Well, why not?
  62. // MDCPUInformation cpu;
  63. if (system_info.processor_architecture == MD_CPU_ARCHITECTURE_X86) {
  64. D32(system_info.cpu.x86_cpu_info.vendor_id[0]);
  65. D32(system_info.cpu.x86_cpu_info.vendor_id[1]);
  66. D32(system_info.cpu.x86_cpu_info.vendor_id[2]);
  67. D32(system_info.cpu.x86_cpu_info.version_information);
  68. D32(system_info.cpu.x86_cpu_info.feature_information);
  69. D32(system_info.cpu.x86_cpu_info.amd_extended_cpu_features);
  70. } else {
  71. D64(system_info.cpu.other_cpu_info.processor_features[0]);
  72. D64(system_info.cpu.other_cpu_info.processor_features[1]);
  73. }
  74. }
  75. const MDRawSystemInfo SystemInfo::windows_x86 = {
  76. MD_CPU_ARCHITECTURE_X86, // processor_architecture
  77. 6, // processor_level
  78. 0xd08, // processor_revision
  79. 1, // number_of_processors
  80. 1, // product_type
  81. 5, // major_version
  82. 1, // minor_version
  83. 2600, // build_number
  84. 2, // platform_id
  85. 0xdeadbeef, // csd_version_rva
  86. 0x100, // suite_mask
  87. 0, // reserved2
  88. { // cpu
  89. { // x86_cpu_info
  90. { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id
  91. 0x6d8, // version_information
  92. 0xafe9fbff, // feature_information
  93. 0xffffffff // amd_extended_cpu_features
  94. }
  95. }
  96. };
  97. const string SystemInfo::windows_x86_csd_version = "Service Pack 2";
  98. String::String(const Dump &dump, const string &contents) : Section(dump) {
  99. D32(contents.size() * 2);
  100. for (string::const_iterator i = contents.begin(); i != contents.end(); i++)
  101. D16(*i);
  102. }
  103. void String::CiteStringIn(test_assembler::Section *section) const {
  104. section->D32(file_offset_);
  105. }
  106. void Memory::CiteMemoryIn(test_assembler::Section *section) const {
  107. section->D64(address_);
  108. CiteLocationIn(section);
  109. }
  110. Context::Context(const Dump &dump, const MDRawContextX86 &context)
  111. : Section(dump) {
  112. // The caller should have properly set the CPU type flag.
  113. assert(context.context_flags & MD_CONTEXT_X86);
  114. // It doesn't make sense to store x86 registers in big-endian form.
  115. assert(dump.endianness() == kLittleEndian);
  116. D32(context.context_flags);
  117. D32(context.dr0);
  118. D32(context.dr1);
  119. D32(context.dr2);
  120. D32(context.dr3);
  121. D32(context.dr6);
  122. D32(context.dr7);
  123. D32(context.float_save.control_word);
  124. D32(context.float_save.status_word);
  125. D32(context.float_save.tag_word);
  126. D32(context.float_save.error_offset);
  127. D32(context.float_save.error_selector);
  128. D32(context.float_save.data_offset);
  129. D32(context.float_save.data_selector);
  130. // context.float_save.register_area[] contains 8-bit quantities and
  131. // does not need to be swapped.
  132. Append(context.float_save.register_area,
  133. sizeof(context.float_save.register_area));
  134. D32(context.float_save.cr0_npx_state);
  135. D32(context.gs);
  136. D32(context.fs);
  137. D32(context.es);
  138. D32(context.ds);
  139. D32(context.edi);
  140. D32(context.esi);
  141. D32(context.ebx);
  142. D32(context.edx);
  143. D32(context.ecx);
  144. D32(context.eax);
  145. D32(context.ebp);
  146. D32(context.eip);
  147. D32(context.cs);
  148. D32(context.eflags);
  149. D32(context.esp);
  150. D32(context.ss);
  151. // context.extended_registers[] contains 8-bit quantities and does
  152. // not need to be swapped.
  153. Append(context.extended_registers, sizeof(context.extended_registers));
  154. assert(Size() == sizeof(MDRawContextX86));
  155. }
  156. Context::Context(const Dump &dump, const MDRawContextARM &context)
  157. : Section(dump) {
  158. // The caller should have properly set the CPU type flag.
  159. assert((context.context_flags & MD_CONTEXT_ARM) ||
  160. (context.context_flags & MD_CONTEXT_ARM_OLD));
  161. // It doesn't make sense to store ARM registers in big-endian form.
  162. assert(dump.endianness() == kLittleEndian);
  163. D32(context.context_flags);
  164. for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
  165. D32(context.iregs[i]);
  166. D32(context.cpsr);
  167. D64(context.float_save.fpscr);
  168. for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; ++i)
  169. D64(context.float_save.regs[i]);
  170. for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; ++i)
  171. D32(context.float_save.extra[i]);
  172. assert(Size() == sizeof(MDRawContextARM));
  173. }
  174. Thread::Thread(const Dump &dump,
  175. u_int32_t thread_id, const Memory &stack, const Context &context,
  176. u_int32_t suspend_count, u_int32_t priority_class,
  177. u_int32_t priority, u_int64_t teb) : Section(dump) {
  178. D32(thread_id);
  179. D32(suspend_count);
  180. D32(priority_class);
  181. D32(priority);
  182. D64(teb);
  183. stack.CiteMemoryIn(this);
  184. context.CiteLocationIn(this);
  185. assert(Size() == sizeof(MDRawThread));
  186. }
  187. Module::Module(const Dump &dump,
  188. u_int64_t base_of_image,
  189. u_int32_t size_of_image,
  190. const String &name,
  191. u_int32_t time_date_stamp,
  192. u_int32_t checksum,
  193. const MDVSFixedFileInfo &version_info,
  194. const Section *cv_record,
  195. const Section *misc_record) : Section(dump) {
  196. D64(base_of_image);
  197. D32(size_of_image);
  198. D32(checksum);
  199. D32(time_date_stamp);
  200. name.CiteStringIn(this);
  201. D32(version_info.signature);
  202. D32(version_info.struct_version);
  203. D32(version_info.file_version_hi);
  204. D32(version_info.file_version_lo);
  205. D32(version_info.product_version_hi);
  206. D32(version_info.product_version_lo);
  207. D32(version_info.file_flags_mask);
  208. D32(version_info.file_flags);
  209. D32(version_info.file_os);
  210. D32(version_info.file_type);
  211. D32(version_info.file_subtype);
  212. D32(version_info.file_date_hi);
  213. D32(version_info.file_date_lo);
  214. cv_record->CiteLocationIn(this);
  215. misc_record->CiteLocationIn(this);
  216. D64(0).D64(0);
  217. }
  218. const MDVSFixedFileInfo Module::stock_version_info = {
  219. MD_VSFIXEDFILEINFO_SIGNATURE, // signature
  220. MD_VSFIXEDFILEINFO_VERSION, // struct_version
  221. 0x11111111, // file_version_hi
  222. 0x22222222, // file_version_lo
  223. 0x33333333, // product_version_hi
  224. 0x44444444, // product_version_lo
  225. MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags_mask
  226. MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags
  227. MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32,
  228. // file_os
  229. MD_VSFIXEDFILEINFO_FILE_TYPE_APP, // file_type
  230. MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype
  231. 0, // file_date_hi
  232. 0 // file_date_lo
  233. };
  234. Exception::Exception(const Dump &dump,
  235. const Context &context,
  236. u_int32_t thread_id,
  237. u_int32_t exception_code,
  238. u_int32_t exception_flags,
  239. u_int64_t exception_address)
  240. : Stream(dump, MD_EXCEPTION_STREAM) {
  241. D32(thread_id);
  242. D32(0); // __align
  243. D32(exception_code);
  244. D32(exception_flags);
  245. D64(0); // exception_record
  246. D64(exception_address);
  247. D32(0); // number_parameters
  248. D32(0); // __align
  249. for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
  250. D64(0); // exception_information
  251. context.CiteLocationIn(this);
  252. assert(Size() == sizeof(MDRawExceptionStream));
  253. }
  254. Dump::Dump(u_int64_t flags,
  255. Endianness endianness,
  256. u_int32_t version,
  257. u_int32_t date_time_stamp)
  258. : test_assembler::Section(endianness),
  259. file_start_(0),
  260. stream_directory_(*this),
  261. stream_count_(0),
  262. thread_list_(*this, MD_THREAD_LIST_STREAM),
  263. module_list_(*this, MD_MODULE_LIST_STREAM),
  264. memory_list_(*this, MD_MEMORY_LIST_STREAM)
  265. {
  266. D32(MD_HEADER_SIGNATURE);
  267. D32(version);
  268. D32(stream_count_label_);
  269. D32(stream_directory_rva_);
  270. D32(0);
  271. D32(date_time_stamp);
  272. D64(flags);
  273. assert(Size() == sizeof(MDRawHeader));
  274. }
  275. Dump &Dump::Add(SynthMinidump::Section *section) {
  276. section->Finish(file_start_ + Size());
  277. Append(*section);
  278. return *this;
  279. }
  280. Dump &Dump::Add(Stream *stream) {
  281. Add(static_cast<SynthMinidump::Section *>(stream));
  282. stream->CiteStreamIn(&stream_directory_);
  283. stream_count_++;
  284. return *this;
  285. }
  286. Dump &Dump::Add(Memory *memory) {
  287. // Add the memory contents themselves to the file.
  288. Add(static_cast<SynthMinidump::Section *>(memory));
  289. // The memory list is a list of MDMemoryDescriptors, not of actual
  290. // memory elements. Produce a descriptor, and add that to the list.
  291. SynthMinidump::Section descriptor(*this);
  292. memory->CiteMemoryIn(&descriptor);
  293. memory_list_.Add(&descriptor);
  294. return *this;
  295. }
  296. Dump &Dump::Add(Thread *thread) {
  297. thread_list_.Add(thread);
  298. return *this;
  299. }
  300. Dump &Dump::Add(Module *module) {
  301. module_list_.Add(module);
  302. return *this;
  303. }
  304. void Dump::Finish() {
  305. if (!thread_list_.Empty()) Add(&thread_list_);
  306. if (!module_list_.Empty()) Add(&module_list_);
  307. if (!memory_list_.Empty()) Add(&memory_list_);
  308. // Create the stream directory. We don't use
  309. // stream_directory_.Finish here, because the stream directory isn't
  310. // cited using a location descriptor; rather, the Minidump header
  311. // has the stream count and MDRVA.
  312. stream_count_label_ = stream_count_;
  313. stream_directory_rva_ = file_start_ + Size();
  314. Append(static_cast<test_assembler::Section &>(stream_directory_));
  315. }
  316. } // namespace SynthMinidump
  317. } // namespace google_breakpad