3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 # This script uses `fix-stacks` to post-process the entries produced by
8 # MozFormatCodeAddress().
10 from __future__
import absolute_import
, print_function
11 from subprocess
import Popen
, PIPE
18 # Matches lines produced by MozFormatCodeAddress(), e.g.
19 # `#01: ???[tests/example +0x43a0]`.
20 line_re
= re
.compile("#\d+: .+\[.+ \+0x[0-9A-Fa-f]+\]")
26 from mozbuild
.configure
import ConfigureSandbox
29 sandbox
= ConfigureSandbox(
34 "--host={}".format(buildconfig
.substs
["HOST_ALIAS"]),
37 moz_configure
= os
.path
.join(buildconfig
.topsrcdir
, "build", "moz.configure")
38 sandbox
.include_file(os
.path
.join(moz_configure
, "init.configure"))
39 # bootstrap_search_path_order has a dependency on developer_options, which
40 # is not defined in init.configure. Its value doesn't matter for us, though.
41 sandbox
["developer_options"] = sandbox
["always"]
42 sandbox
.include_file(os
.path
.join(moz_configure
, "bootstrap.configure"))
43 # Expand the `bootstrap_path` template for "fix-stacks", and execute the
44 # expanded function via `_value_for`, which will trigger autobootstrap.
45 sandbox
._value
_for
(sandbox
["bootstrap_path"]("fix-stacks"))
48 def initFixStacks(jsonMode
, slowWarning
, breakpadSymsDir
, hide_errors
):
49 # Look in MOZ_FETCHES_DIR (for automation), then in MOZBUILD_STATE_PATH
50 # (for a local build where the user has that set), then in ~/.mozbuild
51 # (for a local build with default settings).
52 base
= os
.environ
.get(
54 os
.environ
.get("MOZBUILD_STATE_PATH", os
.path
.expanduser("~/.mozbuild")),
56 fix_stacks_exe
= base
+ "/fix-stacks/fix-stacks"
57 if platform
.system() == "Windows":
58 fix_stacks_exe
= fix_stacks_exe
+ ".exe"
60 if not (os
.path
.isfile(fix_stacks_exe
) and os
.access(fix_stacks_exe
, os
.X_OK
)):
64 # We're out-of-tree (e.g. tests tasks on CI) and can't autobootstrap
65 # (we shouldn't anyways).
68 if not (os
.path
.isfile(fix_stacks_exe
) and os
.access(fix_stacks_exe
, os
.X_OK
)):
69 raise Exception("cannot find `fix-stacks`; please run `./mach bootstrap`")
71 args
= [fix_stacks_exe
]
76 args
.append(breakpadSymsDir
)
78 # Sometimes we need to prevent errors from going to stderr.
79 stderr
= open(os
.devnull
) if hide_errors
else None
83 args
, stdin
=PIPE
, stdout
=PIPE
, stderr
=stderr
, universal_newlines
=True
86 # Shut down the fix_stacks process on exit. We use `terminate()`
87 # because it is more forceful than `wait()`, and the Python docs warn
88 # about possible deadlocks with `wait()`.
89 def cleanup(fix_stacks
):
90 for fn
in [fix_stacks
.stdin
.close
, fix_stacks
.terminate
]:
96 atexit
.register(cleanup
, fix_stacks
)
100 "Initializing stack-fixing for the first stack frame, this may take a while..."
105 line
, jsonMode
=False, slowWarning
=False, breakpadSymsDir
=None, hide_errors
=False
107 is_bytes
= isinstance(line
, bytes
)
108 line_str
= line
.decode("utf-8") if is_bytes
else line
109 if line_re
.search(line_str
) is None:
113 initFixStacks(jsonMode
, slowWarning
, breakpadSymsDir
, hide_errors
)
115 # Sometimes `line` is lacking a trailing newline. If we pass such a `line`
116 # to `fix-stacks` it will wait until it receives a newline, causing this
117 # script to hang. So we add a newline if one is missing and then remove it
119 is_missing_newline
= not line_str
.endswith("\n")
120 if is_missing_newline
:
121 line_str
= line_str
+ "\n"
122 fix_stacks
.stdin
.write(line_str
)
123 fix_stacks
.stdin
.flush()
124 out
= fix_stacks
.stdout
.readline()
125 if is_missing_newline
:
128 if is_bytes
and not isinstance(out
, bytes
):
129 out
= out
.encode("utf-8")
133 if __name__
== "__main__":
134 for line
in sys
.stdin
:
135 sys
.stdout
.write(fixSymbols(line
))