blob: 1a0cc19c4fc99c9e6d1987e2013c5bcb472cb116 [file] [log] [blame]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -04001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Upload all debug symbols required for crash reporting purposes.
6
7This script need only be used to upload release builds symbols or to debug
8crashes on non-release builds (in which case try to only upload the symbols
Mike Frysinger02e1e072013-11-10 22:11:34 -05009for those executables involved).
10"""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040011
Mike Frysingera4fa1e82014-01-15 01:45:56 -050012from __future__ import print_function
13
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040014import ctypes
Mike Frysinger02e92402013-11-22 16:22:02 -050015import functools
Mike Frysingera4fa1e82014-01-15 01:45:56 -050016import httplib
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040017import multiprocessing
18import os
Mike Frysinger094a2172013-08-14 12:54:35 -040019import poster
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040020import random
Mike Frysingerfd355652014-01-23 02:57:48 -050021import socket
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040022import textwrap
23import tempfile
24import time
Mike Frysinger094a2172013-08-14 12:54:35 -040025import urllib2
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040026
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040027from chromite.lib import commandline
28from chromite.lib import cros_build_lib
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040029from chromite.lib import parallel
David Jamesc93e6a4d2014-01-13 11:37:36 -080030from chromite.lib import retry_util
Mike Frysinger69cb41d2013-08-11 20:08:19 -040031from chromite.scripts import cros_generate_breakpad_symbols
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040032
33
34# URLs used for uploading symbols.
35OFFICIAL_UPLOAD_URL = 'http://clients2.google.com/cr/symbol'
36STAGING_UPLOAD_URL = 'http://clients2.google.com/cr/staging_symbol'
37
38
39# The crash server rejects files that are this big.
40CRASH_SERVER_FILE_LIMIT = 350 * 1024 * 1024
41# Give ourselves a little breathing room from what the server expects.
42DEFAULT_FILE_LIMIT = CRASH_SERVER_FILE_LIMIT - (10 * 1024 * 1024)
43
44
Mike Frysingercd78a082013-06-26 17:13:04 -040045# How long to wait (in seconds) for a single upload to complete. This has
46# to allow for symbols that are up to CRASH_SERVER_FILE_LIMIT in size.
47UPLOAD_TIMEOUT = 30 * 60
48
49
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040050# Sleep for 200ms in between uploads to avoid DoS'ing symbol server.
51DEFAULT_SLEEP_DELAY = 0.2
52
53
54# Number of seconds to wait before retrying an upload. The delay will double
55# for each subsequent retry of the same symbol file.
56INITIAL_RETRY_DELAY = 1
57
58# Allow up to 7 attempts to upload a symbol file (total delay may be
59# 1+2+4+8+16+32=63 seconds).
60MAX_RETRIES = 6
61
Mike Frysingereb753bf2013-11-22 16:05:35 -050062# Number of total errors, before uploads are no longer attempted.
63# This is used to avoid lots of errors causing unreasonable delays.
64# See the related, but independent, error values below.
65MAX_TOTAL_ERRORS_FOR_RETRY = 30
66
67# A watermark of transient errors which we allow recovery from. If we hit
68# errors infrequently, overall we're probably doing fine. For example, if
69# we have one failure every 100 passes, then we probably don't want to fail
70# right away. But if we hit a string of failures in a row, we want to abort.
71#
72# The watermark starts at 0 (and can never go below that). When this error
73# level is exceeded, we stop uploading. When a failure happens, we add the
74# fail adjustment, and when an upload succeeds, we add the pass adjustment.
75# We want to penalize failures more so that we ramp up when there is a string
76# of them, but then slowly back off as things start working.
77#
78# A quick example:
79# 0.0: Starting point.
80# 0.0: Upload works, so add -0.5, and then clamp to 0.
81# 1.0: Upload fails, so add 1.0.
82# 2.0: Upload fails, so add 1.0.
83# 1.5: Upload works, so add -0.5.
84# 1.0: Upload works, so add -0.5.
85ERROR_WATERMARK = 3.0
86ERROR_ADJUST_FAIL = 1.0
87ERROR_ADJUST_PASS = -0.5
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040088
89
90def SymUpload(sym_file, upload_url):
Mike Frysinger094a2172013-08-14 12:54:35 -040091 """Upload a symbol file to a HTTP server
92
93 The upload is a multipart/form-data POST with the following parameters:
94 code_file: the basename of the module, e.g. "app"
95 code_identifier: the module file's identifier
96 debug_file: the basename of the debugging file, e.g. "app"
97 debug_identifier: the debug file's identifier, usually consisting of
98 the guid and age embedded in the pdb, e.g.
99 "11111111BBBB3333DDDD555555555555F"
100 version: the file version of the module, e.g. "1.2.3.4"
101 product: HTTP-friendly product name
102 os: the operating system that the module was built for
103 cpu: the CPU that the module was built for
104 symbol_file: the contents of the breakpad-format symbol file
105
106 Args:
107 sym_file: The symbol file to upload
108 upload_url: The crash URL to POST the |sym_file| to
109 """
110 sym_header = cros_generate_breakpad_symbols.ReadSymsHeader(sym_file)
111
112 fields = (
113 ('code_file', sym_header.name),
114 ('debug_file', sym_header.name),
115 ('debug_identifier', sym_header.id.replace('-', '')),
116 # Should we set these fields? They aren't critical, but it might be nice?
117 # We'd have to figure out what file this symbol is coming from and what
118 # package provides it ...
119 #('version', None),
120 #('product', 'ChromeOS'),
121 ('os', sym_header.os),
122 ('cpu', sym_header.cpu),
123 poster.encode.MultipartParam.from_file('symbol_file', sym_file),
124 )
125
126 data, headers = poster.encode.multipart_encode(fields)
127 request = urllib2.Request(upload_url, data, headers)
128 request.add_header('User-agent', 'chromite.upload_symbols')
129 urllib2.urlopen(request, timeout=UPLOAD_TIMEOUT)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400130
131
132def TestingSymUpload(sym_file, upload_url):
133 """A stub version of SymUpload for --testing usage"""
134 cmd = ['sym_upload', sym_file, upload_url]
135 # Randomly fail 80% of the time (the retry logic makes this 80%/3 per file).
136 returncode = random.randint(1, 100) <= 80
137 cros_build_lib.Debug('would run (and return %i): %s', returncode,
Matt Tennant7feda352013-12-20 14:03:40 -0800138 cros_build_lib.CmdToStr(cmd))
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400139 if returncode:
140 output = 'Failed to send the symbol file.'
141 else:
142 output = 'Successfully sent the symbol file.'
143 result = cros_build_lib.CommandResult(cmd=cmd, error=None, output=output,
144 returncode=returncode)
145 if returncode:
Mike Frysingera4fa1e82014-01-15 01:45:56 -0500146 exceptions = (
Mike Frysingerfd355652014-01-23 02:57:48 -0500147 socket.error('[socket.error] forced test fail'),
Mike Frysingera4fa1e82014-01-15 01:45:56 -0500148 httplib.BadStatusLine('[BadStatusLine] forced test fail'),
149 urllib2.HTTPError(upload_url, 400, '[HTTPError] forced test fail',
150 {}, None),
151 urllib2.URLError('[URLError] forced test fail'),
152 )
153 raise random.choice(exceptions)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400154 else:
155 return result
156
157
Mike Frysingereb753bf2013-11-22 16:05:35 -0500158def ErrorLimitHit(num_errors, watermark_errors):
159 """See if our error limit has been hit
160
161 Args:
162 num_errors: A multiprocessing.Value of the raw number of failures.
163 watermark_errors: A multiprocessing.Value of the current rate of failures.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500164
Mike Frysingereb753bf2013-11-22 16:05:35 -0500165 Returns:
166 True if our error limits have been exceeded.
167 """
168 return ((num_errors is not None and
169 num_errors.value > MAX_TOTAL_ERRORS_FOR_RETRY) or
170 (watermark_errors is not None and
171 watermark_errors.value > ERROR_WATERMARK))
172
173
174def _UpdateCounter(counter, adj):
175 """Update |counter| by |adj|
176
177 Handle atomic updates of |counter|. Also make sure it does not
178 fall below 0.
179
180 Args:
181 counter: A multiprocessing.Value to update
182 adj: The value to add to |counter|
183 """
184 def _Update():
185 clamp = 0 if type(adj) is int else 0.0
186 counter.value = max(clamp, counter.value + adj)
187
188 if hasattr(counter, 'get_lock'):
189 with counter.get_lock():
190 _Update()
191 elif counter is not None:
192 _Update()
193
194
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400195def UploadSymbol(sym_file, upload_url, file_limit=DEFAULT_FILE_LIMIT,
Mike Frysinger02e92402013-11-22 16:22:02 -0500196 sleep=0, num_errors=None, watermark_errors=None,
197 failed_queue=None):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400198 """Upload |sym_file| to |upload_url|
199
200 Args:
201 sym_file: The full path to the breakpad symbol to upload
202 upload_url: The crash server to upload things to
203 file_limit: The max file size of a symbol file before we try to strip it
204 sleep: Number of seconds to sleep before running
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400205 num_errors: An object to update with the error count (needs a .value member)
Mike Frysingereb753bf2013-11-22 16:05:35 -0500206 watermark_errors: An object to track current error behavior (needs a .value)
Mike Frysinger02e92402013-11-22 16:22:02 -0500207 failed_queue: When a symbol fails, add it to this queue
Mike Frysinger1a736a82013-12-12 01:50:59 -0500208
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400209 Returns:
210 The number of errors that were encountered.
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400211 """
212 if num_errors is None:
213 num_errors = ctypes.c_int()
Mike Frysingereb753bf2013-11-22 16:05:35 -0500214 if ErrorLimitHit(num_errors, watermark_errors):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400215 # Abandon ship! It's on fire! NOoooooooooooOOOoooooo.
Mike Frysinger7f9be142014-01-15 02:16:42 -0500216 if failed_queue:
217 failed_queue.put(sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400218 return 0
219
220 upload_file = sym_file
221
222 if sleep:
223 # Keeps us from DoS-ing the symbol server.
224 time.sleep(sleep)
225
226 cros_build_lib.Debug('uploading %s' % sym_file)
227
228 # Ideally there'd be a tempfile.SpooledNamedTemporaryFile that we could use.
229 with tempfile.NamedTemporaryFile(prefix='upload_symbols',
230 bufsize=0) as temp_sym_file:
231 if file_limit:
232 # If the symbols size is too big, strip out the call frame info. The CFI
233 # is unnecessary for 32bit x86 targets where the frame pointer is used (as
234 # all of ours have) and it accounts for over half the size of the symbols
235 # uploaded.
236 file_size = os.path.getsize(sym_file)
237 if file_size > file_limit:
238 cros_build_lib.Warning('stripping CFI from %s due to size %s > %s',
239 sym_file, file_size, file_limit)
240 temp_sym_file.writelines([x for x in open(sym_file, 'rb').readlines()
241 if not x.startswith('STACK CFI')])
242 upload_file = temp_sym_file.name
243
244 # Hopefully the crash server will let it through. But it probably won't.
245 # Not sure what the best answer is in this case.
246 file_size = os.path.getsize(upload_file)
247 if file_size > CRASH_SERVER_FILE_LIMIT:
248 cros_build_lib.PrintBuildbotStepWarnings()
Mike Frysinger02e92402013-11-22 16:22:02 -0500249 cros_build_lib.Warning('upload file %s is awfully large, risking '
250 'rejection by the symbol server (%s > %s)',
251 sym_file, file_size, CRASH_SERVER_FILE_LIMIT)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400252
253 # Upload the symbol file.
Mike Frysingereb753bf2013-11-22 16:05:35 -0500254 success = False
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400255 try:
Mike Frysinger9adcfd22013-10-24 12:01:40 -0400256 cros_build_lib.TimedCommand(
David Jamesc93e6a4d2014-01-13 11:37:36 -0800257 retry_util.RetryException,
Mike Frysinger9adcfd22013-10-24 12:01:40 -0400258 (urllib2.HTTPError, urllib2.URLError), MAX_RETRIES, SymUpload,
259 upload_file, upload_url, sleep=INITIAL_RETRY_DELAY,
260 timed_log_msg='upload of %10i bytes took %%s: %s' %
261 (file_size, os.path.basename(sym_file)))
Mike Frysingereb753bf2013-11-22 16:05:35 -0500262 success = True
Mike Frysinger094a2172013-08-14 12:54:35 -0400263 except urllib2.HTTPError as e:
264 cros_build_lib.Warning('could not upload: %s: HTTP %s: %s',
265 os.path.basename(sym_file), e.code, e.reason)
Mike Frysingerfd355652014-01-23 02:57:48 -0500266 except (urllib2.URLError, httplib.HTTPException, socket.error) as e:
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400267 cros_build_lib.Warning('could not upload: %s: %s',
268 os.path.basename(sym_file), e)
Mike Frysingereb753bf2013-11-22 16:05:35 -0500269 finally:
270 if success:
271 _UpdateCounter(watermark_errors, ERROR_ADJUST_PASS)
272 else:
273 _UpdateCounter(num_errors, 1)
274 _UpdateCounter(watermark_errors, ERROR_ADJUST_FAIL)
Mike Frysinger02e92402013-11-22 16:22:02 -0500275 if failed_queue:
276 failed_queue.put(sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400277
278 return num_errors.value
279
280
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500281def SymbolFinder(paths):
282 """Locate symbol files in |paths|
283
284 Args:
285 paths: A list of input paths to walk. Files are returned w/out any checks.
286 Dirs are searched for files that end in ".sym".
Mike Frysinger1a736a82013-12-12 01:50:59 -0500287
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500288 Returns:
289 Yield every viable sym file.
290 """
291 for p in paths:
292 if os.path.isdir(p):
293 for root, _, files in os.walk(p):
294 for f in files:
295 if f.endswith('.sym'):
296 yield os.path.join(root, f)
297 else:
298 yield p
299
300
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400301def UploadSymbols(board=None, official=False, breakpad_dir=None,
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400302 file_limit=DEFAULT_FILE_LIMIT, sleep=DEFAULT_SLEEP_DELAY,
Mike Frysinger7f9be142014-01-15 02:16:42 -0500303 upload_count=None, sym_paths=None, failed_list=None,
304 root=None, retry=True):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400305 """Upload all the generated symbols for |board| to the crash server
306
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400307 You can use in a few ways:
308 * pass |board| to locate all of its symbols
309 * pass |breakpad_dir| to upload all the symbols in there
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500310 * pass |sym_paths| to upload specific symbols (or dirs of symbols)
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400311
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400312 Args:
313 board: The board whose symbols we wish to upload
314 official: Use the official symbol server rather than the staging one
315 breakpad_dir: The full path to the breakpad directory where symbols live
316 file_limit: The max file size of a symbol file before we try to strip it
317 sleep: How long to sleep in between uploads
318 upload_count: If set, only upload this many symbols (meant for testing)
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500319 sym_paths: Specific symbol files (or dirs of sym files) to upload,
320 otherwise search |breakpad_dir|
Mike Frysinger7f9be142014-01-15 02:16:42 -0500321 failed_list: Write the names of all sym files we did not upload; can be a
322 filename or file-like object.
Mike Frysinger118d2502013-08-19 03:36:56 -0400323 root: The tree to prefix to |breakpad_dir| (if |breakpad_dir| is not set)
Mike Frysinger02e92402013-11-22 16:22:02 -0500324 retry: Whether we should retry failures.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500325
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400326 Returns:
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400327 The number of errors that were encountered.
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400328 """
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400329 if official:
330 upload_url = OFFICIAL_UPLOAD_URL
331 else:
332 cros_build_lib.Warning('unofficial builds upload to the staging server')
333 upload_url = STAGING_UPLOAD_URL
334
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500335 if sym_paths:
336 cros_build_lib.Info('uploading specified symbols to %s', upload_url)
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400337 else:
338 if breakpad_dir is None:
Mike Frysinger118d2502013-08-19 03:36:56 -0400339 breakpad_dir = os.path.join(
340 root,
341 cros_generate_breakpad_symbols.FindBreakpadDir(board).lstrip('/'))
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400342 cros_build_lib.Info('uploading all symbols to %s from %s', upload_url,
343 breakpad_dir)
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500344 sym_paths = [breakpad_dir]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400345
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400346 bg_errors = multiprocessing.Value('i')
Mike Frysingereb753bf2013-11-22 16:05:35 -0500347 watermark_errors = multiprocessing.Value('f')
Mike Frysinger02e92402013-11-22 16:22:02 -0500348 failed_queue = multiprocessing.Queue()
349 uploader = functools.partial(
350 UploadSymbol, file_limit=file_limit, sleep=sleep, num_errors=bg_errors,
351 watermark_errors=watermark_errors, failed_queue=failed_queue)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400352
Mike Frysinger02e92402013-11-22 16:22:02 -0500353 # For the first run, we collect the symbols that failed. If the
354 # overall failure rate was low, we'll retry them on the second run.
355 for retry in (retry, False):
356 # We need to limit ourselves to one upload at a time to avoid the server
357 # kicking in DoS protection. See these bugs for more details:
358 # http://crbug.com/209442
359 # http://crbug.com/212496
360 with parallel.BackgroundTaskRunner(uploader, processes=1) as queue:
361 for sym_file in SymbolFinder(sym_paths):
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500362 if upload_count == 0:
363 break
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400364
Mike Frysinger02e92402013-11-22 16:22:02 -0500365 queue.put([sym_file, upload_url])
366
367 if upload_count is not None:
368 upload_count -= 1
369 if upload_count == 0:
370 break
371
372 # See if we need to retry, and if we haven't failed too many times already.
373 if not retry or ErrorLimitHit(bg_errors, watermark_errors):
374 break
375
376 sym_paths = []
377 while not failed_queue.empty():
378 sym_paths.append(failed_queue.get())
379 if sym_paths:
380 cros_build_lib.Warning('retrying %i symbols', len(sym_paths))
Mike Frysinger0d0f9172013-12-13 15:55:40 -0500381 if upload_count is not None:
382 upload_count += len(sym_paths)
Mike Frysinger02e92402013-11-22 16:22:02 -0500383 # Decrement the error count in case we recover in the second pass.
384 assert bg_errors.value >= len(sym_paths), 'more failed files than errors?'
385 bg_errors.value -= len(sym_paths)
386 else:
387 # No failed symbols, so just return now.
388 break
389
Mike Frysinger7f9be142014-01-15 02:16:42 -0500390 # If the user has requested it, save all the symbol files that we failed to
391 # upload to a listing file. This should help with recovery efforts later on.
392 if failed_list:
393 with cros_build_lib.Open(failed_list, 'wb+') as f:
394 while not failed_queue.empty():
395 path = failed_queue.get()
396 if breakpad_dir:
397 path = os.path.relpath(path, breakpad_dir)
398 f.write('%s\n' % path)
399
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500400 return bg_errors.value
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400401
402
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400403def main(argv):
404 parser = commandline.ArgumentParser(description=__doc__)
405
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500406 parser.add_argument('sym_paths', type='path', nargs='*', default=None)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400407 parser.add_argument('--board', default=None,
408 help='board to build packages for')
409 parser.add_argument('--breakpad_root', type='path', default=None,
410 help='root directory for breakpad symbols')
411 parser.add_argument('--official_build', action='store_true', default=False,
412 help='point to official symbol server')
413 parser.add_argument('--regenerate', action='store_true', default=False,
414 help='regenerate all symbols')
415 parser.add_argument('--upload-count', type=int, default=None,
416 help='only upload # number of symbols')
417 parser.add_argument('--strip_cfi', type=int,
418 default=CRASH_SERVER_FILE_LIMIT - (10 * 1024 * 1024),
419 help='strip CFI data for files above this size')
Mike Frysinger7f9be142014-01-15 02:16:42 -0500420 parser.add_argument('--failed-list', type='path',
421 help='where to save a list of failed symbols')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400422 parser.add_argument('--testing', action='store_true', default=False,
423 help='run in testing mode')
424 parser.add_argument('--yes', action='store_true', default=False,
425 help='answer yes to all prompts')
426
427 opts = parser.parse_args(argv)
Mike Frysinger90e49ca2014-01-14 14:42:07 -0500428 opts.Freeze()
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400429
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500430 if opts.sym_paths:
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400431 if opts.regenerate:
432 cros_build_lib.Die('--regenerate may not be used with specific files')
433 else:
434 if opts.board is None:
435 cros_build_lib.Die('--board is required')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400436
437 if opts.breakpad_root and opts.regenerate:
438 cros_build_lib.Die('--regenerate may not be used with --breakpad_root')
439
440 if opts.testing:
441 # TODO(build): Kill off --testing mode once unittests are up-to-snuff.
442 cros_build_lib.Info('running in testing mode')
443 # pylint: disable=W0601,W0603
444 global INITIAL_RETRY_DELAY, SymUpload, DEFAULT_SLEEP_DELAY
445 INITIAL_RETRY_DELAY = DEFAULT_SLEEP_DELAY = 0
446 SymUpload = TestingSymUpload
447
448 if not opts.yes:
Mike Frysingerc5de9602014-02-09 02:42:36 -0500449 prolog = '\n'.join(textwrap.wrap(textwrap.dedent("""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400450 Uploading symbols for an entire Chromium OS build is really only
451 necessary for release builds and in a few cases for developers
452 to debug problems. It will take considerable time to run. For
453 developer debugging purposes, consider instead passing specific
454 files to upload.
Mike Frysingerc5de9602014-02-09 02:42:36 -0500455 """), 80)).strip()
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400456 if not cros_build_lib.BooleanPrompt(
457 prompt='Are you sure you want to upload all build symbols',
Mike Frysingerc5de9602014-02-09 02:42:36 -0500458 default=False, prolog=prolog):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400459 cros_build_lib.Die('better safe than sorry')
460
461 ret = 0
462 if opts.regenerate:
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400463 ret += cros_generate_breakpad_symbols.GenerateBreakpadSymbols(
464 opts.board, breakpad_dir=opts.breakpad_root)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400465
466 ret += UploadSymbols(opts.board, official=opts.official_build,
467 breakpad_dir=opts.breakpad_root,
468 file_limit=opts.strip_cfi, sleep=DEFAULT_SLEEP_DELAY,
Mike Frysinger7f9be142014-01-15 02:16:42 -0500469 upload_count=opts.upload_count, sym_paths=opts.sym_paths,
470 failed_list=opts.failed_list)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400471 if ret:
472 cros_build_lib.Error('encountered %i problem(s)', ret)
473 # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently
474 # return 0 in case we are a multiple of the mask.
475 ret = 1
476
477 return ret
Mike Frysinger094a2172013-08-14 12:54:35 -0400478
479
480# We need this to run once per process. Do it at module import time as that
481# will let us avoid doing it inline at function call time (see SymUpload) as
482# that func might be called by the multiprocessing module which means we'll
483# do the opener logic multiple times overall. Plus, if you're importing this
484# module, it's a pretty good chance that you're going to need this.
485poster.streaminghttp.register_openers()