31
31
import concurrent .futures
32
32
import contextlib
33
33
import datetime
34
+ import enum
34
35
import json
35
36
import os
36
37
import platform
45
46
import time
46
47
import uuid
47
48
48
-
49
49
print_lock = threading .RLock ()
50
50
51
51
try :
@@ -1582,9 +1582,12 @@ def synchronous(debugger):
1582
1582
debugger .RunCommandInterpreter (True , False , run_options , 0 , False , True )
1583
1583
1584
1584
1585
- def CreateSymbolicateCrashLogOptions (
1586
- command_name , description , add_interactive_options
1587
- ):
1585
+ class CrashLogLoadingMode (str , enum .Enum ):
1586
+ batch = "batch"
1587
+ interactive = "interactive"
1588
+
1589
+
1590
+ def CreateSymbolicateCrashLogOptions (command_name , description ):
1588
1591
usage = "crashlog [options] <FILE> [FILE ...]"
1589
1592
arg_parser = argparse .ArgumentParser (
1590
1593
description = description ,
@@ -1600,6 +1603,13 @@ def CreateSymbolicateCrashLogOptions(
1600
1603
help = "crash report(s) to symbolicate" ,
1601
1604
)
1602
1605
1606
+ arg_parser .add_argument (
1607
+ "-m" ,
1608
+ "--mode" ,
1609
+ choices = [mode .value for mode in CrashLogLoadingMode ],
1610
+ help = "change how the symbolicated process and threads are displayed to the user" ,
1611
+ default = CrashLogLoadingMode .interactive ,
1612
+ )
1603
1613
arg_parser .add_argument (
1604
1614
"--version" ,
1605
1615
"-V" ,
@@ -1736,36 +1746,35 @@ def CreateSymbolicateCrashLogOptions(
1736
1746
help = argparse .SUPPRESS ,
1737
1747
default = False ,
1738
1748
)
1739
- if add_interactive_options :
1740
- arg_parser .add_argument (
1741
- "-i" ,
1742
- "--interactive" ,
1743
- action = "store_true" ,
1744
- help = "parse a crash log and load it in a ScriptedProcess" ,
1745
- default = False ,
1746
- )
1747
- arg_parser .add_argument (
1748
- "-b" ,
1749
- "--batch" ,
1750
- action = "store_true" ,
1751
- help = "dump symbolicated stackframes without creating a debug session" ,
1752
- default = True ,
1753
- )
1754
- arg_parser .add_argument (
1755
- "--target" ,
1756
- "-t" ,
1757
- dest = "target_path" ,
1758
- help = "the target binary path that should be used for interactive crashlog (optional)" ,
1759
- default = None ,
1760
- )
1761
- arg_parser .add_argument (
1762
- "--skip-status" ,
1763
- "-s" ,
1764
- dest = "skip_status" ,
1765
- action = "store_true" ,
1766
- help = "prevent the interactive crashlog to dump the process status and thread backtrace at launch" ,
1767
- default = False ,
1768
- )
1749
+ arg_parser .add_argument (
1750
+ "--target" ,
1751
+ "-t" ,
1752
+ dest = "target_path" ,
1753
+ help = "the target binary path that should be used for interactive crashlog (optional)" ,
1754
+ default = None ,
1755
+ )
1756
+ arg_parser .add_argument (
1757
+ "--skip-status" ,
1758
+ "-s" ,
1759
+ dest = "skip_status" ,
1760
+ action = "store_true" ,
1761
+ help = "prevent the interactive crashlog to dump the process status and thread backtrace at launch" ,
1762
+ default = False ,
1763
+ )
1764
+ legacy_group = arg_parser .add_mutually_exclusive_group ()
1765
+ legacy_group .add_argument (
1766
+ "-i" ,
1767
+ "--interactive" ,
1768
+ action = "store_true" ,
1769
+ help = argparse .SUPPRESS ,
1770
+ )
1771
+ legacy_group .add_argument (
1772
+ "-b" ,
1773
+ "--batch" ,
1774
+ action = "store_true" ,
1775
+ help = argparse .SUPPRESS ,
1776
+ )
1777
+
1769
1778
return arg_parser
1770
1779
1771
1780
@@ -1778,7 +1787,7 @@ def CrashLogOptionParser():
1778
1787
created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows
1779
1788
you to explore the program as if it were stopped at the locations described in the crash log and functions can
1780
1789
be disassembled and lookups can be performed using the addresses found in the crash log."""
1781
- return CreateSymbolicateCrashLogOptions ("crashlog" , description , True )
1790
+ return CreateSymbolicateCrashLogOptions ("crashlog" , description )
1782
1791
1783
1792
1784
1793
def SymbolicateCrashLogs (debugger , command_args , result , is_command ):
@@ -1794,8 +1803,36 @@ def SymbolicateCrashLogs(debugger, command_args, result, is_command):
1794
1803
result .SetError (str (e ))
1795
1804
return
1796
1805
1806
+ # To avoid breaking existing users, we should keep supporting legacy flags
1807
+ # even if we don't use them / advertise them anymore.
1808
+ if options .interactive :
1809
+ options .mode = CrashLogLoadingMode .interactive
1810
+ elif options .batch :
1811
+ options .mode = CrashLogLoadingMode .batch
1812
+
1813
+ if (
1814
+ options .mode
1815
+ and options .mode != CrashLogLoadingMode .interactive
1816
+ and (options .target_path or options .skip_status )
1817
+ ):
1818
+ print (
1819
+ "Target path (-t) and skipping process status (-s) options can only used in interactive mode (-m=interactive)."
1820
+ )
1821
+ print ("Aborting symbolication." )
1822
+ arg_parser .print_help ()
1823
+ return
1824
+
1825
+ if options .version :
1826
+ print (debugger .GetVersionString ())
1827
+ return
1828
+
1829
+ if options .debug :
1830
+ print ("command_args = %s" % command_args )
1831
+ print ("options" , options )
1832
+ print ("args" , options .reports )
1833
+
1797
1834
# Interactive mode requires running the crashlog command from inside lldb.
1798
- if options .interactive and not is_command :
1835
+ if options .mode == CrashLogLoadingMode . interactive and not is_command :
1799
1836
lldb_exec = (
1800
1837
subprocess .check_output (["/usr/bin/xcrun" , "-f" , "lldb" ])
1801
1838
.decode ("utf-8" )
@@ -1821,31 +1858,24 @@ def SymbolicateCrashLogs(debugger, command_args, result, is_command):
1821
1858
print (debugger .GetVersionString ())
1822
1859
return
1823
1860
1824
- if options .debug :
1825
- print ("command_args = %s" % command_args )
1826
- print ("options" , options )
1827
- print ("args" , options .reports )
1828
-
1829
1861
if options .debug_delay > 0 :
1830
1862
print ("Waiting %u seconds for debugger to attach..." % options .debug_delay )
1831
1863
time .sleep (options .debug_delay )
1832
1864
error = lldb .SBError ()
1833
1865
1834
1866
def should_run_in_interactive_mode (options , ci ):
1835
- if options .interactive :
1867
+ if options .mode :
1868
+ return options .mode == CrashLogLoadingMode .interactive
1869
+ elif ci and ci .IsInteractive ():
1836
1870
return True
1837
- elif options .batch :
1838
- return False
1839
- # elif ci and ci.IsInteractive():
1840
- # return True
1841
1871
else :
1842
- return False
1872
+ return sys . stdout . isatty ()
1843
1873
1844
1874
ci = debugger .GetCommandInterpreter ()
1845
1875
1846
1876
if options .reports :
1847
1877
for crashlog_file in options .reports :
1848
- crashlog_path = os .path .expanduser (crashlog_file )
1878
+ crashlog_path = os .path .normpath ( os . path . expanduser (crashlog_file ) )
1849
1879
if not os .path .exists (crashlog_path ):
1850
1880
raise FileNotFoundError (
1851
1881
"crashlog file %s does not exist" % crashlog_path
0 commit comments