forked from eden-emu/eden
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
parent
c0cceff365
commit
6c655321e6
4081 changed files with 1185566 additions and 45 deletions
77
externals/breakpad/src/tools/linux/core2md/core2md.cc
vendored
Normal file
77
externals/breakpad/src/tools/linux/core2md/core2md.cc
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// core2md.cc: A utility to convert an ELF core file to a minidump file.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "client/linux/minidump_writer/linux_core_dumper.h"
|
||||
#include "common/path_helper.h"
|
||||
|
||||
using google_breakpad::AppMemoryList;
|
||||
using google_breakpad::MappingList;
|
||||
using google_breakpad::LinuxCoreDumper;
|
||||
|
||||
static int ShowUsage(const char* argv0) {
|
||||
fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n",
|
||||
google_breakpad::BaseName(argv0).c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool WriteMinidumpFromCore(const char* filename,
|
||||
const char* core_path,
|
||||
const char* procfs_override) {
|
||||
MappingList mappings;
|
||||
AppMemoryList memory_list;
|
||||
LinuxCoreDumper dumper(0, core_path, procfs_override);
|
||||
return google_breakpad::WriteMinidump(filename, mappings, memory_list,
|
||||
&dumper);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 4) {
|
||||
return ShowUsage(argv[0]);
|
||||
}
|
||||
|
||||
const char* core_file = argv[1];
|
||||
const char* procfs_dir = argv[2];
|
||||
const char* minidump_file = argv[3];
|
||||
if (!WriteMinidumpFromCore(minidump_file,
|
||||
core_file,
|
||||
procfs_dir)) {
|
||||
perror("core2md: Unable to generate minidump");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
151
externals/breakpad/src/tools/linux/core_handler/core_handler.cc
vendored
Normal file
151
externals/breakpad/src/tools/linux/core_handler/core_handler.cc
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// core_handler.cc: A tool to handle coredumps on Linux
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "client/linux/minidump_writer/linux_core_dumper.h"
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "common/path_helper.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using google_breakpad::AppMemoryList;
|
||||
using google_breakpad::LinuxCoreDumper;
|
||||
using google_breakpad::MappingList;
|
||||
using google_breakpad::scoped_array;
|
||||
|
||||
// Size of the core dump to read in order to access all the threads
|
||||
// descriptions.
|
||||
//
|
||||
// The first section is the note0 section which contains the thread states. On
|
||||
// x86-64 a typical thread description take about 1432B. Reading 1 MB allows
|
||||
// several hundreds of threads.
|
||||
const int core_read_size = 1024 * 1024;
|
||||
|
||||
void ShowUsage(const char* argv0) {
|
||||
fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n",
|
||||
google_breakpad::BaseName(argv0).c_str());
|
||||
fprintf(stderr,
|
||||
"A tool which serves as a core dump handler and produces "
|
||||
"minidump files.\n");
|
||||
fprintf(stderr, "Please refer to the online documentation:\n");
|
||||
fprintf(stderr,
|
||||
"https://chromium.googlesource.com/breakpad/breakpad/+/HEAD"
|
||||
"/docs/linux_core_handler.md\n");
|
||||
}
|
||||
|
||||
bool WriteMinidumpFromCore(const char* filename,
|
||||
const char* core_path,
|
||||
const char* procfs_override) {
|
||||
MappingList mappings;
|
||||
AppMemoryList memory_list;
|
||||
LinuxCoreDumper dumper(0, core_path, procfs_override);
|
||||
return google_breakpad::WriteMinidump(filename, mappings, memory_list,
|
||||
&dumper);
|
||||
}
|
||||
|
||||
bool HandleCrash(pid_t pid, const char* procfs_dir, const char* md_filename) {
|
||||
int r = 0;
|
||||
scoped_array<char> buf(new char[core_read_size]);
|
||||
while (r != core_read_size) {
|
||||
int ret = read(STDIN_FILENO, &buf[r], core_read_size - r);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
} else if (ret == -1) {
|
||||
return false;
|
||||
}
|
||||
r += ret;
|
||||
}
|
||||
|
||||
int fd = memfd_create("core_file", MFD_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int w = write(fd, &buf[0], r);
|
||||
if (w != r) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stringstream core_file_ss;
|
||||
core_file_ss << "/proc/self/fd/" << fd;
|
||||
std::string core_file(core_file_ss.str());
|
||||
|
||||
if (!WriteMinidumpFromCore(md_filename, core_file.c_str(), procfs_dir)) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int ret = EXIT_FAILURE;
|
||||
|
||||
if (argc != 3) {
|
||||
ShowUsage(argv[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* pid_str = argv[1];
|
||||
const char* md_filename = argv[2];
|
||||
pid_t pid = atoi(pid_str);
|
||||
|
||||
std::stringstream proc_dir_ss;
|
||||
proc_dir_ss << "/proc/" << pid_str;
|
||||
std::string proc_dir(proc_dir_ss.str());
|
||||
|
||||
openlog("core_handler", 0, 0);
|
||||
if (HandleCrash(pid, proc_dir.c_str(), md_filename)) {
|
||||
syslog(LOG_NOTICE, "Minidump generated at %s\n", md_filename);
|
||||
ret = EXIT_SUCCESS;
|
||||
} else {
|
||||
syslog(LOG_ERR, "Cannot generate minidump %s\n", md_filename);
|
||||
}
|
||||
closelog();
|
||||
|
||||
return ret;
|
||||
}
|
155
externals/breakpad/src/tools/linux/dump_syms/dump_syms.cc
vendored
Normal file
155
externals/breakpad/src/tools/linux/dump_syms/dump_syms.cc
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/linux/dump_symbols.h"
|
||||
#include "common/path_helper.h"
|
||||
|
||||
using google_breakpad::WriteSymbolFile;
|
||||
using google_breakpad::WriteSymbolFileHeader;
|
||||
|
||||
int usage(const char* self) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s [OPTION] <binary-with-debugging-info> "
|
||||
"[directories-for-debug-file]\n\n",
|
||||
google_breakpad::BaseName(self).c_str());
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -i: Output module header information only.\n");
|
||||
fprintf(stderr, " -c Do not generate CFI section\n");
|
||||
fprintf(stderr, " -d Generate INLINE/INLINE_ORIGIN records\n");
|
||||
fprintf(stderr, " -r Do not handle inter-compilation "
|
||||
"unit references\n");
|
||||
fprintf(stderr, " -v Print all warnings to stderr\n");
|
||||
fprintf(stderr, " -n <name> Use specified name for name of the object\n");
|
||||
fprintf(stderr, " -o <os> Use specified name for the "
|
||||
"operating system\n");
|
||||
fprintf(stderr, " -m Enable writing the optional 'm' field on FUNC "
|
||||
"and PUBLIC, denoting multiple symbols for "
|
||||
"the address.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2)
|
||||
return usage(argv[0]);
|
||||
bool header_only = false;
|
||||
bool cfi = true;
|
||||
bool handle_inlines = false;
|
||||
bool handle_inter_cu_refs = true;
|
||||
bool log_to_stderr = false;
|
||||
bool enable_multiple_field = false;
|
||||
std::string obj_name;
|
||||
const char* obj_os = "Linux";
|
||||
int arg_index = 1;
|
||||
while (arg_index < argc && strlen(argv[arg_index]) > 0 &&
|
||||
argv[arg_index][0] == '-') {
|
||||
if (strcmp("-i", argv[arg_index]) == 0) {
|
||||
header_only = true;
|
||||
} else if (strcmp("-c", argv[arg_index]) == 0) {
|
||||
cfi = false;
|
||||
} else if (strcmp("-d", argv[arg_index]) == 0) {
|
||||
handle_inlines = true;
|
||||
} else if (strcmp("-r", argv[arg_index]) == 0) {
|
||||
handle_inter_cu_refs = false;
|
||||
} else if (strcmp("-v", argv[arg_index]) == 0) {
|
||||
log_to_stderr = true;
|
||||
} else if (strcmp("-n", argv[arg_index]) == 0) {
|
||||
if (arg_index + 1 >= argc) {
|
||||
fprintf(stderr, "Missing argument to -n\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
obj_name = argv[arg_index + 1];
|
||||
++arg_index;
|
||||
} else if (strcmp("-o", argv[arg_index]) == 0) {
|
||||
if (arg_index + 1 >= argc) {
|
||||
fprintf(stderr, "Missing argument to -o\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
obj_os = argv[arg_index + 1];
|
||||
++arg_index;
|
||||
} else if (strcmp("-m", argv[arg_index]) == 0) {
|
||||
enable_multiple_field = true;
|
||||
} else {
|
||||
printf("2.4 %s\n", argv[arg_index]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
++arg_index;
|
||||
}
|
||||
if (arg_index == argc)
|
||||
return usage(argv[0]);
|
||||
// Save stderr so it can be used below.
|
||||
FILE* saved_stderr = fdopen(dup(fileno(stderr)), "w");
|
||||
if (!log_to_stderr) {
|
||||
if (freopen(_PATH_DEVNULL, "w", stderr)) {
|
||||
// If it fails, not a lot we can (or should) do.
|
||||
// Add this brace section to silence gcc warnings.
|
||||
}
|
||||
}
|
||||
const char* binary;
|
||||
std::vector<string> debug_dirs;
|
||||
binary = argv[arg_index];
|
||||
for (int debug_dir_index = arg_index + 1;
|
||||
debug_dir_index < argc;
|
||||
++debug_dir_index) {
|
||||
debug_dirs.push_back(argv[debug_dir_index]);
|
||||
}
|
||||
|
||||
if (obj_name.empty())
|
||||
obj_name = binary;
|
||||
|
||||
if (header_only) {
|
||||
if (!WriteSymbolFileHeader(binary, obj_name, obj_os, std::cout)) {
|
||||
fprintf(saved_stderr, "Failed to process file.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
SymbolData symbol_data = (handle_inlines ? INLINES : NO_DATA) |
|
||||
(cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES;
|
||||
google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs,
|
||||
enable_multiple_field);
|
||||
if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options,
|
||||
std::cout)) {
|
||||
fprintf(saved_stderr, "Failed to write symbol file.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
1534
externals/breakpad/src/tools/linux/md2core/minidump-2-core.cc
vendored
Normal file
1534
externals/breakpad/src/tools/linux/md2core/minidump-2-core.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
88
externals/breakpad/src/tools/linux/md2core/minidump_memory_range.h
vendored
Normal file
88
externals/breakpad/src/tools/linux/md2core/minidump_memory_range.h
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_memory_range.h: Define the google_breakpad::MinidumpMemoryRange
|
||||
// class, which adds methods for handling minidump specific data structures
|
||||
// on top of google_breakpad::MemoryRange. See common/memory_range.h for
|
||||
// more details on MemoryRange.
|
||||
|
||||
#ifndef TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_
|
||||
#define TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A derived class of MemoryRange with added methods for handling minidump
|
||||
// specific data structures. To avoid virtual functions, it is not designed
|
||||
// to be used polymorphically.
|
||||
class MinidumpMemoryRange : public MemoryRange {
|
||||
public:
|
||||
MinidumpMemoryRange() {}
|
||||
|
||||
MinidumpMemoryRange(const void* data, size_t length)
|
||||
: MemoryRange(data, length) {}
|
||||
|
||||
// Returns a subrange of |length| bytes at |offset| bytes of this memory
|
||||
// range, or an empty range if the subrange is out of bounds.
|
||||
// This methods overrides the base implemementation in order to return
|
||||
// an instance of MinidumpMemoryRange instead of MemoryRange.
|
||||
MinidumpMemoryRange Subrange(size_t sub_offset, size_t sub_length) const {
|
||||
if (Covers(sub_offset, sub_length))
|
||||
return MinidumpMemoryRange(data() + sub_offset, sub_length);
|
||||
return MinidumpMemoryRange();
|
||||
}
|
||||
|
||||
// Returns a subrange that covers the offset and length specified by
|
||||
// |location|, or an empty range if the subrange is out of bounds.
|
||||
MinidumpMemoryRange Subrange(const MDLocationDescriptor& location) const {
|
||||
return MinidumpMemoryRange::Subrange(location.rva, location.data_size);
|
||||
}
|
||||
|
||||
// Gets a STL string from a MDString at |sub_offset| bytes of this memory
|
||||
// range. This method only works correctly for ASCII characters and does
|
||||
// not convert between UTF-16 and UTF-8.
|
||||
const std::string GetAsciiMDString(size_t sub_offset) const {
|
||||
std::string str;
|
||||
const MDString* md_str = GetData<MDString>(sub_offset);
|
||||
if (md_str) {
|
||||
const uint16_t* buffer = &md_str->buffer[0];
|
||||
for (uint32_t i = 0; i < md_str->length && buffer[i]; ++i) {
|
||||
str.push_back(buffer[i]);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_
|
261
externals/breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc
vendored
Normal file
261
externals/breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc
vendored
Normal file
|
@ -0,0 +1,261 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_memory_range_unittest.cc:
|
||||
// Unit tests for google_breakpad::MinidumpMemoryRange.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "tools/linux/md2core/minidump_memory_range.h"
|
||||
|
||||
using google_breakpad::MinidumpMemoryRange;
|
||||
using testing::Message;
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kBuffer[10] = { 0 };
|
||||
const size_t kBufferSize = sizeof(kBuffer);
|
||||
const uint8_t* kBufferPointer = reinterpret_cast<const uint8_t*>(kBuffer);
|
||||
|
||||
// Test vectors for verifying Covers, GetData, and Subrange.
|
||||
const struct {
|
||||
bool valid;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
} kSubranges[] = {
|
||||
{ true, 0, 0 },
|
||||
{ true, 0, 2 },
|
||||
{ true, 0, kBufferSize },
|
||||
{ true, 2, 0 },
|
||||
{ true, 2, 4 },
|
||||
{ true, 2, kBufferSize - 2 },
|
||||
{ true, kBufferSize - 1, 1 },
|
||||
{ false, kBufferSize, 0 },
|
||||
{ false, kBufferSize, static_cast<size_t>(-1) },
|
||||
{ false, kBufferSize + 1, 0 },
|
||||
{ false, static_cast<size_t>(-1), 2 },
|
||||
{ false, 1, kBufferSize },
|
||||
{ false, kBufferSize - 1, 2 },
|
||||
{ false, 0, static_cast<size_t>(-1) },
|
||||
{ false, 1, static_cast<size_t>(-1) },
|
||||
};
|
||||
const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]);
|
||||
|
||||
// Test vectors for verifying GetArrayElement.
|
||||
const struct {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
size_t index;
|
||||
const void* const pointer;
|
||||
} kElements[] = {
|
||||
// Valid array elemenets
|
||||
{ 0, 1, 0, kBufferPointer },
|
||||
{ 0, 1, 1, kBufferPointer + 1 },
|
||||
{ 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 },
|
||||
{ 0, 2, 1, kBufferPointer + 2 },
|
||||
{ 0, 4, 2, kBufferPointer + 8 },
|
||||
{ 0, 4, 9, kBufferPointer + 36 },
|
||||
{ kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 },
|
||||
// Invalid array elemenets
|
||||
{ 0, 1, kBufferSize, NULL },
|
||||
{ 0, 4, 10, NULL },
|
||||
{ kBufferSize - 1, 1, 1, NULL },
|
||||
{ kBufferSize - 1, 2, 0, NULL },
|
||||
{ kBufferSize, 1, 0, NULL },
|
||||
};
|
||||
const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]);
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, DefaultConstructor) {
|
||||
MinidumpMemoryRange range;
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0U, range.length());
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, ConstructorWithDataAndLength) {
|
||||
MinidumpMemoryRange range(kBuffer, kBufferSize);
|
||||
EXPECT_EQ(kBufferPointer, range.data());
|
||||
EXPECT_EQ(kBufferSize, range.length());
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, Reset) {
|
||||
MinidumpMemoryRange range;
|
||||
range.Reset();
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0U, range.length());
|
||||
|
||||
range.Set(kBuffer, kBufferSize);
|
||||
EXPECT_EQ(kBufferPointer, range.data());
|
||||
EXPECT_EQ(kBufferSize, range.length());
|
||||
|
||||
range.Reset();
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0U, range.length());
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, Set) {
|
||||
MinidumpMemoryRange range;
|
||||
range.Set(kBuffer, kBufferSize);
|
||||
EXPECT_EQ(kBufferPointer, range.data());
|
||||
EXPECT_EQ(kBufferSize, range.length());
|
||||
|
||||
range.Set(NULL, 0);
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0U, range.length());
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, SubrangeOfEmptyMemoryRange) {
|
||||
MinidumpMemoryRange range;
|
||||
MinidumpMemoryRange subrange = range.Subrange(0, 10);
|
||||
EXPECT_EQ(NULL, subrange.data());
|
||||
EXPECT_EQ(0U, subrange.length());
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, SubrangeAndGetData) {
|
||||
MinidumpMemoryRange range(kBuffer, kBufferSize);
|
||||
for (size_t i = 0; i < kNumSubranges; ++i) {
|
||||
bool valid = kSubranges[i].valid;
|
||||
size_t sub_offset = kSubranges[i].offset;
|
||||
size_t sub_length = kSubranges[i].length;
|
||||
SCOPED_TRACE(Message() << "offset=" << sub_offset
|
||||
<< ", length=" << sub_length);
|
||||
|
||||
MinidumpMemoryRange subrange = range.Subrange(sub_offset, sub_length);
|
||||
if (valid) {
|
||||
EXPECT_TRUE(range.Covers(sub_offset, sub_length));
|
||||
EXPECT_EQ(kBufferPointer + sub_offset,
|
||||
range.GetData(sub_offset, sub_length));
|
||||
EXPECT_EQ(kBufferPointer + sub_offset, subrange.data());
|
||||
EXPECT_EQ(sub_length, subrange.length());
|
||||
} else {
|
||||
EXPECT_FALSE(range.Covers(sub_offset, sub_length));
|
||||
EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length));
|
||||
EXPECT_EQ(NULL, subrange.data());
|
||||
EXPECT_EQ(0U, subrange.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, SubrangeWithMDLocationDescriptor) {
|
||||
MinidumpMemoryRange range(kBuffer, kBufferSize);
|
||||
for (size_t i = 0; i < kNumSubranges; ++i) {
|
||||
bool valid = kSubranges[i].valid;
|
||||
size_t sub_offset = kSubranges[i].offset;
|
||||
size_t sub_length = kSubranges[i].length;
|
||||
SCOPED_TRACE(Message() << "offset=" << sub_offset
|
||||
<< ", length=" << sub_length);
|
||||
|
||||
MDLocationDescriptor location;
|
||||
location.rva = sub_offset;
|
||||
location.data_size = sub_length;
|
||||
MinidumpMemoryRange subrange = range.Subrange(location);
|
||||
if (valid) {
|
||||
EXPECT_TRUE(range.Covers(sub_offset, sub_length));
|
||||
EXPECT_EQ(kBufferPointer + sub_offset,
|
||||
range.GetData(sub_offset, sub_length));
|
||||
EXPECT_EQ(kBufferPointer + sub_offset, subrange.data());
|
||||
EXPECT_EQ(sub_length, subrange.length());
|
||||
} else {
|
||||
EXPECT_FALSE(range.Covers(sub_offset, sub_length));
|
||||
EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length));
|
||||
EXPECT_EQ(NULL, subrange.data());
|
||||
EXPECT_EQ(0U, subrange.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, GetDataWithTemplateType) {
|
||||
MinidumpMemoryRange range(kBuffer, kBufferSize);
|
||||
const char* char_pointer = range.GetData<char>(0);
|
||||
EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer);
|
||||
const int* int_pointer = range.GetData<int>(0);
|
||||
EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer);
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, GetArrayElement) {
|
||||
MinidumpMemoryRange range(kBuffer, kBufferSize);
|
||||
for (size_t i = 0; i < kNumElements; ++i) {
|
||||
size_t element_offset = kElements[i].offset;
|
||||
size_t element_size = kElements[i].size;
|
||||
unsigned element_index = kElements[i].index;
|
||||
const void* const element_pointer = kElements[i].pointer;
|
||||
SCOPED_TRACE(Message() << "offset=" << element_offset
|
||||
<< ", size=" << element_size
|
||||
<< ", index=" << element_index);
|
||||
EXPECT_EQ(element_pointer, range.GetArrayElement(
|
||||
element_offset, element_size, element_index));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, GetArrayElmentWithTemplateType) {
|
||||
MinidumpMemoryRange range(kBuffer, kBufferSize);
|
||||
const char* char_pointer = range.GetArrayElement<char>(0, 0);
|
||||
EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer);
|
||||
const int* int_pointer = range.GetArrayElement<int>(0, 0);
|
||||
EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer);
|
||||
}
|
||||
|
||||
TEST(MinidumpMemoryRangeTest, GetAsciiMDString) {
|
||||
uint8_t buffer[100] = { 0 };
|
||||
|
||||
MDString* md_str = reinterpret_cast<MDString*>(buffer);
|
||||
md_str->length = 4;
|
||||
md_str->buffer[0] = 'T';
|
||||
md_str->buffer[1] = 'e';
|
||||
md_str->buffer[2] = 's';
|
||||
md_str->buffer[3] = 't';
|
||||
md_str->buffer[4] = '\0';
|
||||
|
||||
size_t str2_offset =
|
||||
sizeof(MDString) + (md_str->length + 1) * sizeof(uint16_t);
|
||||
|
||||
md_str = reinterpret_cast<MDString*>(buffer + str2_offset);
|
||||
md_str->length = 9; // Test length larger than actual string
|
||||
md_str->buffer[0] = 'S';
|
||||
md_str->buffer[1] = 't';
|
||||
md_str->buffer[2] = 'r';
|
||||
md_str->buffer[3] = 'i';
|
||||
md_str->buffer[4] = 'n';
|
||||
md_str->buffer[5] = 'g';
|
||||
md_str->buffer[6] = '\0';
|
||||
md_str->buffer[7] = '1';
|
||||
md_str->buffer[8] = '2';
|
||||
|
||||
MinidumpMemoryRange range(buffer, sizeof(buffer));
|
||||
EXPECT_EQ("Test", range.GetAsciiMDString(0));
|
||||
EXPECT_EQ("String", range.GetAsciiMDString(str2_offset));
|
||||
|
||||
// Test out-of-bounds cases.
|
||||
EXPECT_EQ("", range.GetAsciiMDString(
|
||||
sizeof(buffer) - sizeof(MDString) + 1));
|
||||
EXPECT_EQ("", range.GetAsciiMDString(sizeof(buffer)));
|
||||
}
|
62
externals/breakpad/src/tools/linux/pid2md/pid2md.cc
vendored
Normal file
62
externals/breakpad/src/tools/linux/pid2md/pid2md.cc
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// pid2md.cc: An utility to generate a minidump from a running process
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "common/path_helper.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n",
|
||||
google_breakpad::BaseName(argv[0]).c_str());
|
||||
fprintf(stderr,
|
||||
"A tool to generate a minidump from a running process. The process "
|
||||
"resumes its\nactivity once the operation is completed. Permission "
|
||||
"to trace the process is\nrequired.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
pid_t process_id = atoi(argv[1]);
|
||||
const char* minidump_file = argv[2];
|
||||
|
||||
if (!google_breakpad::WriteMinidump(minidump_file, process_id, process_id)) {
|
||||
fprintf(stderr, "Unable to generate minidump.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
159
externals/breakpad/src/tools/linux/symupload/minidump_upload.cc
vendored
Normal file
159
externals/breakpad/src/tools/linux/symupload/minidump_upload.cc
vendored
Normal file
|
@ -0,0 +1,159 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_upload.cc: Upload a minidump to a HTTP server.
|
||||
// The upload is sent as a multipart/form-data POST request with
|
||||
// the following parameters:
|
||||
// prod: the product name
|
||||
// ver: the product version
|
||||
// symbol_file: the breakpad format symbol file
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/http_upload.h"
|
||||
#include "common/path_helper.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using google_breakpad::HTTPUpload;
|
||||
|
||||
struct Options {
|
||||
string minidumpPath;
|
||||
string uploadURLStr;
|
||||
string product;
|
||||
string version;
|
||||
string proxy;
|
||||
string proxy_user_pwd;
|
||||
bool success;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
static void Start(Options *options) {
|
||||
std::map<string, string> parameters;
|
||||
// Add parameters
|
||||
parameters["prod"] = options->product;
|
||||
parameters["ver"] = options->version;
|
||||
|
||||
std::map<string, string> files;
|
||||
files["upload_file_minidump"] = options->minidumpPath;
|
||||
|
||||
// Send it
|
||||
string response, error;
|
||||
bool success = HTTPUpload::SendRequest(options->uploadURLStr,
|
||||
parameters,
|
||||
files,
|
||||
options->proxy,
|
||||
options->proxy_user_pwd,
|
||||
"",
|
||||
&response,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (success) {
|
||||
printf("Successfully sent the minidump file.\n");
|
||||
} else {
|
||||
printf("Failed to send minidump: %s\n", error.c_str());
|
||||
}
|
||||
printf("Response:\n");
|
||||
printf("%s\n", response.c_str());
|
||||
options->success = success;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void
|
||||
Usage(int argc, const char *argv[]) {
|
||||
fprintf(stderr, "Submit minidump information.\n");
|
||||
fprintf(stderr,
|
||||
"Usage: %s [options...] -p <product> -v <version> <minidump> "
|
||||
"<upload-URL>\n",
|
||||
google_breakpad::BaseName(argv[0]).c_str());
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "<minidump> should be a minidump.\n");
|
||||
fprintf(stderr, "<upload-URL> is the destination for the upload\n");
|
||||
|
||||
fprintf(stderr, "-p:\t <product> Product name\n");
|
||||
fprintf(stderr, "-v:\t <version> Product version\n");
|
||||
fprintf(stderr, "-x:\t <host[:port]> Use HTTP proxy on given port\n");
|
||||
fprintf(stderr, "-u:\t <user[:password]> Set proxy user and password\n");
|
||||
fprintf(stderr, "-h:\t Usage\n");
|
||||
fprintf(stderr, "-?:\t Usage\n");
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void
|
||||
SetupOptions(int argc, const char *argv[], Options *options) {
|
||||
extern int optind;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, (char * const*)argv, "p:u:v:x:h?")) != -1) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
options->product = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
options->proxy_user_pwd = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
options->version = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
options->proxy = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Invalid option '%c'\n", ch);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind) != 2) {
|
||||
fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
options->minidumpPath = argv[optind];
|
||||
options->uploadURLStr = argv[optind + 1];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
int main(int argc, const char* argv[]) {
|
||||
Options options;
|
||||
SetupOptions(argc, argv, &options);
|
||||
Start(&options);
|
||||
return options.success ? 0 : 1;
|
||||
}
|
217
externals/breakpad/src/tools/linux/symupload/sym_upload.cc
vendored
Normal file
217
externals/breakpad/src/tools/linux/symupload/sym_upload.cc
vendored
Normal file
|
@ -0,0 +1,217 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// symupload.cc: Upload a symbol file to a HTTP server. The upload is sent as
|
||||
// a multipart/form-data POST request with the following parameters:
|
||||
// code_file: the basename of the module, e.g. "app"
|
||||
// debug_file: the basename of the debugging file, e.g. "app"
|
||||
// debug_identifier: the debug file's identifier, usually consisting of
|
||||
// the guid and age embedded in the pdb, e.g.
|
||||
// "11111111BBBB3333DDDD555555555555F"
|
||||
// version: the file version of the module, e.g. "1.2.3.4"
|
||||
// os: the operating system that the module was built for
|
||||
// cpu: the CPU that the module was built for
|
||||
// symbol_file: the contents of the breakpad-format symbol file
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <locale>
|
||||
|
||||
#include "common/linux/symbol_upload.h"
|
||||
#include "common/path_helper.h"
|
||||
|
||||
using google_breakpad::sym_upload::UploadProtocol;
|
||||
using google_breakpad::sym_upload::Options;
|
||||
|
||||
static void StrToUpper(std::string* str) {
|
||||
if (str == nullptr) {
|
||||
fprintf(stderr, "nullptr passed to StrToUpper.\n");
|
||||
exit(1);
|
||||
}
|
||||
for (size_t i = 0; i < str->length(); i++) {
|
||||
(*str)[i] = std::toupper((*str)[i], std::locale::classic());
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void
|
||||
Usage(int argc, const char *argv[]) {
|
||||
fprintf(stderr, "Submit symbol information.\n");
|
||||
fprintf(stderr, "Usage: %s [options...] <symbol-file> <upload-URL>\n",
|
||||
google_breakpad::BaseName(argv[0]).c_str());
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr,
|
||||
"<symbol-file> should be created by using the dump_syms "
|
||||
"tool.\n");
|
||||
fprintf(stderr, "<upload-URL> is the destination for the upload\n");
|
||||
fprintf(stderr, "-p:\t <protocol> One of ['sym-upload-v1',"
|
||||
" 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n");
|
||||
fprintf(stderr, "-v:\t Version information (e.g., 1.2.3.4)\n");
|
||||
fprintf(stderr, "-x:\t <host[:port]> Use HTTP proxy on given port\n");
|
||||
fprintf(stderr, "-u:\t <user[:password]> Set proxy user and password\n");
|
||||
fprintf(stderr, "-h:\t Usage\n");
|
||||
fprintf(stderr, "-?:\t Usage\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "These options only work with 'sym-upload-v2' protocol:\n");
|
||||
fprintf(stderr, "-k:\t <API-key> A secret used to authenticate with the"
|
||||
" API.\n");
|
||||
fprintf(stderr, "-f:\t Force symbol upload if already exists.\n");
|
||||
fprintf(stderr, "-t:\t <symbol-type> Explicitly set symbol upload type ("
|
||||
"default is 'breakpad').\n"
|
||||
"\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', "
|
||||
"'dsym', 'pdb'].\n"
|
||||
"\t Note: When this flag is set to anything other than 'breakpad', then "
|
||||
"the '-c' and '-i' flags must also be set.\n");
|
||||
fprintf(stderr, "-c:\t <code-file> Explicitly set 'code_file' for symbol "
|
||||
"upload (basename of executable).\n");
|
||||
fprintf(stderr, "-i:\t <debug-id> Explicitly set 'debug_id' for symbol "
|
||||
"upload (typically build ID of executable).\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, " With 'sym-upload-v1':\n");
|
||||
fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, " With 'sym-upload-v2':\n");
|
||||
fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n");
|
||||
fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! "
|
||||
"path/to/symbol_file http://myuploadserver\n", argv[0]);
|
||||
fprintf(stderr, " [Explicitly set symbol type to 'elf']\n");
|
||||
fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! -t elf "
|
||||
"-c app -i 11111111BBBB3333DDDD555555555555F "
|
||||
"path/to/symbol_file http://myuploadserver\n", argv[0]);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void
|
||||
SetupOptions(int argc, const char *argv[], Options *options) {
|
||||
extern int optind, optopt;
|
||||
int ch;
|
||||
constexpr char flag_pattern[] = "u:v:x:p:k:t:c:i:hf?";
|
||||
|
||||
while ((ch = getopt(argc, (char * const*)argv, flag_pattern)) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
case '?':
|
||||
Usage(argc, argv);
|
||||
// ch might be '?' because getopt found an error while parsing args (as
|
||||
// opposed to finding "-?" as an arg), in which case optopt is set to
|
||||
// the bad arg value, so return an error code if optopt is set,
|
||||
// otherwise exit cleanly.
|
||||
exit(optopt == 0 ? 0 : 1);
|
||||
case 'u':
|
||||
options->proxy_user_pwd = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
options->version = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
options->proxy = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
if (strcmp(optarg, "sym-upload-v2") == 0) {
|
||||
options->upload_protocol = UploadProtocol::SYM_UPLOAD_V2;
|
||||
} else if (strcmp(optarg, "sym-upload-v1") == 0) {
|
||||
options->upload_protocol = UploadProtocol::SYM_UPLOAD_V1;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid protocol '%s'\n", optarg);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
options->api_key = optarg;
|
||||
break;
|
||||
case 't': {
|
||||
// This is really an enum, so treat as upper-case for consistency with
|
||||
// enum naming convention on server-side.
|
||||
options->type = optarg;
|
||||
StrToUpper(&(options->type));
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
options->code_file = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
options->debug_id = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
options->force = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Invalid option '%c'\n", ch);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind) != 2) {
|
||||
fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool is_breakpad_upload = options->type.empty() ||
|
||||
options->type == google_breakpad::sym_upload::kBreakpadSymbolType;
|
||||
bool has_code_file = !options->code_file.empty();
|
||||
bool has_debug_id = !options->debug_id.empty();
|
||||
if (is_breakpad_upload && (has_code_file || has_debug_id)) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s: -c and -i should only be specified for non-breakpad "
|
||||
"symbol upload types.\n", argv[0]);
|
||||
fprintf(stderr, "\n");
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
if (!is_breakpad_upload && (!has_code_file || !has_debug_id)) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s: -c and -i must be specified for non-breakpad "
|
||||
"symbol upload types.\n", argv[0]);
|
||||
fprintf(stderr, "\n");
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
options->symbolsPath = argv[optind];
|
||||
options->uploadURLStr = argv[optind + 1];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
int main(int argc, const char* argv[]) {
|
||||
Options options;
|
||||
SetupOptions(argc, argv, &options);
|
||||
google_breakpad::sym_upload::Start(&options);
|
||||
return options.success ? 0 : 1;
|
||||
}
|
1857
externals/breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
vendored
Normal file
1857
externals/breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
vendored
Normal file
File diff suppressed because it is too large
Load diff
340
externals/breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc
vendored
Normal file
340
externals/breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc
vendored
Normal file
|
@ -0,0 +1,340 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dump_syms_tool.cc: Command line tool that uses the DumpSymbols class.
|
||||
// TODO(waylonis): accept stdin
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <mach-o/arch.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/mac/dump_syms.h"
|
||||
#include "common/mac/arch_utilities.h"
|
||||
#include "common/mac/macho_utilities.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
|
||||
using google_breakpad::DumpSymbols;
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::scoped_ptr;
|
||||
using std::vector;
|
||||
|
||||
struct Options {
|
||||
Options()
|
||||
: srcPath(),
|
||||
dsymPath(),
|
||||
arch(),
|
||||
header_only(false),
|
||||
cfi(true),
|
||||
handle_inter_cu_refs(true),
|
||||
handle_inlines(false),
|
||||
enable_multiple(false),
|
||||
module_name(),
|
||||
prefer_extern_name(false) {}
|
||||
|
||||
string srcPath;
|
||||
string dsymPath;
|
||||
std::optional<ArchInfo> arch;
|
||||
bool header_only;
|
||||
bool cfi;
|
||||
bool handle_inter_cu_refs;
|
||||
bool handle_inlines;
|
||||
bool enable_multiple;
|
||||
string module_name;
|
||||
bool prefer_extern_name;
|
||||
};
|
||||
|
||||
static bool StackFrameEntryComparator(const Module::StackFrameEntry* a,
|
||||
const Module::StackFrameEntry* b) {
|
||||
return a->address < b->address;
|
||||
}
|
||||
|
||||
// Copy the CFI data from |from_module| into |to_module|, for any non-
|
||||
// overlapping ranges.
|
||||
static void CopyCFIDataBetweenModules(Module* to_module,
|
||||
const Module* from_module) {
|
||||
typedef vector<Module::StackFrameEntry*>::const_iterator Iterator;
|
||||
|
||||
// Get the CFI data from both the source and destination modules and ensure
|
||||
// it is sorted by start address.
|
||||
vector<Module::StackFrameEntry*> from_data;
|
||||
from_module->GetStackFrameEntries(&from_data);
|
||||
std::sort(from_data.begin(), from_data.end(), &StackFrameEntryComparator);
|
||||
|
||||
vector<Module::StackFrameEntry*> to_data;
|
||||
to_module->GetStackFrameEntries(&to_data);
|
||||
std::sort(to_data.begin(), to_data.end(), &StackFrameEntryComparator);
|
||||
|
||||
Iterator to_it = to_data.begin();
|
||||
|
||||
for (Iterator it = from_data.begin(); it != from_data.end(); ++it) {
|
||||
Module::StackFrameEntry* from_entry = *it;
|
||||
Module::Address from_entry_end = from_entry->address + from_entry->size;
|
||||
|
||||
// Find the first CFI record in the |to_module| that does not have an
|
||||
// address less than the entry to be copied.
|
||||
while (to_it != to_data.end()) {
|
||||
if (from_entry->address > (*to_it)->address)
|
||||
++to_it;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// If the entry does not overlap, then it is safe to copy to |to_module|.
|
||||
if (to_it == to_data.end() || (from_entry->address < (*to_it)->address &&
|
||||
from_entry_end < (*to_it)->address)) {
|
||||
to_module->AddStackFrameEntry(
|
||||
std::make_unique<Module::StackFrameEntry>(*from_entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool SetArchitecture(DumpSymbols& dump_symbols,
|
||||
const ArchInfo& arch,
|
||||
const std::string& filename) {
|
||||
if (!dump_symbols.SetArchitecture(arch)) {
|
||||
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
|
||||
filename.c_str(),
|
||||
GetNameFromCPUType(arch.cputype, arch.cpusubtype));
|
||||
size_t available_size;
|
||||
const SuperFatArch* available =
|
||||
dump_symbols.AvailableArchitectures(&available_size);
|
||||
if (available_size == 1)
|
||||
fprintf(stderr, "the file's architecture is: ");
|
||||
else
|
||||
fprintf(stderr, "architectures present in the file are:\n");
|
||||
for (size_t i = 0; i < available_size; i++) {
|
||||
const SuperFatArch* arch = &available[i];
|
||||
fprintf(stderr, "%s\n",
|
||||
GetNameFromCPUType(arch->cputype, arch->cpusubtype));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Start(const Options& options) {
|
||||
SymbolData symbol_data =
|
||||
(options.handle_inlines ? INLINES : NO_DATA) |
|
||||
(options.cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES;
|
||||
DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs,
|
||||
options.enable_multiple, options.module_name,
|
||||
options.prefer_extern_name);
|
||||
|
||||
// For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the
|
||||
// Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI
|
||||
// data is in the __DWARF,__debug_frame section, which is moved into the
|
||||
// dSYM. Therefore, to get x86_64 CFI data, dump_syms needs to look at both
|
||||
// the dSYM and the Mach-O file. If both paths are present and CFI was
|
||||
// requested, then consider the Module as "split" and dump all the debug data
|
||||
// from the primary debug info file, the dSYM, and then dump additional CFI
|
||||
// data from the source Mach-O file.
|
||||
bool split_module =
|
||||
!options.dsymPath.empty() && !options.srcPath.empty() && options.cfi;
|
||||
const string& primary_file =
|
||||
split_module ? options.dsymPath : options.srcPath;
|
||||
|
||||
if (!dump_symbols.Read(primary_file))
|
||||
return false;
|
||||
|
||||
if (options.arch &&
|
||||
!SetArchitecture(dump_symbols, *options.arch, primary_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.header_only)
|
||||
return dump_symbols.WriteSymbolFileHeader(std::cout);
|
||||
|
||||
// Read the primary file into a Breakpad Module.
|
||||
Module* module = NULL;
|
||||
if (!dump_symbols.ReadSymbolData(&module))
|
||||
return false;
|
||||
scoped_ptr<Module> scoped_module(module);
|
||||
|
||||
// If this is a split module, read the secondary Mach-O file, from which the
|
||||
// CFI data will be extracted.
|
||||
if (split_module && primary_file == options.dsymPath) {
|
||||
if (!dump_symbols.Read(options.srcPath))
|
||||
return false;
|
||||
|
||||
if (options.arch &&
|
||||
!SetArchitecture(dump_symbols, *options.arch, options.srcPath)) {
|
||||
return false;
|
||||
}
|
||||
Module* cfi_module = NULL;
|
||||
if (!dump_symbols.ReadSymbolData(&cfi_module))
|
||||
return false;
|
||||
scoped_ptr<Module> scoped_cfi_module(cfi_module);
|
||||
|
||||
bool name_matches;
|
||||
if (!options.module_name.empty()) {
|
||||
// Ignore the basename of the dSYM and binary and use the passed-in module
|
||||
// name.
|
||||
name_matches = true;
|
||||
} else {
|
||||
name_matches = cfi_module->name() == module->name();
|
||||
}
|
||||
|
||||
// Ensure that the modules are for the same debug code file.
|
||||
if (!name_matches || cfi_module->os() != module->os() ||
|
||||
cfi_module->architecture() != module->architecture() ||
|
||||
cfi_module->identifier() != module->identifier()) {
|
||||
fprintf(stderr, "Cannot generate a symbol file from split sources that do"
|
||||
" not match.\n");
|
||||
if (!name_matches) {
|
||||
fprintf(stderr, "Name mismatch: binary=[%s], dSYM=[%s]\n",
|
||||
cfi_module->name().c_str(), module->name().c_str());
|
||||
}
|
||||
if (cfi_module->os() != module->os()) {
|
||||
fprintf(stderr, "OS mismatch: binary=[%s], dSYM=[%s]\n",
|
||||
cfi_module->os().c_str(), module->os().c_str());
|
||||
}
|
||||
if (cfi_module->architecture() != module->architecture()) {
|
||||
fprintf(stderr, "Architecture mismatch: binary=[%s], dSYM=[%s]\n",
|
||||
cfi_module->architecture().c_str(),
|
||||
module->architecture().c_str());
|
||||
}
|
||||
if (cfi_module->identifier() != module->identifier()) {
|
||||
fprintf(stderr, "Identifier mismatch: binary=[%s], dSYM=[%s]\n",
|
||||
cfi_module->identifier().c_str(), module->identifier().c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CopyCFIDataBetweenModules(module, cfi_module);
|
||||
}
|
||||
|
||||
return module->Write(std::cout, symbol_data);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void Usage(int argc, const char *argv[]) {
|
||||
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] "
|
||||
"[-n MODULE] [-x] <Mach-o file>\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "\t-i: Output module header information only.\n");
|
||||
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n");
|
||||
fprintf(stderr, "\t in the file, if it contains only one architecture]\n");
|
||||
fprintf(stderr, "\t-g: Debug symbol file (dSYM) to dump in addition to the "
|
||||
"Mach-o file\n");
|
||||
fprintf(stderr, "\t-c: Do not generate CFI section\n");
|
||||
fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n");
|
||||
fprintf(stderr, "\t-d: Generate INLINE and INLINE_ORIGIN records\n");
|
||||
fprintf(stderr,
|
||||
"\t-m: Enable writing the optional 'm' field on FUNC "
|
||||
"and PUBLIC, denoting multiple symbols for the address.\n");
|
||||
fprintf(stderr,
|
||||
"\t-n: Use MODULE as the name of the module rather than \n"
|
||||
"the basename of the Mach-O file/dSYM.\n");
|
||||
fprintf(stderr,
|
||||
"\t-x: Prefer the PUBLIC (extern) name over the FUNC if\n"
|
||||
"they do not match.\n");
|
||||
fprintf(stderr, "\t-h: Usage\n");
|
||||
fprintf(stderr, "\t-?: Usage\n");
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void SetupOptions(int argc, const char *argv[], Options *options) {
|
||||
extern int optind;
|
||||
signed char ch;
|
||||
|
||||
while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?hn:x")) != -1) {
|
||||
switch (ch) {
|
||||
case 'i':
|
||||
options->header_only = true;
|
||||
break;
|
||||
case 'a': {
|
||||
std::optional<ArchInfo> arch_info = GetArchInfoFromName(optarg);
|
||||
if (!arch_info) {
|
||||
fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
options->arch = arch_info;
|
||||
break;
|
||||
}
|
||||
case 'g':
|
||||
options->dsymPath = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
options->cfi = false;
|
||||
break;
|
||||
case 'r':
|
||||
options->handle_inter_cu_refs = false;
|
||||
break;
|
||||
case 'd':
|
||||
options->handle_inlines = true;
|
||||
break;
|
||||
case 'm':
|
||||
options->enable_multiple = true;
|
||||
break;
|
||||
case 'n':
|
||||
options->module_name = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
options->prefer_extern_name = true;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
Usage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind) != 1) {
|
||||
fprintf(stderr, "Must specify Mach-o file\n");
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
options->srcPath = argv[optind];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
int main (int argc, const char * argv[]) {
|
||||
Options options;
|
||||
bool result;
|
||||
|
||||
SetupOptions(argc, argv, &options);
|
||||
result = Start(options);
|
||||
|
||||
return !result;
|
||||
}
|
474
externals/breakpad/src/tools/mac/symupload/symupload.mm
vendored
Normal file
474
externals/breakpad/src/tools/mac/symupload/symupload.mm
vendored
Normal file
|
@ -0,0 +1,474 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// symupload.mm: Upload a symbol file to a HTTP server. The upload is sent as
|
||||
// a multipart/form-data POST request with the following parameters:
|
||||
// code_file: the basename of the module, e.g. "app"
|
||||
// debug_file: the basename of the debugging file, e.g. "app"
|
||||
// debug_identifier: the debug file's identifier, usually consisting of
|
||||
// the guid and age embedded in the pdb, e.g.
|
||||
// "11111111BBBB3333DDDD555555555555F"
|
||||
// os: the operating system that the module was built for
|
||||
// cpu: the CPU that the module was built for (x86 or ppc)
|
||||
// symbol_file: the contents of the breakpad-format symbol file
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "HTTPMultipartUpload.h"
|
||||
#include "HTTPPutRequest.h"
|
||||
#include "SymbolCollectorClient.h"
|
||||
#include "common/mac/dump_syms.h"
|
||||
|
||||
using google_breakpad::DumpSymbols;
|
||||
|
||||
NSString* const kBreakpadSymbolType = @"BREAKPAD";
|
||||
NSString* const kMachOSymbolType = @"MACHO";
|
||||
NSString* const kDSYMSymbolType = @"DSYM";
|
||||
|
||||
typedef enum { kSymUploadProtocolV1, kSymUploadProtocolV2 } SymUploadProtocol;
|
||||
|
||||
typedef enum {
|
||||
kResultSuccess = 0,
|
||||
kResultFailure = 1,
|
||||
kResultAlreadyExists = 2
|
||||
} Result;
|
||||
|
||||
typedef struct {
|
||||
NSString* symbolsPath;
|
||||
NSString* uploadURLStr;
|
||||
SymUploadProtocol symUploadProtocol;
|
||||
NSString* apiKey;
|
||||
BOOL force;
|
||||
Result result;
|
||||
NSString* type;
|
||||
NSString* codeFile;
|
||||
NSString* debugID;
|
||||
NSString* productName;
|
||||
} Options;
|
||||
|
||||
//=============================================================================
|
||||
static NSArray* ModuleDataForSymbolFile(NSString* file) {
|
||||
NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:file];
|
||||
NSData* data = [fh readDataOfLength:1024];
|
||||
NSString* str = [[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSScanner* scanner = [NSScanner scannerWithString:str];
|
||||
NSString* line;
|
||||
NSMutableArray* parts = nil;
|
||||
const int MODULE_ID_INDEX = 3;
|
||||
|
||||
if ([scanner scanUpToString:@"\n" intoString:&line]) {
|
||||
parts = [[NSMutableArray alloc] init];
|
||||
NSScanner* moduleInfoScanner = [NSScanner scannerWithString:line];
|
||||
NSString* moduleInfo;
|
||||
// Get everything BEFORE the module name. None of these properties
|
||||
// can have spaces.
|
||||
for (int i = 0; i <= MODULE_ID_INDEX; i++) {
|
||||
[moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo];
|
||||
[parts addObject:moduleInfo];
|
||||
}
|
||||
|
||||
// Now get the module name. This can have a space so we scan to
|
||||
// the end of the line.
|
||||
[moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo];
|
||||
[parts addObject:moduleInfo];
|
||||
}
|
||||
|
||||
[str release];
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void StartSymUploadProtocolV1(Options* options,
|
||||
NSString* OS,
|
||||
NSString* CPU,
|
||||
NSString* debugID,
|
||||
NSString* debugFile) {
|
||||
NSURL* url = [NSURL URLWithString:options->uploadURLStr];
|
||||
HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url];
|
||||
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
|
||||
|
||||
// Add parameters
|
||||
[parameters setObject:debugID forKey:@"debug_identifier"];
|
||||
[parameters setObject:OS forKey:@"os"];
|
||||
[parameters setObject:CPU forKey:@"cpu"];
|
||||
[parameters setObject:debugFile forKey:@"debug_file"];
|
||||
[parameters setObject:debugFile forKey:@"code_file"];
|
||||
[ul setParameters:parameters];
|
||||
|
||||
NSArray* keys = [parameters allKeys];
|
||||
int count = [keys count];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NSString* key = [keys objectAtIndex:i];
|
||||
NSString* value = [parameters objectForKey:key];
|
||||
fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], [value UTF8String]);
|
||||
}
|
||||
|
||||
// Add file
|
||||
[ul addFileAtPath:options->symbolsPath name:@"symbol_file"];
|
||||
|
||||
// Send it
|
||||
NSError* error = nil;
|
||||
NSData* data = [ul send:&error];
|
||||
NSString* result = [[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding];
|
||||
int status = [[ul response] statusCode];
|
||||
|
||||
fprintf(stdout, "Send: %s\n",
|
||||
error ? [[error description] UTF8String] : "No Error");
|
||||
fprintf(stdout, "Response: %d\n", status);
|
||||
fprintf(stdout, "Result: %lu bytes\n%s\n", (unsigned long)[data length],
|
||||
[result UTF8String]);
|
||||
|
||||
[result release];
|
||||
[ul release];
|
||||
options->result = (!error && status == 200) ? kResultSuccess : kResultFailure;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void StartSymUploadProtocolV2(Options* options,
|
||||
NSString* debugID,
|
||||
NSString* debugFile) {
|
||||
options->result = kResultFailure;
|
||||
|
||||
// Only check status of BREAKPAD symbols, because the v2 protocol doesn't
|
||||
// (yet) have a way to check status of other symbol types.
|
||||
if (!options->force && [options->type isEqualToString:kBreakpadSymbolType]) {
|
||||
SymbolStatus symbolStatus =
|
||||
[SymbolCollectorClient checkSymbolStatusOnServer:options->uploadURLStr
|
||||
withAPIKey:options->apiKey
|
||||
withDebugFile:debugFile
|
||||
withDebugID:debugID];
|
||||
if (symbolStatus == SymbolStatusFound) {
|
||||
fprintf(stdout, "Symbol file already exists, upload aborted."
|
||||
" Use \"-f\" to overwrite.\n");
|
||||
options->result = kResultAlreadyExists;
|
||||
return;
|
||||
} else if (symbolStatus == SymbolStatusUnknown) {
|
||||
fprintf(stdout, "Failed to get check for existing symbol.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UploadURLResponse* URLResponse =
|
||||
[SymbolCollectorClient createUploadURLOnServer:options->uploadURLStr
|
||||
withAPIKey:options->apiKey];
|
||||
if (URLResponse == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSURL* uploadURL = [NSURL URLWithString:[URLResponse uploadURL]];
|
||||
HTTPPutRequest* putRequest = [[HTTPPutRequest alloc] initWithURL:uploadURL];
|
||||
[putRequest setFile:options->symbolsPath];
|
||||
|
||||
NSError* error = nil;
|
||||
NSData* data = [putRequest send:&error];
|
||||
NSString* result = [[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding];
|
||||
int responseCode = [[putRequest response] statusCode];
|
||||
[putRequest release];
|
||||
|
||||
if (error || responseCode != 200) {
|
||||
fprintf(stdout, "Failed to upload symbol file.\n");
|
||||
fprintf(stdout, "Response code: %d\n", responseCode);
|
||||
fprintf(stdout, "Response:\n");
|
||||
fprintf(stdout, "%s\n", [result UTF8String]);
|
||||
return;
|
||||
}
|
||||
|
||||
CompleteUploadResult completeUploadResult =
|
||||
[SymbolCollectorClient completeUploadOnServer:options->uploadURLStr
|
||||
withAPIKey:options->apiKey
|
||||
withUploadKey:[URLResponse uploadKey]
|
||||
withDebugFile:debugFile
|
||||
withDebugID:debugID
|
||||
withType:options->type
|
||||
withProductName:options->productName];
|
||||
[URLResponse release];
|
||||
if (completeUploadResult == CompleteUploadResultError) {
|
||||
fprintf(stdout, "Failed to complete upload.\n");
|
||||
return;
|
||||
} else if (completeUploadResult == CompleteUploadResultDuplicateData) {
|
||||
fprintf(stdout, "Uploaded file checksum matched existing file checksum,"
|
||||
" no change necessary.\n");
|
||||
} else {
|
||||
fprintf(stdout, "Successfully sent the symbol file.\n");
|
||||
}
|
||||
options->result = kResultSuccess;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void Start(Options* options) {
|
||||
// If non-BREAKPAD upload special-case.
|
||||
if (![options->type isEqualToString:kBreakpadSymbolType]) {
|
||||
StartSymUploadProtocolV2(options, options->debugID, options->codeFile);
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray* moduleParts = ModuleDataForSymbolFile(options->symbolsPath);
|
||||
// MODULE <os> <cpu> <uuid> <module-name>
|
||||
// 0 1 2 3 4
|
||||
NSString* OS = [moduleParts objectAtIndex:1];
|
||||
NSString* CPU = [moduleParts objectAtIndex:2];
|
||||
NSMutableString* debugID =
|
||||
[NSMutableString stringWithString:[moduleParts objectAtIndex:3]];
|
||||
[debugID replaceOccurrencesOfString:@"-"
|
||||
withString:@""
|
||||
options:0
|
||||
range:NSMakeRange(0, [debugID length])];
|
||||
NSString* debugFile = [moduleParts objectAtIndex:4];
|
||||
|
||||
if (options->symUploadProtocol == kSymUploadProtocolV1) {
|
||||
StartSymUploadProtocolV1(options, OS, CPU, debugID, debugFile);
|
||||
} else if (options->symUploadProtocol == kSymUploadProtocolV2) {
|
||||
StartSymUploadProtocolV2(options, debugID, debugFile);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void Usage(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Submit symbol information.\n");
|
||||
fprintf(stderr, "Usage: %s [options] <symbol-file> <upload-URL>\n", argv[0]);
|
||||
fprintf(stderr, "<symbol-file> should be created by using the dump_syms "
|
||||
"tool.\n");
|
||||
fprintf(stderr, "<upload-URL> is the destination for the upload.\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "\t-p <protocol>: protocol to use for upload, accepts "
|
||||
"[\"sym-upload-v1\", \"sym-upload-v2\"]. Default is "
|
||||
"\"sym-upload-v1\".\n");
|
||||
fprintf(stderr, "\t-k <api-key>: secret for authentication with upload "
|
||||
"server. [Only in sym-upload-v2 protocol mode]\n");
|
||||
fprintf(stderr, "\t-f: Overwrite symbol file on server if already present. "
|
||||
"[Only in sym-upload-v2 protocol mode]\n");
|
||||
fprintf(
|
||||
stderr,
|
||||
"\t-t: <symbol-type> Explicitly set symbol upload type ("
|
||||
"default is 'breakpad').\n"
|
||||
"\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', "
|
||||
"'dsym', 'pdb'].\n"
|
||||
"\t Note: When this flag is set to anything other than 'breakpad', then "
|
||||
"the '-c' and '-i' flags must also be set.\n");
|
||||
fprintf(stderr, "\t-c: <code-file> Explicitly set 'code_file' for symbol "
|
||||
"upload (basename of executable).\n");
|
||||
fprintf(stderr, "\t-i: <debug-id> Explicitly set 'debug_id' for symbol "
|
||||
"upload (typically build ID of executable). The debug-id for "
|
||||
"symbol-types 'dsym' and 'macho' will be determined "
|
||||
"automatically. \n");
|
||||
fprintf(stderr, "\t-n: <product-name> Optionally set 'product_name' for "
|
||||
"symbol upload\n");
|
||||
fprintf(stderr, "\t-h: Usage\n");
|
||||
fprintf(stderr, "\t-?: Usage\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Exit codes:\n");
|
||||
fprintf(stderr, "\t%d: Success\n", kResultSuccess);
|
||||
fprintf(stderr, "\t%d: Failure\n", kResultFailure);
|
||||
fprintf(stderr,
|
||||
"\t%d: Symbol file already exists on server (and -f was not "
|
||||
"specified).\n",
|
||||
kResultAlreadyExists);
|
||||
fprintf(stderr,
|
||||
"\t [This exit code will only be returned by the sym-upload-v2 "
|
||||
"protocol.\n");
|
||||
fprintf(stderr,
|
||||
"\t The sym-upload-v1 protocol can return either Success or "
|
||||
"Failure\n");
|
||||
fprintf(stderr, "\t in this case, and the action taken by the server is "
|
||||
"unspecified.]\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, " With 'sym-upload-v1':\n");
|
||||
fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, " With 'sym-upload-v2':\n");
|
||||
fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n");
|
||||
fprintf(stderr,
|
||||
" %s -p sym-upload-v2 -k mysecret123! "
|
||||
"path/to/symbol_file http://myuploadserver\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, " [Explicitly set symbol type to 'macho']\n");
|
||||
fprintf(stderr,
|
||||
" %s -p sym-upload-v2 -k mysecret123! -t macho "
|
||||
"-c app -i 11111111BBBB3333DDDD555555555555F "
|
||||
"path/to/symbol_file http://myuploadserver\n",
|
||||
argv[0]);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
static void SetupOptions(int argc, const char* argv[], Options* options) {
|
||||
// Set default options values.
|
||||
options->symUploadProtocol = kSymUploadProtocolV1;
|
||||
options->apiKey = nil;
|
||||
options->type = kBreakpadSymbolType;
|
||||
options->codeFile = nil;
|
||||
options->debugID = nil;
|
||||
options->force = NO;
|
||||
options->productName = nil;
|
||||
|
||||
extern int optind;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:n:hf?")) != -1) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
if (strcmp(optarg, "sym-upload-v2") == 0) {
|
||||
options->symUploadProtocol = kSymUploadProtocolV2;
|
||||
break;
|
||||
} else if (strcmp(optarg, "sym-upload-v1") == 0) {
|
||||
// This is already the default but leave in case that changes.
|
||||
options->symUploadProtocol = kSymUploadProtocolV1;
|
||||
break;
|
||||
}
|
||||
Usage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
case 'k':
|
||||
options->apiKey = [NSString stringWithCString:optarg
|
||||
encoding:NSASCIIStringEncoding];
|
||||
break;
|
||||
case 't': {
|
||||
// This is really an enum, so treat as upper-case for consistency with
|
||||
// enum naming convention on server-side.
|
||||
options->type = [[NSString stringWithCString:optarg
|
||||
encoding:NSASCIIStringEncoding]
|
||||
uppercaseString];
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
options->codeFile = [NSString stringWithCString:optarg
|
||||
encoding:NSASCIIStringEncoding];
|
||||
break;
|
||||
case 'i':
|
||||
options->debugID = [NSString stringWithCString:optarg
|
||||
encoding:NSASCIIStringEncoding];
|
||||
break;
|
||||
case 'n':
|
||||
options->productName =
|
||||
[NSString stringWithCString:optarg
|
||||
encoding:NSASCIIStringEncoding];
|
||||
break;
|
||||
case 'f':
|
||||
options->force = YES;
|
||||
break;
|
||||
default:
|
||||
Usage(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind) != 2) {
|
||||
fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int fd = open(argv[optind], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct stat statbuf;
|
||||
if (fstat(fd, &statbuf) < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
|
||||
close(fd);
|
||||
exit(1);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (!S_ISREG(statbuf.st_mode)) {
|
||||
fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool isBreakpadUpload = [options->type isEqualToString:kBreakpadSymbolType];
|
||||
bool hasCodeFile = options->codeFile != nil;
|
||||
bool hasDebugID = options->debugID != nil;
|
||||
if (isBreakpadUpload && (hasCodeFile || hasDebugID)) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr,
|
||||
"%s: -c and -i should only be specified for non-breakpad "
|
||||
"symbol upload types.\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "\n");
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!isBreakpadUpload && hasCodeFile && !hasDebugID &&
|
||||
([options->type isEqualToString:kMachOSymbolType] ||
|
||||
[options->type isEqualToString:kDSYMSymbolType])) {
|
||||
DumpSymbols dump_symbols(SYMBOLS_AND_FILES | INLINES, false);
|
||||
if (dump_symbols.Read(argv[optind])) {
|
||||
std::string identifier = dump_symbols.Identifier();
|
||||
if (identifier.empty()) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr,
|
||||
"%s: Unable to determine debug-id. Please specify with '-i'.\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "\n");
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
options->debugID = [NSString stringWithUTF8String:identifier.c_str()];
|
||||
hasDebugID = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBreakpadUpload && (!hasCodeFile || !hasDebugID)) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr,
|
||||
"%s: -c and -i must be specified for non-breakpad "
|
||||
"symbol upload types.\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "\n");
|
||||
Usage(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
options->symbolsPath = [NSString stringWithUTF8String:argv[optind]];
|
||||
options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
int main(int argc, const char* argv[]) {
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
Options options;
|
||||
|
||||
bzero(&options, sizeof(Options));
|
||||
SetupOptions(argc, argv, &options);
|
||||
Start(&options);
|
||||
|
||||
[pool release];
|
||||
return options.result;
|
||||
}
|
466
externals/breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
vendored
Normal file
466
externals/breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
vendored
Normal file
|
@ -0,0 +1,466 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 45;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */; };
|
||||
5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */; };
|
||||
5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */; };
|
||||
5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */; };
|
||||
5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */; };
|
||||
5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B97447424D0AA5F000C71F5 /* encoding_util.m */; };
|
||||
8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
|
||||
8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.mm */; settings = {ATTRIBUTES = (); }; };
|
||||
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
|
||||
930DA19225ED543A008558E3 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA19025ED543A008558E3 /* dump_syms.cc */; };
|
||||
930DA22C25ED55A9008558E3 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA21F25ED55A8008558E3 /* module.cc */; };
|
||||
930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */; };
|
||||
930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22525ED55A8008558E3 /* stabs_to_module.cc */; };
|
||||
930DA22F25ED55A9008558E3 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22625ED55A9008558E3 /* language.cc */; };
|
||||
930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */; };
|
||||
930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */; };
|
||||
930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23625ED55B6008558E3 /* stabs_reader.cc */; };
|
||||
930DA24225ED55BF008558E3 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23A25ED55BF008558E3 /* macho_id.cc */; };
|
||||
930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23C25ED55BF008558E3 /* macho_utilities.cc */; };
|
||||
930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23F25ED55BF008558E3 /* macho_reader.cc */; };
|
||||
930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24125ED55BF008558E3 /* macho_walker.cc */; };
|
||||
930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */; };
|
||||
930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */; };
|
||||
930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25225ED56DB008558E3 /* elf_reader.cc */; };
|
||||
930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */; };
|
||||
930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25625ED56DB008558E3 /* dwarf2reader.cc */; };
|
||||
930DA26125ED56DB008558E3 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25925ED56DB008558E3 /* bytereader.cc */; };
|
||||
930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26825ED56FF008558E3 /* test_assembler.cc */; };
|
||||
930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26D25ED571F008558E3 /* arch_utilities.cc */; };
|
||||
930DA27825ED572D008558E3 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27125ED572C008558E3 /* path_helper.cc */; };
|
||||
930DA27925ED572D008558E3 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27525ED572C008558E3 /* file_id.cc */; };
|
||||
930DA27A25ED572D008558E3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27725ED572D008558E3 /* md5.cc */; };
|
||||
9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD836000B0544BA0055103E /* minidump_upload.m */; };
|
||||
9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */; };
|
||||
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; };
|
||||
9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 8;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
08FB7796FE84155DC02AAC07 /* symupload.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = symupload.mm; sourceTree = "<group>"; tabWidth = 2; };
|
||||
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
5B6060BB222716FC0015F0A0 /* HTTPRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../../common/mac/HTTPRequest.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060BC222716FC0015F0A0 /* HTTPRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../../common/mac/HTTPRequest.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../../common/mac/HTTPPutRequest.h; sourceTree = "<group>"; };
|
||||
5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../../common/mac/HTTPPutRequest.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060C22227303A0015F0A0 /* encoding_util.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../../common/mac/encoding_util.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../../common/mac/HTTPGetRequest.h; sourceTree = "<group>"; };
|
||||
5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../../common/mac/HTTPGetRequest.m; sourceTree = "<group>"; };
|
||||
5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../../common/mac/HTTPSimplePostRequest.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../../common/mac/HTTPSimplePostRequest.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../../common/mac/SymbolCollectorClient.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../../common/mac/SymbolCollectorClient.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||
5B97447424D0AA5F000C71F5 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../../common/mac/encoding_util.m; sourceTree = "<group>"; };
|
||||
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
|
||||
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
|
||||
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
|
||||
8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
930DA19025ED543A008558E3 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = "<group>"; };
|
||||
930DA19125ED543A008558E3 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = "<group>"; };
|
||||
930DA21F25ED55A8008558E3 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = "<group>"; };
|
||||
930DA22025ED55A8008558E3 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = "<group>"; };
|
||||
930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = "<group>"; };
|
||||
930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = "<group>"; };
|
||||
930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = "<group>"; };
|
||||
930DA22425ED55A8008558E3 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = "<group>"; };
|
||||
930DA22525ED55A8008558E3 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = "<group>"; };
|
||||
930DA22625ED55A9008558E3 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = "<group>"; };
|
||||
930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = "<group>"; };
|
||||
930DA22825ED55A9008558E3 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = "<group>"; };
|
||||
930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = "<group>"; };
|
||||
930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = "<group>"; };
|
||||
930DA23525ED55B6008558E3 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = "<group>"; };
|
||||
930DA23625ED55B6008558E3 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = "<group>"; };
|
||||
930DA23A25ED55BF008558E3 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = "<group>"; };
|
||||
930DA23B25ED55BF008558E3 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = "<group>"; };
|
||||
930DA23C25ED55BF008558E3 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = "<group>"; };
|
||||
930DA23D25ED55BF008558E3 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = "<group>"; };
|
||||
930DA23E25ED55BF008558E3 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = "<group>"; };
|
||||
930DA23F25ED55BF008558E3 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = "<group>"; };
|
||||
930DA24025ED55BF008558E3 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = "<group>"; };
|
||||
930DA24125ED55BF008558E3 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = "<group>"; };
|
||||
930DA24C25ED56DB008558E3 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = "<group>"; };
|
||||
930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_range_list_handler.cc; path = ../../../common/dwarf_range_list_handler.cc; sourceTree = "<group>"; };
|
||||
930DA24E25ED56DB008558E3 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = "<group>"; };
|
||||
930DA24F25ED56DB008558E3 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = "<group>"; };
|
||||
930DA25025ED56DB008558E3 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = "<group>"; };
|
||||
930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_range_list_handler.h; path = ../../../common/dwarf_range_list_handler.h; sourceTree = "<group>"; };
|
||||
930DA25225ED56DB008558E3 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; };
|
||||
930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = "<group>"; };
|
||||
930DA25425ED56DB008558E3 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; };
|
||||
930DA25525ED56DB008558E3 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = "<group>"; };
|
||||
930DA25625ED56DB008558E3 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = "<group>"; };
|
||||
930DA25725ED56DB008558E3 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = "<group>"; };
|
||||
930DA25825ED56DB008558E3 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = "<group>"; };
|
||||
930DA25925ED56DB008558E3 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = "<group>"; };
|
||||
930DA25A25ED56DB008558E3 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = "<group>"; };
|
||||
930DA26725ED56FF008558E3 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = "<group>"; };
|
||||
930DA26825ED56FF008558E3 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = "<group>"; };
|
||||
930DA26C25ED571F008558E3 /* arch_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
|
||||
930DA26D25ED571F008558E3 /* arch_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
|
||||
930DA27125ED572C008558E3 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; };
|
||||
930DA27225ED572C008558E3 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = "<group>"; };
|
||||
930DA27325ED572C008558E3 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; };
|
||||
930DA27425ED572C008558E3 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = "<group>"; };
|
||||
930DA27525ED572C008558E3 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = "<group>"; };
|
||||
930DA27625ED572C008558E3 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = "<group>"; };
|
||||
930DA27725ED572D008558E3 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = md5.cc; path = ../../../common/md5.cc; sourceTree = "<group>"; };
|
||||
9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||
9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../../common/mac/minidump_upload.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
9BD835F90B0544950055103E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
08FB7794FE84155DC02AAC07 /* symupload */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
930DA21E25ED5586008558E3 /* dump_syms */,
|
||||
5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */,
|
||||
5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */,
|
||||
5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */,
|
||||
5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */,
|
||||
5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */,
|
||||
5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */,
|
||||
5B6060C22227303A0015F0A0 /* encoding_util.h */,
|
||||
5B97447424D0AA5F000C71F5 /* encoding_util.m */,
|
||||
5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */,
|
||||
5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */,
|
||||
5B6060BB222716FC0015F0A0 /* HTTPRequest.h */,
|
||||
5B6060BC222716FC0015F0A0 /* HTTPRequest.m */,
|
||||
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */,
|
||||
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */,
|
||||
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */,
|
||||
08FB7796FE84155DC02AAC07 /* symupload.mm */,
|
||||
9BD836000B0544BA0055103E /* minidump_upload.m */,
|
||||
9BD833680B03E4080055103E /* HTTPMultipartUpload.h */,
|
||||
9BD833690B03E4080055103E /* HTTPMultipartUpload.m */,
|
||||
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
);
|
||||
name = symupload;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
08FB779EFE84155DC02AAC07 /* Foundation.framework */,
|
||||
);
|
||||
name = "External Frameworks and Libraries";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DD76FA10486AA7600D96B5E /* symupload */,
|
||||
9BD835FB0B0544950055103E /* minidump_upload */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
930DA21E25ED5586008558E3 /* dump_syms */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
930DA23A25ED55BF008558E3 /* macho_id.cc */,
|
||||
930DA23B25ED55BF008558E3 /* macho_id.h */,
|
||||
930DA23F25ED55BF008558E3 /* macho_reader.cc */,
|
||||
930DA23E25ED55BF008558E3 /* macho_reader.h */,
|
||||
930DA23C25ED55BF008558E3 /* macho_utilities.cc */,
|
||||
930DA24025ED55BF008558E3 /* macho_utilities.h */,
|
||||
930DA24125ED55BF008558E3 /* macho_walker.cc */,
|
||||
930DA23D25ED55BF008558E3 /* macho_walker.h */,
|
||||
930DA19025ED543A008558E3 /* dump_syms.cc */,
|
||||
930DA19125ED543A008558E3 /* dump_syms.h */,
|
||||
930DA23625ED55B6008558E3 /* stabs_reader.cc */,
|
||||
930DA23525ED55B6008558E3 /* stabs_reader.h */,
|
||||
930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */,
|
||||
930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */,
|
||||
930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */,
|
||||
930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */,
|
||||
930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */,
|
||||
930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */,
|
||||
930DA22625ED55A9008558E3 /* language.cc */,
|
||||
930DA22425ED55A8008558E3 /* language.h */,
|
||||
930DA21F25ED55A8008558E3 /* module.cc */,
|
||||
930DA22025ED55A8008558E3 /* module.h */,
|
||||
930DA22525ED55A8008558E3 /* stabs_to_module.cc */,
|
||||
930DA22825ED55A9008558E3 /* stabs_to_module.h */,
|
||||
930DA25025ED56DB008558E3 /* bytereader-inl.h */,
|
||||
930DA25925ED56DB008558E3 /* bytereader.cc */,
|
||||
930DA25525ED56DB008558E3 /* bytereader.h */,
|
||||
930DA24E25ED56DB008558E3 /* cfi_assembler.cc */,
|
||||
930DA25A25ED56DB008558E3 /* cfi_assembler.h */,
|
||||
930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */,
|
||||
930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */,
|
||||
930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */,
|
||||
930DA25825ED56DB008558E3 /* dwarf2diehandler.h */,
|
||||
930DA24F25ED56DB008558E3 /* dwarf2enums.h */,
|
||||
930DA25625ED56DB008558E3 /* dwarf2reader.cc */,
|
||||
930DA25725ED56DB008558E3 /* dwarf2reader.h */,
|
||||
930DA25225ED56DB008558E3 /* elf_reader.cc */,
|
||||
930DA25425ED56DB008558E3 /* elf_reader.h */,
|
||||
930DA24C25ED56DB008558E3 /* line_state_machine.h */,
|
||||
930DA26825ED56FF008558E3 /* test_assembler.cc */,
|
||||
930DA26725ED56FF008558E3 /* test_assembler.h */,
|
||||
930DA26D25ED571F008558E3 /* arch_utilities.cc */,
|
||||
930DA26C25ED571F008558E3 /* arch_utilities.h */,
|
||||
930DA27425ED572C008558E3 /* byte_cursor.h */,
|
||||
930DA27225ED572C008558E3 /* byteswap.h */,
|
||||
930DA27525ED572C008558E3 /* file_id.cc */,
|
||||
930DA27625ED572C008558E3 /* file_id.h */,
|
||||
930DA27725ED572D008558E3 /* md5.cc */,
|
||||
930DA27125ED572C008558E3 /* path_helper.cc */,
|
||||
930DA27325ED572C008558E3 /* path_helper.h */,
|
||||
);
|
||||
name = dump_syms;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8DD76F960486AA7600D96B5E /* symupload */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */;
|
||||
buildPhases = (
|
||||
8DD76F990486AA7600D96B5E /* Sources */,
|
||||
8DD76F9B0486AA7600D96B5E /* Frameworks */,
|
||||
8DD76F9E0486AA7600D96B5E /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = symupload;
|
||||
productInstallPath = "$(HOME)/bin";
|
||||
productName = symupload;
|
||||
productReference = 8DD76FA10486AA7600D96B5E /* symupload */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
9BD835FA0B0544950055103E /* minidump_upload */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */;
|
||||
buildPhases = (
|
||||
9BD835F80B0544950055103E /* Sources */,
|
||||
9BD835F90B0544950055103E /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = minidump_upload;
|
||||
productName = minidump_upload;
|
||||
productReference = 9BD835FB0B0544950055103E /* minidump_upload */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
};
|
||||
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8DD76F960486AA7600D96B5E /* symupload */,
|
||||
9BD835FA0B0544950055103E /* minidump_upload */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8DD76F990486AA7600D96B5E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */,
|
||||
930DA19225ED543A008558E3 /* dump_syms.cc in Sources */,
|
||||
930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */,
|
||||
930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */,
|
||||
5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */,
|
||||
930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */,
|
||||
930DA27825ED572D008558E3 /* path_helper.cc in Sources */,
|
||||
930DA27A25ED572D008558E3 /* md5.cc in Sources */,
|
||||
930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */,
|
||||
930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */,
|
||||
930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */,
|
||||
5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */,
|
||||
5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */,
|
||||
930DA27925ED572D008558E3 /* file_id.cc in Sources */,
|
||||
930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */,
|
||||
930DA22F25ED55A9008558E3 /* language.cc in Sources */,
|
||||
930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */,
|
||||
930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */,
|
||||
930DA24225ED55BF008558E3 /* macho_id.cc in Sources */,
|
||||
5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */,
|
||||
930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */,
|
||||
5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */,
|
||||
930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */,
|
||||
930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */,
|
||||
930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */,
|
||||
930DA26125ED56DB008558E3 /* bytereader.cc in Sources */,
|
||||
930DA22C25ED55A9008558E3 /* module.cc in Sources */,
|
||||
5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */,
|
||||
930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */,
|
||||
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */,
|
||||
930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
9BD835F80B0544950055103E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */,
|
||||
9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB927508733DD40010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../..,
|
||||
../../../common/mac/include,
|
||||
../../../third_party/musl/include/,
|
||||
);
|
||||
PRODUCT_NAME = symupload;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB927608733DD40010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
NDEBUG,
|
||||
HAVE_MACH_O_NLIST_H,
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../..,
|
||||
../../../common/mac/include,
|
||||
../../../third_party/musl/include/,
|
||||
);
|
||||
PRODUCT_NAME = symupload;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1DEB927908733DD40010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB927A08733DD40010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
9BD836030B0544BB0055103E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = ../../..;
|
||||
PRODUCT_NAME = minidump_upload;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
9BD836040B0544BB0055103E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = ../../..;
|
||||
PRODUCT_NAME = minidump_upload;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB927508733DD40010E9CD /* Debug */,
|
||||
1DEB927608733DD40010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB927908733DD40010E9CD /* Debug */,
|
||||
1DEB927A08733DD40010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9BD836030B0544BB0055103E /* Debug */,
|
||||
9BD836040B0544BB0055103E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||
}
|
66
externals/breakpad/src/tools/mac/upload_system_symbols/arch_constants.h
vendored
Normal file
66
externals/breakpad/src/tools/mac/upload_system_symbols/arch_constants.h
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* Copyright 2014 Google LLC
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <mach-o/arch.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach/machine.h>
|
||||
|
||||
// Go/Cgo does not support #define constants, so turn them into symbols
|
||||
// that are reachable from Go.
|
||||
|
||||
#ifndef CPU_TYPE_ARM64
|
||||
#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
|
||||
#endif
|
||||
|
||||
#ifndef CPU_SUBTYPE_ARM64_ALL
|
||||
#define CPU_SUBTYPE_ARM64_ALL 0
|
||||
#endif
|
||||
|
||||
#ifndef CPU_SUBTYPE_ARM64_E
|
||||
#define CPU_SUBTYPE_ARM64_E 2
|
||||
#endif
|
||||
|
||||
const cpu_type_t kCPU_TYPE_ARM = CPU_TYPE_ARM;
|
||||
const cpu_type_t kCPU_TYPE_ARM64 = CPU_TYPE_ARM64;
|
||||
|
||||
const cpu_subtype_t kCPU_SUBTYPE_ARM64_ALL = CPU_SUBTYPE_ARM64_ALL;
|
||||
const cpu_subtype_t kCPU_SUBTYPE_ARM64_E = CPU_SUBTYPE_ARM64_E;
|
||||
const cpu_subtype_t kCPU_SUBTYPE_ARM_V7S = CPU_SUBTYPE_ARM_V7S;
|
||||
|
||||
const char* GetNXArchInfoName(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
|
||||
const NXArchInfo* arch_info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
|
||||
if (!arch_info)
|
||||
return 0;
|
||||
return arch_info->name;
|
||||
}
|
||||
|
||||
const uint32_t kMachHeaderFtypeDylib = MH_DYLIB;
|
||||
const uint32_t kMachHeaderFtypeBundle = MH_BUNDLE;
|
||||
const uint32_t kMachHeaderFtypeExe = MH_EXECUTE;
|
||||
const uint32_t kMachHeaderFtypeDylinker = MH_DYLINKER;
|
68
externals/breakpad/src/tools/mac/upload_system_symbols/arch_reader.go
vendored
Normal file
68
externals/breakpad/src/tools/mac/upload_system_symbols/arch_reader.go
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* Copyright 2014 Google LLC
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/macho"
|
||||
)
|
||||
|
||||
/*
|
||||
#include "arch_constants.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// getArchStringFromHeader takes a MachO FileHeader and returns a string that
|
||||
// represents the CPU type and subtype.
|
||||
// This function is a Go version of src/common/mac/arch_utilities.cc:BreakpadGetArchInfoFromCpuType().
|
||||
func getArchStringFromHeader(header macho.FileHeader) string {
|
||||
// TODO(rsesek): As of 10.9.4, OS X doesn't list these in /usr/include/mach/machine.h.
|
||||
if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_ALL {
|
||||
return "arm64"
|
||||
}
|
||||
if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_E {
|
||||
return "arm64e"
|
||||
}
|
||||
if header.Cpu == C.kCPU_TYPE_ARM && header.SubCpu == C.kCPU_SUBTYPE_ARM_V7S {
|
||||
return "armv7s"
|
||||
}
|
||||
|
||||
cstr := C.GetNXArchInfoName(C.cpu_type_t(header.Cpu), C.cpu_subtype_t(header.SubCpu))
|
||||
if cstr == nil {
|
||||
return ""
|
||||
}
|
||||
return C.GoString(cstr)
|
||||
}
|
||||
|
||||
const (
|
||||
MachODylib macho.Type = C.kMachHeaderFtypeDylib
|
||||
MachOBundle = C.kMachHeaderFtypeBundle
|
||||
MachOExe = C.kMachHeaderFtypeExe
|
||||
MachODylinker = C.kMachHeaderFtypeDylinker
|
||||
)
|
3
externals/breakpad/src/tools/mac/upload_system_symbols/go.mod
vendored
Normal file
3
externals/breakpad/src/tools/mac/upload_system_symbols/go.mod
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
module upload_system_symbols
|
||||
|
||||
go 1.17
|
484
externals/breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go
vendored
Normal file
484
externals/breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go
vendored
Normal file
|
@ -0,0 +1,484 @@
|
|||
/* Copyright 2014 Google LLC
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Tool upload_system_symbols generates and uploads Breakpad symbol files for OS X system libraries.
|
||||
|
||||
This tool shells out to the dump_syms and symupload Breakpad tools. In its default mode, this
|
||||
will find all dynamic libraries on the system, run dump_syms to create the Breakpad symbol files,
|
||||
and then upload them to Google's crash infrastructure.
|
||||
|
||||
The tool can also be used to only dump libraries or upload from a directory. See -help for more
|
||||
information.
|
||||
|
||||
Both i386 and x86_64 architectures will be dumped and uploaded.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/macho"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.")
|
||||
uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.")
|
||||
dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.")
|
||||
systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.")
|
||||
dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.")
|
||||
apiKey = flag.String("api-key", "", "API key to use. If this is present, the `sym-upload-v2` protocol is used.\nSee https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs/sym_upload_v2_protocol.md or\n`symupload`'s help for more information.")
|
||||
)
|
||||
|
||||
var (
|
||||
// pathsToScan are the subpaths in the systemRoot that should be scanned for shared libraries.
|
||||
pathsToScan = []string{
|
||||
"/System/Library/Frameworks",
|
||||
"/System/Library/PrivateFrameworks",
|
||||
"/usr/lib",
|
||||
}
|
||||
|
||||
// optionalPathsToScan is just like pathsToScan, but the paths are permitted to be absent.
|
||||
optionalPathsToScan = []string{
|
||||
// Gone in 10.15.
|
||||
"/Library/QuickTime",
|
||||
// Not present in dumped dyld_shared_caches
|
||||
"/System/Library/Components",
|
||||
}
|
||||
|
||||
// uploadServersV1 are the list of servers to which symbols should be
|
||||
// uploaded when using the V1 protocol.
|
||||
uploadServersV1 = []string{
|
||||
"https://clients2.google.com/cr/symbol",
|
||||
"https://clients2.google.com/cr/staging_symbol",
|
||||
}
|
||||
// uploadServersV2 are the list of servers to which symbols should be
|
||||
// uploaded when using the V2 protocol.
|
||||
uploadServersV2 = []string{
|
||||
"https://staging-crashsymbolcollector-pa.googleapis.com",
|
||||
"https://prod-crashsymbolcollector-pa.googleapis.com",
|
||||
}
|
||||
|
||||
// uploadServers are the list of servers that should be used, accounting
|
||||
// for whether v1 or v2 protocol is used.
|
||||
uploadServers = uploadServersV1
|
||||
|
||||
// blacklistRegexps match paths that should be excluded from dumping.
|
||||
blacklistRegexps = []*regexp.Regexp{
|
||||
regexp.MustCompile(`/System/Library/Frameworks/Python\.framework/`),
|
||||
regexp.MustCompile(`/System/Library/Frameworks/Ruby\.framework/`),
|
||||
regexp.MustCompile(`_profile\.dylib$`),
|
||||
regexp.MustCompile(`_debug\.dylib$`),
|
||||
regexp.MustCompile(`\.a$`),
|
||||
regexp.MustCompile(`\.dat$`),
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
log.SetFlags(0)
|
||||
|
||||
// If `apiKey` is set, we're using the v2 protocol.
|
||||
if len(*apiKey) > 0 {
|
||||
uploadServers = uploadServersV2
|
||||
}
|
||||
|
||||
var uq *UploadQueue
|
||||
|
||||
if *uploadOnlyPath != "" {
|
||||
// -upload-from specified, so handle that case early.
|
||||
uq = StartUploadQueue()
|
||||
uploadFromDirectory(*uploadOnlyPath, uq)
|
||||
uq.Wait()
|
||||
return
|
||||
}
|
||||
|
||||
if *systemRoot == "" {
|
||||
log.Fatal("Need a -system-root to dump symbols for")
|
||||
}
|
||||
|
||||
if *dumpOnlyPath != "" {
|
||||
// -dump-to specified, so make sure that the path is a directory.
|
||||
if fi, err := os.Stat(*dumpOnlyPath); err != nil {
|
||||
log.Fatalf("-dump-to location: %v", err)
|
||||
} else if !fi.IsDir() {
|
||||
log.Fatal("-dump-to location is not a directory")
|
||||
}
|
||||
}
|
||||
|
||||
dumpPath := *dumpOnlyPath
|
||||
if *dumpOnlyPath == "" {
|
||||
// If -dump-to was not specified, then run the upload pipeline and create
|
||||
// a temporary dump output directory.
|
||||
uq = StartUploadQueue()
|
||||
|
||||
if p, err := ioutil.TempDir("", "upload_system_symbols"); err != nil {
|
||||
log.Fatalf("Failed to create temporary directory: %v", err)
|
||||
} else {
|
||||
dumpPath = p
|
||||
defer os.RemoveAll(p)
|
||||
}
|
||||
}
|
||||
|
||||
dq := StartDumpQueue(*systemRoot, dumpPath, uq)
|
||||
dq.Wait()
|
||||
if uq != nil {
|
||||
uq.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// manglePath reduces an absolute filesystem path to a string suitable as the
|
||||
// base for a file name which encodes some of the original path. The result
|
||||
// concatenates the leading initial from each path component except the last to
|
||||
// the last path component; for example /System/Library/Frameworks/AppKit
|
||||
// becomes SLFAppKit.
|
||||
// Assumes ASCII.
|
||||
func manglePath(path string) string {
|
||||
components := strings.Split(path, "/")
|
||||
n := len(components)
|
||||
builder := strings.Builder{}
|
||||
for i, component := range components {
|
||||
if len(component) == 0 {
|
||||
continue
|
||||
}
|
||||
if i < n-1 {
|
||||
builder.WriteString(component[:1])
|
||||
} else {
|
||||
builder.WriteString(component)
|
||||
}
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type WorkerPool struct {
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// StartWorkerPool will launch numWorkers goroutines all running workerFunc.
|
||||
// When workerFunc exits, the goroutine will terminate.
|
||||
func StartWorkerPool(numWorkers int, workerFunc func()) *WorkerPool {
|
||||
p := new(WorkerPool)
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
p.wg.Add(1)
|
||||
go func() {
|
||||
workerFunc()
|
||||
p.wg.Done()
|
||||
}()
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Wait for all the workers in the pool to complete the workerFunc.
|
||||
func (p *WorkerPool) Wait() {
|
||||
p.wg.Wait()
|
||||
}
|
||||
|
||||
type UploadQueue struct {
|
||||
*WorkerPool
|
||||
queue chan string
|
||||
}
|
||||
|
||||
// StartUploadQueue creates a new worker pool and queue, to which paths to
|
||||
// Breakpad symbol files may be sent for uploading.
|
||||
func StartUploadQueue() *UploadQueue {
|
||||
uq := &UploadQueue{
|
||||
queue: make(chan string, 10),
|
||||
}
|
||||
uq.WorkerPool = StartWorkerPool(5, uq.worker)
|
||||
return uq
|
||||
}
|
||||
|
||||
// Upload enqueues the contents of filepath to be uploaded.
|
||||
func (uq *UploadQueue) Upload(filepath string) {
|
||||
uq.queue <- filepath
|
||||
}
|
||||
|
||||
// Done tells the queue that no more files need to be uploaded. This must be
|
||||
// called before WorkerPool.Wait.
|
||||
func (uq *UploadQueue) Done() {
|
||||
close(uq.queue)
|
||||
}
|
||||
|
||||
func (uq *UploadQueue) runSymUpload(symfile, server string) *exec.Cmd {
|
||||
symUpload := path.Join(*breakpadTools, "symupload")
|
||||
args := []string{symfile, server}
|
||||
if len(*apiKey) > 0 {
|
||||
args = append([]string{"-p", "sym-upload-v2", "-k", *apiKey}, args...)
|
||||
}
|
||||
return exec.Command(symUpload, args...)
|
||||
}
|
||||
|
||||
func (uq *UploadQueue) worker() {
|
||||
for symfile := range uq.queue {
|
||||
for _, server := range uploadServers {
|
||||
for i := 0; i < 3; i++ { // Give each upload 3 attempts to succeed.
|
||||
cmd := uq.runSymUpload(symfile, server)
|
||||
if output, err := cmd.Output(); err == nil {
|
||||
// Success. No retry needed.
|
||||
fmt.Printf("Uploaded %s to %s\n", symfile, server)
|
||||
break
|
||||
} else if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == 2 && *apiKey != "" {
|
||||
// Exit code 2 in protocol v2 means the file already exists on the server.
|
||||
// No point retrying.
|
||||
fmt.Printf("File %s already exists on %s\n", symfile, server)
|
||||
break
|
||||
} else {
|
||||
log.Printf("Error running symupload(%s, %s), attempt %d: %v: %s\n", symfile, server, i, err, output)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type DumpQueue struct {
|
||||
*WorkerPool
|
||||
dumpPath string
|
||||
queue chan dumpRequest
|
||||
uq *UploadQueue
|
||||
}
|
||||
|
||||
type dumpRequest struct {
|
||||
path string
|
||||
arch string
|
||||
}
|
||||
|
||||
// StartDumpQueue creates a new worker pool to find all the Mach-O libraries in
|
||||
// root and dump their symbols to dumpPath. If an UploadQueue is passed, the
|
||||
// path to the symbol file will be enqueued there, too.
|
||||
func StartDumpQueue(root, dumpPath string, uq *UploadQueue) *DumpQueue {
|
||||
dq := &DumpQueue{
|
||||
dumpPath: dumpPath,
|
||||
queue: make(chan dumpRequest),
|
||||
uq: uq,
|
||||
}
|
||||
dq.WorkerPool = StartWorkerPool(12, dq.worker)
|
||||
|
||||
findLibsInRoot(root, dq)
|
||||
|
||||
return dq
|
||||
}
|
||||
|
||||
// DumpSymbols enqueues the filepath to have its symbols dumped in the specified
|
||||
// architecture.
|
||||
func (dq *DumpQueue) DumpSymbols(filepath string, arch string) {
|
||||
dq.queue <- dumpRequest{
|
||||
path: filepath,
|
||||
arch: arch,
|
||||
}
|
||||
}
|
||||
|
||||
func (dq *DumpQueue) Wait() {
|
||||
dq.WorkerPool.Wait()
|
||||
if dq.uq != nil {
|
||||
dq.uq.Done()
|
||||
}
|
||||
}
|
||||
|
||||
func (dq *DumpQueue) done() {
|
||||
close(dq.queue)
|
||||
}
|
||||
|
||||
func (dq *DumpQueue) worker() {
|
||||
dumpSyms := path.Join(*breakpadTools, "dump_syms")
|
||||
|
||||
for req := range dq.queue {
|
||||
filebase := path.Join(dq.dumpPath, manglePath(req.path))
|
||||
symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch)
|
||||
f, err := os.Create(symfile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating symbol file: %v", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(dumpSyms, "-a", req.arch, req.path)
|
||||
cmd.Stdout = f
|
||||
err = cmd.Run()
|
||||
f.Close()
|
||||
|
||||
if err != nil {
|
||||
os.Remove(symfile)
|
||||
log.Printf("Error running dump_syms(%s, %s): %v\n", req.arch, req.path, err)
|
||||
} else if dq.uq != nil {
|
||||
dq.uq.Upload(symfile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// uploadFromDirectory handles the upload-only case and merely uploads all files in
|
||||
// a directory.
|
||||
func uploadFromDirectory(directory string, uq *UploadQueue) {
|
||||
d, err := os.Open(directory)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not open directory to upload: %v", err)
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
entries, err := d.Readdirnames(0)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not read directory: %v", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
uq.Upload(path.Join(directory, entry))
|
||||
}
|
||||
|
||||
uq.Done()
|
||||
}
|
||||
|
||||
// findQueue is an implementation detail of the DumpQueue that finds all the
|
||||
// Mach-O files and their architectures.
|
||||
type findQueue struct {
|
||||
*WorkerPool
|
||||
queue chan string
|
||||
dq *DumpQueue
|
||||
}
|
||||
|
||||
// findLibsInRoot looks in all the pathsToScan in the root and manages the
|
||||
// interaction between findQueue and DumpQueue.
|
||||
func findLibsInRoot(root string, dq *DumpQueue) {
|
||||
fq := &findQueue{
|
||||
queue: make(chan string, 10),
|
||||
dq: dq,
|
||||
}
|
||||
fq.WorkerPool = StartWorkerPool(12, fq.worker)
|
||||
|
||||
for _, p := range pathsToScan {
|
||||
fq.findLibsInPath(path.Join(root, p), true)
|
||||
}
|
||||
|
||||
for _, p := range optionalPathsToScan {
|
||||
fq.findLibsInPath(path.Join(root, p), false)
|
||||
}
|
||||
|
||||
close(fq.queue)
|
||||
fq.Wait()
|
||||
dq.done()
|
||||
}
|
||||
|
||||
// findLibsInPath recursively walks the directory tree, sending file paths to
|
||||
// test for being Mach-O to the findQueue.
|
||||
func (fq *findQueue) findLibsInPath(loc string, mustExist bool) {
|
||||
d, err := os.Open(loc)
|
||||
if err != nil {
|
||||
if !mustExist && os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
log.Fatalf("Could not open %s: %v", loc, err)
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
for {
|
||||
fis, err := d.Readdir(100)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Fatalf("Error reading directory %s: %v", loc, err)
|
||||
}
|
||||
|
||||
for _, fi := range fis {
|
||||
fp := path.Join(loc, fi.Name())
|
||||
if fi.IsDir() {
|
||||
fq.findLibsInPath(fp, true)
|
||||
continue
|
||||
} else if fi.Mode()&os.ModeSymlink != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Test the blacklist in the worker to not slow down this main loop.
|
||||
|
||||
fq.queue <- fp
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fq *findQueue) worker() {
|
||||
for fp := range fq.queue {
|
||||
blacklisted := false
|
||||
for _, re := range blacklistRegexps {
|
||||
blacklisted = blacklisted || re.MatchString(fp)
|
||||
}
|
||||
if blacklisted {
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := os.Open(fp)
|
||||
if err != nil {
|
||||
log.Printf("%s: %v", fp, err)
|
||||
continue
|
||||
}
|
||||
|
||||
fatFile, err := macho.NewFatFile(f)
|
||||
if err == nil {
|
||||
// The file is fat, so dump its architectures.
|
||||
for _, fatArch := range fatFile.Arches {
|
||||
fq.dumpMachOFile(fp, fatArch.File)
|
||||
}
|
||||
fatFile.Close()
|
||||
} else if err == macho.ErrNotFat {
|
||||
// The file isn't fat but may still be MachO.
|
||||
thinFile, err := macho.NewFile(f)
|
||||
if err != nil {
|
||||
log.Printf("%s: %v", fp, err)
|
||||
continue
|
||||
}
|
||||
fq.dumpMachOFile(fp, thinFile)
|
||||
thinFile.Close()
|
||||
} else {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) {
|
||||
if image.Type != MachODylib && image.Type != MachOBundle && image.Type != MachODylinker {
|
||||
return
|
||||
}
|
||||
|
||||
arch := getArchStringFromHeader(image.FileHeader)
|
||||
if arch == "" {
|
||||
// Don't know about this architecture type.
|
||||
return
|
||||
}
|
||||
|
||||
if (*dumpArchitecture != "" && *dumpArchitecture == arch) || *dumpArchitecture == "" {
|
||||
fq.dq.DumpSymbols(fp, arch)
|
||||
}
|
||||
}
|
114
externals/breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.sh
vendored
Executable file
114
externals/breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.sh
vendored
Executable file
|
@ -0,0 +1,114 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2023 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Finds the dyld_shared_cache on a system, extracts it, and dumps the symbols
|
||||
# in Breakpad format to the directory passed as the first argument
|
||||
# The script must be in the same directory as `dump_syms`,
|
||||
# `upload_system_symbols` and `dsc_extractor` binaries.
|
||||
# Exits with 0 if all supported architectures for this OS version were found and
|
||||
# dumped, and nonzero otherwise.
|
||||
|
||||
set -ex
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "usage: $0 <destination_directory>" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
destination_dir="$1"
|
||||
|
||||
dir="$(dirname "$0")"
|
||||
dir="$(cd "${dir}"; pwd)"
|
||||
major_version=$(sw_vers -productVersion | cut -d . -f 1)
|
||||
if [[ "${major_version}" -lt 13 ]]; then
|
||||
dsc_directory="/System/Library/dyld"
|
||||
else
|
||||
dsc_directory="/System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld"
|
||||
fi
|
||||
|
||||
working_dir=$(mktemp -d)
|
||||
mkdir "${destination_dir}"
|
||||
trap 'rm -rf "${working_dir}" "${destination_dir}"' EXIT
|
||||
|
||||
architectures=(x86_64h)
|
||||
missing_architectures=()
|
||||
# macOS >= 13 on arm64 still has a x86_64 cache for Rosetta.
|
||||
if [[ "${major_version}" -lt 13 ]] || [[ $(uname -p) == "arm" ]]; then
|
||||
architectures+=( x86_64 )
|
||||
fi
|
||||
if [[ "${major_version}" -ge 11 ]]; then
|
||||
architectures+=( arm64e )
|
||||
fi
|
||||
|
||||
for arch in "${architectures[@]}"; do
|
||||
cache="${dsc_directory}/dyld_shared_cache_${arch}"
|
||||
if [[ ! -f "${cache}" ]]; then
|
||||
missing_architectures+=("${arch}")
|
||||
continue
|
||||
fi
|
||||
"${dir}/dsc_extractor" \
|
||||
"${cache}" \
|
||||
"${working_dir}/${arch}"
|
||||
"${dir}/upload_system_symbols" \
|
||||
--breakpad-tools="${dir}" \
|
||||
--system-root="${working_dir}/${arch}" \
|
||||
--dump-to="${destination_dir}"
|
||||
done
|
||||
if [[ "${#missing_architectures[@]}" -eq "${#architectures[@]}" ]]; then
|
||||
echo "Couldn't locate dyld_shared_cache for any architectures" >& 2
|
||||
echo "in ${dsc_directory}. Exiting." >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "${working_dir}"
|
||||
# We have results now, so let's keep `destination_dir`.
|
||||
trap '' EXIT
|
||||
|
||||
"${dir}/upload_system_symbols" \
|
||||
--breakpad-tools="${dir}" \
|
||||
--system-root=/ \
|
||||
--dump-to="${destination_dir}"
|
||||
|
||||
set +x
|
||||
echo
|
||||
echo "Dumped!"
|
||||
echo "To upload, run:"
|
||||
echo
|
||||
echo "'${dir}/upload_system_symbols'" \\
|
||||
echo " --breakpad-tools='${dir}'" \\
|
||||
echo " --api-key=<YOUR API KEY>" \\
|
||||
echo " --upload-from='${destination_dir}'"
|
||||
|
||||
if [[ "${#missing_architectures[@]}" -gt 0 ]]; then
|
||||
echo "dyld_shared_cache not found for architecture(s):" >& 2
|
||||
echo " " "${missing_architectures[@]}" >& 2
|
||||
echo "You'll need to get symbols for them elsewhere." >& 2
|
||||
exit 1
|
||||
fi
|
165
externals/breakpad/src/tools/python/deps-to-manifest.py
vendored
Executable file
165
externals/breakpad/src/tools/python/deps-to-manifest.py
vendored
Executable file
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright 2016 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Convert gclient's DEPS file to repo's manifest xml file."""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
REMOTES = {
|
||||
'chromium': 'https://chromium.googlesource.com/',
|
||||
'github': 'https://github.com/',
|
||||
}
|
||||
REVIEWS = {
|
||||
'chromium': 'https://chromium-review.googlesource.com',
|
||||
}
|
||||
|
||||
MANIFEST_HEAD = """<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- AUTOGENERATED BY %(prog)s; DO NOT EDIT -->
|
||||
<manifest>
|
||||
|
||||
<default revision='refs/heads/main'
|
||||
remote='chromium'
|
||||
sync-c='true'
|
||||
sync-j='8' />
|
||||
"""
|
||||
|
||||
MANIFEST_REMOTE = """
|
||||
<remote name='%(name)s'
|
||||
fetch='%(fetch)s'
|
||||
review='%(review)s' />
|
||||
"""
|
||||
|
||||
MANIFEST_PROJECT = """
|
||||
<project path='%(path)s'
|
||||
name='%(name)s'
|
||||
revision='%(revision)s'
|
||||
remote='%(remote)s' />
|
||||
"""
|
||||
|
||||
MANIFEST_TAIL = """
|
||||
</manifest>
|
||||
"""
|
||||
|
||||
|
||||
def ConvertDepsToManifest(deps, manifest):
|
||||
"""Convert the |deps| file to the |manifest|."""
|
||||
# Load the DEPS file data.
|
||||
ctx = {}
|
||||
with open(deps, 'rb') as file:
|
||||
exec(compile(file.read(), deps, 'exec'), ctx)
|
||||
|
||||
new_contents = ''
|
||||
|
||||
# Write out the common header.
|
||||
data = {
|
||||
'prog': os.path.basename(__file__),
|
||||
}
|
||||
new_contents += MANIFEST_HEAD % data
|
||||
|
||||
# Write out the <remote> sections.
|
||||
for name, fetch in REMOTES.items():
|
||||
data = {
|
||||
'name': name,
|
||||
'fetch': fetch,
|
||||
'review': REVIEWS.get(name, ''),
|
||||
}
|
||||
new_contents += MANIFEST_REMOTE % data
|
||||
|
||||
# Write out the main repo itself.
|
||||
data = {
|
||||
'path': 'src',
|
||||
'name': 'breakpad/breakpad',
|
||||
'revision': 'refs/heads/main',
|
||||
'remote': 'chromium',
|
||||
}
|
||||
new_contents += MANIFEST_PROJECT % data
|
||||
|
||||
# Write out the <project> sections.
|
||||
for path, url in ctx['deps'].items():
|
||||
for name, fetch in REMOTES.items():
|
||||
if url.startswith(fetch):
|
||||
remote = name
|
||||
break
|
||||
else:
|
||||
raise ValueError('Unknown DEPS remote: %s: %s' % (path, url))
|
||||
|
||||
# The DEPS url will look like:
|
||||
# https://chromium.googlesource.com/external/gyp/@e8ab0833a42691cd2
|
||||
remote_path, rev = url.split('@')
|
||||
remote_path = remote_path[len(fetch):]
|
||||
|
||||
# If it's not a revision, assume it's a tag. Repo wants full ref names.
|
||||
if len(rev) != 40:
|
||||
rev = 'refs/tags/%s' % rev
|
||||
|
||||
data = {
|
||||
'path': path,
|
||||
'name': remote_path,
|
||||
'revision': rev,
|
||||
'remote': remote,
|
||||
}
|
||||
new_contents += MANIFEST_PROJECT % data
|
||||
|
||||
# Write out the common footer.
|
||||
new_contents += MANIFEST_TAIL
|
||||
|
||||
# See if the manifest has actually changed contents to avoid thrashing.
|
||||
try:
|
||||
old_contents = open(manifest).read()
|
||||
except IOError:
|
||||
# In case the file doesn't exist yet.
|
||||
old_contents = ''
|
||||
if old_contents != new_contents:
|
||||
print('Updating %s due to changed %s' % (manifest, deps))
|
||||
with open(manifest, 'w') as fp:
|
||||
fp.write(new_contents)
|
||||
|
||||
|
||||
def GetParser():
|
||||
"""Return a CLI parser."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('deps',
|
||||
help='The DEPS file to convert')
|
||||
parser.add_argument('manifest',
|
||||
help='The manifest xml to generate')
|
||||
return parser
|
||||
|
||||
|
||||
def main(argv):
|
||||
"""The main func!"""
|
||||
parser = GetParser()
|
||||
opts = parser.parse_args(argv)
|
||||
ConvertDepsToManifest(opts.deps, opts.manifest)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
202
externals/breakpad/src/tools/python/filter_syms.py
vendored
Normal file
202
externals/breakpad/src/tools/python/filter_syms.py
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright 2012 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Normalizes and de-duplicates paths within Breakpad symbol files.
|
||||
|
||||
When using DWARF for storing debug symbols, some file information will be
|
||||
stored relative to the current working directory of the current compilation
|
||||
unit, and may be further relativized based upon how the file was #included.
|
||||
|
||||
This helper can be used to parse the Breakpad symbol file generated from such
|
||||
DWARF files and normalize and de-duplicate the FILE records found within,
|
||||
updating any references to the FILE records in the other record types.
|
||||
"""
|
||||
|
||||
import ntpath
|
||||
import optparse
|
||||
import os
|
||||
import posixpath
|
||||
import sys
|
||||
|
||||
class BreakpadParseError(Exception):
|
||||
"""Unsupported Breakpad symbol record exception class."""
|
||||
pass
|
||||
|
||||
class SymbolFileParser(object):
|
||||
"""Parser for Breakpad symbol files.
|
||||
|
||||
The format of these files is documented at
|
||||
https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md
|
||||
"""
|
||||
|
||||
def __init__(self, input_stream, output_stream, ignored_prefixes=None,
|
||||
path_handler=os.path):
|
||||
"""Inits a SymbolFileParser to read symbol records from |input_stream| and
|
||||
write the processed output to |output_stream|.
|
||||
|
||||
|ignored_prefixes| contains a list of optional path prefixes that
|
||||
should be stripped from the final, normalized path outputs.
|
||||
|
||||
For example, if the Breakpad symbol file had all paths starting with a
|
||||
common prefix, such as:
|
||||
FILE 1 /b/build/src/foo.cc
|
||||
FILE 2 /b/build/src/bar.cc
|
||||
Then adding "/b/build/src" as an ignored prefix would result in an output
|
||||
file that contained:
|
||||
FILE 1 foo.cc
|
||||
FILE 2 bar.cc
|
||||
|
||||
Note that |ignored_prefixes| does not necessarily contain file system
|
||||
paths, as the contents of the DWARF DW_AT_comp_dir attribute is dependent
|
||||
upon the host system and compiler, and may contain additional information
|
||||
such as hostname or compiler version.
|
||||
"""
|
||||
|
||||
self.unique_files = {}
|
||||
self.duplicate_files = {}
|
||||
self.input_stream = input_stream
|
||||
self.output_stream = output_stream
|
||||
self.ignored_prefixes = ignored_prefixes or []
|
||||
self.path_handler = path_handler
|
||||
|
||||
def Process(self):
|
||||
"""Processes the Breakpad symbol file."""
|
||||
for line in self.input_stream:
|
||||
parsed = self._ParseRecord(line.rstrip())
|
||||
if parsed:
|
||||
self.output_stream.write(parsed + '\n')
|
||||
|
||||
def _ParseRecord(self, record):
|
||||
"""Parses a single Breakpad symbol record - a single line from the symbol
|
||||
file.
|
||||
|
||||
Returns:
|
||||
The modified string to write to the output file, or None if no line
|
||||
should be written.
|
||||
"""
|
||||
record_type = record.partition(' ')[0]
|
||||
if record_type == 'FILE':
|
||||
return self._ParseFileRecord(record)
|
||||
elif self._IsLineRecord(record_type):
|
||||
return self._ParseLineRecord(record)
|
||||
else:
|
||||
# Simply pass the record through unaltered.
|
||||
return record
|
||||
|
||||
def _NormalizePath(self, path):
|
||||
"""Normalizes a file path to its canonical form.
|
||||
|
||||
As this may not execute on the machine or file system originally
|
||||
responsible for compilation, it may be necessary to further correct paths
|
||||
for symlinks, junctions, or other such file system indirections.
|
||||
|
||||
Returns:
|
||||
A unique, canonical representation for the the file path.
|
||||
"""
|
||||
return self.path_handler.normpath(path)
|
||||
|
||||
def _AdjustPath(self, path):
|
||||
"""Adjusts the supplied path after performing path de-duplication.
|
||||
|
||||
This may be used to perform secondary adjustments, such as removing a
|
||||
common prefix, such as "/D/build", or replacing the file system path with
|
||||
information from the version control system.
|
||||
|
||||
Returns:
|
||||
The actual path to use when writing the FILE record.
|
||||
"""
|
||||
return path[len(next(filter(path.startswith,
|
||||
self.ignored_prefixes + ['']))):]
|
||||
|
||||
def _ParseFileRecord(self, file_record):
|
||||
"""Parses and corrects a FILE record."""
|
||||
file_info = file_record[5:].split(' ', 3)
|
||||
if len(file_info) > 2:
|
||||
raise BreakpadParseError('Unsupported FILE record: ' + file_record)
|
||||
file_index = int(file_info[0])
|
||||
file_name = self._NormalizePath(file_info[1])
|
||||
existing_file_index = self.unique_files.get(file_name)
|
||||
if existing_file_index is None:
|
||||
self.unique_files[file_name] = file_index
|
||||
file_info[1] = self._AdjustPath(file_name)
|
||||
return 'FILE ' + ' '.join(file_info)
|
||||
else:
|
||||
self.duplicate_files[file_index] = existing_file_index
|
||||
return None
|
||||
|
||||
def _IsLineRecord(self, record_type):
|
||||
"""Determines if the current record type is a Line record"""
|
||||
try:
|
||||
line = int(record_type, 16)
|
||||
except (ValueError, TypeError):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _ParseLineRecord(self, line_record):
|
||||
"""Parses and corrects a Line record."""
|
||||
line_info = line_record.split(' ', 5)
|
||||
if len(line_info) > 4:
|
||||
raise BreakpadParseError('Unsupported Line record: ' + line_record)
|
||||
file_index = int(line_info[3])
|
||||
line_info[3] = str(self.duplicate_files.get(file_index, file_index))
|
||||
return ' '.join(line_info)
|
||||
|
||||
def main():
|
||||
option_parser = optparse.OptionParser()
|
||||
option_parser.add_option("-p", "--prefix",
|
||||
action="append", dest="prefixes", type="string",
|
||||
default=[],
|
||||
help="A path prefix that should be removed from "
|
||||
"all FILE lines. May be repeated to specify "
|
||||
"multiple prefixes.")
|
||||
option_parser.add_option("-t", "--path_type",
|
||||
action="store", type="choice", dest="path_handler",
|
||||
choices=['win32', 'posix'],
|
||||
help="Indicates how file paths should be "
|
||||
"interpreted. The default is to treat paths "
|
||||
"the same as the OS running Python (eg: "
|
||||
"os.path)")
|
||||
options, args = option_parser.parse_args()
|
||||
if args:
|
||||
option_parser.error('Unknown argument: %s' % args)
|
||||
|
||||
path_handler = { 'win32': ntpath,
|
||||
'posix': posixpath }.get(options.path_handler, os.path)
|
||||
try:
|
||||
symbol_parser = SymbolFileParser(sys.stdin, sys.stdout, options.prefixes,
|
||||
path_handler)
|
||||
symbol_parser.Process()
|
||||
except BreakpadParseError as e:
|
||||
print >> sys.stderr, 'Got an error while processing symbol file'
|
||||
print >> sys.stderr, str(e)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
136
externals/breakpad/src/tools/python/tests/filter_syms_unittest.py
vendored
Normal file
136
externals/breakpad/src/tools/python/tests/filter_syms_unittest.py
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright 2012 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Unit tests for filter_syms.py"""
|
||||
|
||||
import io
|
||||
import ntpath
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(ROOT_DIR, '..'))
|
||||
|
||||
# In root
|
||||
import filter_syms
|
||||
|
||||
class FilterSysmsTest(unittest.TestCase):
|
||||
def assertParsed(self, input_data, ignored_prefixes, expected):
|
||||
input_io = io.StringIO(input_data)
|
||||
output_io = io.StringIO()
|
||||
parser = filter_syms.SymbolFileParser(input_io, output_io,
|
||||
ignored_prefixes, ntpath)
|
||||
parser.Process()
|
||||
self.assertEqual(output_io.getvalue(), expected)
|
||||
|
||||
def testDuplicateFiles(self):
|
||||
"""Tests that duplicate files in FILE records are correctly removed and
|
||||
that Line records are updated."""
|
||||
|
||||
INPUT = \
|
||||
"""MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||
INFO CODE_ID FFFFFFFF module1.exe
|
||||
FILE 1 foo/../file1_1.cc
|
||||
FILE 2 bar/../file1_1.cc
|
||||
FILE 3 baz/../file1_1.cc
|
||||
FUNC 1000 c 0 Function1_1
|
||||
1000 8 45 2
|
||||
1008 4 46 3
|
||||
100c 4 44 1
|
||||
"""
|
||||
EXPECTED_OUTPUT = \
|
||||
"""MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||
INFO CODE_ID FFFFFFFF module1.exe
|
||||
FILE 1 file1_1.cc
|
||||
FUNC 1000 c 0 Function1_1
|
||||
1000 8 45 1
|
||||
1008 4 46 1
|
||||
100c 4 44 1
|
||||
"""
|
||||
self.assertParsed(INPUT, [], EXPECTED_OUTPUT)
|
||||
|
||||
def testIgnoredPrefix(self):
|
||||
"""Tests that prefixes in FILE records are correctly removed."""
|
||||
|
||||
INPUT = \
|
||||
"""MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||
INFO CODE_ID FFFFFFFF module1.exe
|
||||
FILE 1 /src/build/foo/../file1_1.cc
|
||||
FILE 2 /src/build/bar/../file1_2.cc
|
||||
FILE 3 /src/build/baz/../file1_2.cc
|
||||
FUNC 1000 c 0 Function1_1
|
||||
1000 8 45 2
|
||||
1008 4 46 3
|
||||
100c 4 44 1
|
||||
"""
|
||||
EXPECTED_OUTPUT = \
|
||||
"""MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||
INFO CODE_ID FFFFFFFF module1.exe
|
||||
FILE 1 file1_1.cc
|
||||
FILE 2 file1_2.cc
|
||||
FUNC 1000 c 0 Function1_1
|
||||
1000 8 45 2
|
||||
1008 4 46 2
|
||||
100c 4 44 1
|
||||
"""
|
||||
IGNORED_PREFIXES = ['\\src\\build\\']
|
||||
self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT)
|
||||
|
||||
def testIgnoredPrefixesDuplicateFiles(self):
|
||||
"""Tests that de-duplication of FILE records happens BEFORE prefixes
|
||||
are removed."""
|
||||
|
||||
INPUT = \
|
||||
"""MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||
INFO CODE_ID FFFFFFFF module1.exe
|
||||
FILE 1 /src/build/foo/../file1_1.cc
|
||||
FILE 2 /src/build/bar/../file1_2.cc
|
||||
FILE 3 D:/src/build2/baz/../file1_2.cc
|
||||
FUNC 1000 c 0 Function1_1
|
||||
1000 8 45 2
|
||||
1008 4 46 3
|
||||
100c 4 44 1
|
||||
"""
|
||||
EXPECTED_OUTPUT = \
|
||||
"""MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||
INFO CODE_ID FFFFFFFF module1.exe
|
||||
FILE 1 file1_1.cc
|
||||
FILE 2 file1_2.cc
|
||||
FILE 3 file1_2.cc
|
||||
FUNC 1000 c 0 Function1_1
|
||||
1000 8 45 2
|
||||
1008 4 46 3
|
||||
100c 4 44 1
|
||||
"""
|
||||
IGNORED_PREFIXES = ['\\src\\build\\', 'D:\\src\\build2\\']
|
||||
self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
63
externals/breakpad/src/tools/solaris/dump_syms/Makefile
vendored
Normal file
63
externals/breakpad/src/tools/solaris/dump_syms/Makefile
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2007 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Author: Alfred Peng
|
||||
|
||||
CXX=CC
|
||||
CC=cc
|
||||
|
||||
CXXFLAGS=-g -xs -xdebugformat=stabs -I../../.. -I../../../common/solaris -lelf -ldemangle -D_REENTRANT
|
||||
|
||||
.PHONY:all clean
|
||||
|
||||
BIN=dump_syms
|
||||
|
||||
all:$(BIN)
|
||||
|
||||
DUMP_OBJ=dump_symbols.o guid_creator.o dump_syms.o file_id.o md5.o
|
||||
|
||||
dump_syms:$(DUMP_OBJ)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
dump_symbols.o:../../../common/solaris/dump_symbols.cc
|
||||
$(CXX) $(CXXFLAGS) -c $^
|
||||
|
||||
guid_creator.o:../../../common/solaris/guid_creator.cc
|
||||
$(CXX) $(CXXFLAGS) -c $^
|
||||
|
||||
file_id.o:../../../common/solaris/file_id.cc
|
||||
$(CXX) $(CXXFLAGS) -c $^
|
||||
|
||||
md5.o:../../../common/md5.cc
|
||||
$(CXX) $(CXXFLAGS) -c $^
|
||||
|
||||
test:all
|
||||
./run_regtest.sh
|
||||
|
||||
clean:
|
||||
rm -f $(BIN) $(DUMP_OBJ)
|
57
externals/breakpad/src/tools/solaris/dump_syms/dump_syms.cc
vendored
Normal file
57
externals/breakpad/src/tools/solaris/dump_syms/dump_syms.cc
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2007 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: Alfred Peng
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include "common/solaris/dump_symbols.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <binary-with-stab-symbol>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* binary = argv[1];
|
||||
|
||||
DumpSymbols dumper;
|
||||
if (!dumper.WriteSymbolFile(binary, fileno(stdout))) {
|
||||
fprintf(stderr, "Failed to write symbol file.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
50
externals/breakpad/src/tools/solaris/dump_syms/run_regtest.sh
vendored
Normal file
50
externals/breakpad/src/tools/solaris/dump_syms/run_regtest.sh
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright 2007 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
./dump_syms testdata/dump_syms_regtest.o > testdata/dump_syms_regtest.new
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ] ; then
|
||||
echo "FAIL, dump_syms failed"
|
||||
exit $status
|
||||
fi
|
||||
|
||||
diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.sym > \
|
||||
testdata/dump_syms_regtest.diff
|
||||
status=$?
|
||||
|
||||
if [ $status -eq 0 ] ; then
|
||||
rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new
|
||||
echo "PASS"
|
||||
else
|
||||
echo "FAIL, see testdata/dump_syms_regtest.[new|diff]"
|
||||
fi
|
||||
|
||||
exit $status
|
67
externals/breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc
vendored
Normal file
67
externals/breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2007 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ./dump_syms dump_syms_regtest.pdb > dump_syms_regtest.sym
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class C {
|
||||
public:
|
||||
C() : member_(1) {}
|
||||
virtual ~C() {}
|
||||
|
||||
void set_member(int value) { member_ = value; }
|
||||
int member() const { return member_; }
|
||||
|
||||
void f() { member_ = g(); }
|
||||
virtual int g() { return 2; }
|
||||
static char* h(const C& that) { return 0; }
|
||||
|
||||
private:
|
||||
int member_;
|
||||
};
|
||||
|
||||
static int i() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google_breakpad::C object;
|
||||
object.set_member(google_breakpad::i());
|
||||
object.f();
|
||||
int value = object.g();
|
||||
char* nothing = object.h(object);
|
||||
|
||||
return 0;
|
||||
}
|
129
externals/breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs
vendored
Normal file
129
externals/breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
|
||||
|
||||
Debugging Stab table -- 104 entries
|
||||
|
||||
0: .stabs "dump_syms_regtest.cc",N_UNDF,0x0,0x67,0x71c
|
||||
1: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/",N_SO,0x0,0x0,0x0
|
||||
2: .stabs "dump_syms_regtest.cc",N_SO,0x0,0x4,0x0
|
||||
3: .stabs "",N_OBJ,0x0,0x0,0x0
|
||||
4: .stabs "",N_OBJ,0x0,0x0,0x0
|
||||
5: .stabs "V=9.0;DBG_GEN=5.0.8;dm;cd;backend;ptf;ptx;ptk;s;g;R=5.8<<Sun C++ 5.8 Patch 121018-07 2006/11/01 (ccfe)>>;G=.XAB6Z2hOiL$Gl1b.;A=2",N_OPT,0x0,0x0,0x46fcb88e
|
||||
6: .stabs "dump_syms_regtest.cc",N_SOL,0x0,0x0,0x0
|
||||
7: .stabs "char:t(0,1)=bsc1;0;8",N_ISYM,0x0,0x0,0x0
|
||||
8: .stabs "short:t(0,2)=bs2;0;16",N_ISYM,0x0,0x0,0x0
|
||||
9: .stabs "int:t(0,3)=bs4;0;32",N_ISYM,0x0,0x0,0x0
|
||||
10: .stabs "long:t(0,4)=bs4;0;32",N_ISYM,0x0,0x0,0x0
|
||||
11: .stabs "long long:t(0,5)=bs8;0;64",N_ISYM,0x0,0x0,0x0
|
||||
12: .stabs "unsigned char:t(0,6)=buc1;0;8",N_ISYM,0x0,0x0,0x0
|
||||
13: .stabs "unsigned short:t(0,7)=bu2;0;16",N_ISYM,0x0,0x0,0x0
|
||||
14: .stabs "unsigned:t(0,8)=bu4;0;32",N_ISYM,0x0,0x0,0x0
|
||||
15: .stabs "unsigned long:t(0,9)=bu4;0;32",N_ISYM,0x0,0x0,0x0
|
||||
16: .stabs "unsigned long long:t(0,10)=bu8;0;64",N_ISYM,0x0,0x0,0x0
|
||||
17: .stabs "signed char:t(0,11)=bsc1;0;8",N_ISYM,0x0,0x0,0x0
|
||||
18: .stabs "wchar_t:t(0,12)=buc4;0;32",N_ISYM,0x0,0x0,0x0
|
||||
19: .stabs "void:t(0,13)=bs0;0;0",N_ISYM,0x0,0x0,0x0
|
||||
20: .stabs "float:t(0,14)=R1;4",N_ISYM,0x0,0x0,0x0
|
||||
21: .stabs "double:t(0,15)=R2;8",N_ISYM,0x0,0x0,0x0
|
||||
22: .stabs "long double:t(0,16)=R6;12",N_ISYM,0x0,0x0,0x0
|
||||
23: .stabs "...:t(0,17)=buv4;0;32",N_ISYM,0x0,0x0,0x0
|
||||
24: .stabs "bool:t(0,18)=bub1;0;8",N_ISYM,0x0,0x0,0x0
|
||||
25: .stabs "__1nPgoogle_breakpad_:T(0,19)=Yn0google_breakpad;",N_ISYM,0x0,0x0,0x0
|
||||
26: .stabs "nBC(0,19):U(0,20)",N_ESYM,0x0,0x0,0x0
|
||||
27: .stabs "nBC(0,19):T(0,20)=Yc8C;;AcHmember_:(0,3),32,32;;Cc2t6M_v K2c2T6M_v CcKset_member6Mi_v CcGmember6kM_i CcBf6M_v K3cBg6M_i GcBh6Frk1_pc;;;2 0;;;;110;",N_ESYM,0x0,0x8,0x0
|
||||
28: .stabs "main:F(0,3);(0,3);(0,21)=*(0,22)=*(0,1)",N_FUN,0x0,0x38,0x0
|
||||
29: .stabs "main",N_MAIN,0x0,0x0,0x0
|
||||
30: .stabs "argc:p(0,3)",N_PSYM,0x0,0x4,0x8
|
||||
31: .stabs "argv:p(0,21)",N_PSYM,0x0,0x4,0xc
|
||||
32: .stabn N_LBRAC,0x0,0x1,0x12
|
||||
33: .stabs "object:(0,20)",N_LSYM,0x0,0x8,0xfffffff4
|
||||
34: .stabs "value:(0,3)",N_LSYM,0x0,0x4,0xfffffff0
|
||||
35: .stabs "nothing:(0,22)",N_LSYM,0x0,0x4,0xffffffec
|
||||
36: .stabn N_SLINE,0x0,0x39,0x12
|
||||
37: .stabs "object:2",N_CONSTRUCT,0x0,0xc,0x12
|
||||
38: .stabn N_SLINE,0x2,0x3a,0x1e
|
||||
39: .stabn N_SLINE,0x0,0x3b,0x36
|
||||
40: .stabn N_SLINE,0x0,0x3c,0x42
|
||||
41: .stabn N_SLINE,0x0,0x3d,0x57
|
||||
42: .stabn N_SLINE,0x0,0x3f,0x6c
|
||||
43: .stabs "2:0",N_DESTRUCT,0x0,0xc,0x73
|
||||
44: .stabn N_SLINE,0xfffffffe,0x40,0x9c
|
||||
45: .stabn N_RBRAC,0x0,0x1,0x9c
|
||||
46: .stabs "__1cPgoogle_breakpadBi6F_i_:f(0,3)",N_FUN,0x0,0x32,0x0
|
||||
47: .stabn N_LBRAC,0x0,0x1,0x6
|
||||
48: .stabn N_SLINE,0x0,0x33,0x6
|
||||
49: .stabn N_SLINE,0x0,0x34,0x10
|
||||
50: .stabn N_RBRAC,0x0,0x1,0x10
|
||||
51: .stabs "__1cPgoogle_breakpadBC2t6M_v_:F(0,13);(0,23)=*(0,20)",N_FUN,0x0,0x24,0x0
|
||||
52: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
53: .stabn N_LBRAC,0x0,0x1,0x3
|
||||
54: .stabn N_SLINE,0x0,0x24,0x25
|
||||
55: .stabn N_RBRAC,0x0,0x1,0x25
|
||||
56: .stabs "__1cPgoogle_breakpadBC2T6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x25,0x0
|
||||
57: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
58: .stabn N_LBRAC,0x0,0x1,0x3
|
||||
59: .stabn N_SLINE,0x0,0x25,0x3
|
||||
60: .stabn N_RBRAC,0x0,0x1,0x3
|
||||
61: .stabs "__1cPgoogle_breakpadBCKset_member6Mi_v_:F(0,13);(0,23);(0,3)",N_FUN,0x0,0x27,0x0
|
||||
62: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
63: .stabs "value:p(0,3)",N_PSYM,0x0,0x4,0xc
|
||||
64: .stabn N_LBRAC,0x0,0x1,0x3
|
||||
65: .stabn N_SLINE,0x0,0x27,0x3
|
||||
66: .stabn N_SLINE,0x0,0x27,0xc
|
||||
67: .stabn N_RBRAC,0x0,0x1,0xc
|
||||
68: .stabs "__1cPgoogle_breakpadBCBf6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x2a,0x0
|
||||
69: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
70: .stabn N_LBRAC,0x0,0x1,0x3
|
||||
71: .stabn N_SLINE,0x0,0x2a,0x3
|
||||
72: .stabn N_SLINE,0x0,0x2a,0x1d
|
||||
73: .stabn N_RBRAC,0x0,0x1,0x1d
|
||||
74: .stabs "__1cPgoogle_breakpadBCBg6M_i_:F(0,3);(0,23)",N_FUN,0x0,0x2b,0x0
|
||||
75: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
76: .stabn N_LBRAC,0x0,0x1,0x6
|
||||
77: .stabn N_SLINE,0x0,0x2b,0x6
|
||||
78: .stabn N_SLINE,0x0,0x2b,0x10
|
||||
79: .stabn N_RBRAC,0x0,0x1,0x10
|
||||
80: .stabs "__1cPgoogle_breakpadBCBh6Frk1_pc_:F(0,22);(0,24)=&(0,25)=k(0,20)",N_FUN,0x0,0x2c,0x0
|
||||
81: .stabs "that:p(0,24)",N_PSYM,0x0,0x4,0x8
|
||||
82: .stabn N_LBRAC,0x0,0x1,0x6
|
||||
83: .stabn N_SLINE,0x0,0x2c,0x6
|
||||
84: .stabn N_SLINE,0x0,0x2c,0x10
|
||||
85: .stabn N_RBRAC,0x0,0x1,0x10
|
||||
86: .stabs "__1cPgoogle_breakpadBC2T5B6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x25,0x0
|
||||
87: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
88: .stabn N_LBRAC,0x0,0x1,0x3
|
||||
89: .stabn N_SLINE,0x0,0x25,0xf
|
||||
90: .stabn N_RBRAC,0x0,0x1,0xf
|
||||
91: .stabs "__SLIP.DELETER__A:f(0,13);(0,23);(0,3)",N_FUN,0x0,0x25,0x0
|
||||
92: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8
|
||||
93: .stabs "delete:p(0,3)",N_PSYM,0x0,0x4,0xc
|
||||
94: .stabn N_LBRAC,0x0,0x1,0x3
|
||||
95: .stabn N_LBRAC,0x0,0x2,0x3
|
||||
96: .stabn N_RBRAC,0x0,0x2,0x28
|
||||
97: .stabn N_RBRAC,0x0,0x1,0x28
|
||||
98: .stabs "true:l(0,18);1",N_LSYM,0x0,0x4,0x0
|
||||
99: .stabs "false:l(0,18);0",N_LSYM,0x0,0x4,0x0
|
||||
100: .stabs "__1c2k6Fpv_v_:P(0,13);(0,26)=*(0,13)",N_FUN,0x0,0x0,0x0
|
||||
101: .stabs "__1cPgoogle_breakpadBC2t5B6M_v_:F__1cPgoogle_breakpadBC2t6M_v_",N_ALIAS,0x0,0x0,0x0
|
||||
102: .stabs "cbD__RTTI__1nPgoogle_breakpadBC_(0,19):YR(0,20)",N_LSYM,0x0,0x0,0x0
|
||||
103: .stabn N_ENDM,0x0,0x0,0x0
|
||||
|
||||
|
||||
Index Stab table -- 17 entries
|
||||
|
||||
0: .stabs "dump_syms_regtest.cc",N_UNDF,0x0,0x10,0x3b1
|
||||
1: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/",N_SO,0x0,0x0,0x0
|
||||
2: .stabs "dump_syms_regtest.cc",N_SO,0x0,0x4,0x0
|
||||
3: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata",N_OBJ,0x0,0x0,0x0
|
||||
4: .stabs "dump_syms_regtest.o",N_OBJ,0x0,0x0,0x0
|
||||
5: .stabs "V=9.0;DBG_GEN=5.0.8;dm;cd;backend;ptf;ptx;ptk;s;g;R=5.8<<Sun C++ 5.8 Patch 121018-07 2006/11/01 (ccfe)>>;G=.XAB6Z2hOiL$Gl1b.;A=2",N_OPT,0x0,0x0,0x46fcb88e
|
||||
6: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/; /ws/on10-tools-prc/SUNWspro/SS11/prod/bin/CC -g -xs -xdebugformat=stabs -I../../.. -I../../../common/solaris -D_REENTRANT -xs dump_syms_regtest.cc -Qoption ccfe -prefix -Qoption ccfe .XAB6Z2hOiL\$Gl1b.",N_CMDLINE,0x0,0x0,0x0
|
||||
7: .stabs "__1nPgoogle_breakpadBC_:U",N_ESYM,0x0,0x0,0x0
|
||||
8: .stabs "main",N_MAIN,0x0,0x0,0x0
|
||||
9: .stabs "main",N_FUN,0x0,0x0,0x0
|
||||
10: .stabs "__1cPgoogle_breakpadBC2t6M_v_",N_FUN,0x0,0x0,0x0
|
||||
11: .stabs "__1cPgoogle_breakpadBC2T6M_v_",N_FUN,0x0,0x0,0x0
|
||||
12: .stabs "__1cPgoogle_breakpadBCKset_member6Mi_v_",N_FUN,0x0,0x0,0x0
|
||||
13: .stabs "__1cPgoogle_breakpadBCBf6M_v_",N_FUN,0x0,0x0,0x0
|
||||
14: .stabs "__1cPgoogle_breakpadBCBg6M_i_",N_FUN,0x0,0x0,0x0
|
||||
15: .stabs "__1cPgoogle_breakpadBCBh6Frk1_pc_",N_FUN,0x0,0x0,0x0
|
||||
16: .stabs "__1cPgoogle_breakpadBC2T5B6M_v_",N_FUN,0x0,0x0,0x0
|
33
externals/breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym
vendored
Normal file
33
externals/breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
MODULE solaris x86 3DC8191474338D8587339B5FB3E2C62A0 dump_syms_regtest.o
|
||||
FILE 0 dump_syms_regtest.cc
|
||||
FUNC 0 156 0 main
|
||||
12 18 57 0
|
||||
1e 12 58 0
|
||||
36 24 59 0
|
||||
42 12 60 0
|
||||
57 21 61 0
|
||||
6c 21 63 0
|
||||
9c 48 64 0
|
||||
FUNC 0 16 0 int google_breakpad::i()
|
||||
6 6 51 0
|
||||
10 10 52 0
|
||||
FUNC 0 37 0 google_breakpad::C::C()
|
||||
25 37 36 0
|
||||
FUNC 0 3 0 google_breakpad::C::~C()
|
||||
3 3 37 0
|
||||
FUNC 0 12 0 void google_breakpad::C::set_member(int)
|
||||
3 3 39 0
|
||||
c 9 39 0
|
||||
FUNC 0 29 0 void google_breakpad::C::f()
|
||||
3 3 42 0
|
||||
1d 26 42 0
|
||||
FUNC 0 16 0 int google_breakpad::C::g()
|
||||
6 6 43 0
|
||||
10 10 43 0
|
||||
FUNC 0 16 0 char*google_breakpad::C::h(const google_breakpad::C&)
|
||||
6 6 44 0
|
||||
10 10 44 0
|
||||
FUNC 0 15 0 google_breakpad::C::~C #Nvariant 1()
|
||||
f 15 37 0
|
||||
FUNC 0 0 0 __SLIP.DELETER__A
|
||||
FUNC 0 0 0 void operator delete(void*)
|
BIN
externals/breakpad/src/tools/windows/binaries/dump_syms.exe
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/binaries/dump_syms.exe
vendored
Normal file
Binary file not shown.
BIN
externals/breakpad/src/tools/windows/binaries/symupload.exe
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/binaries/symupload.exe
vendored
Normal file
Binary file not shown.
770
externals/breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc
vendored
Normal file
770
externals/breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc
vendored
Normal file
|
@ -0,0 +1,770 @@
|
|||
// Copyright 2007 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ms_symbol_server_converter.cc: Obtain symbol files from a Microsoft
|
||||
// symbol server, and convert them to Breakpad's dumped format.
|
||||
//
|
||||
// See ms_symbol_server_converter.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <pathcch.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "tools/windows/converter/ms_symbol_server_converter.h"
|
||||
#include "common/windows/pdb_source_line_writer.h"
|
||||
#include "common/windows/pe_source_line_writer.h"
|
||||
#include "common/windows/string_utils-inl.h"
|
||||
|
||||
// SYMOPT_NO_PROMPTS is not defined in earlier platform SDKs. Define it
|
||||
// in that case, in the event that this code is used with a newer version
|
||||
// of DbgHelp at runtime that recognizes the option. The presence of this
|
||||
// bit in the symbol options should not harm earlier versions of DbgHelp.
|
||||
#ifndef SYMOPT_NO_PROMPTS
|
||||
#define SYMOPT_NO_PROMPTS 0x00080000
|
||||
#endif // SYMOPT_NO_PROMPTS
|
||||
|
||||
namespace {
|
||||
|
||||
std::wstring GetExeDirectory() {
|
||||
wchar_t directory[MAX_PATH];
|
||||
|
||||
// Get path to this process exe.
|
||||
DWORD result = GetModuleFileName(/*hModule=*/nullptr, directory, MAX_PATH);
|
||||
if (result <= 0 || result == MAX_PATH) {
|
||||
fprintf(stderr,
|
||||
"GetExeDirectory: failed to get path to process exe.\n");
|
||||
return L"";
|
||||
}
|
||||
HRESULT hr = PathCchRemoveFileSpec(directory, result + 1);
|
||||
if (hr != S_OK) {
|
||||
fprintf(stderr,
|
||||
"GetExeDirectory: failed to remove basename from path '%ls'.\n",
|
||||
directory);
|
||||
return L"";
|
||||
}
|
||||
|
||||
return std::wstring(directory);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Use sscanf_s if it is available, to quench the warning about scanf being
|
||||
// deprecated. Use scanf where sscanf_is not available. Note that the
|
||||
// parameters passed to sscanf and sscanf_s are only compatible as long as
|
||||
// fields of type c, C, s, S, and [ are not used.
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
#define SSCANF sscanf_s
|
||||
#else // _MSC_VER >= 1400
|
||||
#define SSCANF sscanf
|
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
bool GUIDOrSignatureIdentifier::InitializeFromString(
|
||||
const string& identifier) {
|
||||
type_ = TYPE_NONE;
|
||||
|
||||
size_t length = identifier.length();
|
||||
|
||||
if (length > 32 && length <= 40) {
|
||||
// GUID
|
||||
if (SSCANF(identifier.c_str(),
|
||||
"%08X%04hX%04hX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%X",
|
||||
&guid_.Data1, &guid_.Data2, &guid_.Data3,
|
||||
&guid_.Data4[0], &guid_.Data4[1],
|
||||
&guid_.Data4[2], &guid_.Data4[3],
|
||||
&guid_.Data4[4], &guid_.Data4[5],
|
||||
&guid_.Data4[6], &guid_.Data4[7],
|
||||
&age_) != 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
type_ = TYPE_GUID;
|
||||
} else if (length > 8 && length <= 15) {
|
||||
// Signature
|
||||
if (SSCANF(identifier.c_str(), "%08X%x", &signature_, &age_) != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
type_ = TYPE_SIGNATURE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef SSCANF
|
||||
|
||||
MSSymbolServerConverter::MSSymbolServerConverter(
|
||||
const string& local_cache,
|
||||
const vector<string>& symbol_servers,
|
||||
bool trace_symsrv)
|
||||
: symbol_path_(),
|
||||
fail_dns_(false),
|
||||
fail_timeout_(false),
|
||||
fail_http_https_redir_(false),
|
||||
fail_not_found_(false),
|
||||
trace_symsrv_(trace_symsrv) {
|
||||
// Setting local_cache can be done without verifying that it exists because
|
||||
// SymSrv will create it if it is missing - any creation failures will occur
|
||||
// at that time, so there's nothing to check here, making it safe to
|
||||
// assign this in the constructor.
|
||||
|
||||
assert(symbol_servers.size() > 0);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
// These are characters that are interpreted as having special meanings in
|
||||
// symbol_path_.
|
||||
const char kInvalidCharacters[] = "*;";
|
||||
assert(local_cache.find_first_of(kInvalidCharacters) == string::npos);
|
||||
#endif // !defined(NDEBUG)
|
||||
|
||||
for (vector<string>::const_iterator symbol_server = symbol_servers.begin();
|
||||
symbol_server != symbol_servers.end();
|
||||
++symbol_server) {
|
||||
// The symbol path format is explained by
|
||||
// http://msdn.microsoft.com/library/en-us/debug/base/using_symsrv.asp .
|
||||
// "srv*" is the same as "symsrv*symsrv.dll*", which means that
|
||||
// symsrv.dll is to be responsible for locating symbols. symsrv.dll
|
||||
// interprets the rest of the string as a series of symbol stores separated
|
||||
// by '*'. "srv*local_cache*symbol_server" means to check local_cache
|
||||
// first for the symbol file, and if it is not found there, to check
|
||||
// symbol_server. Symbol files found on the symbol server will be placed
|
||||
// in the local cache, decompressed.
|
||||
//
|
||||
// Multiple specifications in this format may be presented, separated by
|
||||
// semicolons.
|
||||
|
||||
assert((*symbol_server).find_first_of(kInvalidCharacters) == string::npos);
|
||||
symbol_path_ += "srv*" + local_cache + "*" + *symbol_server + ";";
|
||||
}
|
||||
|
||||
// Strip the trailing semicolon.
|
||||
symbol_path_.erase(symbol_path_.length() - 1);
|
||||
}
|
||||
|
||||
// A stack-based class that manages SymInitialize and SymCleanup calls.
|
||||
class AutoSymSrv {
|
||||
public:
|
||||
AutoSymSrv() : initialized_(false) {}
|
||||
|
||||
~AutoSymSrv() {
|
||||
if (!Cleanup()) {
|
||||
// Print the error message here, because destructors have no return
|
||||
// value.
|
||||
fprintf(stderr, "~AutoSymSrv: SymCleanup: error %lu\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
bool Initialize(HANDLE process, char* path, bool invade_process) {
|
||||
process_ = process;
|
||||
|
||||
// TODO(nbilling): Figure out why dbghelp.dll is being loaded from
|
||||
// system32/SysWOW64 before exe folder.
|
||||
|
||||
// Attempt to locate and load dbghelp.dll beside the process exe. This is
|
||||
// somewhat of a workaround to loader delay load behavior that is occurring
|
||||
// when we call into symsrv APIs. dbghelp.dll must be loaded from beside
|
||||
// the process exe so that we are guaranteed to find symsrv.dll alongside
|
||||
// dbghelp.dll (a security requirement of dbghelp.dll) and so that the
|
||||
// symsrv.dll file that is loaded has a symsrv.yes file alongside it (a
|
||||
// requirement of symsrv.dll when accessing Microsoft-owned symbol
|
||||
// servers).
|
||||
// 'static local' because we don't care about the value but we need the
|
||||
// initialization to happen exactly once.
|
||||
static HMODULE dbghelp_module = [] () -> HMODULE {
|
||||
std::wstring exe_directory = GetExeDirectory();
|
||||
if (exe_directory.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
std::wstring dbghelp_path = exe_directory + L"\\dbghelp.dll";
|
||||
return LoadLibrary(dbghelp_path.c_str());
|
||||
}();
|
||||
if (dbghelp_module == nullptr) {
|
||||
fprintf(stderr,
|
||||
"AutoSymSrv::Initialize: failed to load dbghelp.dll beside exe.");
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized_ = SymInitialize(process, path, invade_process) == TRUE;
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
bool Cleanup() {
|
||||
if (initialized_) {
|
||||
if (SymCleanup(process_)) {
|
||||
initialized_ = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE process_;
|
||||
bool initialized_;
|
||||
};
|
||||
|
||||
// A stack-based class that "owns" a pathname and deletes it when destroyed,
|
||||
// unless told not to by having its Release() method called. Early deletions
|
||||
// are supported by calling Delete().
|
||||
class AutoDeleter {
|
||||
public:
|
||||
explicit AutoDeleter(const string& path) : path_(path) {}
|
||||
|
||||
~AutoDeleter() {
|
||||
int error;
|
||||
if ((error = Delete()) != 0) {
|
||||
// Print the error message here, because destructors have no return
|
||||
// value.
|
||||
fprintf(stderr, "~AutoDeleter: Delete: error %d for %s\n",
|
||||
error, path_.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int Delete() {
|
||||
if (path_.empty())
|
||||
return 0;
|
||||
|
||||
int error = remove(path_.c_str());
|
||||
Release();
|
||||
return error;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
path_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
string path_;
|
||||
};
|
||||
|
||||
MSSymbolServerConverter::LocateResult
|
||||
MSSymbolServerConverter::LocateFile(const string& debug_or_code_file,
|
||||
const string& debug_or_code_id,
|
||||
const string& version,
|
||||
string* file_name) {
|
||||
assert(file_name);
|
||||
file_name->clear();
|
||||
|
||||
GUIDOrSignatureIdentifier identifier;
|
||||
if (!identifier.InitializeFromString(debug_or_code_id)) {
|
||||
fprintf(stderr,
|
||||
"LocateFile: Unparseable identifier for %s %s %s\n",
|
||||
debug_or_code_file.c_str(),
|
||||
debug_or_code_id.c_str(),
|
||||
version.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
HANDLE process = GetCurrentProcess(); // CloseHandle is not needed.
|
||||
AutoSymSrv symsrv;
|
||||
if (!symsrv.Initialize(process,
|
||||
const_cast<char*>(symbol_path_.c_str()),
|
||||
false)) {
|
||||
fprintf(stderr, "LocateFile: SymInitialize: error %lu for %s %s %s\n",
|
||||
GetLastError(),
|
||||
debug_or_code_file.c_str(),
|
||||
debug_or_code_id.c_str(),
|
||||
version.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
if (!SymRegisterCallback64(process, SymCallback,
|
||||
reinterpret_cast<ULONG64>(this))) {
|
||||
fprintf(stderr,
|
||||
"LocateFile: SymRegisterCallback64: error %lu for %s %s %s\n",
|
||||
GetLastError(),
|
||||
debug_or_code_file.c_str(),
|
||||
debug_or_code_id.c_str(),
|
||||
version.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
// SYMOPT_DEBUG arranges for SymCallback to be called with additional
|
||||
// debugging information. This is used to determine the nature of failures.
|
||||
DWORD options = SymGetOptions() | SYMOPT_DEBUG | SYMOPT_NO_PROMPTS |
|
||||
SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_SECURE;
|
||||
SymSetOptions(options);
|
||||
|
||||
// SymCallback will set these as needed inisde the SymFindFileInPath call.
|
||||
fail_dns_ = false;
|
||||
fail_timeout_ = false;
|
||||
fail_not_found_ = false;
|
||||
|
||||
// Do the lookup.
|
||||
char path[MAX_PATH];
|
||||
if (!SymFindFileInPath(
|
||||
process, NULL,
|
||||
const_cast<char*>(debug_or_code_file.c_str()),
|
||||
const_cast<void*>(identifier.guid_or_signature_pointer()),
|
||||
identifier.age(), 0,
|
||||
identifier.type() == GUIDOrSignatureIdentifier::TYPE_GUID ?
|
||||
SSRVOPT_GUIDPTR : SSRVOPT_DWORDPTR,
|
||||
path, SymFindFileInPathCallback, this)) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_FILE_NOT_FOUND) {
|
||||
// This can be returned for a number of reasons. Use the crumbs
|
||||
// collected by SymCallback to determine which one is relevant.
|
||||
|
||||
// These errors are possibly transient.
|
||||
if (fail_dns_ || fail_timeout_) {
|
||||
return LOCATE_RETRY;
|
||||
}
|
||||
|
||||
if (fail_http_https_redir_) {
|
||||
return LOCATE_HTTP_HTTPS_REDIR;
|
||||
}
|
||||
|
||||
// This is an authoritiative file-not-found message.
|
||||
if (fail_not_found_) {
|
||||
fprintf(stderr,
|
||||
"LocateFile: SymFindFileInPath: LOCATE_NOT_FOUND error "
|
||||
"for %s %s %s\n",
|
||||
debug_or_code_file.c_str(),
|
||||
debug_or_code_id.c_str(),
|
||||
version.c_str());
|
||||
return LOCATE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// If the error is FILE_NOT_FOUND but none of the known error
|
||||
// conditions are matched, fall through to LOCATE_FAILURE.
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"LocateFile: SymFindFileInPath: error %lu for %s %s %s\n",
|
||||
error,
|
||||
debug_or_code_file.c_str(),
|
||||
debug_or_code_id.c_str(),
|
||||
version.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
// Making sure path is null-terminated.
|
||||
path[MAX_PATH - 1] = '\0';
|
||||
|
||||
// The AutoDeleter ensures that the file is only kept when returning
|
||||
// LOCATE_SUCCESS.
|
||||
AutoDeleter deleter(path);
|
||||
|
||||
// Do the cleanup here even though it will happen when symsrv goes out of
|
||||
// scope, to allow it to influence the return value.
|
||||
if (!symsrv.Cleanup()) {
|
||||
fprintf(stderr, "LocateFile: SymCleanup: error %lu for %s %s %s\n",
|
||||
GetLastError(),
|
||||
debug_or_code_file.c_str(),
|
||||
debug_or_code_id.c_str(),
|
||||
version.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
deleter.Release();
|
||||
|
||||
printf("Downloaded: %s\n", path);
|
||||
*file_name = path;
|
||||
return LOCATE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
MSSymbolServerConverter::LocateResult
|
||||
MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo& missing,
|
||||
string* pe_file) {
|
||||
return LocateFile(missing.code_file, missing.code_identifier,
|
||||
missing.version, pe_file);
|
||||
}
|
||||
|
||||
MSSymbolServerConverter::LocateResult
|
||||
MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo& missing,
|
||||
string* symbol_file) {
|
||||
return LocateFile(missing.debug_file, missing.debug_identifier,
|
||||
missing.version, symbol_file);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process,
|
||||
ULONG action,
|
||||
ULONG64 data,
|
||||
ULONG64 context) {
|
||||
MSSymbolServerConverter* self =
|
||||
reinterpret_cast<MSSymbolServerConverter*>(context);
|
||||
|
||||
switch (action) {
|
||||
case CBA_EVENT: {
|
||||
IMAGEHLP_CBA_EVENT* cba_event =
|
||||
reinterpret_cast<IMAGEHLP_CBA_EVENT*>(data);
|
||||
|
||||
// Put the string into a string object to be able to use string::find
|
||||
// for substring matching. This is important because the not-found
|
||||
// message does not use the entire string but is appended to the URL
|
||||
// that SymSrv attempted to retrieve.
|
||||
string desc(cba_event->desc);
|
||||
if (self->trace_symsrv_) {
|
||||
fprintf(stderr, "LocateFile: SymCallback: action desc '%s'\n",
|
||||
desc.c_str());
|
||||
}
|
||||
|
||||
// desc_action maps strings (in desc) to boolean pointers that are to
|
||||
// be set to true if the string matches.
|
||||
struct desc_action {
|
||||
const char* desc; // The substring to match.
|
||||
bool* action; // On match, this pointer will be set to true.
|
||||
};
|
||||
|
||||
static const desc_action desc_actions[] = {
|
||||
// When a DNS error occurs, it could be indiciative of network
|
||||
// problems.
|
||||
{"SYMSRV: The server name or address could not be resolved\n",
|
||||
&self->fail_dns_},
|
||||
|
||||
// This message is produced if no connection is opened.
|
||||
{"SYMSRV: A connection with the server could not be established\n",
|
||||
&self->fail_timeout_},
|
||||
|
||||
// This message is produced if a connection is established but the
|
||||
// server fails to respond to the HTTP request.
|
||||
{"SYMSRV: The operation timed out\n", &self->fail_timeout_},
|
||||
|
||||
// This message is produced if the server is redirecting us from http
|
||||
// to https. When this happens SymSrv will fail and we need to use
|
||||
// the https URL in our call-- we've made a mistake.
|
||||
{"ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR\n",
|
||||
&self->fail_http_https_redir_},
|
||||
|
||||
// This message is produced when the requested file is not found,
|
||||
// even if one or more of the above messages are also produced.
|
||||
// It's trapped to distinguish between not-found and unknown-failure
|
||||
// conditions. Note that this message will not be produced if a
|
||||
// connection is established and the server begins to respond to the
|
||||
// HTTP request but does not finish transmitting the file.
|
||||
{" not found\n", &self->fail_not_found_}};
|
||||
|
||||
for (int desc_action_index = 0;
|
||||
desc_action_index <
|
||||
static_cast<int>(sizeof(desc_actions) / sizeof(desc_action));
|
||||
++desc_action_index) {
|
||||
if (desc.find(desc_actions[desc_action_index].desc) != string::npos) {
|
||||
*(desc_actions[desc_action_index].action) = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This function is a mere fly on the wall. Treat everything as unhandled.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback(
|
||||
const char* filename, void* context) {
|
||||
// FALSE ends the search, indicating that the located symbol file is
|
||||
// satisfactory.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
MSSymbolServerConverter::LocateResult
|
||||
MSSymbolServerConverter::LocateAndConvertSymbolFile(
|
||||
const MissingSymbolInfo& missing,
|
||||
bool keep_symbol_file,
|
||||
bool keep_pe_file,
|
||||
string* converted_symbol_file,
|
||||
string* symbol_file,
|
||||
string* out_pe_file) {
|
||||
assert(converted_symbol_file);
|
||||
converted_symbol_file->clear();
|
||||
if (symbol_file) {
|
||||
symbol_file->clear();
|
||||
}
|
||||
|
||||
string pdb_file;
|
||||
LocateResult result = LocateSymbolFile(missing, &pdb_file);
|
||||
if (result != LOCATE_SUCCESS) {
|
||||
fprintf(stderr, "Fallback to PE-only symbol generation for: %s\n",
|
||||
missing.debug_file.c_str());
|
||||
return LocateAndConvertPEFile(missing, keep_pe_file, converted_symbol_file,
|
||||
out_pe_file);
|
||||
}
|
||||
|
||||
if (symbol_file && keep_symbol_file) {
|
||||
*symbol_file = pdb_file;
|
||||
}
|
||||
|
||||
// The conversion of a symbol file for a Windows 64-bit module requires
|
||||
// loading of the executable file. If there is no executable file, convert
|
||||
// using only the PDB file. Without an executable file, the conversion will
|
||||
// fail for 64-bit modules but it should succeed for 32-bit modules.
|
||||
string pe_file;
|
||||
result = LocatePEFile(missing, &pe_file);
|
||||
if (result != LOCATE_SUCCESS) {
|
||||
fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str());
|
||||
}
|
||||
|
||||
if (out_pe_file && keep_pe_file) {
|
||||
*out_pe_file = pe_file;
|
||||
}
|
||||
|
||||
// Conversion may fail because the file is corrupt. If a broken file is
|
||||
// kept in the local cache, LocateSymbolFile will not hit the network again
|
||||
// to attempt to locate it. To guard against problems like this, the
|
||||
// symbol file in the local cache will be removed if conversion fails.
|
||||
AutoDeleter pdb_deleter(pdb_file);
|
||||
AutoDeleter pe_deleter(pe_file);
|
||||
|
||||
// Be sure that it's a .pdb file, since we'll be replacing .pdb with .sym
|
||||
// for the converted file's name.
|
||||
string pdb_extension = pdb_file.substr(pdb_file.length() - 4);
|
||||
// strcasecmp is called _stricmp here.
|
||||
if (_stricmp(pdb_extension.c_str(), ".pdb") != 0) {
|
||||
fprintf(stderr, "LocateAndConvertSymbolFile: "
|
||||
"no .pdb extension for %s %s %s %s\n",
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
pdb_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
PDBSourceLineWriter writer;
|
||||
wstring pe_file_w;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) {
|
||||
fprintf(stderr,
|
||||
"LocateAndConvertSymbolFile: "
|
||||
"WindowsStringUtils::safe_mbstowcs failed for %s\n",
|
||||
pe_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
wstring pdb_file_w;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(pdb_file, &pdb_file_w)) {
|
||||
fprintf(stderr,
|
||||
"LocateAndConvertSymbolFile: "
|
||||
"WindowsStringUtils::safe_mbstowcs failed for %ws\n",
|
||||
pdb_file_w.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
if (!writer.Open(pdb_file_w, PDBSourceLineWriter::PDB_FILE)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: PDBSourceLineWriter::Open failed for %s %s %s %ws\n",
|
||||
missing.debug_file.c_str(), missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(), pdb_file_w.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
if (!writer.SetCodeFile(pe_file_w)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: PDBSourceLineWriter::SetCodeFile failed for %s %s %s %ws\n",
|
||||
missing.debug_file.c_str(), missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(), pe_file_w.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
*converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym";
|
||||
|
||||
FILE* converted_output = NULL;
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
errno_t err;
|
||||
if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w"))
|
||||
!= 0) {
|
||||
#else // _MSC_VER >= 1400
|
||||
// fopen_s and errno_t were introduced in MSVC8. Use fopen for earlier
|
||||
// environments. Don't use fopen with MSVC8 and later, because it's
|
||||
// deprecated. fopen does not provide reliable error codes, so just use
|
||||
// -1 in the event of a failure.
|
||||
int err;
|
||||
if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) {
|
||||
err = -1;
|
||||
#endif // _MSC_VER >= 1400
|
||||
fprintf(stderr, "LocateAndConvertSymbolFile: "
|
||||
"fopen_s: error %d for %s %s %s %s\n",
|
||||
err,
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
converted_symbol_file->c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
AutoDeleter sym_deleter(*converted_symbol_file);
|
||||
|
||||
bool success = writer.WriteSymbols(converted_output);
|
||||
fclose(converted_output);
|
||||
|
||||
if (!success) {
|
||||
fprintf(stderr, "LocateAndConvertSymbolFile: "
|
||||
"PDBSourceLineWriter::WriteMap failed for %s %s %s %s\n",
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
pdb_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
if (keep_symbol_file) {
|
||||
pdb_deleter.Release();
|
||||
}
|
||||
|
||||
if (keep_pe_file) {
|
||||
pe_deleter.Release();
|
||||
}
|
||||
|
||||
sym_deleter.Release();
|
||||
|
||||
return LOCATE_SUCCESS;
|
||||
}
|
||||
|
||||
MSSymbolServerConverter::LocateResult
|
||||
MSSymbolServerConverter::LocateAndConvertPEFile(
|
||||
const MissingSymbolInfo& missing,
|
||||
bool keep_pe_file,
|
||||
string* converted_symbol_file,
|
||||
string* out_pe_file) {
|
||||
assert(converted_symbol_file);
|
||||
converted_symbol_file->clear();
|
||||
|
||||
string pe_file;
|
||||
MSSymbolServerConverter::LocateResult result = LocatePEFile(missing,
|
||||
&pe_file);
|
||||
if (result != LOCATE_SUCCESS) {
|
||||
fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
if (out_pe_file && keep_pe_file) {
|
||||
*out_pe_file = pe_file;
|
||||
}
|
||||
|
||||
// Conversion may fail because the file is corrupt. If a broken file is
|
||||
// kept in the local cache, LocatePEFile will not hit the network again
|
||||
// to attempt to locate it. To guard against problems like this, the
|
||||
// PE file in the local cache will be removed if conversion fails.
|
||||
AutoDeleter pe_deleter(pe_file);
|
||||
|
||||
// Be sure that it's a .exe or .dll file, since we'll be replacing extension
|
||||
// with .sym for the converted file's name.
|
||||
string pe_extension = pe_file.substr(pe_file.length() - 4);
|
||||
// strcasecmp is called _stricmp here.
|
||||
if (_stricmp(pe_extension.c_str(), ".exe") != 0 &&
|
||||
_stricmp(pe_extension.c_str(), ".dll") != 0) {
|
||||
fprintf(stderr, "LocateAndConvertPEFile: "
|
||||
"no .dll/.exe extension for %s %s %s %s\n",
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
pe_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
*converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym";
|
||||
|
||||
FILE* converted_output = NULL;
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
errno_t err;
|
||||
if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w"))
|
||||
!= 0) {
|
||||
#else // _MSC_VER >= 1400
|
||||
// fopen_s and errno_t were introduced in MSVC8. Use fopen for earlier
|
||||
// environments. Don't use fopen with MSVC8 and later, because it's
|
||||
// deprecated. fopen does not provide reliable error codes, so just use
|
||||
// -1 in the event of a failure.
|
||||
int err;
|
||||
if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) {
|
||||
err = -1;
|
||||
#endif // _MSC_VER >= 1400
|
||||
fprintf(stderr, "LocateAndConvertPEFile: "
|
||||
"fopen_s: error %d for %s %s %s %s\n",
|
||||
err,
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
converted_symbol_file->c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
AutoDeleter sym_deleter(*converted_symbol_file);
|
||||
|
||||
wstring pe_file_w;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) {
|
||||
fprintf(stderr,
|
||||
"LocateAndConvertPEFile: "
|
||||
"WindowsStringUtils::safe_mbstowcs failed for %s\n",
|
||||
pe_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
PESourceLineWriter writer(pe_file_w);
|
||||
PDBModuleInfo module_info;
|
||||
if (!writer.GetModuleInfo(&module_info)) {
|
||||
fprintf(stderr, "LocateAndConvertPEFile: "
|
||||
"PESourceLineWriter::GetModuleInfo failed for %s %s %s %s\n",
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
pe_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
if (module_info.cpu.compare(L"x86_64") != 0) {
|
||||
// This module is not x64 so we cannot generate Breakpad symbols from the
|
||||
// PE alone. Don't delete PE-- no need to retry download.
|
||||
pe_deleter.Release();
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
bool success = writer.WriteSymbols(converted_output);
|
||||
fclose(converted_output);
|
||||
|
||||
if (!success) {
|
||||
fprintf(stderr, "LocateAndConvertPEFile: "
|
||||
"PESourceLineWriter::WriteMap failed for %s %s %s %s\n",
|
||||
missing.debug_file.c_str(),
|
||||
missing.debug_identifier.c_str(),
|
||||
missing.version.c_str(),
|
||||
pe_file.c_str());
|
||||
return LOCATE_FAILURE;
|
||||
}
|
||||
|
||||
if (keep_pe_file) {
|
||||
pe_deleter.Release();
|
||||
}
|
||||
|
||||
sym_deleter.Release();
|
||||
|
||||
return LOCATE_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
242
externals/breakpad/src/tools/windows/converter/ms_symbol_server_converter.h
vendored
Normal file
242
externals/breakpad/src/tools/windows/converter/ms_symbol_server_converter.h
vendored
Normal file
|
@ -0,0 +1,242 @@
|
|||
// Copyright 2007 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ms_symbol_server_converter.h: Obtain symbol files from a Microsoft
|
||||
// symbol server, and convert them to Breakpad's dumped format.
|
||||
//
|
||||
// At runtime, MSSymbolServerConverter and code that it calls depend on being
|
||||
// able to locate suitable versions of dbghelp.dll and symsrv.dll. For best
|
||||
// results, place these files in the same directory as the executable.
|
||||
// dbghelp.dll and symsrv.dll as supplied with Debugging Tools for Windows are
|
||||
// both redistributable, as indicated by the package's redist.txt file.
|
||||
//
|
||||
// When connecting to Microsoft's symbol server at
|
||||
// http://msdl.microsoft.com/download/symbols/, which provides access to
|
||||
// symbols for the operating system itself, symsrv.dll requires agreement to
|
||||
// Microsoft's "Terms of Use for Microsoft Symbols and Binaries." Because this
|
||||
// library places the symbol engine into a promptless mode, the dialog with the
|
||||
// terms will not appear, and use of Microsoft's symbol server will not be
|
||||
// possible. To indicate agreement to the terms, create a file called
|
||||
// symsrv.yes in the same directory as symsrv.dll. (Note that symsrv.dll will
|
||||
// also recognize a symsrv.no file as indicating that you do not accept the
|
||||
// terms; the .yes file takes priority over the .no file.) The terms of use
|
||||
// are contained within symsrv.dll; they were formerly available online at
|
||||
// http://www.microsoft.com/whdc/devtools/debugging/symsrvTOU2.mspx , but
|
||||
// do not appear to be available online any longer as of January, 2007. It is
|
||||
// possible to view the terms from within WinDbg (Debugging Tools for Windows)
|
||||
// by removing any symsrv.yes and symsrv.no files from WinDbg's directory,
|
||||
// setting the symbol path to include Microsoft's symbol server (.sympath), and
|
||||
// attempting to load symbols from their server (.reload).
|
||||
//
|
||||
// This code has been tested with dbghelp.dll 6.5.3.7 and symsrv.dll 6.5.3.8,
|
||||
// included with Microsoft Visual Studio 8 in Common7/IDE. This has also been
|
||||
// tested with dbghelp.dll and symsrv.dll versions 6.6.7.5 and 6.12.2.633,
|
||||
// included with the same versions of Debugging Tools for Windows, available at
|
||||
// http://www.microsoft.com/whdc/devtools/debugging/ .
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_
|
||||
#define TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
// MissingSymbolInfo contains the subset of the information in the processor's
|
||||
// CodeModule structure relevant to obtaining a missing symbol file. Only
|
||||
// debug_file and debug_identifier are relevant in actually obtaining the
|
||||
// missing file; the other fields are for convenience.
|
||||
struct MissingSymbolInfo {
|
||||
string code_file;
|
||||
string code_identifier;
|
||||
string debug_file;
|
||||
string debug_identifier;
|
||||
string version;
|
||||
};
|
||||
|
||||
class GUIDOrSignatureIdentifier {
|
||||
public:
|
||||
enum GUIDOrSignatureType {
|
||||
TYPE_NONE = 0,
|
||||
TYPE_GUID,
|
||||
TYPE_SIGNATURE
|
||||
};
|
||||
|
||||
GUIDOrSignatureIdentifier() : type_(TYPE_NONE) {}
|
||||
|
||||
// Converts |identifier|, a debug_identifier-formatted string, into its
|
||||
// component fields: either a GUID and age, or signature and age. If
|
||||
// successful, sets the relevant fields in the object, including the type
|
||||
// field, and returns true. On error, returns false.
|
||||
bool InitializeFromString(const string& identifier);
|
||||
|
||||
GUIDOrSignatureType type() const { return type_; }
|
||||
GUID guid() const { return guid_; }
|
||||
DWORD signature() const { return signature_; }
|
||||
int age() const { return age_; }
|
||||
const void* guid_or_signature_pointer() const { return &guid_; }
|
||||
|
||||
private:
|
||||
GUIDOrSignatureType type_;
|
||||
|
||||
// An identifier contains either a 128-bit uuid or a 32-bit signature.
|
||||
union {
|
||||
GUID guid_;
|
||||
DWORD signature_;
|
||||
};
|
||||
|
||||
// All identifiers used here have age fields, which indicate a specific
|
||||
// revision given a uuid or signature.
|
||||
int age_;
|
||||
};
|
||||
|
||||
class MSSymbolServerConverter {
|
||||
public:
|
||||
enum LocateResult {
|
||||
LOCATE_FAILURE = 0,
|
||||
LOCATE_NOT_FOUND, // Authoritative: the file is not present.
|
||||
LOCATE_RETRY, // Transient (network?) error, try again later.
|
||||
LOCATE_SUCCESS,
|
||||
LOCATE_HTTP_HTTPS_REDIR
|
||||
};
|
||||
|
||||
// Create a new object. local_cache is the location (pathname) of a local
|
||||
// symbol store used to hold downloaded and converted symbol files. This
|
||||
// directory will be created by LocateSymbolFile when it successfully
|
||||
// retrieves a symbol file. symbol_servers contains a list of locations (URLs
|
||||
// or pathnames) of the upstream symbol server stores, given in order of
|
||||
// preference, with the first string in the vector identifying the first
|
||||
// store to try. The vector must contain at least one string. None of the
|
||||
// strings passed to this constructor may contain asterisk ('*') or semicolon
|
||||
// (';') characters, as the symbol engine uses these characters as separators.
|
||||
// If |trace_symsrv| is set then callbacks from SymSrv will be logged to
|
||||
// stderr.
|
||||
MSSymbolServerConverter(const string& local_cache,
|
||||
const vector<string>& symbol_servers,
|
||||
bool trace_symsrv);
|
||||
|
||||
// Locates the PE file (DLL or EXE) specified by the identifying information
|
||||
// in |missing|, by checking the symbol stores identified when the object
|
||||
// was created. When returning LOCATE_SUCCESS, pe_file is set to
|
||||
// the pathname of the decompressed PE file as it is stored in the
|
||||
// local cache.
|
||||
LocateResult LocatePEFile(const MissingSymbolInfo& missing, string* pe_file);
|
||||
|
||||
// Locates the symbol file specified by the identifying information in
|
||||
// |missing|, by checking the symbol stores identified when the object
|
||||
// was created. When returning LOCATE_SUCCESS, symbol_file is set to
|
||||
// the pathname of the decompressed symbol file as it is stored in the
|
||||
// local cache.
|
||||
LocateResult LocateSymbolFile(const MissingSymbolInfo& missing,
|
||||
string* symbol_file);
|
||||
|
||||
// Calls LocateSymbolFile and converts the returned symbol file to the
|
||||
// dumped-symbol format, storing it adjacent to the symbol file. The
|
||||
// only conversion supported is from pdb files. Returns the return
|
||||
// value of LocateSymbolFile, or if LocateSymbolFile succeeds but
|
||||
// conversion fails, returns LOCATE_FAILURE. The pathname to the
|
||||
// pdb file and to the converted symbol file are returned in
|
||||
// |converted_symbol_file|, |symbol_file|, and |pe_file|. |symbol_file| and
|
||||
// |pe_file| are optional and may be NULL. If only the converted symbol file
|
||||
// is desired, set |keep_symbol_file| and |keep_pe_file| to false to indicate
|
||||
// that the original symbol file (pdb) and executable file (exe, dll) should
|
||||
// be deleted after conversion.
|
||||
LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo& missing,
|
||||
bool keep_symbol_file,
|
||||
bool keep_pe_file,
|
||||
string* converted_symbol_file,
|
||||
string* symbol_file,
|
||||
string* pe_file);
|
||||
|
||||
// Calls LocatePEFile and converts the returned PE file to the
|
||||
// dumped-symbol format, storing it adjacent to the PE file. The
|
||||
// only conversion supported is from PE files. Returns the return
|
||||
// value of LocatePEFile, or if LocatePEFile succeeds but
|
||||
// conversion fails, returns LOCATE_FAILURE. The pathname to the
|
||||
// PE file and to the converted symbol file are returned in
|
||||
// |converted_symbol_file| and |pe_file|. |pe_file| is optional and may be
|
||||
// NULL. If only the converted symbol file is desired, set |keep_pe_file|
|
||||
// to false to indicate that the executable file (exe, dll) should be deleted
|
||||
// after conversion.
|
||||
// NOTE: Currrently only supports x64 PEs.
|
||||
LocateResult LocateAndConvertPEFile(const MissingSymbolInfo& missing,
|
||||
bool keep_pe_file,
|
||||
string* converted_symbol_file,
|
||||
string* pe_file);
|
||||
|
||||
private:
|
||||
// Locates the PDB or PE file (DLL or EXE) specified by the identifying
|
||||
// information in |debug_or_code_file| and |debug_or_code_id|, by checking
|
||||
// the symbol stores identified when the object was created. When
|
||||
// returning LOCATE_SUCCESS, file_name is set to the pathname of the
|
||||
// decompressed PDB or PE file file as it is stored in the local cache.
|
||||
LocateResult LocateFile(const string& debug_or_code_file,
|
||||
const string& debug_or_code_id,
|
||||
const string& version, string* file_name);
|
||||
|
||||
// Called by various SymSrv functions to report status as progress is made
|
||||
// and to allow the callback to influence processing. Messages sent to this
|
||||
// callback can be used to distinguish between the various failure modes
|
||||
// that SymFindFileInPath might encounter.
|
||||
static BOOL CALLBACK SymCallback(HANDLE process, ULONG action, ULONG64 data,
|
||||
ULONG64 context);
|
||||
|
||||
// Called by SymFindFileInPath (in LocateSymbolFile) after a candidate
|
||||
// symbol file is located, when it's present in the local cache.
|
||||
// SymFindFileInPath actually seems to accept NULL for a callback function
|
||||
// and behave properly for our needs in that case, but the documentation
|
||||
// doesn't mention it, so this little callback is provided.
|
||||
static BOOL CALLBACK SymFindFileInPathCallback(const char* filename,
|
||||
void* context);
|
||||
|
||||
// The search path used by SymSrv, built based on the arguments to the
|
||||
// constructor.
|
||||
string symbol_path_;
|
||||
|
||||
// SymCallback will set at least one of these failure variables if
|
||||
// SymFindFileInPath fails for an expected reason.
|
||||
bool fail_dns_; // DNS failures (fail_not_found_ will also be set).
|
||||
bool fail_timeout_; // Timeouts (fail_not_found_ will also be set).
|
||||
bool fail_http_https_redir_; // Bad URL-- we should be using HTTPS.
|
||||
bool fail_not_found_; // The file could not be found. If this is the only
|
||||
// fail_* member set, then it is authoritative.
|
||||
|
||||
// If set then callbacks from SymSrv will be logged to stderr.
|
||||
bool trace_symsrv_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_
|
33
externals/breakpad/src/tools/windows/converter_exe/configure.cmd
vendored
Normal file
33
externals/breakpad/src/tools/windows/converter_exe/configure.cmd
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
@if "%ECHOON%"=="" @echo off
|
||||
SETLOCAL
|
||||
|
||||
REM ******************************************************************
|
||||
REM Please, make sure to run this in an Elevated Command Prompt.
|
||||
REM Usage:
|
||||
REM configure.cmd
|
||||
REM ******************************************************************
|
||||
|
||||
REM ******************************************************************
|
||||
REM Initialize
|
||||
REM ******************************************************************
|
||||
SET SCRIPT_LOCATION=%~dp0
|
||||
|
||||
REM ******************************************************************
|
||||
REM Go to script location
|
||||
REM ******************************************************************
|
||||
pushd %SCRIPT_LOCATION%
|
||||
|
||||
REM ******************************************************************
|
||||
REM Register msdia140.dll.
|
||||
REM ******************************************************************
|
||||
SET MSG=Failed to register msdia140.dll. Make sure to run this in elevated command prompt.
|
||||
%systemroot%\SysWoW64\regsvr32.exe /s msdia140.dll & if errorlevel 1 echo %MSG% & goto :fail
|
||||
|
||||
:success
|
||||
echo Configuration was successful.
|
||||
ENDLOCAL
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
ENDLOCAL
|
||||
exit /b 1
|
908
externals/breakpad/src/tools/windows/converter_exe/converter.cc
vendored
Normal file
908
externals/breakpad/src/tools/windows/converter_exe/converter.cc
vendored
Normal file
|
@ -0,0 +1,908 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma comment(lib, "winhttp.lib")
|
||||
#pragma comment(lib, "wininet.lib")
|
||||
#pragma comment(lib, "diaguids.lib")
|
||||
#pragma comment(lib, "imagehlp.lib")
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/windows/http_upload.h"
|
||||
#include "common/windows/string_utils-inl.h"
|
||||
#include "common/windows/sym_upload_v2_protocol.h"
|
||||
#include "tools/windows/converter/ms_symbol_server_converter.h"
|
||||
#include "tools/windows/converter_exe/escaping.h"
|
||||
#include "tools/windows/converter_exe/http_download.h"
|
||||
#include "tools/windows/converter_exe/tokenizer.h"
|
||||
|
||||
using strings::WebSafeBase64Unescape;
|
||||
using strings::WebSafeBase64Escape;
|
||||
|
||||
namespace {
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::wstring;
|
||||
using crash::HTTPDownload;
|
||||
using crash::Tokenizer;
|
||||
using google_breakpad::HTTPUpload;
|
||||
using google_breakpad::MissingSymbolInfo;
|
||||
using google_breakpad::MSSymbolServerConverter;
|
||||
using google_breakpad::WindowsStringUtils;
|
||||
|
||||
const char* kMissingStringDelimiters = "|";
|
||||
const char* kLocalCachePath = "c:\\symbols";
|
||||
const char* kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/";
|
||||
const wchar_t* kSymbolUploadTypeBreakpad = L"BREAKPAD";
|
||||
const wchar_t* kSymbolUploadTypePE = L"PE";
|
||||
const wchar_t* kSymbolUploadTypePDB = L"PDB";
|
||||
const wchar_t* kConverterProductName = L"WinSymConv";
|
||||
|
||||
// Windows stdio doesn't do line buffering. Use this function to flush after
|
||||
// writing to stdout and stderr so that a log will be available if the
|
||||
// converter crashes.
|
||||
static int FprintfFlush(FILE* file, const char* format, ...) {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int retval = vfprintf(file, format, arguments);
|
||||
va_end(arguments);
|
||||
fflush(file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static string CurrentDateAndTime() {
|
||||
const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)";
|
||||
|
||||
time_t current_time;
|
||||
time(¤t_time);
|
||||
|
||||
// localtime_s is safer but is only available in MSVC8. Use localtime
|
||||
// in earlier environments.
|
||||
struct tm* time_pointer;
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
struct tm time_struct;
|
||||
time_pointer =& time_struct;
|
||||
if (localtime_s(time_pointer,& current_time) != 0) {
|
||||
return kUnknownDateAndTime;
|
||||
}
|
||||
#else // _MSC_VER >= 1400
|
||||
time_pointer = localtime(¤t_time);
|
||||
if (!time_pointer) {
|
||||
return kUnknownDateAndTime;
|
||||
}
|
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
char buffer[256];
|
||||
if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) {
|
||||
return kUnknownDateAndTime;
|
||||
}
|
||||
|
||||
return string(buffer);
|
||||
}
|
||||
|
||||
// ParseMissingString turns |missing_string| into a MissingSymbolInfo
|
||||
// structure. It returns true on success, and false if no such conversion
|
||||
// is possible.
|
||||
static bool ParseMissingString(const string& missing_string,
|
||||
MissingSymbolInfo* missing_info) {
|
||||
assert(missing_info);
|
||||
|
||||
vector<string> tokens;
|
||||
Tokenizer::Tokenize(kMissingStringDelimiters, missing_string,& tokens);
|
||||
if (tokens.size() != 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
missing_info->debug_file = tokens[0];
|
||||
missing_info->debug_identifier = tokens[1];
|
||||
missing_info->version = tokens[2];
|
||||
missing_info->code_file = tokens[3];
|
||||
missing_info->code_identifier = tokens[4];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// StringMapToWStringMap takes each element in a map that associates
|
||||
// (narrow) strings to strings and converts the keys and values to wstrings.
|
||||
// Returns true on success and false on failure, printing an error message.
|
||||
static bool StringMapToWStringMap(const map<string, string>& smap,
|
||||
map<wstring, wstring>* wsmap) {
|
||||
assert(wsmap);
|
||||
wsmap->clear();
|
||||
|
||||
for (map<string, string>::const_iterator iterator = smap.begin();
|
||||
iterator != smap.end();
|
||||
++iterator) {
|
||||
wstring key;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(iterator->first,& key)) {
|
||||
FprintfFlush(stderr,
|
||||
"StringMapToWStringMap: safe_mbstowcs failed for key %s\n",
|
||||
iterator->first.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring value;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(iterator->second,& value)) {
|
||||
FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed "
|
||||
"for value %s\n",
|
||||
iterator->second.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
wsmap->insert(make_pair(key, value));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a
|
||||
// map of parameters suitable for passing to HTTPDownload or HTTPUpload.
|
||||
// Returns true on success and false on failure, printing an error message.
|
||||
static bool MissingSymbolInfoToParameters(const MissingSymbolInfo& missing_info,
|
||||
map<wstring, wstring>* wparameters) {
|
||||
assert(wparameters);
|
||||
|
||||
map<string, string> parameters;
|
||||
string encoded_param;
|
||||
// Indicate the params are encoded.
|
||||
parameters["encoded"] = "true"; // The string value here does not matter.
|
||||
|
||||
WebSafeBase64Escape(missing_info.code_file,& encoded_param);
|
||||
parameters["code_file"] = encoded_param;
|
||||
|
||||
WebSafeBase64Escape(missing_info.code_identifier,& encoded_param);
|
||||
parameters["code_identifier"] = encoded_param;
|
||||
|
||||
WebSafeBase64Escape(missing_info.debug_file,& encoded_param);
|
||||
parameters["debug_file"] = encoded_param;
|
||||
|
||||
WebSafeBase64Escape(missing_info.debug_identifier,& encoded_param);
|
||||
parameters["debug_identifier"] = encoded_param;
|
||||
|
||||
if (!missing_info.version.empty()) {
|
||||
// The version is optional.
|
||||
WebSafeBase64Escape(missing_info.version,& encoded_param);
|
||||
parameters["version"] = encoded_param;
|
||||
}
|
||||
|
||||
WebSafeBase64Escape("WinSymConv",& encoded_param);
|
||||
parameters["product"] = encoded_param;
|
||||
|
||||
if (!StringMapToWStringMap(parameters, wparameters)) {
|
||||
// StringMapToWStringMap will have printed an error.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// UploadSymbolFile sends |converted_file| as identified by |debug_file| and
|
||||
// |debug_identifier|, to the symbol server rooted at |upload_symbol_url|.
|
||||
// Returns true on success and false on failure, printing an error message.
|
||||
static bool UploadSymbolFile(const wstring& upload_symbol_url,
|
||||
const wstring& api_key,
|
||||
const string& debug_file,
|
||||
const string& debug_identifier,
|
||||
const string& symbol_file,
|
||||
const wstring& symbol_type) {
|
||||
wstring debug_file_w;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(debug_file, &debug_file_w)) {
|
||||
FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
|
||||
symbol_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring debug_id_w;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(debug_identifier, &debug_id_w)) {
|
||||
FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
|
||||
symbol_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring symbol_file_w;
|
||||
if (!WindowsStringUtils::safe_mbstowcs(symbol_file, &symbol_file_w)) {
|
||||
FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
|
||||
symbol_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int timeout_ms = 60 * 1000;
|
||||
FprintfFlush(stderr, "Uploading %s\n", symbol_file.c_str());
|
||||
if (!google_breakpad::SymUploadV2ProtocolSend(
|
||||
upload_symbol_url.c_str(), api_key.c_str(), &timeout_ms, debug_file_w,
|
||||
debug_id_w, symbol_file_w, symbol_type, kConverterProductName,
|
||||
/*force=*/true)) {
|
||||
FprintfFlush(stderr,
|
||||
"UploadSymbolFile: HTTPUpload::SendRequest failed "
|
||||
"for %s %s\n",
|
||||
debug_file.c_str(), debug_identifier.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// SendFetchFailedPing informs the symbol server based at
|
||||
// |fetch_symbol_failure_url| that the symbol file identified by
|
||||
// |missing_info| could authoritatively not be located. Returns
|
||||
// true on success and false on failure.
|
||||
static bool SendFetchFailedPing(const wstring& fetch_symbol_failure_url,
|
||||
const MissingSymbolInfo& missing_info) {
|
||||
map<wstring, wstring> parameters;
|
||||
if (!MissingSymbolInfoToParameters(missing_info,& parameters)) {
|
||||
// MissingSymbolInfoToParameters or a callee will have printed an error.
|
||||
return false;
|
||||
}
|
||||
|
||||
string content;
|
||||
if (!HTTPDownload::Download(fetch_symbol_failure_url,
|
||||
& parameters,
|
||||
& content,
|
||||
NULL)) {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed "
|
||||
"for %s %s %s\n",
|
||||
missing_info.debug_file.c_str(),
|
||||
missing_info.debug_identifier.c_str(),
|
||||
missing_info.version.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if it's safe to make an external request for the symbol
|
||||
// file described in missing_info. It's considered safe to make an
|
||||
// external request unless the symbol file's debug_file string matches
|
||||
// the given blacklist regular expression.
|
||||
// The debug_file name is used from the MissingSymbolInfo struct,
|
||||
// matched against the blacklist_regex.
|
||||
static bool SafeToMakeExternalRequest(const MissingSymbolInfo& missing_info,
|
||||
std::regex blacklist_regex) {
|
||||
string file_name = missing_info.debug_file;
|
||||
// Use regex_search because we want to match substrings.
|
||||
if (std::regex_search(file_name, blacklist_regex)) {
|
||||
FprintfFlush(stderr, "Not safe to make external request for file %s\n",
|
||||
file_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Converter options derived from command line parameters.
|
||||
struct ConverterOptions {
|
||||
ConverterOptions()
|
||||
: report_fetch_failures(true), trace_symsrv(false), keep_files(false) {}
|
||||
|
||||
~ConverterOptions() {
|
||||
}
|
||||
|
||||
// Names of MS Symbol Supplier Servers that are internal to Google, and may
|
||||
// have symbols for any request.
|
||||
vector<string> full_internal_msss_servers;
|
||||
|
||||
// Names of MS Symbol Supplier Servers that are internal to Google, and
|
||||
// shouldn't be checked for symbols for any .exe files.
|
||||
vector<string> full_external_msss_servers;
|
||||
|
||||
// Names of MS Symbol Supplier Servers that are external to Google, and may
|
||||
// have symbols for any request.
|
||||
vector<string> no_exe_internal_msss_servers;
|
||||
|
||||
// Names of MS Symbol Supplier Servers that are external to Google, and
|
||||
// shouldn't be checked for symbols for any .exe files.
|
||||
vector<string> no_exe_external_msss_servers;
|
||||
|
||||
// Temporary local storage for symbols.
|
||||
string local_cache_path;
|
||||
|
||||
// URL for uploading symbols.
|
||||
wstring upload_symbols_url;
|
||||
|
||||
// API key to use when uploading symbols.
|
||||
wstring api_key;
|
||||
|
||||
// URL to fetch list of missing symbols.
|
||||
wstring missing_symbols_url;
|
||||
|
||||
// URL to report symbol fetch failure.
|
||||
wstring fetch_symbol_failure_url;
|
||||
|
||||
// Are symbol fetch failures reported.
|
||||
bool report_fetch_failures;
|
||||
|
||||
// File containing the list of missing symbols. Fetch failures are not
|
||||
// reported if such file is provided.
|
||||
string missing_symbols_file;
|
||||
|
||||
// Regex used to blacklist files to prevent external symbol requests.
|
||||
// Owned and cleaned up by this struct.
|
||||
std::regex blacklist_regex;
|
||||
|
||||
// If set then SymSrv callbacks are logged to stderr.
|
||||
bool trace_symsrv;
|
||||
|
||||
// If set then Breakpad/PE/PDB files won't be deleted after processing.
|
||||
bool keep_files;
|
||||
|
||||
private:
|
||||
// DISABLE_COPY_AND_ASSIGN
|
||||
ConverterOptions(const ConverterOptions&);
|
||||
ConverterOptions& operator=(const ConverterOptions&);
|
||||
};
|
||||
|
||||
// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and
|
||||
// attempts to locate it from the symbol servers provided in the
|
||||
// |options.*_msss_servers| arguments. "Full" servers are those that will be
|
||||
// queried for all symbol files; "No-EXE" servers will only be queried for
|
||||
// modules whose missing symbol data indicates are not main program executables.
|
||||
// Results will be sent to the |options.upload_symbols_url| on success or
|
||||
// |options.fetch_symbol_failure_url| on failure, and the local cache will be
|
||||
// stored at |options.local_cache_path|. Because nothing can be done even in
|
||||
// the event of a failure, this function returns no value, although it
|
||||
// may result in error messages being printed.
|
||||
static void ConvertMissingSymbolFile(const MissingSymbolInfo& missing_info,
|
||||
const ConverterOptions& options) {
|
||||
string time_string = CurrentDateAndTime();
|
||||
FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n",
|
||||
time_string.c_str(),
|
||||
missing_info.debug_file.c_str(),
|
||||
missing_info.debug_identifier.c_str(),
|
||||
missing_info.version.c_str());
|
||||
|
||||
// The first lookup is always to internal symbol servers.
|
||||
// Always ask the symbol servers identified as "full."
|
||||
vector<string> msss_servers = options.full_internal_msss_servers;
|
||||
|
||||
// If the file is not an .exe file, also ask an additional set of symbol
|
||||
// servers, such as Microsoft's public symbol server.
|
||||
bool is_exe = false;
|
||||
|
||||
if (missing_info.code_file.length() >= 4) {
|
||||
string code_extension =
|
||||
missing_info.code_file.substr(missing_info.code_file.size() - 4);
|
||||
|
||||
// Firefox is a special case: .dll-only servers should be consulted for
|
||||
// its symbols. This enables us to get its symbols from Mozilla's
|
||||
// symbol server when crashes occur in Google extension code hosted by a
|
||||
// Firefox process.
|
||||
if (_stricmp(code_extension.c_str(), ".exe") == 0 &&
|
||||
_stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) {
|
||||
is_exe = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_exe) {
|
||||
msss_servers.insert(msss_servers.end(),
|
||||
options.no_exe_internal_msss_servers.begin(),
|
||||
options.no_exe_internal_msss_servers.end());
|
||||
}
|
||||
|
||||
// If there are any suitable internal symbol servers, make a request.
|
||||
MSSymbolServerConverter::LocateResult located =
|
||||
MSSymbolServerConverter::LOCATE_FAILURE;
|
||||
string converted_file;
|
||||
string symbol_file;
|
||||
string pe_file;
|
||||
if (msss_servers.size() > 0) {
|
||||
// Attempt to fetch the symbol file and convert it.
|
||||
FprintfFlush(stderr, "Making internal request for %s (%s)\n",
|
||||
missing_info.debug_file.c_str(),
|
||||
missing_info.debug_identifier.c_str());
|
||||
MSSymbolServerConverter converter(options.local_cache_path, msss_servers,
|
||||
options.trace_symsrv);
|
||||
located = converter.LocateAndConvertSymbolFile(
|
||||
missing_info,
|
||||
/*keep_symbol_file=*/true,
|
||||
/*keep_pe_file=*/true, &converted_file, &symbol_file, &pe_file);
|
||||
switch (located) {
|
||||
case MSSymbolServerConverter::LOCATE_SUCCESS:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
|
||||
// Upload it. Don't bother checking the return value. If this
|
||||
// succeeds, it should disappear from the missing symbol list.
|
||||
// If it fails, something will print an error message indicating
|
||||
// the cause of the failure, and the item will remain on the
|
||||
// missing symbol list.
|
||||
UploadSymbolFile(options.upload_symbols_url, options.api_key,
|
||||
missing_info.debug_file, missing_info.debug_identifier,
|
||||
converted_file, kSymbolUploadTypeBreakpad);
|
||||
if (!options.keep_files)
|
||||
remove(converted_file.c_str());
|
||||
|
||||
// Upload PDB/PE if we have them
|
||||
if (!symbol_file.empty()) {
|
||||
UploadSymbolFile(options.upload_symbols_url, options.api_key,
|
||||
missing_info.debug_file,
|
||||
missing_info.debug_identifier, symbol_file,
|
||||
kSymbolUploadTypePDB);
|
||||
if (!options.keep_files)
|
||||
remove(symbol_file.c_str());
|
||||
}
|
||||
if (!pe_file.empty()) {
|
||||
UploadSymbolFile(options.upload_symbols_url, options.api_key,
|
||||
missing_info.code_file,
|
||||
missing_info.debug_identifier, pe_file,
|
||||
kSymbolUploadTypePE);
|
||||
if (!options.keep_files)
|
||||
remove(pe_file.c_str());
|
||||
}
|
||||
|
||||
// Note: this does leave some directories behind that could be
|
||||
// cleaned up. The directories inside options.local_cache_path for
|
||||
// debug_file/debug_identifier can be removed at this point.
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_NOT_FOUND:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n");
|
||||
// The symbol file definitively did not exist. Fall through,
|
||||
// so we can attempt an external query if it's safe to do so.
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_RETRY:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
|
||||
// Fall through in case we should make an external request.
|
||||
// If not, or if an external request fails in the same way,
|
||||
// we'll leave the entry in the symbol file list and
|
||||
// try again on a future pass. Print a message so that there's
|
||||
// a record.
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_HTTP_HTTPS_REDIR:
|
||||
FprintfFlush(
|
||||
stderr,
|
||||
"LocateResult = LOCATE_HTTP_HTTPS_REDIR\n"
|
||||
"One of the specified URLs is using HTTP, which causes a redirect "
|
||||
"from the server to HTTPS, which causes the SymSrv lookup to "
|
||||
"fail.\n"
|
||||
"This URL must be replaced with the correct HTTPS URL.\n");
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_FAILURE:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
|
||||
// LocateAndConvertSymbolFile printed an error message.
|
||||
break;
|
||||
|
||||
default:
|
||||
FprintfFlush(
|
||||
stderr,
|
||||
"FATAL: Unexpected return value '%d' from "
|
||||
"LocateAndConvertSymbolFile()\n",
|
||||
located);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// No suitable internal symbol servers. This is fine because the converter
|
||||
// is mainly used for downloading and converting of external symbols.
|
||||
}
|
||||
|
||||
// Make a request to an external server if the internal request didn't
|
||||
// succeed, and it's safe to do so.
|
||||
if (located != MSSymbolServerConverter::LOCATE_SUCCESS &&
|
||||
SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) {
|
||||
msss_servers = options.full_external_msss_servers;
|
||||
if (!is_exe) {
|
||||
msss_servers.insert(msss_servers.end(),
|
||||
options.no_exe_external_msss_servers.begin(),
|
||||
options.no_exe_external_msss_servers.end());
|
||||
}
|
||||
if (msss_servers.size() > 0) {
|
||||
FprintfFlush(stderr, "Making external request for %s (%s)\n",
|
||||
missing_info.debug_file.c_str(),
|
||||
missing_info.debug_identifier.c_str());
|
||||
MSSymbolServerConverter external_converter(
|
||||
options.local_cache_path, msss_servers, options.trace_symsrv);
|
||||
located = external_converter.LocateAndConvertSymbolFile(
|
||||
missing_info,
|
||||
/*keep_symbol_file=*/true,
|
||||
/*keep_pe_file=*/true, &converted_file, &symbol_file, &pe_file);
|
||||
} else {
|
||||
FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Final handling for this symbol file is based on the result from the
|
||||
// external request (if performed above), or on the result from the
|
||||
// previous internal lookup.
|
||||
switch (located) {
|
||||
case MSSymbolServerConverter::LOCATE_SUCCESS:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
|
||||
// Upload it. Don't bother checking the return value. If this
|
||||
// succeeds, it should disappear from the missing symbol list.
|
||||
// If it fails, something will print an error message indicating
|
||||
// the cause of the failure, and the item will remain on the
|
||||
// missing symbol list.
|
||||
UploadSymbolFile(options.upload_symbols_url, options.api_key,
|
||||
missing_info.debug_file, missing_info.debug_identifier,
|
||||
converted_file, kSymbolUploadTypeBreakpad);
|
||||
if (!options.keep_files)
|
||||
remove(converted_file.c_str());
|
||||
|
||||
// Upload PDB/PE if we have them
|
||||
if (!symbol_file.empty()) {
|
||||
UploadSymbolFile(options.upload_symbols_url, options.api_key,
|
||||
missing_info.debug_file, missing_info.debug_identifier,
|
||||
symbol_file, kSymbolUploadTypePDB);
|
||||
if (!options.keep_files)
|
||||
remove(symbol_file.c_str());
|
||||
}
|
||||
if (!pe_file.empty()) {
|
||||
UploadSymbolFile(options.upload_symbols_url, options.api_key,
|
||||
missing_info.code_file, missing_info.debug_identifier,
|
||||
pe_file, kSymbolUploadTypePE);
|
||||
if (!options.keep_files)
|
||||
remove(pe_file.c_str());
|
||||
}
|
||||
|
||||
// Note: this does leave some directories behind that could be
|
||||
// cleaned up. The directories inside options.local_cache_path for
|
||||
// debug_file/debug_identifier can be removed at this point.
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_NOT_FOUND:
|
||||
// The symbol file definitively didn't exist. Inform the server.
|
||||
// If this fails, something will print an error message indicating
|
||||
// the cause of the failure, but there's really nothing more to
|
||||
// do. If this succeeds, the entry should be removed from the
|
||||
// missing symbols list.
|
||||
if (!options.report_fetch_failures) {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
|
||||
} else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
|
||||
missing_info)) {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
|
||||
} else {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing failed\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_RETRY:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
|
||||
// Nothing to do but leave the entry in the symbol file list and
|
||||
// try again on a future pass. Print a message so that there's
|
||||
// a record.
|
||||
FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry "
|
||||
"for %s %s %s\n",
|
||||
missing_info.debug_file.c_str(),
|
||||
missing_info.debug_identifier.c_str(),
|
||||
missing_info.version.c_str());
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_HTTP_HTTPS_REDIR:
|
||||
FprintfFlush(
|
||||
stderr,
|
||||
"LocateResult = LOCATE_HTTP_HTTPS_REDIR\n"
|
||||
"One of the specified URLs is using HTTP, which causes a redirect "
|
||||
"from the server to HTTPS, which causes the SymSrv lookup to fail.\n"
|
||||
"This URL must be replaced with the correct HTTPS URL.\n");
|
||||
break;
|
||||
|
||||
case MSSymbolServerConverter::LOCATE_FAILURE:
|
||||
FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
|
||||
// LocateAndConvertSymbolFile printed an error message.
|
||||
|
||||
// This is due to a bad debug file name, so fetch failed.
|
||||
if (!options.report_fetch_failures) {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
|
||||
} else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
|
||||
missing_info)) {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
|
||||
} else {
|
||||
FprintfFlush(stderr, "SendFetchFailedPing failed\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
FprintfFlush(
|
||||
stderr,
|
||||
"FATAL: Unexpected return value '%d' from "
|
||||
"LocateAndConvertSymbolFile()\n",
|
||||
located);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reads the contents of file |file_name| and populates |contents|.
|
||||
// Returns true on success.
|
||||
static bool ReadFile(string file_name, string* contents) {
|
||||
char buffer[1024 * 8];
|
||||
FILE* fp = fopen(file_name.c_str(), "rt");
|
||||
if (!fp) {
|
||||
return false;
|
||||
}
|
||||
contents->clear();
|
||||
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
|
||||
contents->append(buffer);
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ConvertMissingSymbolsList obtains a missing symbol list from
|
||||
// |options.missing_symbols_url| or |options.missing_symbols_file| and calls
|
||||
// ConvertMissingSymbolFile for each missing symbol file in the list.
|
||||
static bool ConvertMissingSymbolsList(const ConverterOptions& options) {
|
||||
// Set param to indicate requesting for encoded response.
|
||||
map<wstring, wstring> parameters;
|
||||
parameters[L"product"] = kConverterProductName;
|
||||
parameters[L"encoded"] = L"true";
|
||||
// Get the missing symbol list.
|
||||
string missing_symbol_list;
|
||||
if (!options.missing_symbols_file.empty()) {
|
||||
if (!ReadFile(options.missing_symbols_file,& missing_symbol_list)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!HTTPDownload::Download(options.missing_symbols_url,& parameters,
|
||||
& missing_symbol_list, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tokenize the content into a vector.
|
||||
vector<string> missing_symbol_lines;
|
||||
Tokenizer::Tokenize("\n", missing_symbol_list,& missing_symbol_lines);
|
||||
|
||||
FprintfFlush(stderr, "Found %d missing symbol files in list.\n",
|
||||
missing_symbol_lines.size() - 1); // last line is empty.
|
||||
int convert_attempts = 0;
|
||||
for (vector<string>::const_iterator iterator = missing_symbol_lines.begin();
|
||||
iterator != missing_symbol_lines.end();
|
||||
++iterator) {
|
||||
// Decode symbol line.
|
||||
const string& encoded_line = *iterator;
|
||||
// Skip lines that are blank.
|
||||
if (encoded_line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string line;
|
||||
if (!WebSafeBase64Unescape(encoded_line,& line)) {
|
||||
// If decoding fails, assume the line is not encoded.
|
||||
// This is helpful when the program connects to a debug server without
|
||||
// encoding.
|
||||
line = encoded_line;
|
||||
}
|
||||
|
||||
FprintfFlush(stderr, "\nLine: %s\n", line.c_str());
|
||||
|
||||
// Turn each element into a MissingSymbolInfo structure.
|
||||
MissingSymbolInfo missing_info;
|
||||
if (!ParseMissingString(line,& missing_info)) {
|
||||
FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed "
|
||||
"for %s from %ws\n",
|
||||
line.c_str(), options.missing_symbols_url.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
++convert_attempts;
|
||||
ConvertMissingSymbolFile(missing_info, options);
|
||||
}
|
||||
|
||||
// Say something reassuring, since ConvertMissingSymbolFile was never called
|
||||
// and therefore never reported any progress.
|
||||
if (convert_attempts == 0) {
|
||||
string current_time = CurrentDateAndTime();
|
||||
FprintfFlush(stdout, "converter: %s: nothing to convert\n",
|
||||
current_time.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// usage prints the usage message. It returns 1 as a convenience, to be used
|
||||
// as a return value from main.
|
||||
static int usage(const char* program_name) {
|
||||
FprintfFlush(
|
||||
stderr,
|
||||
"usage: %s [options]\n"
|
||||
" -f <full_msss_server> MS servers to ask for all symbols\n"
|
||||
" -n <no_exe_msss_server> same, but prevent asking for EXEs\n"
|
||||
" -l <local_cache_path> Temporary local storage for symbols\n"
|
||||
" -s <upload_url> URL for uploading symbols\n"
|
||||
" -k <api_key> API key to use when uploading symbols\n"
|
||||
" -m <missing_symbols_url> URL to fetch list of missing symbols\n"
|
||||
" -mf <missing_symbols_file> File containing the list of missing\n"
|
||||
" symbols. Fetch failures are not\n"
|
||||
" reported if such file is provided.\n"
|
||||
" -t <fetch_failure_url> URL to report symbol fetch failure\n"
|
||||
" -b <regex> Regex used to blacklist files to\n"
|
||||
" prevent external symbol requests\n"
|
||||
" -tss If set then SymSrv callbacks will be\n"
|
||||
" traced to stderr.\n"
|
||||
" -keep-files If set then don't delete Breakpad/PE/\n"
|
||||
" PDB files after conversion.\n"
|
||||
" Note that any server specified by -f or -n that starts with \\filer\n"
|
||||
" will be treated as internal, and all others as external.\n",
|
||||
program_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// "Internal" servers consist only of those whose names start with
|
||||
// the literal string "\\filer\".
|
||||
static bool IsInternalServer(const string& server_name) {
|
||||
if (server_name.find("\\\\filer\\") == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Adds a server with the given name to the list of internal or external
|
||||
// servers, as appropriate.
|
||||
static void AddServer(const string& server_name,
|
||||
vector<string>* internal_servers,
|
||||
vector<string>* external_servers) {
|
||||
if (IsInternalServer(server_name)) {
|
||||
internal_servers->push_back(server_name);
|
||||
} else {
|
||||
external_servers->push_back(server_name);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
string time_string = CurrentDateAndTime();
|
||||
FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str());
|
||||
|
||||
ConverterOptions options;
|
||||
options.report_fetch_failures = true;
|
||||
|
||||
string blacklist_regex_str;
|
||||
bool have_any_msss_servers = false;
|
||||
for (int argi = 1; argi < argc; argi++) {
|
||||
string option = argv[argi];
|
||||
if (option == "-tss") {
|
||||
printf("Tracing SymSrv callbacks to stderr.\n");
|
||||
options.trace_symsrv = true;
|
||||
continue;
|
||||
} else if (option == "-keep-files") {
|
||||
printf("Keeping Breakpad/PE/PDB files after conversion.\n");
|
||||
options.keep_files = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
string value = argv[++argi];
|
||||
if (option == "-f") {
|
||||
AddServer(value,& options.full_internal_msss_servers,
|
||||
& options.full_external_msss_servers);
|
||||
have_any_msss_servers = true;
|
||||
} else if (option == "-n") {
|
||||
AddServer(value,& options.no_exe_internal_msss_servers,
|
||||
& options.no_exe_external_msss_servers);
|
||||
have_any_msss_servers = true;
|
||||
} else if (option == "-l") {
|
||||
if (!options.local_cache_path.empty()) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
options.local_cache_path = value;
|
||||
} else if (option == "-s") {
|
||||
if (!WindowsStringUtils::safe_mbstowcs(value,
|
||||
& options.upload_symbols_url)) {
|
||||
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
|
||||
value.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (option == "-k") {
|
||||
if (!WindowsStringUtils::safe_mbstowcs(value, &options.api_key)) {
|
||||
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
|
||||
value.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (option == "-m") {
|
||||
if (!WindowsStringUtils::safe_mbstowcs(value,
|
||||
& options.missing_symbols_url)) {
|
||||
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
|
||||
value.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (option == "-mf") {
|
||||
options.missing_symbols_file = value;
|
||||
printf("Getting the list of missing symbols from a file. Fetch failures"
|
||||
" will not be reported.\n");
|
||||
options.report_fetch_failures = false;
|
||||
} else if (option == "-t") {
|
||||
if (!WindowsStringUtils::safe_mbstowcs(
|
||||
value,
|
||||
& options.fetch_symbol_failure_url)) {
|
||||
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
|
||||
value.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (option == "-b") {
|
||||
blacklist_regex_str = value;
|
||||
} else {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (blacklist_regex_str.empty()) {
|
||||
FprintfFlush(stderr, "No blacklist specified.\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
// Compile the blacklist regular expression for later use.
|
||||
options.blacklist_regex = std::regex(blacklist_regex_str.c_str(),
|
||||
std::regex_constants::icase);
|
||||
|
||||
// Set the defaults. If the user specified any MSSS servers, don't use
|
||||
// any default.
|
||||
if (!have_any_msss_servers) {
|
||||
AddServer(kNoExeMSSSServer,& options.no_exe_internal_msss_servers,
|
||||
& options.no_exe_external_msss_servers);
|
||||
}
|
||||
|
||||
if (options.local_cache_path.empty()) {
|
||||
options.local_cache_path = kLocalCachePath;
|
||||
}
|
||||
|
||||
if (options.upload_symbols_url.empty()) {
|
||||
FprintfFlush(stderr, "No upload symbols URL specified.\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
if (options.api_key.empty()) {
|
||||
FprintfFlush(stderr, "No API key specified.\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
if (options.missing_symbols_url.empty() &&
|
||||
options.missing_symbols_file.empty()) {
|
||||
FprintfFlush(stderr, "No missing symbols URL or file specified.\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
if (options.fetch_symbol_failure_url.empty()) {
|
||||
FprintfFlush(stderr, "No fetch symbol failure URL specified.\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
FprintfFlush(stdout,
|
||||
"# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n",
|
||||
options.full_internal_msss_servers.size(),
|
||||
options.full_external_msss_servers.size(),
|
||||
options.no_exe_internal_msss_servers.size(),
|
||||
options.no_exe_external_msss_servers.size());
|
||||
|
||||
if (!ConvertMissingSymbolsList(options)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
time_string = CurrentDateAndTime();
|
||||
FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str());
|
||||
return 0;
|
||||
}
|
761
externals/breakpad/src/tools/windows/converter_exe/escaping.cc
vendored
Normal file
761
externals/breakpad/src/tools/windows/converter_exe/escaping.cc
vendored
Normal file
|
@ -0,0 +1,761 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "tools/windows/converter_exe/escaping.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define kApb kAsciiPropertyBits
|
||||
|
||||
const unsigned char kAsciiPropertyBits[256] = {
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
|
||||
0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
|
||||
0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
|
||||
0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
|
||||
};
|
||||
|
||||
// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'.
|
||||
static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); }
|
||||
|
||||
///////////////////////////////////
|
||||
// scoped_array
|
||||
///////////////////////////////////
|
||||
// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
|
||||
// with new [] and the destructor deletes objects with delete [].
|
||||
//
|
||||
// As with scoped_ptr<C>, a scoped_array<C> either points to an object
|
||||
// or is NULL. A scoped_array<C> owns the object that it points to.
|
||||
// scoped_array<T> is thread-compatible, and once you index into it,
|
||||
// the returned objects have only the threadsafety guarantees of T.
|
||||
//
|
||||
// Size: sizeof(scoped_array<C>) == sizeof(C*)
|
||||
template <class C>
|
||||
class scoped_array {
|
||||
public:
|
||||
|
||||
// The element type
|
||||
typedef C element_type;
|
||||
|
||||
// Constructor. Defaults to intializing with NULL.
|
||||
// There is no way to create an uninitialized scoped_array.
|
||||
// The input parameter must be allocated with new [].
|
||||
explicit scoped_array(C* p = NULL) : array_(p) { }
|
||||
|
||||
// Destructor. If there is a C object, delete it.
|
||||
// We don't need to test ptr_ == NULL because C++ does that for us.
|
||||
~scoped_array() {
|
||||
enum { type_must_be_complete = sizeof(C) };
|
||||
delete[] array_;
|
||||
}
|
||||
|
||||
// Reset. Deletes the current owned object, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
// this->reset(this->get()) works.
|
||||
void reset(C* p = NULL) {
|
||||
if (p != array_) {
|
||||
enum { type_must_be_complete = sizeof(C) };
|
||||
delete[] array_;
|
||||
array_ = p;
|
||||
}
|
||||
}
|
||||
|
||||
// Get one element of the current object.
|
||||
// Will assert() if there is no current object, or index i is negative.
|
||||
C& operator[](std::ptrdiff_t i) const {
|
||||
assert(i >= 0);
|
||||
assert(array_ != NULL);
|
||||
return array_[i];
|
||||
}
|
||||
|
||||
// Get a pointer to the zeroth element of the current object.
|
||||
// If there is no current object, return NULL.
|
||||
C* get() const {
|
||||
return array_;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether a scoped_array and a raw pointer refer to
|
||||
// the same array, not just to two different but equal arrays.
|
||||
bool operator==(const C* p) const { return array_ == p; }
|
||||
bool operator!=(const C* p) const { return array_ != p; }
|
||||
|
||||
// Swap two scoped arrays.
|
||||
void swap(scoped_array& p2) {
|
||||
C* tmp = array_;
|
||||
array_ = p2.array_;
|
||||
p2.array_ = tmp;
|
||||
}
|
||||
|
||||
// Release an array.
|
||||
// The return value is the current pointer held by this object.
|
||||
// If this object holds a NULL pointer, the return value is NULL.
|
||||
// After this operation, this object will hold a NULL pointer,
|
||||
// and will not own the object any more.
|
||||
C* release() {
|
||||
C* retVal = array_;
|
||||
array_ = NULL;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private:
|
||||
C* array_;
|
||||
|
||||
// Forbid comparison of different scoped_array types.
|
||||
template <class C2> bool operator==(scoped_array<C2> const& p2) const;
|
||||
template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
|
||||
|
||||
// Disallow evil constructors
|
||||
scoped_array(const scoped_array&);
|
||||
void operator=(const scoped_array&);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Escape methods
|
||||
///////////////////////////////////
|
||||
|
||||
namespace strings {
|
||||
|
||||
// Return a mutable char* pointing to a string's internal buffer,
|
||||
// which may not be null-terminated. Writing through this pointer will
|
||||
// modify the string.
|
||||
//
|
||||
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
||||
// next call to a string method that invalidates iterators.
|
||||
//
|
||||
// As of 2006-04, there is no standard-blessed way of getting a
|
||||
// mutable reference to a string's internal buffer. However, issue 530
|
||||
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
|
||||
// proposes this as the method. According to Matt Austern, this should
|
||||
// already work on all current implementations.
|
||||
inline char* string_as_array(string* str) {
|
||||
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
|
||||
return str->empty() ? NULL : &*str->begin();
|
||||
}
|
||||
|
||||
int CalculateBase64EscapedLen(int input_len, bool do_padding) {
|
||||
// these formulae were copied from comments that used to go with the base64
|
||||
// encoding functions
|
||||
int intermediate_result = 8 * input_len + 5;
|
||||
assert(intermediate_result > 0); // make sure we didn't overflow
|
||||
int len = intermediate_result / 6;
|
||||
if (do_padding) len = ((len + 3) / 4) * 4;
|
||||
return len;
|
||||
}
|
||||
|
||||
// Base64Escape does padding, so this calculation includes padding.
|
||||
int CalculateBase64EscapedLen(int input_len) {
|
||||
return CalculateBase64EscapedLen(input_len, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// int Base64Unescape() - base64 decoder
|
||||
// int Base64Escape() - base64 encoder
|
||||
// int WebSafeBase64Unescape() - Google's variation of base64 decoder
|
||||
// int WebSafeBase64Escape() - Google's variation of base64 encoder
|
||||
//
|
||||
// Check out
|
||||
// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
|
||||
// description, but what we care about is that...
|
||||
// Take the encoded stuff in groups of 4 characters and turn each
|
||||
// character into a code 0 to 63 thus:
|
||||
// A-Z map to 0 to 25
|
||||
// a-z map to 26 to 51
|
||||
// 0-9 map to 52 to 61
|
||||
// +(- for WebSafe) maps to 62
|
||||
// /(_ for WebSafe) maps to 63
|
||||
// There will be four numbers, all less than 64 which can be represented
|
||||
// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
|
||||
// Arrange the 6 digit binary numbers into three bytes as such:
|
||||
// aaaaaabb bbbbcccc ccdddddd
|
||||
// Equals signs (one or two) are used at the end of the encoded block to
|
||||
// indicate that the text was not an integer multiple of three bytes long.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int Base64UnescapeInternal(const char *src, int szsrc,
|
||||
char *dest, int szdest,
|
||||
const signed char* unbase64) {
|
||||
static const char kPad64 = '=';
|
||||
|
||||
int decode = 0;
|
||||
int destidx = 0;
|
||||
int state = 0;
|
||||
unsigned int ch = 0;
|
||||
unsigned int temp = 0;
|
||||
|
||||
// The GET_INPUT macro gets the next input character, skipping
|
||||
// over any whitespace, and stopping when we reach the end of the
|
||||
// string or when we read any non-data character. The arguments are
|
||||
// an arbitrary identifier (used as a label for goto) and the number
|
||||
// of data bytes that must remain in the input to avoid aborting the
|
||||
// loop.
|
||||
#define GET_INPUT(label, remain) \
|
||||
label: \
|
||||
--szsrc; \
|
||||
ch = *src++; \
|
||||
decode = unbase64[ch]; \
|
||||
if (decode < 0) { \
|
||||
if (ascii_isspace((char)ch) && szsrc >= remain) \
|
||||
goto label; \
|
||||
state = 4 - remain; \
|
||||
break; \
|
||||
}
|
||||
|
||||
// if dest is null, we're just checking to see if it's legal input
|
||||
// rather than producing output. (I suspect this could just be done
|
||||
// with a regexp...). We duplicate the loop so this test can be
|
||||
// outside it instead of in every iteration.
|
||||
|
||||
if (dest) {
|
||||
// This loop consumes 4 input bytes and produces 3 output bytes
|
||||
// per iteration. We can't know at the start that there is enough
|
||||
// data left in the string for a full iteration, so the loop may
|
||||
// break out in the middle; if so 'state' will be set to the
|
||||
// number of input bytes read.
|
||||
|
||||
while (szsrc >= 4) {
|
||||
// We'll start by optimistically assuming that the next four
|
||||
// bytes of the string (src[0..3]) are four good data bytes
|
||||
// (that is, no nulls, whitespace, padding chars, or illegal
|
||||
// chars). We need to test src[0..2] for nulls individually
|
||||
// before constructing temp to preserve the property that we
|
||||
// never read past a null in the string (no matter how long
|
||||
// szsrc claims the string is).
|
||||
|
||||
if (!src[0] || !src[1] || !src[2] ||
|
||||
(temp = ((unbase64[static_cast<int>(src[0])] << 18) |
|
||||
(unbase64[static_cast<int>(src[1])] << 12) |
|
||||
(unbase64[static_cast<int>(src[2])] << 6) |
|
||||
(unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
|
||||
// Iff any of those four characters was bad (null, illegal,
|
||||
// whitespace, padding), then temp's high bit will be set
|
||||
// (because unbase64[] is -1 for all bad characters).
|
||||
//
|
||||
// We'll back up and resort to the slower decoder, which knows
|
||||
// how to handle those cases.
|
||||
|
||||
GET_INPUT(first, 4);
|
||||
temp = decode;
|
||||
GET_INPUT(second, 3);
|
||||
temp = (temp << 6) | decode;
|
||||
GET_INPUT(third, 2);
|
||||
temp = (temp << 6) | decode;
|
||||
GET_INPUT(fourth, 1);
|
||||
temp = (temp << 6) | decode;
|
||||
} else {
|
||||
// We really did have four good data bytes, so advance four
|
||||
// characters in the string.
|
||||
|
||||
szsrc -= 4;
|
||||
src += 4;
|
||||
decode = -1;
|
||||
ch = '\0';
|
||||
}
|
||||
|
||||
// temp has 24 bits of input, so write that out as three bytes.
|
||||
|
||||
if (destidx+3 > szdest) return -1;
|
||||
dest[destidx+2] = (char)temp;
|
||||
temp >>= 8;
|
||||
dest[destidx+1] = (char)temp;
|
||||
temp >>= 8;
|
||||
dest[destidx] = (char)temp;
|
||||
destidx += 3;
|
||||
}
|
||||
} else {
|
||||
while (szsrc >= 4) {
|
||||
if (!src[0] || !src[1] || !src[2] ||
|
||||
(temp = ((unbase64[static_cast<int>(src[0])] << 18) |
|
||||
(unbase64[static_cast<int>(src[1])] << 12) |
|
||||
(unbase64[static_cast<int>(src[2])] << 6) |
|
||||
(unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
|
||||
GET_INPUT(first_no_dest, 4);
|
||||
GET_INPUT(second_no_dest, 3);
|
||||
GET_INPUT(third_no_dest, 2);
|
||||
GET_INPUT(fourth_no_dest, 1);
|
||||
} else {
|
||||
szsrc -= 4;
|
||||
src += 4;
|
||||
decode = -1;
|
||||
ch = '\0';
|
||||
}
|
||||
destidx += 3;
|
||||
}
|
||||
}
|
||||
|
||||
#undef GET_INPUT
|
||||
|
||||
// if the loop terminated because we read a bad character, return
|
||||
// now.
|
||||
if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch))
|
||||
return -1;
|
||||
|
||||
if (ch == kPad64) {
|
||||
// if we stopped by hitting an '=', un-read that character -- we'll
|
||||
// look at it again when we count to check for the proper number of
|
||||
// equals signs at the end.
|
||||
++szsrc;
|
||||
--src;
|
||||
} else {
|
||||
// This loop consumes 1 input byte per iteration. It's used to
|
||||
// clean up the 0-3 input bytes remaining when the first, faster
|
||||
// loop finishes. 'temp' contains the data from 'state' input
|
||||
// characters read by the first loop.
|
||||
while (szsrc > 0) {
|
||||
--szsrc;
|
||||
ch = *src++;
|
||||
decode = unbase64[ch];
|
||||
if (decode < 0) {
|
||||
if (ascii_isspace((char)ch)) {
|
||||
continue;
|
||||
} else if (ch == '\0') {
|
||||
break;
|
||||
} else if (ch == kPad64) {
|
||||
// back up one character; we'll read it again when we check
|
||||
// for the correct number of equals signs at the end.
|
||||
++szsrc;
|
||||
--src;
|
||||
break;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Each input character gives us six bits of output.
|
||||
temp = (temp << 6) | decode;
|
||||
++state;
|
||||
if (state == 4) {
|
||||
// If we've accumulated 24 bits of output, write that out as
|
||||
// three bytes.
|
||||
if (dest) {
|
||||
if (destidx+3 > szdest) return -1;
|
||||
dest[destidx+2] = (char)temp;
|
||||
temp >>= 8;
|
||||
dest[destidx+1] = (char)temp;
|
||||
temp >>= 8;
|
||||
dest[destidx] = (char)temp;
|
||||
}
|
||||
destidx += 3;
|
||||
state = 0;
|
||||
temp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process the leftover data contained in 'temp' at the end of the input.
|
||||
int expected_equals = 0;
|
||||
switch (state) {
|
||||
case 0:
|
||||
// Nothing left over; output is a multiple of 3 bytes.
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Bad input; we have 6 bits left over.
|
||||
return -1;
|
||||
|
||||
case 2:
|
||||
// Produce one more output byte from the 12 input bits we have left.
|
||||
if (dest) {
|
||||
if (destidx+1 > szdest) return -1;
|
||||
temp >>= 4;
|
||||
dest[destidx] = (char)temp;
|
||||
}
|
||||
++destidx;
|
||||
expected_equals = 2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Produce two more output bytes from the 18 input bits we have left.
|
||||
if (dest) {
|
||||
if (destidx+2 > szdest) return -1;
|
||||
temp >>= 2;
|
||||
dest[destidx+1] = (char)temp;
|
||||
temp >>= 8;
|
||||
dest[destidx] = (char)temp;
|
||||
}
|
||||
destidx += 2;
|
||||
expected_equals = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// state should have no other values at this point.
|
||||
fprintf(stdout, "This can't happen; base64 decoder state = %d", state);
|
||||
}
|
||||
|
||||
// The remainder of the string should be all whitespace, mixed with
|
||||
// exactly 0 equals signs, or exactly 'expected_equals' equals
|
||||
// signs. (Always accepting 0 equals signs is a google extension
|
||||
// not covered in the RFC.)
|
||||
|
||||
int equals = 0;
|
||||
while (szsrc > 0 && *src) {
|
||||
if (*src == kPad64)
|
||||
++equals;
|
||||
else if (!ascii_isspace(*src))
|
||||
return -1;
|
||||
--szsrc;
|
||||
++src;
|
||||
}
|
||||
|
||||
return (equals == 0 || equals == expected_equals) ? destidx : -1;
|
||||
}
|
||||
|
||||
int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) {
|
||||
static const signed char UnBase64[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
|
||||
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
|
||||
60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
|
||||
7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
|
||||
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
|
||||
23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
|
||||
-1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
|
||||
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
|
||||
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
|
||||
49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
// The above array was generated by the following code
|
||||
// #include <sys/time.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <string.h>
|
||||
// main()
|
||||
// {
|
||||
// static const char Base64[] =
|
||||
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
// char *pos;
|
||||
// int idx, i, j;
|
||||
// printf(" ");
|
||||
// for (i = 0; i < 255; i += 8) {
|
||||
// for (j = i; j < i + 8; j++) {
|
||||
// pos = strchr(Base64, j);
|
||||
// if ((pos == NULL) || (j == 0))
|
||||
// idx = -1;
|
||||
// else
|
||||
// idx = pos - Base64;
|
||||
// if (idx == -1)
|
||||
// printf(" %2d, ", idx);
|
||||
// else
|
||||
// printf(" %2d/*%c*/,", idx, j);
|
||||
// }
|
||||
// printf("\n ");
|
||||
// }
|
||||
// }
|
||||
|
||||
return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
|
||||
}
|
||||
|
||||
bool Base64Unescape(const char *src, int slen, string* dest) {
|
||||
// Determine the size of the output string. Base64 encodes every 3 bytes into
|
||||
// 4 characters. any leftover chars are added directly for good measure.
|
||||
// This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt
|
||||
const int dest_len = 3 * (slen / 4) + (slen % 4);
|
||||
|
||||
dest->resize(dest_len);
|
||||
|
||||
// We are getting the destination buffer by getting the beginning of the
|
||||
// string and converting it into a char *.
|
||||
const int len = Base64Unescape(src, slen,
|
||||
string_as_array(dest), dest->size());
|
||||
if (len < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// could be shorter if there was padding
|
||||
assert(len <= dest_len);
|
||||
dest->resize(len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Base64Escape
|
||||
//
|
||||
// NOTE: We have to use an unsigned type for src because code built
|
||||
// in the the /google tree treats characters as signed unless
|
||||
// otherwised specified.
|
||||
//
|
||||
// TODO(who?): Move this function to use the char* type for "src"
|
||||
int Base64EscapeInternal(const unsigned char *src, int szsrc,
|
||||
char *dest, int szdest, const char *base64,
|
||||
bool do_padding) {
|
||||
static const char kPad64 = '=';
|
||||
|
||||
if (szsrc <= 0) return 0;
|
||||
|
||||
char *cur_dest = dest;
|
||||
const unsigned char *cur_src = src;
|
||||
|
||||
// Three bytes of data encodes to four characters of cyphertext.
|
||||
// So we can pump through three-byte chunks atomically.
|
||||
while (szsrc > 2) { /* keep going until we have less than 24 bits */
|
||||
if ((szdest -= 4) < 0) return 0;
|
||||
cur_dest[0] = base64[cur_src[0] >> 2];
|
||||
cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
|
||||
cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
|
||||
cur_dest[3] = base64[cur_src[2] & 0x3f];
|
||||
|
||||
cur_dest += 4;
|
||||
cur_src += 3;
|
||||
szsrc -= 3;
|
||||
}
|
||||
|
||||
/* now deal with the tail (<=2 bytes) */
|
||||
switch (szsrc) {
|
||||
case 0:
|
||||
// Nothing left; nothing more to do.
|
||||
break;
|
||||
case 1:
|
||||
// One byte left: this encodes to two characters, and (optionally)
|
||||
// two pad characters to round out the four-character cypherblock.
|
||||
if ((szdest -= 2) < 0) return 0;
|
||||
cur_dest[0] = base64[cur_src[0] >> 2];
|
||||
cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
|
||||
cur_dest += 2;
|
||||
if (do_padding) {
|
||||
if ((szdest -= 2) < 0) return 0;
|
||||
cur_dest[0] = kPad64;
|
||||
cur_dest[1] = kPad64;
|
||||
cur_dest += 2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Two bytes left: this encodes to three characters, and (optionally)
|
||||
// one pad character to round out the four-character cypherblock.
|
||||
if ((szdest -= 3) < 0) return 0;
|
||||
cur_dest[0] = base64[cur_src[0] >> 2];
|
||||
cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
|
||||
cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
|
||||
cur_dest += 3;
|
||||
if (do_padding) {
|
||||
if ((szdest -= 1) < 0) return 0;
|
||||
cur_dest[0] = kPad64;
|
||||
cur_dest += 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Should not be reached: blocks of 3 bytes are handled
|
||||
// in the while loop before this switch statement.
|
||||
fprintf(stderr, "Logic problem? szsrc = %d", szsrc);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return (cur_dest - dest);
|
||||
}
|
||||
|
||||
static const char kBase64Chars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static const char kWebSafeBase64Chars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
|
||||
return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
|
||||
}
|
||||
|
||||
void Base64Escape(const unsigned char *src, int szsrc,
|
||||
string* dest, bool do_padding) {
|
||||
const int max_escaped_size =
|
||||
CalculateBase64EscapedLen(szsrc, do_padding);
|
||||
dest->clear();
|
||||
dest->resize(max_escaped_size + 1, '\0');
|
||||
const int escaped_len = Base64EscapeInternal(src, szsrc,
|
||||
&*dest->begin(), dest->size(),
|
||||
kBase64Chars,
|
||||
do_padding);
|
||||
assert(max_escaped_size <= escaped_len);
|
||||
dest->resize(escaped_len);
|
||||
}
|
||||
|
||||
void Base64Escape(const string& src, string* dest) {
|
||||
Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
|
||||
src.size(), dest, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// WebSafe methods
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
|
||||
static const signed char UnBase64[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 62/*-*/, -1, -1,
|
||||
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
|
||||
60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
|
||||
7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
|
||||
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
|
||||
23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
|
||||
-1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
|
||||
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
|
||||
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
|
||||
49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
// The above array was generated by the following code
|
||||
// #include <sys/time.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <string.h>
|
||||
// main()
|
||||
// {
|
||||
// static const char Base64[] =
|
||||
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
// char *pos;
|
||||
// int idx, i, j;
|
||||
// printf(" ");
|
||||
// for (i = 0; i < 255; i += 8) {
|
||||
// for (j = i; j < i + 8; j++) {
|
||||
// pos = strchr(Base64, j);
|
||||
// if ((pos == NULL) || (j == 0))
|
||||
// idx = -1;
|
||||
// else
|
||||
// idx = pos - Base64;
|
||||
// if (idx == -1)
|
||||
// printf(" %2d, ", idx);
|
||||
// else
|
||||
// printf(" %2d/*%c*/,", idx, j);
|
||||
// }
|
||||
// printf("\n ");
|
||||
// }
|
||||
// }
|
||||
|
||||
return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
|
||||
}
|
||||
|
||||
bool WebSafeBase64Unescape(const char *src, int slen, string* dest) {
|
||||
int dest_len = 3 * (slen / 4) + (slen % 4);
|
||||
dest->clear();
|
||||
dest->resize(dest_len);
|
||||
int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size());
|
||||
if (len < 0) {
|
||||
dest->clear();
|
||||
return false;
|
||||
}
|
||||
// could be shorter if there was padding
|
||||
assert(len <= dest_len);
|
||||
dest->resize(len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSafeBase64Unescape(const string& src, string* dest) {
|
||||
return WebSafeBase64Unescape(src.data(), src.size(), dest);
|
||||
}
|
||||
|
||||
int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
|
||||
int szdest, bool do_padding) {
|
||||
return Base64EscapeInternal(src, szsrc, dest, szdest,
|
||||
kWebSafeBase64Chars, do_padding);
|
||||
}
|
||||
|
||||
void WebSafeBase64Escape(const unsigned char *src, int szsrc,
|
||||
string *dest, bool do_padding) {
|
||||
const int max_escaped_size =
|
||||
CalculateBase64EscapedLen(szsrc, do_padding);
|
||||
dest->clear();
|
||||
dest->resize(max_escaped_size + 1, '\0');
|
||||
const int escaped_len = Base64EscapeInternal(src, szsrc,
|
||||
&*dest->begin(), dest->size(),
|
||||
kWebSafeBase64Chars,
|
||||
do_padding);
|
||||
assert(max_escaped_size <= escaped_len);
|
||||
dest->resize(escaped_len);
|
||||
}
|
||||
|
||||
void WebSafeBase64EscapeInternal(const string& src,
|
||||
string* dest,
|
||||
bool do_padding) {
|
||||
int encoded_len = CalculateBase64EscapedLen(src.size());
|
||||
scoped_array<char> buf(new char[encoded_len]);
|
||||
int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
|
||||
src.size(), buf.get(),
|
||||
encoded_len, do_padding);
|
||||
dest->assign(buf.get(), len);
|
||||
}
|
||||
|
||||
void WebSafeBase64Escape(const string& src, string* dest) {
|
||||
WebSafeBase64EscapeInternal(src, dest, false);
|
||||
}
|
||||
|
||||
void WebSafeBase64EscapeWithPadding(const string& src, string* dest) {
|
||||
WebSafeBase64EscapeInternal(src, dest, true);
|
||||
}
|
||||
|
||||
} // namespace strings
|
99
externals/breakpad/src/tools/windows/converter_exe/escaping.h
vendored
Normal file
99
externals/breakpad/src/tools/windows/converter_exe/escaping.h
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Base64 escaping methods to encode/decode strings.
|
||||
|
||||
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
|
||||
#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace strings {
|
||||
|
||||
using std::string;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Base64Escape()
|
||||
// WebSafeBase64Escape()
|
||||
// Encode "src" to "dest" using base64 encoding.
|
||||
// src is not null terminated, instead specify len.
|
||||
// 'dest' should have at least CalculateBase64EscapedLen() length.
|
||||
// RETURNS the length of dest.
|
||||
// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
|
||||
// so that we can place the out in the URL or cookies without having
|
||||
// to escape them. It also has an extra parameter "do_padding",
|
||||
// which when set to false will prevent padding with "=".
|
||||
// ----------------------------------------------------------------------
|
||||
void Base64Escape(const string& src, string* dest);
|
||||
int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest);
|
||||
// Encode src into dest with padding.
|
||||
void Base64Escape(const unsigned char* src, int szsrc,
|
||||
string* dest, bool do_padding);
|
||||
|
||||
int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest,
|
||||
int szdest, bool do_padding);
|
||||
// Encode src into dest web-safely without padding.
|
||||
void WebSafeBase64Escape(const string& src, string* dest);
|
||||
// Encode src into dest web-safely with padding.
|
||||
void WebSafeBase64EscapeWithPadding(const string& src, string* dest);
|
||||
void WebSafeBase64Escape(const unsigned char* src, int szsrc,
|
||||
string* dest, bool do_padding);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Base64Unescape()
|
||||
// WebSafeBase64Unescape()
|
||||
// Copies "src" to "dest", where src is in base64 and is written to its
|
||||
// ASCII equivalents. src is not null terminated, instead specify len.
|
||||
// I recommend that slen<szdest, but we honor szdest anyway.
|
||||
// RETURNS the length of dest, or -1 if src contains invalid chars.
|
||||
// The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
|
||||
// The variations that store into a string clear the string first, and
|
||||
// return false (with dest empty) if src contains invalid chars; for
|
||||
// these versions src and dest must be different strings.
|
||||
// ----------------------------------------------------------------------
|
||||
int Base64Unescape(const char* src, int slen, char* dest, int szdest);
|
||||
bool Base64Unescape(const char* src, int slen, string* dest);
|
||||
inline bool Base64Unescape(const string& src, string* dest) {
|
||||
return Base64Unescape(src.data(), src.size(), dest);
|
||||
}
|
||||
|
||||
|
||||
int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest);
|
||||
bool WebSafeBase64Unescape(const char* src, int slen, string* dest);
|
||||
bool WebSafeBase64Unescape(const string& src, string* dest);
|
||||
|
||||
// Return the length to use for the output buffer given to the base64 escape
|
||||
// routines. Make sure to use the same value for do_padding in both.
|
||||
// This function may return incorrect results if given input_len values that
|
||||
// are extremely high, which should happen rarely.
|
||||
int CalculateBase64EscapedLen(int input_len, bool do_padding);
|
||||
// Use this version when calling Base64Escape without a do_padding arg.
|
||||
int CalculateBase64EscapedLen(int input_len);
|
||||
} // namespace strings
|
||||
|
||||
#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
|
96
externals/breakpad/src/tools/windows/converter_exe/http_client.h
vendored
Normal file
96
externals/breakpad/src/tools/windows/converter_exe/http_client.h
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
|
||||
#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
|
||||
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
typedef void* HttpHandle;
|
||||
|
||||
namespace crash {
|
||||
|
||||
// HttpClient provides an abstract layer for HTTP APIs. The actual
|
||||
// implementation can be based on either WinHttp or WinInet.
|
||||
class HttpClient {
|
||||
public:
|
||||
enum AccessType {
|
||||
ACCESS_TYPE_PRECONFIG,
|
||||
ACCESS_TYPE_DIRECT,
|
||||
ACCESS_TYPE_PROXY,
|
||||
};
|
||||
|
||||
virtual ~HttpClient() {}
|
||||
|
||||
virtual bool CrackUrl(const TCHAR* url,
|
||||
DWORD flags,
|
||||
TCHAR* scheme,
|
||||
size_t scheme_buffer_length,
|
||||
TCHAR* host,
|
||||
size_t host_buffer_length,
|
||||
TCHAR* uri,
|
||||
size_t uri_buffer_length,
|
||||
int* port) const = 0;
|
||||
virtual bool Open(const TCHAR* user_agent,
|
||||
DWORD access_type,
|
||||
const TCHAR* proxy_name,
|
||||
const TCHAR* proxy_bypass,
|
||||
HttpHandle* session_handle) const = 0;
|
||||
virtual bool Connect(HttpHandle session_handle,
|
||||
const TCHAR* server,
|
||||
int port,
|
||||
HttpHandle* connection_handle) const = 0;
|
||||
virtual bool OpenRequest(HttpHandle connection_handle,
|
||||
const TCHAR* verb,
|
||||
const TCHAR* uri,
|
||||
const TCHAR* version,
|
||||
const TCHAR* referrer,
|
||||
bool is_secure,
|
||||
HttpHandle* request_handle) const = 0;
|
||||
virtual bool SendRequest(HttpHandle request_handle,
|
||||
const TCHAR* headers,
|
||||
DWORD headers_length) const = 0;
|
||||
virtual bool ReceiveResponse(HttpHandle request_handle) const = 0;
|
||||
virtual bool GetHttpStatusCode(HttpHandle request_handle,
|
||||
int* status_code) const = 0;
|
||||
virtual bool GetContentLength(HttpHandle request_handle,
|
||||
DWORD* content_length) const = 0;
|
||||
virtual bool ReadData(HttpHandle request_handle,
|
||||
void* buffer,
|
||||
DWORD buffer_length,
|
||||
DWORD* bytes_read) const = 0;
|
||||
virtual bool Close(HttpHandle handle) const = 0;
|
||||
|
||||
static const DWORD kUnknownContentLength = (DWORD)-1;
|
||||
};
|
||||
|
||||
} // namespace crash
|
||||
|
||||
#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
|
330
externals/breakpad/src/tools/windows/converter_exe/http_download.cc
vendored
Normal file
330
externals/breakpad/src/tools/windows/converter_exe/http_download.cc
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
#include <WinInet.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "tools/windows/converter_exe/http_download.h"
|
||||
#include "tools/windows/converter_exe/winhttp_client.h"
|
||||
#include "tools/windows/converter_exe/wininet_client.h"
|
||||
|
||||
namespace crash {
|
||||
static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB
|
||||
|
||||
using std::vector;
|
||||
|
||||
// Class that atuo closes the contained HttpHandle when the object
|
||||
// goes out of scope.
|
||||
class AutoHttpHandle {
|
||||
public:
|
||||
AutoHttpHandle() : handle_(NULL) {}
|
||||
explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {}
|
||||
~AutoHttpHandle() {
|
||||
if (handle_) {
|
||||
InternetCloseHandle(handle_);
|
||||
}
|
||||
}
|
||||
|
||||
HttpHandle get() { return handle_; }
|
||||
HttpHandle* get_handle_addr () { return &handle_; }
|
||||
|
||||
private:
|
||||
HttpHandle handle_;
|
||||
};
|
||||
|
||||
// Template class for auto releasing the contained pointer when
|
||||
// the object goes out of scope.
|
||||
template<typename T>
|
||||
class AutoPtr {
|
||||
public:
|
||||
explicit AutoPtr(T* ptr) : ptr_(ptr) {}
|
||||
~AutoPtr() {
|
||||
if (ptr_) {
|
||||
delete ptr_;
|
||||
}
|
||||
}
|
||||
|
||||
T* get() { return ptr_; }
|
||||
T* operator -> () { return ptr_; }
|
||||
|
||||
private:
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
// CheckParameters ensures that the parameters in |parameters| are safe for
|
||||
// use in an HTTP URL. Returns true if they are, false if unsafe characters
|
||||
// are present.
|
||||
static bool CheckParameters(const map<wstring, wstring>* parameters) {
|
||||
for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
|
||||
iterator != parameters->end();
|
||||
++iterator) {
|
||||
const wstring& key = iterator->first;
|
||||
if (key.empty()) {
|
||||
// Disallow empty parameter names.
|
||||
return false;
|
||||
}
|
||||
for (unsigned int i = 0; i < key.size(); ++i) {
|
||||
wchar_t c = key[i];
|
||||
if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const wstring& value = iterator->second;
|
||||
for (unsigned int i = 0; i < value.size(); ++i) {
|
||||
wchar_t c = value[i];
|
||||
if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) {
|
||||
const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP");
|
||||
TCHAR buffer[2] = {0};
|
||||
HttpClient* http_client = NULL;
|
||||
|
||||
if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable,
|
||||
buffer,
|
||||
sizeof(buffer)/sizeof(buffer[0])) > 0) {
|
||||
fprintf(stdout,
|
||||
"Environment variable [%ws] is set, use WinHttp\n",
|
||||
kHttpApiPolicyEnvironmentVariable);
|
||||
http_client = CreateWinHttpClient(url);
|
||||
if (http_client == NULL) {
|
||||
fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? "
|
||||
"Fall back to WinInet API.\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Environment variable [%ws] is NOT set, use WinInet API\n",
|
||||
kHttpApiPolicyEnvironmentVariable);
|
||||
}
|
||||
|
||||
if (http_client == NULL) {
|
||||
return CreateWinInetClient(url);
|
||||
}
|
||||
|
||||
return http_client;
|
||||
}
|
||||
|
||||
// static
|
||||
bool HTTPDownload::Download(const wstring& url,
|
||||
const map<wstring, wstring>* parameters,
|
||||
string *content, int *status_code) {
|
||||
assert(content);
|
||||
AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str()));
|
||||
|
||||
if (!http_client.get()) {
|
||||
fprintf(stderr, "Failed to create any http client.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status_code) {
|
||||
*status_code = 0;
|
||||
}
|
||||
|
||||
wchar_t scheme[16] = {0};
|
||||
wchar_t host[256] = {0};
|
||||
wchar_t path[256] = {0};
|
||||
int port = 0;
|
||||
if (!http_client->CrackUrl(url.c_str(),
|
||||
0,
|
||||
scheme,
|
||||
sizeof(scheme)/sizeof(scheme[0]),
|
||||
host,
|
||||
sizeof(host)/sizeof(host[0]),
|
||||
path,
|
||||
sizeof(path)/sizeof(path[0]),
|
||||
&port)) {
|
||||
fprintf(stderr,
|
||||
"HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n",
|
||||
GetLastError(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool secure = false;
|
||||
if (_wcsicmp(scheme, L"https") == 0) {
|
||||
secure = true;
|
||||
} else if (wcscmp(scheme, L"http") != 0) {
|
||||
fprintf(stderr,
|
||||
"HTTPDownload::Download: scheme must be http or https for %ws\n",
|
||||
url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoHttpHandle internet;
|
||||
if (!http_client->Open(NULL, // user agent
|
||||
HttpClient::ACCESS_TYPE_PRECONFIG,
|
||||
NULL, // proxy name
|
||||
NULL, // proxy bypass
|
||||
internet.get_handle_addr())) {
|
||||
fprintf(stderr,
|
||||
"HTTPDownload::Download: Open: error %lu for %ws\n",
|
||||
GetLastError(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoHttpHandle connection;
|
||||
if (!http_client->Connect(internet.get(),
|
||||
host,
|
||||
port,
|
||||
connection.get_handle_addr())) {
|
||||
fprintf(stderr,
|
||||
"HTTPDownload::Download: InternetConnect: error %lu for %ws\n",
|
||||
GetLastError(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring request_string = path;
|
||||
if (parameters) {
|
||||
// TODO(mmentovai): escape bad characters in parameters instead of
|
||||
// forbidding them.
|
||||
if (!CheckParameters(parameters)) {
|
||||
fprintf(stderr,
|
||||
"HTTPDownload::Download: invalid characters in parameters\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool added_parameter = false;
|
||||
for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
|
||||
iterator != parameters->end();
|
||||
++iterator) {
|
||||
request_string.append(added_parameter ? L"&" : L"?");
|
||||
request_string.append(iterator->first);
|
||||
request_string.append(L"=");
|
||||
request_string.append(iterator->second);
|
||||
added_parameter = true;
|
||||
}
|
||||
}
|
||||
|
||||
AutoHttpHandle request;
|
||||
if (!http_client->OpenRequest(connection.get(),
|
||||
L"GET",
|
||||
request_string.c_str(),
|
||||
NULL, // version
|
||||
NULL, // referer
|
||||
secure,
|
||||
request.get_handle_addr())) {
|
||||
fprintf(stderr,
|
||||
"HttpClient::OpenRequest: error %lu for %ws, request: %ws\n",
|
||||
GetLastError(), url.c_str(), request_string.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!http_client->SendRequest(request.get(), NULL, 0)) {
|
||||
fprintf(stderr,
|
||||
"HttpClient::SendRequest: error %lu for %ws\n",
|
||||
GetLastError(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!http_client->ReceiveResponse(request.get())) {
|
||||
fprintf(stderr,
|
||||
"HttpClient::ReceiveResponse: error %lu for %ws\n",
|
||||
GetLastError(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int http_status = 0;
|
||||
if (!http_client->GetHttpStatusCode(request.get(), &http_status)) {
|
||||
fprintf(stderr,
|
||||
"HttpClient::GetHttpStatusCode: error %lu for %ws\n",
|
||||
GetLastError(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
if (http_status != 200) {
|
||||
fprintf(stderr,
|
||||
"HTTPDownload::Download: HTTP status code %d for %ws\n",
|
||||
http_status, url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD content_length = 0;
|
||||
vector<char>::size_type buffer_size = 0;
|
||||
http_client->GetContentLength(request.get(), &content_length);
|
||||
if (content_length == HttpClient::kUnknownContentLength) {
|
||||
buffer_size = kVectorChunkSize;
|
||||
} else {
|
||||
buffer_size = content_length;
|
||||
}
|
||||
|
||||
if (content_length != 0) {
|
||||
vector<char> response_buffer = vector<char>(buffer_size+1);
|
||||
DWORD size_read;
|
||||
DWORD total_read = 0;
|
||||
bool read_result;
|
||||
do {
|
||||
if (content_length == HttpClient::kUnknownContentLength
|
||||
&& buffer_size == total_read) {
|
||||
// The content length wasn't specified in the response header, so we
|
||||
// have to keep growing the buffer until we're done reading.
|
||||
buffer_size += kVectorChunkSize;
|
||||
response_buffer.resize(buffer_size);
|
||||
}
|
||||
read_result = !!http_client->ReadData(
|
||||
request.get(),
|
||||
&response_buffer[total_read],
|
||||
static_cast<DWORD>(buffer_size) - total_read,
|
||||
&size_read);
|
||||
total_read += size_read;
|
||||
} while (read_result && (size_read != 0));
|
||||
|
||||
if (!read_result) {
|
||||
fprintf(stderr,
|
||||
"HttpClient::ReadData: error %lu for %ws\n",
|
||||
GetLastError(),
|
||||
url.c_str());
|
||||
return false;
|
||||
} else if (size_read != 0) {
|
||||
fprintf(stderr,
|
||||
"HttpClient::ReadData: error %lu/%lu for %ws\n",
|
||||
total_read,
|
||||
content_length,
|
||||
url.c_str());
|
||||
return false;
|
||||
}
|
||||
content->assign(&response_buffer[0], total_read);
|
||||
} else {
|
||||
content->clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crash
|
62
externals/breakpad/src/tools/windows/converter_exe/http_download.h
vendored
Normal file
62
externals/breakpad/src/tools/windows/converter_exe/http_download.h
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
|
||||
#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "tools/windows/converter_exe/winhttp_client.h"
|
||||
|
||||
namespace crash {
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
|
||||
class HTTPDownload {
|
||||
public:
|
||||
// Retrieves the resource located at |url|, a http or https URL, via WinInet.
|
||||
// The request is fetched with GET request; the optional |parameters| are
|
||||
// appended to the URL. Returns true on success, placing the content of the
|
||||
// retrieved resource in |content|. Returns false on failure. HTTP status
|
||||
// codes other than 200 cause Download to return false. If |status_code| is
|
||||
// supplied, it will be set to the value of the HTTP status code, if an HTTP
|
||||
// transaction occurs. If Download fails before a transaction can occur,
|
||||
// |status_code| will be set to 0. Any failures will result in messages
|
||||
// being printed to stderr.
|
||||
static bool Download(const wstring& url,
|
||||
const map<wstring, wstring>* parameters,
|
||||
string *content, int *status_code);
|
||||
private:
|
||||
static HttpClient* CreateHttpClient(const wchar_t*);
|
||||
};
|
||||
|
||||
} // namespace crash
|
||||
|
||||
#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
|
5
externals/breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt
vendored
Normal file
5
externals/breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
msctf.pdb|6A5BABB8E88644C696530BFE3C90F32F2|6.1.7600.16385|msctf.dll|4A5BDFAA109000
|
||||
imm32.pdb|98F27BA5AEE541ECBEE00CD03AD50FEE2|6.1.7600.16385|imm32.dll|4A5BDF402e000
|
||||
amd_opencl64.pdb|3D306D0FCCB14F47AF322A5ACDF5EEA81||amd_opencl64.dll|587901FB1E000
|
||||
igd10iumd64.pdb|B2B72475BB0846D8ADE4344FAE0CCE361 ||igd10iumd64.dll|568D69FBD99000
|
||||
NvCameraWhitelisting64.pdb|3C364C4D3FBF4180B021D52D469C6DAB1||NvCameraWhitelisting64.dll|5B8ED23485000
|
2
externals/breakpad/src/tools/windows/converter_exe/symsrv.yes
vendored
Normal file
2
externals/breakpad/src/tools/windows/converter_exe/symsrv.yes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
See breakpad/tools/windows/converter/ms_symbol_server_converter.h for a
|
||||
description of this file's function.
|
65
externals/breakpad/src/tools/windows/converter_exe/tokenizer.cc
vendored
Normal file
65
externals/breakpad/src/tools/windows/converter_exe/tokenizer.cc
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "tools/windows/converter_exe/tokenizer.h"
|
||||
|
||||
namespace crash {
|
||||
|
||||
// static
|
||||
void Tokenizer::Tokenize(const string& delimiters, const string& input,
|
||||
vector<string>* output) {
|
||||
assert(output);
|
||||
output->clear();
|
||||
|
||||
string::size_type position = 0; // Where to begin looking for a delimiter
|
||||
string::size_type new_position; // Position of found delimiter
|
||||
string token;
|
||||
|
||||
while ((new_position = input.find_first_of(delimiters, position)) !=
|
||||
string::npos) {
|
||||
token = input.substr(position, new_position - position);
|
||||
output->push_back(token);
|
||||
|
||||
// Next time, begin looking right after this delimiter.
|
||||
position = new_position + 1;
|
||||
}
|
||||
|
||||
// There are no more delimiters in the string. Take everything from the
|
||||
// final delimiter up to the end of the string as a token. This may be
|
||||
// an empty string.
|
||||
token = input.substr(position);
|
||||
output->push_back(token);
|
||||
}
|
||||
|
||||
} // namespace crash
|
51
externals/breakpad/src/tools/windows/converter_exe/tokenizer.h
vendored
Normal file
51
externals/breakpad/src/tools/windows/converter_exe/tokenizer.h
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
|
||||
#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace crash {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
class Tokenizer {
|
||||
public:
|
||||
// Splits |input| into a series of tokens delimited in the input string by
|
||||
// any of the characters in |delimiters|. The tokens are passed back in the
|
||||
// |output| vector.
|
||||
static void Tokenize(const string& delimiters, const string& input,
|
||||
vector<string>* output);
|
||||
};
|
||||
|
||||
} // namespace crash
|
||||
|
||||
#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
|
311
externals/breakpad/src/tools/windows/converter_exe/winhttp_client.cc
vendored
Normal file
311
externals/breakpad/src/tools/windows/converter_exe/winhttp_client.cc
vendored
Normal file
|
@ -0,0 +1,311 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "tools/windows/converter_exe/winhttp_client.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <winhttp.h>
|
||||
#include <vector>
|
||||
|
||||
namespace crash {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This class implements HttpClient based on WinInet APIs.
|
||||
class WinHttpClient : public HttpClient {
|
||||
public:
|
||||
virtual ~WinHttpClient() {}
|
||||
virtual bool CrackUrl(const TCHAR* url,
|
||||
DWORD flags,
|
||||
TCHAR* scheme,
|
||||
size_t scheme_buffer_length,
|
||||
TCHAR* host,
|
||||
size_t host_buffer_length,
|
||||
TCHAR* uri,
|
||||
size_t uri_buffer_length,
|
||||
int* port) const;
|
||||
virtual bool Open(const TCHAR* user_agent,
|
||||
DWORD access_type,
|
||||
const TCHAR* proxy_name,
|
||||
const TCHAR* proxy_bypass,
|
||||
HttpHandle* session_handle) const;
|
||||
virtual bool Connect(HttpHandle session_handle,
|
||||
const TCHAR* server,
|
||||
int port,
|
||||
HttpHandle* connection_handle) const;
|
||||
virtual bool OpenRequest(HttpHandle connection_handle,
|
||||
const TCHAR* verb,
|
||||
const TCHAR* uri,
|
||||
const TCHAR* version,
|
||||
const TCHAR* referrer,
|
||||
bool is_secure,
|
||||
HttpHandle* request_handle) const;
|
||||
virtual bool SendRequest(HttpHandle request_handle,
|
||||
const TCHAR* headers,
|
||||
DWORD headers_length) const;
|
||||
virtual bool ReceiveResponse(HttpHandle request_handle) const;
|
||||
virtual bool GetHttpStatusCode(HttpHandle request_handle,
|
||||
int* status_code) const;
|
||||
virtual bool GetContentLength(HttpHandle request_handle,
|
||||
DWORD* content_length) const;
|
||||
virtual bool ReadData(HttpHandle request_handle,
|
||||
void* buffer,
|
||||
DWORD buffer_length,
|
||||
DWORD* bytes_read) const;
|
||||
virtual bool Close(HttpHandle handle) const;
|
||||
|
||||
private:
|
||||
static DWORD MapAccessType(DWORD access_type);
|
||||
static HINTERNET ToHINTERNET(HttpHandle handle);
|
||||
static HttpHandle FromHINTERNET(HINTERNET handle);
|
||||
};
|
||||
|
||||
bool WinHttpClient::CrackUrl(const TCHAR* url,
|
||||
DWORD flags,
|
||||
TCHAR* scheme,
|
||||
size_t scheme_buffer_length,
|
||||
TCHAR* host,
|
||||
size_t host_buffer_length,
|
||||
TCHAR* uri,
|
||||
size_t uri_buffer_length,
|
||||
int* port) const {
|
||||
assert(url);
|
||||
assert(scheme);
|
||||
assert(host);
|
||||
assert(uri);
|
||||
assert(port);
|
||||
|
||||
URL_COMPONENTS url_comp = {0};
|
||||
url_comp.dwStructSize = sizeof(url_comp);
|
||||
url_comp.lpszScheme = scheme;
|
||||
url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
|
||||
url_comp.lpszHostName = host;
|
||||
url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
|
||||
url_comp.lpszUrlPath = uri;
|
||||
url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
|
||||
|
||||
bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
|
||||
if (result) {
|
||||
*port = static_cast<int>(url_comp.nPort);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WinHttpClient::Open(const TCHAR* user_agent,
|
||||
DWORD access_type,
|
||||
const TCHAR* proxy_name,
|
||||
const TCHAR* proxy_bypass,
|
||||
HttpHandle* session_handle) const {
|
||||
*session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
|
||||
MapAccessType(access_type),
|
||||
proxy_name,
|
||||
proxy_bypass,
|
||||
0));
|
||||
|
||||
return !!(*session_handle);
|
||||
}
|
||||
|
||||
bool WinHttpClient::Connect(HttpHandle session_handle,
|
||||
const TCHAR* server,
|
||||
int port,
|
||||
HttpHandle* connection_handle) const {
|
||||
assert(server);
|
||||
|
||||
// Uses NULL user name and password to connect.
|
||||
*connection_handle = FromHINTERNET(::WinHttpConnect(
|
||||
ToHINTERNET(session_handle),
|
||||
server,
|
||||
static_cast<INTERNET_PORT>(port),
|
||||
NULL));
|
||||
return !!(*connection_handle);
|
||||
}
|
||||
|
||||
bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
|
||||
const TCHAR* verb,
|
||||
const TCHAR* uri,
|
||||
const TCHAR* version,
|
||||
const TCHAR* referrer,
|
||||
bool is_secure,
|
||||
HttpHandle* request_handle) const {
|
||||
assert(connection_handle);
|
||||
assert(verb);
|
||||
assert(uri);
|
||||
assert(request_handle);
|
||||
|
||||
*request_handle = FromHINTERNET(::WinHttpOpenRequest(
|
||||
ToHINTERNET(connection_handle),
|
||||
verb,
|
||||
uri,
|
||||
version,
|
||||
referrer,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
is_secure ? WINHTTP_FLAG_SECURE : 0));
|
||||
return !!(*request_handle);
|
||||
}
|
||||
|
||||
bool WinHttpClient::SendRequest(HttpHandle request_handle,
|
||||
const TCHAR* headers,
|
||||
DWORD headers_length) const {
|
||||
assert(request_handle);
|
||||
|
||||
return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
|
||||
headers,
|
||||
headers_length,
|
||||
NULL,
|
||||
0,
|
||||
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
|
||||
NULL);
|
||||
}
|
||||
|
||||
bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
|
||||
assert(request_handle);
|
||||
|
||||
return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
|
||||
}
|
||||
|
||||
bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
|
||||
int* status_code) const {
|
||||
TCHAR http_status_string[4] = {0};
|
||||
DWORD http_status_string_size = sizeof(http_status_string);
|
||||
if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
|
||||
WINHTTP_QUERY_STATUS_CODE,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
static_cast<void*>(&http_status_string),
|
||||
&http_status_string_size, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinHttpClient::GetContentLength(HttpHandle request_handle,
|
||||
DWORD* content_length) const {
|
||||
assert(request_handle);
|
||||
assert(content_length);
|
||||
|
||||
TCHAR content_length_string[11] = {0};
|
||||
DWORD content_length_string_size = sizeof(content_length_string);
|
||||
if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
|
||||
WINHTTP_QUERY_CONTENT_LENGTH,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
static_cast<void*>(&content_length_string),
|
||||
&content_length_string_size, 0)) {
|
||||
*content_length = kUnknownContentLength;
|
||||
} else {
|
||||
*content_length =
|
||||
static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinHttpClient::ReadData(HttpHandle request_handle,
|
||||
void* buffer,
|
||||
DWORD buffer_length,
|
||||
DWORD* bytes_read) const {
|
||||
assert(request_handle);
|
||||
assert(buffer);
|
||||
assert(bytes_read);
|
||||
|
||||
DWORD bytes_read_local = 0;
|
||||
if (!::WinHttpReadData(ToHINTERNET(request_handle),
|
||||
buffer,
|
||||
buffer_length,
|
||||
&bytes_read_local)) {
|
||||
return false;
|
||||
}
|
||||
*bytes_read = bytes_read_local;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinHttpClient::Close(HttpHandle handle) const {
|
||||
assert(handle);
|
||||
return !!::WinHttpCloseHandle(ToHINTERNET(handle));
|
||||
}
|
||||
|
||||
DWORD WinHttpClient::MapAccessType(DWORD access_type) {
|
||||
switch (static_cast<AccessType>(access_type)) {
|
||||
case ACCESS_TYPE_PRECONFIG:
|
||||
default:
|
||||
return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
|
||||
case ACCESS_TYPE_DIRECT:
|
||||
return WINHTTP_ACCESS_TYPE_NO_PROXY;
|
||||
case ACCESS_TYPE_PROXY:
|
||||
return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
|
||||
return static_cast<HINTERNET>(handle);
|
||||
}
|
||||
|
||||
HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
|
||||
return static_cast<HttpHandle>(handle);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
HttpClient* CreateWinHttpClient(const TCHAR* url) {
|
||||
assert(url);
|
||||
|
||||
internal::WinHttpClient winhttp;
|
||||
wchar_t scheme[16] = {0};
|
||||
wchar_t host[256] = {0};
|
||||
wchar_t path[256] = {0};
|
||||
int port = 0;
|
||||
|
||||
if (!winhttp.CrackUrl(url,
|
||||
0,
|
||||
scheme,
|
||||
sizeof(scheme)/sizeof(scheme[0]),
|
||||
host,
|
||||
sizeof(host)/sizeof(host[0]),
|
||||
path,
|
||||
sizeof(path)/sizeof(path[0]),
|
||||
&port)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_wcsicmp(scheme, L"https") == 0) {
|
||||
// Winhttp under WINE doesn't support wildcard certificates, so avoid
|
||||
// to use it if the scheme is https. The caller should fall back to
|
||||
// use wininet if NULL is returned.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new internal::WinHttpClient();
|
||||
}
|
||||
|
||||
} // namespace crash
|
40
externals/breakpad/src/tools/windows/converter_exe/winhttp_client.h
vendored
Normal file
40
externals/breakpad/src/tools/windows/converter_exe/winhttp_client.h
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
|
||||
#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
|
||||
|
||||
#include "tools/windows/converter_exe/http_client.h"
|
||||
|
||||
namespace crash {
|
||||
|
||||
HttpClient* CreateWinHttpClient(const TCHAR* url);
|
||||
|
||||
} // namespace crash
|
||||
|
||||
#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
|
282
externals/breakpad/src/tools/windows/converter_exe/wininet_client.cc
vendored
Normal file
282
externals/breakpad/src/tools/windows/converter_exe/wininet_client.cc
vendored
Normal file
|
@ -0,0 +1,282 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "tools/windows/converter_exe/wininet_client.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <wininet.h>
|
||||
|
||||
namespace crash {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This class implements HttpClient based on WinInet APIs.
|
||||
class WinInetClient : public HttpClient {
|
||||
public:
|
||||
virtual ~WinInetClient() {}
|
||||
virtual bool CrackUrl(const TCHAR* url,
|
||||
DWORD flags,
|
||||
TCHAR* scheme,
|
||||
size_t scheme_buffer_length,
|
||||
TCHAR* host,
|
||||
size_t host_buffer_length,
|
||||
TCHAR* uri,
|
||||
size_t uri_buffer_length,
|
||||
int* port) const;
|
||||
virtual bool Open(const TCHAR* user_agent,
|
||||
DWORD access_type,
|
||||
const TCHAR* proxy_name,
|
||||
const TCHAR* proxy_bypass,
|
||||
HttpHandle* session_handle) const;
|
||||
virtual bool Connect(HttpHandle session_handle,
|
||||
const TCHAR* server,
|
||||
int port,
|
||||
HttpHandle* connection_handle) const;
|
||||
virtual bool OpenRequest(HttpHandle connection_handle,
|
||||
const TCHAR* verb,
|
||||
const TCHAR* uri,
|
||||
const TCHAR* version,
|
||||
const TCHAR* referrer,
|
||||
bool is_secure,
|
||||
HttpHandle* request_handle) const;
|
||||
virtual bool SendRequest(HttpHandle request_handle,
|
||||
const TCHAR* headers,
|
||||
DWORD headers_length) const;
|
||||
virtual bool ReceiveResponse(HttpHandle request_handle) const;
|
||||
virtual bool GetHttpStatusCode(HttpHandle request_handle,
|
||||
int* status_code) const;
|
||||
virtual bool GetContentLength(HttpHandle request_handle,
|
||||
DWORD* content_length) const;
|
||||
virtual bool ReadData(HttpHandle request_handle,
|
||||
void* buffer,
|
||||
DWORD buffer_length,
|
||||
DWORD* bytes_read) const;
|
||||
virtual bool Close(HttpHandle handle) const;
|
||||
|
||||
private:
|
||||
static DWORD MapAccessType(DWORD access_type);
|
||||
static HINTERNET ToHINTERNET(HttpHandle handle);
|
||||
static HttpHandle FromHINTERNET(HINTERNET handle);
|
||||
};
|
||||
|
||||
bool WinInetClient::CrackUrl(const TCHAR* url,
|
||||
DWORD flags,
|
||||
TCHAR* scheme,
|
||||
size_t scheme_buffer_length,
|
||||
TCHAR* host,
|
||||
size_t host_buffer_length,
|
||||
TCHAR* uri,
|
||||
size_t uri_buffer_length,
|
||||
int* port) const {
|
||||
assert(url);
|
||||
assert(scheme);
|
||||
assert(host);
|
||||
assert(uri);
|
||||
assert(port);
|
||||
|
||||
URL_COMPONENTS url_comp = {0};
|
||||
url_comp.dwStructSize = sizeof(url_comp);
|
||||
url_comp.lpszScheme = scheme;
|
||||
url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
|
||||
url_comp.lpszHostName = host;
|
||||
url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
|
||||
url_comp.lpszUrlPath = uri;
|
||||
url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
|
||||
|
||||
bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
|
||||
if (result) {
|
||||
*port = static_cast<int>(url_comp.nPort);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WinInetClient::Open(const TCHAR* user_agent,
|
||||
DWORD access_type,
|
||||
const TCHAR* proxy_name,
|
||||
const TCHAR* proxy_bypass,
|
||||
HttpHandle* session_handle) const {
|
||||
*session_handle = FromHINTERNET(::InternetOpen(user_agent,
|
||||
MapAccessType(access_type),
|
||||
proxy_name,
|
||||
proxy_bypass,
|
||||
0));
|
||||
return !!(*session_handle);
|
||||
}
|
||||
|
||||
bool WinInetClient::Connect(HttpHandle session_handle,
|
||||
const TCHAR* server,
|
||||
int port,
|
||||
HttpHandle* connection_handle) const {
|
||||
assert(server);
|
||||
|
||||
// Uses NULL user name and password to connect. Always uses http service.
|
||||
*connection_handle = FromHINTERNET(::InternetConnect(
|
||||
ToHINTERNET(session_handle),
|
||||
server,
|
||||
static_cast<INTERNET_PORT>(port),
|
||||
NULL,
|
||||
NULL,
|
||||
INTERNET_SERVICE_HTTP,
|
||||
0,
|
||||
0));
|
||||
return !!(*connection_handle);
|
||||
}
|
||||
|
||||
bool WinInetClient::OpenRequest(HttpHandle connection_handle,
|
||||
const TCHAR* verb,
|
||||
const TCHAR* uri,
|
||||
const TCHAR* version,
|
||||
const TCHAR* referrer,
|
||||
bool is_secure,
|
||||
HttpHandle* request_handle) const {
|
||||
assert(connection_handle);
|
||||
assert(verb);
|
||||
assert(uri);
|
||||
|
||||
*request_handle = FromHINTERNET(::HttpOpenRequest(
|
||||
ToHINTERNET(connection_handle),
|
||||
verb,
|
||||
uri,
|
||||
version,
|
||||
referrer,
|
||||
NULL,
|
||||
is_secure ? INTERNET_FLAG_SECURE : 0,
|
||||
NULL));
|
||||
return !!(*request_handle);
|
||||
}
|
||||
|
||||
bool WinInetClient::SendRequest(HttpHandle request_handle,
|
||||
const TCHAR* headers,
|
||||
DWORD headers_length) const {
|
||||
assert(request_handle);
|
||||
|
||||
return !!::HttpSendRequest(ToHINTERNET(request_handle),
|
||||
headers,
|
||||
headers_length,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
bool WinInetClient::ReceiveResponse(HttpHandle) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
|
||||
int* status_code) const {
|
||||
assert(request_handle);
|
||||
|
||||
TCHAR http_status_string[4] = {0};
|
||||
DWORD http_status_string_size = sizeof(http_status_string);
|
||||
if (!::HttpQueryInfo(ToHINTERNET(request_handle),
|
||||
HTTP_QUERY_STATUS_CODE,
|
||||
static_cast<void*>(&http_status_string),
|
||||
&http_status_string_size,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*status_code = _tcstol(http_status_string, NULL, 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinInetClient::GetContentLength(HttpHandle request_handle,
|
||||
DWORD* content_length) const {
|
||||
assert(request_handle);
|
||||
assert(content_length);
|
||||
|
||||
TCHAR content_length_string[11];
|
||||
DWORD content_length_string_size = sizeof(content_length_string);
|
||||
if (!::HttpQueryInfo(ToHINTERNET(request_handle),
|
||||
HTTP_QUERY_CONTENT_LENGTH,
|
||||
static_cast<void*>(&content_length_string),
|
||||
&content_length_string_size,
|
||||
0)) {
|
||||
*content_length = kUnknownContentLength;
|
||||
} else {
|
||||
*content_length = wcstol(content_length_string, NULL, 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinInetClient::ReadData(HttpHandle request_handle,
|
||||
void* buffer,
|
||||
DWORD buffer_length,
|
||||
DWORD* bytes_read) const {
|
||||
assert(request_handle);
|
||||
assert(buffer);
|
||||
assert(bytes_read);
|
||||
|
||||
DWORD bytes_read_local = 0;
|
||||
if (!::InternetReadFile(ToHINTERNET(request_handle),
|
||||
buffer,
|
||||
buffer_length,
|
||||
&bytes_read_local)) {
|
||||
return false;
|
||||
}
|
||||
*bytes_read = bytes_read_local;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinInetClient::Close(HttpHandle handle) const {
|
||||
assert(handle);
|
||||
return !!::InternetCloseHandle(ToHINTERNET(handle));
|
||||
}
|
||||
|
||||
DWORD WinInetClient::MapAccessType(DWORD access_type) {
|
||||
switch (static_cast<AccessType>(access_type)) {
|
||||
case ACCESS_TYPE_PRECONFIG:
|
||||
default:
|
||||
return INTERNET_OPEN_TYPE_PRECONFIG;
|
||||
case ACCESS_TYPE_DIRECT:
|
||||
return INTERNET_OPEN_TYPE_DIRECT;
|
||||
case ACCESS_TYPE_PROXY:
|
||||
return INTERNET_OPEN_TYPE_PROXY;
|
||||
}
|
||||
}
|
||||
|
||||
HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
|
||||
return static_cast<HINTERNET>(handle);
|
||||
}
|
||||
|
||||
HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
|
||||
return static_cast<HttpHandle>(handle);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
HttpClient* CreateWinInetClient(const TCHAR*) {
|
||||
return new internal::WinInetClient();
|
||||
}
|
||||
|
||||
} // namespace crash
|
40
externals/breakpad/src/tools/windows/converter_exe/wininet_client.h
vendored
Normal file
40
externals/breakpad/src/tools/windows/converter_exe/wininet_client.h
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
|
||||
#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
|
||||
|
||||
#include "tools/windows/converter_exe/http_client.h"
|
||||
|
||||
namespace crash {
|
||||
|
||||
HttpClient* CreateWinInetClient(const TCHAR* url);
|
||||
|
||||
} // namespace crash
|
||||
|
||||
#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
|
86
externals/breakpad/src/tools/windows/converter_exe/winsymconv.cmd
vendored
Normal file
86
externals/breakpad/src/tools/windows/converter_exe/winsymconv.cmd
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
@if "%ECHOON%"=="" @echo off
|
||||
SETLOCAL
|
||||
|
||||
REM ******************************************************************
|
||||
REM Usage:
|
||||
REM winsymconv
|
||||
REM ******************************************************************
|
||||
|
||||
REM ******************************************************************
|
||||
REM Initialize
|
||||
REM ******************************************************************
|
||||
SET SCRIPT_LOCATION=%~dp0
|
||||
SET DBGHELP_WINHTTP=
|
||||
SET USE_WINHTTP=
|
||||
|
||||
REM ******************************************************************
|
||||
REM Go to script location
|
||||
REM ******************************************************************
|
||||
pushd %SCRIPT_LOCATION%
|
||||
|
||||
REM ******************************************************************
|
||||
REM Make sure the symbol file directory exists
|
||||
REM ******************************************************************
|
||||
SET SYMBOL_DIR=%SCRIPT_LOCATION%symbol
|
||||
if NOT EXIST %SYMBOL_DIR% MKDIR %SYMBOL_DIR%
|
||||
if NOT EXIST %SYMBOL_DIR% echo Failed to create directory '%SYMBOL_DIR%' & goto :fail
|
||||
|
||||
:restart
|
||||
|
||||
REM ******************************************************************
|
||||
REM Convert missing Windows symbols on the staging instance.
|
||||
REM ******************************************************************
|
||||
echo Converting missing Windows symbols on staging instance ...
|
||||
|
||||
google_converter.exe ^
|
||||
-n http://msdl.microsoft.com/download/symbols ^
|
||||
-n http://symbols.mozilla.org/firefox ^
|
||||
-n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
|
||||
-n https://download.amd.com/dir/bin ^
|
||||
-n https://driver-symbols.nvidia.com ^
|
||||
-n https://software.intel.com/sites/downloads/symbols ^
|
||||
-l %SYMBOL_DIR% ^
|
||||
-s https://clients2.google.com/cr/staging_symbol ^
|
||||
-m https://clients2.google.com/cr/staging_symbol/missingsymbols ^
|
||||
-t https://clients2.google.com/cr/staging_symbol/fetchfailed ^
|
||||
-b "google|chrome|internal|private" ^
|
||||
> %SCRIPT_LOCATION%last_cycle_staging.txt
|
||||
|
||||
REM ******************************************************************
|
||||
REM Convert missing Windows symbols on the production instance.
|
||||
REM ******************************************************************
|
||||
echo Converting missing Windows symbols on production instance ...
|
||||
|
||||
google_converter.exe ^
|
||||
-n http://msdl.microsoft.com/download/symbols ^
|
||||
-n http://symbols.mozilla.org/firefox ^
|
||||
-n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
|
||||
-n https://download.amd.com/dir/bin ^
|
||||
-n https://driver-symbols.nvidia.com ^
|
||||
-n https://software.intel.com/sites/downloads/symbols ^
|
||||
-l %SYMBOL_DIR% ^
|
||||
-s https://clients2.google.com/cr/symbol ^
|
||||
-m https://clients2.google.com/cr/symbol/missingsymbols ^
|
||||
-t https://clients2.google.com/cr/symbol/fetchfailed ^
|
||||
-b "google|chrome|internal|private" ^
|
||||
> %SCRIPT_LOCATION%last_cycle_prod.txt
|
||||
|
||||
REM ******************************************************************
|
||||
REM Sleep for 5 minutes ...
|
||||
REM ******************************************************************
|
||||
echo Sleeping for 5 minutes ...
|
||||
|
||||
%SCRIPT_LOCATION%sleep.exe 300
|
||||
|
||||
REM ******************************************
|
||||
REM Restart work loop ...
|
||||
REM ******************************************
|
||||
goto :restart
|
||||
|
||||
:success
|
||||
ENDLOCAL
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
ENDLOCAL
|
||||
exit /b 1
|
72
externals/breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd
vendored
Normal file
72
externals/breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
@if "%ECHOON%"=="" @echo off
|
||||
SETLOCAL
|
||||
|
||||
REM ******************************************************************
|
||||
REM Usage:
|
||||
REM winsymconv_test
|
||||
REM ******************************************************************
|
||||
|
||||
REM ******************************************************************
|
||||
REM Initialize
|
||||
REM ******************************************************************
|
||||
SET SCRIPT_LOCATION=%~dp0
|
||||
SET DBGHELP_WINHTTP=
|
||||
SET USE_WINHTTP=
|
||||
|
||||
REM ******************************************************************
|
||||
REM Go to script location
|
||||
REM ******************************************************************
|
||||
pushd %SCRIPT_LOCATION%
|
||||
|
||||
REM ******************************************************************
|
||||
REM Make sure the symbol file directory exists
|
||||
REM ******************************************************************
|
||||
SET SYMBOL_DIR=%SCRIPT_LOCATION%symbol
|
||||
if NOT EXIST %SYMBOL_DIR% MKDIR %SYMBOL_DIR%
|
||||
if NOT EXIST %SYMBOL_DIR% echo Failed to create directory '%SYMBOL_DIR%' & goto :fail
|
||||
|
||||
REM ******************************************************************
|
||||
REM Testing on the staging instance.
|
||||
REM ******************************************************************
|
||||
echo Testing on the staging instance ...
|
||||
|
||||
google_converter.exe ^
|
||||
-n http://msdl.microsoft.com/download/symbols ^
|
||||
-n http://symbols.mozilla.org/firefox ^
|
||||
-n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
|
||||
-n https://download.amd.com/dir/bin ^
|
||||
-n https://driver-symbols.nvidia.com ^
|
||||
-n https://software.intel.com/sites/downloads/symbols ^
|
||||
-l %SYMBOL_DIR% ^
|
||||
-s https://clients2.google.com/cr/staging_symbol ^
|
||||
-mf %SCRIPT_LOCATION%missing_symbols_test.txt ^
|
||||
-t https://clients2.google.com/cr/staging_symbol/fetchfailed ^
|
||||
-b "google|chrome|internal|private" ^
|
||||
> %SCRIPT_LOCATION%last_cycle_staging.txt
|
||||
|
||||
REM ******************************************************************
|
||||
REM Testing on the production instance.
|
||||
REM ******************************************************************
|
||||
echo Testing on the production instance ...
|
||||
|
||||
google_converter.exe ^
|
||||
-n http://msdl.microsoft.com/download/symbols ^
|
||||
-n http://symbols.mozilla.org/firefox ^
|
||||
-n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
|
||||
-n https://download.amd.com/dir/bin ^
|
||||
-n https://driver-symbols.nvidia.com ^
|
||||
-n https://software.intel.com/sites/downloads/symbols ^
|
||||
-l %SYMBOL_DIR% ^
|
||||
-s https://clients2.google.com/cr/symbol ^
|
||||
-mf %SCRIPT_LOCATION%missing_symbols_test.txt ^
|
||||
-t https://clients2.google.com/cr/symbol/fetchfailed ^
|
||||
-b "google|chrome|internal|private" ^
|
||||
> %SCRIPT_LOCATION%last_cycle_prod.txt
|
||||
|
||||
:success
|
||||
ENDLOCAL
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
ENDLOCAL
|
||||
exit /b 1
|
102
externals/breakpad/src/tools/windows/dump_syms/dump_syms.cc
vendored
Normal file
102
externals/breakpad/src/tools/windows/dump_syms/dump_syms.cc
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Windows utility to dump the line number data from a pdb file to
|
||||
// a text-based format that we can use from the minidump processor.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common/windows/pdb_source_line_writer.h"
|
||||
#include "common/windows/pe_source_line_writer.h"
|
||||
|
||||
using google_breakpad::PDBSourceLineWriter;
|
||||
using google_breakpad::PESourceLineWriter;
|
||||
using std::unique_ptr;
|
||||
using std::wstring;
|
||||
|
||||
int usage(const wchar_t* self) {
|
||||
fprintf(stderr, "Usage: %ws [--pe] [--i] <file.[pdb|exe|dll]>\n", self);
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr,
|
||||
"--pe:\tRead debugging information from PE file and do "
|
||||
"not attempt to locate matching PDB file.\n"
|
||||
"\tThis is only supported for PE32+ (64 bit) PE files.\n");
|
||||
fprintf(stderr,
|
||||
"--i:\tOutput INLINE/INLINE_ORIGIN record\n"
|
||||
"\tThis cannot be used with [--pe].\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t** argv) {
|
||||
bool success = false;
|
||||
bool pe = false;
|
||||
bool handle_inline = false;
|
||||
int arg_index = 1;
|
||||
while (arg_index < argc && wcslen(argv[arg_index]) > 0 &&
|
||||
wcsncmp(L"--", argv[arg_index], 2) == 0) {
|
||||
if (wcscmp(L"--pe", argv[arg_index]) == 0) {
|
||||
pe = true;
|
||||
} else if (wcscmp(L"--i", argv[arg_index]) == 0) {
|
||||
handle_inline = true;
|
||||
}
|
||||
++arg_index;
|
||||
}
|
||||
|
||||
if ((pe && handle_inline) || arg_index == argc) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
wchar_t* file_path = argv[arg_index];
|
||||
if (pe) {
|
||||
PESourceLineWriter pe_writer(file_path);
|
||||
success = pe_writer.WriteSymbols(stdout);
|
||||
} else {
|
||||
PDBSourceLineWriter pdb_writer(handle_inline);
|
||||
if (!pdb_writer.Open(wstring(file_path), PDBSourceLineWriter::ANY_FILE)) {
|
||||
fprintf(stderr, "Open failed.\n");
|
||||
return 1;
|
||||
}
|
||||
success = pdb_writer.WriteSymbols(stdout);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
fprintf(stderr, "WriteSymbols failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
248
externals/breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc
vendored
Normal file
248
externals/breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc
vendored
Normal file
|
@ -0,0 +1,248 @@
|
|||
// Copyright 2003 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
namespace tools {
|
||||
namespace windows {
|
||||
namespace dump_syms {
|
||||
|
||||
namespace {
|
||||
|
||||
// Root names of PDB and dumped symbol files to be regression tested. These are
|
||||
// specified in complexity of the resulting dumped symbol files.
|
||||
const wchar_t* kRootNames[] = {
|
||||
// A PDB file with no OMAP data.
|
||||
L"dump_syms_regtest",
|
||||
// A PDB file with OMAP data for an image that has been function-level
|
||||
// reordered.
|
||||
L"omap_reorder_funcs",
|
||||
// A PDB file with OMAP data for an image that had new content injected, all
|
||||
// of it with source data.
|
||||
L"omap_stretched_filled",
|
||||
// A PDB file with OMAP data for an image that had new content injected, but
|
||||
// without source data.
|
||||
L"omap_stretched",
|
||||
// A PDB file with OMAP data for an image that has been basic block reordered.
|
||||
L"omap_reorder_bbs",
|
||||
// A 64bit PDB file with no OMAP data.
|
||||
L"dump_syms_regtest64",
|
||||
};
|
||||
|
||||
const wchar_t* kPEOnlyRootNames[] = {
|
||||
L"pe_only_symbol_test",
|
||||
};
|
||||
|
||||
void TrimLastComponent(const std::wstring& path,
|
||||
std::wstring* trimmed,
|
||||
std::wstring* component) {
|
||||
size_t len = path.size();
|
||||
while (len > 0 && path[len - 1] != '\\')
|
||||
--len;
|
||||
|
||||
if (component != NULL)
|
||||
component->assign(path.c_str() + len, path.c_str() + path.size());
|
||||
|
||||
while (len > 0 && path[len - 1] == '\\')
|
||||
--len;
|
||||
|
||||
if (trimmed != NULL)
|
||||
trimmed->assign(path.c_str(), len);
|
||||
}
|
||||
|
||||
// Get the directory of the current executable.
|
||||
bool GetSelfDirectory(std::wstring* self_dir) {
|
||||
std::wstring command_line = GetCommandLineW();
|
||||
|
||||
int num_args = 0;
|
||||
wchar_t** args = NULL;
|
||||
args = ::CommandLineToArgvW(command_line.c_str(), &num_args);
|
||||
if (args == NULL)
|
||||
return false;
|
||||
|
||||
*self_dir = args[0];
|
||||
TrimLastComponent(*self_dir, self_dir, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RunCommand(const std::wstring& command_line,
|
||||
std::string* stdout_string) {
|
||||
// Create a PIPE for the child process stdout.
|
||||
HANDLE child_stdout_read = 0;
|
||||
HANDLE child_stdout_write = 0;
|
||||
SECURITY_ATTRIBUTES sec_attr_stdout = {};
|
||||
sec_attr_stdout.nLength = sizeof(sec_attr_stdout);
|
||||
sec_attr_stdout.bInheritHandle = TRUE;
|
||||
ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write,
|
||||
&sec_attr_stdout, 0));
|
||||
ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT,
|
||||
0));
|
||||
|
||||
// Create a PIPE for the child process stdin.
|
||||
HANDLE child_stdin_read = 0;
|
||||
HANDLE child_stdin_write = 0;
|
||||
SECURITY_ATTRIBUTES sec_attr_stdin = {};
|
||||
sec_attr_stdin.nLength = sizeof(sec_attr_stdin);
|
||||
sec_attr_stdin.bInheritHandle = TRUE;
|
||||
ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write,
|
||||
&sec_attr_stdin, 0));
|
||||
ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT,
|
||||
0));
|
||||
|
||||
// Startup the child.
|
||||
STARTUPINFO startup_info = {};
|
||||
PROCESS_INFORMATION process_info = {};
|
||||
startup_info.cb = sizeof(STARTUPINFO);
|
||||
startup_info.hStdError = NULL;
|
||||
startup_info.hStdInput = child_stdin_read;
|
||||
startup_info.hStdOutput = child_stdout_write;
|
||||
startup_info.dwFlags = STARTF_USESTDHANDLES;
|
||||
ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL,
|
||||
TRUE, 0, NULL, NULL,
|
||||
&startup_info, &process_info));
|
||||
|
||||
// Collect the output.
|
||||
ASSERT_TRUE(::CloseHandle(child_stdout_write));
|
||||
char buffer[4096] = {};
|
||||
DWORD bytes_read = 0;
|
||||
while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read,
|
||||
NULL) && bytes_read > 0) {
|
||||
stdout_string->append(buffer, bytes_read);
|
||||
}
|
||||
|
||||
// Wait for the process to finish.
|
||||
::WaitForSingleObject(process_info.hProcess, INFINITE);
|
||||
|
||||
// Shut down all of our handles.
|
||||
ASSERT_TRUE(::CloseHandle(process_info.hThread));
|
||||
ASSERT_TRUE(::CloseHandle(process_info.hProcess));
|
||||
ASSERT_TRUE(::CloseHandle(child_stdin_write));
|
||||
ASSERT_TRUE(::CloseHandle(child_stdin_read));
|
||||
ASSERT_TRUE(::CloseHandle(child_stdout_read));
|
||||
}
|
||||
|
||||
void GetFileContents(const std::wstring& path, std::string* content) {
|
||||
FILE* f = ::_wfopen(path.c_str(), L"rb");
|
||||
ASSERT_TRUE(f != NULL);
|
||||
|
||||
char buffer[4096] = {};
|
||||
while (true) {
|
||||
size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f);
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
content->append(buffer, bytes_read);
|
||||
}
|
||||
}
|
||||
|
||||
class DumpSymsRegressionTest : public testing::TestWithParam<const wchar_t*> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
std::wstring self_dir;
|
||||
ASSERT_TRUE(GetSelfDirectory(&self_dir));
|
||||
dump_syms_exe = self_dir + L"\\dump_syms.exe";
|
||||
|
||||
TrimLastComponent(self_dir, &testdata_dir, NULL);
|
||||
testdata_dir += L"\\testdata";
|
||||
}
|
||||
|
||||
std::wstring dump_syms_exe;
|
||||
std::wstring testdata_dir;
|
||||
};
|
||||
|
||||
class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam<const wchar_t*> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
std::wstring self_dir;
|
||||
ASSERT_TRUE(GetSelfDirectory(&self_dir));
|
||||
dump_syms_exe = self_dir + L"\\dump_syms.exe";
|
||||
|
||||
TrimLastComponent(self_dir, &testdata_dir, NULL);
|
||||
testdata_dir += L"\\testdata";
|
||||
}
|
||||
|
||||
std::wstring dump_syms_exe;
|
||||
std::wstring testdata_dir;
|
||||
};
|
||||
|
||||
} //namespace
|
||||
|
||||
TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {
|
||||
const wchar_t* root_name = GetParam();
|
||||
std::wstring root_path = testdata_dir + L"\\" + root_name;
|
||||
|
||||
std::wstring sym_path = root_path + L".sym";
|
||||
std::string expected_symbols;
|
||||
ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
|
||||
|
||||
std::wstring pdb_path = root_path + L".pdb";
|
||||
std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" +
|
||||
pdb_path + L"\"";
|
||||
std::string symbols;
|
||||
ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
|
||||
|
||||
EXPECT_EQ(expected_symbols, symbols);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DumpSyms, DumpSymsRegressionTest,
|
||||
testing::ValuesIn(kRootNames));
|
||||
|
||||
TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) {
|
||||
const wchar_t* root_name = GetParam();
|
||||
std::wstring root_path = testdata_dir + L"\\" + root_name;
|
||||
|
||||
std::wstring sym_path = root_path + L".sym";
|
||||
std::string expected_symbols;
|
||||
ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
|
||||
|
||||
std::wstring dll_path = root_path + L".dll";
|
||||
std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" +
|
||||
dll_path + L"\"";
|
||||
std::string symbols;
|
||||
ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
|
||||
|
||||
EXPECT_EQ(expected_symbols, symbols);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest,
|
||||
testing::ValuesIn(kPEOnlyRootNames));
|
||||
|
||||
|
||||
} // namespace dump_syms
|
||||
} // namespace windows
|
||||
} // namespace tools
|
52
externals/breakpad/src/tools/windows/dump_syms/run_regtest.sh
vendored
Executable file
52
externals/breakpad/src/tools/windows/dump_syms/run_regtest.sh
vendored
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright 2006 Google LLC
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Release/dump_syms.exe testdata/dump_syms_regtest.pdb | \
|
||||
tr -d '\015' > \
|
||||
testdata/dump_syms_regtest.new
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ] ; then
|
||||
echo "FAIL, dump_syms.exe failed"
|
||||
exit $status
|
||||
fi
|
||||
|
||||
diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.sym > \
|
||||
testdata/dump_syms_regtest.diff
|
||||
status=$?
|
||||
|
||||
if [ $status -eq 0 ] ; then
|
||||
rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new
|
||||
echo "PASS"
|
||||
else
|
||||
echo "FAIL, see testdata/dump_syms_regtest.[new|diff]"
|
||||
fi
|
||||
|
||||
exit $status
|
75
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc
vendored
Normal file
75
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2007 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// with 32-bit cl
|
||||
// cl /Zi dump_syms_regtest.cc /link /PROFILE
|
||||
// dump_syms dump_syms_regtest.pdb > dump_syms_regtest.sym
|
||||
|
||||
// with 64-bit cl
|
||||
// cp dump_syms_regtest.cc dump_syms_regtest64.cc
|
||||
// cl /Zi dump_syms_regtest64.cc /link /PROFILE
|
||||
// dump_syms dump_syms_regtest64.pdb > dump_syms_regtest64.sym
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class C {
|
||||
public:
|
||||
C() : member_(1) {}
|
||||
virtual ~C() {}
|
||||
|
||||
void set_member(int value) { member_ = value; }
|
||||
int member() const { return member_; }
|
||||
|
||||
void f() { member_ = g(); }
|
||||
virtual int g() { return 2; }
|
||||
static char* h(const C& that) { return 0; }
|
||||
|
||||
private:
|
||||
int member_;
|
||||
};
|
||||
|
||||
static int i() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google_breakpad::C object;
|
||||
object.set_member(google_breakpad::i());
|
||||
object.f();
|
||||
int value = object.g();
|
||||
char* nothing = object.h(object);
|
||||
|
||||
return 0;
|
||||
}
|
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb
vendored
Normal file
Binary file not shown.
2945
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest.sym
vendored
Normal file
2945
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest64.exe
vendored
Executable file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest64.exe
vendored
Executable file
Binary file not shown.
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest64.pdb
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest64.pdb
vendored
Normal file
Binary file not shown.
4561
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest64.sym
vendored
Normal file
4561
externals/breakpad/src/tools/windows/dump_syms/testdata/dump_syms_regtest64.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_bbs.pdb
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_bbs.pdb
vendored
Normal file
Binary file not shown.
6209
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_bbs.sym
vendored
Normal file
6209
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_bbs.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_funcs.pdb
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_funcs.pdb
vendored
Normal file
Binary file not shown.
2945
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_funcs.sym
vendored
Normal file
2945
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_reorder_funcs.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched.pdb
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched.pdb
vendored
Normal file
Binary file not shown.
3137
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched.sym
vendored
Normal file
3137
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched_filled.pdb
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched_filled.pdb
vendored
Normal file
Binary file not shown.
2945
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched_filled.sym
vendored
Normal file
2945
externals/breakpad/src/tools/windows/dump_syms/testdata/omap_stretched_filled.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/pe_only_symbol_test.dll
vendored
Normal file
BIN
externals/breakpad/src/tools/windows/dump_syms/testdata/pe_only_symbol_test.dll
vendored
Normal file
Binary file not shown.
214
externals/breakpad/src/tools/windows/dump_syms/testdata/pe_only_symbol_test.sym
vendored
Normal file
214
externals/breakpad/src/tools/windows/dump_syms/testdata/pe_only_symbol_test.sym
vendored
Normal file
|
@ -0,0 +1,214 @@
|
|||
MODULE windows x86_64 2A5EAB481FAB4A17A9761CDC14FE531A1 pe_only_symbol_test.pdb
|
||||
INFO CODE_ID 5C8AD05F12000 pe_only_symbol_test.dll
|
||||
STACK CFI INIT 1440 39 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1440 .cfa: $rsp 32 +
|
||||
STACK CFI INIT 1490 7f .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1490 .cfa: $rsp 128 +
|
||||
STACK CFI INIT 1520 41 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1520 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 1570 35 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1570 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 15b0 3a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 15b0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 1640 8 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1640 .cfa: $rsp 16 +
|
||||
STACK CFI INIT 1650 d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1650 .cfa: $rsp 16 +
|
||||
STACK CFI INIT 1660 b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1660 .cfa: $rsp 16 +
|
||||
STACK CFI INIT 1670 5a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1670 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 16e0 97 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 16e0 .cfa: $rsp 112 +
|
||||
STACK CFI INIT 17c0 3f .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 17c0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1810 23 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1810 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1840 16 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1840 .cfa: $rsp 16 +
|
||||
STACK CFI INIT 1856 20 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1856 .cfa: $rsp 16 +
|
||||
STACK CFI INIT 1876 5 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1876 .cfa: $rsp 16 +
|
||||
STACK CFI INIT 1890 1b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1890 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 18ab 56 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 18ab .cfa: $rsp 48 +
|
||||
STACK CFI INIT 1901 10 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1901 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 1940 7 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1940 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1947 1a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1947 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1961 b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1961 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 196c 4c .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 196c .cfa: $rsp 64 +
|
||||
STACK CFI INIT 19b8 5 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 19b8 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 19bd 13 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 19bd .cfa: $rsp 64 +
|
||||
STACK CFI INIT 19d0 73 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 19d0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1a90 3a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1a90 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 1ae0 f8 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1ae0 .cfa: $rsp 96 +
|
||||
STACK CFI INIT 1c30 21 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1c30 .cfa: $rsp 8 +
|
||||
STACK CFI INIT 1c60 87 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1c60 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1d10 13a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1d10 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 1ea0 88 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1ea0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 1f50 135 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 1f50 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 20e0 4d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 20e0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 2140 2a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2140 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 2180 36 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2180 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 2290 36 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2290 .cfa: $rsp 96 +
|
||||
STACK CFI INIT 22e0 44 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 22e0 .cfa: $rsp 96 +
|
||||
STACK CFI INIT 2340 5f .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2340 .cfa: $rsp 544 +
|
||||
STACK CFI INIT 239f d9 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 239f .cfa: $rsp 544 +
|
||||
STACK CFI INIT 2478 1d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2478 .cfa: $rsp 544 +
|
||||
STACK CFI INIT 2560 cf .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2560 .cfa: $rsp 1088 +
|
||||
STACK CFI INIT 2670 2d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2670 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 269d 6b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 269d .cfa: $rsp 80 +
|
||||
STACK CFI INIT 2708 1a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2708 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 2770 260 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2770 .cfa: $rsp 3824 +
|
||||
STACK CFI INIT 2a70 1f .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2a70 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 2aa0 c5 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2aa0 .cfa: $rsp 1088 +
|
||||
STACK CFI INIT 2ba0 64 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2ba0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 2c20 25 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2c20 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 2c50 35 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2c50 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 2ca0 d1 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2ca0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 2db0 13 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2db0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 2dd0 9b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2dd0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 2ea0 10e .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 2ea0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 3000 91 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3000 .cfa: $rsp 128 +
|
||||
STACK CFI INIT 30c0 b2 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 30c0 .cfa: $rsp 128 +
|
||||
STACK CFI INIT 31a0 be .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 31a0 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 3290 74 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3290 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 3330 16 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3330 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3350 15 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3350 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3380 45 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3380 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 33e0 3b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 33e0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3430 40 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3430 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 34a0 15 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 34a0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 34c0 c6 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 34c0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 35c0 e .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 35c0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 35e0 8a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 35e0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 36a0 62 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 36a0 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 3720 2d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3720 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3760 1d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3760 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3790 30 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3790 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 37d0 15 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 37d0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 37f0 5b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 37f0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 3870 2e .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3870 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 38b0 15 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 38b0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 38d0 49 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 38d0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3930 10c .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3930 .cfa: $rsp 128 +
|
||||
STACK CFI INIT 3a80 8b .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3a80 .cfa: $rsp 96 +
|
||||
STACK CFI INIT 3b30 2f .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3b30 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3b70 3f .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3b70 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3bc0 82 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3bc0 .cfa: $rsp 80 +
|
||||
STACK CFI INIT 3c70 50 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3c70 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 3ce0 33 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3ce0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 3d50 191 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3d50 .cfa: $rsp 1536 +
|
||||
STACK CFI INIT 3f50 51 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3f50 .cfa: $rsp 176 +
|
||||
STACK CFI INIT 3fc0 e .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3fc0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 3ff0 a6 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 3ff0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 40c0 16 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 40c0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 40f0 72 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 40f0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 4180 42 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4180 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 41e0 42 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 41e0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 4250 1e .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4250 .cfa: $rsp 32 +
|
||||
STACK CFI INIT 4280 18 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4280 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 42a0 37 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 42a0 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 4300 145 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4300 .cfa: $rsp 1120 +
|
||||
STACK CFI INIT 44a0 2ae .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 44a0 .cfa: $rsp 640 +
|
||||
STACK CFI INIT 4800 103 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4800 .cfa: $rsp 1664 +
|
||||
STACK CFI INIT 4950 3c5 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4950 .cfa: $rsp 240 +
|
||||
STACK CFI INIT 4e10 36d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 4e10 .cfa: $rsp 96 +
|
||||
STACK CFI INIT 5270 25 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 5270 .cfa: $rsp 32 +
|
||||
STACK CFI INIT 66c0 2 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 66c0 .cfa: $rsp 8 +
|
||||
STACK CFI INIT 76d0 1a .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 76d0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 76f0 20 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 76f0 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 7720 48 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 7720 .cfa: $rsp 64 +
|
||||
STACK CFI INIT 7780 20 .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 7780 .cfa: $rsp 48 +
|
||||
STACK CFI INIT 77b0 3d .cfa: $rsp .ra: .cfa 8 - ^
|
||||
STACK CFI 77b0 .cfa: $rsp 48 +
|
23
externals/breakpad/src/tools/windows/refresh_binaries.bat
vendored
Normal file
23
externals/breakpad/src/tools/windows/refresh_binaries.bat
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
REM This batch file is meant to facilitate regenerating prebuilt binaries for
|
||||
REM the Windows tools.
|
||||
REM You MUST run it from a Visual Studio xxxx Command Prompt. To do this,
|
||||
REM navigate to:
|
||||
REM
|
||||
REM Start->Programs->Microsoft Visual Studio XXXX->Tools->
|
||||
REM Visual Studio Command Prompt
|
||||
REM
|
||||
REM Then run this batch file. It performs an SVN update, edits the
|
||||
REM README.binaries file to contain
|
||||
REM the revision number, and builds the tools. You must run 'svn commit' to
|
||||
REM commit the pending edits to the repository.
|
||||
|
||||
pushd %~dp0
|
||||
if %VisualStudioVersion% == 14.0 set GYP_MSVS_VERSION=2015
|
||||
gyp tools_windows.gyp
|
||||
msbuild tools_windows.sln /p:Configuration=Release /t:Clean,Build
|
||||
copy Release\symupload.exe binaries\
|
||||
copy Release\dump_syms.exe binaries\
|
||||
git add binaries
|
||||
git commit -m "Built Windows binaries"
|
||||
echo Done!
|
||||
popd
|
316
externals/breakpad/src/tools/windows/symupload/symupload.cc
vendored
Normal file
316
externals/breakpad/src/tools/windows/symupload/symupload.cc
vendored
Normal file
|
@ -0,0 +1,316 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Tool to upload an exe/dll and its associated symbols to an HTTP server.
|
||||
// The PDB file is located automatically, using the path embedded in the
|
||||
// executable. The upload is sent as a multipart/form-data POST request,
|
||||
// with the following parameters:
|
||||
// code_file: the basename of the module, e.g. "app.exe"
|
||||
// debug_file: the basename of the debugging file, e.g. "app.pdb"
|
||||
// debug_identifier: the debug file's identifier, usually consisting of
|
||||
// the guid and age embedded in the pdb, e.g.
|
||||
// "11111111BBBB3333DDDD555555555555F"
|
||||
// product: the HTTP-friendly product name, e.g. "MyApp"
|
||||
// version: the file version of the module, e.g. "1.2.3.4"
|
||||
// os: the operating system that the module was built for, always
|
||||
// "windows" in this implementation.
|
||||
// cpu: the CPU that the module was built for, typically "x86".
|
||||
// symbol_file: the contents of the breakpad-format symbol file
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <wininet.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/windows/string_utils-inl.h"
|
||||
|
||||
#include "common/windows/http_upload.h"
|
||||
#include "common/windows/pdb_source_line_writer.h"
|
||||
#include "common/windows/sym_upload_v2_protocol.h"
|
||||
#include "common/windows/symbol_collector_client.h"
|
||||
|
||||
using google_breakpad::HTTPUpload;
|
||||
using google_breakpad::PDBModuleInfo;
|
||||
using google_breakpad::PDBSourceLineWriter;
|
||||
using google_breakpad::WindowsStringUtils;
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::wstring;
|
||||
|
||||
const wchar_t* kSymbolUploadTypeBreakpad = L"BREAKPAD";
|
||||
|
||||
// Extracts the file version information for the given filename,
|
||||
// as a string, for example, "1.2.3.4". Returns true on success.
|
||||
static bool GetFileVersionString(const wchar_t* filename, wstring* version) {
|
||||
DWORD handle;
|
||||
DWORD version_size = GetFileVersionInfoSize(filename, &handle);
|
||||
if (version_size < sizeof(VS_FIXEDFILEINFO)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<char> version_info(version_size);
|
||||
if (!GetFileVersionInfo(filename, handle, version_size, &version_info[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void* file_info_buffer = NULL;
|
||||
unsigned int file_info_length;
|
||||
if (!VerQueryValue(&version_info[0], L"\\",
|
||||
&file_info_buffer, &file_info_length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The maximum value of each version component is 65535 (0xffff),
|
||||
// so the max length is 24, including the terminating null.
|
||||
wchar_t ver_string[24];
|
||||
VS_FIXEDFILEINFO* file_info =
|
||||
reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer);
|
||||
swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]),
|
||||
L"%d.%d.%d.%d",
|
||||
file_info->dwFileVersionMS >> 16,
|
||||
file_info->dwFileVersionMS & 0xffff,
|
||||
file_info->dwFileVersionLS >> 16,
|
||||
file_info->dwFileVersionLS & 0xffff);
|
||||
|
||||
// remove when VC++7.1 is no longer supported
|
||||
ver_string[sizeof(ver_string) / sizeof(ver_string[0]) - 1] = L'\0';
|
||||
|
||||
*version = ver_string;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates a new temporary file and writes the symbol data from the given
|
||||
// exe/dll file to it. Returns the path to the temp file in temp_file_path
|
||||
// and information about the pdb in pdb_info.
|
||||
static bool DumpSymbolsToTempFile(const wchar_t* file,
|
||||
wstring* temp_file_path,
|
||||
PDBModuleInfo* pdb_info,
|
||||
bool handle_inline) {
|
||||
google_breakpad::PDBSourceLineWriter writer(handle_inline);
|
||||
// Use EXE_FILE to get information out of the exe/dll in addition to the
|
||||
// pdb. The name and version number of the exe/dll are of value, and
|
||||
// there's no way to locate an exe/dll given a pdb.
|
||||
if (!writer.Open(file, PDBSourceLineWriter::EXE_FILE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t temp_path[_MAX_PATH];
|
||||
if (GetTempPath(_MAX_PATH, temp_path) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t temp_filename[_MAX_PATH];
|
||||
if (GetTempFileName(temp_path, L"sym", 0, temp_filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* temp_file = NULL;
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
if (_wfopen_s(&temp_file, temp_filename, L"w") != 0)
|
||||
#else // _MSC_VER >= 1400
|
||||
// _wfopen_s was introduced in MSVC8. Use _wfopen for earlier environments.
|
||||
// Don't use it with MSVC8 and later, because it's deprecated.
|
||||
if (!(temp_file = _wfopen(temp_filename, L"w")))
|
||||
#endif // _MSC_VER >= 1400
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = writer.WriteSymbols(temp_file);
|
||||
fclose(temp_file);
|
||||
if (!success) {
|
||||
_wunlink(temp_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
*temp_file_path = temp_filename;
|
||||
|
||||
return writer.GetModuleInfo(pdb_info);
|
||||
}
|
||||
|
||||
__declspec(noreturn) void printUsageAndExit() {
|
||||
wprintf(L"Usage:\n\n"
|
||||
L" symupload [--i] [--timeout NN] [--product product_name] ^\n"
|
||||
L" <file.exe|file.dll> <symbol upload URL> ^\n"
|
||||
L" [...<symbol upload URLs>]\n\n");
|
||||
wprintf(L" - i: Extract inline information from pdb.\n");
|
||||
wprintf(L" - Timeout is in milliseconds, or can be 0 to be unlimited.\n");
|
||||
wprintf(L" - product_name is an HTTP-friendly product name. It must only\n"
|
||||
L" contain an ascii subset: alphanumeric and punctuation.\n"
|
||||
L" This string is case-sensitive.\n\n");
|
||||
wprintf(L"Example:\n\n"
|
||||
L" symupload.exe --timeout 0 --product Chrome ^\n"
|
||||
L" chrome.dll http://no.free.symbol.server.for.you\n");
|
||||
wprintf(L"\n");
|
||||
wprintf(L"sym-upload-v2 usage:\n"
|
||||
L" symupload -p [-f] <file.exe|file.dll> <API-URL> <API-key>\n");
|
||||
wprintf(L"\n");
|
||||
wprintf(L"sym_upload_v2 Options:\n");
|
||||
wprintf(L" <API-URL> is the sym_upload_v2 API URL.\n");
|
||||
wprintf(L" <API-key> is a secret used to authenticate with the API.\n");
|
||||
wprintf(L" -p:\t Use sym_upload_v2 protocol.\n");
|
||||
wprintf(L" -f:\t Force symbol upload if already exists.\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t* argv[]) {
|
||||
const wchar_t* module;
|
||||
const wchar_t* product = nullptr;
|
||||
bool handle_inline = false;
|
||||
int timeout = -1;
|
||||
int currentarg = 1;
|
||||
bool use_sym_upload_v2 = false;
|
||||
bool force = false;
|
||||
const wchar_t* api_url = nullptr;
|
||||
const wchar_t* api_key = nullptr;
|
||||
while (argc > currentarg + 1) {
|
||||
if (!wcscmp(L"--i", argv[currentarg])) {
|
||||
handle_inline = true;
|
||||
++currentarg;
|
||||
continue;
|
||||
}
|
||||
if (!wcscmp(L"--timeout", argv[currentarg])) {
|
||||
timeout = _wtoi(argv[currentarg + 1]);
|
||||
currentarg += 2;
|
||||
continue;
|
||||
}
|
||||
if (!wcscmp(L"--product", argv[currentarg])) {
|
||||
product = argv[currentarg + 1];
|
||||
currentarg += 2;
|
||||
continue;
|
||||
}
|
||||
if (!wcscmp(L"-p", argv[currentarg])) {
|
||||
use_sym_upload_v2 = true;
|
||||
++currentarg;
|
||||
continue;
|
||||
}
|
||||
if (!wcscmp(L"-f", argv[currentarg])) {
|
||||
force = true;
|
||||
++currentarg;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (argc >= currentarg + 2)
|
||||
module = argv[currentarg++];
|
||||
else
|
||||
printUsageAndExit();
|
||||
|
||||
wstring symbol_file;
|
||||
PDBModuleInfo pdb_info;
|
||||
if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info, handle_inline)) {
|
||||
fwprintf(stderr, L"Could not get symbol data from %s\n", module);
|
||||
return 1;
|
||||
}
|
||||
|
||||
wstring code_file = WindowsStringUtils::GetBaseName(wstring(module));
|
||||
wstring file_version;
|
||||
// Don't make a missing version a hard error. Issue a warning, and let the
|
||||
// server decide whether to reject files without versions.
|
||||
if (!GetFileVersionString(module, &file_version)) {
|
||||
fwprintf(stderr, L"Warning: Could not get file version for %s\n", module);
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
if (use_sym_upload_v2) {
|
||||
if (argc >= currentarg + 2) {
|
||||
api_url = argv[currentarg++];
|
||||
api_key = argv[currentarg++];
|
||||
wstring product_name = product ? wstring(product) : L"";
|
||||
|
||||
success = google_breakpad::SymUploadV2ProtocolSend(
|
||||
api_url, api_key, timeout == -1 ? nullptr : &timeout,
|
||||
pdb_info.debug_file, pdb_info.debug_identifier, symbol_file,
|
||||
kSymbolUploadTypeBreakpad, product_name, force);
|
||||
} else {
|
||||
printUsageAndExit();
|
||||
}
|
||||
} else {
|
||||
map<wstring, wstring> parameters;
|
||||
parameters[L"code_file"] = code_file;
|
||||
parameters[L"debug_file"] = pdb_info.debug_file;
|
||||
parameters[L"debug_identifier"] = pdb_info.debug_identifier;
|
||||
parameters[L"os"] = L"windows"; // This version of symupload is Windows-only
|
||||
parameters[L"cpu"] = pdb_info.cpu;
|
||||
|
||||
map<wstring, wstring> files;
|
||||
files[L"symbol_file"] = symbol_file;
|
||||
|
||||
if (!file_version.empty()) {
|
||||
parameters[L"version"] = file_version;
|
||||
}
|
||||
|
||||
// Don't make a missing product name a hard error. Issue a warning and let
|
||||
// the server decide whether to reject files without product name.
|
||||
if (product) {
|
||||
parameters[L"product"] = product;
|
||||
}
|
||||
else {
|
||||
fwprintf(
|
||||
stderr,
|
||||
L"Warning: No product name (flag --product) was specified for %s\n",
|
||||
module);
|
||||
}
|
||||
|
||||
while (currentarg < argc) {
|
||||
int response_code;
|
||||
if (!HTTPUpload::SendMultipartPostRequest(argv[currentarg], parameters, files,
|
||||
timeout == -1 ? NULL : &timeout,
|
||||
nullptr, &response_code)) {
|
||||
success = false;
|
||||
fwprintf(stderr,
|
||||
L"Symbol file upload to %s failed. Response code = %ld\n",
|
||||
argv[currentarg], response_code);
|
||||
}
|
||||
currentarg++;
|
||||
}
|
||||
}
|
||||
|
||||
_wunlink(symbol_file.c_str());
|
||||
|
||||
if (success) {
|
||||
wprintf(L"Uploaded breakpad symbols for windows-%s/%s/%s (%s %s)\n",
|
||||
pdb_info.cpu.c_str(), pdb_info.debug_file.c_str(),
|
||||
pdb_info.debug_identifier.c_str(), code_file.c_str(),
|
||||
file_version.c_str());
|
||||
}
|
||||
|
||||
return success ? 0 : 1;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue