commands/FBCopyCommands.py (91 lines of code) (raw):

#!/usr/bin/python # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. from __future__ import print_function import errno import os import time import fbchisellldbbase as fb import fbchisellldbobjecthelpers as objectHelpers import lldb def lldbcommands(): return [FBCopyCommand()] def _copyFromURL(url, preferredFilename, noOpen): data = fb.evaluateObjectExpression( "(id)[NSData dataWithContentsOfURL:(id){}]".format(url) ) defaultFilename = fb.describeObject( "(id)[[{} pathComponents] lastObject]".format(url) ) _copyFromData(data, defaultFilename, preferredFilename, noOpen) def _copyFromData(data, defaultFilename, preferredFilename, noOpen): directory = "/tmp/chisel_copy/" path = directory + (preferredFilename or defaultFilename) try: os.makedirs(directory) except OSError as e: if e.errno == errno.EEXIST and os.path.isdir(directory): pass else: raise startAddress = fb.evaluateExpression("(void *)[(id)" + data + " bytes]") length = fb.evaluateExpression("(NSUInteger)[(id)" + data + " length]") address = int(startAddress, 16) length = int(length) if not (address or length): print("Could not get data.") return process = lldb.debugger.GetSelectedTarget().GetProcess() error = lldb.SBError() mem = process.ReadMemory(address, length, error) if error is not None and str(error) != "success": print(error) else: with open(path, "wb") as file: file.write(mem) file.close() print(path) if not noOpen: os.system("open " + path) def _copy(target, preferredFilename, noOpen): target = "(" + target + ")" if objectHelpers.isKindOfClass(target, "NSURL"): _copyFromURL(target, preferredFilename, noOpen) elif objectHelpers.isKindOfClass(target, "NSData"): _copyFromData( target, time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime()) + ".data", preferredFilename, noOpen, ) else: print( "{} isn't supported. You can copy an NSURL or NSData.".format( objectHelpers.className(target) ) ) class FBCopyCommand(fb.FBCommand): def name(self): return "copy" def description(self): return "Copy data to your Mac." def options(self): return [ fb.FBCommandArgument( short="-f", long="--filename", arg="filename", help="The output filename.", ), fb.FBCommandArgument( short="-n", long="--no-open", arg="noOpen", boolean=True, default=False, help="Do not open the file.", ), ] def args(self): return [ fb.FBCommandArgument(arg="target", type="(id)", help="The object to copy.") ] def run(self, arguments, options): _copy(arguments[0], options.filename, options.noOpen)