mrb_parser 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +1 -0
- data/bin/mrb_parser +32 -0
- data/lib/mrb_parser/code_dump.rb +390 -0
- data/lib/mrb_parser/crc.rb +32 -0
- data/lib/mrb_parser/debug_info.rb +76 -0
- data/lib/mrb_parser/debug_info_file.rb +40 -0
- data/lib/mrb_parser/debug_section.rb +43 -0
- data/lib/mrb_parser/end_section.rb +21 -0
- data/lib/mrb_parser/error.rb +3 -0
- data/lib/mrb_parser/header.rb +59 -0
- data/lib/mrb_parser/irep_record.rb +109 -0
- data/lib/mrb_parser/irep_section.rb +34 -0
- data/lib/mrb_parser/lineno_section.rb +35 -0
- data/lib/mrb_parser/section.rb +51 -0
- data/lib/mrb_parser/utils.rb +45 -0
- data/lib/mrb_parser/version.rb +3 -0
- data/lib/mrb_parser.rb +44 -0
- data/mrb_parser.gemspec +24 -0
- data/spec/spec_helper.rb +1 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b96059708452f131c2ef1c44c20b13c163b687f9
|
4
|
+
data.tar.gz: 9df8a740b518b0b6cd628f9c026360213bd1c5a5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fdc2cd80c1e26c8b5eee9191c628398d71f757512d2cf202c208ab571af24760609a25b5993b840a9662a262bea230bc8e7bdb7be5c5330782cdb834f51ece9c
|
7
|
+
data.tar.gz: fe9035d908042c98ebc57d00d37ddc84da200a96cb81524b40118cf5ef7056e53b8a8cb9242cb30b3235604401394a1dfb247084bda47815d809789f0ed98650
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Team Yamanekko
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# MrbParser: mrb file parser
|
2
|
+
|
3
|
+
MrbParer is a parser library and command to parse mrb format, binary code format
|
4
|
+
generated by mruby(mrbc).
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'mrb_parser'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install mrb_parser
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
MrbParser has a simple command: ``mrb_parser``.
|
23
|
+
|
24
|
+
$ mrb_parser sample.mrb
|
25
|
+
|
26
|
+
To show more information, with ``-d`` option:
|
27
|
+
|
28
|
+
$ mrb_parser -d sample.mrb
|
29
|
+
|
30
|
+
## TODO
|
31
|
+
|
32
|
+
* support LINENO section (current implementation is broken)
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
1. Fork it
|
37
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
38
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
39
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
40
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/mrb_parser
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mrb_parser'
|
5
|
+
|
6
|
+
def usage
|
7
|
+
abort "usage: mrb_parser [-d] <mrb file>"
|
8
|
+
end
|
9
|
+
|
10
|
+
def main
|
11
|
+
if ARGV.size < 1 or ARGV.size > 2
|
12
|
+
usage
|
13
|
+
end
|
14
|
+
|
15
|
+
verbose = nil
|
16
|
+
filename = ARGV[0]
|
17
|
+
if filename == "-d"
|
18
|
+
filename = ARGV[1]
|
19
|
+
verbose = true
|
20
|
+
end
|
21
|
+
|
22
|
+
if !File.exist? filename
|
23
|
+
abort "#{filename}: file not found"
|
24
|
+
end
|
25
|
+
|
26
|
+
parser = MrbParser.new(filename)
|
27
|
+
parser.verbose = verbose
|
28
|
+
parser.parse
|
29
|
+
parser.dump
|
30
|
+
end
|
31
|
+
|
32
|
+
main
|
@@ -0,0 +1,390 @@
|
|
1
|
+
class MrbParser
|
2
|
+
class CodeDump
|
3
|
+
|
4
|
+
MAXARG_Bx = 0xffff
|
5
|
+
MAXARG_sBx = (MAXARG_Bx>>1) ## `sBx' is signed
|
6
|
+
|
7
|
+
OP_NOP = 0 # /* */
|
8
|
+
OP_MOVE = 1 # /* A B R(A) := R(B) */
|
9
|
+
OP_LOADL = 2 # /* A Bx R(A) := Lit(Bx) */
|
10
|
+
OP_LOADI = 3 # /* A sBx R(A) := sBx */
|
11
|
+
OP_LOADSYM = 4 # /* A Bx R(A) := Sym(Bx) */
|
12
|
+
OP_LOADNIL = 5 # /* A R(A) := nil */
|
13
|
+
OP_LOADSELF = 6 # /* A R(A) := self */
|
14
|
+
OP_LOADT = 7 # /* A R(A) := true */
|
15
|
+
OP_LOADF = 8 # /* A R(A) := false */
|
16
|
+
|
17
|
+
OP_GETGLOBAL = 9 # /* A Bx R(A) := getglobal(Sym(Bx)) */
|
18
|
+
OP_SETGLOBAL =10 # /* A Bx setglobal(Sym(Bx), R(A)) */
|
19
|
+
OP_GETSPECIAL=11 # /*A Bx R(A) := Special[Bx] */
|
20
|
+
OP_SETSPECIAL=12 # /*A Bx Special[Bx] := R(A) */
|
21
|
+
OP_GETIV = 13 # /* A Bx R(A) := ivget(Sym(Bx)) */
|
22
|
+
OP_SETIV = 14 # /* A Bx ivset(Sym(Bx),R(A)) */
|
23
|
+
OP_GETCV = 15 # /* A Bx R(A) := cvget(Sym(Bx)) */
|
24
|
+
OP_SETCV = 16 # /* A Bx cvset(Sym(Bx),R(A)) */
|
25
|
+
OP_GETCONST = 17 # /* A Bx R(A) := constget(Sym(Bx)) */
|
26
|
+
OP_SETCONST = 18 # /* A Bx constset(Sym(Bx),R(A)) */
|
27
|
+
OP_GETMCNST = 19 # /* A Bx R(A) := R(A)::Sym(B) */
|
28
|
+
OP_SETMCNST = 20 # /* A Bx R(A+1)::Sym(B) := R(A) */
|
29
|
+
OP_GETUPVAR = 21 # /* A B C R(A) := uvget(B,C) */
|
30
|
+
OP_SETUPVAR = 22 # /* A B C uvset(B,C,R(A)) */
|
31
|
+
|
32
|
+
OP_JMP = 23 # /* sBx pc+=sBx */
|
33
|
+
OP_JMPIF = 24 # /* A sBx if R(A) pc+=sBx */
|
34
|
+
OP_JMPNOT = 25 # /* A sBx if !R(A) pc+=sBx */
|
35
|
+
OP_ONERR = 26 # /* sBx rescue_push(pc+sBx) */
|
36
|
+
OP_RESCUE = 27 # /* A clear(exc); R(A) := exception (ignore when A=0) */
|
37
|
+
OP_POPERR = 28 # /* A A.times{rescue_pop()} */
|
38
|
+
OP_RAISE = 29 # /* A raise(R(A)) */
|
39
|
+
OP_EPUSH = 30 # /* Bx ensure_push(SEQ[Bx]) */
|
40
|
+
OP_EPOP = 31 # /* A A.times{ensure_pop().call} */
|
41
|
+
|
42
|
+
OP_SEND = 32 # /* A B C R(A) := call(R(A),mSym(B),R(A+1),...,R(A+C)) */
|
43
|
+
OP_SENDB = 33 # /* A B C R(A) := call(R(A),mSym(B),R(A+1),...,R(A+C),&R(A+C+1))*/
|
44
|
+
OP_FSEND = 34 # /* A B C R(A) := fcall(R(A),mSym(B),R(A+1),...,R(A+C-1)) */
|
45
|
+
OP_CALL = 35 # /* A B C R(A) := self.call(R(A),.., R(A+C)) */
|
46
|
+
OP_SUPER = 36 # /* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */
|
47
|
+
OP_ARGARY = 37 # /* A Bx R(A) := argument array (16=6:1:5:4) */
|
48
|
+
OP_ENTER = 38 # /* Ax arg setup according to flags (24=5:5:1:5:5:1:1) */
|
49
|
+
OP_KARG = 39 # /* A B C R(A) := kdict[mSym(B)]; if C kdict.rm(mSym(B)) */
|
50
|
+
OP_KDICT = 40 # /* A C R(A) := kdict */
|
51
|
+
|
52
|
+
OP_RETURN = 41 # /* A B return R(A) (B=normal,in-block return/break) */
|
53
|
+
OP_TAILCALL = 42 # /* A B C return call(R(A),mSym(B),*R(C)) */
|
54
|
+
OP_BLKPUSH = 43 # /* A Bx R(A) := block (16=6:1:5:4) */
|
55
|
+
|
56
|
+
OP_ADD = 44 # /* A B C R(A) := R(A)+R(A+1) (mSyms[B]=:+,C=1) */
|
57
|
+
OP_ADDI = 45 # /* A B C R(A) := R(A)+C (mSyms[B]=:+) */
|
58
|
+
OP_SUB = 46 # /* A B C R(A) := R(A)-R(A+1) (mSyms[B]=:-,C=1) */
|
59
|
+
OP_SUBI = 47 # /* A B C R(A) := R(A)-C (mSyms[B]=:-) */
|
60
|
+
OP_MUL = 48 # /* A B C R(A) := R(A)*R(A+1) (mSyms[B]=:*,C=1) */
|
61
|
+
OP_DIV = 49 # /* A B C R(A) := R(A)/R(A+1) (mSyms[B]=:/,C=1) */
|
62
|
+
OP_EQ = 50 # /* A B C R(A) := R(A)==R(A+1) (mSyms[B]=:==,C=1) */
|
63
|
+
OP_LT = 51 # /* A B C R(A) := R(A)<R(A+1) (mSyms[B]=:<,C=1) */
|
64
|
+
OP_LE = 52 # /* A B C R(A) := R(A)<=R(A+1) (mSyms[B]=:<=,C=1) */
|
65
|
+
OP_GT = 53 # /* A B C R(A) := R(A)>R(A+1) (mSyms[B]=:>,C=1) */
|
66
|
+
OP_GE = 54 # /* A B C R(A) := R(A)>=R(A+1) (mSyms[B]=:>=,C=1) */
|
67
|
+
|
68
|
+
OP_ARRAY = 55 # /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
|
69
|
+
OP_ARYCAT = 56 # /* A B ary_cat(R(A),R(B)) */
|
70
|
+
OP_ARYPUSH = 57 # /* A B ary_push(R(A),R(B)) */
|
71
|
+
OP_AREF = 58 # /* A B C R(A) := R(B)[C] */
|
72
|
+
OP_ASET = 59 # /* A B C R(B)[C] := R(A) */
|
73
|
+
OP_APOST = 60 # /* A B C *R(A),R(A+1)..R(A+C) := R(A) */
|
74
|
+
|
75
|
+
OP_STRING = 61 # /* A Bx R(A) := str_dup(Lit(Bx)) */
|
76
|
+
OP_STRCAT = 62 # /* A B str_cat(R(A),R(B)) */
|
77
|
+
|
78
|
+
OP_HASH = 63 # /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
|
79
|
+
OP_LAMBDA = 64 # /* A Bz Cz R(A) := lambda(SEQ[Bz],Cm) */
|
80
|
+
OP_RANGE = 65 # /* A B C R(A) := range_new(R(B),R(B+1),C) */
|
81
|
+
|
82
|
+
OP_OCLASS = 66 # /* A R(A) := ::Object */
|
83
|
+
OP_CLASS = 67 # /* A B R(A) := newclass(R(A),mSym(B),R(A+1)) */
|
84
|
+
OP_MODULE = 68 # /* A B R(A) := newmodule(R(A),mSym(B)) */
|
85
|
+
OP_EXEC = 69 # /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
|
86
|
+
OP_METHOD = 70 # /* A B R(A).newmethod(mSym(B),R(A+1)) */
|
87
|
+
OP_SCLASS = 71 # /* A B R(A) := R(B).singleton_class */
|
88
|
+
OP_TCLASS = 72 # /* A R(A) := target_class */
|
89
|
+
|
90
|
+
OP_DEBUG = 73 # /* A print R(A) */
|
91
|
+
OP_STOP = 74 # /* stop VM */
|
92
|
+
OP_ERR = 75 # /* Bx raise RuntimeError with message Lit(Bx) */
|
93
|
+
|
94
|
+
OP_RSVD1 = 76 # /* reserved instruction #1 */
|
95
|
+
OP_RSVD2 = 77 # /* reserved instruction #2 */
|
96
|
+
OP_RSVD3 = 78 # /* reserved instruction #3 */
|
97
|
+
OP_RSVD4 = 79 # /* reserved instruction #4 */
|
98
|
+
OP_RSVD5 = 80 # /* reserved instruction #5 */
|
99
|
+
|
100
|
+
|
101
|
+
OP_R_NORMAL = 0
|
102
|
+
OP_R_BREAK = 1
|
103
|
+
OP_R_RETURN = 2
|
104
|
+
|
105
|
+
# instructions: packed 32 bit
|
106
|
+
# -------------------------------
|
107
|
+
# A:B:C:OP = 9: 9: 7: 7
|
108
|
+
# A:Bx:OP = 9:16: 7
|
109
|
+
# Ax:OP = 25: 7
|
110
|
+
# A:Bz:Cz:OP = 9:14: 2: 7
|
111
|
+
|
112
|
+
def initialize(irep)
|
113
|
+
@irep = irep
|
114
|
+
end
|
115
|
+
|
116
|
+
def opcode(code)
|
117
|
+
code & 0x7F
|
118
|
+
end
|
119
|
+
|
120
|
+
def getarg_a(code)
|
121
|
+
(code >> 23) & 0x1ff
|
122
|
+
end
|
123
|
+
|
124
|
+
def getarg_b(code)
|
125
|
+
(code >> 14) & 0x1ff
|
126
|
+
end
|
127
|
+
|
128
|
+
def getarg_c(code)
|
129
|
+
(code >> 7) & 0x7f
|
130
|
+
end
|
131
|
+
|
132
|
+
def getarg_bx(code)
|
133
|
+
(code >> 7) & 0xffff
|
134
|
+
end
|
135
|
+
|
136
|
+
def getarg_sbx(code)
|
137
|
+
getarg_bx(code) - MAXARG_sBx
|
138
|
+
end
|
139
|
+
|
140
|
+
def getarg_ax(code)
|
141
|
+
(code >> 7) & 0x1ffffff
|
142
|
+
end
|
143
|
+
|
144
|
+
def getarg_unpack_b(code, n1, n2)
|
145
|
+
(code >> (7 + n2)) & ((1 << n1)-1)
|
146
|
+
end
|
147
|
+
|
148
|
+
def getarg_unpack_c(code, n1, n2)
|
149
|
+
(code >> 7) & ((1 << n2)-1)
|
150
|
+
end
|
151
|
+
|
152
|
+
def getarg_b2(code)
|
153
|
+
getarg_unpack_b(code, 14, 2)
|
154
|
+
end
|
155
|
+
|
156
|
+
def getarg_c2(code)
|
157
|
+
getarg_unpack_c(code, 14, 2)
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def dump(c, i)
|
162
|
+
printf("%03d ", i)
|
163
|
+
op = opcode(c)
|
164
|
+
case op
|
165
|
+
when OP_NOP
|
166
|
+
printf("OP_NOP\n")
|
167
|
+
when OP_MOVE
|
168
|
+
printf("OP_MOVE\tR%d\tR%d\n", getarg_a(c), getarg_b(c))
|
169
|
+
when OP_LOADL
|
170
|
+
printf("OP_LOADL\tR%d\tL(%d)\n", getarg_a(c), getarg_bx(c))
|
171
|
+
when OP_LOADI
|
172
|
+
printf("OP_LOADI\tR%d\t%d\n", getarg_a(c), getarg_sbx(c))
|
173
|
+
when OP_LOADSYM
|
174
|
+
printf("OP_LOADSYM\tR%d\t:%s\n", getarg_a(c),
|
175
|
+
@irep.syms[getarg_bx(c)])
|
176
|
+
when OP_LOADNIL
|
177
|
+
printf("OP_LOADNIL\tR%d\n", getarg_a(c))
|
178
|
+
when OP_LOADSELF
|
179
|
+
printf("OP_LOADSELF\tR%d\n", getarg_a(c))
|
180
|
+
when OP_LOADT
|
181
|
+
printf("OP_LOADT\tR%d\n", getarg_a(c))
|
182
|
+
when OP_LOADF
|
183
|
+
printf("OP_LOADF\tR%d\n", getarg_a(c))
|
184
|
+
when OP_GETGLOBAL
|
185
|
+
printf("OP_GETGLOBAL\tR%d\t:%s\n", getarg_a(c),
|
186
|
+
@irep.syms[getarg_bx(c)])
|
187
|
+
when OP_SETGLOBAL
|
188
|
+
printf("OP_SETGLOBAL\t:%s\tR%d\n",
|
189
|
+
@irep.syms[getarg_bx(c)],
|
190
|
+
getarg_a(c))
|
191
|
+
when OP_GETCONST
|
192
|
+
printf("OP_GETCONST\tR%d\t:%s\n", getarg_a(c),
|
193
|
+
@irep.syms[getarg_bx(c)])
|
194
|
+
when OP_SETCONST
|
195
|
+
printf("OP_SETCONST\t:%s\tR%d\n",
|
196
|
+
@irep.syms[getarg_bx(c)],
|
197
|
+
getarg_a(c))
|
198
|
+
when OP_GETMCNST
|
199
|
+
printf("OP_GETMCNST\tR%d\tR%d::%s\n", getarg_a(c), getarg_a(c),
|
200
|
+
@irep.syms[getarg_bx(c)])
|
201
|
+
when OP_SETMCNST
|
202
|
+
printf("OP_SETMCNST\tR%d::%s\tR%d\n", getarg_a(c)+1,
|
203
|
+
@irep.syms[getarg_bx(c)],
|
204
|
+
getarg_a(c))
|
205
|
+
when OP_GETIV
|
206
|
+
printf("OP_GETIV\tR%d\t%s\n", getarg_a(c),
|
207
|
+
@irep.syms[getarg_bx(c)])
|
208
|
+
when OP_SETIV
|
209
|
+
printf("OP_SETIV\t%s\tR%d\n",
|
210
|
+
@irep.syms[getarg_bx(c)],
|
211
|
+
getarg_a(c))
|
212
|
+
when OP_GETUPVAR
|
213
|
+
printf("OP_GETUPVAR\tR%d\t%d\t%d\n",
|
214
|
+
getarg_a(c), getarg_b(c), getarg_c(c))
|
215
|
+
when OP_SETUPVAR
|
216
|
+
printf("OP_SETUPVAR\tR%d\t%d\t%d\n",
|
217
|
+
getarg_a(c), getarg_b(c), getarg_c(c))
|
218
|
+
when OP_GETCV
|
219
|
+
printf("OP_GETCV\tR%d\t%s\n", getarg_a(c),
|
220
|
+
@irep.syms[getarg_bx(c)])
|
221
|
+
when OP_SETCV
|
222
|
+
printf("OP_SETCV\t%s\tR%d\n",
|
223
|
+
@irep.syms[getarg_bx(c)],
|
224
|
+
getarg_a(c))
|
225
|
+
when OP_JMP
|
226
|
+
printf("OP_JMP\t\t%03d\n", i+getarg_sbx(c))
|
227
|
+
when OP_JMPIF
|
228
|
+
printf("OP_JMPIF\tR%d\t%03d\n", getarg_a(c), i+getarg_sbx(c))
|
229
|
+
when OP_JMPNOT
|
230
|
+
printf("OP_JMPNOT\tR%d\t%03d\n", getarg_a(c), i+getarg_sbx(c));
|
231
|
+
when OP_SEND
|
232
|
+
printf("OP_SEND\tR%d\t:%s\t%d\n", getarg_a(c),
|
233
|
+
@irep.syms[getarg_b(c)],
|
234
|
+
getarg_c(c))
|
235
|
+
when OP_SENDB
|
236
|
+
printf("OP_SENDB\tR%d\t:%s\t%d\n", getarg_a(c),
|
237
|
+
@irep.syms[getarg_b(c)],
|
238
|
+
getarg_c(c))
|
239
|
+
when OP_TAILCALL
|
240
|
+
printf("OP_TAILCALL\tR%d\t:%s\t%d\n", getarg_a(c),
|
241
|
+
@irep.syms[getarg_b(c)],
|
242
|
+
getarg_c(c))
|
243
|
+
when OP_SUPER
|
244
|
+
printf("OP_SUPER\tR%d\t%d\n", getarg_a(c),
|
245
|
+
getarg_c(c))
|
246
|
+
when OP_ARGARY
|
247
|
+
printf("OP_ARGARY\tR%d\t%d:%d:%d:%d\n", getarg_a(c),
|
248
|
+
(getarg_bx(c)>>10)&0x3f,
|
249
|
+
(getarg_bx(c)>>9)&0x1,
|
250
|
+
(getarg_bx(c)>>4)&0x1f,
|
251
|
+
(getarg_bx(c)>>0)&0xf)
|
252
|
+
|
253
|
+
when OP_ENTER
|
254
|
+
printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
|
255
|
+
(getarg_ax(c)>>18)&0x1f,
|
256
|
+
(getarg_ax(c)>>13)&0x1f,
|
257
|
+
(getarg_ax(c)>>12)&0x1,
|
258
|
+
(getarg_ax(c)>>7)&0x1f,
|
259
|
+
(getarg_ax(c)>>2)&0x1f,
|
260
|
+
(getarg_ax(c)>>1)&0x1,
|
261
|
+
getarg_ax(c) & 0x1)
|
262
|
+
when OP_RETURN
|
263
|
+
printf("OP_RETURN\tR%d", getarg_a(c))
|
264
|
+
case getarg_b(c)
|
265
|
+
when OP_R_NORMAL
|
266
|
+
printf("\n")
|
267
|
+
when OP_R_RETURN
|
268
|
+
printf("\treturn\n")
|
269
|
+
when OP_R_BREAK
|
270
|
+
printf("\tbreak\n")
|
271
|
+
else
|
272
|
+
printf("\tbroken\n")
|
273
|
+
end
|
274
|
+
when OP_BLKPUSH
|
275
|
+
printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d\n", getarg_a(c),
|
276
|
+
(getarg_bx(c)>>10)&0x3f,
|
277
|
+
(getarg_bx(c)>>9)&0x1,
|
278
|
+
(getarg_bx(c)>>4)&0x1f,
|
279
|
+
(getarg_bx(c)>>0)&0xf)
|
280
|
+
|
281
|
+
when OP_LAMBDA
|
282
|
+
printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", getarg_a(c), getarg_b2(c), getarg_c2(c))
|
283
|
+
when OP_RANGE
|
284
|
+
printf("OP_RANGE\tR%d\tR%d\t%d\n", getarg_a(c), getarg_b(c), getarg_c(c))
|
285
|
+
when OP_METHOD
|
286
|
+
printf("OP_METHOD\tR%d\t:%s\n", getarg_a(c),
|
287
|
+
@irep.syms[getarg_b(c)])
|
288
|
+
|
289
|
+
when OP_ADD
|
290
|
+
printf("OP_ADD\tR%d\t:%s\t%d\n", getarg_a(c),
|
291
|
+
@irep.syms[getarg_b(c)],
|
292
|
+
getarg_c(c))
|
293
|
+
when OP_ADDI
|
294
|
+
printf("OP_ADDI\tR%d\t:%s\t%d\n", getarg_a(c),
|
295
|
+
@irep.syms[getarg_b(c)],
|
296
|
+
getarg_c(c))
|
297
|
+
when OP_SUB
|
298
|
+
printf("OP_SUB\tR%d\t:%s\t%d\n", getarg_a(c),
|
299
|
+
@irep.syms[getarg_b(c)],
|
300
|
+
getarg_c(c))
|
301
|
+
when OP_SUBI
|
302
|
+
printf("OP_SUBI\tR%d\t:%s\t%d\n", getarg_a(c),
|
303
|
+
@irep.syms[getarg_b(c)],
|
304
|
+
getarg_c(c))
|
305
|
+
when OP_MUL
|
306
|
+
printf("OP_MUL\tR%d\t:%s\t%d\n", getarg_a(c),
|
307
|
+
@irep.syms[getarg_b(c)],
|
308
|
+
getarg_c(c))
|
309
|
+
when OP_DIV
|
310
|
+
printf("OP_DIV\tR%d\t:%s\t%d\n", getarg_a(c),
|
311
|
+
@irep.syms[getarg_b(c)],
|
312
|
+
getarg_c(c))
|
313
|
+
when OP_LT
|
314
|
+
printf("OP_LT\tR%d\t:%s\t%d\n", getarg_a(c),
|
315
|
+
@irep.syms[getarg_b(c)],
|
316
|
+
getarg_c(c))
|
317
|
+
when OP_LE
|
318
|
+
printf("OP_LE\tR%d\t:%s\t%d\n", getarg_a(c),
|
319
|
+
@irep.syms[getarg_b(c)],
|
320
|
+
getarg_c(c))
|
321
|
+
when OP_GT
|
322
|
+
printf("OP_GT\tR%d\t:%s\t%d\n", getarg_a(c),
|
323
|
+
@irep.syms[getarg_b(c)],
|
324
|
+
getarg_c(c))
|
325
|
+
when OP_GE
|
326
|
+
printf("OP_GE\tR%d\t:%s\t%d\n", getarg_a(c),
|
327
|
+
@irep.syms[getarg_b(c)],
|
328
|
+
getarg_c(c))
|
329
|
+
when OP_EQ
|
330
|
+
printf("OP_EQ\tR%d\t:%s\t%d\n", getarg_a(c),
|
331
|
+
@irep.syms[getarg_b(c)],
|
332
|
+
getarg_c(c))
|
333
|
+
|
334
|
+
when OP_STOP
|
335
|
+
printf("OP_STOP\n")
|
336
|
+
|
337
|
+
when OP_ARRAY
|
338
|
+
printf("OP_ARRAY\tR%d\tR%d\t%d\n", getarg_a(c), getarg_b(c), getarg_c(c))
|
339
|
+
when OP_ARYCAT
|
340
|
+
printf("OP_ARYCAT\tR%d\tR%d\n", getarg_a(c), getarg_b(c))
|
341
|
+
when OP_ARYPUSH
|
342
|
+
printf("OP_ARYPUSH\tR%d\tR%d\n", getarg_a(c), getarg_b(c))
|
343
|
+
when OP_AREF
|
344
|
+
printf("OP_AREF\tR%d\tR%d\t%d\n", getarg_a(c), getarg_b(c), getarg_c(c))
|
345
|
+
when OP_APOST
|
346
|
+
printf("OP_APOST\tR%d\t%d\t%d\n", getarg_a(c), getarg_b(c), getarg_c(c))
|
347
|
+
when OP_STRING
|
348
|
+
s = @irep.pool[getarg_bx(c)]
|
349
|
+
printf("OP_STRING\tR%d\t%s\n", getarg_a(c), s)
|
350
|
+
when OP_STRCAT
|
351
|
+
printf("OP_STRCAT\tR%d\tR%d\n", getarg_a(c), getarg_b(c))
|
352
|
+
when OP_HASH
|
353
|
+
printf("OP_HASH\tR%d\tR%d\t%d\n", getarg_a(c), getarg_b(c), getarg_c(c))
|
354
|
+
|
355
|
+
when OP_OCLASS
|
356
|
+
printf("OP_OCLASS\tR%d\n", getarg_a(c))
|
357
|
+
when OP_CLASS
|
358
|
+
printf("OP_cLASS\tR%d\t:%s\n", getarg_a(c),
|
359
|
+
@irep.syms[getarg_b(c)])
|
360
|
+
when OP_MODULE
|
361
|
+
printf("OP_MODULE\tR%d\t:%s\n", getarg_a(c),
|
362
|
+
@irep.syms[getarg_b(c)])
|
363
|
+
when OP_EXEC
|
364
|
+
printf("OP_EXEC\tR%d\tI(%+d)\n", getarg_a(c), getarg_bx(c))
|
365
|
+
when OP_SCLASS
|
366
|
+
printf("OP_SCLASS\tR%d\tR%d\n", getarg_a(c), getarg_b(c))
|
367
|
+
when OP_TCLASS
|
368
|
+
printf("OP_TCLASS\tR%d\n", getarg_a(c))
|
369
|
+
when OP_ERR
|
370
|
+
printf("OP_ERR\tL(%d)\n", getarg_bx(c))
|
371
|
+
when OP_EPUSH
|
372
|
+
printf("OP_EPUSH\t:I(%+d)\n", getarg_bx(c))
|
373
|
+
when OP_ONERR
|
374
|
+
printf("OP_ONERR\t%03d\n", i+getarg_sbx(c))
|
375
|
+
when OP_RESCUE
|
376
|
+
printf("OP_RESCUE\tR%d\n", getarg_a(c))
|
377
|
+
when OP_RAISE
|
378
|
+
printf("OP_RAISE\tR%d\n", getarg_a(c))
|
379
|
+
when OP_POPERR
|
380
|
+
printf("OP_POPERR\t%d\n", getarg_a(c))
|
381
|
+
when OP_EPOP
|
382
|
+
printf("OP_EPOP\t%d\n", getarg_a(c))
|
383
|
+
else
|
384
|
+
printf("OP_unknown %d\t%d\t%d\t%d\n", opcode(c),
|
385
|
+
getarg_a(c), getarg_b(c), getarg_c(c))
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
390
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class MrbParser
|
2
|
+
|
3
|
+
##
|
4
|
+
# calculate CRC
|
5
|
+
#
|
6
|
+
# an Ruby port of src/crc.c in mruby
|
7
|
+
#
|
8
|
+
class CRC
|
9
|
+
|
10
|
+
CRC_16_CCITT = 0x11021 ## x^16+x^12+x^5+1
|
11
|
+
CRC_XOR_PATTERN = (CRC_16_CCITT << 8)
|
12
|
+
CRC_CARRY_BIT = 0x01000000
|
13
|
+
CHAR_BIT = 8
|
14
|
+
|
15
|
+
def self.calc_crc_16_ccitt(data0, nbytes, crc)
|
16
|
+
data = data0.unpack("C*")
|
17
|
+
crcwk = crc << 8
|
18
|
+
for ibyte in 0...nbytes
|
19
|
+
crcwk |= data[ibyte]
|
20
|
+
for ibit in 0...CHAR_BIT
|
21
|
+
crcwk <<= 1
|
22
|
+
carry = crcwk & CRC_CARRY_BIT
|
23
|
+
if carry.nonzero?
|
24
|
+
crcwk ^= CRC_XOR_PATTERN
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
return crcwk >> 8
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class MrbParser
|
2
|
+
class DebugInfo
|
3
|
+
|
4
|
+
MRB_DEBUG_LINE_ARY = 0
|
5
|
+
MRB_DEBUG_LINE_FLAT_MAP = 1
|
6
|
+
|
7
|
+
LINE_TYPE = ["ARY", "FLAT_MAP"]
|
8
|
+
|
9
|
+
attr_accessor :pc_count
|
10
|
+
attr_accessor :files
|
11
|
+
attr_accessor :debug_section
|
12
|
+
attr_accessor :irep_record
|
13
|
+
attr_reader :infos
|
14
|
+
|
15
|
+
def initialize(debug_section, irep_record)
|
16
|
+
@debug_section = debug_section
|
17
|
+
@irep_record = irep_record
|
18
|
+
irep_record.debug_info = self
|
19
|
+
@infos = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_record(parser)
|
23
|
+
@pc_count = parser.read_uint32
|
24
|
+
flen = parser.read_uint16
|
25
|
+
@files = []
|
26
|
+
flen.times do
|
27
|
+
file = DebugInfoFile.new
|
28
|
+
@files << file
|
29
|
+
file.start_pos = parser.read_uint32
|
30
|
+
filename_idx = parser.read_uint16
|
31
|
+
file.filename = @debug_section.filenames[filename_idx]
|
32
|
+
|
33
|
+
file.line_entry_count = parser.read_uint32
|
34
|
+
file.line_type = parser.read_uint8
|
35
|
+
case file.line_type
|
36
|
+
when MRB_DEBUG_LINE_ARY ## 0
|
37
|
+
file.line_ary = []
|
38
|
+
file.line_entry_count.times do
|
39
|
+
file.line_ary << parser.read_uint16
|
40
|
+
end
|
41
|
+
when MRB_DEBUG_LINE_FLAT_MAP ## 1
|
42
|
+
file.line_flat_map = []
|
43
|
+
file.line_entry_count.times do
|
44
|
+
start_pos = parser.read_uint32
|
45
|
+
line = parser.read_uint16
|
46
|
+
file.line_flat_map << {start_pos: start_pos, line: line}
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@irep_record.recs.each do |irep_record|
|
53
|
+
info = MrbParser::DebugInfo.new(@debug_section, irep_record)
|
54
|
+
@infos << info
|
55
|
+
info.parse_record(parser)
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def printf_indent(n, *args)
|
61
|
+
print " "*n
|
62
|
+
printf *args
|
63
|
+
end
|
64
|
+
|
65
|
+
def dump(n = 2)
|
66
|
+
printf_indent n, "*** DEBUG INFO ***\n"
|
67
|
+
printf_indent n, "count: %d\n", @pc_count
|
68
|
+
printf_indent n, "files: %d\n", @files.size
|
69
|
+
@files.map{|file| file.dump(n+2)}
|
70
|
+
@infos.each do |debug_info|
|
71
|
+
debug_info.dump(n + 2)
|
72
|
+
end
|
73
|
+
printf_indent n, "*** ***\n"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class MrbParser
|
2
|
+
class DebugInfoFile
|
3
|
+
attr_accessor :start_pos
|
4
|
+
attr_accessor :filename
|
5
|
+
attr_accessor :line_entry_count
|
6
|
+
attr_accessor :line_type
|
7
|
+
|
8
|
+
attr_accessor :line_flat_map
|
9
|
+
attr_accessor :line_ary
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
end
|
13
|
+
|
14
|
+
def printf_indent(n, *args)
|
15
|
+
print " "*n
|
16
|
+
printf *args
|
17
|
+
end
|
18
|
+
|
19
|
+
def dump(n = 2)
|
20
|
+
printf_indent n, "*** DEBUG INFO FILE ***\n"
|
21
|
+
printf_indent n, "start: %d\n", @start_pos
|
22
|
+
printf_indent n, "fname: %s\n", @filename
|
23
|
+
printf_indent n, "line type: %d (%s)\n", @line_type,
|
24
|
+
MrbParser::DebugInfo::LINE_TYPE[@line_type]
|
25
|
+
printf_indent n, "lines: %d\n", @line_entry_count
|
26
|
+
case @line_type
|
27
|
+
when MrbParser::DebugInfo::MRB_DEBUG_LINE_ARY
|
28
|
+
@line_ary.each do |line|
|
29
|
+
printf_indent n, " line: %d\n", line
|
30
|
+
end
|
31
|
+
when MrbParser::DebugInfo::MRB_DEBUG_LINE_FLAT_MAP
|
32
|
+
@line_flat_map.each do |map|
|
33
|
+
printf_indent n, " line: %d, start_pos: %d\n", map[:line], map[:start_pos]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
printf_indent n, "*** ***\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mrb_parser/debug_info'
|
2
|
+
require 'mrb_parser/debug_info_file'
|
3
|
+
|
4
|
+
class MrbParser
|
5
|
+
class DebugSection < Section
|
6
|
+
|
7
|
+
attr_accessor :debug_info
|
8
|
+
attr_accessor :filenames
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_record(parser)
|
15
|
+
rec = parser.irep_section.rec
|
16
|
+
@debug_info = MrbParser::DebugInfo.new(self, rec)
|
17
|
+
@debug_info.parse_record(parser)
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_body(parser)
|
21
|
+
filenames_len = parser.read_uint16
|
22
|
+
@filenames = []
|
23
|
+
filenames_len.times do
|
24
|
+
@filenames << parser.read_n16string
|
25
|
+
end
|
26
|
+
parse_record(parser)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def dump
|
31
|
+
printf "*** DEBUG SECTION ***\n"
|
32
|
+
printf "secID: %s\n", @signature
|
33
|
+
printf "size : %s\n", @size
|
34
|
+
printf "files: %d\n", @filenames.size
|
35
|
+
@filenames.each do |fname|
|
36
|
+
printf " filename: %s\n", fname
|
37
|
+
end
|
38
|
+
@debug_info.dump
|
39
|
+
printf "*** ***\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class MrbParser
|
2
|
+
class EndSection < Section
|
3
|
+
def initialize(*)
|
4
|
+
super
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse_body(parser)
|
8
|
+
end
|
9
|
+
|
10
|
+
def end?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def dump
|
15
|
+
printf "*** END SECTION ***\n"
|
16
|
+
printf "secID: %s\n", @signature
|
17
|
+
printf "size : %s\n", @size
|
18
|
+
printf "*** ***\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'mrb_parser/crc'
|
2
|
+
class MrbParser
|
3
|
+
class Header
|
4
|
+
|
5
|
+
attr_reader :signature, :version, :crc, :size,
|
6
|
+
:compiler_name, :compiler_version
|
7
|
+
|
8
|
+
def self.parse(parser)
|
9
|
+
header = Header.new()
|
10
|
+
header.parse(parser)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(parser)
|
17
|
+
@signature = parser.read_chars(4)
|
18
|
+
@version = parser.read_chars(4)
|
19
|
+
@crc = parser.read_uint16
|
20
|
+
@crc_verified = check_crc(parser)
|
21
|
+
@size = parser.read_uint32
|
22
|
+
@compiler_name = parser.read_chars(4)
|
23
|
+
@compiler_version = parser.read_chars(4)
|
24
|
+
|
25
|
+
if parser.verbose
|
26
|
+
if !valid?
|
27
|
+
STDERR.print "** [WARN] This header seems to be invalid. **\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_crc(parser)
|
35
|
+
pos = parser.pos
|
36
|
+
rest_data = parser.read(nil)
|
37
|
+
parser.seek(pos)
|
38
|
+
checksum = MrbParser::CRC.calc_crc_16_ccitt(rest_data, rest_data.size, 0)
|
39
|
+
@crc == checksum
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def valid?
|
44
|
+
@signature == "RITE" && @version == "0002" && @crc_verified
|
45
|
+
end
|
46
|
+
|
47
|
+
def dump
|
48
|
+
printf "*** BINARY HEADER ***\n"
|
49
|
+
printf "secID: %s\n", @signature
|
50
|
+
printf "ver : %s\n", @version
|
51
|
+
printf "crc : 0x%04x (%s)\n", @crc, @crc_verified
|
52
|
+
printf "size : 0x%08x\n", @size
|
53
|
+
printf "compiler:\n"
|
54
|
+
printf " name: %s\n", @compiler_name
|
55
|
+
printf " ver : %s\n", @compiler_version
|
56
|
+
printf "*** ***\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'mrb_parser/code_dump'
|
2
|
+
|
3
|
+
class MrbParser
|
4
|
+
class IrepRecord
|
5
|
+
|
6
|
+
IREP_TT_STRING = 0
|
7
|
+
IREP_TT_FIXNUM = 1
|
8
|
+
IREP_TT_FLOAT = 2
|
9
|
+
|
10
|
+
MRB_DUMP_NULL_SYM_LEN = 0xFFFF
|
11
|
+
|
12
|
+
attr_accessor :debug_info
|
13
|
+
attr_reader :recs
|
14
|
+
attr_reader :syms
|
15
|
+
attr_reader :pool
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_record(parser)
|
21
|
+
@section_size = parser.read_uint32
|
22
|
+
@nlocals = parser.read_uint16
|
23
|
+
@nregs = parser.read_uint16
|
24
|
+
rlen = parser.read_uint16
|
25
|
+
parse_iseq(parser)
|
26
|
+
parse_pool(parser)
|
27
|
+
parse_symbol(parser)
|
28
|
+
@recs = []
|
29
|
+
rlen.times do |i|
|
30
|
+
rec = IrepRecord.new()
|
31
|
+
@recs[i] = rec.parse_record(parser)
|
32
|
+
end
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_iseq(parser)
|
37
|
+
ilen = parser.read_uint32
|
38
|
+
@iseq = []
|
39
|
+
ilen.times do |i|
|
40
|
+
@iseq << parser.read_uint32
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_pool(parser)
|
45
|
+
plen = parser.read_uint32
|
46
|
+
@pool = []
|
47
|
+
plen.times do |i|
|
48
|
+
type = parser.read_uint8
|
49
|
+
str = parser.read_n16string
|
50
|
+
case type
|
51
|
+
when IREP_TT_FIXNUM
|
52
|
+
@pool[i] = Integer(str)
|
53
|
+
when IREP_TT_FLOAT
|
54
|
+
@pool[i] = Float(str)
|
55
|
+
when IREP_TT_STRING
|
56
|
+
@pool[i] = str
|
57
|
+
else
|
58
|
+
@pool[i] = nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_symbol(parser)
|
64
|
+
slen = parser.read_uint32
|
65
|
+
@syms = []
|
66
|
+
slen.times do |i|
|
67
|
+
len = parser.read_uint16
|
68
|
+
if len == MRB_DUMP_NULL_SYM_LEN
|
69
|
+
@syms[i] = nil
|
70
|
+
next
|
71
|
+
end
|
72
|
+
@syms[i] = parser.read_chars(len)
|
73
|
+
terminater = parser.read_uint8 ## skip NULL byte
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def printf_indent(n, *args)
|
78
|
+
print " "*n
|
79
|
+
printf *args
|
80
|
+
end
|
81
|
+
|
82
|
+
def dump(n = 2)
|
83
|
+
code_dump = MrbParser::CodeDump.new(self)
|
84
|
+
printf_indent n, "*** IREP RECORD ***\n"
|
85
|
+
printf_indent n, "locals: %d\n", @nlocals
|
86
|
+
printf_indent n, "regs : %d\n", @nregs
|
87
|
+
printf_indent n, "iseqs : %d\n", @iseq.size
|
88
|
+
@iseq.each_with_index do |code, i|
|
89
|
+
printf_indent n, " code: %08x\n", code
|
90
|
+
printf_indent n, " "
|
91
|
+
code_dump.dump(code, i)
|
92
|
+
end
|
93
|
+
printf_indent n, "pools : %d\n", @pool.size
|
94
|
+
@pool.each do |pool|
|
95
|
+
printf_indent n, " pool: %s\n", pool.inspect
|
96
|
+
end
|
97
|
+
printf_indent n, "syms : %d\n", @syms.size
|
98
|
+
@syms.each do |item|
|
99
|
+
printf_indent n, " sym: %s\n", item.inspect
|
100
|
+
end
|
101
|
+
printf_indent n, "ireps : %d\n", @recs.size
|
102
|
+
@recs.each do |rec|
|
103
|
+
rec.dump(n+2)
|
104
|
+
end
|
105
|
+
printf_indent n, "*** ***\n"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'mrb_parser/irep_record'
|
2
|
+
class MrbParser
|
3
|
+
class IrepSection < Section
|
4
|
+
|
5
|
+
attr_reader :rec
|
6
|
+
|
7
|
+
def initialize(*)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_body(parser)
|
12
|
+
@vm_version = parser.read_chars(4)
|
13
|
+
@rec = parse_record(parser)
|
14
|
+
parser.irep_section = self
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse_record(parser)
|
19
|
+
rec = MrbParser::IrepRecord.new
|
20
|
+
rec.parse_record(parser)
|
21
|
+
rec
|
22
|
+
end
|
23
|
+
|
24
|
+
def dump
|
25
|
+
printf "*** IREP SECTION ***\n"
|
26
|
+
printf "secID : %s\n", @signature
|
27
|
+
printf "size : %s\n", @size
|
28
|
+
printf "vm ver: %s\n", @vm_version
|
29
|
+
@rec.dump
|
30
|
+
printf "*** ***\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class MrbParser
|
2
|
+
class LinenoSection < Section
|
3
|
+
def initialize(*)
|
4
|
+
super
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse_body(parser, irep_record = nil)
|
8
|
+
record_size = parser.read_uint32
|
9
|
+
@filename = parser.read_n16string
|
10
|
+
@niseq = parser.read_uint32
|
11
|
+
@lines = []
|
12
|
+
@niseq.times do |i|
|
13
|
+
line = parser.read_uint16
|
14
|
+
@lines << line
|
15
|
+
end
|
16
|
+
|
17
|
+
unless irep_record
|
18
|
+
irep_record = parser.irep_section.rec
|
19
|
+
end
|
20
|
+
irep_record.debug_info = self
|
21
|
+
|
22
|
+
irep_record.recs.each do |rec|
|
23
|
+
parse_body(parser, rec)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def dump
|
28
|
+
printf "*** LINENO SECTION ***\n"
|
29
|
+
printf "secID : %s\n", @signature
|
30
|
+
printf "size : %s\n", @size
|
31
|
+
printf "*** ***\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class MrbParser
|
2
|
+
class Section
|
3
|
+
|
4
|
+
require 'mrb_parser/irep_section'
|
5
|
+
require 'mrb_parser/lineno_section'
|
6
|
+
require 'mrb_parser/debug_section'
|
7
|
+
require 'mrb_parser/end_section'
|
8
|
+
|
9
|
+
BINARY_EOF = "END\0"
|
10
|
+
IREP_IDENTIFIER = "IREP"
|
11
|
+
LINENO_IDENTIFIER = "LINE"
|
12
|
+
DEBUG_IDENTIFIER = "DBG\0"
|
13
|
+
|
14
|
+
attr_reader :signature, :size
|
15
|
+
|
16
|
+
def initialize(signature = nil, size = nil)
|
17
|
+
@signature = signature
|
18
|
+
@size = size
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse(parser)
|
22
|
+
section = MrbParser::Section.new
|
23
|
+
section.parse(parser)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(parser)
|
27
|
+
signature = parser.read_chars(4)
|
28
|
+
size = parser.read_uint32
|
29
|
+
case signature
|
30
|
+
when IREP_IDENTIFIER
|
31
|
+
section = MrbParser::IrepSection
|
32
|
+
when LINENO_IDENTIFIER
|
33
|
+
section = MrbParser::LinenoSection
|
34
|
+
when DEBUG_IDENTIFIER
|
35
|
+
section = MrbParser::DebugSection
|
36
|
+
when BINARY_EOF
|
37
|
+
section = MrbParser::EndSection
|
38
|
+
else
|
39
|
+
raise MrbParser::Error, "cannot parse; invalid section signature: '#{signature}'"
|
40
|
+
end
|
41
|
+
sec = section.new(signature, size)
|
42
|
+
sec.parse_body(parser)
|
43
|
+
sec
|
44
|
+
end
|
45
|
+
|
46
|
+
def end?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class MrbParser
|
2
|
+
module Utils
|
3
|
+
def read(n)
|
4
|
+
@data.read(n)
|
5
|
+
end
|
6
|
+
|
7
|
+
def pos
|
8
|
+
@data.pos
|
9
|
+
end
|
10
|
+
|
11
|
+
def seek(n)
|
12
|
+
@data.seek(n)
|
13
|
+
end
|
14
|
+
|
15
|
+
def read_format(pat, n)
|
16
|
+
byteseq = @data.read(n)
|
17
|
+
val = byteseq.unpack(pat)[0]
|
18
|
+
if @verbose
|
19
|
+
p [@data, n, val]
|
20
|
+
end
|
21
|
+
val
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_uint8
|
25
|
+
read_format("C1", 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
def read_uint16
|
29
|
+
read_format("n1", 2)
|
30
|
+
end
|
31
|
+
|
32
|
+
def read_uint32
|
33
|
+
read_format("N1", 4)
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_chars(n)
|
37
|
+
read_format("a#{n}", n)
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_n16string
|
41
|
+
len = read_uint16
|
42
|
+
read_format("a#{len}", len)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/mrb_parser.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'mrb_parser/header'
|
2
|
+
require 'mrb_parser/section'
|
3
|
+
require 'mrb_parser/error'
|
4
|
+
require "mrb_parser/version"
|
5
|
+
require "mrb_parser/utils"
|
6
|
+
|
7
|
+
class MrbParser
|
8
|
+
include MrbParser::Utils
|
9
|
+
|
10
|
+
attr_accessor :verbose
|
11
|
+
attr_accessor :irep_section
|
12
|
+
attr_reader :header, :sections
|
13
|
+
|
14
|
+
def self.parse(filename)
|
15
|
+
parser = MrbParser.new(filename)
|
16
|
+
parser.parse
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(filename)
|
20
|
+
@filename = filename
|
21
|
+
@data = nil
|
22
|
+
@irep_section = nil
|
23
|
+
@sections = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse
|
27
|
+
@data = File.open(@filename)
|
28
|
+
@header = MrbParser::Header.parse(self)
|
29
|
+
|
30
|
+
while true
|
31
|
+
section = MrbParser::Section.parse(self)
|
32
|
+
@sections << section
|
33
|
+
break if section.end?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def dump
|
38
|
+
@header.dump
|
39
|
+
@sections.each do |section|
|
40
|
+
section.dump
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/mrb_parser.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mrb_parser/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "mrb_parser"
|
8
|
+
spec.version = MrbParser::VERSION
|
9
|
+
spec.authors = ["yamanekko"]
|
10
|
+
spec.email = ["yamanekko@tatsu-zine.com"]
|
11
|
+
spec.description = %q{simple library to parse mrb file, mruby bytecode file.}
|
12
|
+
spec.summary = %q{mrb (mruby bytecode) parser}
|
13
|
+
spec.homepage = "https://github.com/yamanekko/mrb_parser"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../lib/mrb_parser'
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mrb_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- yamanekko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: simple library to parse mrb file, mruby bytecode file.
|
56
|
+
email:
|
57
|
+
- yamanekko@tatsu-zine.com
|
58
|
+
executables:
|
59
|
+
- mrb_parser
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/mrb_parser
|
69
|
+
- lib/mrb_parser.rb
|
70
|
+
- lib/mrb_parser/code_dump.rb
|
71
|
+
- lib/mrb_parser/crc.rb
|
72
|
+
- lib/mrb_parser/debug_info.rb
|
73
|
+
- lib/mrb_parser/debug_info_file.rb
|
74
|
+
- lib/mrb_parser/debug_section.rb
|
75
|
+
- lib/mrb_parser/end_section.rb
|
76
|
+
- lib/mrb_parser/error.rb
|
77
|
+
- lib/mrb_parser/header.rb
|
78
|
+
- lib/mrb_parser/irep_record.rb
|
79
|
+
- lib/mrb_parser/irep_section.rb
|
80
|
+
- lib/mrb_parser/lineno_section.rb
|
81
|
+
- lib/mrb_parser/section.rb
|
82
|
+
- lib/mrb_parser/utils.rb
|
83
|
+
- lib/mrb_parser/version.rb
|
84
|
+
- mrb_parser.gemspec
|
85
|
+
- spec/spec_helper.rb
|
86
|
+
homepage: https://github.com/yamanekko/mrb_parser
|
87
|
+
licenses:
|
88
|
+
- MIT
|
89
|
+
metadata: {}
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 2.2.0.rc.1
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: mrb (mruby bytecode) parser
|
110
|
+
test_files:
|
111
|
+
- spec/spec_helper.rb
|