Opdis 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/module/Model.h ADDED
@@ -0,0 +1,230 @@
1
+ /* Model.h
2
+ * Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
3
+ * Written by TG Community Developers <community@thoughtgang.org>
4
+ * Released under the GNU Public License, version 3.
5
+ * See http://www.gnu.org/licenses/gpl.txt for details.
6
+ */
7
+
8
+ #ifndef OPDIS_RB_MODEL_H
9
+ #define OPDIS_RB_MODEL_H
10
+
11
+ #include <opdis/opdis.h>
12
+ #include <ruby.h>
13
+
14
+ #define GEN_ATTR_ASCII "ascii"
15
+
16
+ /* Instruction Class */
17
+ #define INSN_DECODE_INVALID_NAME "DECODE_INVALID"
18
+ #define INSN_DECODE_INVALID "invalid"
19
+ #define INSN_DECODE_BASIC_NAME "DECODE_BASIC"
20
+ #define INSN_DECODE_BASIC "basic"
21
+ #define INSN_DECODE_MNEM_NAME "DECODE_MNEMONIC"
22
+ #define INSN_DECODE_MNEM "mnemonic"
23
+ #define INSN_DECODE_OPS_NAME "DECODE_OPERANDS"
24
+ #define INSN_DECODE_OPS "operands"
25
+ #define INSN_DECODE_MNEMFLG_NAME "DECODE_MNEMONIC_FLAGS"
26
+ #define INSN_DECODE_MNEMFLG "mnemonic flags"
27
+ #define INSN_DECODE_OPFLG_NAME "DECODE_OPERAND_FLAGS"
28
+ #define INSN_DECODE_OPFLG "operand flags"
29
+
30
+ #define INSN_ATTR_STATUS "status"
31
+ #define INSN_ATTR_OFFSET "offset"
32
+ #define INSN_ATTR_VMA "vma"
33
+ #define INSN_ATTR_SIZE "size"
34
+ #define INSN_ATTR_BYTES "bytes"
35
+ #define INSN_ATTR_PREFIXES "prefixes"
36
+ #define INSN_ATTR_MNEMONIC "mnemonic"
37
+ #define INSN_ATTR_CATEGORY "category"
38
+ #define INSN_ATTR_ISA "isa"
39
+ #define INSN_ATTR_FLAGS "flags"
40
+ #define INSN_ATTR_FLAGS "flags"
41
+ #define INSN_ATTR_COMMENT "comment"
42
+ #define INSN_ATTR_OPERANDS "operands"
43
+ #define INSN_ATTR_TGT "target" // method
44
+ #define INSN_ATTR_DEST "dest" // method
45
+ #define INSN_ATTR_SRC "src" // method
46
+ #define INSN_ATTR_TGT_IDX "tgt_idx" // private
47
+ #define INSN_ATTR_DEST_IDX "dest_idx" // private
48
+ #define INSN_ATTR_SRC_IDX "src_idx" // private
49
+
50
+ #define INSN_ISA_GEN_NAME "ISA_GEN"
51
+ #define INSN_ISA_GEN "general"
52
+ #define INSN_ISA_FPU_NAME "ISA_FPU"
53
+ #define INSN_ISA_FPU "fpu"
54
+ #define INSN_ISA_GPU_NAME "ISA_GPU"
55
+ #define INSN_ISA_GPU "gpu"
56
+ #define INSN_ISA_SIMD_NAME "ISA_SIMD"
57
+ #define INSN_ISA_SIMD "simd"
58
+ #define INSN_ISA_VM_NAME "ISA_VM"
59
+ #define INSN_ISA_VM "vm"
60
+
61
+ #define INSN_CAT_CFLOW_NAME "CAT_CFLOW"
62
+ #define INSN_CAT_CFLOW "control-flow"
63
+ #define INSN_CAT_STACK_NAME "CAT_STACK"
64
+ #define INSN_CAT_STACK "stack"
65
+ #define INSN_CAT_LOST_NAME "CAT_LOADSTORE"
66
+ #define INSN_CAT_LOST "load/store"
67
+ #define INSN_CAT_TEST_NAME "CAT_TEST"
68
+ #define INSN_CAT_TEST "test"
69
+ #define INSN_CAT_MATH_NAME "CAT_MATH"
70
+ #define INSN_CAT_MATH "mathematic"
71
+ #define INSN_CAT_BIT_NAME "CAT_BIT"
72
+ #define INSN_CAT_BIT "bitwise"
73
+ #define INSN_CAT_IO_NAME "CAT_IO"
74
+ #define INSN_CAT_IO "i/o"
75
+ #define INSN_CAT_TRAP_NAME "CAT_TRAP"
76
+ #define INSN_CAT_TRAP "trap"
77
+ #define INSN_CAT_PRIV_NAME "CAT_PRIV"
78
+ #define INSN_CAT_PRIV "privileged"
79
+ #define INSN_CAT_NOP_NAME "CAT_NOP"
80
+ #define INSN_CAT_NOP "no-op"
81
+
82
+ #define INSN_FLAG_CALL_NAME "FLG_CALL"
83
+ #define INSN_FLAG_CALL "call"
84
+ #define INSN_FLAG_CALLCC_NAME "FLG_CALLCC"
85
+ #define INSN_FLAG_CALLCC "conditional call"
86
+ #define INSN_FLAG_JMP_NAME "JMP"
87
+ #define INSN_FLAG_JMP "jump"
88
+ #define INSN_FLAG_JMPCC_NAME "FLG_JMPCC"
89
+ #define INSN_FLAG_JMPCC "conditional jump"
90
+ #define INSN_FLAG_RET_NAME "FLG_RET"
91
+ #define INSN_FLAG_RET "return"
92
+ #define INSN_FLAG_PUSH_NAME "FLG_PUSH"
93
+ #define INSN_FLAG_PUSH "push"
94
+ #define INSN_FLAG_POP_NAME "FLG_POP"
95
+ #define INSN_FLAG_POP "pop"
96
+ #define INSN_FLAG_FRAME_NAME "FLG_FRAME"
97
+ #define INSN_FLAG_FRAME "enter frame"
98
+ #define INSN_FLAG_UNFRAME_NAME "FLG_UNFRAME"
99
+ #define INSN_FLAG_UNFRAME "exit frame"
100
+ #define INSN_FLAG_AND_NAME "FLG_AND"
101
+ #define INSN_FLAG_AND "bitwise and"
102
+ #define INSN_FLAG_OR_NAME "FLG_OR"
103
+ #define INSN_FLAG_OR "bitwise or"
104
+ #define INSN_FLAG_XOR_NAME "FLG_XOR"
105
+ #define INSN_FLAG_XOR "bitwise xor"
106
+ #define INSN_FLAG_NOT_NAME "FLG_NOT"
107
+ #define INSN_FLAG_NOT "bitwise not"
108
+ #define INSN_FLAG_LSL_NAME "FLG_LSL"
109
+ #define INSN_FLAG_LSL "logical shift left"
110
+ #define INSN_FLAG_LSR_NAME "FLG_LSR"
111
+ #define INSN_FLAG_LSR "logical shift right"
112
+ #define INSN_FLAG_ASL_NAME "FLG_ASL"
113
+ #define INSN_FLAG_ASL "arithmetic shift left"
114
+ #define INSN_FLAG_ASR_NAME "FLG_ASR"
115
+ #define INSN_FLAG_ASR "arithmetic shift right"
116
+ #define INSN_FLAG_ROL_NAME "FLG_ROL"
117
+ #define INSN_FLAG_ROL "rotate left"
118
+ #define INSN_FLAG_ROR_NAME "FLG_ROR"
119
+ #define INSN_FLAG_ROR "rotate right"
120
+ #define INSN_FLAG_RCL_NAME "FLG_RCL"
121
+ #define INSN_FLAG_RCL "rotate carry left"
122
+ #define INSN_FLAG_RCR_NAME "FLG_RCR"
123
+ #define INSN_FLAG_RCR "rotate carry right"
124
+ #define INSN_FLAG_OUT_NAME "FLG_OUT"
125
+ #define INSN_FLAG_OUT "input from port"
126
+ #define INSN_FLAG_IN_NAME "FLG_IN"
127
+ #define INSN_FLAG_IN "output to port"
128
+
129
+ /* Operand Base Class */
130
+
131
+ #define OP_ATTR_FLAGS "flags"
132
+ #define OP_ATTR_DATA_SZ "data_size"
133
+
134
+ #define OP_FLAG_R_NAME "FLG_READ"
135
+ #define OP_FLAG_R "r"
136
+ #define OP_FLAG_W_NAME "FLG_WRITE"
137
+ #define OP_FLAG_W "w"
138
+ #define OP_FLAG_X_NAME "FLG_EXEC"
139
+ #define OP_FLAG_X "x"
140
+ #define OP_FLAG_SIGNED_NAME "FLG_SIGNED"
141
+ #define OP_FLAG_SIGNED "signed"
142
+ #define OP_FLAG_ADDR_NAME "FLG_ADDR"
143
+ #define OP_FLAG_ADDR "address"
144
+ #define OP_FLAG_IND_NAME "FLG_INDIRECT"
145
+ #define OP_FLAG_IND "indirect_address"
146
+
147
+ /* Immediate Class */
148
+ #define IMM_ATTR_VAL "value"
149
+ #define IMM_ATTR_SIGNED "signed"
150
+ #define IMM_ATTR_UNSIGNED "unsigned"
151
+ #define IMM_ATTR_VMA "vma"
152
+
153
+ /* Address Expression Class */
154
+
155
+ #define ADDR_EXP_ATTR_SHIFT "shift"
156
+ #define ADDR_EXP_ATTR_SCALE "scale"
157
+ #define ADDR_EXP_ATTR_INDEX "index"
158
+ #define ADDR_EXP_ATTR_BASE "base"
159
+ #define ADDR_EXP_ATTR_DISP "displacement"
160
+
161
+ #define ADDR_EXP_SHIFT_LSL_NAME "SHIFT_LSL"
162
+ #define ADDR_EXP_SHIFT_LSL "lsl"
163
+ #define ADDR_EXP_SHIFT_LSR_NAME "SHIFT_LSR"
164
+ #define ADDR_EXP_SHIFT_LSR "lsr"
165
+ #define ADDR_EXP_SHIFT_ASL_NAME "SHIFT_ASL"
166
+ #define ADDR_EXP_SHIFT_ASL "asl"
167
+ #define ADDR_EXP_SHIFT_ROR_NAME "SHIFT_ROR"
168
+ #define ADDR_EXP_SHIFT_ROR "ror"
169
+ #define ADDR_EXP_SHIFT_RRX_NAME "SHIFT_RRX"
170
+ #define ADDR_EXP_SHIFT_RRX "rrx"
171
+
172
+ /* Absolute Address Class */
173
+
174
+ #define ABS_ADDR_ATTR_SEG "segment"
175
+ #define ABS_ADDR_ATTR_OFF "offset"
176
+
177
+ /* Register Class */
178
+
179
+ #define REG_ATTR_FLAGS "purpose"
180
+ #define REG_ATTR_ID "id"
181
+ #define REG_ATTR_SIZE "size"
182
+ #define REG_ATTR_NAME "name"
183
+
184
+ #define REG_FLAG_GEN_NAME "FLG_GEN"
185
+ #define REG_FLAG_GEN "general purpose"
186
+ #define REG_FLAG_FPU_NAME "FLG_FPU"
187
+ #define REG_FLAG_FPU "fpu"
188
+ #define REG_FLAG_GPU_NAME "FLG_GPU"
189
+ #define REG_FLAG_GPU "gpu"
190
+ #define REG_FLAG_SIMD_NAME "FLG_SIMD"
191
+ #define REG_FLAG_SIMD "simd"
192
+ #define REG_FLAG_TASK_NAME "FLG_TASK"
193
+ #define REG_FLAG_TASK "task_mgt"
194
+ #define REG_FLAG_MEM_NAME "FLG_MEM"
195
+ #define REG_FLAG_MEM "memory_mgt"
196
+ #define REG_FLAG_DBG_NAME "FLG_DEBUG"
197
+ #define REG_FLAG_DBG "debug"
198
+ #define REG_FLAG_PC_NAME "FLG_PC"
199
+ #define REG_FLAG_PC "pc"
200
+ #define REG_FLAG_CC_NAME "FLG_FLAGS"
201
+ #define REG_FLAG_CC "flags"
202
+ #define REG_FLAG_STACK_NAME "FLG_STACK"
203
+ #define REG_FLAG_STACK "stack"
204
+ #define REG_FLAG_FRAME_NAME "FLG_FRAME"
205
+ #define REG_FLAG_FRAME "stack_frame"
206
+ #define REG_FLAG_SEG_NAME "FLG_SEGMENT"
207
+ #define REG_FLAG_SEG "segment"
208
+ #define REG_FLAG_Z_NAME "FLG_ZERO"
209
+ #define REG_FLAG_Z "zero"
210
+ #define REG_FLAG_IN_NAME "FLG_IN"
211
+ #define REG_FLAG_IN "args in"
212
+ #define REG_FLAG_OUT_NAME "FLG_OUT"
213
+ #define REG_FLAG_OUT "args out"
214
+ #define REG_FLAG_LOCALS_NAME "FLG_LOCALS"
215
+ #define REG_FLAG_LOCALS "locals"
216
+ #define REG_FLAG_RET_NAME "FLG_RET"
217
+ #define REG_FLAG_RET "return"
218
+
219
+ void Opdis_initModel( VALUE modOpdis );
220
+
221
+ /* Allocate and fill a Ruby Opdis::Instruction object from an opdis_insn_t */
222
+ VALUE Opdis_insnFromC( const opdis_insn_t * insn );
223
+
224
+ /* Fill a Ruby Opdis::Instruction object from an opdis_insn_t */
225
+ int Opdis_insnFillFromC( const opdis_insn_t * insn, VALUE dest );
226
+
227
+ /* Fill an opdis_insn_t from a Ruby Opdis::Instruction object */
228
+ int Opdis_insnToC( VALUE insn, opdis_insn_t * c_insn );
229
+
230
+ #endif
data/module/Opdis.c ADDED
@@ -0,0 +1,850 @@
1
+ /* Opdis.c
2
+ * Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
3
+ * Written by TG Community Developers <community@thoughtgang.org>
4
+ * Released under the GNU Public License, version 3.
5
+ * See http://www.gnu.org/licenses/gpl.txt for details.
6
+ */
7
+
8
+ #include <errno.h>
9
+ #include <string.h>
10
+
11
+ #include <ruby.h>
12
+ #include "ruby_compat.h"
13
+
14
+ #include <opdis/opdis.h>
15
+
16
+ #include "Opdis.h"
17
+ #include "Arch.h"
18
+ #include "Callbacks.h"
19
+ #include "Model.h"
20
+
21
+ #define IVAR(attr) "@" attr
22
+ #define SETTER(attr) attr "="
23
+
24
+ static VALUE symToSym, symRead, symCall, symSize, symPath;
25
+ static VALUE symDecode, symVisited, symResolve;
26
+
27
+ static VALUE clsDisasm, clsOutput;
28
+
29
+ static VALUE modOpdis;
30
+
31
+ static VALUE str_to_sym( const char * str ) {
32
+ VALUE var = rb_str_new_cstr(str);
33
+ return (var == Qnil) ? Qnil : rb_funcall(var, symToSym, 0);
34
+ }
35
+
36
+ /* BFD Support (requires BFD gem) */
37
+ static VALUE clsBfdTgt = Qnil;
38
+ static VALUE clsBfdSec = Qnil;
39
+ static VALUE clsBfdSym = Qnil;
40
+
41
+ #define GET_BFD_CLASS(cls,name) (cls = cls == Qnil ? path2class(name) : cls)
42
+
43
+ #define ALLOC_FIXED_INSN opdis_insn_alloc_fixed(128, 32, 16, 32)
44
+
45
+
46
+ /* ---------------------------------------------------------------------- */
47
+ /* Disasm Output Class */
48
+ /* This is basically a Hash of VMA => Instruction entries, with an @errors
49
+ * attribute that gets filled with error messages from the disassembler */
50
+
51
+ /* insn containing vma */
52
+ static VALUE cls_output_contain( VALUE instance, VALUE vma ) {
53
+ unsigned long long addr = NUM2ULL(vma);
54
+ /* NOTE: '32 bytes is the largest insn' may not be valid */
55
+ unsigned long long orig = addr, min = addr - 32;
56
+ int cont = 1;
57
+
58
+ /* iterate backwards from vma looking for insn containing vma */
59
+ for ( cont = 1; cont > 0 && addr >= min; addr -= 1 ) {
60
+ VALUE rb_size;
61
+ VALUE val = rb_hash_lookup2( instance, ULL2NUM(addr), Qfalse );
62
+
63
+ if ( val == Qfalse ) {
64
+ if ( addr == 0 ) {
65
+ cont = 0;
66
+ }
67
+ continue;
68
+ }
69
+
70
+ /* requested vma exists; return it */
71
+ if ( addr == orig ) {
72
+ return val;
73
+ }
74
+
75
+ /* does insn contain (insn.size + addr) requested vma? */
76
+ rb_size = rb_funcall(val, rb_intern(IVAR(INSN_ATTR_SIZE)), 0);
77
+ if ( rb_size == Qnil || addr + NUM2UINT(rb_size) < orig ) {
78
+ /* nope - no insn contains requested vma */
79
+ cont = 0;
80
+ } else {
81
+ /* yup - found it */
82
+ return val;
83
+ }
84
+ }
85
+
86
+ return Qfalse;
87
+ }
88
+
89
+ static VALUE cls_output_init( VALUE instance ) {
90
+ rb_iv_set(instance, IVAR(OUT_ATTR_ERRORS), rb_ary_new() );
91
+ return instance;
92
+ }
93
+
94
+ static void init_output_class( VALUE modOpdis ) {
95
+ clsOutput = rb_define_class_under(modOpdis, OPDIS_OUTPUT_CLASS_NAME,
96
+ rb_cHash);
97
+ rb_define_method(clsOutput, "initialize", cls_output_init, 0);
98
+
99
+ /* read-only attribute for error list */
100
+ rb_define_attr(clsOutput, OUT_ATTR_ERRORS, 1, 0);
101
+
102
+ /* setters */
103
+ rb_define_method(clsOutput, OUT_METHOD_CONTAIN, cls_output_contain, 1);
104
+ }
105
+
106
+
107
+ /* ---------------------------------------------------------------------- */
108
+ /* Disassembler Class */
109
+
110
+ /* list all recognized syntaxes */
111
+ static VALUE cls_disasm_syntaxes( VALUE class ) {
112
+ VALUE ary = rb_ary_new();
113
+ rb_ary_push( ary, rb_str_new_cstr(DIS_SYNTAX_ATT) );
114
+ rb_ary_push( ary, rb_str_new_cstr(DIS_SYNTAX_INTEL) );
115
+ return ary;
116
+ }
117
+
118
+ static int fill_disasm_def_array( const Opdis_disasm_def * def, void * arg ) {
119
+ VALUE * ary = (VALUE *) arg;
120
+ const Opdis_disasm_def * invalid = Opdis_disasm_invalid();
121
+
122
+ /* do not report the INVALID disasm def */
123
+ if ( def != invalid ) {
124
+ rb_ary_push( * ary, rb_str_new_cstr(def->name) );
125
+ }
126
+
127
+ return 1;
128
+ }
129
+
130
+ /* list all recognized architectures */
131
+ static VALUE cls_disasm_architectures( VALUE class ) {
132
+ VALUE ary = rb_ary_new();
133
+
134
+ Opdis_disasm_iter( fill_disasm_def_array, &ary );
135
+
136
+ return ary;
137
+ }
138
+
139
+ /* list all recognized disassembly algorithms */
140
+ static VALUE cls_disasm_strategies( VALUE class ) {
141
+ VALUE ary = rb_ary_new();
142
+ rb_ary_push( ary, rb_str_new_cstr(DIS_STRAT_SINGLE) );
143
+ rb_ary_push( ary, rb_str_new_cstr(DIS_STRAT_LINEAR) );
144
+ rb_ary_push( ary, rb_str_new_cstr(DIS_STRAT_CFLOW) );
145
+ rb_ary_push( ary, rb_str_new_cstr(DIS_STRAT_SYMBOL) );
146
+ rb_ary_push( ary, rb_str_new_cstr(DIS_STRAT_SECTION) );
147
+ rb_ary_push( ary, rb_str_new_cstr(DIS_STRAT_ENTRY) );
148
+ return ary;
149
+ }
150
+
151
+ /* local decoder callback: this calls the decode method in the object provided
152
+ * by the user. */
153
+ static int local_decoder( const opdis_insn_buf_t in, opdis_insn_t * out,
154
+ const opdis_byte_t * buf, opdis_off_t offset,
155
+ opdis_vma_t vma, opdis_off_t length, void * arg ) {
156
+ /* Build a hash containing the arguments passed to the decoder */
157
+ VALUE hash = Opdis_decoderHash( in, buf, offset, vma, length );
158
+ /* Create a Ruby Opdis::Instruction object based on the C object */
159
+ VALUE insn = Opdis_insnFromC(out);
160
+ VALUE obj = (VALUE) arg;
161
+
162
+ /* invoke decode method in Decoder object */
163
+ VALUE var = rb_funcall(obj, symDecode, 2, insn, hash);
164
+
165
+ /* Move info back to C domain */
166
+ Opdis_insnToC( insn, out );
167
+
168
+ return (Qfalse == var || Qnil == var) ? 0 : 1;
169
+ }
170
+
171
+ static VALUE cls_disasm_set_decoder(VALUE instance, VALUE obj) {
172
+ opdis_t opdis;
173
+ Data_Get_Struct(instance, opdis_info_t, opdis);
174
+ if (! opdis ) {
175
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
176
+ }
177
+
178
+ /* 'nil' causes opdis to revert to default decoder */
179
+ if ( Qnil == obj ) {
180
+ opdis_set_decoder( opdis, opdis_default_decoder, NULL );
181
+ return Qtrue;
182
+ }
183
+
184
+ /* objects without a 'decode' method cannot be decoders */
185
+ if (! rb_respond_to(obj, rb_intern(DECODER_METHOD)) ) {
186
+ return Qfalse;
187
+ }
188
+
189
+ opdis_set_decoder( opdis, local_decoder, (void *) obj );
190
+ rb_iv_set(instance, IVAR(DIS_ATTR_DECODER), obj );
191
+
192
+ return Qtrue;
193
+ }
194
+
195
+ /* local insn handler object: this invokes the visited? method in the handler
196
+ * object provided by the user. */
197
+ static int local_handler( const opdis_insn_t * i, void * arg ) {
198
+ VALUE obj = (VALUE) arg;
199
+ VALUE insn = Opdis_insnFromC(i);
200
+
201
+ /* invoke visited? method in Handler object */
202
+ VALUE var = rb_funcall(obj, symVisited, 1, insn);
203
+
204
+ /* True means already visited, so continue = 0 */
205
+ return (Qtrue == var) ? 0 : 1;
206
+ }
207
+
208
+ static VALUE cls_disasm_set_handler(VALUE instance, VALUE obj) {
209
+ opdis_t opdis;
210
+ Data_Get_Struct(instance, opdis_info_t, opdis);
211
+ if (! opdis ) {
212
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
213
+ }
214
+
215
+ /* nil causes opdis to revert to default decoder */
216
+ if ( Qnil == obj ) {
217
+ opdis_set_handler( opdis, opdis_default_handler, opdis );
218
+ return Qtrue;
219
+ }
220
+
221
+ /* objects without a visited? method cannot be handlers */
222
+ if (! rb_respond_to(obj, rb_intern(HANDLER_METHOD)) ) {
223
+ return Qfalse;
224
+ }
225
+
226
+ opdis_set_handler( opdis, local_handler, (void *) obj );
227
+ rb_iv_set(instance, IVAR(DIS_ATTR_HANDLER), obj );
228
+
229
+ return Qtrue;
230
+ }
231
+
232
+ /* local resolver callback: this invokes the ruby resolve method in the object
233
+ * provided by the user */
234
+ static opdis_vma_t local_resolver ( const opdis_insn_t * i, void * arg ) {
235
+ VALUE obj = (VALUE) arg;
236
+ VALUE insn = Opdis_insnFromC(i);
237
+
238
+ /* invoke resolve method in Resolver object */
239
+ VALUE vma = rb_funcall(obj, symResolve, 1, insn);
240
+
241
+ return (Qnil == vma) ? OPDIS_INVALID_ADDR : (opdis_vma_t) NUM2UINT(vma);
242
+ }
243
+
244
+ static VALUE cls_disasm_set_resolver(VALUE instance, VALUE obj) {
245
+ opdis_t opdis;
246
+ Data_Get_Struct(instance, opdis_info_t, opdis);
247
+ if (! opdis ) {
248
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
249
+ }
250
+
251
+ /* nil causes opdis to revert to default resolver */
252
+ if ( Qnil == obj ) {
253
+ opdis_set_resolver( opdis, opdis_default_resolver, NULL );
254
+ return Qtrue;
255
+ }
256
+
257
+ /* objects without a resolve method cannot be Resolvers */
258
+ if (! rb_respond_to(obj, rb_intern(RESOLVER_METHOD)) ) {
259
+ return Qfalse;
260
+ }
261
+
262
+ opdis_set_resolver( opdis, local_resolver, (void *) obj );
263
+ rb_iv_set(instance, IVAR(DIS_ATTR_RESOLVER), obj );
264
+
265
+ return Qtrue;
266
+ }
267
+
268
+ static VALUE cls_disasm_get_debug(VALUE instance) {
269
+ opdis_t opdis;
270
+ Data_Get_Struct(instance, opdis_info_t, opdis);
271
+ return (opdis && opdis->debug) ? Qtrue : Qfalse;
272
+ }
273
+
274
+ static VALUE cls_disasm_set_debug(VALUE instance, VALUE enabled) {
275
+ opdis_t opdis;
276
+ Data_Get_Struct(instance, opdis_info_t, opdis);
277
+ if (! opdis ) {
278
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
279
+ }
280
+ opdis->debug = (enabled == Qtrue) ? 1 : 0;
281
+ return Qtrue;
282
+ }
283
+
284
+ static VALUE cls_disasm_get_syntax(VALUE instance) {
285
+ opdis_t opdis;
286
+ VALUE str;
287
+
288
+ Data_Get_Struct(instance, opdis_info_t, opdis);
289
+ if (! opdis ) {
290
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
291
+ }
292
+
293
+ if ( opdis->disassembler == print_insn_i386_intel ) {
294
+ str = rb_str_new_cstr(DIS_SYNTAX_INTEL);
295
+ } else {
296
+ str = rb_str_new_cstr(DIS_SYNTAX_ATT);
297
+ }
298
+
299
+ return str;
300
+ }
301
+
302
+ static VALUE cls_disasm_set_syntax(VALUE instance, VALUE syntax) {
303
+ opdis_t opdis;
304
+ enum opdis_x86_syntax_t syn;
305
+ VALUE syntax_s = rb_any_to_s(syntax);
306
+ const char * str = StringValueCStr(syntax_s);
307
+
308
+ if (! strcmp(str, DIS_SYNTAX_INTEL) ) {
309
+ syn = opdis_x86_syntax_intel;
310
+ } else if (! strcmp(str, DIS_SYNTAX_ATT) ) {
311
+ syn = opdis_x86_syntax_att;
312
+ } else {
313
+ rb_raise(rb_eArgError, "Syntax must be 'intel' or 'att'");
314
+ }
315
+
316
+ Data_Get_Struct(instance, opdis_info_t, opdis);
317
+ if (! opdis ) {
318
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
319
+ }
320
+ opdis_set_x86_syntax(opdis, syn);
321
+
322
+ return Qtrue;
323
+ }
324
+
325
+ struct get_arch_name_arg {
326
+ opdis_t opdis;
327
+ const char * name;
328
+ };
329
+
330
+ static int get_name_for_arch( const Opdis_disasm_def * def, void * arg ) {
331
+ struct get_arch_name_arg * out = (struct get_arch_name_arg *) arg;
332
+ if ( def->arch == out->opdis->config.arch &&
333
+ def->mach == out->opdis->config.mach ) {
334
+ out->name = def->name;
335
+ return 0;
336
+ }
337
+
338
+ return 1;
339
+ }
340
+
341
+
342
+ static VALUE cls_disasm_get_arch(VALUE instance) {
343
+ opdis_t opdis;
344
+ struct get_arch_name_arg arg = { NULL, "unknown" };
345
+
346
+ Data_Get_Struct(instance, opdis_info_t, opdis);
347
+ if (! opdis ) {
348
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
349
+ }
350
+
351
+ Opdis_disasm_iter( get_name_for_arch, &arg );
352
+
353
+ return rb_str_new_cstr(arg.name);
354
+ }
355
+
356
+ static VALUE cls_disasm_set_arch(VALUE instance, VALUE arch) {
357
+ opdis_t opdis;
358
+ const Opdis_disasm_def * def;
359
+ const char * name = rb_string_value_cstr(&arch);
360
+
361
+ Data_Get_Struct(instance, opdis_info_t, opdis);
362
+ if (! opdis ) {
363
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
364
+ }
365
+
366
+ def = Opdis_disasm_for_name( name );
367
+
368
+ if ( def != Opdis_disasm_invalid() ) {
369
+ struct disassemble_info * info = &opdis->config;
370
+ info->application_data = def->fn;
371
+ info->arch = def->arch;
372
+ info->mach = def->mach;
373
+
374
+ rb_iv_set(instance, IVAR(DIS_ATTR_ARCH), arch);
375
+ }
376
+
377
+ return Qfalse;
378
+ }
379
+
380
+ static VALUE cls_disasm_get_opts(VALUE instance) {
381
+ opdis_t opdis;
382
+ Data_Get_Struct(instance, opdis_info_t, opdis);
383
+ return (opdis == NULL) ? Qnil :
384
+ rb_str_new_cstr(opdis->config.disassembler_options);
385
+ }
386
+
387
+ static VALUE cls_disasm_set_opts(VALUE instance, VALUE opts) {
388
+ char * str;
389
+ opdis_t opdis;
390
+ VALUE opts_s = opts;
391
+ Data_Get_Struct(instance, opdis_info_t, opdis);
392
+ if (! opdis ) {
393
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
394
+ }
395
+
396
+ str = StringValueCStr(opts_s);
397
+ opdis_set_disassembler_options( opdis, str );
398
+ return Qtrue;
399
+ }
400
+
401
+ /* get opdis options from an argument hash */
402
+ static void cls_disasm_handle_args( VALUE instance, VALUE hash ) {
403
+ VALUE var;
404
+
405
+ /* opdis callbacks */
406
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_RESOLVER), Qfalse);
407
+ if ( Qfalse != var ) cls_disasm_set_resolver(instance, var);
408
+
409
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_HANDLER), Qfalse);
410
+ if ( Qfalse != var ) cls_disasm_set_handler(instance, var);
411
+
412
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_DECODER), Qfalse);
413
+ if ( Qfalse != var ) cls_disasm_set_decoder(instance, var);
414
+
415
+ /* opdis settings */
416
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_SYNTAX), Qfalse);
417
+ if ( Qfalse != var ) cls_disasm_set_syntax(instance, var);
418
+
419
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_DEBUG), Qfalse);
420
+ if ( Qfalse != var ) cls_disasm_set_debug(instance, var);
421
+
422
+ /* libopcodes settings */
423
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_OPTIONS), Qfalse);
424
+ if ( Qfalse != var ) cls_disasm_set_opts(instance, var);
425
+
426
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_ARCH), Qfalse);
427
+ if ( Qfalse != var ) cls_disasm_set_arch(instance, var);
428
+ }
429
+
430
+ struct DISPLAY_ARGS { VALUE output; VALUE block; };
431
+
432
+ /* local display handler: this adds instructions to a Disassembly object
433
+ * and invokes block if provided. */
434
+ static void local_display( const opdis_insn_t * i, void * arg ) {
435
+ struct DISPLAY_ARGS * args = (struct DISPLAY_ARGS *) arg;
436
+ VALUE insn = Opdis_insnFromC(i);
437
+
438
+ if ( insn == Qnil ) {
439
+ char buf[128];
440
+ VALUE errors = rb_iv_get(args->output, IVAR(OUT_ATTR_ERRORS));
441
+ snprintf( buf, 127-1, "%s: Unable to convert C insn to Ruby",
442
+ DIS_ERR_DECODE );
443
+ rb_ary_push( errors, rb_str_new_cstr(buf) );
444
+ return;
445
+ }
446
+
447
+ if ( Qnil != args->block ) {
448
+ rb_funcall(args->block, symCall, 1, insn);
449
+ }
450
+
451
+ rb_hash_aset( args->output, INT2NUM(i->vma), insn );
452
+
453
+ rb_thread_schedule();
454
+ }
455
+
456
+ /* local error handler: this appends errors to a ruby array in arg */
457
+ static void local_error( enum opdis_error_t error, const char * msg,
458
+ void * arg ) {
459
+ const char * type;
460
+ char buf[128] = {0};
461
+ VALUE errors = (VALUE) arg;
462
+
463
+ switch (error) {
464
+ case opdis_error_bounds: type = DIS_ERR_BOUNDS; break;
465
+ case opdis_error_invalid_insn: type = DIS_ERR_INVALID; break;
466
+ case opdis_error_decode_insn: type = DIS_ERR_DECODE; break;
467
+ case opdis_error_bfd: type = DIS_ERR_BFD; break;
468
+ case opdis_error_max_items: type = DIS_ERR_MAX; break;
469
+ case opdis_error_unknown:
470
+ default: type = DIS_ERR_UNK; break;
471
+ }
472
+
473
+ snprintf( buf, 128-1, "%s: %s", type, msg );
474
+
475
+ /* append error message to error list */
476
+ rb_ary_push( errors, rb_str_new_cstr(buf) );
477
+ }
478
+
479
+ static void config_buf_from_args( opdis_buf_t buf, VALUE hash ) {
480
+ VALUE var;
481
+
482
+ /* buffer vma */
483
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_BUFVMA), Qfalse);
484
+ if ( Qfalse != var && Qnil != var ) buf->vma = NUM2UINT(var);
485
+
486
+ // TODO: other options?
487
+ }
488
+
489
+ static opdis_buf_t opdis_buf_for_target( VALUE tgt, VALUE hash ) {
490
+ unsigned char * buf = NULL;
491
+ unsigned int buf_len = 0;
492
+ opdis_buf_t obuf;
493
+
494
+ /* String object containing bytes */
495
+ if ( Qtrue == rb_obj_is_kind_of( tgt, rb_cString ) ) {
496
+ buf = (unsigned char*) RSTRING_PTR(tgt);
497
+ buf_len = RSTRING_LEN(tgt);
498
+
499
+ /* Array object containing bytes */
500
+ } else if ( Qtrue == rb_obj_is_kind_of( tgt, rb_cArray ) ) {
501
+ int i;
502
+ unsigned char * sbuf;
503
+ buf_len = RARRAY_LEN(tgt);
504
+ sbuf = alloca(buf_len);
505
+ for( i=0; i < buf_len; i++ ) {
506
+ VALUE val = rb_ary_entry( tgt, i );
507
+ sbuf[i] = (unsigned char) NUM2UINT(val);
508
+ }
509
+
510
+ buf = sbuf;
511
+
512
+ /* IO object containing bytes */
513
+ } else if ( Qtrue == rb_obj_is_kind_of( tgt, rb_cIO ) ) {
514
+ VALUE str = rb_funcall( tgt, symRead, 0 );
515
+ buf = (unsigned char*) RSTRING_PTR(str);
516
+ buf_len = RSTRING_LEN(str);
517
+
518
+ } else {
519
+ rb_raise(rb_eArgError, "Buffer must be a String, IO or Array");
520
+ }
521
+
522
+ if (! buf || ! buf_len ) {
523
+ rb_raise(rb_eArgError, "Cannot disassemble empty buffer");
524
+ }
525
+
526
+ obuf = opdis_buf_alloc( buf_len, 0 );
527
+ opdis_buf_fill( obuf, 0, buf, buf_len );
528
+
529
+ /* apply target-specific args (vma, etc) */
530
+ config_buf_from_args( obuf, hash );
531
+
532
+ return obuf;
533
+ }
534
+
535
+ struct OPDIS_TGT {bfd * abfd; asection * sec; asymbol * sym; opdis_buf_t buf;};
536
+
537
+ static void load_target( opdis_t opdis, VALUE tgt, VALUE hash,
538
+ struct OPDIS_TGT * out ) {
539
+
540
+ /* Ruby Bfd::Target object */
541
+ if ( Qnil != GET_BFD_CLASS(clsBfdTgt, BFD_TGT_PATH) &&
542
+ Qtrue == rb_obj_is_kind_of( tgt, clsBfdTgt ) ) {
543
+ Data_Get_Struct(tgt, bfd, out->abfd );
544
+ if (! out->abfd ) {
545
+ rb_raise( rb_eRuntimeError, "Invalid bfd" );
546
+ }
547
+
548
+ /* Ruby Bfd::Symbol object */
549
+ } else if ( Qnil != GET_BFD_CLASS(clsBfdSym, BFD_SYM_PATH) &&
550
+ Qtrue == rb_obj_is_kind_of( tgt, clsBfdSym ) ) {
551
+ Data_Get_Struct(tgt, asymbol, out->sym );
552
+ if (! out->sym ) {
553
+ rb_raise( rb_eRuntimeError, "Invalid bfd symbol" );
554
+ }
555
+ out->abfd = out->sym->the_bfd;
556
+
557
+ /* Ruby Bfd::Section object */
558
+ } else if ( Qnil != GET_BFD_CLASS(clsBfdSec, BFD_SEC_PATH) &&
559
+ Qtrue == rb_obj_is_kind_of( tgt, clsBfdSec ) ) {
560
+ Data_Get_Struct(tgt, asection, out->sec );
561
+ if (! out->sec ) {
562
+ rb_raise( rb_eRuntimeError, "Invalid bfd section" );
563
+ }
564
+ out->abfd = out->sec->owner;
565
+
566
+ /* Other non-Bfd Ruby object */
567
+ } else {
568
+ out->buf = opdis_buf_for_target( tgt, hash );
569
+ }
570
+
571
+ /* Set arch, etc based on BFD info */
572
+ if ( out->abfd ) {
573
+ opdis_config_from_bfd( opdis, out->abfd );
574
+ }
575
+ }
576
+
577
+ static void perform_disassembly( VALUE instance, opdis_t opdis, VALUE target,
578
+ VALUE hash ) {
579
+ VALUE var;
580
+ VALUE rb_vma = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_VMA),
581
+ INT2NUM(0));
582
+ VALUE rb_len = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_LEN),
583
+ INT2NUM(0));
584
+ opdis_vma_t vma = NUM2ULL(rb_vma);
585
+ opdis_off_t len = NUM2UINT(rb_len);
586
+ const char * strategy = DIS_STRAT_LINEAR;
587
+ struct OPDIS_TGT tgt = {0};
588
+
589
+ /* load target based on its Ruby object type */
590
+ load_target( opdis, target, hash, &tgt );
591
+
592
+ /* apply general args (syntax, arch, etc), overriding Bfd config */
593
+ cls_disasm_handle_args(instance, hash);
594
+
595
+ /* get disassembly algorithm to use */
596
+ var = rb_hash_lookup2(hash, str_to_sym(DIS_ARG_STRATEGY), Qfalse);
597
+ if ( Qfalse != var ) strategy = StringValueCStr(var);
598
+
599
+ rb_thread_schedule();
600
+
601
+ // Disable garbage collection
602
+ // TODO: INVESTIGATE why without this, ruby crashes!
603
+ rb_gc_disable();
604
+
605
+ /* Single instruction disassembly */
606
+ if (! strcmp( strategy, DIS_STRAT_SINGLE ) ) {
607
+ opdis_insn_t * insn = ALLOC_FIXED_INSN;
608
+
609
+ if ( tgt.abfd ) {
610
+ opdis_disasm_bfd_insn( opdis, tgt.abfd, vma, insn );
611
+ } else {
612
+ opdis_disasm_insn( opdis, tgt.buf, vma, insn );
613
+ }
614
+
615
+ /* invoke display function */
616
+ opdis->display( insn, opdis->display_arg );
617
+
618
+ opdis_insn_free(insn);
619
+
620
+ /* Linear disassembly */
621
+ } else if (! strcmp( strategy, DIS_STRAT_LINEAR ) ) {
622
+ if ( tgt.abfd ) {
623
+ opdis_disasm_bfd_linear( opdis, tgt.abfd, vma, len );
624
+ } else {
625
+ opdis_disasm_linear( opdis, tgt.buf, vma, len );
626
+ }
627
+
628
+ /* Control Flow disassembly */
629
+ } else if (! strcmp( strategy, DIS_STRAT_CFLOW ) ) {
630
+ if ( tgt.abfd ) {
631
+ opdis_disasm_bfd_cflow( opdis, tgt.abfd, vma );
632
+ } else {
633
+ opdis_disasm_cflow( opdis, tgt.buf, vma );
634
+ }
635
+
636
+ /* Control Flow disassembly of BFD symbol */
637
+ } else if (! strcmp( strategy, DIS_STRAT_SYMBOL ) ) {
638
+ if (! tgt.sym ) {
639
+ rb_raise(rb_eArgError, "Bfd::Symbol required");
640
+ }
641
+ opdis_disasm_bfd_symbol( opdis, tgt.sym );
642
+
643
+ /* Linear disassembly of BFD section */
644
+ } else if (! strcmp( strategy, DIS_STRAT_SECTION ) ) {
645
+ if (! tgt.sec ) {
646
+ rb_raise(rb_eArgError, "Bfd::Section required");
647
+ }
648
+ opdis_disasm_bfd_section( opdis, tgt.sec );
649
+
650
+ /* Control Flow disassembly of BFD entry point */
651
+ } else if (! strcmp( strategy, DIS_STRAT_ENTRY ) ) {
652
+ if (! tgt.abfd ) {
653
+ rb_raise(rb_eArgError, "Bfd::Target required");
654
+ }
655
+ opdis_disasm_bfd_entry( opdis, tgt.abfd );
656
+ } else {
657
+ if ( tgt.buf ) {
658
+ opdis_buf_free(tgt.buf);
659
+ }
660
+ rb_raise(rb_eArgError, "Unknown strategy '%s'", strategy);
661
+ }
662
+
663
+ if ( tgt.buf ) {
664
+ opdis_buf_free(tgt.buf);
665
+ }
666
+
667
+ // Enable garbage collection
668
+ // TODO: INVESTIGATE why ruby needs gc disable/enable
669
+ rb_gc_enable();
670
+ }
671
+
672
+
673
+ /* Disassembler strategies produce blocks */
674
+ static VALUE cls_disasm_disassemble(VALUE instance, VALUE tgt, VALUE hash ) {
675
+ opdis_t opdis, opdis_orig;
676
+ VALUE args[1] = {Qnil};
677
+ struct DISPLAY_ARGS display_args = { Qnil, Qnil };
678
+
679
+ /* Create duplicate opdis_t in order to be threadsafe */
680
+ Data_Get_Struct(instance, opdis_info_t, opdis_orig);
681
+ if (! opdis_orig ) {
682
+ rb_raise( rb_eRuntimeError, "Invalid opdis_t" );
683
+ }
684
+ opdis = opdis_dupe(opdis_orig);
685
+
686
+ /* yield to a block, if provided */
687
+ if ( rb_block_given_p() ) {
688
+ display_args.block = rb_block_proc();
689
+ }
690
+
691
+ display_args.output = rb_class_new_instance( 0, args, clsOutput );
692
+
693
+ opdis_set_display( opdis, local_display, &display_args );
694
+
695
+ opdis_set_error_reporter( opdis, local_error,
696
+ (void *) rb_iv_get(display_args.output,
697
+ IVAR(OUT_ATTR_ERRORS)) );
698
+
699
+ perform_disassembly( instance, opdis, tgt, hash );
700
+
701
+ opdis_term(opdis);
702
+
703
+ return display_args.output;
704
+ }
705
+
706
+ /* new: takes hash of arguments */
707
+ static VALUE cls_disasm_new(VALUE class, VALUE hash) {
708
+ VALUE instance;
709
+ VALUE argv[1] = { Qnil };
710
+ opdis_t opdis = opdis_init();
711
+
712
+ instance = Data_Wrap_Struct(class, NULL, opdis_term, opdis);
713
+ rb_obj_call_init(instance, 0, argv);
714
+
715
+ cls_disasm_handle_args(instance, hash);
716
+
717
+ return instance;
718
+ }
719
+
720
+ /* usage: writes a list of disassembler options to IO object */
721
+ static VALUE cls_disasm_usage(VALUE class, VALUE io) {
722
+ const char * filename;
723
+ VALUE path;
724
+ FILE * f;
725
+
726
+ if (! rb_respond_to(io, symPath) ) {
727
+ rb_raise( rb_eArgError, "Argument must respond to :path" );
728
+ }
729
+
730
+ /* get path from ruby File object */
731
+ path = rb_funcall(io, symPath, 0);
732
+ if ( Qnil == path ) {
733
+ rb_raise( rb_eArgError, "Object#path returned nil" );
734
+ }
735
+
736
+ filename = StringValueCStr(path);
737
+ f = fopen( filename, "w");
738
+ if (! f ) {
739
+ rb_raise( rb_eRuntimeError,
740
+ "Could not open %s object for write: %s",
741
+ filename, strerror(errno) );
742
+ }
743
+
744
+ /* invoke libopcodes to write usage into to FILE * */
745
+ disassembler_usage(f);
746
+
747
+ fclose(f);
748
+
749
+ return Qtrue;
750
+ }
751
+
752
+ static void define_disasm_constants() {
753
+ /* Error types */
754
+ rb_define_const(clsDisasm, DIS_ERR_BOUNDS_NAME,
755
+ rb_str_new_cstr(DIS_ERR_BOUNDS));
756
+ rb_define_const(clsDisasm, DIS_ERR_INVALID_NAME,
757
+ rb_str_new_cstr(DIS_ERR_INVALID));
758
+ rb_define_const(clsDisasm, DIS_ERR_DECODE_NAME,
759
+ rb_str_new_cstr(DIS_ERR_DECODE));
760
+ rb_define_const(clsDisasm, DIS_ERR_BFD_NAME,
761
+ rb_str_new_cstr(DIS_ERR_BFD));
762
+ rb_define_const(clsDisasm, DIS_ERR_MAX_NAME,
763
+ rb_str_new_cstr(DIS_ERR_MAX));
764
+
765
+ /* Disassembly algorithms */
766
+ rb_define_const(clsDisasm, DIS_STRAT_SINGLE_NAME,
767
+ rb_str_new_cstr(DIS_STRAT_SINGLE));
768
+ rb_define_const(clsDisasm, DIS_STRAT_LINEAR_NAME,
769
+ rb_str_new_cstr(DIS_STRAT_LINEAR));
770
+ rb_define_const(clsDisasm, DIS_STRAT_CFLOW_NAME,
771
+ rb_str_new_cstr(DIS_STRAT_CFLOW));
772
+ rb_define_const(clsDisasm, DIS_STRAT_SYMBOL_NAME,
773
+ rb_str_new_cstr(DIS_STRAT_SYMBOL));
774
+ rb_define_const(clsDisasm, DIS_STRAT_SECTION_NAME,
775
+ rb_str_new_cstr(DIS_STRAT_SECTION));
776
+ rb_define_const(clsDisasm, DIS_STRAT_ENTRY_NAME,
777
+ rb_str_new_cstr(DIS_STRAT_ENTRY));
778
+
779
+ /* Lists of symbolic constants */
780
+ rb_define_singleton_method(clsDisasm, DIS_CONST_STRATEGIES,
781
+ cls_disasm_strategies, 0);
782
+ rb_define_singleton_method(clsDisasm, DIS_CONST_ARCHES,
783
+ cls_disasm_architectures, 0);
784
+ rb_define_singleton_method(clsDisasm, DIS_CONST_SYNTAXES,
785
+ cls_disasm_syntaxes, 0);
786
+ }
787
+
788
+ static void init_disasm_class( VALUE modOpdis ) {
789
+ clsDisasm = rb_define_class_under(modOpdis, OPDIS_DISASM_CLASS_NAME,
790
+ rb_cObject);
791
+ rb_define_singleton_method(clsDisasm, "ext_new", cls_disasm_new, 1);
792
+ rb_define_singleton_method(clsDisasm, "ext_usage", cls_disasm_usage, 1);
793
+
794
+ /* read-only attributes */
795
+ rb_define_attr(clsDisasm, DIS_ATTR_DECODER, 1, 0);
796
+ rb_define_attr(clsDisasm, DIS_ATTR_HANDLER, 1, 0);
797
+ rb_define_attr(clsDisasm, DIS_ATTR_RESOLVER, 1, 0);
798
+
799
+ /* setters */
800
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_DECODER),
801
+ cls_disasm_set_decoder, 1);
802
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_HANDLER),
803
+ cls_disasm_set_handler, 1);
804
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_RESOLVER),
805
+ cls_disasm_set_resolver, 1);
806
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_DEBUG),
807
+ cls_disasm_set_debug, 1);
808
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_SYNTAX),
809
+ cls_disasm_set_syntax, 1);
810
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_ARCH),
811
+ cls_disasm_set_arch, 1);
812
+ rb_define_method(clsDisasm, SETTER(DIS_ATTR_OPTS),
813
+ cls_disasm_set_opts, 1);
814
+
815
+ /* getters */
816
+ rb_define_method(clsDisasm, DIS_ATTR_DEBUG, cls_disasm_get_debug, 0);
817
+ rb_define_method(clsDisasm, DIS_ATTR_SYNTAX, cls_disasm_get_syntax, 0);
818
+ rb_define_method(clsDisasm, DIS_ATTR_ARCH, cls_disasm_get_arch, 0);
819
+ rb_define_method(clsDisasm, DIS_ATTR_OPTS, cls_disasm_get_opts, 0);
820
+
821
+ /* methods */
822
+ rb_define_method(clsDisasm, DIS_METHOD_DISASM, cls_disasm_disassemble,
823
+ 2);
824
+
825
+ define_disasm_constants();
826
+ }
827
+
828
+ /* ---------------------------------------------------------------------- */
829
+ /* Opdis Module */
830
+
831
+ void Init_OpdisExt() {
832
+ symToSym = rb_intern("to_sym");
833
+ symCall = rb_intern("call");
834
+ symRead = rb_intern("read");
835
+ symSize = rb_intern("size");
836
+ symPath = rb_intern("path");
837
+
838
+ symDecode = rb_intern(DECODER_METHOD);
839
+ symVisited = rb_intern(HANDLER_METHOD);
840
+ symResolve = rb_intern(RESOLVER_METHOD);
841
+
842
+ modOpdis = rb_define_module(OPDIS_MODULE_NAME);
843
+
844
+ init_disasm_class(modOpdis);
845
+ init_output_class(modOpdis);
846
+
847
+ Opdis_initCallbacks(modOpdis);
848
+
849
+ Opdis_initModel(modOpdis);
850
+ }