diff options
Diffstat (limited to 'src/tools')
57 files changed, 4664 insertions, 5844 deletions
diff --git a/src/tools/linux/core2md/core2md.cc b/src/tools/linux/core2md/core2md.cc index c3a9da39..3f34294f 100644 --- a/src/tools/linux/core2md/core2md.cc +++ b/src/tools/linux/core2md/core2md.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -33,13 +32,15 @@ #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", argv0); + fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n", + google_breakpad::BaseName(argv0).c_str()); return 1; } diff --git a/src/tools/linux/core_handler/core_handler.cc b/src/tools/linux/core_handler/core_handler.cc new file mode 100644 index 00000000..224073d3 --- /dev/null +++ b/src/tools/linux/core_handler/core_handler.cc @@ -0,0 +1,147 @@ +// 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 + +#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; +} diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc index ebdf2314..8998b3b3 100644 --- a/src/tools/linux/dump_syms/dump_syms.cc +++ b/src/tools/linux/dump_syms/dump_syms.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -37,32 +36,41 @@ #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", 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) { +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; @@ -72,6 +80,8 @@ int main(int argc, char **argv) { 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) { @@ -90,6 +100,8 @@ int main(int argc, char **argv) { } 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]); @@ -124,8 +136,10 @@ int main(int argc, char **argv) { return 1; } } else { - SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI; - google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs); + 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"); diff --git a/src/tools/linux/md2core/minidump-2-core.cc b/src/tools/linux/md2core/minidump-2-core.cc index a60be323..a4ddbe8e 100644 --- a/src/tools/linux/md2core/minidump-2-core.cc +++ b/src/tools/linux/md2core/minidump-2-core.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -77,6 +76,8 @@ #define ELF_ARCH EM_MIPS #elif defined(__aarch64__) #define ELF_ARCH EM_AARCH64 +#elif defined(__riscv) + #define ELF_ARCH EM_RISCV #endif #if defined(__arm__) @@ -84,7 +85,7 @@ // containing core registers, while they use 'user_regs_struct' on other // architectures. This file-local typedef simplifies the source code. typedef user_regs user_regs_struct; -#elif defined (__mips__) +#elif defined (__mips__) || defined(__riscv) // This file-local typedef simplifies the source code. typedef gregset_t user_regs_struct; #endif @@ -149,16 +150,14 @@ SetupOptions(int argc, const char* argv[], Options* options) { options->use_filename = false; options->inc_guid = false; - while ((ch = getopt(argc, (char * const *)argv, "fhio:S:v")) != -1) { + while ((ch = getopt(argc, (char * const*)argv, "fhio:S:v")) != -1) { switch (ch) { case 'h': Usage(argc, argv); exit(0); - break; case '?': Usage(argc, argv); exit(1); - break; case 'f': options->use_filename = true; @@ -224,7 +223,7 @@ writea(int fd, const void* idata, size_t length) { */ static inline int sex() { int probe = 1; - return !*(char *)&probe; + return !*(char*)&probe; } typedef struct elf_timeval { /* Time value with microsecond resolution */ @@ -261,7 +260,7 @@ typedef struct prpsinfo { /* Information about process */ unsigned char pr_zomb; /* Zombie */ signed char pr_nice; /* Nice val */ unsigned long pr_flag; /* Flags */ -#if defined(__x86_64__) || defined(__mips__) +#if defined(__x86_64__) || defined(__mips__) || defined(__riscv) uint32_t pr_uid; /* User ID */ uint32_t pr_gid; /* Group ID */ #else @@ -308,7 +307,7 @@ struct CrashedProcess { struct Thread { pid_t tid; -#if defined(__mips__) +#if defined(__mips__) || defined(__riscv) mcontext_t mcontext; #else user_regs_struct regs; @@ -535,6 +534,71 @@ ParseThreadRegisters(CrashedProcess::Thread* thread, thread->mcontext.fpc_eir = rawregs->float_save.fir; #endif } +#elif defined(__riscv) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { +# if __riscv_xlen == 32 + const MDRawContextRISCV* rawregs = range.GetData<MDRawContextRISCV>(0); +# elif __riscv_xlen == 64 + const MDRawContextRISCV64* rawregs = range.GetData<MDRawContextRISCV64>(0); +# else +# error "Unexpected __riscv_xlen" +# endif + + thread->mcontext.__gregs[0] = rawregs->pc; + thread->mcontext.__gregs[1] = rawregs->ra; + thread->mcontext.__gregs[2] = rawregs->sp; + thread->mcontext.__gregs[3] = rawregs->gp; + thread->mcontext.__gregs[4] = rawregs->tp; + thread->mcontext.__gregs[5] = rawregs->t0; + thread->mcontext.__gregs[6] = rawregs->t1; + thread->mcontext.__gregs[7] = rawregs->t2; + thread->mcontext.__gregs[8] = rawregs->s0; + thread->mcontext.__gregs[9] = rawregs->s1; + thread->mcontext.__gregs[10] = rawregs->a0; + thread->mcontext.__gregs[11] = rawregs->a1; + thread->mcontext.__gregs[12] = rawregs->a2; + thread->mcontext.__gregs[13] = rawregs->a3; + thread->mcontext.__gregs[14] = rawregs->a4; + thread->mcontext.__gregs[15] = rawregs->a5; + thread->mcontext.__gregs[16] = rawregs->a6; + thread->mcontext.__gregs[17] = rawregs->a7; + thread->mcontext.__gregs[18] = rawregs->s2; + thread->mcontext.__gregs[19] = rawregs->s3; + thread->mcontext.__gregs[20] = rawregs->s4; + thread->mcontext.__gregs[21] = rawregs->s5; + thread->mcontext.__gregs[22] = rawregs->s6; + thread->mcontext.__gregs[23] = rawregs->s7; + thread->mcontext.__gregs[24] = rawregs->s8; + thread->mcontext.__gregs[25] = rawregs->s9; + thread->mcontext.__gregs[26] = rawregs->s10; + thread->mcontext.__gregs[27] = rawregs->s11; + thread->mcontext.__gregs[28] = rawregs->t3; + thread->mcontext.__gregs[29] = rawregs->t4; + thread->mcontext.__gregs[30] = rawregs->t5; + thread->mcontext.__gregs[31] = rawregs->t6; + +# if __riscv_flen == 32 + for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__f.__f[i] = rawregs->float_save.regs[i]; + } + thread->mcontext.__fpregs.__f.__fcsr = rawregs->float_save.fpcsr; +# elif __riscv_flen == 64 + for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__d.__f[i] = rawregs->float_save.regs[i]; + } + thread->mcontext.__fpregs.__d.__fcsr = rawregs->float_save.fpcsr; +# elif __riscv_flen == 128 + for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__q.__f[2*i] = rawregs->float_save.regs[i].high; + thread->mcontext.__fpregs.__q.__f[2*i+1] = rawregs->float_save.regs[i].low; + } + thread->mcontext.__fpregs.__q.__fcsr = rawregs->float_save.fpcsr; +# else +# error "Unexpected __riscv_flen" +# endif +} #else #error "This code has not been ported to your platform yet" #endif @@ -602,7 +666,8 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, exit(1); } #elif defined(__aarch64__) - if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD) { + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD && + sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) { fprintf(stderr, "This version of minidump-2-core only supports ARM (64bit).\n"); exit(1); @@ -623,11 +688,26 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, # else # error "This mips ABI is currently not supported (n32)" # endif +#elif defined(__riscv) +# if __riscv_xlen == 32 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV) { + fprintf(stderr, + "This version of minidump-2-core only supports RISCV.\n"); + exit(1); + } +# elif __riscv_xlen == 64 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV64) { + fprintf(stderr, + "This version of minidump-2-core only supports RISCV64.\n"); + exit(1); + } +# else +# error "Unexpected __riscv_xlen" +# endif #else #error "This code has not been ported to your platform yet" #endif - if (!strstr(full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str(), - "Linux") && + if (sysinfo->platform_id != MD_OS_LINUX && sysinfo->platform_id != MD_OS_NACL) { fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n"); exit(1); @@ -651,6 +731,10 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, ? "MIPS" : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS64 ? "MIPS64" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV + ? "RISCV" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV64 + ? "RISCV64" : "???", sysinfo->number_of_processors, sysinfo->processor_level, @@ -660,10 +744,10 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) { fputs("Vendor id: ", stderr); const char *nul = - (const char *)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0, + (const char*)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0, sizeof(sysinfo->cpu.x86_cpu_info.vendor_id)); fwrite(sysinfo->cpu.x86_cpu_info.vendor_id, - nul ? nul - (const char *)&sysinfo->cpu.x86_cpu_info.vendor_id[0] + nul ? nul - (const char*)&sysinfo->cpu.x86_cpu_info.vendor_id[0] : sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr); fputs("\n", stderr); } @@ -759,7 +843,7 @@ ParseEnvironment(const Options& options, CrashedProcess* crashinfo, memcpy(env, range.data(), range.length()); int nul_count = 0; for (char *ptr = env;;) { - ptr = (char *)memchr(ptr, '\000', range.length() - (ptr - env)); + ptr = (char*)memchr(ptr, '\000', range.length() - (ptr - env)); if (!ptr) { break; } @@ -928,6 +1012,8 @@ WriteThread(const Options& options, const CrashedProcess::Thread& thread, pr.pr_pid = thread.tid; #if defined(__mips__) memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct)); +#elif defined(__riscv) + memcpy(&pr.pr_reg, &thread.mcontext.__gregs, sizeof(user_regs_struct)); #else memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct)); #endif @@ -1076,7 +1162,7 @@ AugmentMappings(const Options& options, CrashedProcess* crashinfo, for (unsigned i = 0; i < crashinfo->threads.size(); ++i) { const CrashedProcess::Thread& thread = crashinfo->threads[i]; AddDataToMapping(crashinfo, - string((char *)thread.stack, thread.stack_length), + string((char*)thread.stack, thread.stack_length), thread.stack_addr); } diff --git a/src/tools/linux/md2core/minidump_memory_range.h b/src/tools/linux/md2core/minidump_memory_range.h index a793e2cf..6cf07470 100644 --- a/src/tools/linux/md2core/minidump_memory_range.h +++ b/src/tools/linux/md2core/minidump_memory_range.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // diff --git a/src/tools/linux/md2core/minidump_memory_range_unittest.cc b/src/tools/linux/md2core/minidump_memory_range_unittest.cc index fe4ded83..9012101d 100644 --- a/src/tools/linux/md2core/minidump_memory_range_unittest.cc +++ b/src/tools/linux/md2core/minidump_memory_range_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // diff --git a/src/tools/linux/pid2md/pid2md.cc b/src/tools/linux/pid2md/pid2md.cc new file mode 100644 index 00000000..ca1cb637 --- /dev/null +++ b/src/tools/linux/pid2md/pid2md.cc @@ -0,0 +1,58 @@ +// 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 + +#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; +} diff --git a/src/tools/linux/symupload/minidump_upload.cc b/src/tools/linux/symupload/minidump_upload.cc index 19f17450..6adead03 100644 --- a/src/tools/linux/symupload/minidump_upload.cc +++ b/src/tools/linux/symupload/minidump_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -41,6 +40,7 @@ #include <string> #include "common/linux/http_upload.h" +#include "common/path_helper.h" #include "common/using_std_string.h" using google_breakpad::HTTPUpload; @@ -91,8 +91,10 @@ static void Start(Options *options) { 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", argv[0]); + 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"); @@ -111,7 +113,7 @@ 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) { + while ((ch = getopt(argc, (char * const*)argv, "p:u:v:x:h?")) != -1) { switch (ch) { case 'p': options->product = optarg; diff --git a/src/tools/linux/symupload/sym_upload.cc b/src/tools/linux/symupload/sym_upload.cc index f155eb95..8f5e8a50 100644 --- a/src/tools/linux/symupload/sym_upload.cc +++ b/src/tools/linux/symupload/sym_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -47,6 +46,7 @@ #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; @@ -66,10 +66,11 @@ 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]); + 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, + "<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"); @@ -111,17 +112,20 @@ Usage(int argc, const char *argv[]) { //============================================================================= static void SetupOptions(int argc, const char *argv[], Options *options) { - extern int optind; + 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) { + while ((ch = getopt(argc, (char * const*)argv, flag_pattern)) != -1) { switch (ch) { case 'h': case '?': Usage(argc, argv); - exit(0); - break; + // 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; @@ -166,7 +170,6 @@ SetupOptions(int argc, const char *argv[], Options *options) { fprintf(stderr, "Invalid option '%c'\n", ch); Usage(argc, argv); exit(1); - break; } } diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi deleted file mode 100644 index 020e4c1c..00000000 --- a/src/tools/linux/tools_linux.gypi +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2014 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'target_defaults': { - 'include_dirs': [ - '../..', - ], - }, - 'targets': [ - { - 'target_name': 'dump_syms', - 'type': 'executable', - 'sources': [ - 'dump_syms/dump_syms.cc', - ], - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'md2core', - 'type': 'executable', - 'sources': [ - 'md2core/minidump-2-core.cc', - 'md2core/minidump_memory_range.h', - ], - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'minidump_upload', - 'type': 'executable', - 'sources': [ - 'symupload/minidump_upload.cc', - ], - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'symupload', - 'type': 'executable', - 'sources': [ - 'symupload/sym_upload.cc', - ], - 'link_settings': { - 'libraries': [ - '-ldl', - ], - }, - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - ], -} diff --git a/src/tools/mac/crash_report/crash_report.mm b/src/tools/mac/crash_report/crash_report.mm deleted file mode 100644 index f68200c7..00000000 --- a/src/tools/mac/crash_report/crash_report.mm +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// 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 Inc. 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. - -// crash_report.mm: Convert the contents of a minidump into a format that -// looks more like Apple's CrashReporter format - -#include <unistd.h> - -#include <mach/machine.h> -#include <mach-o/arch.h> - -#include <string> - -#include <Foundation/Foundation.h> - -#include "common/scoped_ptr.h" -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "google_breakpad/processor/call_stack.h" -#include "google_breakpad/processor/code_module.h" -#include "google_breakpad/processor/minidump.h" -#include "google_breakpad/processor/minidump_processor.h" -#include "google_breakpad/processor/process_state.h" -#include "google_breakpad/processor/stack_frame_cpu.h" -#include "google_breakpad/processor/system_info.h" -#include "processor/pathname_stripper.h" -#include "processor/simple_symbol_supplier.h" - -#include "on_demand_symbol_supplier.h" - -using std::string; - -using google_breakpad::BasicSourceLineResolver; -using google_breakpad::CallStack; -using google_breakpad::CodeModule; -using google_breakpad::CodeModules; -using google_breakpad::Minidump; -using google_breakpad::MinidumpProcessor; -using google_breakpad::OnDemandSymbolSupplier; -using google_breakpad::PathnameStripper; -using google_breakpad::ProcessState; -using google_breakpad::scoped_ptr; -using google_breakpad::StackFrame; -using google_breakpad::StackFramePPC; -using google_breakpad::StackFrameX86; -using google_breakpad::SystemInfo; - -typedef struct { - NSString *minidumpPath; - NSString *searchDir; - NSString *symbolSearchDir; - BOOL printThreadMemory; -} Options; - -//============================================================================= -static int PrintRegister(const char *name, u_int32_t value, int sequence) { - if (sequence % 4 == 0) { - printf("\n"); - } - printf("%6s = 0x%08x ", name, value); - return ++sequence; -} - -//============================================================================= -static void PrintStack(const CallStack *stack, const string &cpu) { - size_t frame_count = stack->frames()->size(); - char buffer[1024]; - for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { - const StackFrame *frame = stack->frames()->at(frame_index); - const CodeModule *module = frame->module; - printf("%2zu ", frame_index); - - if (module) { - // Module name (20 chars max) - strcpy(buffer, PathnameStripper::File(module->code_file()).c_str()); - int maxStr = 20; - buffer[maxStr] = 0; - printf("%-*s", maxStr, buffer); - - strcpy(buffer, module->version().c_str()); - buffer[maxStr] = 0; - - printf("%-*s",maxStr, buffer); - - u_int64_t instruction = frame->instruction; - - // PPC only: Adjust the instruction to match that of Crash reporter. The - // instruction listed is actually the return address. See the detailed - // comments in stackwalker_ppc.cc for more information. - if (cpu == "ppc" && frame_index) - instruction += 4; - - printf(" 0x%08llx ", instruction); - - // Function name - if (!frame->function_name.empty()) { - printf("%s", frame->function_name.c_str()); - if (!frame->source_file_name.empty()) { - string source_file = PathnameStripper::File(frame->source_file_name); - printf(" + 0x%llx (%s:%d)", - instruction - frame->source_line_base, - source_file.c_str(), frame->source_line); - } else { - printf(" + 0x%llx", instruction - frame->function_base); - } - } - } - printf("\n"); - } -} - -//============================================================================= -static void PrintRegisters(const CallStack *stack, const string &cpu) { - int sequence = 0; - const StackFrame *frame = stack->frames()->at(0); - if (cpu == "x86") { - const StackFrameX86 *frame_x86 = - reinterpret_cast<const StackFrameX86*>(frame); - - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) - sequence = PrintRegister("eip", frame_x86->context.eip, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) - sequence = PrintRegister("esp", frame_x86->context.esp, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) - sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) - sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) - sequence = PrintRegister("esi", frame_x86->context.esi, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) - sequence = PrintRegister("edi", frame_x86->context.edi, sequence); - if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { - sequence = PrintRegister("eax", frame_x86->context.eax, sequence); - sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); - sequence = PrintRegister("edx", frame_x86->context.edx, sequence); - sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); - } - } else if (cpu == "ppc") { - const StackFramePPC *frame_ppc = - reinterpret_cast<const StackFramePPC*>(frame); - - if ((frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_ALL) == - StackFramePPC::CONTEXT_VALID_ALL) { - sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); - sequence = PrintRegister("srr1", frame_ppc->context.srr1, sequence); - sequence = PrintRegister("cr", frame_ppc->context.cr, sequence); - sequence = PrintRegister("xer", frame_ppc->context.xer, sequence); - sequence = PrintRegister("lr", frame_ppc->context.lr, sequence); - sequence = PrintRegister("ctr", frame_ppc->context.ctr, sequence); - sequence = PrintRegister("mq", frame_ppc->context.mq, sequence); - sequence = PrintRegister("vrsave", frame_ppc->context.vrsave, sequence); - - sequence = 0; - char buffer[5]; - for (int i = 0; i < MD_CONTEXT_PPC_GPR_COUNT; ++i) { - sprintf(buffer, "r%d", i); - sequence = PrintRegister(buffer, frame_ppc->context.gpr[i], sequence); - } - } else { - if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) - sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); - if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) - sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); - } - } - - printf("\n"); -} - -static void PrintModules(const CodeModules *modules) { - if (!modules) - return; - - printf("\n"); - printf("Loaded modules:\n"); - - u_int64_t main_address = 0; - const CodeModule *main_module = modules->GetMainModule(); - if (main_module) { - main_address = main_module->base_address(); - } - - unsigned int module_count = modules->module_count(); - for (unsigned int module_sequence = 0; - module_sequence < module_count; - ++module_sequence) { - const CodeModule *module = modules->GetModuleAtSequence(module_sequence); - assert(module); - u_int64_t base_address = module->base_address(); - printf("0x%08llx - 0x%08llx %s %s%s %s\n", - base_address, base_address + module->size() - 1, - PathnameStripper::File(module->code_file()).c_str(), - module->version().empty() ? "???" : module->version().c_str(), - main_module != NULL && base_address == main_address ? - " (main)" : "", - module->code_file().c_str()); - } -} - -static void ProcessSingleReport(Options *options, NSString *file_path) { - string minidump_file([file_path fileSystemRepresentation]); - BasicSourceLineResolver resolver; - string search_dir = options->searchDir ? - [options->searchDir fileSystemRepresentation] : ""; - string symbol_search_dir = options->symbolSearchDir ? - [options->symbolSearchDir fileSystemRepresentation] : ""; - scoped_ptr<OnDemandSymbolSupplier> symbol_supplier( - new OnDemandSymbolSupplier(search_dir, symbol_search_dir)); - scoped_ptr<MinidumpProcessor> - minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver)); - ProcessState process_state; - scoped_ptr<Minidump> dump(new google_breakpad::Minidump(minidump_file)); - - if (!dump->Read()) { - fprintf(stderr, "Minidump %s could not be read\n", dump->path().c_str()); - return; - } - if (minidump_processor->Process(dump.get(), &process_state) != - google_breakpad::PROCESS_OK) { - fprintf(stderr, "MinidumpProcessor::Process failed\n"); - return; - } - - const SystemInfo *system_info = process_state.system_info(); - string cpu = system_info->cpu; - - // Convert the time to a string - u_int32_t time_date_stamp = process_state.time_date_stamp(); - struct tm timestruct; - gmtime_r(reinterpret_cast<time_t*>(&time_date_stamp), ×truct); - char timestr[20]; - strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct); - printf("Date: %s GMT\n", timestr); - - printf("Operating system: %s (%s)\n", system_info->os.c_str(), - system_info->os_version.c_str()); - printf("Architecture: %s\n", cpu.c_str()); - - if (process_state.crashed()) { - printf("Crash reason: %s\n", process_state.crash_reason().c_str()); - printf("Crash address: 0x%llx\n", process_state.crash_address()); - } else { - printf("No crash\n"); - } - - int requesting_thread = process_state.requesting_thread(); - if (requesting_thread != -1) { - printf("\n"); - printf("Thread %d (%s)\n", - requesting_thread, - process_state.crashed() ? "crashed" : - "requested dump, did not crash"); - PrintStack(process_state.threads()->at(requesting_thread), cpu); - } - - // Print all of the threads in the dump. - int thread_count = static_cast<int>(process_state.threads()->size()); - const std::vector<google_breakpad::MemoryRegion*> - *thread_memory_regions = process_state.thread_memory_regions(); - - for (int thread_index = 0; thread_index < thread_count; ++thread_index) { - if (thread_index != requesting_thread) { - // Don't print the crash thread again, it was already printed. - printf("\n"); - printf("Thread %d\n", thread_index); - PrintStack(process_state.threads()->at(thread_index), cpu); - google_breakpad::MemoryRegion *thread_stack_bytes = - thread_memory_regions->at(thread_index); - if (options->printThreadMemory) { - thread_stack_bytes->Print(); - } - } - } - - // Print the crashed registers - if (requesting_thread != -1) { - printf("\nThread %d:", requesting_thread); - PrintRegisters(process_state.threads()->at(requesting_thread), cpu); - } - - // Print information about modules - PrintModules(process_state.modules()); -} - -//============================================================================= -static void Start(Options *options) { - NSFileManager *manager = [NSFileManager defaultManager]; - NSString *minidump_path = options->minidumpPath; - BOOL is_dir = NO; - BOOL file_exists = [manager fileExistsAtPath:minidump_path - isDirectory:&is_dir]; - if (file_exists && is_dir) { - NSDirectoryEnumerator *enumerator = - [manager enumeratorAtPath:minidump_path]; - NSString *current_file = nil; - while ((current_file = [enumerator nextObject])) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - if ([[current_file pathExtension] isEqualTo:@"dmp"]) { - printf("Attempting to process report: %s\n", - [current_file cStringUsingEncoding:NSASCIIStringEncoding]); - NSString *full_path = - [minidump_path stringByAppendingPathComponent:current_file]; - ProcessSingleReport(options, full_path); - } - [pool release]; - } - } else if (file_exists) { - ProcessSingleReport(options, minidump_path); - } -} - -//============================================================================= -static void Usage(int argc, const char *argv[]) { - fprintf(stderr, "Convert a minidump to a crash report. Breakpad symbol " - "files will be used (or created if missing) in /tmp.\n" - "If a symbol-file-search-dir is specified, any symbol " - "files in it will be used instead of being loaded from " - "modules on disk.\n" - "If modules cannot be found at the paths stored in the " - "minidump file, they will be searched for at " - "<module-search-dir>/<path-in-minidump-file>.\n"); - fprintf(stderr, "Usage: %s [-s module-search-dir] [-S symbol-file-search-dir] " - "minidump-file\n", argv[0]); - fprintf(stderr, "\t-s: Specify a search directory to use for missing modules\n" - "\t-S: Specify a search directory to use for symbol files\n" - "\t-t: Print thread stack memory in hex\n" - "\t-h: Usage\n" - "\t-?: Usage\n"); -} - -//============================================================================= -static void SetupOptions(int argc, const char *argv[], Options *options) { - extern int optind; - char ch; - - while ((ch = getopt(argc, (char * const *)argv, "S:s:ht?")) != -1) { - switch (ch) { - case 's': - options->searchDir = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:optarg - length:strlen(optarg)]; - break; - - case 'S': - options->symbolSearchDir = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:optarg - length:strlen(optarg)]; - break; - - case 't': - options->printThreadMemory = YES; - break; - case 'h': - case '?': - Usage(argc, argv); - exit(1); - break; - } - } - - if ((argc - optind) != 1) { - fprintf(stderr, "%s: Missing minidump file\n", argv[0]); - Usage(argc, argv); - exit(1); - } - - options->minidumpPath = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:argv[optind] - length:strlen(argv[optind])]; -} - -//============================================================================= -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 0; -} diff --git a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj b/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj deleted file mode 100644 index 33204f7e..00000000 --- a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj +++ /dev/null @@ -1,618 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 45; - objects = { - -/* Begin PBXBuildFile section */ - 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; }; - 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */; }; - 4247E6402110D5A500482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4247E63F2110D5A500482558 /* path_helper.cc */; }; - 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; }; - 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; }; - 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; }; - 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */; }; - 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */; }; - 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722C126F9B6E00B43EAF /* x86_misc.c */; }; - 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */; }; - 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7234126F9BC200B43EAF /* ia32_settings.c */; }; - 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */; }; - 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725A126F9C8000B43EAF /* ia32_operand.c */; }; - 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725C126F9C9200B43EAF /* x86_insn.c */; }; - 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */; }; - 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7263126F9CBB00B43EAF /* x86_imm.c */; }; - 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA5613DFBA84006CABE3 /* md5.cc */; }; - 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; }; - 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */; }; - 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */; }; - 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */; }; - 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */; }; - 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */; }; - 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */; }; - 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8411F0C6FB00FCF3E4 /* language.cc */; }; - 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8611F0C6FB00FCF3E4 /* module.cc */; }; - 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */; }; - 8B40BDC00C0638E4009535AF /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B40BDBF0C0638E4009535AF /* logging.cc */; }; - 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; }; - 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; - 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */; }; - 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */; }; - 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172A0B1B8B2400F8391B /* call_stack.cc */; }; - 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */; }; - 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF173F0B1B8B9A00F8391B /* minidump.cc */; }; - 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */; }; - 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */; }; - 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17530B1B8BF900F8391B /* stackwalker.cc */; }; - 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF175B0B1B8C1B00F8391B /* process_state.cc */; }; - 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */; }; - 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */; }; - 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */; }; - 9BE650B20B52FE3000611104 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AC0B52FE3000611104 /* file_id.cc */; }; - 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AE0B52FE3000611104 /* macho_id.cc */; }; - 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650B00B52FE3000611104 /* macho_walker.cc */; }; - D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */; }; - D2A5DD631188658B00081F03 /* tokenize.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD621188658B00081F03 /* tokenize.cc */; }; - F407DC48185773C10064622B /* exploitability_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC40185773C10064622B /* exploitability_linux.cc */; }; - F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC41185773C10064622B /* stack_frame_symbolizer.cc */; }; - F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC42185773C10064622B /* stackwalker_arm64.cc */; }; - F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC44185773C10064622B /* stackwalker_mips.cc */; }; - F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC46185773C10064622B /* stackwalker_ppc64.cc */; }; - F44DDD8719C85CD50047280E /* dump_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8419C85CD50047280E /* dump_context.cc */; }; - F44DDD8819C85CD50047280E /* dump_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8519C85CD50047280E /* dump_object.cc */; }; - F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8619C85CD50047280E /* microdump_processor.cc */; }; - F47180561D745DEF0032F208 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180541D745DEF0032F208 /* elf_reader.cc */; }; - F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180571D7467630032F208 /* proc_maps_linux.cc */; }; - F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180591D7468A40032F208 /* symbolic_constants_win.cc */; }; - F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4D43B2E1A38490700C290B2 /* microdump.cc */; }; - F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE20E8ABCA600E953AD /* bytereader.cc */; }; - F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */; }; - F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */; }; - F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */; }; - FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */; }; - FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 08FB7796FE84155DC02AAC07 /* crash_report.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = crash_report.mm; sourceTree = "<group>"; }; - 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; }; - 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; }; - 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_old_arm64_context.cc; path = ../../../processor/convert_old_arm64_context.cc; sourceTree = "<group>"; }; - 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_old_arm64_context.h; path = ../../../processor/convert_old_arm64_context.h; sourceTree = "<group>"; }; - 4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; }; - 4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; }; - 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; }; - 4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; }; - 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; }; - 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = disassembler_x86.cc; path = ../../../processor/disassembler_x86.cc; sourceTree = SOURCE_ROOT; }; - 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_disasm.c; path = ../../../third_party/libdisasm/x86_disasm.c; sourceTree = SOURCE_ROOT; }; - 4D2C722C126F9B6E00B43EAF /* x86_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_misc.c; path = ../../../third_party/libdisasm/x86_misc.c; sourceTree = SOURCE_ROOT; }; - 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_operand_list.c; path = ../../../third_party/libdisasm/x86_operand_list.c; sourceTree = SOURCE_ROOT; }; - 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_invariant.c; path = ../../../third_party/libdisasm/ia32_invariant.c; sourceTree = SOURCE_ROOT; }; - 4D2C7234126F9BC200B43EAF /* ia32_settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_settings.c; path = ../../../third_party/libdisasm/ia32_settings.c; sourceTree = SOURCE_ROOT; }; - 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_insn.c; path = ../../../third_party/libdisasm/ia32_insn.c; sourceTree = SOURCE_ROOT; }; - 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_opcode_tables.c; path = ../../../third_party/libdisasm/ia32_opcode_tables.c; sourceTree = SOURCE_ROOT; }; - 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_implicit.c; path = ../../../third_party/libdisasm/ia32_implicit.c; sourceTree = SOURCE_ROOT; }; - 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_reg.c; path = ../../../third_party/libdisasm/ia32_reg.c; sourceTree = SOURCE_ROOT; }; - 4D2C725A126F9C8000B43EAF /* ia32_operand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_operand.c; path = ../../../third_party/libdisasm/ia32_operand.c; sourceTree = SOURCE_ROOT; }; - 4D2C725C126F9C9200B43EAF /* x86_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_insn.c; path = ../../../third_party/libdisasm/x86_insn.c; sourceTree = SOURCE_ROOT; }; - 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_modrm.c; path = ../../../third_party/libdisasm/ia32_modrm.c; sourceTree = SOURCE_ROOT; }; - 4D2C7263126F9CBB00B43EAF /* x86_imm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_imm.c; path = ../../../third_party/libdisasm/x86_imm.c; sourceTree = SOURCE_ROOT; }; - 4D72CA5613DFBA84006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; - 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; - 5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; - 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; - 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; - 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; - 8B31FF2411F0C62700FCF3E4 /* 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 = SOURCE_ROOT; }; - 8B31FF2511F0C62700FCF3E4 /* 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 = SOURCE_ROOT; }; - 8B31FF2611F0C62700FCF3E4 /* 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 = SOURCE_ROOT; }; - 8B31FF2711F0C62700FCF3E4 /* 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 = SOURCE_ROOT; }; - 8B31FF2811F0C62700FCF3E4 /* 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 = SOURCE_ROOT; }; - 8B31FF2911F0C62700FCF3E4 /* 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 = SOURCE_ROOT; }; - 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; }; - 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; }; - 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; }; - 8B31FF8411F0C6FB00FCF3E4 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF8511F0C6FB00FCF3E4 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; }; - 8B31FF8611F0C6FB00FCF3E4 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF8711F0C6FB00FCF3E4 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; }; - 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; }; - 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; }; - 8B40BDBF0C0638E4009535AF /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../../processor/logging.cc; sourceTree = SOURCE_ROOT; }; - 8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; }; - 9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; }; - 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_module.h; path = ../../../processor/basic_code_module.h; sourceTree = SOURCE_ROOT; }; - 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; }; - 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_modules.h; path = ../../../processor/basic_code_modules.h; sourceTree = SOURCE_ROOT; }; - 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_source_line_resolver.h; sourceTree = "<group>"; }; - 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = "<group>"; }; - 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_source_line_resolver.cc; path = ../../../processor/basic_source_line_resolver.cc; sourceTree = SOURCE_ROOT; }; - 9B44619D0B66C66B00BBB817 /* system_info.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = system_info.h; sourceTree = "<group>"; }; - 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = breakpad_types.h; sourceTree = "<group>"; }; - 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = "<group>"; }; - 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = "<group>"; }; - 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = "<group>"; }; - 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = "<group>"; }; - 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = "<group>"; }; - 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = "<group>"; }; - 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = "<group>"; }; - 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = "<group>"; }; - 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = "<group>"; }; - 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = "<group>"; }; - 9BDF172A0B1B8B2400F8391B /* call_stack.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = call_stack.cc; path = ../../../processor/call_stack.cc; sourceTree = SOURCE_ROOT; }; - 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_processor.cc; path = ../../../processor/minidump_processor.cc; sourceTree = SOURCE_ROOT; }; - 9BDF173F0B1B8B9A00F8391B /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../../processor/minidump.cc; sourceTree = SOURCE_ROOT; }; - 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc.cc; path = ../../../processor/stackwalker_ppc.cc; sourceTree = SOURCE_ROOT; }; - 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_x86.cc; path = ../../../processor/stackwalker_x86.cc; sourceTree = SOURCE_ROOT; }; - 9BDF17530B1B8BF900F8391B /* stackwalker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker.cc; path = ../../../processor/stackwalker.cc; sourceTree = SOURCE_ROOT; }; - 9BDF175B0B1B8C1B00F8391B /* process_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = process_state.cc; path = ../../../processor/process_state.cc; sourceTree = SOURCE_ROOT; }; - 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = on_demand_symbol_supplier.h; sourceTree = "<group>"; }; - 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = "<group>"; }; - 9BDF192D0B1BC15D00F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; }; - 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; }; - 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathname_stripper.cc; path = ../../../processor/pathname_stripper.cc; sourceTree = SOURCE_ROOT; }; - 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "range_map-inl.h"; path = "../../../processor/range_map-inl.h"; sourceTree = SOURCE_ROOT; }; - 9BDF1A7B0B1BE30100F8391B /* range_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = range_map.h; path = ../../../processor/range_map.h; sourceTree = SOURCE_ROOT; }; - 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "address_map-inl.h"; path = "../../../processor/address_map-inl.h"; sourceTree = SOURCE_ROOT; }; - 9BDF1AFB0B1BEB6300F8391B /* address_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = address_map.h; path = ../../../processor/address_map.h; sourceTree = SOURCE_ROOT; }; - 9BE650AC0B52FE3000611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; - 9BE650AD0B52FE3000611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; - 9BE650AE0B52FE3000611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; - 9BE650AF0B52FE3000611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; - 9BE650B00B52FE3000611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; - 9BE650B10B52FE3000611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; - D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_frame_info.cc; path = ../../../processor/cfi_frame_info.cc; sourceTree = SOURCE_ROOT; }; - D2A5DD621188658B00081F03 /* tokenize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tokenize.cc; path = ../../../processor/tokenize.cc; sourceTree = SOURCE_ROOT; }; - F407DC40185773C10064622B /* exploitability_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_linux.cc; path = ../../../processor/exploitability_linux.cc; sourceTree = "<group>"; }; - F407DC41185773C10064622B /* stack_frame_symbolizer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stack_frame_symbolizer.cc; path = ../../../processor/stack_frame_symbolizer.cc; sourceTree = "<group>"; }; - F407DC42185773C10064622B /* stackwalker_arm64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm64.cc; path = ../../../processor/stackwalker_arm64.cc; sourceTree = "<group>"; }; - F407DC43185773C10064622B /* stackwalker_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm64.h; path = ../../../processor/stackwalker_arm64.h; sourceTree = "<group>"; }; - F407DC44185773C10064622B /* stackwalker_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_mips.cc; path = ../../../processor/stackwalker_mips.cc; sourceTree = "<group>"; }; - F407DC45185773C10064622B /* stackwalker_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_mips.h; path = ../../../processor/stackwalker_mips.h; sourceTree = "<group>"; }; - F407DC46185773C10064622B /* stackwalker_ppc64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc64.cc; path = ../../../processor/stackwalker_ppc64.cc; sourceTree = "<group>"; }; - F407DC47185773C10064622B /* stackwalker_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_ppc64.h; path = ../../../processor/stackwalker_ppc64.h; sourceTree = "<group>"; }; - F44DDD8419C85CD50047280E /* dump_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_context.cc; path = ../../../processor/dump_context.cc; sourceTree = "<group>"; }; - F44DDD8519C85CD50047280E /* dump_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_object.cc; path = ../../../processor/dump_object.cc; sourceTree = "<group>"; }; - F44DDD8619C85CD50047280E /* microdump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump_processor.cc; path = ../../../processor/microdump_processor.cc; sourceTree = "<group>"; }; - F44DDD8A19C85CFB0047280E /* dump_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_context.h; path = ../../../google_breakpad/processor/dump_context.h; sourceTree = "<group>"; }; - F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = "<group>"; }; - F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = "<group>"; }; - F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = "<group>"; }; - F47180541D745DEF0032F208 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; }; - F47180551D745DEF0032F208 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; }; - F47180571D7467630032F208 /* proc_maps_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proc_maps_linux.cc; path = ../../../processor/proc_maps_linux.cc; sourceTree = "<group>"; }; - F47180591D7468A40032F208 /* symbolic_constants_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = symbolic_constants_win.cc; path = ../../../processor/symbolic_constants_win.cc; sourceTree = "<group>"; }; - F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = "<group>"; }; - F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = "<group>"; }; - F9C7ECE20E8ABCA600E953AD /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; - F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; - F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; }; - F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm.cc; path = ../../../processor/stackwalker_arm.cc; sourceTree = SOURCE_ROOT; }; - F9F0706610FBC02D0037B88B /* stackwalker_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm.h; path = ../../../processor/stackwalker_arm.h; sourceTree = SOURCE_ROOT; }; - FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_amd64.cc; path = ../../../processor/stackwalker_amd64.cc; sourceTree = SOURCE_ROOT; }; - FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_amd64.h; path = ../../../processor/stackwalker_amd64.h; sourceTree = SOURCE_ROOT; }; - FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_sparc.cc; path = ../../../processor/stackwalker_sparc.cc; sourceTree = SOURCE_ROOT; }; - FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stackwalker_sparc.h; path = ../../../processor/stackwalker_sparc.h; sourceTree = SOURCE_ROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 08FB7794FE84155DC02AAC07 /* crash_report */ = { - isa = PBXGroup; - children = ( - 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */, - 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */, - 4247E63F2110D5A500482558 /* path_helper.cc */, - 4247E63E2110D5A500482558 /* path_helper.h */, - 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */, - 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */, - 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */, - F9C7ECE10E8ABC7F00E953AD /* DWARF */, - 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */, - 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */, - 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */, - 5578003F0BE1F28500EC23E0 /* macho_utilities.h */, - 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */, - 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */, - 9BDF192D0B1BC15D00F8391B /* dump_syms.h */, - 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */, - 08FB7796FE84155DC02AAC07 /* crash_report.mm */, - F44DDD8D19C85CFC0047280E /* process_result.h */, - 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */, - F44DDD8419C85CD50047280E /* dump_context.cc */, - F44DDD8A19C85CFB0047280E /* dump_context.h */, - F44DDD8519C85CD50047280E /* dump_object.cc */, - F44DDD8B19C85CFB0047280E /* dump_object.h */, - F4D43B2E1A38490700C290B2 /* microdump.cc */, - F4D43B301A38492000C290B2 /* microdump.h */, - F44DDD8619C85CD50047280E /* microdump_processor.cc */, - F44DDD8C19C85CFC0047280E /* microdump_processor.h */, - 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */, - 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */, - 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */, - 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */, - 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */, - 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */, - 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */, - 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */, - 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */, - 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */, - 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */, - 8B31FF8411F0C6FB00FCF3E4 /* language.cc */, - 8B31FF8511F0C6FB00FCF3E4 /* language.h */, - 4D72CA5613DFBA84006CABE3 /* md5.cc */, - 8B31FF8611F0C6FB00FCF3E4 /* module.cc */, - 8B31FF8711F0C6FB00FCF3E4 /* module.h */, - 08FB7795FE84155DC02AAC07 /* breakpad */, - 4D2C726E126F9CE200B43EAF /* libdisasm */, - 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, - 1AB674ADFE9D54B511CA2CBB /* Products */, - ); - name = crash_report; - sourceTree = "<group>"; - }; - 08FB7795FE84155DC02AAC07 /* breakpad */ = { - isa = PBXGroup; - children = ( - 9BE650AB0B52FE1A00611104 /* common */, - 9BDF17280B1B8B0200F8391B /* processor */, - 9BDF16F70B1B8ACD00F8391B /* google_breakpad */, - ); - name = breakpad; - 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 /* crash_report */, - ); - name = Products; - sourceTree = "<group>"; - }; - 4D2C726E126F9CE200B43EAF /* libdisasm */ = { - isa = PBXGroup; - children = ( - 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */, - 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */, - 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */, - 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */, - 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */, - 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */, - 4D2C725A126F9C8000B43EAF /* ia32_operand.c */, - 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */, - 4D2C7234126F9BC200B43EAF /* ia32_settings.c */, - 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */, - 4D2C7263126F9CBB00B43EAF /* x86_imm.c */, - 4D2C725C126F9C9200B43EAF /* x86_insn.c */, - 4D2C722C126F9B6E00B43EAF /* x86_misc.c */, - 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */, - ); - name = libdisasm; - sourceTree = "<group>"; - }; - 9BDF16F70B1B8ACD00F8391B /* google_breakpad */ = { - isa = PBXGroup; - children = ( - 9BDF16F80B1B8ACD00F8391B /* common */, - 9BDF16FB0B1B8ACD00F8391B /* processor */, - ); - name = google_breakpad; - path = ../../../google_breakpad; - sourceTree = SOURCE_ROOT; - }; - 9BDF16F80B1B8ACD00F8391B /* common */ = { - isa = PBXGroup; - children = ( - 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */, - 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */, - ); - path = common; - sourceTree = "<group>"; - }; - 9BDF16FB0B1B8ACD00F8391B /* processor */ = { - isa = PBXGroup; - children = ( - 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */, - 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */, - 9B35FEE20B2675F9008DE8C7 /* code_module.h */, - 9B35FEE30B2675F9008DE8C7 /* code_modules.h */, - 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */, - 9BDF16FE0B1B8ACD00F8391B /* minidump.h */, - 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */, - 9BDF17000B1B8ACD00F8391B /* process_state.h */, - 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */, - 9BDF17010B1B8ACD00F8391B /* stack_frame.h */, - 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */, - 9BDF17030B1B8ACD00F8391B /* stackwalker.h */, - 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */, - 9B44619D0B66C66B00BBB817 /* system_info.h */, - ); - path = processor; - sourceTree = "<group>"; - }; - 9BDF17280B1B8B0200F8391B /* processor */ = { - isa = PBXGroup; - children = ( - 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */, - F407DC40185773C10064622B /* exploitability_linux.cc */, - F407DC41185773C10064622B /* stack_frame_symbolizer.cc */, - F407DC42185773C10064622B /* stackwalker_arm64.cc */, - F407DC43185773C10064622B /* stackwalker_arm64.h */, - F407DC44185773C10064622B /* stackwalker_mips.cc */, - F407DC45185773C10064622B /* stackwalker_mips.h */, - F407DC46185773C10064622B /* stackwalker_ppc64.cc */, - F407DC47185773C10064622B /* stackwalker_ppc64.h */, - 4D2C721E126F9ADE00B43EAF /* exploitability.cc */, - 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */, - D2A5DD621188658B00081F03 /* tokenize.cc */, - D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */, - F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */, - F9F0706610FBC02D0037B88B /* stackwalker_arm.h */, - 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */, - 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */, - 9BDF1AFB0B1BEB6300F8391B /* address_map.h */, - 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */, - 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */, - 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */, - 9BDF172A0B1B8B2400F8391B /* call_stack.cc */, - 8B40BDBF0C0638E4009535AF /* logging.cc */, - 9BDF173F0B1B8B9A00F8391B /* minidump.cc */, - 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */, - 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */, - F47180571D7467630032F208 /* proc_maps_linux.cc */, - 9BDF175B0B1B8C1B00F8391B /* process_state.cc */, - 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */, - 9BDF1A7B0B1BE30100F8391B /* range_map.h */, - 9BDF17530B1B8BF900F8391B /* stackwalker.cc */, - 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */, - 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */, - FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */, - FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */, - FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */, - FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */, - F47180591D7468A40032F208 /* symbolic_constants_win.cc */, - ); - name = processor; - sourceTree = "<group>"; - }; - 9BE650AB0B52FE1A00611104 /* common */ = { - isa = PBXGroup; - children = ( - 9BE650AC0B52FE3000611104 /* file_id.cc */, - 9BE650AD0B52FE3000611104 /* file_id.h */, - 9BE650AE0B52FE3000611104 /* macho_id.cc */, - 9BE650AF0B52FE3000611104 /* macho_id.h */, - 9BE650B00B52FE3000611104 /* macho_walker.cc */, - 9BE650B10B52FE3000611104 /* macho_walker.h */, - ); - name = common; - sourceTree = "<group>"; - }; - F9C7ECE10E8ABC7F00E953AD /* DWARF */ = { - isa = PBXGroup; - children = ( - F9C7ECE20E8ABCA600E953AD /* bytereader.cc */, - F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */, - 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */, - 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */, - F47180541D745DEF0032F208 /* elf_reader.cc */, - F47180551D745DEF0032F208 /* elf_reader.h */, - F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */, - ); - name = DWARF; - sourceTree = "<group>"; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 8DD76F960486AA7600D96B5E /* crash_report */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */; - buildPhases = ( - 8DD76F990486AA7600D96B5E /* Sources */, - 8DD76F9B0486AA7600D96B5E /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = crash_report; - productInstallPath = "$(HOME)/bin"; - productName = crash_report; - productReference = 8DD76FA10486AA7600D96B5E /* crash_report */; - 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 "crash_report" */; - compatibilityVersion = "Xcode 3.1"; - developmentRegion = en; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 08FB7794FE84155DC02AAC07 /* crash_report */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 8DD76F960486AA7600D96B5E /* crash_report */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 8DD76F990486AA7600D96B5E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */, - 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */, - F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */, - 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */, - 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */, - 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */, - F44DDD8719C85CD50047280E /* dump_context.cc in Sources */, - 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */, - 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */, - 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */, - 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */, - F47180561D745DEF0032F208 /* elf_reader.cc in Sources */, - 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */, - 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */, - 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */, - 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */, - 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */, - 9BE650B20B52FE3000611104 /* file_id.cc in Sources */, - 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */, - 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */, - 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */, - 8B40BDC00C0638E4009535AF /* logging.cc in Sources */, - FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */, - FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */, - F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */, - F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */, - F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */, - F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */, - D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */, - D2A5DD631188658B00081F03 /* tokenize.cc in Sources */, - 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */, - F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */, - 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */, - F44DDD8819C85CD50047280E /* dump_object.cc in Sources */, - 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */, - 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */, - 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */, - 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */, - 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */, - 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */, - 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */, - F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */, - F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */, - 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */, - 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */, - 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */, - 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */, - F407DC48185773C10064622B /* exploitability_linux.cc in Sources */, - 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */, - 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */, - 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */, - 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */, - F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */, - 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */, - 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */, - 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */, - 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */, - 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */, - 4247E6402110D5A500482558 /* path_helper.cc in Sources */, - F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */, - 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */, - 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */, - F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */, - 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */, - 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */, - F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */, - 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */, - 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1DEB927508733DD40010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - HEADER_SEARCH_PATHS = ../../../../src; - PRODUCT_NAME = crash_report; - }; - name = Debug; - }; - 1DEB927608733DD40010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - HEADER_SEARCH_PATHS = ../../../../src; - PRODUCT_NAME = crash_report; - }; - name = Release; - }; - 1DEB927908733DD40010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - }; - name = Debug; - }; - 1DEB927A08733DD40010E9CD /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB927508733DD40010E9CD /* Debug */, - 1DEB927608733DD40010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB927908733DD40010E9CD /* Debug */, - 1DEB927A08733DD40010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; -} diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.h b/src/tools/mac/crash_report/on_demand_symbol_supplier.h deleted file mode 100644 index 3fbe108e..00000000 --- a/src/tools/mac/crash_report/on_demand_symbol_supplier.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// 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 Inc. 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. - -// on_demand_symbol_supplier.h: Provides a Symbol Supplier that will create -// a breakpad symbol file on demand. - -#ifndef TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ -#define TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ - -#include <map> -#include <string> -#include "google_breakpad/processor/symbol_supplier.h" - -namespace google_breakpad { - -using std::map; -using std::string; -class MinidumpModule; - -class OnDemandSymbolSupplier : public SymbolSupplier { - public: - // |search_dir| is the directory to search for alternative symbols with - // the same name as the module in the minidump - OnDemandSymbolSupplier(const string &search_dir, - const string &symbol_search_dir); - virtual ~OnDemandSymbolSupplier() {} - - // Returns the path to the symbol file for the given module. - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file); - - // Returns the path to the symbol file for the given module. - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data); - // Allocates data buffer on heap, and takes the ownership of - // the data buffer. - virtual SymbolResult GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size); - - // Delete the data buffer allocated for module in GetCStringSymbolData(). - virtual void FreeSymbolData(const CodeModule *module); - - protected: - // Search directory - string search_dir_; - string symbol_search_dir_; - - // When we create a symbol file for a module, save the name of the module - // and the path to that module's symbol file. - map<string, string> module_file_map_; - - // Map of allocated data buffers, keyed by module->code_file(). - map<string, char *> memory_buffers_; - - // Return the name for |module| This will be the value used as the key - // to the |module_file_map_|. - string GetNameForModule(const CodeModule *module); - - // Find the module on local system. If the module resides in a different - // location than the full path in the minidump, this will be the location - // used. - string GetLocalModulePath(const CodeModule *module); - - // Return the full path for |module|. - string GetModulePath(const CodeModule *module); - - // Return the path to the symbol file for |module|. If an empty string is - // returned, then |module| doesn't have a symbol file. - string GetModuleSymbolFile(const CodeModule *module); - - // Generate the breakpad symbol file for |module|. Return true if successful. - // File is generated in /tmp. - bool GenerateSymbolFile(const CodeModule *module, - const SystemInfo *system_info); -}; - -} // namespace google_breakpad - -#endif // TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/src/tools/mac/crash_report/on_demand_symbol_supplier.mm deleted file mode 100644 index 1955d266..00000000 --- a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// 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 Inc. 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. - -#import <Foundation/Foundation.h> -#include <sys/stat.h> -#include <map> -#include <string> -#include <iostream> -#include <fstream> -#include <utility> - -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "google_breakpad/processor/minidump.h" -#include "google_breakpad/processor/system_info.h" -#include "processor/pathname_stripper.h" - -#include "on_demand_symbol_supplier.h" -#include "common/mac/dump_syms.h" - -using std::map; -using std::string; - -using google_breakpad::OnDemandSymbolSupplier; -using google_breakpad::PathnameStripper; -using google_breakpad::SymbolSupplier; -using google_breakpad::SystemInfo; - -OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &search_dir, - const string &symbol_search_dir) - : search_dir_(search_dir) { - NSFileManager *mgr = [NSFileManager defaultManager]; - size_t length = symbol_search_dir.length(); - if (length) { - // Load all sym files in symbol_search_dir into our module_file_map - // A symbol file always starts with a line like this: - // MODULE mac x86 BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon - // or - // MODULE mac ppc BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon - const char *symbolSearchStr = symbol_search_dir.c_str(); - NSString *symbolSearchPath = - [mgr stringWithFileSystemRepresentation:symbolSearchStr - length:strlen(symbolSearchStr)]; - NSDirectoryEnumerator *dirEnum = [mgr enumeratorAtPath:symbolSearchPath]; - NSString *fileName; - NSCharacterSet *hexSet = - [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; - NSCharacterSet *newlineSet = - [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; - while ((fileName = [dirEnum nextObject])) { - // Check to see what type of file we have - NSDictionary *attrib = [dirEnum fileAttributes]; - NSString *fileType = [attrib objectForKey:NSFileType]; - if ([fileType isEqualToString:NSFileTypeDirectory]) { - // Skip subdirectories - [dirEnum skipDescendents]; - } else { - NSString *filePath = [symbolSearchPath stringByAppendingPathComponent:fileName]; - NSString *dataStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; - if (dataStr) { - // Check file to see if it is of appropriate type, and grab module - // name. - NSScanner *scanner = [NSScanner scannerWithString:dataStr]; - BOOL goodScan = [scanner scanString:@"MODULE mac " intoString:nil]; - if (goodScan) { - goodScan = ([scanner scanString:@"x86 " intoString:nil] || - [scanner scanString:@"x86_64 " intoString:nil] || - [scanner scanString:@"ppc " intoString:nil]); - if (goodScan) { - NSString *moduleID; - goodScan = [scanner scanCharactersFromSet:hexSet - intoString:&moduleID]; - if (goodScan) { - // Module IDs are always 33 chars long - goodScan = [moduleID length] == 33; - if (goodScan) { - NSString *moduleName; - goodScan = [scanner scanUpToCharactersFromSet:newlineSet - intoString:&moduleName]; - if (goodScan) { - goodScan = [moduleName length] > 0; - if (goodScan) { - const char *moduleNameStr = [moduleName UTF8String]; - const char *filePathStr = [filePath fileSystemRepresentation]; - // Map our file - module_file_map_[moduleNameStr] = filePathStr; - } - } - } - } - } - } - } - } - } - } -} - -SymbolSupplier::SymbolResult -OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file) { - string path(GetModuleSymbolFile(module)); - - if (path.empty()) { - if (!GenerateSymbolFile(module, system_info)) - return NOT_FOUND; - - path = GetModuleSymbolFile(module); - } - - if (path.empty()) - return NOT_FOUND; - - *symbol_file = path; - return FOUND; -} - -SymbolSupplier::SymbolResult -OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data) { - SymbolSupplier::SymbolResult s = GetSymbolFile(module, - system_info, - symbol_file); - - - if (s == FOUND) { - std::ifstream in(symbol_file->c_str()); - getline(in, *symbol_data, std::string::traits_type::to_char_type( - std::string::traits_type::eof())); - in.close(); - } - - return s; -} - -SymbolSupplier::SymbolResult -OnDemandSymbolSupplier::GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size) { - std::string symbol_data_string; - SymbolSupplier::SymbolResult result = GetSymbolFile(module, - system_info, - symbol_file, - &symbol_data_string); - if (result == FOUND) { - *symbol_data_size = symbol_data_string.size() + 1; - *symbol_data = new char[*symbol_data_size]; - if (*symbol_data == NULL) { - // Should return INTERRUPT on memory allocation failure. - return INTERRUPT; - } - memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); - (*symbol_data)[symbol_data_string.size()] = '\0'; - memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); - } - return result; -} - -void OnDemandSymbolSupplier::FreeSymbolData(const CodeModule *module) { - map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); - if (it != memory_buffers_.end()) { - delete [] it->second; - memory_buffers_.erase(it); - } -} - -string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) { - NSFileManager *mgr = [NSFileManager defaultManager]; - const char *moduleStr = module->code_file().c_str(); - NSString *modulePath = - [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)]; - const char *searchStr = search_dir_.c_str(); - NSString *searchDir = - [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)]; - - if ([mgr fileExistsAtPath:modulePath]) - return module->code_file(); - - // If the module is not found, try to start appending the components to the - // search string and stop if a file (not dir) is found or all components - // have been appended - NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"]; - size_t count = [pathComponents count]; - NSMutableString *path = [NSMutableString string]; - - for (size_t i = 0; i < count; ++i) { - [path setString:searchDir]; - - for (size_t j = 0; j < i + 1; ++j) { - size_t idx = count - 1 - i + j; - [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]]; - } - - BOOL isDir; - if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) { - return [path fileSystemRepresentation]; - } - } - - return ""; -} - -string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) { - return module->code_file(); -} - -string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) { - return PathnameStripper::File(module->code_file()); -} - -string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) { - string name(GetNameForModule(module)); - map<string, string>::iterator result = module_file_map_.find(name); - - return (result == module_file_map_.end()) ? "" : (*result).second; -} - -static float GetFileModificationTime(const char *path) { - float result = 0; - struct stat file_stat; - if (stat(path, &file_stat) == 0) - result = (float)file_stat.st_mtimespec.tv_sec + - (float)file_stat.st_mtimespec.tv_nsec / 1.0e9f; - - return result; -} - -bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module, - const SystemInfo *system_info) { - bool result = true; - string name = GetNameForModule(module); - string module_path = GetLocalModulePath(module); - NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym", - name.c_str(), system_info->cpu.c_str()]; - - if (module_path.empty()) - return false; - - // Check if there's already a symbol file cached. Ensure that the file is - // newer than the module. Otherwise, generate a new one. - BOOL generate_file = YES; - if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) { - // Check if the module file is newer than the saved symbols - float cache_time = - GetFileModificationTime([symbol_path fileSystemRepresentation]); - float module_time = - GetFileModificationTime(module_path.c_str()); - - if (cache_time > module_time) - generate_file = NO; - } - - if (generate_file) { - DumpSymbols dump(ALL_SYMBOL_DATA, false); - if (dump.Read(module_path)) { - // What Breakpad calls "x86" should be given to the system as "i386". - std::string architecture; - if (system_info->cpu.compare("x86") == 0) { - architecture = "i386"; - } else { - architecture = system_info->cpu; - } - - if (dump.SetArchitecture(architecture)) { - std::fstream file([symbol_path fileSystemRepresentation], - std::ios_base::out | std::ios_base::trunc); - dump.WriteSymbolFile(file); - } else { - printf("Architecture %s not available for %s\n", - system_info->cpu.c_str(), name.c_str()); - result = false; - } - } else { - printf("Unable to open %s\n", module_path.c_str()); - result = false; - } - } - - // Add the mapping - if (result) - module_file_map_[name] = [symbol_path fileSystemRepresentation]; - - return result; -} diff --git a/src/tools/mac/dump_syms/dump_syms_tool.cc b/src/tools/mac/dump_syms/dump_syms_tool.cc index 6f68457b..2e05cbf3 100644 --- a/src/tools/mac/dump_syms/dump_syms_tool.cc +++ b/src/tools/mac/dump_syms/dump_syms_tool.cc @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -37,6 +36,8 @@ #include <algorithm> #include <iostream> +#include <memory> +#include <utility> #include <vector> #include "common/mac/dump_syms.h" @@ -51,8 +52,14 @@ using std::vector; struct Options { Options() - : srcPath(), dsymPath(), arch(), header_only(false), - cfi(true), handle_inter_cu_refs(true) {} + : srcPath(), + dsymPath(), + arch(), + header_only(false), + cfi(true), + handle_inter_cu_refs(true), + handle_inlines(false), + enable_multiple(false) {} string srcPath; string dsymPath; @@ -60,6 +67,8 @@ struct Options { bool header_only; bool cfi; bool handle_inter_cu_refs; + bool handle_inlines; + bool enable_multiple; }; static bool StackFrameEntryComparator(const Module::StackFrameEntry* a, @@ -101,14 +110,47 @@ static void CopyCFIDataBetweenModules(Module* to_module, // 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(new Module::StackFrameEntry(*from_entry)); + to_module->AddStackFrameEntry( + std::make_unique<Module::StackFrameEntry>(*from_entry)); } } } -static bool Start(const Options &options) { - SymbolData symbol_data = options.cfi ? ALL_SYMBOL_DATA : NO_CFI; - DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs); +static bool SetArchitecture(DumpSymbols& dump_symbols, + const NXArchInfo* arch, + const std::string& filename) { + if (!dump_symbols.SetArchitecture(arch->cputype, arch->cpusubtype)) { + fprintf(stderr, "%s: no architecture '%s' is present in file.\n", + filename.c_str(), arch->name); + 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]; + const NXArchInfo* arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType(arch->cputype, + arch->cpusubtype); + if (arch_info) + fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description); + else + fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n", + 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); // 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 @@ -126,31 +168,9 @@ static bool Start(const Options &options) { if (!dump_symbols.Read(primary_file)) return false; - if (options.arch) { - if (!dump_symbols.SetArchitecture(options.arch->cputype, - options.arch->cpusubtype)) { - fprintf(stderr, "%s: no architecture '%s' is present in file.\n", - primary_file.c_str(), options.arch->name); - 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]; - const NXArchInfo *arch_info = - google_breakpad::BreakpadGetArchInfoFromCpuType( - arch->cputype, arch->cpusubtype); - if (arch_info) - fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description); - else - fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n", - arch->cputype, arch->cpusubtype); - } - return false; - } + if (options.arch && + !SetArchitecture(dump_symbols, options.arch, primary_file)) { + return false; } if (options.header_only) @@ -168,6 +188,10 @@ static bool Start(const Options &options) { 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; @@ -201,6 +225,10 @@ static void Usage(int argc, const char *argv[]) { "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-h: Usage\n"); fprintf(stderr, "\t-?: Usage\n"); } @@ -210,7 +238,7 @@ 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:chr?")) != -1) { + while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?h")) != -1) { switch (ch) { case 'i': options->header_only = true; @@ -235,6 +263,12 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { case 'r': options->handle_inter_cu_refs = false; break; + case 'd': + options->handle_inlines = true; + break; + case 'm': + options->enable_multiple = true; + break; case '?': case 'h': Usage(argc, argv); diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc index 6e784ca7..b724cc74 100644 --- a/src/tools/mac/dump_syms/macho_dump.cc +++ b/src/tools/mac/dump_syms/macho_dump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -60,7 +59,7 @@ namespace mach_o = google_breakpad::mach_o; string program_name; -int check_syscall(int result, const char *operation, const char *filename) { +int check_syscall(int result, const char* operation, const char* filename) { if (result < 0) { fprintf(stderr, "%s: %s '%s': %s\n", program_name.c_str(), operation, @@ -73,7 +72,7 @@ int check_syscall(int result, const char *operation, const char *filename) { class DumpSection: public mach_o::Reader::SectionHandler { public: DumpSection() : index_(0) { } - bool HandleSection(const mach_o::Section §ion) { + bool HandleSection(const mach_o::Section& section) { printf(" section %d '%s' in segment '%s'\n" " address: 0x%llx\n" " alignment: 1 << %d B\n" @@ -92,13 +91,13 @@ class DumpSection: public mach_o::Reader::SectionHandler { class DumpCommand: public mach_o::Reader::LoadCommandHandler { public: - DumpCommand(mach_o::Reader *reader) : reader_(reader), index_(0) { } + DumpCommand(mach_o::Reader* reader) : reader_(reader), index_(0) { } bool UnknownCommand(mach_o::LoadCommandType type, - const ByteBuffer &contents) { + const ByteBuffer& contents) { printf(" load command %d: %d", index_++, type); return true; } - bool SegmentCommand(const mach_o::Segment &segment) { + bool SegmentCommand(const mach_o::Segment& segment) { printf(" load command %d: %s-bit segment '%s'\n" " address: 0x%llx\n" " memory size: 0x%llx\n" @@ -115,24 +114,24 @@ class DumpCommand: public mach_o::Reader::LoadCommandHandler { return reader_->WalkSegmentSections(segment, &dump_section); } private: - mach_o::Reader *reader_; + mach_o::Reader* reader_; int index_; }; -void DumpFile(const char *filename) { +void DumpFile(const char* filename) { int fd = check_syscall(open(filename, O_RDONLY), "opening", filename); struct stat attributes; check_syscall(fstat(fd, &attributes), "getting file attributes for", filename); - void *mapping = mmap(NULL, attributes.st_size, PROT_READ, + void* mapping = mmap(NULL, attributes.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - check_syscall(mapping == (void *)-1 ? -1 : 0, + check_syscall(mapping == (void*)-1 ? -1 : 0, "mapping contents of", filename); mach_o::FatReader::Reporter fat_reporter(filename); mach_o::FatReader fat_reader(&fat_reporter); - if (!fat_reader.Read(reinterpret_cast<uint8_t *>(mapping), + if (!fat_reader.Read(reinterpret_cast<uint8_t*>(mapping), attributes.st_size)) { exit(1); } @@ -140,14 +139,14 @@ void DumpFile(const char *filename) { size_t object_files_size; const SuperFatArch* super_fat_object_files = fat_reader.object_files(&object_files_size); - struct fat_arch *object_files; + struct fat_arch* object_files; if (!super_fat_object_files->ConvertToFatArch(object_files)) { exit(1); } printf(" object file count: %ld\n", object_files_size); for (size_t i = 0; i < object_files_size; i++) { - const struct fat_arch &file = object_files[i]; - const NXArchInfo *fat_arch_info = + const struct fat_arch& file = object_files[i]; + const NXArchInfo* fat_arch_info = google_breakpad::BreakpadGetArchInfoFromCpuType( file.cputype, file.cpusubtype); printf("\n object file %ld:\n" @@ -162,7 +161,7 @@ void DumpFile(const char *filename) { name << filename; if (object_files_size > 1) name << ", object file #" << i; - ByteBuffer file_contents(reinterpret_cast<uint8_t *>(mapping) + ByteBuffer file_contents(reinterpret_cast<uint8_t*>(mapping) + file.offset, file.size); mach_o::Reader::Reporter reporter(name.str()); mach_o::Reader reader(&reporter); @@ -170,7 +169,7 @@ void DumpFile(const char *filename) { exit(1); } - const NXArchInfo *macho_arch_info = + const NXArchInfo* macho_arch_info = NXGetArchInfoFromCpuType(reader.cpu_type(), reader.cpu_subtype()); printf(" Mach-O header:\n" @@ -190,7 +189,7 @@ void DumpFile(const char *filename) { } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { program_name = google_breakpad::BaseName(argv[0]); if (argc == 1) { fprintf(stderr, "Usage: %s FILE ...\n" diff --git a/src/tools/mac/symupload/minidump_upload.m b/src/tools/mac/symupload/minidump_upload.m deleted file mode 100644 index 741ad765..00000000 --- a/src/tools/mac/symupload/minidump_upload.m +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// 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 Inc. 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.m: 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 - -#import <unistd.h> - -#import <Foundation/Foundation.h> - -#import "common/mac/HTTPMultipartUpload.h" - -typedef struct { - NSString *minidumpPath; - NSString *uploadURLStr; - NSString *product; - NSString *version; - BOOL success; -} Options; - -//============================================================================= -static void Start(Options *options) { - NSURL *url = [NSURL URLWithString:options->uploadURLStr]; - HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; - NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - - // Add parameters - [parameters setObject:options->product forKey:@"prod"]; - [parameters setObject:options->version forKey:@"ver"]; - [ul setParameters:parameters]; - - // Add file - [ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"]; - - // Send it - NSError *error = nil; - NSData *data = [ul send:&error]; - NSString *result = [[NSString alloc] initWithData:data - encoding:NSUTF8StringEncoding]; - - NSLog(@"Send: %@", error ? [error description] : @"No Error"); - NSLog(@"Response: %ld", (long)[[ul response] statusCode]); - NSLog(@"Result: %lu bytes\n%@", (unsigned long)[data length], result); - - [result release]; - [ul release]; - options->success = !error; -} - -//============================================================================= -static void -Usage(int argc, const char *argv[]) { - fprintf(stderr, "Submit minidump information.\n"); - fprintf(stderr, "Usage: %s -p <product> -v <version> <minidump> " - "<upload-URL>\n", argv[0]); - fprintf(stderr, "<minidump> should be a minidump.\n"); - fprintf(stderr, "<upload-URL> is the destination for the upload\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; - char ch; - - while ((ch = getopt(argc, (char * const *)argv, "p:v:h?")) != -1) { - switch (ch) { - case 'p': - options->product = [NSString stringWithUTF8String:optarg]; - break; - case 'v': - options->version = [NSString stringWithUTF8String:optarg]; - 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); - } - - options->minidumpPath = [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.success ? 0 : 1; -} diff --git a/src/tools/mac/symupload/symupload.m b/src/tools/mac/symupload/symupload.m deleted file mode 100644 index a7cce7b0..00000000 --- a/src/tools/mac/symupload/symupload.m +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// 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 Inc. 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.m: 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" - -typedef struct { - NSString *symbolsPath; - NSString *uploadURLStr; - BOOL success; -} 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 Start(Options *options) { - NSURL *url = [NSURL URLWithString:options->uploadURLStr]; - HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; - NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath); - NSMutableString *compactedID = - [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; - [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0 - range:NSMakeRange(0, [compactedID length])]; - - // Add parameters - [parameters setObject:compactedID forKey:@"debug_identifier"]; - - // MODULE <os> <cpu> <uuid> <module-name> - // 0 1 2 3 4 - [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"]; - [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"]; - [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"]; - [parameters setObject:[moduleParts objectAtIndex:4] 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->success = !error && status==200; -} - -//============================================================================= -static void -Usage(int argc, const char *argv[]) { - fprintf(stderr, "Submit symbol information.\n"); - fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]); - fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n"); - fprintf(stderr, "<upload-URL> is the destination for the upload\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; - char ch; - - while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) { - switch (ch) { - 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); - } - - 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.success ? 0 : 1; -} diff --git a/src/tools/mac/symupload/symupload.mm b/src/tools/mac/symupload/symupload.mm new file mode 100644 index 00000000..521b811f --- /dev/null +++ b/src/tools/mac/symupload/symupload.mm @@ -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; +} diff --git a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj index a6a78dc5..903c66f1 100644 --- a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj +++ b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj @@ -7,9 +7,38 @@ 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.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.m */; settings = {ATTRIBUTES = (); }; }; + 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 */; }; @@ -30,16 +59,78 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; }; + 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; }; - 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; }; - 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; }; + 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; path = minidump_upload.m; sourceTree = "<group>"; }; + 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 */ @@ -65,10 +156,23 @@ 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.m */, + 08FB7796FE84155DC02AAC07 /* symupload.mm */, 9BD836000B0544BA0055103E /* minidump_upload.m */, 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */, 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */, @@ -95,6 +199,63 @@ 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 */ @@ -137,9 +298,15 @@ /* 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 = ""; @@ -155,8 +322,37 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */, + 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; }; @@ -175,7 +371,13 @@ 1DEB927508733DD40010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../../..; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include, + ../../../third_party/musl/include/, + ); PRODUCT_NAME = symupload; }; name = Debug; @@ -183,7 +385,17 @@ 1DEB927608733DD40010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../../..; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + 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; diff --git a/src/tools/mac/tools_mac.gypi b/src/tools/mac/tools_mac.gypi deleted file mode 100644 index 7457573b..00000000 --- a/src/tools/mac/tools_mac.gypi +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright 2014 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'target_defaults': { - 'include_dirs': [ - '../..', - ], - }, - 'targets': [ - { - 'target_name': 'crash_report', - 'type': 'executable', - 'sources': [ - 'crash_report/crash_report.mm', - 'crash_report/on_demand_symbol_supplier.h', - 'crash_report/on_demand_symbol_supplier.mm', - ], - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - ], - }, - 'dependencies': [ - '../common/common.gyp:common', - '../processor/processor.gyp:processor', - ], - }, - { - 'target_name': 'dump_syms', - 'type': 'executable', - 'sources': [ - 'dump_syms/dump_syms_tool.cc', - ], - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - ], - }, - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'macho_dump', - 'type': 'executable', - 'sources': [ - 'dump_syms/macho_dump.cc', - ], - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'minidump_upload', - 'type': 'executable', - 'sources': [ - 'symupload/minidump_upload.m', - ], - 'include_dirs': [ - '../../common/mac', - ], - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - ], - }, - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'symupload', - 'type': 'executable', - 'sources': [ - 'symupload/symupload.m', - ], - 'include_dirs': [ - '../../common/mac', - ], - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - ], - }, - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - ], -} diff --git a/src/tools/mac/upload_system_symbols/arch_constants.h b/src/tools/mac/upload_system_symbols/arch_constants.h index e12e53e2..b6dbc89a 100644 --- a/src/tools/mac/upload_system_symbols/arch_constants.h +++ b/src/tools/mac/upload_system_symbols/arch_constants.h @@ -1,5 +1,4 @@ -/* Copyright 2014, Google Inc. -All rights reserved. +/* Copyright 2014 Google LLC Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer. 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 Inc. nor the names of its + * 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. diff --git a/src/tools/mac/upload_system_symbols/arch_reader.go b/src/tools/mac/upload_system_symbols/arch_reader.go index ed98fa60..03a76421 100644 --- a/src/tools/mac/upload_system_symbols/arch_reader.go +++ b/src/tools/mac/upload_system_symbols/arch_reader.go @@ -1,5 +1,4 @@ -/* Copyright 2014, Google Inc. -All rights reserved. +/* Copyright 2014 Google LLC Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer. 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 Inc. nor the names of its + * 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. diff --git a/src/tools/mac/upload_system_symbols/go.mod b/src/tools/mac/upload_system_symbols/go.mod new file mode 100644 index 00000000..ff21bba9 --- /dev/null +++ b/src/tools/mac/upload_system_symbols/go.mod @@ -0,0 +1,3 @@ +module upload_system_symbols + +go 1.17 diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/src/tools/mac/upload_system_symbols/upload_system_symbols.go index 05a7764a..ba067276 100644 --- a/src/tools/mac/upload_system_symbols/upload_system_symbols.go +++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.go @@ -1,5 +1,4 @@ -/* Copyright 2014, Google Inc. -All rights reserved. +/* Copyright 2014 Google LLC Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer. 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 Inc. nor the names of its + * 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. @@ -64,12 +63,12 @@ var ( 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/Components", "/System/Library/Frameworks", "/System/Library/PrivateFrameworks", "/usr/lib", @@ -79,13 +78,26 @@ var ( optionalPathsToScan = []string{ // Gone in 10.15. "/Library/QuickTime", + // Not present in dumped dyld_shared_caches + "/System/Library/Components", } - // uploadServers are the list of servers to which symbols should be uploaded. - uploadServers = []string{ + // 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{ @@ -102,6 +114,11 @@ 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 != "" { @@ -195,17 +212,29 @@ func (uq *UploadQueue) Done() { close(uq.queue) } -func (uq *UploadQueue) worker() { +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 := exec.Command(symUpload, symfile, server) + 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) diff --git a/src/tools/python/deps-to-manifest.py b/src/tools/python/deps-to-manifest.py index b4562854..2fcaf771 100755 --- a/src/tools/python/deps-to-manifest.py +++ b/src/tools/python/deps-to-manifest.py @@ -1,6 +1,5 @@ #!/usr/bin/python -# Copyright 2016 Google Inc. -# All rights reserved. +# Copyright 2016 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -12,7 +11,7 @@ # 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 Inc. nor the names of its +# * 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. # @@ -49,7 +48,7 @@ MANIFEST_HEAD = """<?xml version='1.0' encoding='UTF-8'?> <!-- AUTOGENERATED BY %(prog)s; DO NOT EDIT --> <manifest> - <default revision='refs/heads/master' + <default revision='refs/heads/main' remote='chromium' sync-c='true' sync-j='8' /> @@ -100,7 +99,7 @@ def ConvertDepsToManifest(deps, manifest): data = { 'path': 'src', 'name': 'breakpad/breakpad', - 'revision': 'refs/heads/master', + 'revision': 'refs/heads/main', 'remote': 'chromium', } new_contents += MANIFEST_PROJECT % data diff --git a/src/tools/python/filter_syms.py b/src/tools/python/filter_syms.py index abddf789..caf3693a 100644 --- a/src/tools/python/filter_syms.py +++ b/src/tools/python/filter_syms.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 Google Inc. -# All rights reserved. +# Copyright 2012 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -12,7 +11,7 @@ # 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 Inc. nor the names of its +# * 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. # diff --git a/src/tools/python/tests/filter_syms_unittest.py b/src/tools/python/tests/filter_syms_unittest.py index b111f349..1081fc73 100644 --- a/src/tools/python/tests/filter_syms_unittest.py +++ b/src/tools/python/tests/filter_syms_unittest.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 Google Inc. -# All rights reserved. +# Copyright 2012 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -12,7 +11,7 @@ # 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 Inc. nor the names of its +# * 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. # diff --git a/src/tools/solaris/dump_syms/Makefile b/src/tools/solaris/dump_syms/Makefile index ff77105c..c5f48240 100644 --- a/src/tools/solaris/dump_syms/Makefile +++ b/src/tools/solaris/dump_syms/Makefile @@ -1,5 +1,4 @@ -# Copyright (c) 2007, Google Inc. -# All rights reserved. +# Copyright 2007 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ # 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 Inc. nor the names of its +# * 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. # diff --git a/src/tools/solaris/dump_syms/dump_syms.cc b/src/tools/solaris/dump_syms/dump_syms.cc index 54cea57e..fc331c21 100644 --- a/src/tools/solaris/dump_syms/dump_syms.cc +++ b/src/tools/solaris/dump_syms/dump_syms.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -36,13 +35,13 @@ using namespace google_breakpad; -int main(int argc, char **argv) { +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]; + const char* binary = argv[1]; DumpSymbols dumper; if (!dumper.WriteSymbolFile(binary, fileno(stdout))) { diff --git a/src/tools/solaris/dump_syms/run_regtest.sh b/src/tools/solaris/dump_syms/run_regtest.sh index ffb34330..27710d9a 100644 --- a/src/tools/solaris/dump_syms/run_regtest.sh +++ b/src/tools/solaris/dump_syms/run_regtest.sh @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2007, Google Inc. -# All rights reserved. +# Copyright 2007 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 Inc. nor the names of its +# * 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. # diff --git a/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc b/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc index e617a23b..b4d191bd 100644 --- a/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc +++ b/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -41,7 +40,7 @@ class C { void f() { member_ = g(); } virtual int g() { return 2; } - static char* h(const C &that) { return 0; } + static char* h(const C& that) { return 0; } private: int member_; @@ -53,12 +52,12 @@ static int i() { } // namespace google_breakpad -int main(int argc, char **argv) { +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); + char* nothing = object.h(object); return 0; } diff --git a/src/tools/tools.gyp b/src/tools/tools.gyp deleted file mode 100644 index e6a4210f..00000000 --- a/src/tools/tools.gyp +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2014 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'conditions': [ - ['OS=="mac"', { - 'includes': ['mac/tools_mac.gypi'], - }], - ['OS=="linux"', { - 'includes': ['linux/tools_linux.gypi'], - }], - ], -} diff --git a/src/tools/windows/converter/ms_symbol_server_converter.cc b/src/tools/windows/converter/ms_symbol_server_converter.cc index 2b40faee..bfe46925 100644 --- a/src/tools/windows/converter/ms_symbol_server_converter.cc +++ b/src/tools/windows/converter/ms_symbol_server_converter.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -92,7 +91,7 @@ namespace google_breakpad { #endif // _MSC_VER >= 1400 bool GUIDOrSignatureIdentifier::InitializeFromString( - const string &identifier) { + const string& identifier) { type_ = TYPE_NONE; size_t length = identifier.length(); @@ -128,11 +127,15 @@ bool GUIDOrSignatureIdentifier::InitializeFromString( #undef SSCANF MSSymbolServerConverter::MSSymbolServerConverter( - const string &local_cache, const vector<string> &symbol_servers) + const string& local_cache, + const vector<string>& symbol_servers, + bool trace_symsrv) : symbol_path_(), fail_dns_(false), fail_timeout_(false), - fail_not_found_(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 @@ -184,7 +187,7 @@ class AutoSymSrv { } } - bool Initialize(HANDLE process, char *path, bool invade_process) { + bool Initialize(HANDLE process, char* path, bool invade_process) { process_ = process; // TODO(nbilling): Figure out why dbghelp.dll is being loaded from @@ -240,7 +243,7 @@ class AutoSymSrv { // are supported by calling Delete(). class AutoDeleter { public: - explicit AutoDeleter(const string &path) : path_(path) {} + explicit AutoDeleter(const string& path) : path_(path) {} ~AutoDeleter() { int error; @@ -270,10 +273,10 @@ class AutoDeleter { }; MSSymbolServerConverter::LocateResult -MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, - const string &debug_or_code_id, - const string &version, - string *file_name) { +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(); @@ -290,7 +293,7 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, HANDLE process = GetCurrentProcess(); // CloseHandle is not needed. AutoSymSrv symsrv; if (!symsrv.Initialize(process, - const_cast<char *>(symbol_path_.c_str()), + const_cast<char*>(symbol_path_.c_str()), false)) { fprintf(stderr, "LocateFile: SymInitialize: error %lu for %s %s %s\n", GetLastError(), @@ -326,8 +329,8 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, 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()), + 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, @@ -342,6 +345,10 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, 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, @@ -393,15 +400,15 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, MSSymbolServerConverter::LocateResult -MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo &missing, - string *pe_file) { +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) { +MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo& missing, + string* symbol_file) { return LocateFile(missing.debug_file, missing.debug_identifier, missing.version, symbol_file); } @@ -412,51 +419,58 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, ULONG action, ULONG64 data, ULONG64 context) { - MSSymbolServerConverter *self = - reinterpret_cast<MSSymbolServerConverter *>(context); + MSSymbolServerConverter* self = + reinterpret_cast<MSSymbolServerConverter*>(context); switch (action) { case CBA_EVENT: { - IMAGEHLP_CBA_EVENT *cba_event = - reinterpret_cast<IMAGEHLP_CBA_EVENT *>(data); + 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. + 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 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_ } - }; + // 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 < @@ -478,7 +492,7 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, // static BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback( - const char *filename, void *context) { + const char* filename, void* context) { // FALSE ends the search, indicating that the located symbol file is // satisfactory. return FALSE; @@ -486,12 +500,12 @@ BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback( MSSymbolServerConverter::LocateResult MSSymbolServerConverter::LocateAndConvertSymbolFile( - const MissingSymbolInfo &missing, + const MissingSymbolInfo& missing, bool keep_symbol_file, bool keep_pe_file, - string *converted_symbol_file, - string *symbol_file, - string *out_pe_file) { + string* converted_symbol_file, + string* symbol_file, + string* out_pe_file) { assert(converted_symbol_file); converted_symbol_file->clear(); if (symbol_file) { @@ -580,7 +594,7 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile( *converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym"; - FILE *converted_output = NULL; + 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")) @@ -634,10 +648,10 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile( MSSymbolServerConverter::LocateResult MSSymbolServerConverter::LocateAndConvertPEFile( - const MissingSymbolInfo &missing, + const MissingSymbolInfo& missing, bool keep_pe_file, - string *converted_symbol_file, - string *out_pe_file) { + string* converted_symbol_file, + string* out_pe_file) { assert(converted_symbol_file); converted_symbol_file->clear(); @@ -676,7 +690,7 @@ MSSymbolServerConverter::LocateAndConvertPEFile( *converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym"; - FILE *converted_output = NULL; + 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")) diff --git a/src/tools/windows/converter/ms_symbol_server_converter.gyp b/src/tools/windows/converter/ms_symbol_server_converter.gyp deleted file mode 100644 index 57ec7906..00000000 --- a/src/tools/windows/converter/ms_symbol_server_converter.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'ms_symbol_server_converter', - 'type': 'static_library', - 'msvs_guid': '1463C4CD-23FC-4DE9-BFDE-283338200157', - 'sources': [ - 'ms_symbol_server_converter.cc', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - ], - }, - ], -} diff --git a/src/tools/windows/converter/ms_symbol_server_converter.h b/src/tools/windows/converter/ms_symbol_server_converter.h index 401f7c34..ffdea7c0 100644 --- a/src/tools/windows/converter/ms_symbol_server_converter.h +++ b/src/tools/windows/converter/ms_symbol_server_converter.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -101,13 +100,13 @@ class GUIDOrSignatureIdentifier { // 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); + 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_; } + const void* guid_or_signature_pointer() const { return &guid_; } private: GUIDOrSignatureType type_; @@ -127,9 +126,10 @@ 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_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 @@ -141,23 +141,26 @@ class MSSymbolServerConverter { // 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. - MSSymbolServerConverter(const string &local_cache, - const vector<string> &symbol_servers); + // 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); + 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); + 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 @@ -170,12 +173,12 @@ class MSSymbolServerConverter { // 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, + LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo& missing, bool keep_symbol_file, bool keep_pe_file, - string *converted_symbol_file, - string *symbol_file, - string *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 @@ -188,10 +191,10 @@ class MSSymbolServerConverter { // 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); + 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 @@ -199,9 +202,9 @@ class MSSymbolServerConverter { // 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); + 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 @@ -215,8 +218,8 @@ class MSSymbolServerConverter { // 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); + static BOOL CALLBACK SymFindFileInPathCallback(const char* filename, + void* context); // The search path used by SymSrv, built based on the arguments to the // constructor. @@ -226,8 +229,12 @@ class MSSymbolServerConverter { // 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 diff --git a/src/tools/windows/converter_exe/converter.cc b/src/tools/windows/converter_exe/converter.cc index 5b70903a..75ec55b0 100644 --- a/src/tools/windows/converter_exe/converter.cc +++ b/src/tools/windows/converter_exe/converter.cc @@ -1,807 +1,904 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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")
-
-#include <cassert>
-#include <cstdio>
-#include <ctime>
-#include <map>
-#include <regex>
-#include <string>
-#include <vector>
-
-#include "tools/windows/converter_exe/escaping.h"
-#include "tools/windows/converter_exe/http_download.h"
-#include "tools/windows/converter_exe/tokenizer.h"
-#include "common/windows/http_upload.h"
-#include "common/windows/string_utils-inl.h"
-#include "tools/windows/converter/ms_symbol_server_converter.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/";
-
-// 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, ¤t_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 |missing_info|
-// 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 MissingSymbolInfo &missing_info,
- const string &converted_file) {
- map<wstring, wstring> parameters;
- if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) {
- // MissingSymbolInfoToParameters or a callee will have printed an error.
- return false;
- }
-
- wstring converted_file_w;
-
- if (!WindowsStringUtils::safe_mbstowcs(converted_file, &converted_file_w)) {
- FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
- converted_file.c_str());
- return false;
- }
- map<wstring, wstring> files;
- files[L"symbol_file"] = converted_file_w;
-
- FprintfFlush(stderr, "Uploading %s\n", converted_file.c_str());
- if (!HTTPUpload::SendMultipartPostRequest(
- upload_symbol_url, parameters,
- files, NULL, NULL, NULL)) {
- FprintfFlush(stderr, "UploadSymbolFile: HTTPUpload::SendRequest 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;
-}
-
-// 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, ¶meters)) {
- // MissingSymbolInfoToParameters or a callee will have printed an error.
- return false;
- }
-
- string content;
- if (!HTTPDownload::Download(fetch_symbol_failure_url,
- ¶meters,
- &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) {
- }
-
- ~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;
-
- // 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;
-
- 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;
- 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);
- located = converter.LocateAndConvertSymbolFile(missing_info,
- false, // keep_symbol_file
- false, // keep_pe_file
- &converted_file,
- NULL, // symbol_file
- NULL); // 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, missing_info,
- converted_file);
- remove(converted_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_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);
- located = external_converter.LocateAndConvertSymbolFile(
- missing_info,
- false, // keep_symbol_file
- false, // keep_pe_file
- &converted_file,
- NULL, // symbol_file
- NULL); // 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, missing_info,
- converted_file);
- remove(converted_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_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"] = L"WinSymConv";
- 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, ¶meters,
- &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"
- " -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"
- " 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;
-
- // All arguments are paired.
- if (argc % 2 != 1) {
- return usage(argv[0]);
- }
-
- string blacklist_regex_str;
- bool have_any_msss_servers = false;
- for (int argi = 1; argi < argc; argi += 2) {
- string option = argv[argi];
- string value = argv[argi + 1];
-
- 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 == "-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.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;
-}
+// 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") + +#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; +} diff --git a/src/tools/windows/converter_exe/converter.gyp b/src/tools/windows/converter_exe/converter.gyp deleted file mode 100644 index fe443d1b..00000000 --- a/src/tools/windows/converter_exe/converter.gyp +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'converter_exe', - 'type': 'executable', - 'sources': [ - 'converter.cc', - 'escaping.cc', - 'escaping.h', - 'http_client.h', - 'http_download.cc', - 'http_download.h', - 'tokenizer.cc', - 'tokenizer.h', - 'winhttp_client.cc', - 'winhttp_client.h', - 'wininet_client.cc', - 'wininet_client.h', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - '../converter/ms_symbol_server_converter.gyp:ms_symbol_server_converter', - ], - }, - ], -} diff --git a/src/tools/windows/converter_exe/escaping.cc b/src/tools/windows/converter_exe/escaping.cc index 74a7203a..de074298 100644 --- a/src/tools/windows/converter_exe/escaping.cc +++ b/src/tools/windows/converter_exe/escaping.cc @@ -1,757 +1,757 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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 "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
+// 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. + +#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 diff --git a/src/tools/windows/converter_exe/escaping.h b/src/tools/windows/converter_exe/escaping.h index c8aa90b7..bc36bf57 100644 --- a/src/tools/windows/converter_exe/escaping.h +++ b/src/tools/windows/converter_exe/escaping.h @@ -1,99 +1,99 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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_
+// 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_ diff --git a/src/tools/windows/converter_exe/http_client.h b/src/tools/windows/converter_exe/http_client.h index 3e7aa8a7..38ebf2e4 100644 --- a/src/tools/windows/converter_exe/http_client.h +++ b/src/tools/windows/converter_exe/http_client.h @@ -1,96 +1,96 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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_
+// 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_ diff --git a/src/tools/windows/converter_exe/http_download.cc b/src/tools/windows/converter_exe/http_download.cc index 5afc1ccc..75f674e0 100644 --- a/src/tools/windows/converter_exe/http_download.cc +++ b/src/tools/windows/converter_exe/http_download.cc @@ -1,326 +1,326 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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 <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
+// 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. + +#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 diff --git a/src/tools/windows/converter_exe/http_download.h b/src/tools/windows/converter_exe/http_download.h index 2d705d5e..f58a3d0f 100644 --- a/src/tools/windows/converter_exe/http_download.h +++ b/src/tools/windows/converter_exe/http_download.h @@ -1,62 +1,62 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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_
+// 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_ diff --git a/src/tools/windows/converter_exe/tokenizer.cc b/src/tools/windows/converter_exe/tokenizer.cc index 992694cd..6d627536 100644 --- a/src/tools/windows/converter_exe/tokenizer.cc +++ b/src/tools/windows/converter_exe/tokenizer.cc @@ -1,61 +1,61 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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 <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
+// 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. + +#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 diff --git a/src/tools/windows/converter_exe/tokenizer.h b/src/tools/windows/converter_exe/tokenizer.h index f4bbcfd0..d9829f60 100644 --- a/src/tools/windows/converter_exe/tokenizer.h +++ b/src/tools/windows/converter_exe/tokenizer.h @@ -1,51 +1,51 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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_
+// 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_ diff --git a/src/tools/windows/converter_exe/winhttp_client.cc b/src/tools/windows/converter_exe/winhttp_client.cc index 8a8ade3b..f8c1492d 100644 --- a/src/tools/windows/converter_exe/winhttp_client.cc +++ b/src/tools/windows/converter_exe/winhttp_client.cc @@ -1,307 +1,307 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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 "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
+// 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. + +#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 diff --git a/src/tools/windows/converter_exe/winhttp_client.h b/src/tools/windows/converter_exe/winhttp_client.h index 819d610f..4ccac7e0 100644 --- a/src/tools/windows/converter_exe/winhttp_client.h +++ b/src/tools/windows/converter_exe/winhttp_client.h @@ -1,40 +1,40 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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_
+// 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_ diff --git a/src/tools/windows/converter_exe/wininet_client.cc b/src/tools/windows/converter_exe/wininet_client.cc index 3e542db2..90cf114c 100644 --- a/src/tools/windows/converter_exe/wininet_client.cc +++ b/src/tools/windows/converter_exe/wininet_client.cc @@ -1,278 +1,278 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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 "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
+// 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. + +#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 diff --git a/src/tools/windows/converter_exe/wininet_client.h b/src/tools/windows/converter_exe/wininet_client.h index bd04b605..8b4c61b5 100644 --- a/src/tools/windows/converter_exe/wininet_client.h +++ b/src/tools/windows/converter_exe/wininet_client.h @@ -1,40 +1,40 @@ -// Copyright 2019 Google Inc. All rights reserved.
-//
-// 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 Inc. 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_
+// 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_ diff --git a/src/tools/windows/dump_syms/dump_syms.cc b/src/tools/windows/dump_syms/dump_syms.cc index 5b7d1777..26c226a2 100644 --- a/src/tools/windows/dump_syms/dump_syms.cc +++ b/src/tools/windows/dump_syms/dump_syms.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -33,35 +32,61 @@ #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 std::wstring; 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; - if (argc == 2) { - PDBSourceLineWriter pdb_writer; - if (!pdb_writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) { +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); - } else if (argc == 3 && wcscmp(argv[1], L"--pe") == 0) { - PESourceLineWriter pe_writer(argv[2]); - success = pe_writer.WriteSymbols(stdout); - } else { - fprintf(stderr, "Usage: %ws [--pe] <file.[pdb|exe|dll]>\n", argv[0]); - 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"); - return 1; } if (!success) { diff --git a/src/tools/windows/dump_syms/dump_syms.gyp b/src/tools/windows/dump_syms/dump_syms.gyp deleted file mode 100644 index b815574b..00000000 --- a/src/tools/windows/dump_syms/dump_syms.gyp +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2013 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'dump_syms', - 'type': 'executable', - 'sources': [ - 'dump_syms.cc', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - ], - }, - { - 'target_name': 'dump_syms_unittest', - 'type': 'executable', - 'sources': [ - 'dump_syms_unittest.cc', - ], - 'dependencies': [ - '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', - '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', - 'dump_syms', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'shell32.lib', - ], - }, - }, - }, - ], -} diff --git a/src/tools/windows/dump_syms/dump_syms_unittest.cc b/src/tools/windows/dump_syms/dump_syms_unittest.cc index 766e5c09..97dc5c9b 100644 --- a/src/tools/windows/dump_syms/dump_syms_unittest.cc +++ b/src/tools/windows/dump_syms/dump_syms_unittest.cc @@ -1,244 +1,244 @@ -// Copyright 2003 Google Inc. All rights reserved.
-//
-// 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 Inc. 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 <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_CASE_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_CASE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest,
- testing::ValuesIn(kPEOnlyRootNames));
-
-
-} // namespace dump_syms
-} // namespace windows
-} // namespace tools
+// 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. + +#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 diff --git a/src/tools/windows/dump_syms/run_regtest.sh b/src/tools/windows/dump_syms/run_regtest.sh index 1f20f64f..2401edd1 100755 --- a/src/tools/windows/dump_syms/run_regtest.sh +++ b/src/tools/windows/dump_syms/run_regtest.sh @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2006, Google Inc. -# All rights reserved. +# Copyright 2006 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 Inc. nor the names of its +# * 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. # diff --git a/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc b/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc index e8efbeb8..442676ba 100644 --- a/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc +++ b/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -48,7 +47,7 @@ class C { void f() { member_ = g(); } virtual int g() { return 2; } - static char* h(const C &that) { return 0; } + static char* h(const C& that) { return 0; } private: int member_; @@ -60,12 +59,12 @@ static int i() { } // namespace google_breakpad -int main(int argc, char **argv) { +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); + char* nothing = object.h(object); return 0; } diff --git a/src/tools/windows/symupload/symupload.cc b/src/tools/windows/symupload/symupload.cc index 7e302932..65123a28 100644 --- a/src/tools/windows/symupload/symupload.cc +++ b/src/tools/windows/symupload/symupload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 Inc. nor the names of its +// * 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. // @@ -56,24 +55,23 @@ #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 std::string; -using std::wstring; -using std::vector; -using std::map; using google_breakpad::HTTPUpload; -using google_breakpad::SymbolCollectorClient; -using google_breakpad::SymbolStatus; -using google_breakpad::UploadUrlResponse; -using google_breakpad::CompleteUploadResult; 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) { +static bool GetFileVersionString(const wchar_t* filename, wstring* version) { DWORD handle; DWORD version_size = GetFileVersionInfoSize(filename, &handle); if (version_size < sizeof(VS_FIXEDFILEINFO)) { @@ -85,7 +83,7 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) { return false; } - void *file_info_buffer = NULL; + void* file_info_buffer = NULL; unsigned int file_info_length; if (!VerQueryValue(&version_info[0], L"\\", &file_info_buffer, &file_info_length)) { @@ -95,7 +93,7 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) { // 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 = + 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", @@ -114,10 +112,11 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) { // 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) { - google_breakpad::PDBSourceLineWriter writer; +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. @@ -135,7 +134,7 @@ static bool DumpSymbolsToTempFile(const wchar_t *file, return false; } - FILE *temp_file = NULL; + 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 @@ -159,97 +158,12 @@ static bool DumpSymbolsToTempFile(const wchar_t *file, return writer.GetModuleInfo(pdb_info); } -static bool DoSymUploadV2( - const wchar_t* api_url, - const wchar_t* api_key, - const wstring& debug_file, - const wstring& debug_id, - const wstring& symbol_file, - bool force) { - wstring url(api_url); - wstring key(api_key); - - if (!force) { - SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( - url, - key, - debug_file, - debug_id); - if (symbolStatus == SymbolStatus::Found) { - wprintf(L"Symbol file already exists, upload aborted." - L" Use \"-f\" to overwrite.\n"); - return true; - } - else if (symbolStatus == SymbolStatus::Unknown) { - wprintf(L"Failed to get check for existing symbol.\n"); - return false; - } - } - - UploadUrlResponse uploadUrlResponse; - if (!SymbolCollectorClient::CreateUploadUrl( - url, - key, - &uploadUrlResponse)) { - wprintf(L"Failed to create upload URL.\n"); - return false; - } - - wstring signed_url = uploadUrlResponse.upload_url; - wstring upload_key = uploadUrlResponse.upload_key; - wstring response; - int response_code; - bool success = HTTPUpload::SendPutRequest( - signed_url, - symbol_file, - /* timeout = */ NULL, - &response, - &response_code); - if (!success) { - wprintf(L"Failed to send symbol file.\n"); - wprintf(L"Response code: %ld\n", response_code); - wprintf(L"Response:\n"); - wprintf(L"%s\n", response.c_str()); - return false; - } - else if (response_code == 0) { - wprintf(L"Failed to send symbol file: No response code\n"); - return false; - } - else if (response_code != 200) { - wprintf(L"Failed to send symbol file: Response code %ld\n", response_code); - wprintf(L"Response:\n"); - wprintf(L"%s\n", response.c_str()); - return false; - } - - CompleteUploadResult completeUploadResult = - SymbolCollectorClient::CompleteUpload( - url, - key, - upload_key, - debug_file, - debug_id); - if (completeUploadResult == CompleteUploadResult::Error) { - wprintf(L"Failed to complete upload.\n"); - return false; - } - else if (completeUploadResult == CompleteUploadResult::DuplicateData) { - wprintf(L"Uploaded file checksum matched existing file checksum," - L" no change necessary.\n"); - } - else { - wprintf(L"Successfully sent the symbol file.\n"); - } - - return true; -} - __declspec(noreturn) void printUsageAndExit() { wprintf(L"Usage:\n\n" - L" symupload [--timeout NN] [--product product_name] ^\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" @@ -270,9 +184,10 @@ __declspec(noreturn) void printUsageAndExit() { exit(0); } -int wmain(int argc, wchar_t *argv[]) { - const wchar_t *module; - const wchar_t *product = nullptr; +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; @@ -280,6 +195,11 @@ int wmain(int argc, wchar_t *argv[]) { 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; @@ -310,7 +230,7 @@ int wmain(int argc, wchar_t *argv[]) { wstring symbol_file; PDBModuleInfo pdb_info; - if (!DumpSymbolsToTempFile(module, &symbol_file, &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; } @@ -329,14 +249,12 @@ int wmain(int argc, wchar_t *argv[]) { if (argc >= currentarg + 2) { api_url = argv[currentarg++]; api_key = argv[currentarg++]; + wstring product_name = product ? wstring(product) : L""; - success = DoSymUploadV2( - api_url, - api_key, - pdb_info.debug_file, - pdb_info.debug_identifier, - symbol_file, - force); + 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(); } diff --git a/src/tools/windows/symupload/symupload.gyp b/src/tools/windows/symupload/symupload.gyp deleted file mode 100644 index 4567a4bd..00000000 --- a/src/tools/windows/symupload/symupload.gyp +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2013 Google Inc. All rights reserved. -# -# 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 Inc. 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'symupload', - 'type': 'executable', - 'sources': [ - 'symupload.cc', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'LargeAddressAware': '2', - }, - }, - }, - ], -} diff --git a/src/tools/windows/tools_windows.gyp b/src/tools/windows/tools_windows.gyp deleted file mode 100644 index 17b88b4a..00000000 --- a/src/tools/windows/tools_windows.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 Google Inc. All rights reserved. -# -# 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 Inc. 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. - - -{ - 'includes': [ - '../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'build_all', - 'type': 'none', - 'dependencies': [ - './converter/ms_symbol_server_converter.gyp:*', - './converter_exe/converter.gyp:*', - './dump_syms/dump_syms.gyp:*', - './symupload/symupload.gyp:*', - ], - }, - ], -} |