rmarshal 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rmarshal.rb +2 -0
- data/lib/rmarshal/disasm.rb +56 -0
- data/lib/rmarshal/opcodes.rb +115 -0
- data/lib/rmarshal/pyc.rb +9 -0
- data/lib/rmarshal/unmarshal.rb +113 -0
- data/test/exhaustive.py +33 -0
- data/test/test.rb +5 -0
- metadata +61 -0
data/lib/rmarshal.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rmarshal/opcodes'
|
2
|
+
|
3
|
+
class Disasm
|
4
|
+
def initialize(code, consts, varnames, names)
|
5
|
+
@code = code
|
6
|
+
@consts = consts
|
7
|
+
@varnames = varnames
|
8
|
+
@names = names
|
9
|
+
@insts = []
|
10
|
+
@off = 0
|
11
|
+
|
12
|
+
while @off != @code.size
|
13
|
+
@insts[@insts.size] = parse
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def insts() @insts end
|
18
|
+
def byte()
|
19
|
+
val = @code[@off].ord
|
20
|
+
@off += 1
|
21
|
+
val
|
22
|
+
end
|
23
|
+
def short()
|
24
|
+
val = @code[@off...@off+2].unpack('s')[0]
|
25
|
+
@off += 2
|
26
|
+
val
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse
|
30
|
+
off = @off
|
31
|
+
opcd = byte
|
32
|
+
if not $opcodes.has_key? opcd
|
33
|
+
raise "Unknown opcode #{opcd}"
|
34
|
+
end
|
35
|
+
|
36
|
+
name, arg = $opcodes[opcd]
|
37
|
+
if arg == nil
|
38
|
+
[off, name]
|
39
|
+
else
|
40
|
+
val = short
|
41
|
+
arg = case arg
|
42
|
+
when :const then @consts[val]
|
43
|
+
when :name then @names[val]
|
44
|
+
when :jrel then @off + val
|
45
|
+
when :local then @varnames[val]
|
46
|
+
else val
|
47
|
+
end
|
48
|
+
|
49
|
+
[off, name, arg]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def disasm(*args)
|
55
|
+
Disasm.new(*args).insts
|
56
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
$opcodes = {
|
2
|
+
0x00 => [:STOP_CODE, nil],
|
3
|
+
0x01 => [:POP_TOP, nil],
|
4
|
+
0x02 => [:ROT_TWO, nil],
|
5
|
+
0x03 => [:ROT_THREE, nil],
|
6
|
+
0x04 => [:DUP_TOP, nil],
|
7
|
+
0x05 => [:ROT_FOUR, nil],
|
8
|
+
0x09 => [:NOP, nil],
|
9
|
+
0x0A => [:UNARY_POSITIVE, nil],
|
10
|
+
0x0B => [:UNARY_NEGATIVE, nil],
|
11
|
+
0x0C => [:UNARY_NOT, nil],
|
12
|
+
0x0D => [:UNARY_CONVERT, nil],
|
13
|
+
0x0F => [:UNARY_INVERT, nil],
|
14
|
+
0x12 => [:LIST_APPEND, nil],
|
15
|
+
0x13 => [:BINARY_POWER, nil],
|
16
|
+
0x14 => [:BINARY_MULTIPLY, nil],
|
17
|
+
0x15 => [:BINARY_DIVIDE, nil],
|
18
|
+
0x16 => [:BINARY_MODULO, nil],
|
19
|
+
0x17 => [:BINARY_ADD, nil],
|
20
|
+
0x18 => [:BINARY_SUBTRACT, nil],
|
21
|
+
0x19 => [:BINARY_SUBSCR, nil],
|
22
|
+
0x1A => [:BINARY_FLOOR_DIVIDE, nil],
|
23
|
+
0x1B => [:BINARY_TRUE_DIVIDE, nil],
|
24
|
+
0x1C => [:INPLACE_FLOOR_DIVIDE, nil],
|
25
|
+
0x1D => [:INPLACE_TRUE_DIVIDE, nil],
|
26
|
+
0x1E => [:SLICE_0, nil],
|
27
|
+
0x1F => [:SLICE_1, nil],
|
28
|
+
0x20 => [:SLICE_2, nil],
|
29
|
+
0x21 => [:SLICE_3, nil],
|
30
|
+
0x28 => [:STORE_SLICE_0, nil],
|
31
|
+
0x29 => [:STORE_SLICE_1, nil],
|
32
|
+
0x2A => [:STORE_SLICE_2, nil],
|
33
|
+
0x2B => [:STORE_SLICE_3, nil],
|
34
|
+
0x32 => [:DELETE_SLICE_0, nil],
|
35
|
+
0x33 => [:DELETE_SLICE_1, nil],
|
36
|
+
0x34 => [:DELETE_SLICE_2, nil],
|
37
|
+
0x35 => [:DELETE_SLICE_3, nil],
|
38
|
+
0x36 => [:STORE_MAP, nil],
|
39
|
+
0x37 => [:INPLACE_ADD, nil],
|
40
|
+
0x38 => [:INPLACE_SUBTRACT, nil],
|
41
|
+
0x39 => [:INPLACE_MULTIPLY, nil],
|
42
|
+
0x3A => [:INPLACE_DIVIDE, nil],
|
43
|
+
0x3B => [:INPLACE_MODULO, nil],
|
44
|
+
0x3C => [:STORE_SUBSCR, nil],
|
45
|
+
0x3D => [:DELETE_SUBSCR, nil],
|
46
|
+
0x3E => [:BINARY_LSHIFT, nil],
|
47
|
+
0x3F => [:BINARY_RSHIFT, nil],
|
48
|
+
0x40 => [:BINARY_AND, nil],
|
49
|
+
0x41 => [:BINARY_XOR, nil],
|
50
|
+
0x42 => [:BINARY_OR, nil],
|
51
|
+
0x43 => [:INPLACE_POWER, nil],
|
52
|
+
0x44 => [:GET_ITER, nil],
|
53
|
+
0x46 => [:PRINT_EXPR, nil],
|
54
|
+
0x47 => [:PRINT_ITEM, nil],
|
55
|
+
0x48 => [:PRINT_NEWLINE, nil],
|
56
|
+
0x49 => [:PRINT_ITEM_TO, nil],
|
57
|
+
0x4A => [:PRINT_NEWLINE_TO, nil],
|
58
|
+
0x4B => [:INPLACE_LSHIFT, nil],
|
59
|
+
0x4C => [:INPLACE_RSHIFT, nil],
|
60
|
+
0x4D => [:INPLACE_AND, nil],
|
61
|
+
0x4E => [:INPLACE_XOR, nil],
|
62
|
+
0x4F => [:INPLACE_OR, nil],
|
63
|
+
0x50 => [:BREAK_LOOP, nil],
|
64
|
+
0x51 => [:WITH_CLEANUP, nil],
|
65
|
+
0x52 => [:LOAD_LOCALS, nil],
|
66
|
+
0x53 => [:RETURN_VALUE, nil],
|
67
|
+
0x54 => [:IMPORT_STAR, nil],
|
68
|
+
0x55 => [:EXEC_STMT, nil],
|
69
|
+
0x56 => [:YIELD_VALUE, nil],
|
70
|
+
0x57 => [:POP_BLOCK, nil],
|
71
|
+
0x58 => [:END_FINALLY, nil],
|
72
|
+
0x59 => [:BUILD_CLASS, nil],
|
73
|
+
0x5A => [:STORE_NAME, :name],
|
74
|
+
0x5B => [:DELETE_NAME, :name],
|
75
|
+
0x5C => [:UNPACK_SEQUENCE, nil],
|
76
|
+
0x5D => [:FOR_ITER, :jrel],
|
77
|
+
0x5F => [:STORE_ATTR, :name],
|
78
|
+
0x60 => [:DELETE_ATTR, :name],
|
79
|
+
0x61 => [:STORE_GLOBAL, :name],
|
80
|
+
0x62 => [:DELETE_GLOBAL, :name],
|
81
|
+
0x63 => [:DUP_TOPX, nil],
|
82
|
+
0x64 => [:LOAD_CONST, :const],
|
83
|
+
0x65 => [:LOAD_NAME, :name],
|
84
|
+
0x66 => [:BUILD_TUPLE, nil],
|
85
|
+
0x67 => [:BUILD_LIST, nil],
|
86
|
+
0x68 => [:BUILD_MAP, nil],
|
87
|
+
0x69 => [:LOAD_ATTR, :name],
|
88
|
+
0x6A => [:COMPARE_OP, :compare],
|
89
|
+
0x6B => [:IMPORT_NAME, :name],
|
90
|
+
0x6C => [:IMPORT_FROM, :name],
|
91
|
+
0x6E => [:JUMP_FORWARD, :jrel],
|
92
|
+
0x6F => [:JUMP_IF_FALSE, :jrel],
|
93
|
+
0x70 => [:JUMP_IF_TRUE, :jrel],
|
94
|
+
0x71 => [:JUMP_ABSOLUTE, :jabs],
|
95
|
+
0x74 => [:LOAD_GLOBAL, :name],
|
96
|
+
0x77 => [:CONTINUE_LOOP, :jabs],
|
97
|
+
0x78 => [:SETUP_LOOP, :jrel],
|
98
|
+
0x79 => [:SETUP_EXCEPT, :jrel],
|
99
|
+
0x7A => [:SETUP_FINALLY, :jrel],
|
100
|
+
0x7C => [:LOAD_FAST, :local],
|
101
|
+
0x7D => [:STORE_FAST, :local],
|
102
|
+
0x7E => [:DELETE_FAST, :local],
|
103
|
+
0x82 => [:RAISE_VARARGS, nil],
|
104
|
+
0x83 => [:CALL_FUNCTION, nil],
|
105
|
+
0x84 => [:MAKE_FUNCTION, nil],
|
106
|
+
0x85 => [:BUILD_SLICE, nil],
|
107
|
+
0x86 => [:MAKE_CLOSURE, nil],
|
108
|
+
0x87 => [:LOAD_CLOSURE, :free],
|
109
|
+
0x88 => [:LOAD_DEREF, :free],
|
110
|
+
0x89 => [:STORE_DEREF, :free],
|
111
|
+
0x8C => [:CALL_FUNCTION_VAR, nil],
|
112
|
+
0x8D => [:CALL_FUNCTION_KW, nil],
|
113
|
+
0x8E => [:CALL_FUNCTION_VAR_KW, nil],
|
114
|
+
0x8F => [:EXTENDED_ARG, nil],
|
115
|
+
}
|
data/lib/rmarshal/pyc.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rmarshal/disasm'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
class Code
|
5
|
+
def initialize(
|
6
|
+
argcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars,
|
7
|
+
cellvars, filename, name, firstlineno, lnotab
|
8
|
+
)
|
9
|
+
|
10
|
+
@argcount, @nlocals, @stacksize, @flags = argcount, nlocals, stacksize, flags
|
11
|
+
@code, @consts, @names, @varnames = code, consts, names, varnames
|
12
|
+
@freevars, @cellvars, @filename, @name = freevars, cellvars, filename, name
|
13
|
+
@firstlineno, @lnotab = firstlineno, lnotab
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(sym)
|
17
|
+
instance_variable_get sym
|
18
|
+
end
|
19
|
+
|
20
|
+
def disassemble
|
21
|
+
disasm @code, @consts, @varnames, @names
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Unmarshal
|
26
|
+
def initialize(fp)
|
27
|
+
@fp = fp
|
28
|
+
@interned = []
|
29
|
+
|
30
|
+
@value = unmarshal
|
31
|
+
end
|
32
|
+
|
33
|
+
def value() @value end
|
34
|
+
def byte() @fp.read 1 end
|
35
|
+
def long() @fp.read(4).unpack('i')[0] end
|
36
|
+
def double() @fp.read(8).unpack('E')[0] end
|
37
|
+
|
38
|
+
def unmarshal
|
39
|
+
type = byte
|
40
|
+
case type
|
41
|
+
when '.' then :Ellipsis
|
42
|
+
when '0' then :null # Special!
|
43
|
+
when 'N' then nil
|
44
|
+
when 'T' then true
|
45
|
+
when 'F' then false
|
46
|
+
|
47
|
+
when 'c'
|
48
|
+
argcount, nlocals, stacksize, flags = long, long, long, long
|
49
|
+
|
50
|
+
code_, consts, names, varnames, freevars = unmarshal, unmarshal, unmarshal, unmarshal, unmarshal
|
51
|
+
cellvars, filename, name = unmarshal, unmarshal, unmarshal
|
52
|
+
firstlineno, lnotab = long, unmarshal
|
53
|
+
|
54
|
+
Code.new(
|
55
|
+
argcount, nlocals, stacksize, flags,
|
56
|
+
code_, consts, names, varnames, freevars,
|
57
|
+
cellvars, filename, name, firstlineno, lnotab
|
58
|
+
)
|
59
|
+
|
60
|
+
when 'f' then @fp.read(byte).to_f
|
61
|
+
when 'g' then double
|
62
|
+
when 'i' then long
|
63
|
+
when 'I' then @fp.read(8).unpack('q')[0]
|
64
|
+
|
65
|
+
when 'R'
|
66
|
+
@interned[long]
|
67
|
+
|
68
|
+
when 's' then @fp.read long
|
69
|
+
|
70
|
+
when 'S' then :StopIteration
|
71
|
+
|
72
|
+
when 't'
|
73
|
+
str = @fp.read long
|
74
|
+
@interned[@interned.size] = str
|
75
|
+
str
|
76
|
+
|
77
|
+
when 'u' then @fp.read(long).force_encoding 'utf-8'
|
78
|
+
|
79
|
+
when 'x'
|
80
|
+
Complex @fp.read(byte).to_f(), @fp.read(byte).to_f()
|
81
|
+
when 'y'
|
82
|
+
Complex double, double
|
83
|
+
|
84
|
+
when '(', '['
|
85
|
+
(0...long).map { unmarshal }
|
86
|
+
|
87
|
+
when '{'
|
88
|
+
val = {}
|
89
|
+
|
90
|
+
while true
|
91
|
+
key = unmarshal
|
92
|
+
break if key == :null
|
93
|
+
|
94
|
+
val[key] = unmarshal
|
95
|
+
end
|
96
|
+
|
97
|
+
val
|
98
|
+
|
99
|
+
when '<', '>'
|
100
|
+
Set.new((0...long).map { unmarshal })
|
101
|
+
|
102
|
+
when '?'
|
103
|
+
raise 'TYPE_UNKNOWN encountered. Incomplete marshal.'
|
104
|
+
|
105
|
+
else
|
106
|
+
raise "Unknown type '#{type}'"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def unmarshal(fp)
|
112
|
+
Unmarshal.new(fp).value
|
113
|
+
end
|
data/test/exhaustive.py
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# Creates a file containing all possible marshal types
|
4
|
+
|
5
|
+
import marshal
|
6
|
+
|
7
|
+
def testfunc():
|
8
|
+
print 'Test'
|
9
|
+
|
10
|
+
def exhaustive():
|
11
|
+
return (
|
12
|
+
None, # TYPE_NONE 'N'
|
13
|
+
False, # TYPE_FALSE 'F'
|
14
|
+
True, # TYPE_TRUE 'T'
|
15
|
+
0, # TYPE_INT 'i'
|
16
|
+
#1L, # TYPE_LONG 'l'
|
17
|
+
0.0, # TYPE_BINARY_FLOAT 'g'
|
18
|
+
1j, # TYPE_BINARY_COMPLEX 'y'
|
19
|
+
'foo', # TYPE_STRING 's'
|
20
|
+
'bar', # TYPE_INTERNED 't'
|
21
|
+
'bar', # TYPE_STRINGREF 'R'
|
22
|
+
u'unicode €', # TYPE_UNICODE 'u'
|
23
|
+
[0, 'test', True], # TYPE_LIST '['
|
24
|
+
{0 : 1, 'bar' : 'baz'}, # TYPE_DICT '{'
|
25
|
+
testfunc.func_code, # TYPE_CODE 'c'
|
26
|
+
|
27
|
+
set([0, 1, 2]), # TYPE_SET
|
28
|
+
frozenset([3, 4, 5]), # TYPE_FROZENSET
|
29
|
+
StopIteration, # TYPE_STOPITER
|
30
|
+
Ellipsis, # TYPE_ELLIPSIS
|
31
|
+
)
|
32
|
+
|
33
|
+
marshal.dump(exhaustive(), file('tests\exhaustive.mrsh', 'wb'))
|
data/test/test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rmarshal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cody Brocious
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-20 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: cody.brocious@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/rmarshal/disasm.rb
|
26
|
+
- lib/rmarshal/opcodes.rb
|
27
|
+
- lib/rmarshal/pyc.rb
|
28
|
+
- lib/rmarshal/unmarshal.rb
|
29
|
+
- lib/rmarshal.rb
|
30
|
+
- test/exhaustive.py
|
31
|
+
- test/test.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/daeken/RMarshal
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Ruby gem to support the Python marshal format
|
60
|
+
test_files: []
|
61
|
+
|