blob: 978e25ec899292da4c150ed4d1be13b5cc651539 [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
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080024import multiprocessing.sharedctypes
Mike Frysinger69cb41d2013-08-11 20:08:19 -040025import os
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080026import re
27from typing import Optional
Mike Frysinger69cb41d2013-08-11 20:08:19 -040028
Chris McDonaldb55b7032021-06-17 16:41:32 -060029from chromite.cbuildbot import cbuildbot_alerts
Mike Frysinger06a51c82021-04-06 11:39:17 -040030from chromite.lib import build_target_lib
Mike Frysinger69cb41d2013-08-11 20:08:19 -040031from chromite.lib import commandline
32from chromite.lib import cros_build_lib
33from chromite.lib import osutils
34from chromite.lib import parallel
Mike Frysinger96ad3f22014-04-24 23:27:27 -040035from chromite.lib import signals
Alex Klein1809f572021-09-09 11:28:37 -060036from chromite.utils import file_util
Mike Frysinger69cb41d2013-08-11 20:08:19 -040037
Mike Frysinger807d8282022-04-28 22:45:17 -040038
Stephen Boydfc1c8032021-10-06 20:58:37 -070039# Elf files that don't exist but have a split .debug file installed.
40ALLOWED_DEBUG_ONLY_FILES = {
Alex Klein1699fab2022-09-08 08:46:06 -060041 "boot/vmlinux",
Stephen Boydfc1c8032021-10-06 20:58:37 -070042}
Mike Frysinger69cb41d2013-08-11 20:08:19 -040043
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -080044# Allowlist of elf files that we know we can't symbolize in the normal way, but
45# which we don't have an automatic way to detect.
46EXPECTED_POOR_SYMBOLIZATION_FILES = ALLOWED_DEBUG_ONLY_FILES | {
47 # Git binaries are downloaded as binary blobs already stripped.
48 "usr/bin/git",
49 "usr/bin/git-receive-pack",
50 "usr/bin/git-upload-archive",
51 "usr/bin/git-upload-pack",
52 # Prebuild Android binary
53 "build/rootfs/opt/google/vms/android/etc/bin/XkbToKcmConverter",
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -070054 "build/rootfs/opt/google/containers/android/etc/bin/XkbToKcmConverter",
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -080055 # Pulled from
56 # https://skia.googlesource.com/buildbot/+/refs/heads/main/gold-client/, no
57 # need to resymbolize.
58 "usr/bin/goldctl",
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -080059}
60
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080061# Allowlist of patterns for ELF files that symbolize (dump_syms exits with
62# success) but don't pass symbol file validation. Note that ELFs listed in
63# EXPECTED_POOR_SYMBOLIZATION_FILES do not have their symbol files validated and
64# do not need to be repeated here.
65ALLOWLIST_NO_SYMBOL_FILE_VALIDATION = {
66 # Built in a weird way, see comments at top of
67 # https://source.chromium.org/chromium/chromium/src/+/main:native_client/src/trusted/service_runtime/linux/nacl_bootstrap.x
68 "opt/google/chrome/nacl_helper_bootstrap",
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -070069 # TODO(b/279645511): Investigate why this doesn't have STACK records on
70 # jacuzzi, scarlet, kukui, etc.
71 "usr/bin/rma_reset",
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080072}
73# Same but patterns not exact paths.
74ALLOWLIST_NO_SYMBOL_FILE_VALIDATION_RE = tuple(
75 re.compile(x)
76 for x in (
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080077 # Prebuilt closed-source library.
78 r"usr/lib[^/]*/python[0-9]\.[0-9]/site-packages/.*/x_ignore_nofocus.so",
79 # b/273577373: Rarely used, and only by few programs that do
Ian Barkley-Yeung5b485132023-07-25 16:54:31 -070080 # non-standard encoding conversions.
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080081 r"lib[^/]*/libnss_files\.so\.[0-9.]+",
82 r"lib[^/]*/libnss_dns\.so\.[0-9.]+",
83 r"usr/lib[^/]*/gconv/libISOIR165\.so",
84 r"usr/lib[^/]*/gconv/libGB\.so",
85 r"usr/lib[^/]*/gconv/libKSC\.so",
86 r"usr/lib[^/]*/gconv/libCNS\.so",
87 r"usr/lib[^/]*/gconv/libJISX0213\.so",
88 r"usr/lib[^/]*/gconv/libJIS\.so",
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -080089 )
90)
91
Alex Klein1699fab2022-09-08 08:46:06 -060092SymbolHeader = collections.namedtuple(
93 "SymbolHeader",
94 (
95 "cpu",
96 "id",
97 "name",
98 "os",
99 ),
100)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400101
102
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800103class SymbolGenerationResult(enum.Enum):
104 """Result of running dump_syms
105
106 Return value of _DumpAllowingBasicFallback() and _DumpExpectingSymbols().
107 """
108
109 SUCCESS = 1
110 UNEXPECTED_FAILURE = 2
111 EXPECTED_FAILURE = 3
112
113
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800114class ExpectedFiles(enum.Enum):
115 """The files always expect to see dump_syms run on.
116
117 We do extra validation on a few, semi-randomly chosen files. If we do not
118 create symbol files for these ELFs, something is very wrong.
119 """
120
121 ASH_CHROME = enum.auto()
122 LIBC = enum.auto()
123 CRASH_REPORTER = enum.auto()
124 LIBMETRICS = enum.auto()
125
126
127ALL_EXPECTED_FILES = frozenset(
128 (
129 ExpectedFiles.ASH_CHROME,
130 ExpectedFiles.LIBC,
131 ExpectedFiles.CRASH_REPORTER,
132 ExpectedFiles.LIBMETRICS,
133 )
134)
135
136
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -0700137# Regular expression for ChromeOS's libc.so. Note that some containers have
138# their own libc.so file; we don't want to do the extra validation on those.
139# (They are often subsets of the full libc and will not pass STACK count tests.)
140LIBC_REGEX = re.compile(r"lib[^/]*/libc\.so\.[0-9.]+")
141
Ian Barkley-Yeung5b485132023-07-25 16:54:31 -0700142# Regular expression to find shared object libraries. Covers filenames like
143# "libcontainer.so" and also "libc.so.6" and also
144# "libabsl_log_entry.so.2301.0.0".
145SO_REGEX = re.compile(r"\.so(?:\.[0-9]+)*$")
146
147
148def IsSharedLibrary(elf_file: str) -> Optional[re.Match]:
149 """Returns non-None if the elf_file appears to be a shared library.
150
151 Tests if the elf_file appears to be a shared object library. The test is
152 just based on the filename.
153
154 Args:
155 elf_file: The path of the elf_file being tested.
156
157 Returns:
158 An object that evaluates to true if the elf_file is a shared object
159 library. None if the elf_file is not a shared object library.
160 """
161 return SO_REGEX.search(elf_file)
162
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -0700163
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800164class SymbolFileLineCounts:
165 """Counts of the various types of lines in a .sym file"""
166
167 LINE_NUMBER_REGEX = re.compile(r"^([0-9a-f]+)")
168
169 def __init__(self, sym_file: str, elf_file: str):
170 # https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs/symbol_files.md
171 # explains what these line types are.
172 self.module_lines = 0
173 self.file_lines = 0
174 self.inline_origin_lines = 0
175 self.func_lines = 0
176 self.inline_lines = 0
177 self.line_number_lines = 0
178 self.public_lines = 0
179 self.stack_lines = 0
180 # Not listed in the documentation but still present.
181 self.info_lines = 0
182
183 with open(sym_file, mode="r", encoding="utf-8") as f:
184 for line in f:
185 words = line.split()
186 expected_words_max = None
187 if not words:
188 raise ValueError(
189 f"{elf_file}: symbol file has unexpected blank line"
190 )
191
192 line_type = words[0]
193 if line_type == "MODULE":
194 self.module_lines += 1
195 expected_words_min = 5
196 expected_words_max = 5
197 elif line_type == "FILE":
198 self.file_lines += 1
199 expected_words_min = 3
200 # No max, filenames can have spaces.
201 elif line_type == "INLINE_ORIGIN":
202 self.inline_origin_lines += 1
203 expected_words_min = 3
204 # No max, function parameter lists can have spaces.
205 elif line_type == "FUNC":
206 self.func_lines += 1
207 expected_words_min = 5
208 # No max, function parameter lists can have spaces.
209 elif line_type == "INLINE":
210 self.inline_lines += 1
211 expected_words_min = 5
212 # No max, INLINE can have multiple address pairs.
213 elif SymbolFileLineCounts.LINE_NUMBER_REGEX.match(line_type):
214 self.line_number_lines += 1
215 expected_words_min = 4
216 expected_words_max = 4
217 line_type = "line number"
218 elif line_type == "PUBLIC":
219 self.public_lines += 1
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -0700220 # TODO(b/251003272): expected_words_min should be 4;
221 # however, dump_syms sometimes produces PUBLIC records with
222 # no symbol name. This is an error but is not affecting our
223 # ability to decode stacks.
224 expected_words_min = 3
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800225 # No max, function parameter lists can have spaces.
226 elif line_type == "STACK":
227 self.stack_lines += 1
228 expected_words_min = 5
229 # No max, expressions can be complex.
230 elif line_type == "INFO":
231 self.info_lines += 1
232 # Not documented, so unclear what the min & max are
233 expected_words_min = None
234 else:
235 raise ValueError(
236 f"{elf_file}: symbol file has unknown line type "
Ian Barkley-Yeungccfa1b52023-07-07 18:55:46 -0700237 f"{line_type} (line='{line}')"
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800238 )
239
240 if expected_words_max is not None:
241 if not (
242 expected_words_min <= len(words) <= expected_words_max
243 ):
244 raise ValueError(
245 f"{elf_file}: symbol file has {line_type} line "
246 f"with {len(words)} words (expected "
Ian Barkley-Yeungccfa1b52023-07-07 18:55:46 -0700247 f"{expected_words_min} - {expected_words_max}) "
248 f"(line='{line}')"
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800249 )
250 elif expected_words_min is not None:
251 if len(words) < expected_words_min:
252 raise ValueError(
253 f"{elf_file}: symbol file has {line_type} line "
254 f"with {len(words)} words (expected "
Ian Barkley-Yeungccfa1b52023-07-07 18:55:46 -0700255 f"{expected_words_min} or more) (line='{line}')"
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800256 )
257
258
259def ValidateSymbolFile(
260 sym_file: str,
261 elf_file: str,
262 sysroot: Optional[str],
263 found_files: Optional[multiprocessing.managers.ListProxy],
264) -> bool:
265 """Checks that the given sym_file has enough info for us to get good stacks.
266
267 Validates that the given sym_file has enough information for us to get
268 good error reports -- enough STACK records to unwind the stack and enough
269 FUNC or PUBLIC records to turn the function addresses into human-readable
270 names.
271
272 Args:
273 sym_file: The complete path to the breakpad symbol file to validate
274 elf_file: The complete path to the elf file which was the source of the
275 symbol file.
276 sysroot: If not None, the root of the build directory ('/build/eve', for
277 instance).
278 found_files: A multiprocessing.managers.ListProxy list containing
279 ExpectedFiles, representing which of the "should always be present"
280 files have been processed.
281
282 Returns:
283 True if the symbol file passes validation.
284 """
285 if sysroot is not None:
286 relative_path = os.path.relpath(elf_file, sysroot)
287 else:
288 relative_path = os.path.relpath(elf_file, "/")
289
290 if relative_path in ALLOWLIST_NO_SYMBOL_FILE_VALIDATION:
291 return True
292 for regex in ALLOWLIST_NO_SYMBOL_FILE_VALIDATION_RE:
293 if regex.match(relative_path):
294 return True
295
296 counts = SymbolFileLineCounts(sym_file, elf_file)
297
298 errors = False
Ian Barkley-Yeung5b485132023-07-25 16:54:31 -0700299 # Executables should always have code, and thus STACK records. Many shared
300 # libraries, however, just have some constants (libabsl_log_entry.so) or
301 # are stubs that only have code under some #if or USE condition
302 # (libcros_ml_core.so). It is correct for such shared libraries to have no
303 # STACK records.
304 is_shared_library = IsSharedLibrary(elf_file)
305 if counts.stack_lines == 0 and not is_shared_library:
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800306 # Use the elf_file in error messages; sym_file is still a temporary
307 # file with a meaningless-to-humans name right now.
308 logging.warning("%s: Symbol file has no STACK records", elf_file)
309 errors = True
310 if counts.module_lines != 1:
311 logging.warning(
312 "%s: Symbol file has %d MODULE lines", elf_file, counts.module_lines
313 )
314 errors = True
315 # Many shared object files have only PUBLIC functions. In theory,
316 # executables should always have at least one FUNC (main) and some line
317 # numbers, but for reasons I'm unclear on, C-based executables often just
318 # have PUBLIC records. dump_syms does not support line numbers after
319 # PUBLIC records, only FUNC records, so such executables will also have
320 # no line numbers.
321 if counts.public_lines == 0 and counts.func_lines == 0:
322 logging.warning(
323 "%s: Symbol file has no FUNC or PUBLIC records", elf_file
324 )
325 errors = True
326 # However, if we get a FUNC record, we do want line numbers for it.
327 if counts.func_lines > 0 and counts.line_number_lines == 0:
328 logging.warning(
329 "%s: Symbol file has FUNC records but no line numbers", elf_file
330 )
331 errors = True
332
333 if counts.line_number_lines > 0 and counts.file_lines == 0:
334 logging.warning(
335 "%s: Symbol file has line number records but no FILE records",
336 elf_file,
337 )
338 errors = True
339 if counts.inline_lines > 0 and counts.file_lines == 0:
340 logging.warning(
341 "%s: Symbol file has INLINE records but no FILE records", elf_file
342 )
343 errors = True
344
345 if counts.inline_lines > 0 and counts.inline_origin_lines == 0:
346 logging.warning(
347 "%s: Symbol file has INLINE records but no INLINE_ORIGIN records",
348 elf_file,
349 )
350 errors = True
351
352 def _AddFoundFile(files, found):
353 """Add another file to the list of expected files we've found."""
354 if files is not None:
355 files.append(found)
356
357 # Extra validation for a few ELF files which are special. Either these are
358 # unusually important to the system (chrome binary, which is where a large
359 # fraction of our crashes occur, and libc.so, which is in every stack), or
360 # they are some hand-chosen ELF files which stand in for "normal" platform2
361 # binaries. Not all ELF files would pass the extra validation, so we can't
362 # run these checks on every ELF, but we want to make sure we don't end up
363 # with, say, a chrome build or a platform2 build with just one or two FUNC
364 # records on every binary.
365 if relative_path == "opt/google/chrome/chrome":
366 _AddFoundFile(found_files, ExpectedFiles.ASH_CHROME)
367 if counts.func_lines < 100000:
368 logging.warning(
369 "chrome should have at least 100,000 FUNC records, found %d",
370 counts.func_lines,
371 )
372 errors = True
373 if counts.stack_lines < 1000000:
374 logging.warning(
375 "chrome should have at least 1,000,000 STACK records, found %d",
376 counts.stack_lines,
377 )
378 errors = True
379 if counts.line_number_lines < 1000000:
380 logging.warning(
381 "chrome should have at least 1,000,000 line number records, "
382 "found %d",
383 counts.line_number_lines,
384 )
385 errors = True
386 # Lacros symbol files are not generated as part of the ChromeOS build and
387 # can't be validated here.
388 # TODO(b/273836486): Add similar logic to the code that generates Lacros
389 # symbols.
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -0700390 elif LIBC_REGEX.fullmatch(relative_path):
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800391 _AddFoundFile(found_files, ExpectedFiles.LIBC)
392 if counts.public_lines < 100:
393 logging.warning(
394 "%s should have at least 100 PUBLIC records, found %d",
395 elf_file,
396 counts.public_lines,
397 )
398 errors = True
399 if counts.stack_lines < 10000:
400 logging.warning(
401 "%s should have at least 10000 STACK records, found %d",
402 elf_file,
403 counts.stack_lines,
404 )
405 errors = True
406 elif relative_path == "sbin/crash_reporter":
407 # Representative platform2 executable.
408 _AddFoundFile(found_files, ExpectedFiles.CRASH_REPORTER)
409 if counts.stack_lines < 1000:
410 logging.warning(
411 "crash_reporter should have at least 1000 STACK records, "
412 "found %d",
413 counts.stack_lines,
414 )
415 errors = True
416 if counts.func_lines < 1000:
417 logging.warning(
418 "crash_reporter should have at least 1000 FUNC records, "
419 "found %d",
420 counts.func_lines,
421 )
422 errors = True
423 if counts.line_number_lines < 10000:
424 logging.warning(
425 "crash_reporter should have at least 10,000 line number "
426 "records, found %d",
427 counts.line_number_lines,
428 )
429 errors = True
430 elif os.path.basename(relative_path) == "libmetrics.so":
431 # Representative platform2 shared library.
432 _AddFoundFile(found_files, ExpectedFiles.LIBMETRICS)
433 if counts.func_lines < 100:
434 logging.warning(
435 "libmetrics should have at least 100 FUNC records, found %d",
436 counts.func_lines,
437 )
438 errors = True
439 if counts.public_lines == 0:
440 logging.warning(
441 "libmetrics should have at least 1 PUBLIC record, found %d",
442 counts.public_lines,
443 )
444 errors = True
445 if counts.stack_lines < 1000:
446 logging.warning(
447 "libmetrics should have at least 1000 STACK records, found %d",
448 counts.stack_lines,
449 )
450 errors = True
451 if counts.line_number_lines < 5000:
452 logging.warning(
453 "libmetrics should have at least 5000 line number records, "
454 "found %d",
455 counts.line_number_lines,
456 )
457 errors = True
458
459 return not errors
460
461
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800462def _ExpectGoodSymbols(elf_file, sysroot):
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800463 """Determines if we expect dump_syms to create good symbols.
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800464
465 We know that certain types of files never generate good symbols. Distinguish
466 those from the majority of elf files which should generate good symbols.
467
468 Args:
469 elf_file: The complete path to the file which we will pass to dump_syms
470 sysroot: If not None, the root of the build directory ('/build/eve', for
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800471 instance)
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800472
473 Returns:
474 True if the elf file should generate good symbols, False if not.
475 """
476 # .ko files (kernel object files) never produce good symbols.
477 if elf_file.endswith(".ko"):
478 return False
479
480 # dump_syms doesn't understand Golang executables.
481 result = cros_build_lib.run(
482 ["/usr/bin/file", elf_file], print_cmd=False, stdout=True
483 )
484 if b"Go BuildID" in result.stdout:
485 return False
486
487 if sysroot is not None:
488 relative_path = os.path.relpath(elf_file, sysroot)
489 else:
Ian Barkley-Yeunge1785762023-03-08 18:32:18 -0800490 relative_path = os.path.relpath(elf_file, "/")
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800491
492 if relative_path in EXPECTED_POOR_SYMBOLIZATION_FILES:
493 return False
494
Ian Barkley-Yeunge1785762023-03-08 18:32:18 -0800495 # Binaries in /usr/local are not actually shipped to end-users, so we
496 # don't care if they get good symbols -- we should never get crash reports
497 # for them anyways.
498 if relative_path.startswith("usr/local"):
499 return False
500
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800501 return True
502
503
504def ReadSymsHeader(sym_file, name_for_errors):
Alex Klein1699fab2022-09-08 08:46:06 -0600505 """Parse the header of the symbol file
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400506
Alex Klein1699fab2022-09-08 08:46:06 -0600507 The first line of the syms file will read like:
Alex Klein8b444532023-04-11 16:35:24 -0600508 MODULE Linux arm F4F6FA6CCBDEF455039C8DE869C8A2F40 blkid
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400509
Alex Klein1699fab2022-09-08 08:46:06 -0600510 https://code.google.com/p/google-breakpad/wiki/SymbolFiles
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400511
Alex Klein1699fab2022-09-08 08:46:06 -0600512 Args:
Alex Klein8b444532023-04-11 16:35:24 -0600513 sym_file: The symbol file to parse
514 name_for_errors: A name for error strings. Can be the name of the elf
515 file that generated the symbol file, or the name of the symbol file
516 if the symbol file has already been moved to a meaningful location.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500517
Alex Klein1699fab2022-09-08 08:46:06 -0600518 Returns:
Alex Klein8b444532023-04-11 16:35:24 -0600519 A SymbolHeader object
Mike Frysinger1a736a82013-12-12 01:50:59 -0500520
Alex Klein1699fab2022-09-08 08:46:06 -0600521 Raises:
Alex Klein8b444532023-04-11 16:35:24 -0600522 ValueError if the first line of |sym_file| is invalid
Alex Klein1699fab2022-09-08 08:46:06 -0600523 """
524 with file_util.Open(sym_file, "rb") as f:
525 header = f.readline().decode("utf-8").split()
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400526
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800527 if len(header) != 5 or header[0] != "MODULE":
528 raise ValueError(
529 f"header of sym file from {name_for_errors} is invalid"
530 )
Mike Frysinger50cedd32014-02-09 23:03:18 -0500531
Alex Klein1699fab2022-09-08 08:46:06 -0600532 return SymbolHeader(
533 os=header[1], cpu=header[2], id=header[3], name=header[4]
534 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400535
536
Alex Klein1699fab2022-09-08 08:46:06 -0600537def GenerateBreakpadSymbol(
538 elf_file,
539 debug_file=None,
540 breakpad_dir=None,
541 strip_cfi=False,
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800542 sysroot=None,
Alex Klein1699fab2022-09-08 08:46:06 -0600543 num_errors=None,
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800544 found_files=None,
Alex Klein1699fab2022-09-08 08:46:06 -0600545 dump_syms_cmd="dump_syms",
David Rileyc1a44f62023-07-07 16:18:34 -0700546 dump_syms_args=None,
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700547 force_basic_fallback=False,
Alex Klein1699fab2022-09-08 08:46:06 -0600548):
549 """Generate the symbols for |elf_file| using |debug_file|
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400550
Alex Klein1699fab2022-09-08 08:46:06 -0600551 Args:
Alex Klein8b444532023-04-11 16:35:24 -0600552 elf_file: The file to dump symbols for
553 debug_file: Split debug file to use for symbol information
554 breakpad_dir: The dir to store the output symbol file in
555 strip_cfi: Do not generate CFI data
556 sysroot: Path to the sysroot with the elf_file under it
557 num_errors: An object to update with the error count (needs a .value
558 member).
559 found_files: A multiprocessing.managers.ListProxy list containing
560 ExpectedFiles, representing which of the "should always be present"
561 files have been processed.
562 dump_syms_cmd: Command to use for dumping symbols.
David Rileyc1a44f62023-07-07 16:18:34 -0700563 dump_syms_args: List of args to pass to dump_syms_cmd.
564 If not specified, a reasonable default will be used.
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700565 force_basic_fallback: If True, always use _DumpAllowingBasicFallback()
566 instead of _DumpExpectingSymbols().
Mike Frysinger1a736a82013-12-12 01:50:59 -0500567
Alex Klein1699fab2022-09-08 08:46:06 -0600568 Returns:
Alex Klein8b444532023-04-11 16:35:24 -0600569 The name of symbol file written out on success, or the failure count.
Alex Klein1699fab2022-09-08 08:46:06 -0600570 """
571 assert breakpad_dir
572 if num_errors is None:
Trent Apted1e2e4f32023-05-05 03:50:20 +0000573 num_errors = ctypes.c_int(0)
David Rileyc1a44f62023-07-07 16:18:34 -0700574 if dump_syms_args is None:
575 dump_syms_args = ["-v", "-d", "-m"]
Alex Klein1699fab2022-09-08 08:46:06 -0600576 debug_file_only = not os.path.exists(elf_file)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400577
David Rileyc1a44f62023-07-07 16:18:34 -0700578 cmd_base = [dump_syms_cmd] + dump_syms_args
Alex Klein1699fab2022-09-08 08:46:06 -0600579 if strip_cfi:
580 cmd_base += ["-c"]
581 # Some files will not be readable by non-root (e.g. set*id /bin/su).
582 needs_sudo = not os.access(elf_file, os.R_OK)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400583
Alex Klein1699fab2022-09-08 08:46:06 -0600584 def _DumpIt(cmd_args):
585 if needs_sudo:
586 run_command = cros_build_lib.sudo_run
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400587 else:
Alex Klein1699fab2022-09-08 08:46:06 -0600588 run_command = cros_build_lib.run
589 return run_command(
590 cmd_base + cmd_args,
591 stderr=True,
592 stdout=temp.name,
593 check=False,
594 debug_level=logging.DEBUG,
595 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400596
Alex Klein1699fab2022-09-08 08:46:06 -0600597 def _CrashCheck(result, file_or_files, msg):
598 if result.returncode:
599 cbuildbot_alerts.PrintBuildbotStepWarnings()
600 if result.returncode < 0:
601 logging.warning(
602 "dump_syms %s crashed with %s; %s",
603 file_or_files,
604 signals.StrSignal(-result.returncode),
605 msg,
606 )
607 else:
608 logging.warning(
609 "dump_syms %s returned %d; %s",
610 file_or_files,
611 result.returncode,
612 msg,
613 )
614 logging.warning("output:\n%s", result.stderr.decode("utf-8"))
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400615
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800616 def _DumpAllowingBasicFallback():
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800617 """Dump symbols for an ELF when we do NOT expect to get good symbols.
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800618
619 Returns:
620 A SymbolGenerationResult
621 """
Alex Klein1699fab2022-09-08 08:46:06 -0600622 if debug_file:
623 # Try to dump the symbols using the debug file like normal.
624 if debug_file_only:
625 cmd_args = [debug_file]
626 file_or_files = debug_file
627 else:
628 cmd_args = [elf_file, os.path.dirname(debug_file)]
629 file_or_files = [elf_file, debug_file]
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400630
Alex Klein1699fab2022-09-08 08:46:06 -0600631 result = _DumpIt(cmd_args)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400632
Alex Klein1699fab2022-09-08 08:46:06 -0600633 if result.returncode:
634 # Sometimes dump_syms can crash because there's too much info.
635 # Try dumping and stripping the extended stuff out. At least
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800636 # this way we'll get the extended symbols.
637 # https://crbug.com/266064
Alex Klein1699fab2022-09-08 08:46:06 -0600638 _CrashCheck(result, file_or_files, "retrying w/out CFI")
639 cmd_args = ["-c", "-r"] + cmd_args
640 result = _DumpIt(cmd_args)
641 _CrashCheck(result, file_or_files, "retrying w/out debug")
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700642
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800643 if not result.returncode:
644 return SymbolGenerationResult.SUCCESS
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700645
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800646 # If that didn't work (no debug, or dump_syms still failed), try
647 # dumping just the file itself directly.
648 result = _DumpIt([elf_file])
649 if result.returncode:
650 # A lot of files (like kernel files) contain no debug information,
651 # do not consider such occurrences as errors.
652 cbuildbot_alerts.PrintBuildbotStepWarnings()
653 if b"file contains no debugging information" in result.stderr:
654 logging.warning("dump_syms failed; giving up entirely.")
655 logging.warning("No symbols found for %s", elf_file)
656 return SymbolGenerationResult.EXPECTED_FAILURE
657 else:
658 _CrashCheck(result, elf_file, "counting as failure")
659 return SymbolGenerationResult.UNEXPECTED_FAILURE
660
661 return SymbolGenerationResult.SUCCESS
662
663 def _DumpExpectingSymbols():
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800664 """Dump symbols for an ELF when we expect to get good symbols.
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800665
666 Returns:
667 A SymbolGenerationResult. We never expect failure, so the result
668 will always be SUCCESS or UNEXPECTED_FAILURE.
669 """
670 if not debug_file:
671 logging.warning("%s must have debug file", elf_file)
672 return SymbolGenerationResult.UNEXPECTED_FAILURE
673
674 cmd_args = [elf_file, os.path.dirname(debug_file)]
675 result = _DumpIt(cmd_args)
676 if result.returncode:
Ian Barkley-Yeungab1dab12023-04-21 18:19:55 -0700677 _CrashCheck(
678 result,
679 [elf_file, debug_file],
680 "unexpected symbol generation failure",
681 )
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800682 return SymbolGenerationResult.UNEXPECTED_FAILURE
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800683
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800684 try:
685 if not ValidateSymbolFile(
686 temp.name, elf_file, sysroot, found_files
687 ):
Ian Barkley-Yeung9c9430e2023-08-09 17:24:18 -0700688 logging.error("%s: symbol file failed validation", elf_file)
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800689 return SymbolGenerationResult.UNEXPECTED_FAILURE
690 except ValueError as e:
Ian Barkley-Yeung9c9430e2023-08-09 17:24:18 -0700691 logging.error(
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800692 "%s: symbol file failed validation due to exception %s",
693 elf_file,
694 e,
695 )
696 return SymbolGenerationResult.UNEXPECTED_FAILURE
697
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800698 return SymbolGenerationResult.SUCCESS
699
700 osutils.SafeMakedirs(breakpad_dir)
701 with cros_build_lib.UnbufferedNamedTemporaryFile(
702 dir=breakpad_dir, delete=False
703 ) as temp:
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700704 if not force_basic_fallback and _ExpectGoodSymbols(elf_file, sysroot):
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800705 result = _DumpExpectingSymbols()
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800706 else:
707 result = _DumpAllowingBasicFallback()
708
709 if result == SymbolGenerationResult.UNEXPECTED_FAILURE:
710 num_errors.value += 1
711 os.unlink(temp.name)
712 return num_errors.value
713
714 if result == SymbolGenerationResult.EXPECTED_FAILURE:
715 os.unlink(temp.name)
716 return 0
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700717
Alex Klein1699fab2022-09-08 08:46:06 -0600718 # Move the dumped symbol file to the right place:
Alex Klein8b444532023-04-11 16:35:24 -0600719 # /$SYSROOT/usr/lib/debug/breakpad/<module-name>/<id>/<module-name>.sym
Ian Barkley-Yeungfdaaf2e2023-03-02 17:30:39 -0800720 header = ReadSymsHeader(temp, elf_file)
Alex Klein1699fab2022-09-08 08:46:06 -0600721 logging.info("Dumped %s as %s : %s", elf_file, header.name, header.id)
722 sym_file = os.path.join(
723 breakpad_dir, header.name, header.id, header.name + ".sym"
724 )
725 osutils.SafeMakedirs(os.path.dirname(sym_file))
726 os.rename(temp.name, sym_file)
727 os.chmod(sym_file, 0o644)
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700728
Alex Klein1699fab2022-09-08 08:46:06 -0600729 return sym_file
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400730
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700731
Alex Klein1699fab2022-09-08 08:46:06 -0600732def GenerateBreakpadSymbols(
733 board,
734 breakpad_dir=None,
735 strip_cfi=False,
736 generate_count=None,
737 sysroot=None,
738 num_processes=None,
739 clean_breakpad=False,
740 exclude_dirs=(),
741 file_list=None,
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700742 always_use_basic_fallback=False,
743 ignore_expected_files=(),
Alex Klein1699fab2022-09-08 08:46:06 -0600744):
745 """Generate symbols for this board.
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700746
Alex Klein1699fab2022-09-08 08:46:06 -0600747 If |file_list| is None, symbols are generated for all executables, otherwise
748 only for the files included in |file_list|.
Prathmesh Prabhu9995e9b2013-10-31 16:43:55 -0700749
Alex Klein1699fab2022-09-08 08:46:06 -0600750 TODO(build):
751 This should be merged with buildbot_commands.GenerateBreakpadSymbols()
752 once we rewrite cros_generate_breakpad_symbols in python.
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400753
Alex Klein1699fab2022-09-08 08:46:06 -0600754 Args:
Alex Klein8b444532023-04-11 16:35:24 -0600755 board: The board whose symbols we wish to generate
756 breakpad_dir: The full path to the breakpad directory where symbols live
757 strip_cfi: Do not generate CFI data
758 generate_count: If set, only generate this many symbols (meant for
759 testing)
760 sysroot: The root where to find the corresponding ELFs
761 num_processes: Number of jobs to run in parallel
762 clean_breakpad: Should we `rm -rf` the breakpad output dir first; note:
763 we do not do any locking, so do not run more than one in parallel
764 when True
765 exclude_dirs: List of dirs (relative to |sysroot|) to not search
766 file_list: Only generate symbols for files in this list. Each file must
767 be a full path (including |sysroot| prefix).
768 TODO(build): Support paths w/o |sysroot|.
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700769 always_use_basic_fallback: If True, use the "basic fallback" mode for
770 all symbol files.
771 ignore_expected_files: A list of ExpectedFiles that will not be
772 considered "missing" if we do not generate symbols for them.
Alex Klein1699fab2022-09-08 08:46:06 -0600773
774 Returns:
Alex Klein8b444532023-04-11 16:35:24 -0600775 The number of errors that were encountered.
Alex Klein1699fab2022-09-08 08:46:06 -0600776 """
777 if sysroot is None:
778 sysroot = build_target_lib.get_default_sysroot_path(board)
779 if breakpad_dir is None:
780 breakpad_dir = FindBreakpadDir(board, sysroot=sysroot)
781 if clean_breakpad:
782 logging.info("cleaning out %s first", breakpad_dir)
783 osutils.RmDir(breakpad_dir, ignore_missing=True, sudo=True)
784 # Make sure non-root can write out symbols as needed.
785 osutils.SafeMakedirs(breakpad_dir, sudo=True)
786 if not os.access(breakpad_dir, os.W_OK):
787 cros_build_lib.sudo_run(["chown", "-R", str(os.getuid()), breakpad_dir])
788 debug_dir = FindDebugDir(board, sysroot=sysroot)
789 exclude_paths = [os.path.join(debug_dir, x) for x in exclude_dirs]
790 if file_list is None:
791 file_list = []
792 file_filter = dict.fromkeys([os.path.normpath(x) for x in file_list], False)
793
794 logging.info("generating breakpad symbols using %s", debug_dir)
795
796 # Let's locate all the debug_files and elfs first along with the debug file
Alex Klein8b444532023-04-11 16:35:24 -0600797 # sizes. This way we can start processing the largest files first in
798 # parallel with the small ones.
Alex Klein1699fab2022-09-08 08:46:06 -0600799 # If |file_list| was given, ignore all other files.
800 targets = []
801 for root, dirs, files in os.walk(debug_dir):
802 if root in exclude_paths:
803 logging.info("Skipping excluded dir %s", root)
804 del dirs[:]
805 continue
806
807 for debug_file in files:
808 debug_file = os.path.join(root, debug_file)
809 # Turn /build/$BOARD/usr/lib/debug/sbin/foo.debug into
810 # /build/$BOARD/sbin/foo.
811 elf_file = os.path.join(
812 sysroot, debug_file[len(debug_dir) + 1 : -6]
813 )
814
815 if file_filter:
816 if elf_file in file_filter:
817 file_filter[elf_file] = True
818 elif debug_file in file_filter:
819 file_filter[debug_file] = True
820 else:
821 continue
822
823 # Filter out files based on common issues with the debug file.
824 if not debug_file.endswith(".debug"):
825 continue
826
827 elif os.path.islink(debug_file):
828 # The build-id stuff is common enough to filter out by default.
829 if "/.build-id/" in debug_file:
830 msg = logging.debug
831 else:
832 msg = logging.warning
833 msg("Skipping symbolic link %s", debug_file)
834 continue
835
836 # Filter out files based on common issues with the elf file.
837 elf_path = os.path.relpath(elf_file, sysroot)
838 debug_only = elf_path in ALLOWED_DEBUG_ONLY_FILES
839 if not os.path.exists(elf_file) and not debug_only:
Alex Klein8b444532023-04-11 16:35:24 -0600840 # Sometimes we filter out programs from /usr/bin but leave
841 # behind the .debug file.
Alex Klein1699fab2022-09-08 08:46:06 -0600842 logging.warning("Skipping missing %s", elf_file)
843 continue
844
845 targets.append((os.path.getsize(debug_file), elf_file, debug_file))
846
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800847 with multiprocessing.Manager() as mp_manager:
848 bg_errors = parallel.WrapMultiprocessing(multiprocessing.Value, "i")
849 found_files = parallel.WrapMultiprocessing(mp_manager.list)
850 if file_filter:
851 files_not_found = [
852 x for x, found in file_filter.items() if not found
853 ]
854 bg_errors.value += len(files_not_found)
855 if files_not_found:
856 logging.error(
857 "Failed to find requested files: %s", files_not_found
858 )
Alex Klein1699fab2022-09-08 08:46:06 -0600859
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800860 # Now start generating symbols for the discovered elfs.
861 with parallel.BackgroundTaskRunner(
862 GenerateBreakpadSymbol,
863 breakpad_dir=breakpad_dir,
864 strip_cfi=strip_cfi,
865 num_errors=bg_errors,
866 processes=num_processes,
867 sysroot=sysroot,
868 found_files=found_files,
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700869 force_basic_fallback=always_use_basic_fallback,
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800870 ) as queue:
871 for _, elf_file, debug_file in sorted(targets, reverse=True):
Alex Klein1699fab2022-09-08 08:46:06 -0600872 if generate_count == 0:
873 break
874
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800875 queue.put([elf_file, debug_file])
876 if generate_count is not None:
877 generate_count -= 1
878 if generate_count == 0:
879 break
880
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700881 missing = (
882 ALL_EXPECTED_FILES
883 - frozenset(found_files)
884 - frozenset(ignore_expected_files)
885 )
886 if (
887 missing
888 and not file_filter
889 and generate_count is None
890 and not always_use_basic_fallback
891 ):
Ian Barkley-Yeung9c9430e2023-08-09 17:24:18 -0700892 logging.error(
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800893 "Not all expected files were processed successfully, "
894 "missing %s",
895 missing,
896 )
Ian Barkley-Yeung9c9430e2023-08-09 17:24:18 -0700897 bg_errors.value += 1
Ian Barkley-Yeungc5b6f582023-03-08 18:23:07 -0800898
Alex Klein1699fab2022-09-08 08:46:06 -0600899 return bg_errors.value
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400900
901
Mike Frysinger3f571af2016-08-31 23:56:53 -0400902def FindDebugDir(board, sysroot=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600903 """Given a |board|, return the path to the split debug dir for it"""
904 if sysroot is None:
905 sysroot = build_target_lib.get_default_sysroot_path(board)
906 return os.path.join(sysroot, "usr", "lib", "debug")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400907
908
Mike Frysinger3f571af2016-08-31 23:56:53 -0400909def FindBreakpadDir(board, sysroot=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600910 """Given a |board|, return the path to the breakpad dir for it"""
911 return os.path.join(FindDebugDir(board, sysroot=sysroot), "breakpad")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400912
913
914def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600915 parser = commandline.ArgumentParser(description=__doc__)
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400916
Alex Klein1699fab2022-09-08 08:46:06 -0600917 parser.add_argument(
918 "--board", default=None, help="board to generate symbols for"
919 )
920 parser.add_argument(
921 "--breakpad_root",
922 type="path",
923 default=None,
924 help="root output directory for breakpad symbols",
925 )
926 parser.add_argument(
927 "--sysroot",
928 type="path",
929 default=None,
930 help="root input directory for files",
931 )
932 parser.add_argument(
933 "--exclude-dir",
934 type=str,
935 action="append",
936 default=[],
937 help="directory (relative to |board| root) to not search",
938 )
939 parser.add_argument(
940 "--generate-count",
941 type=int,
942 default=None,
943 help="only generate # number of symbols",
944 )
945 parser.add_argument(
946 "--noclean",
947 dest="clean",
948 action="store_false",
949 default=True,
950 help="do not clean out breakpad dir before running",
951 )
952 parser.add_argument(
953 "--jobs", type=int, default=None, help="limit number of parallel jobs"
954 )
955 parser.add_argument(
956 "--strip_cfi",
957 action="store_true",
958 default=False,
959 help="do not generate CFI data (pass -c to dump_syms)",
960 )
961 parser.add_argument(
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700962 "--ignore_errors",
963 action="store_true",
964 default=False,
965 help="Ignore errors from dump_syms, do not validate symbol files, "
966 "just generate symbols best effort",
967 )
968 parser.add_argument(
969 "--ignore_expected_file",
970 type=str,
971 action="append",
972 default=[],
973 choices=[x.name for x in ExpectedFiles],
974 help="do not generate errors if symbols are not generated for these "
975 "files",
976 )
977 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -0600978 "file_list",
979 nargs="*",
980 default=None,
Trent Aptedc4f366a2023-05-16 15:32:48 +1000981 help=(
982 "generate symbols for only these files "
983 "(e.g. /build/$BOARD/usr/bin/foo)"
984 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600985 )
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400986
Alex Klein1699fab2022-09-08 08:46:06 -0600987 opts = parser.parse_args(argv)
988 opts.Freeze()
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -0700989 ignore_expected_files = [
990 ExpectedFiles[x] for x in opts.ignore_expected_file
991 ]
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400992
Alex Klein1699fab2022-09-08 08:46:06 -0600993 if opts.board is None and opts.sysroot is None:
994 cros_build_lib.Die("--board or --sysroot is required")
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400995
Alex Klein1699fab2022-09-08 08:46:06 -0600996 ret = GenerateBreakpadSymbols(
997 opts.board,
998 breakpad_dir=opts.breakpad_root,
999 strip_cfi=opts.strip_cfi,
1000 generate_count=opts.generate_count,
1001 sysroot=opts.sysroot,
1002 num_processes=opts.jobs,
1003 clean_breakpad=opts.clean,
1004 exclude_dirs=opts.exclude_dir,
1005 file_list=opts.file_list,
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -07001006 always_use_basic_fallback=opts.ignore_errors,
1007 ignore_expected_files=ignore_expected_files,
Alex Klein1699fab2022-09-08 08:46:06 -06001008 )
1009 if ret:
1010 logging.error("encountered %i problem(s)", ret)
Alex Klein8b444532023-04-11 16:35:24 -06001011 # Since exit(status) gets masked, clamp it to 1 so we don't
1012 # inadvertently return 0 in case we are a multiple of the mask.
Alex Klein1699fab2022-09-08 08:46:06 -06001013 ret = 1
Mike Frysinger69cb41d2013-08-11 20:08:19 -04001014
Ian Barkley-Yeungb5274442023-04-28 16:32:20 -07001015 if opts.ignore_errors:
1016 return 0
1017
Alex Klein1699fab2022-09-08 08:46:06 -06001018 return ret