Opdis 1.3.0

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.
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
+ }