mib updated this revision to Diff 409335.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119501/new/

https://reviews.llvm.org/D119501

Files:
  lldb/bindings/python/CMakeLists.txt
  lldb/examples/python/crashlog.py
  lldb/examples/python/scripted_process/crashlog_scripted_process.py
  lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
  lldb/test/Shell/ScriptInterpreter/Python/Crashlog/Inputs/scripted_crashlog.ips
  lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test

Index: lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test
@@ -0,0 +1,10 @@
+# RUN: %clang_host -g %S/Inputs/test.c -o %t.out
+
+# RUN: cp %S/Inputs/scripted_crashlog.ips %t.crash
+# RUN: %python %S/patch-crashlog.py --binary %t.out --crashlog %t.crash --offsets '{"main":20, "bar":9, "foo":16}' --json
+# RUN: %lldb %t.out -o 'command script import lldb.macosx.crashlog' -o 'crashlog -i %t.crash' -o 'process status' 2>&1 | FileCheck %s
+
+# CHECK: "crashlog" {{.*}} commands have been installed, use the "--help" options on these commands
+# CHECK: Process 92190 stopped
+# CHECK: * thread #1, name = 'CrashLogScriptedThread.thread-0', stop reason = EXC_BAD_ACCESS
+# CHECK: frame #0: 0x0000000104a23f68 scripted_crashlog_json.test.tmp.out`foo at test.c:3:6 [artificial]
Index: lldb/test/Shell/ScriptInterpreter/Python/Crashlog/Inputs/scripted_crashlog.ips
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Python/Crashlog/Inputs/scripted_crashlog.ips
@@ -0,0 +1,95 @@
+{"app_name":"scripted_crashlog_json.test.tmp.out","timestamp":"2022-02-14 16:30:31.00 -0800","app_version":"","slice_uuid":"b928ee77-9429-334f-ac88-41440bb3d4c7","build_version":"","platform":1,"share_with_app_devs":0,"is_first_party":1,"bug_type":"309","os_version":"macOS 12.3 (21E209)","incident_id":"E57CADE7-DC44-45CE-8D16-18EBC4406B97","name":"scripted_crashlog_json.test.tmp.out"}
+{
+  "uptime" : 260000,
+  "procLaunch" : "2022-02-14 16:30:31.8048 -0800",
+  "procRole" : "Unspecified",
+  "version" : 2,
+  "userID" : 501,
+  "deployVersion" : 210,
+  "modelCode" : "MacBookPro18,2",
+  "procStartAbsTime" : 6478056069413,
+  "coalitionID" : 22196,
+  "osVersion" : {
+    "train" : "macOS 12.3",
+    "build" : "",
+    "releaseType" : ""
+  },
+  "captureTime" : "2022-02-14 16:30:31.8096 -0800",
+  "incident" : "E57CADE7-DC44-45CE-8D16-18EBC4406B97",
+  "bug_type" : "309",
+  "pid" : 92190,
+  "procExitAbsTime" : 6478056175721,
+  "translated" : false,
+  "cpuType" : "ARM-64",
+  "procName" : "scripted_crashlog_json.test.tmp.out",
+  "procPath" : "\/Users\/USER\/*\/scripted_crashlog_json.test.tmp.out",
+  "parentProc" : "zsh",
+  "parentPid" : 82132,
+  "coalitionName" : "com.apple.Terminal",
+  "crashReporterKey" : "CDC11418-EDBF-2A49-0D83-8B441A5004B0",
+  "responsiblePid" : 76395,
+  "responsibleProc" : "Terminal",
+  "wakeTime" : 14889,
+  "sleepWakeUUID" : "BCA947AE-2F0A-44C7-8445-FEDFFA236CD0",
+  "sip" : "enabled",
+  "vmRegionInfo" : "0 is not in any region.  Bytes before following region: 4372692992\n      REGION TYPE                    START - END         [ VSIZE] PRT\/MAX SHRMOD  REGION DETAIL\n      UNUSED SPACE AT START\n--->  \n      __TEXT                      104a20000-104a24000    [   16K] r-x\/r-x SM=COW  ....test.tmp.out",
+  "isCorpse" : 1,
+  "exception" : {"codes":"0x0000000000000001, 0x0000000000000000","rawCodes":[1,0],"type":"EXC_BAD_ACCESS","signal":"SIGSEGV","subtype":"KERN_INVALID_ADDRESS at 0x0000000000000000"},
+  "termination" : {"flags":0,"code":11,"namespace":"SIGNAL","indicator":"Segmentation fault: 11","byProc":"exc handler","byPid":92190},
+  "vmregioninfo" : "0 is not in any region.  Bytes before following region: 4372692992\n      REGION TYPE                    START - END         [ VSIZE] PRT\/MAX SHRMOD  REGION DETAIL\n      UNUSED SPACE AT START\n--->  \n      __TEXT                      104a20000-104a24000    [   16K] r-x\/r-x SM=COW  ....test.tmp.out",
+  "extMods" : {"caller":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"system":{"thread_create":0,"thread_set_state":156,"task_for_pid":28},"targeted":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"warnings":0},
+  "faultingThread" : 0,
+  "threads" : [{"triggered":true,"id":4567339,"threadState":{"x":[{"value":1},{"value":6094187136},{"value":6094187152},{"value":6094187720},{"value":0},{"value":0},{"value":0},{"value":0},{"value":1},{"value":0},{"value":0},{"value":2},{"value":2},{"value":0},{"value":80},{"value":0},{"value":13118353544},{"value":7701436843874442528},{"value":0},{"value":4373676128},{"sourceLine":8,"value":4372709256,"sourceFile":"test.c","symbol":"main","symbolLocation":0},{"value":4373332080,"symbolLocation":0,"symbol":"dyld4::sConfigBuffer"},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":4372709248},"cpsr":{"value":1610616832},"fp":{"value":6094186736},"sp":{"value":6094186720},"esr":{"value":2449473606,"description":"(Data Abort) byte write Translation fault"},"pc":{"value":4372709224,"matchesCrashFrame":1},"far":{"value":0}},"queue":"com.apple.main-thread","frames":[{"imageOffset":16232,"sourceLine":3,"sourceFile":"test.c","symbol":"foo","imageIndex":0,"symbolLocation":16},{"imageOffset":16256,"sourceLine":6,"sourceFile":"test.c","symbol":"bar","imageIndex":0,"symbolLocation":12},{"imageOffset":16288,"sourceLine":8,"sourceFile":"test.c","symbol":"main","imageIndex":0,"symbolLocation":24},{"imageOffset":20620,"symbol":"start","symbolLocation":520,"imageIndex":1}]}],
+  "usedImages" : [
+  {
+    "source" : "P",
+    "arch" : "arm64",
+    "base" : 4372692992,
+    "size" : 16384,
+    "uuid" : "b928ee77-9429-334f-ac88-41440bb3d4c7",
+    "path" : "\/Users\/USER\/*\/scripted_crashlog_json.test.tmp.out",
+    "name" : "scripted_crashlog_json.test.tmp.out"
+  },
+  {
+    "source" : "P",
+    "arch" : "arm64e",
+    "base" : 4372938752,
+    "size" : 393216,
+    "uuid" : "41293cda-474b-3700-924e-6ba0f7698eac",
+    "path" : "\/usr\/lib\/dyld",
+    "name" : "dyld"
+  }
+],
+  "sharedCache" : {
+  "base" : 6924156928,
+  "size" : 3151052800,
+  "uuid" : "2ff78c31-e522-3e4a-a414-568e926f7274"
+},
+  "vmSummary" : "ReadOnly portion of Libraries: Total=589.5M resident=0K(0%) swapped_out_or_unallocated=589.5M(100%)\nWritable regions: Total=529.1M written=0K(0%) resident=0K(0%) swapped_out=0K(0%) unallocated=529.1M(100%)\n\n                                VIRTUAL   REGION \nREGION TYPE                        SIZE    COUNT (non-coalesced) \n===========                     =======  ======= \nKernel Alloc Once                   32K        1 \nMALLOC                           137.2M       11 \nMALLOC guard page                   96K        5 \nMALLOC_NANO (reserved)           384.0M        1         reserved VM address space (unallocated)\nSTACK GUARD                       56.0M        1 \nStack                             8176K        1 \n__AUTH                              46K       11 \n__AUTH_CONST                        67K       38 \n__DATA                             173K       36 \n__DATA_CONST                       242K       39 \n__DATA_DIRTY                        73K       21 \n__LINKEDIT                       584.9M        3 \n__OBJC_CONST                        10K        5 \n__OBJC_RO                         82.9M        1 \n__OBJC_RW                         3168K        1 \n__TEXT                            4696K       43 \ndyld private memory               1024K        1 \nshared memory                       48K        2 \n===========                     =======  ======= \nTOTAL                              1.2G      221 \nTOTAL, minus reserved VM space   878.5M      221 \n",
+  "legacyInfo" : {
+  "threadTriggered" : {
+    "queue" : "com.apple.main-thread"
+  }
+},
+  "trialInfo" : {
+  "rollouts" : [
+    {
+      "rolloutId" : "60186475825c62000ccf5450",
+      "factorPackIds" : {
+        "SIRI_VALUE_INFERENCE_CONTACT_RESOLUTION" : "601864d8825c62000ccf5451"
+      },
+      "deploymentId" : 230000005
+    },
+    {
+      "rolloutId" : "61030413bfe6dc472e1c980c",
+      "factorPackIds" : {
+
+      },
+      "deploymentId" : 230000183
+    }
+  ],
+  "experiments" : [
+
+  ]
+}
+}
Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -303,6 +303,9 @@
 
   StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
 
+  // FIXME: Need to sort the dictionary otherwise the thread ids won't match the
+  // thread indices.
+
   if (!thread_info_sp)
     return ScriptedInterface::ErrorWithMessage<bool>(
         LLVM_PRETTY_FUNCTION,
Index: lldb/examples/python/scripted_process/crashlog_scripted_process.py
===================================================================
--- /dev/null
+++ lldb/examples/python/scripted_process/crashlog_scripted_process.py
@@ -0,0 +1,148 @@
+import os,json,struct,signal
+
+from typing import Any, Dict
+
+import lldb
+from lldb.plugins.scripted_process import ScriptedProcess
+from lldb.plugins.scripted_process import ScriptedThread
+
+from lldb.macosx.crashlog import CrashLog,CrashLogParser
+
+class CrashLogScriptedProcess(ScriptedProcess):
+    def parse_crashlog(self):
+        try:
+            crash_log = CrashLogParser().parse(self.dbg, self.crashlog_path, False)
+        except Exception as e:
+            return
+
+        self.pid = crash_log.process_id
+        self.crashed_thread_idx = crash_log.crashed_thread_idx
+        self.loaded_images = []
+
+        for thread in crash_log.threads:
+            if thread.did_crash():
+                for ident in thread.idents:
+                    images = crash_log.find_images_with_identifier(ident)
+                    if images:
+                        for image in images:
+                            #TODO: Add to self.loaded_images and load images in lldb
+                            err = image.add_module(self.target)
+                            if err:
+                                print(err)
+                            else:
+                                self.loaded_images.append(image)
+            self.threads[thread.index] = CrashLogScriptedThread(self, None, thread)
+
+    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
+        super().__init__(target, args)
+
+        if not self.target or not self.target.IsValid():
+            return
+
+        self.crashlog_path = None
+
+        crashlog_path = args.GetValueForKey("crashlog_path")
+        if crashlog_path and crashlog_path.IsValid():
+            if crashlog_path.GetType() == lldb.eStructuredDataTypeString:
+                self.crashlog_path = crashlog_path.GetStringValue(4096)
+
+        if not self.crashlog_path:
+            return
+
+        self.pid = super().get_process_id()
+        self.crashed_thread_idx = 0
+        self.parse_crashlog()
+
+    def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
+        return None
+
+    def get_thread_with_id(self, tid: int):
+        return {}
+
+    def get_registers_for_thread(self, tid: int):
+        return {}
+
+    def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
+        # NOTE: CrashLogs don't contain any memory.
+        return lldb.SBData()
+
+    def get_loaded_images(self):
+        # TODO: Iterate over corefile_target modules and build a data structure
+        # from it.
+        return self.loaded_images
+
+    def get_process_id(self) -> int:
+        return self.pid
+
+    def should_stop(self) -> bool:
+        return True
+
+    def is_alive(self) -> bool:
+        return True
+
+    def get_scripted_thread_plugin(self):
+        return CrashLogScriptedThread.__module__ + "." + CrashLogScriptedThread.__name__
+
+class CrashLogScriptedThread(ScriptedThread):
+    def create_register_ctx(self):
+        if not self.has_crashed:
+            return dict.fromkeys([*map(lambda reg: reg['name'], self.register_info['registers'])] , 0)
+
+        if not self.backing_thread or not len(self.backing_thread.registers):
+            return dict.fromkeys([*map(lambda reg: reg['name'], self.register_info['registers'])] , 0)
+
+        for reg in self.register_info['registers']:
+            reg_name = reg['name']
+            if reg_name in self.backing_thread.registers:
+                self.register_ctx[reg_name] = self.backing_thread.registers[reg_name]
+            else:
+                self.register_ctx[reg_name] = 0
+
+        return self.register_ctx
+
+    def create_stackframes(self):
+        if not self.has_crashed:
+            return None
+
+        if not self.backing_thread or not len(self.backing_thread.frames):
+            return None
+
+        for frame in self.backing_thread.frames:
+            sym_addr = lldb.SBAddress()
+            sym_addr.SetLoadAddress(frame.pc, self.target)
+            if not sym_addr.IsValid():
+                continue
+            self.frames.append({"idx": frame.index, "pc": frame.pc})
+
+        return self.frames
+
+    def __init__(self, process, args, crashlog_thread):
+        super().__init__(process, args)
+
+        self.backing_thread = crashlog_thread
+        self.idx = self.backing_thread.index
+        self.has_crashed = (self.scripted_process.crashed_thread_idx == self.idx)
+        self.create_stackframes()
+
+    def get_thread_id(self) -> int:
+        return self.idx
+
+    def get_name(self) -> str:
+        return CrashLogScriptedThread.__name__ + ".thread-" + str(self.idx)
+
+    def get_state(self):
+        if not self.has_crashed:
+            return lldb.eStateStopped
+        return lldb.eStateCrashed
+
+    def get_stop_reason(self) -> Dict[str, Any]:
+        if not self.has_crashed:
+            return { "type": lldb.eStopReasonNone, "data": {  }}
+        # TODO: Investigate what stop reason should be reported when crashed
+        return { "type": lldb.eStopReasonException, "data": { "desc": "EXC_BAD_ACCESS" }}
+
+    def get_register_context(self) -> str:
+        if not self.register_ctx:
+            self.register_ctx = self.create_register_ctx()
+
+        return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values())
Index: lldb/examples/python/crashlog.py
===================================================================
--- lldb/examples/python/crashlog.py
+++ lldb/examples/python/crashlog.py
@@ -63,7 +63,6 @@
 
 from lldb.utils import symbolication
 
-
 def read_plist(s):
     if sys.version_info.major == 3:
         return plistlib.loads(s)
@@ -768,138 +767,6 @@
     sys.exit(0)
 
 
-class Interactive(cmd.Cmd):
-    '''Interactive prompt for analyzing one or more Darwin crash logs, type "help" to see a list of supported commands.'''
-    image_option_parser = None
-
-    def __init__(self, crash_logs):
-        cmd.Cmd.__init__(self)
-        self.use_rawinput = False
-        self.intro = 'Interactive crashlogs prompt, type "help" to see a list of supported commands.'
-        self.crash_logs = crash_logs
-        self.prompt = '% '
-
-    def default(self, line):
-        '''Catch all for unknown command, which will exit the interpreter.'''
-        print("uknown command: %s" % line)
-        return True
-
-    def do_q(self, line):
-        '''Quit command'''
-        return True
-
-    def do_quit(self, line):
-        '''Quit command'''
-        return True
-
-    def do_symbolicate(self, line):
-        description = '''Symbolicate one or more darwin crash log files by index to provide source file and line information,
-        inlined stack frames back to the concrete functions, and disassemble the location of the crash
-        for the first frame of the crashed thread.'''
-        option_parser = CreateSymbolicateCrashLogOptions(
-            'symbolicate', description, False)
-        command_args = shlex.split(line)
-        try:
-            (options, args) = option_parser.parse_args(command_args)
-        except:
-            return
-
-        if args:
-            # We have arguments, they must valid be crash log file indexes
-            for idx_str in args:
-                idx = int(idx_str)
-                if idx < len(self.crash_logs):
-                    SymbolicateCrashLog(self.crash_logs[idx], options)
-                else:
-                    print('error: crash log index %u is out of range' % (idx))
-        else:
-            # No arguments, symbolicate all crash logs using the options
-            # provided
-            for idx in range(len(self.crash_logs)):
-                SymbolicateCrashLog(self.crash_logs[idx], options)
-
-    def do_list(self, line=None):
-        '''Dump a list of all crash logs that are currently loaded.
-
-        USAGE: list'''
-        print('%u crash logs are loaded:' % len(self.crash_logs))
-        for (crash_log_idx, crash_log) in enumerate(self.crash_logs):
-            print('[%u] = %s' % (crash_log_idx, crash_log.path))
-
-    def do_image(self, line):
-        '''Dump information about one or more binary images in the crash log given an image basename, or all images if no arguments are provided.'''
-        usage = "usage: %prog [options] <PATH> [PATH ...]"
-        description = '''Dump information about one or more images in all crash logs. The <PATH> can be a full path, image basename, or partial path. Searches are done in this order.'''
-        command_args = shlex.split(line)
-        if not self.image_option_parser:
-            self.image_option_parser = optparse.OptionParser(
-                description=description, prog='image', usage=usage)
-            self.image_option_parser.add_option(
-                '-a',
-                '--all',
-                action='store_true',
-                help='show all images',
-                default=False)
-        try:
-            (options, args) = self.image_option_parser.parse_args(command_args)
-        except:
-            return
-
-        if args:
-            for image_path in args:
-                fullpath_search = image_path[0] == '/'
-                for (crash_log_idx, crash_log) in enumerate(self.crash_logs):
-                    matches_found = 0
-                    for (image_idx, image) in enumerate(crash_log.images):
-                        if fullpath_search:
-                            if image.get_resolved_path() == image_path:
-                                matches_found += 1
-                                print('[%u] ' % (crash_log_idx), image)
-                        else:
-                            image_basename = image.get_resolved_path_basename()
-                            if image_basename == image_path:
-                                matches_found += 1
-                                print('[%u] ' % (crash_log_idx), image)
-                    if matches_found == 0:
-                        for (image_idx, image) in enumerate(crash_log.images):
-                            resolved_image_path = image.get_resolved_path()
-                            if resolved_image_path and string.find(
-                                    image.get_resolved_path(), image_path) >= 0:
-                                print('[%u] ' % (crash_log_idx), image)
-        else:
-            for crash_log in self.crash_logs:
-                for (image_idx, image) in enumerate(crash_log.images):
-                    print('[%u] %s' % (image_idx, image))
-        return False
-
-
-def interactive_crashlogs(debugger, options, args):
-    crash_log_files = list()
-    for arg in args:
-        for resolved_path in glob.glob(arg):
-            crash_log_files.append(resolved_path)
-
-    crash_logs = list()
-    for crash_log_file in crash_log_files:
-        try:
-            crash_log = CrashLogParser().parse(debugger, crash_log_file, options.verbose)
-        except Exception as e:
-            print(e)
-            continue
-        if options.debug:
-            crash_log.dump()
-        if not crash_log.images:
-            print('error: no images in crash log "%s"' % (crash_log))
-            continue
-        else:
-            crash_logs.append(crash_log)
-
-    interpreter = Interactive(crash_logs)
-    # List all crash logs that were imported
-    interpreter.do_list()
-    interpreter.cmdloop()
-
-
 def save_crashlog(debugger, command, exe_ctx, result, dict):
     usage = "usage: %prog [options] <output-path>"
     description = '''Export the state of current target into a crashlog file'''
@@ -1094,6 +961,43 @@
         for error in crash_log.errors:
             print(error)
 
+def load_crashlog_in_scripted_process(debugger, crash_log_file):
+    result = lldb.SBCommandReturnObject()
+
+    crashlog_path = os.path.expanduser(crash_log_file)
+    if not os.path.exists(crashlog_path):
+        result.PutCString("error: crashlog file %s does not exist" % crashlog_path)
+
+    try:
+        crashlog = CrashLogParser().parse(debugger, crashlog_path, False)
+    except Exception as e:
+        result.PutCString("error: python exception: %s" % e)
+        return
+
+    target = crashlog.create_target()
+    if not target:
+        result.PutCString("error: couldn't create target")
+        return
+
+    ci = debugger.GetCommandInterpreter()
+    if not ci:
+        result.PutCString("error: couldn't get command interpreter")
+        return
+
+    res = lldb.SBCommandReturnObject()
+    ci.HandleCommand('script from lldb.macosx import crashlog_scripted_process', res)
+    if not res.Succeeded():
+        result.PutCString("error: couldn't import crashlog scripted process module")
+        return
+
+    structured_data = lldb.SBStructuredData()
+    structured_data.SetFromJSON(json.dumps({ "crashlog_path" : crashlog_path }))
+    launch_info = lldb.SBLaunchInfo(None)
+    launch_info.SetProcessPluginName("ScriptedProcess")
+    launch_info.SetScriptedProcessClassName("crashlog_scripted_process.CrashLogScriptedProcess")
+    launch_info.SetScriptedProcessDictionary(structured_data)
+    error = lldb.SBError()
+    process = target.Launch(launch_info, error)
 
 def CreateSymbolicateCrashLogOptions(
         command_name,
@@ -1197,8 +1101,14 @@
             '-i',
             '--interactive',
             action='store_true',
-            help='parse all crash logs and enter interactive mode',
+            help='parse a crash log and load it in a ScriptedProcess',
             default=False)
+        option_parser.add_option(
+            '-b',
+            '--batch',
+            action='store_true',
+            help='dump symbolicated stackframes without creating a debug session',
+            default=True)
     return option_parser
 
 
@@ -1230,11 +1140,23 @@
         time.sleep(options.debug_delay)
     error = lldb.SBError()
 
-    if args:
+    def should_run_in_interactive_mode(options, ci):
         if options.interactive:
-            interactive_crashlogs(debugger, options, args)
+            return True
+        elif options.batch:
+            return False
+        # elif ci and ci.IsInteractive():
+        #     return True
         else:
-            for crash_log_file in args:
+            return False
+
+    ci = debugger.GetCommandInterpreter()
+
+    if args:
+        for crash_log_file in args:
+            if should_run_in_interactive_mode(options, ci):
+                load_crashlog_in_scripted_process(debugger, crash_log_file)
+            else:
                 crash_log = CrashLogParser().parse(debugger, crash_log_file, options.verbose)
                 SymbolicateCrashLog(crash_log, options)
 
Index: lldb/bindings/python/CMakeLists.txt
===================================================================
--- lldb/bindings/python/CMakeLists.txt
+++ lldb/bindings/python/CMakeLists.txt
@@ -114,6 +114,7 @@
       ${swig_target}
       ${lldb_python_target_dir} "macosx"
       FILES "${LLDB_SOURCE_DIR}/examples/python/crashlog.py"
+            "${LLDB_SOURCE_DIR}/examples/python/scripted_process/crashlog_scripted_process.py"
             "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap.py")
 
     create_python_package(
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to