Skip to content

Commit 144230c

Browse files
committed
Add set/show tempdir
Useful in remote debugging when a file gets decompiled and needs to be shared.
1 parent 0ad9ecb commit 144230c

9 files changed

Lines changed: 159 additions & 60 deletions

File tree

trepan/__main__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python3
22
# -*- coding: iso-8859-1 -*-
3-
# Copyright (C) 2008-2010, 2013-2018, 2020 Rocky Bernstein <rocky@gnu.org>
3+
# Copyright (C) 2008-2010, 2013-2018, 2020-2021 Rocky Bernstein
4+
# <rocky@gnu.org>
45
#
56
# This program is free software: you can redistribute it and/or modify
67
# it under the terms of the GNU General Public License as published by
@@ -155,7 +156,10 @@ def main(dbg=None, sys_argv=list(sys.argv)):
155156

156157
short_name = osp.basename(mainpyfile).strip(".pyc")
157158
fd = tempfile.NamedTemporaryFile(
158-
suffix=".py", prefix=short_name + "_", delete=False
159+
suffix=".py",
160+
prefix=short_name + "_",
161+
delete=False,
162+
dir=dbg.settings["tempdir"],
159163
)
160164
old_write = fd.file.write
161165

trepan/lib/default.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2008-2009, 2013, 2015, 2017, 2020 Rocky Bernstein <rocky@gnu.org>
2+
# Copyright (C) 2008-2009, 2013, 2015, 2017, 2020-2021 Rocky Bernstein
3+
# <rocky@gnu.org>
34
#
45
# This program is free software: you can redistribute it and/or modify
56
# it under the terms of the GNU General Public License as published by
@@ -104,6 +105,9 @@
104105
# (In the Python they are "class" and "def" statments)
105106
"skip": True,
106107
"step_ignore": 0,
108+
# Location to put temporary decompiled python files.
109+
# If value is None, use Python's defaults
110+
"tempdir": None,
107111
# print trace output?
108112
"trace": False,
109113
# The target maximum print length. Used for example in listing

trepan/lib/deparse.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
# -*- coding: utf-8 -*-
2-
'''Deparsing Routines'''
2+
"""Deparsing Routines"""
33

44
import sys, tempfile
55
from io import StringIO
66
from hashlib import sha1
77
from uncompyle6.semantics.linemap import code_deparse_with_map
8-
from uncompyle6.semantics.fragments import (
9-
deparsed_find, code_deparse)
8+
from uncompyle6.semantics.fragments import deparsed_find, code_deparse
109
import pyficache
10+
1111
# FIXME remap filename to a short name.
1212

1313
deparse_cache = {}
1414

15-
def deparse_and_cache(co, errmsg_fn):
15+
16+
def deparse_and_cache(co, errmsg_fn, tempdir=None):
1617
# co = proc_obj.curframe.f_code
1718
out = StringIO()
1819
deparsed = deparse_cache.get(co, None)
@@ -27,32 +28,33 @@ def deparse_and_cache(co, errmsg_fn):
2728
deparse_cache[co] = deparsed
2829

2930
text = out.getvalue()
30-
linemap = [(line_no, deparsed.source_linemap[line_no])
31-
for line_no in
32-
sorted(deparsed.source_linemap.keys())]
31+
linemap = [
32+
(line_no, deparsed.source_linemap[line_no])
33+
for line_no in sorted(deparsed.source_linemap.keys())
34+
]
3335

3436
# FIXME: DRY code with version in cmdproc.py print_location
3537

3638
name_for_code = sha1(co.co_code).hexdigest()[:6]
37-
prefix='deparsed-'
38-
fd = tempfile.NamedTemporaryFile(suffix='.py',
39-
prefix=prefix,
40-
delete=False)
39+
prefix = "deparsed-"
40+
fd = tempfile.NamedTemporaryFile(
41+
suffix=".py", prefix=prefix, dir=tempdir, delete=False
42+
)
4143
with fd:
42-
fd.write(text.encode('utf-8'))
44+
fd.write(text.encode("utf-8"))
4345
map_line = "\n\n# %s" % linemap
44-
fd.write(map_line.encode('utf-8'))
46+
fd.write(map_line.encode("utf-8"))
4547
remapped_file = fd.name
4648
fd.close()
4749
# FIXME remap filename to a short name.
48-
pyficache.remap_file_lines(name_for_code, remapped_file,
49-
linemap)
50+
pyficache.remap_file_lines(name_for_code, remapped_file, linemap)
5051
return remapped_file, name_for_code
5152

53+
5254
def deparse_offset(co, name, last_i, errmsg_fn):
5355
nodeInfo = None
5456
deparsed = deparse_cache.get(co, None)
55-
if not deparsed or not hasattr(deparsed, 'offsets'):
57+
if not deparsed or not hasattr(deparsed, "offsets"):
5658
out = StringIO()
5759
try:
5860
# FIXME: cache co
@@ -76,14 +78,15 @@ def deparse_offset(co, name, last_i, errmsg_fn):
7678

7779

7880
# Demo it
79-
if __name__ == '__main__':
81+
if __name__ == "__main__":
8082
import inspect
83+
8184
def msg(msg_str):
8285
print(msg_str)
8386
return
8487

8588
def errmsg(msg_str):
86-
msg('*** ' + msg_str)
89+
msg("*** " + msg_str)
8790
return
8891

8992
curframe = inspect.currentframe()

trepan/processor/cmdfns.py

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2013, 2015, 2017-2018, 2020 Rocky Bernstein <rocky@gnu.org>
2+
# Copyright (C) 2013, 2015, 2017-2018, 2020-2021 Rocky Bernstein <rocky@gnu.org>
33
#
44
# This program is free software: you can redistribute it and/or modify
55
# it under the terms of the GNU General Public License as published by
@@ -22,8 +22,10 @@
2222
from xdis import IS_PYPY
2323

2424

25-
def source_tempfile_remap(prefix, text):
26-
fd = tempfile.NamedTemporaryFile(suffix=".py", prefix=prefix, delete=False)
25+
def source_tempfile_remap(prefix, text, tempdir=None):
26+
fd = tempfile.NamedTemporaryFile(
27+
suffix=".py", prefix=prefix, dir=tempdir, delete=False
28+
)
2729
with fd:
2830
fd.write(bytes(text, "UTF-8"))
2931
fd.close()
@@ -48,31 +50,6 @@ def deparse_fn(code):
4850
return None
4951

5052

51-
def deparse_getline(code, filename, line_number, opts):
52-
# I Would like to figure out how to deparse the entire module,
53-
# instead doing this on a line-by-line basis.
54-
# But because th Python import library routines have been rewritten many times, I
55-
# can't figure out how to get from "<frozen importlib>" to
56-
# the module's code.
57-
# So for now, we'll have to do this on a function by function
58-
# bases. Fortunately pyficache has the ability to remap line
59-
# numbers
60-
deparsed = deparse_fn(code)
61-
text = deparsed.text.strip()
62-
if text:
63-
prefix = os.path.basename(filename) + "_"
64-
remapped_filename = source_tempfile_remap(prefix, text)
65-
lines = text.split("\n")
66-
first_line = code.co_firstlineno
67-
linemap = [
68-
(line_no, deparsed.source_linemap[line_no])
69-
for line_no in sorted(deparsed.source_linemap.keys())
70-
]
71-
pyficache.remap_file_lines(filename, remapped_filename, linemap)
72-
return remapped_filename, pyficache.getline(filename, line_number, opts)
73-
return None, None
74-
75-
7653
def get_an_int(errmsg, arg, msg_on_error, min_value=None, max_value=None):
7754
"""Another get_int() routine, this one simpler and less stylized
7855
than get_int(). We eval arg return it as an integer value or

trepan/processor/cmdproc.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2008-2010, 2013-2020 Rocky Bernstein <rocky@gnu.org>
2+
# Copyright (C) 2008-2010, 2013-2021 Rocky Bernstein <rocky@gnu.org>
33
#
44
# This program is free software: you can redistribute it and/or modify
55
# it under the terms of the GNU General Public License as published by
@@ -207,7 +207,9 @@ def print_location(proc_obj):
207207
filename = pyficache.unmap_file(filename)
208208
if "<string>" == filename:
209209
remapped = cmdfns.source_tempfile_remap(
210-
"eval_string", dbgr_obj.eval_string
210+
"eval_string",
211+
dbgr_obj.eval_string,
212+
tempdir=proc_obj.settings("tempdir"),
211213
)
212214
pyficache.remap_file(filename, remapped)
213215
filename, lineno = pyficache.unmap_file_line(filename, lineno)
@@ -230,7 +232,9 @@ def print_location(proc_obj):
230232
pass
231233
pass
232234
elif pyficache.main.remap_re_hash:
233-
remapped_file = pyficache.remap_file_pat(filename, pyficache.main.remap_re_hash)
235+
remapped_file = pyficache.remap_file_pat(
236+
filename, pyficache.main.remap_re_hash
237+
)
234238
elif m and m.group(1) in sys.modules:
235239
remapped_file = m.group(1)
236240
pyficache.remap_file(filename, remapped_file)
@@ -255,7 +259,10 @@ def print_location(proc_obj):
255259
# Deparse the code object into a temp file and remap the line from code
256260
# into the corresponding line of the tempfile
257261
co = proc_obj.curframe.f_code
258-
temp_filename, name_for_code = deparse_and_cache(co, proc_obj.errmsg)
262+
tempdir = proc_obj.settings("tempdir")
263+
temp_filename, name_for_code = deparse_and_cache(
264+
co, proc_obj.errmsg, tempdir=tempdir
265+
)
259266
lineno = 1
260267
# _, lineno = pyficache.unmap_file_line(temp_filename, lineno, True)
261268
if temp_filename:
@@ -275,7 +282,10 @@ def print_location(proc_obj):
275282
# FIXME: DRY code with version in cmdproc.py print_location
276283
prefix = osp.basename(temp_name).split(".")[0]
277284
fd = tempfile.NamedTemporaryFile(
278-
suffix=".py", prefix=prefix, delete=False
285+
suffix=".py",
286+
prefix=prefix,
287+
delete=False,
288+
dir=proc_obj.settings("tempdir"),
279289
)
280290
with fd:
281291
fd.write("".join(lines).encode("utf-8"))
@@ -343,7 +353,10 @@ def print_location(proc_obj):
343353
val = proc_obj.event_arg
344354
intf_obj.msg("R=> %s" % proc_obj._saferepr(val))
345355
pass
346-
elif proc_obj.event == "call" and proc_obj.curframe.f_locals.get("__name__", "") != "__main__":
356+
elif (
357+
proc_obj.event == "call"
358+
and proc_obj.curframe.f_locals.get("__name__", "") != "__main__"
359+
):
347360
try:
348361
proc_obj.commands["info"].run(["info", "locals"])
349362
except:
@@ -450,8 +463,8 @@ def add_remap_pat(self, pat, replace, clear_remap=True):
450463
self.remap_re_hash[re.compile(pat)] = (pat, replace)
451464
pyficache.main.add_remap_pat(pat, replace, clear_remap)
452465
if clear_remap:
453-
self.file2file_remap = {}
454-
pyficache.file2file_remap = {}
466+
self.file2file_remap = {}
467+
pyficache.file2file_remap = {}
455468

456469
# To be overridden in derived debuggers
457470
def defaultFile(self):

trepan/processor/command/deparse.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2015-2018, 2020 Rocky Bernstein
2+
# Copyright (C) 2015-2018, 2020-2021 Rocky Bernstein
33
#
44
# This program is free software: you can redistribute it and/or modify
55
# it under the terms of the GNU General Public License as published by
@@ -112,7 +112,9 @@ def run(self, args):
112112
nodeInfo = None
113113

114114
if len(args) >= 1 and args[0] == ".":
115-
temp_filename, name_for_code = deparse_and_cache(co, self.errmsg)
115+
temp_filename, name_for_code = deparse_and_cache(
116+
co, self.errmsg, tempdir=self.settings["tempdir"]
117+
)
116118
if not temp_filename:
117119
return
118120
self.print_text("".join(getlines(temp_filename)))

trepan/processor/command/list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2009, 2012-2017, 2020 Rocky Bernstein
2+
# Copyright (C) 2009, 2012-2017, 2020-2021 Rocky Bernstein
33
#
44
# This program is free software: you can redistribute it and/or modify
55
# it under the terms of the GNU General Public License as published by
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (C) 2021 Rocky Bernstein
3+
#
4+
5+
import os
6+
7+
# Our local modules
8+
from trepan.processor.command.base_subcmd import DebuggerSubcommand
9+
10+
11+
class SetTempdir(DebuggerSubcommand):
12+
"""**set tempdir** *directory*
13+
14+
Set the temporary directory for temporary decompiled python files.
15+
16+
This is sometimes useful remote debugging where you might set up a
17+
common shared location available between the debugged process and
18+
the front end client.
19+
Examples:
20+
---------
21+
22+
set tempdir /code/tmp # /code is a shared directory
23+
24+
See also:
25+
--------
26+
27+
`show tempdir`
28+
"""
29+
30+
in_list = True
31+
min_abbrev = len("temp")
32+
min_args = 1
33+
max_args = 1
34+
short_help = "Set a directory for storing decompiled Python"
35+
36+
def run(self, args):
37+
dirpath = args[0]
38+
if os.path.isdir(dirpath):
39+
self.debugger.settings[self.name] = dirpath
40+
else:
41+
self.errmsg("set tempdir: directory %s not found; not changed." % dirpath)
42+
return
43+
44+
pass
45+
46+
47+
# if __name__ == '__main__':
48+
# from trepan.processor.command.set.tempdir import __demo_helper__ as Mhelper
49+
# sub = Mhelper.demo_run(SetTempdir)
50+
# d = sub.proc.debugger
51+
# sub.run(['tempdir'])
52+
# print(d.settings['tempdir'])
53+
# pass
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (C) 2021 Rocky Bernstein
3+
#
4+
5+
# Our local modules
6+
from trepan.processor.command.base_subcmd import DebuggerSubcommand
7+
8+
9+
class ShowTempdir(DebuggerSubcommand):
10+
"""**show tempdir**
11+
12+
Show the temporary directory usind in decompiled python files.
13+
14+
See also:
15+
--------
16+
17+
`set tempdir`
18+
"""
19+
20+
in_list = True
21+
min_abbrev = len("temp")
22+
min_args = 0
23+
max_args = 0
24+
short_help = "Set a directory for storing decompiled Python"
25+
26+
def run(self, args):
27+
tempdir = self.debugger.settings.get(self.name, None)
28+
if tempdir:
29+
self.msg("tempdir is %s." % tempdir)
30+
else:
31+
self.msg("tempdir not set; Python default is used.")
32+
return
33+
34+
pass
35+
36+
37+
if __name__ == "__main__":
38+
from trepan.processor.command.set_subcmd import __demo_helper__ as Mhelper
39+
40+
sub = Mhelper.demo_run(ShowTempdir)
41+
d = sub.proc.debugger
42+
sub.run(["show"])
43+
pass

0 commit comments

Comments
 (0)