blob: c12fb0293df1293a57f9f996333d04a0f711859b [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2013 The ChromiumOS Authors
Mike Frysinger69cb41d2013-08-11 20:08:19 -04002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Generate minidump symbols for use by the Crash server.
6
7Note: This should be run inside the chroot.
8
9This produces files in the breakpad format required by minidump_stackwalk and
10the crash server to dump stack information.
11
12Basically it scans all the split .debug files in /build/$BOARD/usr/lib/debug/
13and converts them over using the `dump_syms` programs. Those plain text .sym
14files are then stored in /build/$BOARD/usr/lib/debug/breakpad/.
15
Mike Frysinger02e1e072013-11-10 22:11:34 -050016If you want to actually upload things, see upload_symbols.py.
17"""
Mike Frysinger69cb41d2013-08-11 20:08:19 -040018
19import collections
20import ctypes
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -080021import enum
Chris McDonaldb55b7032021-06-17 16:41:32 -060022import logging
Mike Frysinger69cb41d2013-08-11 20:08:19 -040023import multiprocessing
24import os
Mike Frysinger69cb41d2013-08-11 20:08:19 -040025
Chris McDonaldb55b7032021-06-17 16:41:32 -060026from chromite.cbuildbot import cbuildbot_alerts
Mike Frysinger06a51c82021-04-06 11:39:17 -040027from chromite.lib import build_target_lib
Mike Frysinger69cb41d2013-08-11 20:08:19 -040028from chromite.lib import commandline
29from chromite.lib import cros_build_lib
30from chromite.lib import osutils
31from chromite.lib import parallel
Mike Frysinger96ad3f22014-04-24 23:27:27 -040032from chromite.lib import signals
Alex Klein1809f572021-09-09 11:28:37 -060033from chromite.utils import file_util
Mike Frysinger69cb41d2013-08-11 20:08:19 -040034
Mike Frysinger807d8282022-04-28 22:45:17 -040035
Stephen Boydfc1c8032021-10-06 20:58:37 -070036# Elf files that don't exist but have a split .debug file installed.
37ALLOWED_DEBUG_ONLY_FILES = {
Alex Klein1699fab2022-09-08 08:46:06 -060038 "boot/vmlinux",
Stephen Boydfc1c8032021-10-06 20:58:37 -070039}
Mike Frysinger69cb41d2013-08-11 20:08:19 -040040
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -080041# Allowlist of elf files that we know we can't symbolize in the normal way, but
42# which we don't have an automatic way to detect.
43EXPECTED_POOR_SYMBOLIZATION_FILES = ALLOWED_DEBUG_ONLY_FILES | {
44 # Git binaries are downloaded as binary blobs already stripped.
45 "usr/bin/git",
46 "usr/bin/git-receive-pack",
47 "usr/bin/git-upload-archive",
48 "usr/bin/git-upload-pack",
49 # Prebuild Android binary
50 "build/rootfs/opt/google/vms/android/etc/bin/XkbToKcmConverter",
51 # Pulled from
52 # https://skia.googlesource.com/buildbot/+/refs/heads/main/gold-client/, no
53 # need to resymbolize.
54 "usr/bin/goldctl",
55 # This is complete for --board=eve
56 # TODO(b/241470012): Complete for other boards.
57}
58
Alex Klein1699fab2022-09-08 08:46:06 -060059SymbolHeader = collections.namedtuple(
60 "SymbolHeader",
61 (
62 "cpu",
63 "id",
64 "name",
65 "os",
66 ),
67)
Mike Frysinger69cb41d2013-08-11 20:08:19 -040068
69
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -080070class SymbolGenerationResult(enum.Enum):
71 """Result of running dump_syms
72
73 Return value of _DumpAllowingBasicFallback() and _DumpExpectingSymbols().
74 """
75
76 SUCCESS = 1
77 UNEXPECTED_FAILURE = 2
78 EXPECTED_FAILURE = 3
79
80
81def _ExpectGoodSymbols(elf_file, sysroot):
82 """Determines if we expect dump_syms to create good symbols
83
84 We know that certain types of files never generate good symbols. Distinguish
85 those from the majority of elf files which should generate good symbols.
86
87 Args:
88 elf_file: The complete path to the file which we will pass to dump_syms
89 sysroot: If not None, the root of the build directory ('/build/eve', for
90 instance)
91
92 Returns:
93 True if the elf file should generate good symbols, False if not.
94 """
95 # .ko files (kernel object files) never produce good symbols.
96 if elf_file.endswith(".ko"):
97 return False
98
99 # dump_syms doesn't understand Golang executables.
100 result = cros_build_lib.run(
101 ["/usr/bin/file", elf_file], print_cmd=False, stdout=True
102 )
103 if b"Go BuildID" in result.stdout:
104 return False
105
106 if sysroot is not None:
107 relative_path = os.path.relpath(elf_file, sysroot)
108 else:
Ian Barkley-Yeunge1785762023-03-08 18:32:18 -0800109 relative_path = os.path.relpath(elf_file, "/")
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800110
111 if relative_path in EXPECTED_POOR_SYMBOLIZATION_FILES:
112 return False
113
Ian Barkley-Yeunge1785762023-03-08 18:32:18 -0800114 # Binaries in /usr/local are not actually shipped to end-users, so we
115 # don't care if they get good symbols -- we should never get crash reports
116 # for them anyways.
117 if relative_path.startswith("usr/local"):
118 return False
119
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800120 return True
121
122
123def ReadSymsHeader(sym_file, name_for_errors):
Alex Klein1699fab2022-09-08 08:46:06 -0600124 """Parse the header of the symbol file
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400125
Alex Klein1699fab2022-09-08 08:46:06 -0600126 The first line of the syms file will read like:
127 MODULE Linux arm F4F6FA6CCBDEF455039C8DE869C8A2F40 blkid
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400128
Alex Klein1699fab2022-09-08 08:46:06 -0600129 https://code.google.com/p/google-breakpad/wiki/SymbolFiles
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400130
Alex Klein1699fab2022-09-08 08:46:06 -0600131 Args:
132 sym_file: The symbol file to parse
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800133 name_for_errors: A name for error strings. Can be the name of the elf file
134 that generated the symbol file, or the name of the symbol file if the
135 symbol file has already been moved to a meaningful location.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500136
Alex Klein1699fab2022-09-08 08:46:06 -0600137 Returns:
138 A SymbolHeader object
Mike Frysinger1a736a82013-12-12 01:50:59 -0500139
Alex Klein1699fab2022-09-08 08:46:06 -0600140 Raises:
141 ValueError if the first line of |sym_file| is invalid
142 """
143 with file_util.Open(sym_file, "rb") as f:
144 header = f.readline().decode("utf-8").split()
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400145
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800146 if len(header) != 5 or header[0] != "MODULE":
147 raise ValueError(
148 f"header of sym file from {name_for_errors} is invalid"
149 )
Mike Frysinger50cedd32014-02-09 23:03:18 -0500150
Alex Klein1699fab2022-09-08 08:46:06 -0600151 return SymbolHeader(
152 os=header[1], cpu=header[2], id=header[3], name=header[4]
153 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400154
155
Alex Klein1699fab2022-09-08 08:46:06 -0600156def GenerateBreakpadSymbol(
157 elf_file,
158 debug_file=None,
159 breakpad_dir=None,
160 strip_cfi=False,
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800161 sysroot=None,
Alex Klein1699fab2022-09-08 08:46:06 -0600162 num_errors=None,
163 dump_syms_cmd="dump_syms",
164):
165 """Generate the symbols for |elf_file| using |debug_file|
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400166
Alex Klein1699fab2022-09-08 08:46:06 -0600167 Args:
168 elf_file: The file to dump symbols for
169 debug_file: Split debug file to use for symbol information
170 breakpad_dir: The dir to store the output symbol file in
171 strip_cfi: Do not generate CFI data
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800172 sysroot: Path to the sysroot with the elf_file under it
Alex Klein1699fab2022-09-08 08:46:06 -0600173 num_errors: An object to update with the error count (needs a .value member)
174 dump_syms_cmd: Command to use for dumping symbols.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500175
Alex Klein1699fab2022-09-08 08:46:06 -0600176 Returns:
177 The name of symbol file written out on success, or the failure count.
178 """
179 assert breakpad_dir
180 if num_errors is None:
181 num_errors = ctypes.c_int()
182 debug_file_only = not os.path.exists(elf_file)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400183
Alex Klein1699fab2022-09-08 08:46:06 -0600184 cmd_base = [dump_syms_cmd, "-v"]
185 if strip_cfi:
186 cmd_base += ["-c"]
187 # Some files will not be readable by non-root (e.g. set*id /bin/su).
188 needs_sudo = not os.access(elf_file, os.R_OK)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400189
Alex Klein1699fab2022-09-08 08:46:06 -0600190 def _DumpIt(cmd_args):
191 if needs_sudo:
192 run_command = cros_build_lib.sudo_run
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400193 else:
Alex Klein1699fab2022-09-08 08:46:06 -0600194 run_command = cros_build_lib.run
195 return run_command(
196 cmd_base + cmd_args,
197 stderr=True,
198 stdout=temp.name,
199 check=False,
200 debug_level=logging.DEBUG,
201 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400202
Alex Klein1699fab2022-09-08 08:46:06 -0600203 def _CrashCheck(result, file_or_files, msg):
204 if result.returncode:
205 cbuildbot_alerts.PrintBuildbotStepWarnings()
206 if result.returncode < 0:
207 logging.warning(
208 "dump_syms %s crashed with %s; %s",
209 file_or_files,
210 signals.StrSignal(-result.returncode),
211 msg,
212 )
213 else:
214 logging.warning(
215 "dump_syms %s returned %d; %s",
216 file_or_files,
217 result.returncode,
218 msg,
219 )
220 logging.warning("output:\n%s", result.stderr.decode("utf-8"))
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400221
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800222 def _DumpAllowingBasicFallback():
223 """Dump symbols for a executable when we do NOT expect to get good symbols.
224
225 Returns:
226 A SymbolGenerationResult
227 """
Alex Klein1699fab2022-09-08 08:46:06 -0600228 if debug_file:
229 # Try to dump the symbols using the debug file like normal.
230 if debug_file_only:
231 cmd_args = [debug_file]
232 file_or_files = debug_file
233 else:
234 cmd_args = [elf_file, os.path.dirname(debug_file)]
235 file_or_files = [elf_file, debug_file]
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400236
Alex Klein1699fab2022-09-08 08:46:06 -0600237 result = _DumpIt(cmd_args)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400238
Alex Klein1699fab2022-09-08 08:46:06 -0600239 if result.returncode:
240 # Sometimes dump_syms can crash because there's too much info.
241 # Try dumping and stripping the extended stuff out. At least
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800242 # this way we'll get the extended symbols.
243 # https://crbug.com/266064
Alex Klein1699fab2022-09-08 08:46:06 -0600244 _CrashCheck(result, file_or_files, "retrying w/out CFI")
245 cmd_args = ["-c", "-r"] + cmd_args
246 result = _DumpIt(cmd_args)
247 _CrashCheck(result, file_or_files, "retrying w/out debug")
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700248
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800249 if not result.returncode:
250 return SymbolGenerationResult.SUCCESS
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700251
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800252 # If that didn't work (no debug, or dump_syms still failed), try
253 # dumping just the file itself directly.
254 result = _DumpIt([elf_file])
255 if result.returncode:
256 # A lot of files (like kernel files) contain no debug information,
257 # do not consider such occurrences as errors.
258 cbuildbot_alerts.PrintBuildbotStepWarnings()
259 if b"file contains no debugging information" in result.stderr:
260 logging.warning("dump_syms failed; giving up entirely.")
261 logging.warning("No symbols found for %s", elf_file)
262 return SymbolGenerationResult.EXPECTED_FAILURE
263 else:
264 _CrashCheck(result, elf_file, "counting as failure")
265 return SymbolGenerationResult.UNEXPECTED_FAILURE
266
267 return SymbolGenerationResult.SUCCESS
268
269 def _DumpExpectingSymbols():
270 """Dump symbols for a executable when we expect to get good symbols.
271
272 Returns:
273 A SymbolGenerationResult. We never expect failure, so the result
274 will always be SUCCESS or UNEXPECTED_FAILURE.
275 """
276 if not debug_file:
277 logging.warning("%s must have debug file", elf_file)
278 return SymbolGenerationResult.UNEXPECTED_FAILURE
279
280 cmd_args = [elf_file, os.path.dirname(debug_file)]
281 result = _DumpIt(cmd_args)
282 if result.returncode:
283 _CrashCheck(result, [elf_file, debug_file], "unexpected failure")
284 return SymbolGenerationResult.UNEXPECTED_FAILURE
285 return SymbolGenerationResult.SUCCESS
286
287 osutils.SafeMakedirs(breakpad_dir)
288 with cros_build_lib.UnbufferedNamedTemporaryFile(
289 dir=breakpad_dir, delete=False
290 ) as temp:
291 if _ExpectGoodSymbols(elf_file, sysroot):
292 result = _DumpExpectingSymbols()
293 # Until the EXPECTED_POOR_SYMBOLIZATION_FILES allowlist is
294 # completely set up for all boards, don't fail the build if
295 # _ExpectGoodSymbols is wrong.
296 # TODO(b/241470012): Remove the call to _DumpAllowingBasicFallback()
297 # and just error out if _DumpExpectingSymbols fails.
298 if result == SymbolGenerationResult.UNEXPECTED_FAILURE:
299 result = _DumpAllowingBasicFallback()
300 else:
301 result = _DumpAllowingBasicFallback()
302
303 if result == SymbolGenerationResult.UNEXPECTED_FAILURE:
304 num_errors.value += 1
305 os.unlink(temp.name)
306 return num_errors.value
307
308 if result == SymbolGenerationResult.EXPECTED_FAILURE:
309 os.unlink(temp.name)
310 return 0
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700311
Alex Klein1699fab2022-09-08 08:46:06 -0600312 # Move the dumped symbol file to the right place:
313 # /build/$BOARD/usr/lib/debug/breakpad/<module-name>/<id>/<module-name>.sym
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800314 header = ReadSymsHeader(temp, elf_file)
Alex Klein1699fab2022-09-08 08:46:06 -0600315 logging.info("Dumped %s as %s : %s", elf_file, header.name, header.id)
316 sym_file = os.path.join(
317 breakpad_dir, header.name, header.id, header.name + ".sym"
318 )
319 osutils.SafeMakedirs(os.path.dirname(sym_file))
320 os.rename(temp.name, sym_file)
321 os.chmod(sym_file, 0o644)
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700322
Alex Klein1699fab2022-09-08 08:46:06 -0600323 return sym_file
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400324
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700325
Alex Klein1699fab2022-09-08 08:46:06 -0600326def GenerateBreakpadSymbols(
327 board,
328 breakpad_dir=None,
329 strip_cfi=False,
330 generate_count=None,
331 sysroot=None,
332 num_processes=None,
333 clean_breakpad=False,
334 exclude_dirs=(),
335 file_list=None,
336):
337 """Generate symbols for this board.
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700338
Alex Klein1699fab2022-09-08 08:46:06 -0600339 If |file_list| is None, symbols are generated for all executables, otherwise
340 only for the files included in |file_list|.
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700341
Alex Klein1699fab2022-09-08 08:46:06 -0600342 TODO(build):
343 This should be merged with buildbot_commands.GenerateBreakpadSymbols()
344 once we rewrite cros_generate_breakpad_symbols in python.
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400345
Alex Klein1699fab2022-09-08 08:46:06 -0600346 Args:
347 board: The board whose symbols we wish to generate
348 breakpad_dir: The full path to the breakpad directory where symbols live
349 strip_cfi: Do not generate CFI data
350 generate_count: If set, only generate this many symbols (meant for testing)
351 sysroot: The root where to find the corresponding ELFs
352 num_processes: Number of jobs to run in parallel
353 clean_breakpad: Should we `rm -rf` the breakpad output dir first; note: we
354 do not do any locking, so do not run more than one in parallel when True
355 exclude_dirs: List of dirs (relative to |sysroot|) to not search
356 file_list: Only generate symbols for files in this list. Each file must be a
357 full path (including |sysroot| prefix).
358 TODO(build): Support paths w/o |sysroot|.
359
360 Returns:
361 The number of errors that were encountered.
362 """
363 if sysroot is None:
364 sysroot = build_target_lib.get_default_sysroot_path(board)
365 if breakpad_dir is None:
366 breakpad_dir = FindBreakpadDir(board, sysroot=sysroot)
367 if clean_breakpad:
368 logging.info("cleaning out %s first", breakpad_dir)
369 osutils.RmDir(breakpad_dir, ignore_missing=True, sudo=True)
370 # Make sure non-root can write out symbols as needed.
371 osutils.SafeMakedirs(breakpad_dir, sudo=True)
372 if not os.access(breakpad_dir, os.W_OK):
373 cros_build_lib.sudo_run(["chown", "-R", str(os.getuid()), breakpad_dir])
374 debug_dir = FindDebugDir(board, sysroot=sysroot)
375 exclude_paths = [os.path.join(debug_dir, x) for x in exclude_dirs]
376 if file_list is None:
377 file_list = []
378 file_filter = dict.fromkeys([os.path.normpath(x) for x in file_list], False)
379
380 logging.info("generating breakpad symbols using %s", debug_dir)
381
382 # Let's locate all the debug_files and elfs first along with the debug file
383 # sizes. This way we can start processing the largest files first in parallel
384 # with the small ones.
385 # If |file_list| was given, ignore all other files.
386 targets = []
387 for root, dirs, files in os.walk(debug_dir):
388 if root in exclude_paths:
389 logging.info("Skipping excluded dir %s", root)
390 del dirs[:]
391 continue
392
393 for debug_file in files:
394 debug_file = os.path.join(root, debug_file)
395 # Turn /build/$BOARD/usr/lib/debug/sbin/foo.debug into
396 # /build/$BOARD/sbin/foo.
397 elf_file = os.path.join(
398 sysroot, debug_file[len(debug_dir) + 1 : -6]
399 )
400
401 if file_filter:
402 if elf_file in file_filter:
403 file_filter[elf_file] = True
404 elif debug_file in file_filter:
405 file_filter[debug_file] = True
406 else:
407 continue
408
409 # Filter out files based on common issues with the debug file.
410 if not debug_file.endswith(".debug"):
411 continue
412
413 elif os.path.islink(debug_file):
414 # The build-id stuff is common enough to filter out by default.
415 if "/.build-id/" in debug_file:
416 msg = logging.debug
417 else:
418 msg = logging.warning
419 msg("Skipping symbolic link %s", debug_file)
420 continue
421
422 # Filter out files based on common issues with the elf file.
423 elf_path = os.path.relpath(elf_file, sysroot)
424 debug_only = elf_path in ALLOWED_DEBUG_ONLY_FILES
425 if not os.path.exists(elf_file) and not debug_only:
426 # Sometimes we filter out programs from /usr/bin but leave behind
427 # the .debug file.
428 logging.warning("Skipping missing %s", elf_file)
429 continue
430
431 targets.append((os.path.getsize(debug_file), elf_file, debug_file))
432
433 bg_errors = parallel.WrapMultiprocessing(multiprocessing.Value, "i")
434 if file_filter:
435 files_not_found = [x for x, found in file_filter.items() if not found]
436 bg_errors.value += len(files_not_found)
437 if files_not_found:
438 logging.error("Failed to find requested files: %s", files_not_found)
439
440 # Now start generating symbols for the discovered elfs.
441 with parallel.BackgroundTaskRunner(
442 GenerateBreakpadSymbol,
443 breakpad_dir=breakpad_dir,
444 strip_cfi=strip_cfi,
445 num_errors=bg_errors,
446 processes=num_processes,
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800447 sysroot=sysroot,
Alex Klein1699fab2022-09-08 08:46:06 -0600448 ) as queue:
449 for _, elf_file, debug_file in sorted(targets, reverse=True):
450 if generate_count == 0:
451 break
452
453 queue.put([elf_file, debug_file])
454 if generate_count is not None:
455 generate_count -= 1
456 if generate_count == 0:
457 break
458
459 return bg_errors.value
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400460
461
Mike Frysinger3f571af2016-08-31 23:56:53 -0400462def FindDebugDir(board, sysroot=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600463 """Given a |board|, return the path to the split debug dir for it"""
464 if sysroot is None:
465 sysroot = build_target_lib.get_default_sysroot_path(board)
466 return os.path.join(sysroot, "usr", "lib", "debug")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400467
468
Mike Frysinger3f571af2016-08-31 23:56:53 -0400469def FindBreakpadDir(board, sysroot=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600470 """Given a |board|, return the path to the breakpad dir for it"""
471 return os.path.join(FindDebugDir(board, sysroot=sysroot), "breakpad")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400472
473
474def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600475 parser = commandline.ArgumentParser(description=__doc__)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400476
Alex Klein1699fab2022-09-08 08:46:06 -0600477 parser.add_argument(
478 "--board", default=None, help="board to generate symbols for"
479 )
480 parser.add_argument(
481 "--breakpad_root",
482 type="path",
483 default=None,
484 help="root output directory for breakpad symbols",
485 )
486 parser.add_argument(
487 "--sysroot",
488 type="path",
489 default=None,
490 help="root input directory for files",
491 )
492 parser.add_argument(
493 "--exclude-dir",
494 type=str,
495 action="append",
496 default=[],
497 help="directory (relative to |board| root) to not search",
498 )
499 parser.add_argument(
500 "--generate-count",
501 type=int,
502 default=None,
503 help="only generate # number of symbols",
504 )
505 parser.add_argument(
506 "--noclean",
507 dest="clean",
508 action="store_false",
509 default=True,
510 help="do not clean out breakpad dir before running",
511 )
512 parser.add_argument(
513 "--jobs", type=int, default=None, help="limit number of parallel jobs"
514 )
515 parser.add_argument(
516 "--strip_cfi",
517 action="store_true",
518 default=False,
519 help="do not generate CFI data (pass -c to dump_syms)",
520 )
521 parser.add_argument(
522 "file_list",
523 nargs="*",
524 default=None,
525 help="generate symbols for only these files "
526 "(e.g. /build/$BOARD/usr/bin/foo)",
527 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400528
Alex Klein1699fab2022-09-08 08:46:06 -0600529 opts = parser.parse_args(argv)
530 opts.Freeze()
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400531
Alex Klein1699fab2022-09-08 08:46:06 -0600532 if opts.board is None and opts.sysroot is None:
533 cros_build_lib.Die("--board or --sysroot is required")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400534
Alex Klein1699fab2022-09-08 08:46:06 -0600535 ret = GenerateBreakpadSymbols(
536 opts.board,
537 breakpad_dir=opts.breakpad_root,
538 strip_cfi=opts.strip_cfi,
539 generate_count=opts.generate_count,
540 sysroot=opts.sysroot,
541 num_processes=opts.jobs,
542 clean_breakpad=opts.clean,
543 exclude_dirs=opts.exclude_dir,
544 file_list=opts.file_list,
545 )
546 if ret:
547 logging.error("encountered %i problem(s)", ret)
548 # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently
549 # return 0 in case we are a multiple of the mask.
550 ret = 1
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400551
Alex Klein1699fab2022-09-08 08:46:06 -0600552 return ret