Skip to content

Commit eb06d8e

Browse files
committed
Update symbolicate-linux-fatal to bring in all 4.1 fixes/improvements
1 parent f6985b6 commit eb06d8e

File tree

1 file changed

+89
-39
lines changed

1 file changed

+89
-39
lines changed

utils/symbolicate-linux-fatal

Lines changed: 89 additions & 39 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
@@ -40,6 +42,11 @@ except ImportError:
4042
sys.path.append(site_packages)
4143
import lldb
4244

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

4451
def process_ldd(lddoutput):
4552
dyn_libs = {}
@@ -53,29 +60,18 @@ def process_ldd(lddoutput):
5360
return dyn_libs
5461

5562

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)
63+
def setup_lldb_target(binary, memmap):
64+
global lldb_target
65+
if not lldb_target:
66+
lldb_debugger = lldb.SBDebugger.Create()
67+
lldb_target = lldb_debugger.CreateTarget(binary)
68+
module = lldb_target.GetModuleAtIndex(0)
6069
for dynlib_path in memmap:
6170
module = lldb_target.AddModule(
6271
dynlib_path, lldb.LLDB_ARCH_DEFAULT, None, None)
6372
text_section = module.FindSection(".text")
6473
slide = text_section.GetFileAddress() - text_section.GetFileOffset()
6574
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 = {}
78-
7975

8076
def check_base_address(dynlib_path, dynlib_baseaddr, memmap):
8177
global known_memmap
@@ -91,7 +87,6 @@ def check_base_address(dynlib_path, dynlib_baseaddr, memmap):
9187
dynlib_path, existing_baseaddr, dynlib_baseaddr)
9288
raise Exception(error_msg)
9389

94-
9590
def symbolicate_one(frame_addr, frame_idx, dynlib_fname):
9691
global lldb_target
9792
so_addr = lldb_target.ResolveLoadAddress(frame_addr - 1)
@@ -115,12 +110,12 @@ def symbolicate_one(frame_addr, frame_idx, dynlib_fname):
115110
return "{0:s} {1:s} {2:s}".format(
116111
frame_fragment, symbol_fragment, line_fragment)
117112

118-
119-
def process_stack(binary, dyn_libs, stack):
113+
def get_processed_stack(binary, dyn_libs, stack):
120114
global lldb_target
121115
global known_memmap
116+
processed_stack = []
122117
if len(stack) == 0:
123-
return
118+
return processed_stack
124119
memmap = {}
125120
full_stack = []
126121
for line in stack:
@@ -150,21 +145,51 @@ def process_stack(binary, dyn_libs, stack):
150145
full_stack.append(
151146
{"line": line, "framePC": framePC, "dynlib_fname": dynlib_fname})
152147

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:
148+
setup_lldb_target(binary, memmap)
149+
150+
for frame_idx, frame in enumerate(full_stack):
159151
frame_addr = frame["framePC"]
160152
dynlib_fname = frame["dynlib_fname"]
161153
try:
162154
sym_line = symbolicate_one(frame_addr, frame_idx, dynlib_fname)
163-
print(sym_line)
155+
processed_stack.append(sym_line)
164156
except Exception:
165-
print(frame["line"].rstrip())
166-
frame_idx = frame_idx + 1
157+
processed_stack.append(frame["line"].rstrip())
158+
159+
return processed_stack
160+
161+
def is_fatal_error(line):
162+
return line.startswith("Fatal error:")
163+
164+
def is_stack_trace_header(line):
165+
return line.startswith("Current stack trace:")
166+
167+
def should_print_previous_line(current_line, previous_line):
168+
return is_fatal_error(previous_line) and not is_stack_trace_header(current_line)
169+
170+
def should_print_current_line(current_line, previous_line):
171+
return (not is_fatal_error(current_line) and not is_stack_trace_header(current_line)) or (is_stack_trace_header(current_line) and not is_fatal_error(previous_line))
172+
173+
def fatal_error_with_stack_trace_found(current_line, previous_line):
174+
return is_stack_trace_header(current_line) and is_fatal_error(previous_line)
175+
176+
def print_stack(fatal_error_header, fatal_error_stack_trace_header, fatal_log_format, processed_stack):
177+
if not fatal_error_header:
178+
for line in processed_stack:
179+
print_with_flush(line)
180+
else:
181+
#fatal error with a stack trace
182+
stack_str = fatal_error_header + fatal_error_stack_trace_header + '\n'.join(processed_stack)
183+
formatted_output = fatal_log_format
184+
185+
if "%t" in formatted_output:
186+
current_time = datetime.datetime.now()
187+
time_in_iso_format = current_time.strftime('%Y-%m-%dT%H:%M:%S,%f%z')
188+
formatted_output = formatted_output.replace("%t", time_in_iso_format)
189+
if "%m" in formatted_output:
190+
formatted_output = formatted_output.replace("%m", stack_str)
167191

192+
print_with_flush(formatted_output)
168193

169194
def main():
170195
parser = argparse.ArgumentParser(
@@ -175,35 +200,60 @@ def main():
175200
parser.add_argument(
176201
"log", nargs='?', type=argparse.FileType("rU"), default="-",
177202
help="Log file for symbolication. Defaults to stdin.")
203+
parser.add_argument(
204+
"--fatal-log-format", default="%m",
205+
help="Format for logging fatal errors. Variable %%t will be replaced with current time in ISO 8601 format, variable %%m will be replaced with the error message with a full stack trace.")
178206
args = parser.parse_args()
179207

180208
binary = args.binary
209+
fatal_log_format = args.fatal_log_format
181210

182211
lddoutput = subprocess.check_output(
183212
['ldd', binary], stderr=subprocess.STDOUT)
184213
dyn_libs = process_ldd(lddoutput)
185214

186215
instack = False
216+
previous_line = ""
187217
stackidx = 0
188218
stack = []
219+
fatal_error_header = ""
220+
fatal_error_stack_trace_header = ""
189221

190222
while True:
191-
line = args.log.readline()
192-
if not line:
223+
current_line = args.log.readline()
224+
if not current_line:
193225
break
194-
if instack and line.startswith(str(stackidx)):
195-
stack.append(line)
226+
if instack and current_line.startswith(str(stackidx)):
227+
stack.append(current_line)
196228
stackidx = stackidx + 1
197229
else:
230+
processed_stack = get_processed_stack(binary, dyn_libs, stack)
231+
print_stack(fatal_error_header, fatal_error_stack_trace_header, fatal_log_format, processed_stack)
232+
198233
instack = False
199234
stackidx = 0
200-
process_stack(binary, dyn_libs, stack)
201235
stack = []
202-
print(line.rstrip())
203-
if line.startswith("Current stack trace:"):
204-
instack = True
205-
process_stack(binary, dyn_libs, stack)
236+
fatal_error_header = ""
237+
fatal_error_stack_trace_header = ""
238+
239+
if is_stack_trace_header(current_line):
240+
instack = True
241+
242+
if should_print_previous_line(current_line, previous_line):
243+
print_with_flush(previous_line.rstrip())
244+
245+
if should_print_current_line(current_line, previous_line):
246+
print_with_flush(current_line.rstrip())
247+
248+
if fatal_error_with_stack_trace_found(current_line, previous_line):
249+
fatal_error_header = previous_line
250+
fatal_error_stack_trace_header = current_line
206251

252+
previous_line = current_line
253+
if is_fatal_error(previous_line):
254+
print_with_flush(previous_line.rstrip())
255+
processed_stack = get_processed_stack(binary, dyn_libs, stack)
256+
print_stack(fatal_error_header, fatal_error_stack_trace_header, fatal_log_format, processed_stack)
207257

208258
if __name__ == '__main__':
209259
main()

0 commit comments

Comments
 (0)