blob: 816ed3cfd32d5415e548012972e0712a23279252 [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:
109 relative_path = elf_file
110
111 if relative_path in EXPECTED_POOR_SYMBOLIZATION_FILES:
112 return False
113
114 return True
115
116
117def ReadSymsHeader(sym_file, name_for_errors):
Alex Klein1699fab2022-09-08 08:46:06 -0600118 """Parse the header of the symbol file
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400119
Alex Klein1699fab2022-09-08 08:46:06 -0600120 The first line of the syms file will read like:
121 MODULE Linux arm F4F6FA6CCBDEF455039C8DE869C8A2F40 blkid
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400122
Alex Klein1699fab2022-09-08 08:46:06 -0600123 https://code.google.com/p/google-breakpad/wiki/SymbolFiles
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400124
Alex Klein1699fab2022-09-08 08:46:06 -0600125 Args:
126 sym_file: The symbol file to parse
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800127 name_for_errors: A name for error strings. Can be the name of the elf file
128 that generated the symbol file, or the name of the symbol file if the
129 symbol file has already been moved to a meaningful location.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500130
Alex Klein1699fab2022-09-08 08:46:06 -0600131 Returns:
132 A SymbolHeader object
Mike Frysinger1a736a82013-12-12 01:50:59 -0500133
Alex Klein1699fab2022-09-08 08:46:06 -0600134 Raises:
135 ValueError if the first line of |sym_file| is invalid
136 """
137 with file_util.Open(sym_file, "rb") as f:
138 header = f.readline().decode("utf-8").split()
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400139
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800140 if len(header) != 5 or header[0] != "MODULE":
141 raise ValueError(
142 f"header of sym file from {name_for_errors} is invalid"
143 )
Mike Frysinger50cedd32014-02-09 23:03:18 -0500144
Alex Klein1699fab2022-09-08 08:46:06 -0600145 return SymbolHeader(
146 os=header[1], cpu=header[2], id=header[3], name=header[4]
147 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400148
149
Alex Klein1699fab2022-09-08 08:46:06 -0600150def GenerateBreakpadSymbol(
151 elf_file,
152 debug_file=None,
153 breakpad_dir=None,
154 strip_cfi=False,
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800155 sysroot=None,
Alex Klein1699fab2022-09-08 08:46:06 -0600156 num_errors=None,
157 dump_syms_cmd="dump_syms",
158):
159 """Generate the symbols for |elf_file| using |debug_file|
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400160
Alex Klein1699fab2022-09-08 08:46:06 -0600161 Args:
162 elf_file: The file to dump symbols for
163 debug_file: Split debug file to use for symbol information
164 breakpad_dir: The dir to store the output symbol file in
165 strip_cfi: Do not generate CFI data
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800166 sysroot: Path to the sysroot with the elf_file under it
Alex Klein1699fab2022-09-08 08:46:06 -0600167 num_errors: An object to update with the error count (needs a .value member)
168 dump_syms_cmd: Command to use for dumping symbols.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500169
Alex Klein1699fab2022-09-08 08:46:06 -0600170 Returns:
171 The name of symbol file written out on success, or the failure count.
172 """
173 assert breakpad_dir
174 if num_errors is None:
175 num_errors = ctypes.c_int()
176 debug_file_only = not os.path.exists(elf_file)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400177
Alex Klein1699fab2022-09-08 08:46:06 -0600178 cmd_base = [dump_syms_cmd, "-v"]
179 if strip_cfi:
180 cmd_base += ["-c"]
181 # Some files will not be readable by non-root (e.g. set*id /bin/su).
182 needs_sudo = not os.access(elf_file, os.R_OK)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400183
Alex Klein1699fab2022-09-08 08:46:06 -0600184 def _DumpIt(cmd_args):
185 if needs_sudo:
186 run_command = cros_build_lib.sudo_run
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400187 else:
Alex Klein1699fab2022-09-08 08:46:06 -0600188 run_command = cros_build_lib.run
189 return run_command(
190 cmd_base + cmd_args,
191 stderr=True,
192 stdout=temp.name,
193 check=False,
194 debug_level=logging.DEBUG,
195 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400196
Alex Klein1699fab2022-09-08 08:46:06 -0600197 def _CrashCheck(result, file_or_files, msg):
198 if result.returncode:
199 cbuildbot_alerts.PrintBuildbotStepWarnings()
200 if result.returncode < 0:
201 logging.warning(
202 "dump_syms %s crashed with %s; %s",
203 file_or_files,
204 signals.StrSignal(-result.returncode),
205 msg,
206 )
207 else:
208 logging.warning(
209 "dump_syms %s returned %d; %s",
210 file_or_files,
211 result.returncode,
212 msg,
213 )
214 logging.warning("output:\n%s", result.stderr.decode("utf-8"))
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400215
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800216 def _DumpAllowingBasicFallback():
217 """Dump symbols for a executable when we do NOT expect to get good symbols.
218
219 Returns:
220 A SymbolGenerationResult
221 """
Alex Klein1699fab2022-09-08 08:46:06 -0600222 if debug_file:
223 # Try to dump the symbols using the debug file like normal.
224 if debug_file_only:
225 cmd_args = [debug_file]
226 file_or_files = debug_file
227 else:
228 cmd_args = [elf_file, os.path.dirname(debug_file)]
229 file_or_files = [elf_file, debug_file]
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400230
Alex Klein1699fab2022-09-08 08:46:06 -0600231 result = _DumpIt(cmd_args)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400232
Alex Klein1699fab2022-09-08 08:46:06 -0600233 if result.returncode:
234 # Sometimes dump_syms can crash because there's too much info.
235 # Try dumping and stripping the extended stuff out. At least
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800236 # this way we'll get the extended symbols.
237 # https://crbug.com/266064
Alex Klein1699fab2022-09-08 08:46:06 -0600238 _CrashCheck(result, file_or_files, "retrying w/out CFI")
239 cmd_args = ["-c", "-r"] + cmd_args
240 result = _DumpIt(cmd_args)
241 _CrashCheck(result, file_or_files, "retrying w/out debug")
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700242
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800243 if not result.returncode:
244 return SymbolGenerationResult.SUCCESS
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700245
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800246 # If that didn't work (no debug, or dump_syms still failed), try
247 # dumping just the file itself directly.
248 result = _DumpIt([elf_file])
249 if result.returncode:
250 # A lot of files (like kernel files) contain no debug information,
251 # do not consider such occurrences as errors.
252 cbuildbot_alerts.PrintBuildbotStepWarnings()
253 if b"file contains no debugging information" in result.stderr:
254 logging.warning("dump_syms failed; giving up entirely.")
255 logging.warning("No symbols found for %s", elf_file)
256 return SymbolGenerationResult.EXPECTED_FAILURE
257 else:
258 _CrashCheck(result, elf_file, "counting as failure")
259 return SymbolGenerationResult.UNEXPECTED_FAILURE
260
261 return SymbolGenerationResult.SUCCESS
262
263 def _DumpExpectingSymbols():
264 """Dump symbols for a executable when we expect to get good symbols.
265
266 Returns:
267 A SymbolGenerationResult. We never expect failure, so the result
268 will always be SUCCESS or UNEXPECTED_FAILURE.
269 """
270 if not debug_file:
271 logging.warning("%s must have debug file", elf_file)
272 return SymbolGenerationResult.UNEXPECTED_FAILURE
273
274 cmd_args = [elf_file, os.path.dirname(debug_file)]
275 result = _DumpIt(cmd_args)
276 if result.returncode:
277 _CrashCheck(result, [elf_file, debug_file], "unexpected failure")
278 return SymbolGenerationResult.UNEXPECTED_FAILURE
279 return SymbolGenerationResult.SUCCESS
280
281 osutils.SafeMakedirs(breakpad_dir)
282 with cros_build_lib.UnbufferedNamedTemporaryFile(
283 dir=breakpad_dir, delete=False
284 ) as temp:
285 if _ExpectGoodSymbols(elf_file, sysroot):
286 result = _DumpExpectingSymbols()
287 # Until the EXPECTED_POOR_SYMBOLIZATION_FILES allowlist is
288 # completely set up for all boards, don't fail the build if
289 # _ExpectGoodSymbols is wrong.
290 # TODO(b/241470012): Remove the call to _DumpAllowingBasicFallback()
291 # and just error out if _DumpExpectingSymbols fails.
292 if result == SymbolGenerationResult.UNEXPECTED_FAILURE:
293 result = _DumpAllowingBasicFallback()
294 else:
295 result = _DumpAllowingBasicFallback()
296
297 if result == SymbolGenerationResult.UNEXPECTED_FAILURE:
298 num_errors.value += 1
299 os.unlink(temp.name)
300 return num_errors.value
301
302 if result == SymbolGenerationResult.EXPECTED_FAILURE:
303 os.unlink(temp.name)
304 return 0
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700305
Alex Klein1699fab2022-09-08 08:46:06 -0600306 # Move the dumped symbol file to the right place:
307 # /build/$BOARD/usr/lib/debug/breakpad/<module-name>/<id>/<module-name>.sym
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800308 header = ReadSymsHeader(temp, elf_file)
Alex Klein1699fab2022-09-08 08:46:06 -0600309 logging.info("Dumped %s as %s : %s", elf_file, header.name, header.id)
310 sym_file = os.path.join(
311 breakpad_dir, header.name, header.id, header.name + ".sym"
312 )
313 osutils.SafeMakedirs(os.path.dirname(sym_file))
314 os.rename(temp.name, sym_file)
315 os.chmod(sym_file, 0o644)
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700316
Alex Klein1699fab2022-09-08 08:46:06 -0600317 return sym_file
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400318
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700319
Alex Klein1699fab2022-09-08 08:46:06 -0600320def GenerateBreakpadSymbols(
321 board,
322 breakpad_dir=None,
323 strip_cfi=False,
324 generate_count=None,
325 sysroot=None,
326 num_processes=None,
327 clean_breakpad=False,
328 exclude_dirs=(),
329 file_list=None,
330):
331 """Generate symbols for this board.
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700332
Alex Klein1699fab2022-09-08 08:46:06 -0600333 If |file_list| is None, symbols are generated for all executables, otherwise
334 only for the files included in |file_list|.
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700335
Alex Klein1699fab2022-09-08 08:46:06 -0600336 TODO(build):
337 This should be merged with buildbot_commands.GenerateBreakpadSymbols()
338 once we rewrite cros_generate_breakpad_symbols in python.
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400339
Alex Klein1699fab2022-09-08 08:46:06 -0600340 Args:
341 board: The board whose symbols we wish to generate
342 breakpad_dir: The full path to the breakpad directory where symbols live
343 strip_cfi: Do not generate CFI data
344 generate_count: If set, only generate this many symbols (meant for testing)
345 sysroot: The root where to find the corresponding ELFs
346 num_processes: Number of jobs to run in parallel
347 clean_breakpad: Should we `rm -rf` the breakpad output dir first; note: we
348 do not do any locking, so do not run more than one in parallel when True
349 exclude_dirs: List of dirs (relative to |sysroot|) to not search
350 file_list: Only generate symbols for files in this list. Each file must be a
351 full path (including |sysroot| prefix).
352 TODO(build): Support paths w/o |sysroot|.
353
354 Returns:
355 The number of errors that were encountered.
356 """
357 if sysroot is None:
358 sysroot = build_target_lib.get_default_sysroot_path(board)
359 if breakpad_dir is None:
360 breakpad_dir = FindBreakpadDir(board, sysroot=sysroot)
361 if clean_breakpad:
362 logging.info("cleaning out %s first", breakpad_dir)
363 osutils.RmDir(breakpad_dir, ignore_missing=True, sudo=True)
364 # Make sure non-root can write out symbols as needed.
365 osutils.SafeMakedirs(breakpad_dir, sudo=True)
366 if not os.access(breakpad_dir, os.W_OK):
367 cros_build_lib.sudo_run(["chown", "-R", str(os.getuid()), breakpad_dir])
368 debug_dir = FindDebugDir(board, sysroot=sysroot)
369 exclude_paths = [os.path.join(debug_dir, x) for x in exclude_dirs]
370 if file_list is None:
371 file_list = []
372 file_filter = dict.fromkeys([os.path.normpath(x) for x in file_list], False)
373
374 logging.info("generating breakpad symbols using %s", debug_dir)
375
376 # Let's locate all the debug_files and elfs first along with the debug file
377 # sizes. This way we can start processing the largest files first in parallel
378 # with the small ones.
379 # If |file_list| was given, ignore all other files.
380 targets = []
381 for root, dirs, files in os.walk(debug_dir):
382 if root in exclude_paths:
383 logging.info("Skipping excluded dir %s", root)
384 del dirs[:]
385 continue
386
387 for debug_file in files:
388 debug_file = os.path.join(root, debug_file)
389 # Turn /build/$BOARD/usr/lib/debug/sbin/foo.debug into
390 # /build/$BOARD/sbin/foo.
391 elf_file = os.path.join(
392 sysroot, debug_file[len(debug_dir) + 1 : -6]
393 )
394
395 if file_filter:
396 if elf_file in file_filter:
397 file_filter[elf_file] = True
398 elif debug_file in file_filter:
399 file_filter[debug_file] = True
400 else:
401 continue
402
403 # Filter out files based on common issues with the debug file.
404 if not debug_file.endswith(".debug"):
405 continue
406
407 elif os.path.islink(debug_file):
408 # The build-id stuff is common enough to filter out by default.
409 if "/.build-id/" in debug_file:
410 msg = logging.debug
411 else:
412 msg = logging.warning
413 msg("Skipping symbolic link %s", debug_file)
414 continue
415
416 # Filter out files based on common issues with the elf file.
417 elf_path = os.path.relpath(elf_file, sysroot)
418 debug_only = elf_path in ALLOWED_DEBUG_ONLY_FILES
419 if not os.path.exists(elf_file) and not debug_only:
420 # Sometimes we filter out programs from /usr/bin but leave behind
421 # the .debug file.
422 logging.warning("Skipping missing %s", elf_file)
423 continue
424
425 targets.append((os.path.getsize(debug_file), elf_file, debug_file))
426
427 bg_errors = parallel.WrapMultiprocessing(multiprocessing.Value, "i")
428 if file_filter:
429 files_not_found = [x for x, found in file_filter.items() if not found]
430 bg_errors.value += len(files_not_found)
431 if files_not_found:
432 logging.error("Failed to find requested files: %s", files_not_found)
433
434 # Now start generating symbols for the discovered elfs.
435 with parallel.BackgroundTaskRunner(
436 GenerateBreakpadSymbol,
437 breakpad_dir=breakpad_dir,
438 strip_cfi=strip_cfi,
439 num_errors=bg_errors,
440 processes=num_processes,
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800441 sysroot=sysroot,
Alex Klein1699fab2022-09-08 08:46:06 -0600442 ) as queue:
443 for _, elf_file, debug_file in sorted(targets, reverse=True):
444 if generate_count == 0:
445 break
446
447 queue.put([elf_file, debug_file])
448 if generate_count is not None:
449 generate_count -= 1
450 if generate_count == 0:
451 break
452
453 return bg_errors.value
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400454
455
Mike Frysinger3f571af2016-08-31 23:56:53 -0400456def FindDebugDir(board, sysroot=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600457 """Given a |board|, return the path to the split debug dir for it"""
458 if sysroot is None:
459 sysroot = build_target_lib.get_default_sysroot_path(board)
460 return os.path.join(sysroot, "usr", "lib", "debug")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400461
462
Mike Frysinger3f571af2016-08-31 23:56:53 -0400463def FindBreakpadDir(board, sysroot=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600464 """Given a |board|, return the path to the breakpad dir for it"""
465 return os.path.join(FindDebugDir(board, sysroot=sysroot), "breakpad")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400466
467
468def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600469 parser = commandline.ArgumentParser(description=__doc__)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400470
Alex Klein1699fab2022-09-08 08:46:06 -0600471 parser.add_argument(
472 "--board", default=None, help="board to generate symbols for"
473 )
474 parser.add_argument(
475 "--breakpad_root",
476 type="path",
477 default=None,
478 help="root output directory for breakpad symbols",
479 )
480 parser.add_argument(
481 "--sysroot",
482 type="path",
483 default=None,
484 help="root input directory for files",
485 )
486 parser.add_argument(
487 "--exclude-dir",
488 type=str,
489 action="append",
490 default=[],
491 help="directory (relative to |board| root) to not search",
492 )
493 parser.add_argument(
494 "--generate-count",
495 type=int,
496 default=None,
497 help="only generate # number of symbols",
498 )
499 parser.add_argument(
500 "--noclean",
501 dest="clean",
502 action="store_false",
503 default=True,
504 help="do not clean out breakpad dir before running",
505 )
506 parser.add_argument(
507 "--jobs", type=int, default=None, help="limit number of parallel jobs"
508 )
509 parser.add_argument(
510 "--strip_cfi",
511 action="store_true",
512 default=False,
513 help="do not generate CFI data (pass -c to dump_syms)",
514 )
515 parser.add_argument(
516 "file_list",
517 nargs="*",
518 default=None,
519 help="generate symbols for only these files "
520 "(e.g. /build/$BOARD/usr/bin/foo)",
521 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400522
Alex Klein1699fab2022-09-08 08:46:06 -0600523 opts = parser.parse_args(argv)
524 opts.Freeze()
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400525
Alex Klein1699fab2022-09-08 08:46:06 -0600526 if opts.board is None and opts.sysroot is None:
527 cros_build_lib.Die("--board or --sysroot is required")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400528
Alex Klein1699fab2022-09-08 08:46:06 -0600529 ret = GenerateBreakpadSymbols(
530 opts.board,
531 breakpad_dir=opts.breakpad_root,
532 strip_cfi=opts.strip_cfi,
533 generate_count=opts.generate_count,
534 sysroot=opts.sysroot,
535 num_processes=opts.jobs,
536 clean_breakpad=opts.clean,
537 exclude_dirs=opts.exclude_dir,
538 file_list=opts.file_list,
539 )
540 if ret:
541 logging.error("encountered %i problem(s)", ret)
542 # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently
543 # return 0 in case we are a multiple of the mask.
544 ret = 1
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400545
Alex Klein1699fab2022-09-08 08:46:06 -0600546 return ret