Skip to content

Commit 0c9ee31

Browse files
Chris Ellsworthfacebook-github-bot
Chris Ellsworth
authored andcommitted
Copy command
Summary: The `copy` command can be used to copy any `NSURL` or `NSData` to the host machine. The item will be copied to `/tmp/chisel_copy` and opened in the default application. If copying an `NSURL`, the file will retain its existing name and extension. If copying an `NSData`, a name will be generated with the `.data` extension. Options: - `--filename`: Set a name for the file to be copied. - `--no-open`: Prevent the file from being opened after copying. Reviewed By: kolinkrewinkel Differential Revision: D20922370 fbshipit-source-id: a4491f2ef03bf115fce37abdb79e2bd7269635a8
1 parent c238204 commit 0c9ee31

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

commands/FBCopyCommands.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/python
2+
3+
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4+
#
5+
# This source code is licensed under the MIT license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
from __future__ import print_function
9+
import os
10+
import time
11+
12+
import lldb
13+
import errno
14+
import fblldbbase as fb
15+
import fblldbobjecthelpers as objectHelpers
16+
17+
18+
def lldbcommands():
19+
return [FBCopyCommand()]
20+
21+
22+
def _copyFromURL(url, preferredFilename, noOpen):
23+
data = fb.evaluateObjectExpression(
24+
'(id)[NSData dataWithContentsOfURL:(id){}]'.format(url)
25+
)
26+
defaultFilename = fb.describeObject(
27+
'(id)[[{} pathComponents] lastObject]'.format(url)
28+
)
29+
_copyFromData(data, defaultFilename, preferredFilename, noOpen)
30+
31+
32+
def _copyFromData(data, defaultFilename, preferredFilename, noOpen):
33+
directory = '/tmp/chisel_copy/'
34+
35+
path = directory + (preferredFilename or defaultFilename)
36+
37+
try:
38+
os.makedirs(directory)
39+
except OSError as e:
40+
if e.errno == errno.EEXIST and os.path.isdir(directory):
41+
pass
42+
else:
43+
raise
44+
45+
startAddress = fb.evaluateExpression('(void *)[(id)' + data + ' bytes]')
46+
length = fb.evaluateExpression('(NSUInteger)[(id)' + data + ' length]')
47+
48+
address = int(startAddress, 16)
49+
length = int(length)
50+
51+
if not (address or length):
52+
print('Could not get data.')
53+
return
54+
55+
process = lldb.debugger.GetSelectedTarget().GetProcess()
56+
error = lldb.SBError()
57+
mem = process.ReadMemory(address, length, error)
58+
59+
if error is not None and str(error) != 'success':
60+
print(error)
61+
else:
62+
with open(path, 'wb') as file:
63+
file.write(mem)
64+
file.close()
65+
print(path)
66+
if not noOpen:
67+
os.system('open ' + path)
68+
69+
70+
def _copy(target, preferredFilename, noOpen):
71+
target = '(' + target + ')'
72+
73+
if objectHelpers.isKindOfClass(target, 'NSURL'):
74+
_copyFromURL(target, preferredFilename, noOpen)
75+
elif objectHelpers.isKindOfClass(target, 'NSData'):
76+
_copyFromData(
77+
target,
78+
time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime()) + ".data",
79+
preferredFilename,
80+
noOpen
81+
)
82+
else:
83+
print('{} isn\'t supported. You can copy an NSURL or NSData.'.format(
84+
objectHelpers.className(target)
85+
))
86+
87+
88+
class FBCopyCommand(fb.FBCommand):
89+
def name(self):
90+
return 'copy'
91+
92+
def description(self):
93+
return 'Copy data to your Mac.'
94+
95+
def options(self):
96+
return [
97+
fb.FBCommandArgument(
98+
short='-f', long='--filename', arg='filename',
99+
help='The output filename.'
100+
),
101+
fb.FBCommandArgument(
102+
short='-n', long='--no-open', arg='noOpen',
103+
boolean=True, default=False,
104+
help='Do not open the file.'
105+
),
106+
]
107+
108+
def args(self):
109+
return [
110+
fb.FBCommandArgument(
111+
arg='target', type='(id)', help='The object to copy.'
112+
)
113+
]
114+
115+
def run(self, arguments, options):
116+
_copy(arguments[0], options.filename, options.noOpen)

0 commit comments

Comments
 (0)