summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Laplante <chris.laplante@agilent.com>2020-08-14 16:55:57 -0400
committerRichard Purdie <richard.purdie@linuxfoundation.org>2020-08-15 11:44:20 +0100
commit0e15931688322f9422c4f128965f050b6e030c29 (patch)
tree28d9f414604fb6738c05dc52eaa63579ab87309e
parentb1cd7723c4d81081c6d1935be7373c7f06ae1b97 (diff)
downloadpoky-0e15931688322f9422c4f128965f050b6e030c29.tar.gz
bitbake: build: print a backtrace with the original metadata locations of Bash shell funcs
Leverage the comments that emit_var writes and the backtrace that the shell func writes to generate an additional metadata-relative backtrace. This will help the user troubleshoot shell funcs much more easily. Example: | WARNING: /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955:171 exit 1 from 'exit 1' | WARNING: Backtrace (BB generated script): | #1: myclass_do_something, /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955, line 171 | #2: do_something, /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955, line 166 | #3: actually_fail, /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955, line 153 | #4: my_compile_extra, /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955, line 155 | #5: do_compile, /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955, line 141 | #6: main, /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.68955, line 184 | | Backtrace (metadata-relative locations): | #1: myclass_do_something, /home/laplante/repos/oe-core/meta/classes/myclass.bbclass, line 2 | #2: do_something, autogenerated, line 2 | #3: actually_fail, /home/laplante/repos/oe-core/meta/recipes-extended/libsolv/libsolv_0.7.14.bb, line 36 | #4: my_compile_extra, /home/laplante/repos/oe-core/meta/recipes-extended/libsolv/libsolv_0.7.14.bb, line 38 | #5: do_compile, autogenerated, line 3 ERROR: Task (/home/laplante/repos/oe-core/meta/recipes-extended/libsolv/libsolv_0.7.14.bb:do_compile) failed with exit code '1' NOTE: Tasks Summary: Attempted 542 tasks of which 541 didn't need to be rerun and 1 failed. Summary: 1 task failed: /home/laplante/repos/oe-core/meta/recipes-extended/libsolv/libsolv_0.7.14.bb:do_compile Summary: There was 1 ERROR message shown, returning a non-zero exit code. (Bitbake rev: ae1aa4ea79826c32b20e1e7abdf77a15b601c6f2) Signed-off-by: Chris Laplante <chris.laplante@agilent.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/build.py58
-rw-r--r--bitbake/lib/bb/process.py3
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
16import sys 16import sys
17import logging 17import logging
18import glob 18import glob
19import itertools
19import time 20import time
21import re
20import stat 22import stat
21import bb 23import bb
22import bb.msg 24import 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
56class Popen(subprocess.Popen): 57class Popen(subprocess.Popen):
57 defaults = { 58 defaults = {