Skip to content

Commit fb52a2e

Browse files
authored
Merge pull request #20681 from apple/fix-symbolicate-linux-fatal-for-streaming-stacktraces-2
Fix symbolicate linux fatal for streaming stacktraces 2
2 parents c3e84ec + 820d5f3 commit fb52a2e

File tree

1 file changed

+120
-37
lines changed

1 file changed

+120
-37
lines changed

utils/symbolicate-linux-fatal

Lines changed: 120 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
from __future__ import print_function
2626

2727
import argparse
28+
import datetime
2829
import os
2930
import subprocess
31+
import sys
3032

3133
try:
3234
import lldb
@@ -36,10 +38,17 @@ except ImportError:
3638
if swift_exec is not None:
3739
site_packages = os.path.join(os.path.dirname(swift_exec),
3840
'../lib/python2.7/site-packages/')
39-
import sys
4041
sys.path.append(site_packages)
4142
import lldb
4243

44+
lldb_target = None
45+
known_memmap = {}
46+
47+
48+
def print_with_flush(buff):
49+
print(buff)
50+
sys.stdout.flush()
51+
4352

4453
def process_ldd(lddoutput):
4554
dyn_libs = {}
@@ -53,28 +62,18 @@ def process_ldd(lddoutput):
5362
return dyn_libs
5463

5564

56-
def create_lldb_target(binary, memmap):
57-
lldb_debugger = lldb.SBDebugger.Create()
58-
lldb_target = lldb_debugger.CreateTarget(binary)
59-
module = lldb_target.GetModuleAtIndex(0)
65+
def setup_lldb_target(binary, memmap):
66+
global lldb_target
67+
if not lldb_target:
68+
lldb_debugger = lldb.SBDebugger.Create()
69+
lldb_target = lldb_debugger.CreateTarget(binary)
70+
module = lldb_target.GetModuleAtIndex(0)
6071
for dynlib_path in memmap:
6172
module = lldb_target.AddModule(
6273
dynlib_path, lldb.LLDB_ARCH_DEFAULT, None, None)
6374
text_section = module.FindSection(".text")
6475
slide = text_section.GetFileAddress() - text_section.GetFileOffset()
6576
lldb_target.SetModuleLoadAddress(module, memmap[dynlib_path] - slide)
66-
return lldb_target
67-
68-
69-
def add_lldb_target_modules(lldb_target, memmap):
70-
for dynlib_path in memmap:
71-
module = lldb_target.AddModule(
72-
dynlib_path, lldb.LLDB_ARCH_DEFAULT, None, None)
73-
lldb_target.SetModuleLoadAddress(module, memmap[dynlib_path])
74-
75-
76-
lldb_target = None
77-
known_memmap = {}
7877

7978

8079
def check_base_address(dynlib_path, dynlib_baseaddr, memmap):
@@ -116,11 +115,12 @@ def symbolicate_one(frame_addr, frame_idx, dynlib_fname):
116115
frame_fragment, symbol_fragment, line_fragment)
117116

118117

119-
def process_stack(binary, dyn_libs, stack):
118+
def get_processed_stack(binary, dyn_libs, stack):
120119
global lldb_target
121120
global known_memmap
121+
processed_stack = []
122122
if len(stack) == 0:
123-
return
123+
return processed_stack
124124
memmap = {}
125125
full_stack = []
126126
for line in stack:
@@ -150,20 +150,68 @@ def process_stack(binary, dyn_libs, stack):
150150
full_stack.append(
151151
{"line": line, "framePC": framePC, "dynlib_fname": dynlib_fname})
152152

153-
if lldb_target is None:
154-
lldb_target = create_lldb_target(binary, memmap)
155-
else:
156-
add_lldb_target_modules(lldb_target, memmap)
157-
frame_idx = 0
158-
for frame in full_stack:
153+
setup_lldb_target(binary, memmap)
154+
155+
for frame_idx, frame in enumerate(full_stack):
159156
frame_addr = frame["framePC"]
160157
dynlib_fname = frame["dynlib_fname"]
161158
try:
162159
sym_line = symbolicate_one(frame_addr, frame_idx, dynlib_fname)
163-
print(sym_line)
160+
processed_stack.append(sym_line)
164161
except Exception:
165-
print(frame["line"].rstrip())
166-
frame_idx = frame_idx + 1
162+
processed_stack.append(frame["line"].rstrip())
163+
164+
return processed_stack
165+
166+
167+
def is_fatal_error(line):
168+
return line.startswith("Fatal error:")
169+
170+
171+
def is_stack_trace_header(line):
172+
return line.startswith("Current stack trace:")
173+
174+
175+
def should_print_previous_line(current_line, previous_line):
176+
return is_fatal_error(previous_line) and \
177+
not is_stack_trace_header(current_line)
178+
179+
180+
def should_print_current_line(current_line, previous_line):
181+
return (not is_fatal_error(current_line) and
182+
not is_stack_trace_header(current_line)) or \
183+
(is_stack_trace_header(current_line) and
184+
not is_fatal_error(previous_line))
185+
186+
187+
def fatal_error_with_stack_trace_found(current_line, previous_line):
188+
return is_stack_trace_header(current_line) and \
189+
is_fatal_error(previous_line)
190+
191+
192+
def print_stack(fatal_error_header,
193+
fatal_error_stack_trace_header,
194+
fatal_log_format,
195+
processed_stack):
196+
if not fatal_error_header:
197+
for line in processed_stack:
198+
print_with_flush(line)
199+
else:
200+
# fatal error with a stack trace
201+
stack_str = fatal_error_header + fatal_error_stack_trace_header + \
202+
'\n'.join(processed_stack)
203+
formatted_output = fatal_log_format
204+
205+
if "%t" in formatted_output:
206+
current_time = datetime.datetime.now()
207+
time_in_iso_format = \
208+
current_time.strftime('%Y-%m-%dT%H:%M:%S,%f%z')
209+
formatted_output = \
210+
formatted_output.replace("%t", time_in_iso_format)
211+
if "%m" in formatted_output:
212+
formatted_output = formatted_output.replace("%m", stack_str)
213+
214+
print_with_flush(formatted_output)
167215

168216

169217
def main():
@@ -175,34 +223,69 @@ def main():
175223
parser.add_argument(
176224
"log", nargs='?', type=argparse.FileType("rU"), default="-",
177225
help="Log file for symbolication. Defaults to stdin.")
226+
parser.add_argument(
227+
"--fatal-log-format", default="%m",
228+
help="Format for logging fatal errors. Variable %%t will be "
229+
"replaced with current time in ISO 8601 format, variable "
230+
"%%m will be replaced with the error message with a full "
231+
"stack trace.")
178232
args = parser.parse_args()
179233

180234
binary = args.binary
235+
fatal_log_format = args.fatal_log_format
181236

182237
lddoutput = subprocess.check_output(
183238
['ldd', binary], stderr=subprocess.STDOUT)
184239
dyn_libs = process_ldd(lddoutput)
185240

186241
instack = False
242+
previous_line = ""
187243
stackidx = 0
188244
stack = []
245+
fatal_error_header = ""
246+
fatal_error_stack_trace_header = ""
189247

190248
while True:
191-
line = args.log.readline()
192-
if not line:
249+
current_line = args.log.readline()
250+
if not current_line:
193251
break
194-
if instack and line.startswith(str(stackidx)):
195-
stack.append(line)
252+
if instack and current_line.startswith(str(stackidx)):
253+
stack.append(current_line)
196254
stackidx = stackidx + 1
197255
else:
256+
processed_stack = get_processed_stack(binary, dyn_libs, stack)
257+
print_stack(fatal_error_header,
258+
fatal_error_stack_trace_header,
259+
fatal_log_format,
260+
processed_stack)
261+
198262
instack = False
199263
stackidx = 0
200-
process_stack(binary, dyn_libs, stack)
201264
stack = []
202-
print(line.rstrip())
203-
if line.startswith("Current stack trace:"):
204-
instack = True
205-
process_stack(binary, dyn_libs, stack)
265+
fatal_error_header = ""
266+
fatal_error_stack_trace_header = ""
267+
268+
if is_stack_trace_header(current_line):
269+
instack = True
270+
271+
if should_print_previous_line(current_line, previous_line):
272+
print_with_flush(previous_line.rstrip())
273+
274+
if should_print_current_line(current_line, previous_line):
275+
print_with_flush(current_line.rstrip())
276+
277+
if fatal_error_with_stack_trace_found(current_line, previous_line):
278+
fatal_error_header = previous_line
279+
fatal_error_stack_trace_header = current_line
280+
281+
previous_line = current_line
282+
if is_fatal_error(previous_line):
283+
print_with_flush(previous_line.rstrip())
284+
processed_stack = get_processed_stack(binary, dyn_libs, stack)
285+
print_stack(fatal_error_header,
286+
fatal_error_stack_trace_header,
287+
fatal_log_format,
288+
processed_stack)
206289

207290

208291
if __name__ == '__main__':

0 commit comments

Comments
 (0)