1 | // Copyright (c) 2006, Google Inc. |
2 | // All rights reserved. |
3 | // |
4 | // Redistribution and use in source and binary forms, with or without |
5 | // modification, are permitted provided that the following conditions are |
6 | // met: |
7 | // |
8 | // * Redistributions of source code must retain the above copyright |
9 | // notice, this list of conditions and the following disclaimer. |
10 | // * Redistributions in binary form must reproduce the above |
11 | // copyright notice, this list of conditions and the following disclaimer |
12 | // in the documentation and/or other materials provided with the |
13 | // distribution. |
14 | // * Neither the name of Google Inc. nor the names of its |
15 | // contributors may be used to endorse or promote products derived from |
16 | // this software without specific prior written permission. |
17 | // |
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | |
30 | // symupload.cc: Upload a symbol file to a HTTP server. The upload is sent as |
31 | // a multipart/form-data POST request with the following parameters: |
32 | // code_file: the basename of the module, e.g. "app" |
33 | // debug_file: the basename of the debugging file, e.g. "app" |
34 | // debug_identifier: the debug file's identifier, usually consisting of |
35 | // the guid and age embedded in the pdb, e.g. |
36 | // "11111111BBBB3333DDDD555555555555F" |
37 | // version: the file version of the module, e.g. "1.2.3.4" |
38 | // os: the operating system that the module was built for |
39 | // cpu: the CPU that the module was built for |
40 | // symbol_file: the contents of the breakpad-format symbol file |
41 | |
42 | #include <stdio.h> |
43 | #include <stdlib.h> |
44 | #include <string.h> |
45 | #include <unistd.h> |
46 | |
47 | #include <locale> |
48 | |
49 | #include "common/linux/symbol_upload.h" |
50 | #include "common/path_helper.h" |
51 | |
52 | using google_breakpad::sym_upload::UploadProtocol; |
53 | using google_breakpad::sym_upload::Options; |
54 | |
55 | static void StrToUpper(std::string* str) { |
56 | if (str == nullptr) { |
57 | fprintf(stderr, "nullptr passed to StrToUpper.\n" ); |
58 | exit(1); |
59 | } |
60 | for (size_t i = 0; i < str->length(); i++) { |
61 | (*str)[i] = std::toupper((*str)[i], std::locale::classic()); |
62 | } |
63 | } |
64 | |
65 | //============================================================================= |
66 | static void |
67 | Usage(int argc, const char *argv[]) { |
68 | fprintf(stderr, "Submit symbol information.\n" ); |
69 | fprintf(stderr, "Usage: %s [options...] <symbol-file> <upload-URL>\n" , |
70 | google_breakpad::BaseName(argv[0]).c_str()); |
71 | fprintf(stderr, "Options:\n" ); |
72 | fprintf(stderr, |
73 | "<symbol-file> should be created by using the dump_syms " |
74 | "tool.\n" ); |
75 | fprintf(stderr, "<upload-URL> is the destination for the upload\n" ); |
76 | fprintf(stderr, "-p:\t <protocol> One of ['sym-upload-v1'," |
77 | " 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n" ); |
78 | fprintf(stderr, "-v:\t Version information (e.g., 1.2.3.4)\n" ); |
79 | fprintf(stderr, "-x:\t <host[:port]> Use HTTP proxy on given port\n" ); |
80 | fprintf(stderr, "-u:\t <user[:password]> Set proxy user and password\n" ); |
81 | fprintf(stderr, "-h:\t Usage\n" ); |
82 | fprintf(stderr, "-?:\t Usage\n" ); |
83 | fprintf(stderr, "\n" ); |
84 | fprintf(stderr, "These options only work with 'sym-upload-v2' protocol:\n" ); |
85 | fprintf(stderr, "-k:\t <API-key> A secret used to authenticate with the" |
86 | " API.\n" ); |
87 | fprintf(stderr, "-f:\t Force symbol upload if already exists.\n" ); |
88 | fprintf(stderr, "-t:\t <symbol-type> Explicitly set symbol upload type (" |
89 | "default is 'breakpad').\n" |
90 | "\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', " |
91 | "'dsym', 'pdb'].\n" |
92 | "\t Note: When this flag is set to anything other than 'breakpad', then " |
93 | "the '-c' and '-i' flags must also be set.\n" ); |
94 | fprintf(stderr, "-c:\t <code-file> Explicitly set 'code_file' for symbol " |
95 | "upload (basename of executable).\n" ); |
96 | fprintf(stderr, "-i:\t <debug-id> Explicitly set 'debug_id' for symbol " |
97 | "upload (typically build ID of executable).\n" ); |
98 | fprintf(stderr, "\n" ); |
99 | fprintf(stderr, "Examples:\n" ); |
100 | fprintf(stderr, " With 'sym-upload-v1':\n" ); |
101 | fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n" , |
102 | argv[0]); |
103 | fprintf(stderr, " With 'sym-upload-v2':\n" ); |
104 | fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n" ); |
105 | fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! " |
106 | "path/to/symbol_file http://myuploadserver\n" , argv[0]); |
107 | fprintf(stderr, " [Explicitly set symbol type to 'elf']\n" ); |
108 | fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! -t elf " |
109 | "-c app -i 11111111BBBB3333DDDD555555555555F " |
110 | "path/to/symbol_file http://myuploadserver\n" , argv[0]); |
111 | } |
112 | |
113 | //============================================================================= |
114 | static void |
115 | SetupOptions(int argc, const char *argv[], Options *options) { |
116 | extern int optind, optopt; |
117 | int ch; |
118 | constexpr char flag_pattern[] = "u:v:x:p:k:t:c:i:hf?" ; |
119 | |
120 | while ((ch = getopt(argc, (char * const*)argv, flag_pattern)) != -1) { |
121 | switch (ch) { |
122 | case 'h': |
123 | case '?': |
124 | Usage(argc, argv); |
125 | // ch might be '?' because getopt found an error while parsing args (as |
126 | // opposed to finding "-?" as an arg), in which case optopt is set to |
127 | // the bad arg value, so return an error code if optopt is set, |
128 | // otherwise exit cleanly. |
129 | exit(optopt == 0 ? 0 : 1); |
130 | case 'u': |
131 | options->proxy_user_pwd = optarg; |
132 | break; |
133 | case 'v': |
134 | options->version = optarg; |
135 | break; |
136 | case 'x': |
137 | options->proxy = optarg; |
138 | break; |
139 | case 'p': |
140 | if (strcmp(optarg, "sym-upload-v2" ) == 0) { |
141 | options->upload_protocol = UploadProtocol::SYM_UPLOAD_V2; |
142 | } else if (strcmp(optarg, "sym-upload-v1" ) == 0) { |
143 | options->upload_protocol = UploadProtocol::SYM_UPLOAD_V1; |
144 | } else { |
145 | fprintf(stderr, "Invalid protocol '%s'\n" , optarg); |
146 | Usage(argc, argv); |
147 | exit(1); |
148 | } |
149 | break; |
150 | case 'k': |
151 | options->api_key = optarg; |
152 | break; |
153 | case 't': { |
154 | // This is really an enum, so treat as upper-case for consistency with |
155 | // enum naming convention on server-side. |
156 | options->type = optarg; |
157 | StrToUpper(&(options->type)); |
158 | break; |
159 | } |
160 | case 'c': |
161 | options->code_file = optarg; |
162 | break; |
163 | case 'i': |
164 | options->debug_id = optarg; |
165 | break; |
166 | case 'f': |
167 | options->force = true; |
168 | break; |
169 | |
170 | default: |
171 | fprintf(stderr, "Invalid option '%c'\n" , ch); |
172 | Usage(argc, argv); |
173 | exit(1); |
174 | } |
175 | } |
176 | |
177 | if ((argc - optind) != 2) { |
178 | fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n" , argv[0]); |
179 | Usage(argc, argv); |
180 | exit(1); |
181 | } |
182 | |
183 | bool is_breakpad_upload = options->type.empty() || |
184 | options->type == google_breakpad::sym_upload::kBreakpadSymbolType; |
185 | bool has_code_file = !options->code_file.empty(); |
186 | bool has_debug_id = !options->debug_id.empty(); |
187 | if (is_breakpad_upload && (has_code_file || has_debug_id)) { |
188 | fprintf(stderr, "\n" ); |
189 | fprintf(stderr, "%s: -c and -i should only be specified for non-breakpad " |
190 | "symbol upload types.\n" , argv[0]); |
191 | fprintf(stderr, "\n" ); |
192 | Usage(argc, argv); |
193 | exit(1); |
194 | } |
195 | if (!is_breakpad_upload && (!has_code_file || !has_debug_id)) { |
196 | fprintf(stderr, "\n" ); |
197 | fprintf(stderr, "%s: -c and -i must be specified for non-breakpad " |
198 | "symbol upload types.\n" , argv[0]); |
199 | fprintf(stderr, "\n" ); |
200 | Usage(argc, argv); |
201 | exit(1); |
202 | } |
203 | |
204 | options->symbolsPath = argv[optind]; |
205 | options->uploadURLStr = argv[optind + 1]; |
206 | } |
207 | |
208 | //============================================================================= |
209 | int main(int argc, const char* argv[]) { |
210 | Options options; |
211 | SetupOptions(argc, argv, &options); |
212 | google_breakpad::sym_upload::Start(&options); |
213 | return options.success ? 0 : 1; |
214 | } |
215 | |