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 :
@@ -1582,9 +1582,12 @@ def synchronous(debugger):
15821582 debugger .RunCommandInterpreter (True , False , run_options , 0 , False , True )
15831583
15841584
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 ):
15881591 usage = "crashlog [options] <FILE> [FILE ...]"
15891592 arg_parser = argparse .ArgumentParser (
15901593 description = description ,
@@ -1600,6 +1603,12 @@ def CreateSymbolicateCrashLogOptions(
16001603 help = "crash report(s) to symbolicate" ,
16011604 )
16021605
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 (default: interactive)" ,
1611+ )
16031612 arg_parser .add_argument (
16041613 "--version" ,
16051614 "-V" ,
@@ -1736,36 +1745,35 @@ def CreateSymbolicateCrashLogOptions(
17361745 help = argparse .SUPPRESS ,
17371746 default = False ,
17381747 )
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- )
1748+ arg_parser .add_argument (
1749+ "--target" ,
1750+ "-t" ,
1751+ dest = "target_path" ,
1752+ help = "the target binary path that should be used for interactive crashlog (optional)" ,
1753+ default = None ,
1754+ )
1755+ arg_parser .add_argument (
1756+ "--skip-status" ,
1757+ "-s" ,
1758+ dest = "skip_status" ,
1759+ action = "store_true" ,
1760+ help = "prevent the interactive crashlog to dump the process status and thread backtrace at launch" ,
1761+ default = False ,
1762+ )
1763+ legacy_group = arg_parser .add_mutually_exclusive_group ()
1764+ legacy_group .add_argument (
1765+ "-i" ,
1766+ "--interactive" ,
1767+ action = "store_true" ,
1768+ help = argparse .SUPPRESS ,
1769+ )
1770+ legacy_group .add_argument (
1771+ "-b" ,
1772+ "--batch" ,
1773+ action = "store_true" ,
1774+ help = argparse .SUPPRESS ,
1775+ )
1776+
17691777 return arg_parser
17701778
17711779
@@ -1778,7 +1786,7 @@ def CrashLogOptionParser():
17781786created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows
17791787you to explore the program as if it were stopped at the locations described in the crash log and functions can
17801788be disassembled and lookups can be performed using the addresses found in the crash log."""
1781- return CreateSymbolicateCrashLogOptions ("crashlog" , description , True )
1789+ return CreateSymbolicateCrashLogOptions ("crashlog" , description )
17821790
17831791
17841792def SymbolicateCrashLogs (debugger , command_args , result , is_command ):
@@ -1794,8 +1802,35 @@ def SymbolicateCrashLogs(debugger, command_args, result, is_command):
17941802 result .SetError (str (e ))
17951803 return
17961804
1805+ # To avoid breaking existing users, we should keep supporting legacy flags
1806+ # even if we don't use them / advertise them anymore.
1807+ if not options .mode :
1808+ if options .batch :
1809+ options .mode = CrashLogLoadingMode .batch
1810+ else :
1811+ options .mode = CrashLogLoadingMode .interactive
1812+
1813+ if options .mode != CrashLogLoadingMode .interactive and (
1814+ options .target_path or options .skip_status
1815+ ):
1816+ print (
1817+ "Target path (-t) and skipping process status (-s) options can only used in interactive mode (-m=interactive)."
1818+ )
1819+ print ("Aborting symbolication." )
1820+ arg_parser .print_help ()
1821+ return
1822+
1823+ if options .version :
1824+ print (debugger .GetVersionString ())
1825+ return
1826+
1827+ if options .debug :
1828+ print ("command_args = %s" % command_args )
1829+ print ("options" , options )
1830+ print ("args" , options .reports )
1831+
17971832 # Interactive mode requires running the crashlog command from inside lldb.
1798- if options .interactive and not is_command :
1833+ if options .mode == CrashLogLoadingMode . interactive and not is_command :
17991834 lldb_exec = (
18001835 subprocess .check_output (["/usr/bin/xcrun" , "-f" , "lldb" ])
18011836 .decode ("utf-8" )
@@ -1821,31 +1856,26 @@ def SymbolicateCrashLogs(debugger, command_args, result, is_command):
18211856 print (debugger .GetVersionString ())
18221857 return
18231858
1824- if options .debug :
1825- print ("command_args = %s" % command_args )
1826- print ("options" , options )
1827- print ("args" , options .reports )
1828-
18291859 if options .debug_delay > 0 :
18301860 print ("Waiting %u seconds for debugger to attach..." % options .debug_delay )
18311861 time .sleep (options .debug_delay )
18321862 error = lldb .SBError ()
18331863
18341864 def should_run_in_interactive_mode (options , ci ):
1835- if options .interactive :
1836- return True
1837- elif options .batch :
1865+ if options .mode == CrashLogLoadingMode .batch :
18381866 return False
1839- # elif ci and ci.IsInteractive():
1840- # return True
1867+ elif options .mode == CrashLogLoadingMode .interactive or (
1868+ ci and ci .IsInteractive ()
1869+ ):
1870+ return True
18411871 else :
1842- return False
1872+ return sys . stdout . isatty ()
18431873
18441874 ci = debugger .GetCommandInterpreter ()
18451875
18461876 if options .reports :
18471877 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 ) )
18491879 if not os .path .exists (crashlog_path ):
18501880 raise FileNotFoundError (
18511881 "crashlog file %s does not exist" % crashlog_path
0 commit comments