diff options
author | jbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-09 17:53:01 +0000 |
---|---|---|
committer | jbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-09 17:53:01 +0000 |
commit | 317e270b12e2a325127293d1c8e4797ed5fdfd64 (patch) | |
tree | 85ae0fe3452f32af30ababfbba1fb42b694df133 /chrome/app | |
parent | 6d6afe837ea1230508731c530fb47c262b8aaecb (diff) | |
download | chromium_src-317e270b12e2a325127293d1c8e4797ed5fdfd64.zip chromium_src-317e270b12e2a325127293d1c8e4797ed5fdfd64.tar.gz chromium_src-317e270b12e2a325127293d1c8e4797ed5fdfd64.tar.bz2 |
linux crash dump now includes gpu data
BUG=71852
TEST=
Review URL: http://codereview.chromium.org/6580055
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77483 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/app')
-rw-r--r-- | chrome/app/breakpad_linux.cc | 435 |
1 files changed, 221 insertions, 214 deletions
diff --git a/chrome/app/breakpad_linux.cc b/chrome/app/breakpad_linux.cc index 9a470dc..1f8905a 100644 --- a/chrome/app/breakpad_linux.cc +++ b/chrome/app/breakpad_linux.cc @@ -99,12 +99,174 @@ static unsigned my_uint64_len(uint64_t i) { // uint64_t version of my_itos() from // breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative -// integer to a string. +// integer to a string (not null-terminated). static void my_uint64tos(char* output, uint64_t i, unsigned i_len) { for (unsigned index = i_len; index; --index, i /= 10) output[index - 1] = '0' + (i % 10); } +namespace { + +// MIME substrings. +static const char g_rn[] = "\r\n"; +static const char g_form_data_msg[] = "Content-Disposition: form-data; name=\""; +static const char g_quote_msg[] = "\""; +static const char g_dashdash_msg[] = "--"; +static const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; +static const char g_content_type_msg[] = + "Content-Type: application/octet-stream"; + +// MimeWriter manages an iovec for writing MIMEs to a file. +class MimeWriter { + public: + static const int kIovCapacity = 30; + static const size_t kMaxCrashChunkSize = 64; + + MimeWriter(int fd, const char* const mime_boundary); + ~MimeWriter(); + + // Append boundary. + void AddBoundary(); + + // Append end of file boundary. + void AddEnd(); + + // Append key/value pair with specified sizes. + void AddPairData(const char* msg_type, + size_t msg_type_size, + const char* msg_data, + size_t msg_data_size); + + // Append key/value pair. + void AddPairString(const char* msg_type, + const char* msg_data) { + AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data)); + } + + // Append key/value pair, splitting value into chunks no larger than + // kMaxCrashChunkSize. The msg_type string will have a counter suffix to + // distinguish each chunk. + void AddPairDataInChunks(const char* msg_type, + size_t msg_type_size, + const char* msg_data, + size_t msg_data_size); + + // Add binary file dump. Currently this is only done once, so the name is + // fixed. + void AddFileDump(uint8_t* file_data, + size_t file_size); + + // Flush any pending iovecs to the output file. + void Flush() { + IGNORE_RET(sys_writev(fd_, iov_, iov_index_)); + iov_index_ = 0; + } + + private: + DISALLOW_COPY_AND_ASSIGN(MimeWriter); + + void AddItem(const void* base, size_t size); + // Minor performance trade-off for easier-to-maintain code. + void AddString(const char* str) { + AddItem(str, my_strlen(str)); + } + + struct kernel_iovec iov_[kIovCapacity]; + int iov_index_; + + // Output file descriptor. + int fd_; + + const char* const mime_boundary_; +}; + +MimeWriter::MimeWriter(int fd, const char* const mime_boundary) + : iov_index_(0), + fd_(fd), + mime_boundary_(mime_boundary) { +} + +MimeWriter::~MimeWriter() { +} + +void MimeWriter::AddBoundary() { + AddString(mime_boundary_); + AddString(g_rn); +} + +void MimeWriter::AddEnd() { + AddString(mime_boundary_); + AddString(g_dashdash_msg); + AddString(g_rn); +} + +void MimeWriter::AddPairData(const char* msg_type, + size_t msg_type_size, + const char* msg_data, + size_t msg_data_size) { + AddString(g_form_data_msg); + AddItem(msg_type, msg_type_size); + AddString(g_quote_msg); + AddString(g_rn); + AddString(g_rn); + AddItem(msg_data, msg_data_size); + AddString(g_rn); +} + +void MimeWriter::AddPairDataInChunks(const char* msg_type, + size_t msg_type_size, + const char* msg_data, + size_t msg_data_size) { + unsigned i = 0; + size_t done = 0, msg_length = msg_data_size; + + while (msg_length) { + char num[16]; + const unsigned num_len = my_int_len(++i); + my_itos(num, i, num_len); + + size_t chunk_len = std::min((size_t)kMaxCrashChunkSize, msg_length); + + AddString(g_form_data_msg); + AddItem(msg_type, msg_type_size); + AddItem(num, num_len); + AddString(g_quote_msg); + AddString(g_rn); + AddString(g_rn); + AddItem(msg_data + done, chunk_len); + AddString(g_rn); + AddBoundary(); + Flush(); + + done += chunk_len; + msg_length -= chunk_len; + } +} + +void MimeWriter::AddFileDump(uint8_t* file_data, + size_t file_size) { + AddString(g_form_data_msg); + AddString(g_dump_msg); + AddString(g_rn); + AddString(g_content_type_msg); + AddString(g_rn); + AddString(g_rn); + AddItem(file_data, file_size); + AddString(g_rn); +} + +void MimeWriter::AddItem(const void* base, size_t size) { + // Check if the iovec is full and needs to be flushed to output file. + if (iov_index_ == kIovCapacity) { + Flush(); + } + iov_[iov_index_].iov_base = const_cast<void*>(base); + iov_[iov_index_].iov_len = size; + ++iov_index_; +} + +} // namespace + pid_t HandleCrashDump(const BreakpadInfo& info) { // WARNING: this code runs in a compromised context. It may not call into // libc nor allocate memory normally. @@ -190,8 +352,6 @@ pid_t HandleCrashDump(const BreakpadInfo& info) { mime_boundary[28 + 16] = 0; IGNORE_RET(sys_close(ufd)); - static const char version_msg[] = PRODUCT_VERSION; - // The MIME block looks like this: // BOUNDARY \r\n (0, 1) // Content-Disposition: form-data; name="prod" \r\n \r\n (2..6) @@ -219,6 +379,11 @@ pid_t HandleCrashDump(const BreakpadInfo& info) { // abcdef \r\n (5, 6) // BOUNDARY \r\n (7, 8) // + // zero or more gpu entries: + // Content-Disposition: form-data; name="gpu-xxxxx" \r\n \r\n (0..4) + // <gpu-xxxxx> \r\n (5, 6) + // BOUNDARY \r\n (7, 8) + // // zero or more: // Content-Disposition: form-data; name="url-chunk-1" \r\n \r\n (0..5) // abcdef \r\n (6, 7) @@ -229,96 +394,30 @@ pid_t HandleCrashDump(const BreakpadInfo& info) { // <dump contents> (6) // \r\n BOUNDARY -- \r\n (7,8,9,10) - static const char rn[] = {'\r', '\n'}; - static const char form_data_msg[] = "Content-Disposition: form-data; name=\""; - static const char prod_msg[] = "prod"; - static const char quote_msg[] = {'"'}; -#if defined(OS_CHROMEOS) + #if defined(OS_CHROMEOS) static const char chrome_product_msg[] = "Chrome_ChromeOS"; -#else // OS_LINUX + #else // OS_LINUX static const char chrome_product_msg[] = "Chrome_Linux"; -#endif + #endif + static const char version_msg[] = PRODUCT_VERSION; + static const char prod_msg[] = "prod"; static const char ver_msg[] = "ver"; static const char guid_msg[] = "guid"; - static const char dashdash_msg[] = {'-', '-'}; - static const char dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; - static const char content_type_msg[] = - "Content-Type: application/octet-stream"; static const char url_chunk_msg[] = "url-chunk-"; static const char process_time_msg[] = "ptime"; static const char process_type_msg[] = "ptype"; static const char distro_msg[] = "lsb-release"; - struct kernel_iovec iov[29]; - iov[0].iov_base = mime_boundary; - iov[0].iov_len = sizeof(mime_boundary) - 1; - iov[1].iov_base = const_cast<char*>(rn); - iov[1].iov_len = sizeof(rn); - - iov[2].iov_base = const_cast<char*>(form_data_msg); - iov[2].iov_len = sizeof(form_data_msg) - 1; - iov[3].iov_base = const_cast<char*>(prod_msg); - iov[3].iov_len = sizeof(prod_msg) - 1; - iov[4].iov_base = const_cast<char*>(quote_msg); - iov[4].iov_len = sizeof(quote_msg); - iov[5].iov_base = const_cast<char*>(rn); - iov[5].iov_len = sizeof(rn); - iov[6].iov_base = const_cast<char*>(rn); - iov[6].iov_len = sizeof(rn); - - iov[7].iov_base = const_cast<char*>(chrome_product_msg); - iov[7].iov_len = sizeof(chrome_product_msg) - 1; - iov[8].iov_base = const_cast<char*>(rn); - iov[8].iov_len = sizeof(rn); - - iov[9].iov_base = mime_boundary; - iov[9].iov_len = sizeof(mime_boundary) - 1; - iov[10].iov_base = const_cast<char*>(rn); - iov[10].iov_len = sizeof(rn); - - iov[11].iov_base = const_cast<char*>(form_data_msg); - iov[11].iov_len = sizeof(form_data_msg) - 1; - iov[12].iov_base = const_cast<char*>(ver_msg); - iov[12].iov_len = sizeof(ver_msg) - 1; - iov[13].iov_base = const_cast<char*>(quote_msg); - iov[13].iov_len = sizeof(quote_msg); - iov[14].iov_base = const_cast<char*>(rn); - iov[14].iov_len = sizeof(rn); - iov[15].iov_base = const_cast<char*>(rn); - iov[15].iov_len = sizeof(rn); - - iov[16].iov_base = const_cast<char*>(version_msg); - iov[16].iov_len = sizeof(version_msg) - 1; - iov[17].iov_base = const_cast<char*>(rn); - iov[17].iov_len = sizeof(rn); - - iov[18].iov_base = mime_boundary; - iov[18].iov_len = sizeof(mime_boundary) - 1; - iov[19].iov_base = const_cast<char*>(rn); - iov[19].iov_len = sizeof(rn); - - iov[20].iov_base = const_cast<char*>(form_data_msg); - iov[20].iov_len = sizeof(form_data_msg) - 1; - iov[21].iov_base = const_cast<char*>(guid_msg); - iov[21].iov_len = sizeof(guid_msg) - 1; - iov[22].iov_base = const_cast<char*>(quote_msg); - iov[22].iov_len = sizeof(quote_msg); - iov[23].iov_base = const_cast<char*>(rn); - iov[23].iov_len = sizeof(rn); - iov[24].iov_base = const_cast<char*>(rn); - iov[24].iov_len = sizeof(rn); - - iov[25].iov_base = const_cast<char*>(info.guid); - iov[25].iov_len = info.guid_length; - iov[26].iov_base = const_cast<char*>(rn); - iov[26].iov_len = sizeof(rn); - - iov[27].iov_base = mime_boundary; - iov[27].iov_len = sizeof(mime_boundary) - 1; - iov[28].iov_base = const_cast<char*>(rn); - iov[28].iov_len = sizeof(rn); - - IGNORE_RET(sys_writev(fd, iov, 29)); + MimeWriter writer(fd, mime_boundary); + + writer.AddBoundary(); + writer.AddPairString(prod_msg, chrome_product_msg); + writer.AddBoundary(); + writer.AddPairString(ver_msg, version_msg); + writer.AddBoundary(); + writer.AddPairString(guid_msg, info.guid); + writer.AddBoundary(); + writer.Flush(); if (info.process_start_time > 0) { struct kernel_timeval tv; @@ -330,150 +429,58 @@ pid_t HandleCrashDump(const BreakpadInfo& info) { const unsigned time_len = my_uint64_len(time); my_uint64tos(time_str, time, time_len); - iov[0].iov_base = const_cast<char*>(form_data_msg); - iov[0].iov_len = sizeof(form_data_msg) - 1; - iov[1].iov_base = const_cast<char*>(process_time_msg); - iov[1].iov_len = sizeof(process_time_msg) - 1; - iov[2].iov_base = const_cast<char*>(quote_msg); - iov[2].iov_len = sizeof(quote_msg); - iov[3].iov_base = const_cast<char*>(rn); - iov[3].iov_len = sizeof(rn); - iov[4].iov_base = const_cast<char*>(rn); - iov[4].iov_len = sizeof(rn); - - iov[5].iov_base = const_cast<char*>(time_str); - iov[5].iov_len = time_len; - iov[6].iov_base = const_cast<char*>(rn); - iov[6].iov_len = sizeof(rn); - iov[7].iov_base = mime_boundary; - iov[7].iov_len = sizeof(mime_boundary) - 1; - iov[8].iov_base = const_cast<char*>(rn); - iov[8].iov_len = sizeof(rn); - - IGNORE_RET(sys_writev(fd, iov, 9)); + writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1, + time_str, time_len); + writer.AddBoundary(); + writer.Flush(); } } } if (info.process_type_length) { - iov[0].iov_base = const_cast<char*>(form_data_msg); - iov[0].iov_len = sizeof(form_data_msg) - 1; - iov[1].iov_base = const_cast<char*>(process_type_msg); - iov[1].iov_len = sizeof(process_type_msg) - 1; - iov[2].iov_base = const_cast<char*>(quote_msg); - iov[2].iov_len = sizeof(quote_msg); - iov[3].iov_base = const_cast<char*>(rn); - iov[3].iov_len = sizeof(rn); - iov[4].iov_base = const_cast<char*>(rn); - iov[4].iov_len = sizeof(rn); - - iov[5].iov_base = const_cast<char*>(info.process_type); - iov[5].iov_len = info.process_type_length; - iov[6].iov_base = const_cast<char*>(rn); - iov[6].iov_len = sizeof(rn); - iov[7].iov_base = mime_boundary; - iov[7].iov_len = sizeof(mime_boundary) - 1; - iov[8].iov_base = const_cast<char*>(rn); - iov[8].iov_len = sizeof(rn); - - IGNORE_RET(sys_writev(fd, iov, 9)); + writer.AddPairString(process_type_msg, info.process_type); + writer.AddBoundary(); + writer.Flush(); + } + + // If GPU info is known, send it. + unsigned gpu_vendor_len = my_strlen(child_process_logging::g_gpu_vendor_id); + if (gpu_vendor_len) { + static const char vendor_msg[] = "gpu-venid"; + static const char device_msg[] = "gpu-devid"; + static const char driver_msg[] = "gpu-driver"; + static const char psver_msg[] = "gpu-psver"; + static const char vsver_msg[] = "gpu-vsver"; + + writer.AddPairString(vendor_msg, child_process_logging::g_gpu_vendor_id); + writer.AddBoundary(); + writer.AddPairString(device_msg, child_process_logging::g_gpu_device_id); + writer.AddBoundary(); + writer.AddPairString(driver_msg, child_process_logging::g_gpu_driver_ver); + writer.AddBoundary(); + writer.AddPairString(psver_msg, child_process_logging::g_gpu_ps_ver); + writer.AddBoundary(); + writer.AddPairString(vsver_msg, child_process_logging::g_gpu_vs_ver); + writer.AddBoundary(); + writer.Flush(); } if (info.distro_length) { - iov[0].iov_base = const_cast<char*>(form_data_msg); - iov[0].iov_len = sizeof(form_data_msg) - 1; - iov[1].iov_base = const_cast<char*>(distro_msg); - iov[1].iov_len = sizeof(distro_msg) - 1; - iov[2].iov_base = const_cast<char*>(quote_msg); - iov[2].iov_len = sizeof(quote_msg); - iov[3].iov_base = const_cast<char*>(rn); - iov[3].iov_len = sizeof(rn); - iov[4].iov_base = const_cast<char*>(rn); - iov[4].iov_len = sizeof(rn); - - iov[5].iov_base = const_cast<char*>(info.distro); - iov[5].iov_len = info.distro_length; - iov[6].iov_base = const_cast<char*>(rn); - iov[6].iov_len = sizeof(rn); - iov[7].iov_base = mime_boundary; - iov[7].iov_len = sizeof(mime_boundary) - 1; - iov[8].iov_base = const_cast<char*>(rn); - iov[8].iov_len = sizeof(rn); - - IGNORE_RET(sys_writev(fd, iov, 9)); + writer.AddPairString(distro_msg, info.distro); + writer.AddBoundary(); + writer.Flush(); } // For rendererers and plugins. if (info.crash_url_length) { - unsigned i = 0, done = 0, crash_url_length = info.crash_url_length; - static const unsigned kMaxCrashChunkSize = 64; - static const unsigned kMaxUrlLength = 8 * kMaxCrashChunkSize; - if (crash_url_length > kMaxUrlLength) - crash_url_length = kMaxUrlLength; - - while (crash_url_length) { - char num[16]; - const unsigned num_len = my_int_len(++i); - my_itos(num, i, num_len); - - iov[0].iov_base = const_cast<char*>(form_data_msg); - iov[0].iov_len = sizeof(form_data_msg) - 1; - iov[1].iov_base = const_cast<char*>(url_chunk_msg); - iov[1].iov_len = sizeof(url_chunk_msg) - 1; - iov[2].iov_base = num; - iov[2].iov_len = num_len; - iov[3].iov_base = const_cast<char*>(quote_msg); - iov[3].iov_len = sizeof(quote_msg); - iov[4].iov_base = const_cast<char*>(rn); - iov[4].iov_len = sizeof(rn); - iov[5].iov_base = const_cast<char*>(rn); - iov[5].iov_len = sizeof(rn); - - const unsigned len = crash_url_length > kMaxCrashChunkSize ? - kMaxCrashChunkSize : crash_url_length; - iov[6].iov_base = const_cast<char*>(info.crash_url + done); - iov[6].iov_len = len; - iov[7].iov_base = const_cast<char*>(rn); - iov[7].iov_len = sizeof(rn); - iov[8].iov_base = mime_boundary; - iov[8].iov_len = sizeof(mime_boundary) - 1; - iov[9].iov_base = const_cast<char*>(rn); - iov[9].iov_len = sizeof(rn); - - IGNORE_RET(sys_writev(fd, iov, 10)); - - done += len; - crash_url_length -= len; - } + static const unsigned kMaxUrlLength = 8 * MimeWriter::kMaxCrashChunkSize; + writer.AddPairDataInChunks(url_chunk_msg, sizeof(url_chunk_msg) - 1, + info.crash_url, std::min(info.crash_url_length, kMaxUrlLength)); } - iov[0].iov_base = const_cast<char*>(form_data_msg); - iov[0].iov_len = sizeof(form_data_msg) - 1; - iov[1].iov_base = const_cast<char*>(dump_msg); - iov[1].iov_len = sizeof(dump_msg) - 1; - iov[2].iov_base = const_cast<char*>(rn); - iov[2].iov_len = sizeof(rn); - - iov[3].iov_base = const_cast<char*>(content_type_msg); - iov[3].iov_len = sizeof(content_type_msg) - 1; - iov[4].iov_base = const_cast<char*>(rn); - iov[4].iov_len = sizeof(rn); - iov[5].iov_base = const_cast<char*>(rn); - iov[5].iov_len = sizeof(rn); - - iov[6].iov_base = dump_data; - iov[6].iov_len = st.st_size; - - iov[7].iov_base = const_cast<char*>(rn); - iov[7].iov_len = sizeof(rn); - iov[8].iov_base = mime_boundary; - iov[8].iov_len = sizeof(mime_boundary) - 1; - iov[9].iov_base = const_cast<char*>(dashdash_msg); - iov[9].iov_len = sizeof(dashdash_msg); - iov[10].iov_base = const_cast<char*>(rn); - iov[10].iov_len = sizeof(rn); - - IGNORE_RET(sys_writev(fd, iov, 11)); + writer.AddFileDump(dump_data, st.st_size); + writer.AddEnd(); + writer.Flush(); IGNORE_RET(sys_close(fd)); |