diff options
Diffstat (limited to 'bitbake/lib/bb')
-rw-r--r-- | bitbake/lib/bb/build.py | 58 | ||||
-rw-r--r-- | bitbake/lib/bb/process.py | 3 |
2 files changed, 60 insertions, 1 deletions
diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py index 98cbc48cd4..5479a53d7e 100644 --- a/bitbake/lib/bb/build.py +++ b/bitbake/lib/bb/build.py | |||
@@ -16,7 +16,9 @@ import os | |||
16 | import sys | 16 | import sys |
17 | import logging | 17 | import logging |
18 | import glob | 18 | import glob |
19 | import itertools | ||
19 | import time | 20 | import time |
21 | import re | ||
20 | import stat | 22 | import stat |
21 | import bb | 23 | import bb |
22 | import bb.msg | 24 | import bb.msg |
@@ -495,6 +497,62 @@ exit $ret | |||
495 | bb.debug(2, "Executing shell function %s" % func) | 497 | bb.debug(2, "Executing shell function %s" % func) |
496 | with open(os.devnull, 'r+') as stdin, logfile: | 498 | with open(os.devnull, 'r+') as stdin, logfile: |
497 | bb.process.run(cmd, shell=False, stdin=stdin, log=logfile, extrafiles=[(fifo,readfifo)]) | 499 | bb.process.run(cmd, shell=False, stdin=stdin, log=logfile, extrafiles=[(fifo,readfifo)]) |
500 | except bb.process.ExecutionError as exe: | ||
501 | # Find the backtrace that the shell trap generated | ||
502 | backtrace_marker_regex = re.compile(r"WARNING: Backtrace \(BB generated script\)") | ||
503 | stdout_lines = (exe.stdout or "").split("\n") | ||
504 | backtrace_start_line = None | ||
505 | for i, line in enumerate(reversed(stdout_lines)): | ||
506 | if backtrace_marker_regex.search(line): | ||
507 | backtrace_start_line = len(stdout_lines) - i | ||
508 | break | ||
509 | |||
510 | # Read the backtrace frames, starting at the location we just found | ||
511 | backtrace_entry_regex = re.compile(r"#(?P<frameno>\d+): (?P<funcname>[^\s]+), (?P<file>.+?), line (" | ||
512 | r"?P<lineno>\d+)") | ||
513 | backtrace_frames = [] | ||
514 | if backtrace_start_line: | ||
515 | for line in itertools.islice(stdout_lines, backtrace_start_line, None): | ||
516 | match = backtrace_entry_regex.search(line) | ||
517 | if match: | ||
518 | backtrace_frames.append(match.groupdict()) | ||
519 | |||
520 | with open(runfile, "r") as script: | ||
521 | script_lines = [line.rstrip() for line in script.readlines()] | ||
522 | |||
523 | # For each backtrace frame, search backwards in the script (from the line number called out by the frame), | ||
524 | # to find the comment that emit_vars injected when it wrote the script. This will give us the metadata | ||
525 | # filename (e.g. .bb or .bbclass) and line number where the shell function was originally defined. | ||
526 | script_metadata_comment_regex = re.compile(r"# line: (?P<lineno>\d+), file: (?P<file>.+)") | ||
527 | better_frames = [] | ||
528 | # Skip the very last frame since it's just the call to the shell task in the body of the script | ||
529 | for frame in backtrace_frames[:-1]: | ||
530 | # Check whether the frame corresponds to a function defined in the script vs external script. | ||
531 | if os.path.samefile(frame["file"], runfile): | ||
532 | # Search backwards from the frame lineno to locate the comment that BB injected | ||
533 | i = int(frame["lineno"]) - 1 | ||
534 | while i >= 0: | ||
535 | match = script_metadata_comment_regex.match(script_lines[i]) | ||
536 | if match: | ||
537 | # Calculate the relative line in the function itself | ||
538 | relative_line_in_function = int(frame["lineno"]) - i - 2 | ||
539 | # Calculate line in the function as declared in the metadata | ||
540 | metadata_function_line = relative_line_in_function + int(match["lineno"]) | ||
541 | better_frames.append("#{frameno}: {funcname}, {file}, line {lineno}".format( | ||
542 | frameno=frame["frameno"], | ||
543 | funcname=frame["funcname"], | ||
544 | file=match["file"], | ||
545 | lineno=metadata_function_line | ||
546 | )) | ||
547 | break | ||
548 | i -= 1 | ||
549 | else: | ||
550 | better_frames.append("#{frameno}: {funcname}, {file}, line {lineno}".format(**frame)) | ||
551 | |||
552 | if better_frames: | ||
553 | better_frames = ("\t{0}".format(frame) for frame in better_frames) | ||
554 | exe.extra_message = "\nBacktrace (metadata-relative locations):\n{0}".format("\n".join(better_frames)) | ||
555 | raise | ||
498 | finally: | 556 | finally: |
499 | os.unlink(fifopath) | 557 | os.unlink(fifopath) |
500 | 558 | ||
diff --git a/bitbake/lib/bb/process.py b/bitbake/lib/bb/process.py index 2dc472a86f..f36c929d25 100644 --- a/bitbake/lib/bb/process.py +++ b/bitbake/lib/bb/process.py | |||
@@ -41,6 +41,7 @@ class ExecutionError(CmdError): | |||
41 | self.exitcode = exitcode | 41 | self.exitcode = exitcode |
42 | self.stdout = stdout | 42 | self.stdout = stdout |
43 | self.stderr = stderr | 43 | self.stderr = stderr |
44 | self.extra_message = None | ||
44 | 45 | ||
45 | def __str__(self): | 46 | def __str__(self): |
46 | message = "" | 47 | message = "" |
@@ -51,7 +52,7 @@ class ExecutionError(CmdError): | |||
51 | if message: | 52 | if message: |
52 | message = ":\n" + message | 53 | message = ":\n" + message |
53 | return (CmdError.__str__(self) + | 54 | return (CmdError.__str__(self) + |
54 | " with exit code %s" % self.exitcode + message) | 55 | " with exit code %s" % self.exitcode + message + (self.extra_message or "")) |
55 | 56 | ||
56 | class Popen(subprocess.Popen): | 57 | class Popen(subprocess.Popen): |
57 | defaults = { | 58 | defaults = { |