3131import concurrent .futures
3232import contextlib
3333import datetime
34+ import enum
3435import json
3536import os
3637import platform
4546import time
4647import uuid
4748
48-
4949print_lock = threading .RLock ()
5050
5151try :
@@ -1585,9 +1585,12 @@ def synchronous(debugger):
15851585 debugger .RunCommandInterpreter (True , False , run_options , 0 , False , True )
15861586
15871587
1588- def CreateSymbolicateCrashLogOptions (
1589- command_name , description , add_interactive_options
1590- ):
1588+ class CrashLogLoadingMode (str , enum .Enum ):
1589+ batch = "batch"
1590+ interactive = "interactive"
1591+
1592+
1593+ def CreateSymbolicateCrashLogOptions (command_name , description ):
15911594 usage = "crashlog [options] <FILE> [FILE ...]"
15921595 arg_parser = argparse .ArgumentParser (
15931596 description = description ,
@@ -1603,6 +1606,12 @@ def CreateSymbolicateCrashLogOptions(
16031606 help = "crash report(s) to symbolicate" ,
16041607 )
16051608
1609+ arg_parser .add_argument (
1610+ "-m" ,
1611+ "--mode" ,
1612+ choices = [mode .value for mode in CrashLogLoadingMode ],
1613+ help = "change how the symbolicated process and threads are displayed to the user (default: interactive)" ,
1614+ )
16061615 arg_parser .add_argument (
16071616 "--version" ,
16081617 "-V" ,
@@ -1739,36 +1748,35 @@ def CreateSymbolicateCrashLogOptions(
17391748 help = argparse .SUPPRESS ,
17401749 default = False ,
17411750 )
1742- if add_interactive_options :
1743- arg_parser .add_argument (
1744- "-i" ,
1745- "--interactive" ,
1746- action = "store_true" ,
1747- help = "parse a crash log and load it in a ScriptedProcess" ,
1748- default = False ,
1749- )
1750- arg_parser .add_argument (
1751- "-b" ,
1752- "--batch" ,
1753- action = "store_true" ,
1754- help = "dump symbolicated stackframes without creating a debug session" ,
1755- default = True ,
1756- )
1757- arg_parser .add_argument (
1758- "--target" ,
1759- "-t" ,
1760- dest = "target_path" ,
1761- help = "the target binary path that should be used for interactive crashlog (optional)" ,
1762- default = None ,
1763- )
1764- arg_parser .add_argument (
1765- "--skip-status" ,
1766- "-s" ,
1767- dest = "skip_status" ,
1768- action = "store_true" ,
1769- help = "prevent the interactive crashlog to dump the process status and thread backtrace at launch" ,
1770- default = False ,
1771- )
1751+ arg_parser .add_argument (
1752+ "--target" ,
1753+ "-t" ,
1754+ dest = "target_path" ,
1755+ help = "the target binary path that should be used for interactive crashlog (optional)" ,
1756+ default = None ,
1757+ )
1758+ arg_parser .add_argument (
1759+ "--skip-status" ,
1760+ "-s" ,
1761+ dest = "skip_status" ,
1762+ action = "store_true" ,
1763+ help = "prevent the interactive crashlog to dump the process status and thread backtrace at launch" ,
1764+ default = False ,
1765+ )
1766+ legacy_group = arg_parser .add_mutually_exclusive_group ()
1767+ legacy_group .add_argument (
1768+ "-i" ,
1769+ "--interactive" ,
1770+ action = "store_true" ,
1771+ help = argparse .SUPPRESS ,
1772+ )
1773+ legacy_group .add_argument (
1774+ "-b" ,
1775+ "--batch" ,
1776+ action = "store_true" ,
1777+ help = argparse .SUPPRESS ,
1778+ )
1779+
17721780 return arg_parser
17731781
17741782
@@ -1781,7 +1789,7 @@ def CrashLogOptionParser():
17811789created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows
17821790you to explore the program as if it were stopped at the locations described in the crash log and functions can
17831791be disassembled and lookups can be performed using the addresses found in the crash log."""
1784- return CreateSymbolicateCrashLogOptions ("crashlog" , description , True )
1792+ return CreateSymbolicateCrashLogOptions ("crashlog" , description )
17851793
17861794
17871795def SymbolicateCrashLogs (debugger , command_args , result , is_command ):
@@ -1797,8 +1805,35 @@ def SymbolicateCrashLogs(debugger, command_args, result, is_command):
17971805 result .SetError (str (e ))
17981806 return
17991807
1808+ # To avoid breaking existing users, we should keep supporting legacy flags
1809+ # even if we don't use them / advertise them anymore.
1810+ if not options .mode :
1811+ if options .batch :
1812+ options .mode = CrashLogLoadingMode .batch
1813+ else :
1814+ options .mode = CrashLogLoadingMode .interactive
1815+
1816+ if options .mode != CrashLogLoadingMode .interactive and (
1817+ options .target_path or options .skip_status
1818+ ):
1819+ print (
1820+ "Target path (-t) and skipping process status (-s) options can only used in interactive mode (-m=interactive)."
1821+ )
1822+ print ("Aborting symbolication." )
1823+ arg_parser .print_help ()
1824+ return
1825+
1826+ if options .version :
1827+ print (debugger .GetVersionString ())
1828+ return
1829+
1830+ if options .debug :
1831+ print ("command_args = %s" % command_args )
1832+ print ("options" , options )
1833+ print ("args" , options .reports )
1834+
18001835 # Interactive mode requires running the crashlog command from inside lldb.
1801- if options .interactive and not is_command :
1836+ if options .mode == CrashLogLoadingMode . interactive and not is_command :
18021837 lldb_exec = (
18031838 subprocess .check_output (["/usr/bin/xcrun" , "-f" , "lldb" ])
18041839 .decode ("utf-8" )
@@ -1824,31 +1859,26 @@ def SymbolicateCrashLogs(debugger, command_args, result, is_command):
18241859 print (debugger .GetVersionString ())
18251860 return
18261861
1827- if options .debug :
1828- print ("command_args = %s" % command_args )
1829- print ("options" , options )
1830- print ("args" , options .reports )
1831-
18321862 if options .debug_delay > 0 :
18331863 print ("Waiting %u seconds for debugger to attach..." % options .debug_delay )
18341864 time .sleep (options .debug_delay )
18351865 error = lldb .SBError ()
18361866
18371867 def should_run_in_interactive_mode (options , ci ):
1838- if options .interactive :
1839- return True
1840- elif options .batch :
1868+ if options .mode == CrashLogLoadingMode .batch :
18411869 return False
1842- # elif ci and ci.IsInteractive():
1843- # return True
1870+ elif options .mode == CrashLogLoadingMode .interactive or (
1871+ ci and ci .IsInteractive ()
1872+ ):
1873+ return True
18441874 else :
1845- return False
1875+ return sys . stdout . isatty ()
18461876
18471877 ci = debugger .GetCommandInterpreter ()
18481878
18491879 if options .reports :
18501880 for crashlog_file in options .reports :
1851- crashlog_path = os .path .expanduser (crashlog_file )
1881+ crashlog_path = os .path .normpath ( os . path . expanduser (crashlog_file ) )
18521882 if not os .path .exists (crashlog_path ):
18531883 raise FileNotFoundError (
18541884 "crashlog file %s does not exist" % crashlog_path
0 commit comments