blob: 18b34a6c540b93eba1d15b5a7b8c6f9d34e8cd1f [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:
449 query = textwrap.wrap(textwrap.dedent("""
450 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.
455 """), 80)
456 cros_build_lib.Warning('\n%s', '\n'.join(query))
457 if not cros_build_lib.BooleanPrompt(
458 prompt='Are you sure you want to upload all build symbols',
459 default=False):
460 cros_build_lib.Die('better safe than sorry')
461
462 ret = 0
463 if opts.regenerate:
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400464 ret += cros_generate_breakpad_symbols.GenerateBreakpadSymbols(
465 opts.board, breakpad_dir=opts.breakpad_root)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400466
467 ret += UploadSymbols(opts.board, official=opts.official_build,
468 breakpad_dir=opts.breakpad_root,
469 file_limit=opts.strip_cfi, sleep=DEFAULT_SLEEP_DELAY,
Mike Frysinger7f9be142014-01-15 02:16:42 -0500470 upload_count=opts.upload_count, sym_paths=opts.sym_paths,
471 failed_list=opts.failed_list)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400472 if ret:
473 cros_build_lib.Error('encountered %i problem(s)', ret)
474 # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently
475 # return 0 in case we are a multiple of the mask.
476 ret = 1
477
478 return ret
Mike Frysinger094a2172013-08-14 12:54:35 -0400479
480
481# We need this to run once per process. Do it at module import time as that
482# will let us avoid doing it inline at function call time (see SymUpload) as
483# that func might be called by the multiprocessing module which means we'll
484# do the opener logic multiple times overall. Plus, if you're importing this
485# module, it's a pretty good chance that you're going to need this.
486poster.streaminghttp.register_openers()