1*9712c20fSFrederick Mayle // Copyright 2011 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle // * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle // * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle // * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle
29*9712c20fSFrederick Mayle // symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper
30*9712c20fSFrederick Mayle // function for linux symbol upload tool.
31*9712c20fSFrederick Mayle
32*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
33*9712c20fSFrederick Mayle #include <config.h> // Must come first
34*9712c20fSFrederick Mayle #endif
35*9712c20fSFrederick Mayle
36*9712c20fSFrederick Mayle #include "common/linux/symbol_upload.h"
37*9712c20fSFrederick Mayle
38*9712c20fSFrederick Mayle #include <assert.h>
39*9712c20fSFrederick Mayle #include <stdio.h>
40*9712c20fSFrederick Mayle
41*9712c20fSFrederick Mayle #include <functional>
42*9712c20fSFrederick Mayle #include <iostream>
43*9712c20fSFrederick Mayle #include <vector>
44*9712c20fSFrederick Mayle
45*9712c20fSFrederick Mayle #include "common/linux/http_upload.h"
46*9712c20fSFrederick Mayle #include "common/linux/libcurl_wrapper.h"
47*9712c20fSFrederick Mayle #include "common/linux/symbol_collector_client.h"
48*9712c20fSFrederick Mayle
49*9712c20fSFrederick Mayle namespace google_breakpad {
50*9712c20fSFrederick Mayle namespace sym_upload {
51*9712c20fSFrederick Mayle
TokenizeByChar(const string & source_string,int c,std::vector<string> * results)52*9712c20fSFrederick Mayle void TokenizeByChar(const string& source_string, int c,
53*9712c20fSFrederick Mayle std::vector<string>* results) {
54*9712c20fSFrederick Mayle assert(results);
55*9712c20fSFrederick Mayle string::size_type cur_pos = 0, next_pos = 0;
56*9712c20fSFrederick Mayle while ((next_pos = source_string.find(c, cur_pos)) != string::npos) {
57*9712c20fSFrederick Mayle if (next_pos != cur_pos)
58*9712c20fSFrederick Mayle results->push_back(source_string.substr(cur_pos, next_pos - cur_pos));
59*9712c20fSFrederick Mayle cur_pos = next_pos + 1;
60*9712c20fSFrederick Mayle }
61*9712c20fSFrederick Mayle if (cur_pos < source_string.size() && next_pos != cur_pos)
62*9712c20fSFrederick Mayle results->push_back(source_string.substr(cur_pos));
63*9712c20fSFrederick Mayle }
64*9712c20fSFrederick Mayle
65*9712c20fSFrederick Mayle //=============================================================================
66*9712c20fSFrederick Mayle // Parse out the module line which have 5 parts.
67*9712c20fSFrederick Mayle // MODULE <os> <cpu> <uuid> <module-name>
ModuleDataForSymbolFile(const string & file,std::vector<string> * module_parts)68*9712c20fSFrederick Mayle bool ModuleDataForSymbolFile(const string& file,
69*9712c20fSFrederick Mayle std::vector<string>* module_parts) {
70*9712c20fSFrederick Mayle assert(module_parts);
71*9712c20fSFrederick Mayle const size_t kModulePartNumber = 5;
72*9712c20fSFrederick Mayle FILE* fp = fopen(file.c_str(), "r");
73*9712c20fSFrederick Mayle if (fp) {
74*9712c20fSFrederick Mayle char buffer[1024];
75*9712c20fSFrederick Mayle if (fgets(buffer, sizeof(buffer), fp)) {
76*9712c20fSFrederick Mayle string line(buffer);
77*9712c20fSFrederick Mayle string::size_type line_break_pos = line.find_first_of('\n');
78*9712c20fSFrederick Mayle if (line_break_pos == string::npos) {
79*9712c20fSFrederick Mayle assert(0 && "The file is invalid!");
80*9712c20fSFrederick Mayle fclose(fp);
81*9712c20fSFrederick Mayle return false;
82*9712c20fSFrederick Mayle }
83*9712c20fSFrederick Mayle line.resize(line_break_pos);
84*9712c20fSFrederick Mayle const char kDelimiter = ' ';
85*9712c20fSFrederick Mayle TokenizeByChar(line, kDelimiter, module_parts);
86*9712c20fSFrederick Mayle if (module_parts->size() != kModulePartNumber)
87*9712c20fSFrederick Mayle module_parts->clear();
88*9712c20fSFrederick Mayle }
89*9712c20fSFrederick Mayle fclose(fp);
90*9712c20fSFrederick Mayle }
91*9712c20fSFrederick Mayle
92*9712c20fSFrederick Mayle return module_parts->size() == kModulePartNumber;
93*9712c20fSFrederick Mayle }
94*9712c20fSFrederick Mayle
95*9712c20fSFrederick Mayle //=============================================================================
CompactIdentifier(const string & uuid)96*9712c20fSFrederick Mayle string CompactIdentifier(const string& uuid) {
97*9712c20fSFrederick Mayle std::vector<string> components;
98*9712c20fSFrederick Mayle TokenizeByChar(uuid, '-', &components);
99*9712c20fSFrederick Mayle string result;
100*9712c20fSFrederick Mayle for (size_t i = 0; i < components.size(); ++i)
101*9712c20fSFrederick Mayle result += components[i];
102*9712c20fSFrederick Mayle return result;
103*9712c20fSFrederick Mayle }
104*9712c20fSFrederick Mayle
105*9712c20fSFrederick Mayle // |options| describes the current sym_upload options.
106*9712c20fSFrederick Mayle // |module_parts| contains the strings parsed from the MODULE entry of the
107*9712c20fSFrederick Mayle // Breakpad symbol file being uploaded.
108*9712c20fSFrederick Mayle // |compacted_id| is the debug_id from the MODULE entry of the Breakpad symbol
109*9712c20fSFrederick Mayle // file being uploaded, with all hyphens removed.
SymUploadV1Start(const Options & options,std::vector<string> module_parts,const string & compacted_id)110*9712c20fSFrederick Mayle bool SymUploadV1Start(
111*9712c20fSFrederick Mayle const Options& options,
112*9712c20fSFrederick Mayle std::vector<string> module_parts,
113*9712c20fSFrederick Mayle const string& compacted_id) {
114*9712c20fSFrederick Mayle std::map<string, string> parameters;
115*9712c20fSFrederick Mayle // Add parameters
116*9712c20fSFrederick Mayle if (!options.version.empty())
117*9712c20fSFrederick Mayle parameters["version"] = options.version;
118*9712c20fSFrederick Mayle
119*9712c20fSFrederick Mayle // MODULE <os> <cpu> <uuid> <module-name>
120*9712c20fSFrederick Mayle // 0 1 2 3 4
121*9712c20fSFrederick Mayle parameters["os"] = module_parts[1];
122*9712c20fSFrederick Mayle parameters["cpu"] = module_parts[2];
123*9712c20fSFrederick Mayle parameters["debug_file"] = module_parts[4];
124*9712c20fSFrederick Mayle parameters["code_file"] = module_parts[4];
125*9712c20fSFrederick Mayle parameters["debug_identifier"] = compacted_id;
126*9712c20fSFrederick Mayle
127*9712c20fSFrederick Mayle std::map<string, string> files;
128*9712c20fSFrederick Mayle files["symbol_file"] = options.symbolsPath;
129*9712c20fSFrederick Mayle
130*9712c20fSFrederick Mayle string response, error;
131*9712c20fSFrederick Mayle long response_code;
132*9712c20fSFrederick Mayle bool success = HTTPUpload::SendRequest(options.uploadURLStr,
133*9712c20fSFrederick Mayle parameters,
134*9712c20fSFrederick Mayle files,
135*9712c20fSFrederick Mayle options.proxy,
136*9712c20fSFrederick Mayle options.proxy_user_pwd,
137*9712c20fSFrederick Mayle /*ca_certificate_file=*/"",
138*9712c20fSFrederick Mayle &response,
139*9712c20fSFrederick Mayle &response_code,
140*9712c20fSFrederick Mayle &error);
141*9712c20fSFrederick Mayle
142*9712c20fSFrederick Mayle if (!success) {
143*9712c20fSFrederick Mayle printf("Failed to send symbol file: %s\n", error.c_str());
144*9712c20fSFrederick Mayle printf("Response code: %ld\n", response_code);
145*9712c20fSFrederick Mayle printf("Response:\n");
146*9712c20fSFrederick Mayle printf("%s\n", response.c_str());
147*9712c20fSFrederick Mayle } else if (response_code == 0) {
148*9712c20fSFrederick Mayle printf("Failed to send symbol file: No response code\n");
149*9712c20fSFrederick Mayle } else if (response_code != 200) {
150*9712c20fSFrederick Mayle printf("Failed to send symbol file: Response code %ld\n", response_code);
151*9712c20fSFrederick Mayle printf("Response:\n");
152*9712c20fSFrederick Mayle printf("%s\n", response.c_str());
153*9712c20fSFrederick Mayle } else {
154*9712c20fSFrederick Mayle printf("Successfully sent the symbol file.\n");
155*9712c20fSFrederick Mayle }
156*9712c20fSFrederick Mayle
157*9712c20fSFrederick Mayle return success;
158*9712c20fSFrederick Mayle }
159*9712c20fSFrederick Mayle
160*9712c20fSFrederick Mayle // |options| describes the current sym_upload options.
161*9712c20fSFrederick Mayle // |code_id| is the basename of the module for which symbols are being
162*9712c20fSFrederick Mayle // uploaded.
163*9712c20fSFrederick Mayle // |debug_id| is the debug_id of the module for which symbols are being
164*9712c20fSFrederick Mayle // uploaded.
SymUploadV2Start(const Options & options,const string & code_file,const string & debug_id,const string & type)165*9712c20fSFrederick Mayle bool SymUploadV2Start(
166*9712c20fSFrederick Mayle const Options& options,
167*9712c20fSFrederick Mayle const string& code_file,
168*9712c20fSFrederick Mayle const string& debug_id,
169*9712c20fSFrederick Mayle const string& type) {
170*9712c20fSFrederick Mayle google_breakpad::LibcurlWrapper libcurl_wrapper;
171*9712c20fSFrederick Mayle if (!libcurl_wrapper.Init()) {
172*9712c20fSFrederick Mayle printf("Failed to init google_breakpad::LibcurlWrapper.\n");
173*9712c20fSFrederick Mayle return false;
174*9712c20fSFrederick Mayle }
175*9712c20fSFrederick Mayle
176*9712c20fSFrederick Mayle if (!options.force) {
177*9712c20fSFrederick Mayle SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus(
178*9712c20fSFrederick Mayle &libcurl_wrapper,
179*9712c20fSFrederick Mayle options.uploadURLStr,
180*9712c20fSFrederick Mayle options.api_key,
181*9712c20fSFrederick Mayle code_file,
182*9712c20fSFrederick Mayle debug_id);
183*9712c20fSFrederick Mayle if (symbolStatus == SymbolStatus::Found) {
184*9712c20fSFrederick Mayle printf("Symbol file already exists, upload aborted."
185*9712c20fSFrederick Mayle " Use \"-f\" to overwrite.\n");
186*9712c20fSFrederick Mayle return true;
187*9712c20fSFrederick Mayle } else if (symbolStatus == SymbolStatus::Unknown) {
188*9712c20fSFrederick Mayle printf("Failed to check for existing symbol.\n");
189*9712c20fSFrederick Mayle return false;
190*9712c20fSFrederick Mayle }
191*9712c20fSFrederick Mayle }
192*9712c20fSFrederick Mayle
193*9712c20fSFrederick Mayle UploadUrlResponse uploadUrlResponse;
194*9712c20fSFrederick Mayle if (!SymbolCollectorClient::CreateUploadUrl(
195*9712c20fSFrederick Mayle &libcurl_wrapper,
196*9712c20fSFrederick Mayle options.uploadURLStr,
197*9712c20fSFrederick Mayle options.api_key,
198*9712c20fSFrederick Mayle &uploadUrlResponse)) {
199*9712c20fSFrederick Mayle printf("Failed to create upload URL.\n");
200*9712c20fSFrederick Mayle return false;
201*9712c20fSFrederick Mayle }
202*9712c20fSFrederick Mayle
203*9712c20fSFrederick Mayle string signed_url = uploadUrlResponse.upload_url;
204*9712c20fSFrederick Mayle string upload_key = uploadUrlResponse.upload_key;
205*9712c20fSFrederick Mayle string header;
206*9712c20fSFrederick Mayle string response;
207*9712c20fSFrederick Mayle long response_code;
208*9712c20fSFrederick Mayle
209*9712c20fSFrederick Mayle if (!libcurl_wrapper.SendPutRequest(signed_url,
210*9712c20fSFrederick Mayle options.symbolsPath,
211*9712c20fSFrederick Mayle &response_code,
212*9712c20fSFrederick Mayle &header,
213*9712c20fSFrederick Mayle &response)) {
214*9712c20fSFrederick Mayle printf("Failed to send symbol file.\n");
215*9712c20fSFrederick Mayle printf("Response code: %ld\n", response_code);
216*9712c20fSFrederick Mayle printf("Response:\n");
217*9712c20fSFrederick Mayle printf("%s\n", response.c_str());
218*9712c20fSFrederick Mayle return false;
219*9712c20fSFrederick Mayle } else if (response_code == 0) {
220*9712c20fSFrederick Mayle printf("Failed to send symbol file: No response code\n");
221*9712c20fSFrederick Mayle return false;
222*9712c20fSFrederick Mayle } else if (response_code != 200) {
223*9712c20fSFrederick Mayle printf("Failed to send symbol file: Response code %ld\n", response_code);
224*9712c20fSFrederick Mayle printf("Response:\n");
225*9712c20fSFrederick Mayle printf("%s\n", response.c_str());
226*9712c20fSFrederick Mayle return false;
227*9712c20fSFrederick Mayle }
228*9712c20fSFrederick Mayle
229*9712c20fSFrederick Mayle CompleteUploadResult completeUploadResult =
230*9712c20fSFrederick Mayle SymbolCollectorClient::CompleteUpload(&libcurl_wrapper,
231*9712c20fSFrederick Mayle options.uploadURLStr,
232*9712c20fSFrederick Mayle options.api_key,
233*9712c20fSFrederick Mayle upload_key,
234*9712c20fSFrederick Mayle code_file,
235*9712c20fSFrederick Mayle debug_id,
236*9712c20fSFrederick Mayle type);
237*9712c20fSFrederick Mayle if (completeUploadResult == CompleteUploadResult::Error) {
238*9712c20fSFrederick Mayle printf("Failed to complete upload.\n");
239*9712c20fSFrederick Mayle return false;
240*9712c20fSFrederick Mayle } else if (completeUploadResult == CompleteUploadResult::DuplicateData) {
241*9712c20fSFrederick Mayle printf("Uploaded file checksum matched existing file checksum,"
242*9712c20fSFrederick Mayle " no change necessary.\n");
243*9712c20fSFrederick Mayle } else {
244*9712c20fSFrederick Mayle printf("Successfully sent the symbol file.\n");
245*9712c20fSFrederick Mayle }
246*9712c20fSFrederick Mayle
247*9712c20fSFrederick Mayle return true;
248*9712c20fSFrederick Mayle }
249*9712c20fSFrederick Mayle
250*9712c20fSFrederick Mayle //=============================================================================
Start(Options * options)251*9712c20fSFrederick Mayle void Start(Options* options) {
252*9712c20fSFrederick Mayle if (options->upload_protocol == UploadProtocol::SYM_UPLOAD_V2) {
253*9712c20fSFrederick Mayle string code_file;
254*9712c20fSFrederick Mayle string debug_id;
255*9712c20fSFrederick Mayle string type;
256*9712c20fSFrederick Mayle
257*9712c20fSFrederick Mayle if (options->type.empty() || options->type == kBreakpadSymbolType) {
258*9712c20fSFrederick Mayle // Breakpad upload so read these from input file.
259*9712c20fSFrederick Mayle std::vector<string> module_parts;
260*9712c20fSFrederick Mayle if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) {
261*9712c20fSFrederick Mayle fprintf(stderr, "Failed to parse symbol file!\n");
262*9712c20fSFrederick Mayle return;
263*9712c20fSFrederick Mayle }
264*9712c20fSFrederick Mayle code_file = module_parts[4];
265*9712c20fSFrederick Mayle debug_id = CompactIdentifier(module_parts[3]);
266*9712c20fSFrederick Mayle type = kBreakpadSymbolType;
267*9712c20fSFrederick Mayle } else {
268*9712c20fSFrederick Mayle // Native upload so these must be explicitly set.
269*9712c20fSFrederick Mayle code_file = options->code_file;
270*9712c20fSFrederick Mayle debug_id = options->debug_id;
271*9712c20fSFrederick Mayle type = options->type;
272*9712c20fSFrederick Mayle }
273*9712c20fSFrederick Mayle
274*9712c20fSFrederick Mayle options->success = SymUploadV2Start(*options, code_file, debug_id, type);
275*9712c20fSFrederick Mayle } else {
276*9712c20fSFrederick Mayle std::vector<string> module_parts;
277*9712c20fSFrederick Mayle if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) {
278*9712c20fSFrederick Mayle fprintf(stderr, "Failed to parse symbol file!\n");
279*9712c20fSFrederick Mayle return;
280*9712c20fSFrederick Mayle }
281*9712c20fSFrederick Mayle const string compacted_id = CompactIdentifier(module_parts[3]);
282*9712c20fSFrederick Mayle options->success = SymUploadV1Start(*options, module_parts, compacted_id);
283*9712c20fSFrederick Mayle }
284*9712c20fSFrederick Mayle }
285*9712c20fSFrederick Mayle
286*9712c20fSFrederick Mayle } // namespace sym_upload
287*9712c20fSFrederick Mayle } // namespace google_breakpad
288