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
52using google_breakpad::sym_upload::UploadProtocol;
53using google_breakpad::sym_upload::Options;
54
55static 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//=============================================================================
66static void
67Usage(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//=============================================================================
114static void
115SetupOptions(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//=============================================================================
209int 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