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/ChangeLog +2 -0
- data/LICENSE +674 -0
- data/LICENSE.README +8 -0
- data/README +101 -0
- data/examples/array_linear.rb +23 -0
- data/examples/bfd_entry.rb +24 -0
- data/examples/bfd_section.rb +24 -0
- data/examples/bfd_symbol.rb +27 -0
- data/examples/buf_linear.rb +25 -0
- data/examples/decoder.rb +45 -0
- data/examples/file_linear.rb +31 -0
- data/examples/libopcodes_options.rb +11 -0
- data/examples/resolver.rb +191 -0
- data/examples/supported_architectures.rb +11 -0
- data/examples/visited_handler.rb +61 -0
- data/examples/x86_decoder.rb +46 -0
- data/lib/Opdis.rb +123 -0
- data/module/Arch.c +364 -0
- data/module/Arch.h +37 -0
- data/module/Callbacks.c +266 -0
- data/module/Callbacks.h +43 -0
- data/module/Model.c +1275 -0
- data/module/Model.h +230 -0
- data/module/Opdis.c +850 -0
- data/module/Opdis.h +89 -0
- data/module/extconf.rb +126 -0
- data/module/rdoc_input/Callbacks.rb +143 -0
- data/module/rdoc_input/Model.rb +636 -0
- data/module/rdoc_input/Opdis.rb +253 -0
- data/module/ruby_compat.c +72 -0
- data/module/ruby_compat.h +25 -0
- data/tests/ut_opdis.rb +30 -0
- data/tests/ut_opdis_bfd.rb +556 -0
- metadata +109 -0
data/module/Arch.h
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
/* Arch.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_EXT_ARCH_H
|
9
|
+
#define OPDIS_EXT_ARCH_H
|
10
|
+
|
11
|
+
#include <bfd.h>
|
12
|
+
#include <dis-asm.h>
|
13
|
+
|
14
|
+
/* Disassembler definitions for supported architectures */
|
15
|
+
typedef struct {
|
16
|
+
const char * name; /* unique name for disassembler */
|
17
|
+
enum bfd_architecture arch; /* architecture from bfd.h */
|
18
|
+
unsigned long mach; /* machine from bfd.h or 0 */
|
19
|
+
disassembler_ftype fn; /* print_insn fn from dis-asm.h */
|
20
|
+
} Opdis_disasm_def;
|
21
|
+
|
22
|
+
/* disassembler iterator callback function. Returns 0 if iteration should
|
23
|
+
* halt; 1 otherwise. */
|
24
|
+
typedef int (*OPDIS_DISASM_ITER_FN) ( const Opdis_disasm_def *, void * );
|
25
|
+
|
26
|
+
/* iterate over all available disassemblers, invoking 'fn' on each */
|
27
|
+
void Opdis_disasm_iter( OPDIS_DISASM_ITER_FN fn, void * arg );
|
28
|
+
|
29
|
+
/* return the disassembler definition for 'name', or the invalid
|
30
|
+
* definition. */
|
31
|
+
const Opdis_disasm_def * Opdis_disasm_for_name( const char * name );
|
32
|
+
|
33
|
+
/* return an invalid disassembler definition with safe values for
|
34
|
+
* name and fn, and an architecture of bfd_arch_unknown. */
|
35
|
+
const Opdis_disasm_def * Opdis_disasm_invalid( void );
|
36
|
+
|
37
|
+
#endif
|
data/module/Callbacks.c
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
/* Calbacks.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 <ruby.h>
|
9
|
+
#include "ruby_compat.h"
|
10
|
+
|
11
|
+
#include <opdis/opdis.h>
|
12
|
+
#include <opdis/model.h>
|
13
|
+
#include <opdis/x86_decoder.h>
|
14
|
+
|
15
|
+
#include "Callbacks.h"
|
16
|
+
#include "Opdis.h"
|
17
|
+
#include "Model.h"
|
18
|
+
|
19
|
+
#define IVAR(attr) "@" attr
|
20
|
+
#define SETTER(attr) attr "="
|
21
|
+
|
22
|
+
static VALUE symToSym, symDecode, symVisited, symResolve;
|
23
|
+
static VALUE clsDecoder, clsX86Decoder, clsX86IntelDecoder;
|
24
|
+
static VALUE clsHandler, clsResolver;
|
25
|
+
|
26
|
+
static VALUE str_to_sym( const char * str ) {
|
27
|
+
VALUE var = rb_str_new_cstr(str);
|
28
|
+
return rb_funcall(var, symToSym, 0);
|
29
|
+
}
|
30
|
+
|
31
|
+
#define ALLOC_FIXED_INSN opdis_insn_alloc_fixed(128, 32, 16, 32)
|
32
|
+
|
33
|
+
/* ---------------------------------------------------------------------- */
|
34
|
+
/* Decoder Class */
|
35
|
+
|
36
|
+
static VALUE insn_type_to_str( enum dis_insn_type t ) {
|
37
|
+
const char *s = "Unknown";
|
38
|
+
switch (t) {
|
39
|
+
case dis_noninsn: s = "Invalid"; break;
|
40
|
+
case dis_nonbranch: s = "Not branch"; break;
|
41
|
+
case dis_branch: s = "Unconditional branch"; break;
|
42
|
+
case dis_condbranch: s = "Conditional branch"; break;
|
43
|
+
case dis_jsr: s = "Jump to subroutine"; break;
|
44
|
+
case dis_condjsr: s = "Conditional jump to subroutine"; break;
|
45
|
+
case dis_dref: s = "Data reference"; break;
|
46
|
+
case dis_dref2: s = "Two data references"; break;
|
47
|
+
}
|
48
|
+
return rb_str_new_cstr(s);
|
49
|
+
}
|
50
|
+
|
51
|
+
static void fill_decoder_hash( VALUE hash, const opdis_insn_buf_t in,
|
52
|
+
const opdis_byte_t * buf, opdis_off_t offset,
|
53
|
+
opdis_vma_t vma, opdis_off_t length ) {
|
54
|
+
int i;
|
55
|
+
VALUE str, ary;
|
56
|
+
char info = in->insn_info_valid;
|
57
|
+
|
58
|
+
/* instruction location and size */
|
59
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_VMA), INT2NUM(vma) );
|
60
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_OFF), INT2NUM(offset) );
|
61
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_LEN), INT2NUM(length) );
|
62
|
+
|
63
|
+
/* target buffer */
|
64
|
+
str = rb_str_new( (const char *) buf, offset + length );
|
65
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_BUF), str );
|
66
|
+
|
67
|
+
/* decode instruction as provided by libopcodes */
|
68
|
+
|
69
|
+
/* 1. get items from opdis_insn_buf_t */
|
70
|
+
ary = rb_ary_new();
|
71
|
+
for ( i = 0; i < in->item_count; i++ ) {
|
72
|
+
rb_ary_push( ary, rb_str_new_cstr(in->items[i]) );
|
73
|
+
}
|
74
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_ITEMS), ary );
|
75
|
+
|
76
|
+
/* 2. get raw ASCII version of insn from libopcodes */
|
77
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_STR),
|
78
|
+
rb_str_new_cstr(in->string) );
|
79
|
+
|
80
|
+
/* 3. get instruction metadata set by libopcodes */
|
81
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_DELAY),
|
82
|
+
info ? INT2NUM(in->branch_delay_insns) : Qnil);
|
83
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_DATA),
|
84
|
+
info ? INT2NUM(in->data_size) : Qnil);
|
85
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_TYPE),
|
86
|
+
info ? insn_type_to_str(in->insn_type) : Qnil);
|
87
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_TGT),
|
88
|
+
info ? INT2NUM(in->target) : Qnil);
|
89
|
+
rb_hash_aset( hash, str_to_sym(DECODER_MEMBER_TGT2),
|
90
|
+
info ? INT2NUM(in->target2) : Qnil );
|
91
|
+
}
|
92
|
+
|
93
|
+
static int invoke_builtin_decoder( OPDIS_DECODER fn, VALUE insn, VALUE hash ) {
|
94
|
+
int rv;
|
95
|
+
VALUE var;
|
96
|
+
opdis_insn_buf_t inbuf;
|
97
|
+
opdis_byte_t * buf;
|
98
|
+
opdis_off_t offset;
|
99
|
+
opdis_vma_t vma;
|
100
|
+
opdis_off_t length;
|
101
|
+
opdis_insn_t * c_insn = ALLOC_FIXED_INSN;
|
102
|
+
|
103
|
+
Opdis_insnToC( insn, c_insn );
|
104
|
+
|
105
|
+
/* get insn_buf_t from decoder instance; this saves some trouble */
|
106
|
+
Data_Get_Struct( hash, opdis_insn_buffer_t, inbuf );
|
107
|
+
if (! inbuf ) {
|
108
|
+
/* something went wrong: we weren't called from local_decoder */
|
109
|
+
rb_raise( rb_eRuntimeError, "opdis_insn_buf_t not found" );
|
110
|
+
}
|
111
|
+
|
112
|
+
/* convert decoder arguments to C */
|
113
|
+
var = rb_hash_lookup2(hash, str_to_sym(DECODER_MEMBER_VMA), Qfalse);
|
114
|
+
vma = ( Qfalse != var ) ? NUM2UINT(var) : 0;
|
115
|
+
|
116
|
+
var = rb_hash_lookup2(hash, str_to_sym(DECODER_MEMBER_OFF), Qfalse);
|
117
|
+
offset = ( Qfalse != var ) ? NUM2UINT(var) : 0;
|
118
|
+
|
119
|
+
var = rb_hash_lookup2(hash, str_to_sym(DECODER_MEMBER_LEN), Qfalse);
|
120
|
+
length = ( Qfalse != var ) ? NUM2UINT(var) : 0;
|
121
|
+
|
122
|
+
var = rb_hash_lookup2(hash, str_to_sym(DECODER_MEMBER_BUF), Qfalse);
|
123
|
+
buf = ( Qfalse != var ) ? (opdis_byte_t *) RSTRING_PTR(var) : NULL;
|
124
|
+
|
125
|
+
if ( buf == NULL ) {
|
126
|
+
rb_raise( rb_eRuntimeError, "DecodeHash.buf is NULL" );
|
127
|
+
}
|
128
|
+
|
129
|
+
/* invoke C decoder callback */
|
130
|
+
// TODO: pass something meaningful in arg
|
131
|
+
rv = fn( inbuf, c_insn, buf, offset, vma, length, NULL );
|
132
|
+
if ( rv ) {
|
133
|
+
// TODO : error handler?
|
134
|
+
Opdis_insnFillFromC( c_insn, insn );
|
135
|
+
}
|
136
|
+
|
137
|
+
opdis_insn_free(c_insn);
|
138
|
+
|
139
|
+
return rv ? Qtrue : Qfalse;
|
140
|
+
}
|
141
|
+
|
142
|
+
static VALUE cls_decoder_decode( VALUE instance, VALUE insn, VALUE hash ) {
|
143
|
+
rb_thread_schedule();
|
144
|
+
invoke_builtin_decoder(opdis_default_decoder, insn, hash);
|
145
|
+
return insn;
|
146
|
+
}
|
147
|
+
|
148
|
+
static void init_decoder_class( VALUE modOpdis ) {
|
149
|
+
clsDecoder = rb_define_class_under(modOpdis, "InstructionDecoder",
|
150
|
+
rb_cObject);
|
151
|
+
rb_define_method(clsDecoder, DECODER_METHOD, cls_decoder_decode, 2);
|
152
|
+
}
|
153
|
+
|
154
|
+
/* ----------------------------------------------------------------- */
|
155
|
+
/* X86 Decoder Class */
|
156
|
+
|
157
|
+
static VALUE cls_x86decoder_decode( VALUE instance, VALUE insn, VALUE hash ) {
|
158
|
+
rb_thread_schedule();
|
159
|
+
invoke_builtin_decoder(opdis_x86_att_decoder, insn, hash);
|
160
|
+
return insn;
|
161
|
+
}
|
162
|
+
|
163
|
+
static VALUE cls_x86inteldecoder_decode(VALUE instance, VALUE insn, VALUE hash){
|
164
|
+
invoke_builtin_decoder(opdis_x86_intel_decoder, insn, hash);
|
165
|
+
return insn;
|
166
|
+
}
|
167
|
+
|
168
|
+
static void init_x86decoder_class( VALUE modOpdis ) {
|
169
|
+
/* AT&T Decoder */
|
170
|
+
clsX86Decoder = rb_define_class_under(modOpdis, "X86Decoder",
|
171
|
+
clsDecoder);
|
172
|
+
rb_define_method(clsX86Decoder, DECODER_METHOD,
|
173
|
+
cls_x86decoder_decode, 2);
|
174
|
+
|
175
|
+
/* Intel Decoder */
|
176
|
+
clsX86IntelDecoder = rb_define_class_under(modOpdis, "X86IntelDecoder",
|
177
|
+
clsDecoder);
|
178
|
+
rb_define_method(clsX86IntelDecoder, DECODER_METHOD,
|
179
|
+
cls_x86inteldecoder_decode, 2);
|
180
|
+
}
|
181
|
+
|
182
|
+
/* ---------------------------------------------------------------------- */
|
183
|
+
/* VisitedAddr Class */
|
184
|
+
|
185
|
+
static VALUE cls_handler_visited( VALUE instance, VALUE insn ) {
|
186
|
+
int rv;
|
187
|
+
opdis_t opdis;
|
188
|
+
opdis_insn_t * c_insn = ALLOC_FIXED_INSN;
|
189
|
+
|
190
|
+
Opdis_insnToC( insn, c_insn );
|
191
|
+
|
192
|
+
Data_Get_Struct(instance, opdis_info_t, opdis);
|
193
|
+
if (! opdis ) {
|
194
|
+
rb_raise(rb_eRuntimeError, "opdis_t not found in Handler");
|
195
|
+
}
|
196
|
+
|
197
|
+
rb_thread_schedule();
|
198
|
+
rv = opdis_default_handler(c_insn, opdis);
|
199
|
+
|
200
|
+
return rv ? Qtrue : Qfalse;
|
201
|
+
}
|
202
|
+
|
203
|
+
/* NOTE: this uses its own opdis_t with a visited_addr tree */
|
204
|
+
static VALUE cls_handler_new( VALUE class ) {
|
205
|
+
VALUE argv[1] = {Qnil};
|
206
|
+
opdis_t opdis = opdis_init();
|
207
|
+
VALUE instance = Data_Wrap_Struct(class, NULL, opdis_term, opdis);
|
208
|
+
rb_obj_call_init(instance, 0, argv);
|
209
|
+
|
210
|
+
opdis->visited_addr = opdis_vma_tree_init();
|
211
|
+
|
212
|
+
return instance;
|
213
|
+
}
|
214
|
+
|
215
|
+
static void init_handler_class( VALUE modOpdis ) {
|
216
|
+
|
217
|
+
clsHandler = rb_define_class_under(modOpdis, "VisitedAddressTracker",
|
218
|
+
rb_cObject);
|
219
|
+
rb_define_singleton_method(clsHandler, "new", cls_handler_new, 0);
|
220
|
+
rb_define_method(clsHandler, HANDLER_METHOD, cls_handler_visited, 1);
|
221
|
+
}
|
222
|
+
|
223
|
+
/* ---------------------------------------------------------------------- */
|
224
|
+
/* Resolver Class */
|
225
|
+
|
226
|
+
static VALUE cls_resolver_resolve( VALUE instance, VALUE insn ) {
|
227
|
+
int rv;
|
228
|
+
opdis_insn_t * c_insn = ALLOC_FIXED_INSN;
|
229
|
+
|
230
|
+
Opdis_insnToC( insn, c_insn );
|
231
|
+
|
232
|
+
rb_thread_schedule();
|
233
|
+
rv = opdis_default_resolver( c_insn, NULL );
|
234
|
+
|
235
|
+
return INT2NUM(rv);
|
236
|
+
}
|
237
|
+
|
238
|
+
static void init_resolver_class( VALUE modOpdis ) {
|
239
|
+
clsResolver = rb_define_class_under(modOpdis, "AddressResolver",
|
240
|
+
rb_cObject);
|
241
|
+
rb_define_method(clsResolver, RESOLVER_METHOD, cls_resolver_resolve, 1);
|
242
|
+
}
|
243
|
+
|
244
|
+
void Opdis_initCallbacks( VALUE modOpdis ) {
|
245
|
+
symToSym = rb_intern("to_sym");
|
246
|
+
|
247
|
+
symDecode = rb_intern(DECODER_METHOD);
|
248
|
+
symVisited = rb_intern(HANDLER_METHOD);
|
249
|
+
symResolve = rb_intern(RESOLVER_METHOD);
|
250
|
+
|
251
|
+
init_resolver_class(modOpdis);
|
252
|
+
init_handler_class(modOpdis);
|
253
|
+
init_decoder_class(modOpdis);
|
254
|
+
init_x86decoder_class(modOpdis);
|
255
|
+
}
|
256
|
+
|
257
|
+
VALUE Opdis_decoderHash( const opdis_insn_buf_t in,
|
258
|
+
const opdis_byte_t * buf, opdis_off_t offset,
|
259
|
+
opdis_vma_t vma, opdis_off_t length ) {
|
260
|
+
/* here we cheat and store insn_buf in hash in case one of the local
|
261
|
+
* decoder base classes gets called */
|
262
|
+
VALUE hash = Data_Wrap_Struct(rb_cHash, NULL, NULL, in);
|
263
|
+
fill_decoder_hash( hash, in, buf, offset, vma, length );
|
264
|
+
return hash;
|
265
|
+
}
|
266
|
+
|
data/module/Callbacks.h
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
/* Callbacks.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_CALLBACKS_H
|
9
|
+
#define OPDIS_RB_CALLBACKS_H
|
10
|
+
|
11
|
+
/* Resolver */
|
12
|
+
|
13
|
+
#define RESOLVER_METHOD "resolve"
|
14
|
+
|
15
|
+
/* Handler */
|
16
|
+
|
17
|
+
#define HANDLER_METHOD "visited?"
|
18
|
+
|
19
|
+
/* Decoder */
|
20
|
+
|
21
|
+
#define DECODER_METHOD "decode"
|
22
|
+
|
23
|
+
/* info provided to decoder */
|
24
|
+
#define DECODER_MEMBER_VMA "vma"
|
25
|
+
#define DECODER_MEMBER_OFF "offset"
|
26
|
+
#define DECODER_MEMBER_LEN "size"
|
27
|
+
#define DECODER_MEMBER_BUF "buffer"
|
28
|
+
#define DECODER_MEMBER_ITEMS "items"
|
29
|
+
#define DECODER_MEMBER_STR "raw_insn"
|
30
|
+
#define DECODER_MEMBER_DELAY "branch_delay"
|
31
|
+
#define DECODER_MEMBER_DATA "data_size"
|
32
|
+
#define DECODER_MEMBER_TYPE "type"
|
33
|
+
#define DECODER_MEMBER_TGT "target"
|
34
|
+
#define DECODER_MEMBER_TGT2 "target2"
|
35
|
+
|
36
|
+
void Opdis_initCallbacks( VALUE modOpdis );
|
37
|
+
|
38
|
+
/* Genererate a hash suitable for passing to a Ruby Decoder method */
|
39
|
+
VALUE Opdis_decoderHash( const opdis_insn_buf_t in,
|
40
|
+
const opdis_byte_t * buf, opdis_off_t offset,
|
41
|
+
opdis_vma_t vma, opdis_off_t length );
|
42
|
+
|
43
|
+
#endif
|
data/module/Model.c
ADDED
@@ -0,0 +1,1275 @@
|
|
1
|
+
/* Model.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 <ruby.h>
|
9
|
+
#include "ruby_compat.h"
|
10
|
+
|
11
|
+
#include <opdis/model.h>
|
12
|
+
|
13
|
+
#include "Model.h"
|
14
|
+
|
15
|
+
static VALUE symToSym, symToS;
|
16
|
+
static VALUE clsInsn, clsOp, clsReg, clsAbsAddr;
|
17
|
+
static VALUE clsRegOp, clsAbsAddrOp, clsAddrExprOp, clsImmOp;
|
18
|
+
|
19
|
+
#define IVAR(attr) "@" attr
|
20
|
+
#define SETTER(attr) attr "="
|
21
|
+
|
22
|
+
/* TODO: remove if not needed
|
23
|
+
static VALUE str_to_sym( const char * str ) {
|
24
|
+
VALUE var = rb_str_new_cstr(str);
|
25
|
+
return rb_funcall(var, symToSym, 0);
|
26
|
+
}
|
27
|
+
*/
|
28
|
+
|
29
|
+
#define ALLOC_FIXED_INSN opdis_alloc_fixed(128, 32, 16, 32)
|
30
|
+
|
31
|
+
/* ---------------------------------------------------------------------- */
|
32
|
+
/* Supported architectures */
|
33
|
+
|
34
|
+
/* ---------------------------------------------------------------------- */
|
35
|
+
/* Shared Methods */
|
36
|
+
|
37
|
+
static VALUE cls_generic_to_s( VALUE instance ) {
|
38
|
+
return rb_iv_get(instance, IVAR(GEN_ATTR_ASCII) );
|
39
|
+
}
|
40
|
+
|
41
|
+
/* ---------------------------------------------------------------------- */
|
42
|
+
/* Operand Base Class */
|
43
|
+
|
44
|
+
static VALUE cls_op_init(VALUE instance) {
|
45
|
+
rb_iv_set(instance, IVAR(INSN_ATTR_FLAGS), rb_ary_new() );
|
46
|
+
return instance;
|
47
|
+
}
|
48
|
+
|
49
|
+
static void define_op_constants() {
|
50
|
+
rb_define_const(clsOp, OP_FLAG_R_NAME, rb_str_new_cstr(OP_FLAG_R));
|
51
|
+
rb_define_const(clsOp, OP_FLAG_W_NAME, rb_str_new_cstr(OP_FLAG_W));
|
52
|
+
rb_define_const(clsOp, OP_FLAG_X_NAME, rb_str_new_cstr(OP_FLAG_X));
|
53
|
+
rb_define_const(clsOp, OP_FLAG_SIGNED_NAME,
|
54
|
+
rb_str_new_cstr(OP_FLAG_SIGNED));
|
55
|
+
rb_define_const(clsOp, OP_FLAG_ADDR_NAME,
|
56
|
+
rb_str_new_cstr(OP_FLAG_ADDR));
|
57
|
+
rb_define_const(clsOp, OP_FLAG_IND_NAME, rb_str_new_cstr(OP_FLAG_IND));
|
58
|
+
}
|
59
|
+
|
60
|
+
static void init_op_class( VALUE modOpdis ) {
|
61
|
+
clsOp = rb_define_class_under(modOpdis, "Operand", rb_cObject);
|
62
|
+
rb_define_method(clsOp, "initialize", cls_op_init, 0);
|
63
|
+
rb_define_method(clsOp, "to_s", cls_generic_to_s, 0);
|
64
|
+
|
65
|
+
define_op_constants();
|
66
|
+
|
67
|
+
/* read-write attributes */
|
68
|
+
rb_define_attr(clsOp, OP_ATTR_FLAGS, 1, 1);
|
69
|
+
rb_define_attr(clsOp, GEN_ATTR_ASCII, 1, 1);
|
70
|
+
rb_define_attr(clsOp, OP_ATTR_DATA_SZ, 1, 1);
|
71
|
+
}
|
72
|
+
|
73
|
+
/* ---------------------------------------------------------------------- */
|
74
|
+
/* Register Class */
|
75
|
+
|
76
|
+
static void set_ruby_reg_flags( VALUE instance, enum opdis_reg_flag_t val ) {
|
77
|
+
VALUE flags = rb_iv_get(instance, IVAR(REG_ATTR_FLAGS) );
|
78
|
+
if ( val & opdis_reg_flag_gen ) {
|
79
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_GEN) );
|
80
|
+
}
|
81
|
+
if ( val & opdis_reg_flag_fpu ) {
|
82
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_FPU) );
|
83
|
+
}
|
84
|
+
if ( val & opdis_reg_flag_gpu ) {
|
85
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_GPU) );
|
86
|
+
}
|
87
|
+
if ( val & opdis_reg_flag_simd ) {
|
88
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_SIMD) );
|
89
|
+
}
|
90
|
+
if ( val & opdis_reg_flag_task ) {
|
91
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_TASK) );
|
92
|
+
}
|
93
|
+
if ( val & opdis_reg_flag_mem ) {
|
94
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_MEM) );
|
95
|
+
}
|
96
|
+
if ( val & opdis_reg_flag_debug ) {
|
97
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_DBG) );
|
98
|
+
}
|
99
|
+
if ( val & opdis_reg_flag_pc ) {
|
100
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_PC) );
|
101
|
+
}
|
102
|
+
if ( val & opdis_reg_flag_flags ) {
|
103
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_CC) );
|
104
|
+
}
|
105
|
+
if ( val & opdis_reg_flag_stack ) {
|
106
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_STACK) );
|
107
|
+
}
|
108
|
+
if ( val & opdis_reg_flag_frame ) {
|
109
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_FRAME) );
|
110
|
+
}
|
111
|
+
if ( val & opdis_reg_flag_seg ) {
|
112
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_SEG) );
|
113
|
+
}
|
114
|
+
if ( val & opdis_reg_flag_zero ) {
|
115
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_Z) );
|
116
|
+
}
|
117
|
+
if ( val & opdis_reg_flag_argsin ) {
|
118
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_IN) );
|
119
|
+
}
|
120
|
+
if ( val & opdis_reg_flag_argsout ) {
|
121
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_OUT) );
|
122
|
+
}
|
123
|
+
if ( val & opdis_reg_flag_locals ) {
|
124
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_LOCALS) );
|
125
|
+
}
|
126
|
+
if ( val & opdis_reg_flag_return ) {
|
127
|
+
rb_ary_push(flags, rb_str_new_cstr( REG_FLAG_RET) );
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
static void set_c_reg_flags( opdis_reg_t * dest, VALUE reg ) {
|
132
|
+
int i;
|
133
|
+
struct RArray * flags = RARRAY( rb_iv_get(reg, IVAR(REG_ATTR_FLAGS)) );
|
134
|
+
dest->flags = opdis_reg_flag_unknown;
|
135
|
+
|
136
|
+
for ( i=0; i < RARRAY_LEN(flags); i++ ) {
|
137
|
+
VALUE val = RARRAY_PTR(flags)[i];
|
138
|
+
if (! strcmp( REG_FLAG_GEN, StringValueCStr(val) ) ) {
|
139
|
+
dest->flags |= opdis_reg_flag_gen;
|
140
|
+
} else if (! strcmp( REG_FLAG_FPU, StringValueCStr(val) ) ) {
|
141
|
+
dest->flags |= opdis_reg_flag_fpu;
|
142
|
+
} else if (! strcmp( REG_FLAG_GPU, StringValueCStr(val) ) ) {
|
143
|
+
dest->flags |= opdis_reg_flag_gpu;
|
144
|
+
} else if (! strcmp( REG_FLAG_SIMD, StringValueCStr(val) ) ) {
|
145
|
+
dest->flags |= opdis_reg_flag_simd;
|
146
|
+
} else if (! strcmp( REG_FLAG_TASK, StringValueCStr(val) ) ) {
|
147
|
+
dest->flags |= opdis_reg_flag_task;
|
148
|
+
} else if (! strcmp( REG_FLAG_MEM, StringValueCStr(val) ) ) {
|
149
|
+
dest->flags |= opdis_reg_flag_mem;
|
150
|
+
} else if (! strcmp( REG_FLAG_DBG, StringValueCStr(val) ) ) {
|
151
|
+
dest->flags |= opdis_reg_flag_debug;
|
152
|
+
} else if (! strcmp( REG_FLAG_PC, StringValueCStr(val) ) ) {
|
153
|
+
dest->flags |= opdis_reg_flag_pc;
|
154
|
+
} else if (! strcmp( REG_FLAG_CC, StringValueCStr(val) ) ) {
|
155
|
+
dest->flags |= opdis_reg_flag_flags;
|
156
|
+
} else if (! strcmp( REG_FLAG_STACK, StringValueCStr(val) ) ) {
|
157
|
+
dest->flags |= opdis_reg_flag_stack;
|
158
|
+
} else if (! strcmp( REG_FLAG_FRAME, StringValueCStr(val) ) ) {
|
159
|
+
dest->flags |= opdis_reg_flag_frame;
|
160
|
+
} else if (! strcmp( REG_FLAG_SEG, StringValueCStr(val) ) ) {
|
161
|
+
dest->flags |= opdis_reg_flag_seg;
|
162
|
+
} else if (! strcmp( REG_FLAG_Z, StringValueCStr(val) ) ) {
|
163
|
+
dest->flags |= opdis_reg_flag_zero;
|
164
|
+
} else if (! strcmp( REG_FLAG_IN, StringValueCStr(val) ) ) {
|
165
|
+
dest->flags |= opdis_reg_flag_argsin;
|
166
|
+
} else if (! strcmp( REG_FLAG_OUT, StringValueCStr(val) ) ) {
|
167
|
+
dest->flags |= opdis_reg_flag_argsout;
|
168
|
+
} else if (! strcmp( REG_FLAG_LOCALS, StringValueCStr(val) ) ) {
|
169
|
+
dest->flags |= opdis_reg_flag_locals;
|
170
|
+
} else if (! strcmp( REG_FLAG_RET, StringValueCStr(val) ) ) {
|
171
|
+
dest->flags |= opdis_reg_flag_return;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
static void fill_ruby_reg( opdis_reg_t * reg, VALUE dest ) {
|
177
|
+
rb_iv_set(dest, IVAR(REG_ATTR_ID), UINT2NUM(reg->id) );
|
178
|
+
rb_iv_set(dest, IVAR(REG_ATTR_SIZE), UINT2NUM(reg->size) );
|
179
|
+
rb_iv_set(dest, IVAR(GEN_ATTR_ASCII), rb_str_new_cstr(reg->ascii) );
|
180
|
+
set_ruby_reg_flags(dest, reg->flags);
|
181
|
+
}
|
182
|
+
|
183
|
+
static VALUE reg_from_c( opdis_reg_t * reg ) {
|
184
|
+
VALUE args[1] = {Qnil};
|
185
|
+
VALUE var = rb_class_new_instance(0, args, clsReg);
|
186
|
+
if ( var != Qnil ) {
|
187
|
+
fill_ruby_reg(reg, var);
|
188
|
+
}
|
189
|
+
return var;
|
190
|
+
}
|
191
|
+
|
192
|
+
static void reg_to_c( VALUE reg, opdis_reg_t * dest ) {
|
193
|
+
VALUE val;
|
194
|
+
|
195
|
+
val = rb_iv_get(reg, IVAR(REG_ATTR_ID));
|
196
|
+
dest->id = (val == Qnil) ? 0 : (unsigned char) NUM2UINT(val);
|
197
|
+
|
198
|
+
val = rb_iv_get(reg, IVAR(REG_ATTR_SIZE));
|
199
|
+
dest->size = (val == Qnil) ? 0 : (unsigned char) NUM2UINT(val);
|
200
|
+
|
201
|
+
val = rb_iv_get(reg, IVAR(GEN_ATTR_ASCII));
|
202
|
+
if ( val != Qnil ) {
|
203
|
+
strncpy( dest->ascii, StringValueCStr(val), OPDIS_REG_NAME_SZ );
|
204
|
+
}
|
205
|
+
|
206
|
+
set_c_reg_flags( dest, reg );
|
207
|
+
}
|
208
|
+
|
209
|
+
|
210
|
+
/* ---------------------------------------------------------------------- */
|
211
|
+
/* Register Operand */
|
212
|
+
|
213
|
+
static VALUE reg_op_from_c( opdis_reg_t * reg ) {
|
214
|
+
VALUE args[1] = {Qnil};
|
215
|
+
VALUE var = rb_class_new_instance(0, args, clsRegOp);
|
216
|
+
if ( var != Qnil ) {
|
217
|
+
fill_ruby_reg(reg, var);
|
218
|
+
}
|
219
|
+
return var;
|
220
|
+
}
|
221
|
+
|
222
|
+
static void init_reg_attributes( VALUE class ) {
|
223
|
+
rb_define_attr(class, REG_ATTR_ID, 1, 0);
|
224
|
+
rb_define_attr(class, GEN_ATTR_ASCII, 1, 0);
|
225
|
+
rb_define_attr(class, REG_ATTR_FLAGS, 1, 0);
|
226
|
+
rb_define_attr(class, REG_ATTR_SIZE, 1, 0);
|
227
|
+
}
|
228
|
+
|
229
|
+
static void define_reg_constants( VALUE class ) {
|
230
|
+
rb_define_const(class, REG_FLAG_GEN_NAME,
|
231
|
+
rb_str_new_cstr(REG_FLAG_GEN));
|
232
|
+
rb_define_const(class, REG_FLAG_FPU_NAME,
|
233
|
+
rb_str_new_cstr(REG_FLAG_FPU));
|
234
|
+
rb_define_const(class, REG_FLAG_GPU_NAME,
|
235
|
+
rb_str_new_cstr(REG_FLAG_GPU));
|
236
|
+
rb_define_const(class, REG_FLAG_SIMD_NAME,
|
237
|
+
rb_str_new_cstr(REG_FLAG_SIMD));
|
238
|
+
rb_define_const(class, REG_FLAG_TASK_NAME,
|
239
|
+
rb_str_new_cstr(REG_FLAG_TASK));
|
240
|
+
rb_define_const(class, REG_FLAG_MEM_NAME,
|
241
|
+
rb_str_new_cstr(REG_FLAG_MEM));
|
242
|
+
rb_define_const(class, REG_FLAG_DBG_NAME,
|
243
|
+
rb_str_new_cstr(REG_FLAG_DBG));
|
244
|
+
rb_define_const(class, REG_FLAG_PC_NAME,
|
245
|
+
rb_str_new_cstr(REG_FLAG_PC));
|
246
|
+
rb_define_const(class, REG_FLAG_CC_NAME,
|
247
|
+
rb_str_new_cstr(REG_FLAG_CC));
|
248
|
+
rb_define_const(class, REG_FLAG_STACK_NAME,
|
249
|
+
rb_str_new_cstr(REG_FLAG_STACK));
|
250
|
+
rb_define_const(class, REG_FLAG_FRAME_NAME,
|
251
|
+
rb_str_new_cstr(REG_FLAG_FRAME));
|
252
|
+
rb_define_const(class, REG_FLAG_SEG_NAME,
|
253
|
+
rb_str_new_cstr(REG_FLAG_SEG));
|
254
|
+
rb_define_const(class, REG_FLAG_Z_NAME,
|
255
|
+
rb_str_new_cstr(REG_FLAG_Z));
|
256
|
+
rb_define_const(class, REG_FLAG_IN_NAME,
|
257
|
+
rb_str_new_cstr(REG_FLAG_IN));
|
258
|
+
rb_define_const(class, REG_FLAG_OUT_NAME,
|
259
|
+
rb_str_new_cstr(REG_FLAG_OUT));
|
260
|
+
rb_define_const(class, REG_FLAG_LOCALS_NAME,
|
261
|
+
rb_str_new_cstr(REG_FLAG_LOCALS));
|
262
|
+
rb_define_const(class, REG_FLAG_RET_NAME,
|
263
|
+
rb_str_new_cstr(REG_FLAG_RET));
|
264
|
+
}
|
265
|
+
|
266
|
+
static VALUE cls_reg_init(VALUE instance) {
|
267
|
+
rb_iv_set(instance, IVAR(REG_ATTR_FLAGS), rb_ary_new() );
|
268
|
+
return instance;
|
269
|
+
}
|
270
|
+
|
271
|
+
static VALUE cls_reg_op_init(VALUE instance) {
|
272
|
+
cls_op_init(instance);
|
273
|
+
return cls_reg_init(instance);
|
274
|
+
}
|
275
|
+
|
276
|
+
static void init_reg_class( VALUE modOpdis ) {
|
277
|
+
/* Register */
|
278
|
+
clsReg = rb_define_class_under(modOpdis, "Register", rb_cObject);
|
279
|
+
|
280
|
+
rb_define_method(clsReg, "initialize", cls_reg_init, 0);
|
281
|
+
rb_define_method(clsReg, "to_s", cls_generic_to_s, 0);
|
282
|
+
rb_define_attr(clsReg, GEN_ATTR_ASCII, 1, 0);
|
283
|
+
rb_define_alias(clsReg, REG_ATTR_NAME, GEN_ATTR_ASCII );
|
284
|
+
|
285
|
+
define_reg_constants( clsReg );
|
286
|
+
init_reg_attributes( clsReg );
|
287
|
+
|
288
|
+
/* Register Operand */
|
289
|
+
clsRegOp = rb_define_class_under(modOpdis, "RegisterOperand", clsOp);
|
290
|
+
rb_define_method(clsRegOp, "initialize", cls_reg_op_init, 0);
|
291
|
+
rb_define_method(clsRegOp, "to_s", cls_generic_to_s, 0);
|
292
|
+
rb_define_alias(clsRegOp, REG_ATTR_NAME, GEN_ATTR_ASCII );
|
293
|
+
|
294
|
+
define_reg_constants( clsRegOp );
|
295
|
+
init_reg_attributes( clsRegOp );
|
296
|
+
}
|
297
|
+
|
298
|
+
/* ---------------------------------------------------------------------- */
|
299
|
+
/* Absolute Address Operand Class */
|
300
|
+
|
301
|
+
static void fill_ruby_absaddr( opdis_abs_addr_t * addr, VALUE dest ) {
|
302
|
+
rb_iv_set(dest, IVAR(ABS_ADDR_ATTR_SEG), reg_from_c(&addr->segment) );
|
303
|
+
rb_iv_set(dest, IVAR(ABS_ADDR_ATTR_OFF), addr->offset );
|
304
|
+
}
|
305
|
+
|
306
|
+
static VALUE absaddr_from_c( opdis_abs_addr_t * addr ) {
|
307
|
+
VALUE args[1] = {Qnil};
|
308
|
+
VALUE var = rb_class_new_instance(0, args, clsAbsAddr);
|
309
|
+
if ( var != Qnil ) {
|
310
|
+
fill_ruby_absaddr(addr, var);
|
311
|
+
}
|
312
|
+
return var;
|
313
|
+
}
|
314
|
+
|
315
|
+
static void absaddr_to_c( VALUE addr, opdis_abs_addr_t * dest ) {
|
316
|
+
reg_to_c( rb_iv_get(addr, IVAR(ABS_ADDR_ATTR_SEG)), &dest->segment );
|
317
|
+
dest->offset = NUM2OFFT(rb_iv_get(addr, IVAR(ABS_ADDR_ATTR_OFF)));
|
318
|
+
}
|
319
|
+
|
320
|
+
/* ---------------------------------------------------------------------- */
|
321
|
+
/* Absolute Address Operand */
|
322
|
+
|
323
|
+
static VALUE absaddr_op_from_c( opdis_abs_addr_t * addr ) {
|
324
|
+
VALUE args[1] = {Qnil};
|
325
|
+
VALUE var = rb_class_new_instance(0, args, clsAbsAddrOp);
|
326
|
+
if ( var != Qnil ) {
|
327
|
+
fill_ruby_absaddr(addr, var);
|
328
|
+
}
|
329
|
+
return var;
|
330
|
+
}
|
331
|
+
|
332
|
+
static void init_abs_addr_attributes( VALUE class ) {
|
333
|
+
rb_define_attr(class, ABS_ADDR_ATTR_SEG, 1, 1);
|
334
|
+
rb_define_attr(class, ABS_ADDR_ATTR_OFF, 1, 1);
|
335
|
+
}
|
336
|
+
|
337
|
+
static VALUE cls_absaddr_to_s( VALUE instance ) {
|
338
|
+
VALUE str;
|
339
|
+
VALUE off = rb_funcall( rb_iv_get(instance, IVAR(ABS_ADDR_ATTR_OFF)),
|
340
|
+
symToS, 1, INT2NUM(16) );
|
341
|
+
VALUE seg = rb_iv_get(instance, IVAR(ABS_ADDR_ATTR_SEG));
|
342
|
+
|
343
|
+
if ( seg == Qnil ) {
|
344
|
+
return off;
|
345
|
+
}
|
346
|
+
|
347
|
+
str = rb_str_dup(rb_iv_get(seg, IVAR(GEN_ATTR_ASCII)));
|
348
|
+
rb_str_buf_cat_ascii(str, ":");
|
349
|
+
rb_str_concat(str, off);
|
350
|
+
|
351
|
+
return str;
|
352
|
+
}
|
353
|
+
|
354
|
+
static void init_absaddr_class( VALUE modOpdis ) {
|
355
|
+
/* Absolute Address */
|
356
|
+
clsAbsAddr = rb_define_class_under(modOpdis, "AbsoluteAddress",
|
357
|
+
rb_cObject);
|
358
|
+
rb_define_method(clsAbsAddr, "to_s", cls_absaddr_to_s, 0);
|
359
|
+
rb_define_attr(clsAbsAddr, GEN_ATTR_ASCII, 1, 0);
|
360
|
+
|
361
|
+
init_abs_addr_attributes( clsAbsAddr );
|
362
|
+
|
363
|
+
/* Absolute Address Operand */
|
364
|
+
clsAbsAddrOp = rb_define_class_under(modOpdis, "AbsoluteAddressOperand",
|
365
|
+
clsOp);
|
366
|
+
rb_define_method(clsAbsAddrOp, "to_s", cls_absaddr_to_s, 0);
|
367
|
+
init_abs_addr_attributes( clsAbsAddrOp );
|
368
|
+
}
|
369
|
+
|
370
|
+
/* ---------------------------------------------------------------------- */
|
371
|
+
/* Address Expression Class */
|
372
|
+
|
373
|
+
static enum opdis_addr_expr_shift_t get_expr_shift( const char * str ) {
|
374
|
+
if (! strcmp( ADDR_EXP_SHIFT_LSL, str ) ) {
|
375
|
+
return opdis_addr_expr_lsl;
|
376
|
+
} else if (! strcmp( ADDR_EXP_SHIFT_LSR, str ) ) {
|
377
|
+
return opdis_addr_expr_lsr;
|
378
|
+
} else if (! strcmp( ADDR_EXP_SHIFT_ROR, str ) ) {
|
379
|
+
return opdis_addr_expr_ror;
|
380
|
+
} else if (! strcmp( ADDR_EXP_SHIFT_RRX, str ) ) {
|
381
|
+
return opdis_addr_expr_rrx;
|
382
|
+
}
|
383
|
+
|
384
|
+
return opdis_addr_expr_asl;
|
385
|
+
}
|
386
|
+
|
387
|
+
static const char * get_expr_shift_str( enum opdis_addr_expr_shift_t val ){
|
388
|
+
const char * str = ADDR_EXP_SHIFT_ASL;
|
389
|
+
|
390
|
+
switch (val) {
|
391
|
+
case opdis_addr_expr_lsl: str = ADDR_EXP_SHIFT_LSL; break;
|
392
|
+
case opdis_addr_expr_lsr: str = ADDR_EXP_SHIFT_LSR; break;
|
393
|
+
case opdis_addr_expr_asl: str = ADDR_EXP_SHIFT_ASL; break;
|
394
|
+
case opdis_addr_expr_ror: str = ADDR_EXP_SHIFT_ROR; break;
|
395
|
+
case opdis_addr_expr_rrx: str = ADDR_EXP_SHIFT_RRX; break;
|
396
|
+
}
|
397
|
+
|
398
|
+
return str;
|
399
|
+
}
|
400
|
+
|
401
|
+
|
402
|
+
static void fill_ruby_addrexpr( opdis_addr_expr_t * expr, VALUE dest ) {
|
403
|
+
|
404
|
+
if ( expr->elements & opdis_addr_expr_base ) {
|
405
|
+
rb_iv_set(dest, IVAR(ADDR_EXP_ATTR_BASE),
|
406
|
+
reg_from_c(&expr->base) );
|
407
|
+
}
|
408
|
+
|
409
|
+
if ( expr->elements & opdis_addr_expr_index ) {
|
410
|
+
rb_iv_set(dest, IVAR(ADDR_EXP_ATTR_INDEX),
|
411
|
+
reg_from_c(&expr->index) );
|
412
|
+
}
|
413
|
+
|
414
|
+
if ( expr->elements & opdis_addr_expr_disp ) {
|
415
|
+
if ( expr->elements & opdis_addr_expr_disp_abs ) {
|
416
|
+
rb_iv_set(dest, IVAR(ADDR_EXP_ATTR_DISP),
|
417
|
+
absaddr_from_c(&expr->displacement.a));
|
418
|
+
} else if ( expr->elements & opdis_addr_expr_disp_s ) {
|
419
|
+
rb_iv_set(dest, IVAR(ADDR_EXP_ATTR_DISP),
|
420
|
+
LL2NUM(expr->displacement.s));
|
421
|
+
} else {
|
422
|
+
rb_iv_set(dest, IVAR(ADDR_EXP_ATTR_DISP),
|
423
|
+
ULL2NUM(expr->displacement.u));
|
424
|
+
}
|
425
|
+
}
|
426
|
+
|
427
|
+
rb_iv_set( dest, IVAR(ADDR_EXP_ATTR_SHIFT),
|
428
|
+
rb_str_new_cstr(get_expr_shift_str(expr->shift)) );
|
429
|
+
}
|
430
|
+
|
431
|
+
static VALUE addrexpr_op_from_c( opdis_addr_expr_t * expr ) {
|
432
|
+
VALUE args[1] = {Qnil};
|
433
|
+
VALUE var = rb_class_new_instance(0, args, clsAddrExprOp);
|
434
|
+
if ( var != Qnil ) {
|
435
|
+
fill_ruby_addrexpr( expr, var );
|
436
|
+
}
|
437
|
+
return var;
|
438
|
+
}
|
439
|
+
|
440
|
+
static void addrexpr_to_c( VALUE expr, opdis_addr_expr_t * dest ) {
|
441
|
+
VALUE val;
|
442
|
+
val = rb_iv_get(expr, IVAR(ADDR_EXP_ATTR_BASE));
|
443
|
+
if ( val != Qnil ) {
|
444
|
+
dest->elements |= opdis_addr_expr_base;
|
445
|
+
reg_to_c( val, &dest->base );
|
446
|
+
}
|
447
|
+
|
448
|
+
val = rb_iv_get(expr, IVAR(ADDR_EXP_ATTR_INDEX));
|
449
|
+
if ( val != Qnil ) {
|
450
|
+
dest->elements |= opdis_addr_expr_index;
|
451
|
+
reg_to_c( val, &dest->index );
|
452
|
+
}
|
453
|
+
|
454
|
+
val = rb_iv_get(expr, IVAR(ADDR_EXP_ATTR_SCALE));
|
455
|
+
dest->scale = (val == Qnil) ? 1 : NUM2INT(val);
|
456
|
+
|
457
|
+
val = rb_iv_get(expr, IVAR(ADDR_EXP_ATTR_SHIFT));
|
458
|
+
dest->shift = (val == Qnil ) ? opdis_addr_expr_asl :
|
459
|
+
get_expr_shift(StringValueCStr(val));
|
460
|
+
|
461
|
+
val = rb_iv_get(expr, IVAR(ADDR_EXP_ATTR_DISP));
|
462
|
+
if ( val != Qnil ) {
|
463
|
+
dest->elements |= opdis_addr_expr_disp;
|
464
|
+
if ( Qtrue == rb_obj_is_kind_of( val, clsAbsAddr ) ) {
|
465
|
+
dest->elements |= opdis_addr_expr_disp_abs;
|
466
|
+
absaddr_to_c(val, &dest->displacement.a);
|
467
|
+
} else {
|
468
|
+
dest->displacement.u = NUM2ULL(val);
|
469
|
+
// TODO: int rb_cmpint(VALUE, VALUE, VALUE)
|
470
|
+
dest->elements |= opdis_addr_expr_disp_u;
|
471
|
+
//dest->elements |= ( (is_signed) ?
|
472
|
+
// opdis_addr_expr_disp_s :
|
473
|
+
// opdis_addr_expr_disp_u );
|
474
|
+
}
|
475
|
+
}
|
476
|
+
}
|
477
|
+
|
478
|
+
static VALUE cls_addrexpr_to_s( VALUE instance ) {
|
479
|
+
VALUE val, str;
|
480
|
+
int needs_plus = 0;
|
481
|
+
|
482
|
+
str = rb_str_new_cstr("");
|
483
|
+
val = rb_iv_get(instance, IVAR(ADDR_EXP_ATTR_BASE));
|
484
|
+
if ( val != Qnil ) {
|
485
|
+
rb_str_concat(str, rb_iv_get(val, IVAR(GEN_ATTR_ASCII)));
|
486
|
+
needs_plus = 1;
|
487
|
+
}
|
488
|
+
|
489
|
+
val = rb_iv_get(instance, IVAR(ADDR_EXP_ATTR_INDEX));
|
490
|
+
if ( val != Qnil ) {
|
491
|
+
VALUE v;
|
492
|
+
if ( needs_plus ) {
|
493
|
+
rb_str_buf_cat_ascii(str, "+");
|
494
|
+
needs_plus = 0;
|
495
|
+
}
|
496
|
+
|
497
|
+
/* subexpression start */
|
498
|
+
rb_str_buf_cat_ascii(str, "(");
|
499
|
+
|
500
|
+
/* index register */
|
501
|
+
rb_str_concat(str, rb_iv_get(val, IVAR(GEN_ATTR_ASCII)));
|
502
|
+
|
503
|
+
/* scale operation */
|
504
|
+
v = rb_iv_get(instance, IVAR(ADDR_EXP_ATTR_SHIFT));
|
505
|
+
if ( v == Qnil ) {
|
506
|
+
rb_str_buf_cat_ascii(str, "*");
|
507
|
+
} else {
|
508
|
+
rb_str_concat(str, v);
|
509
|
+
}
|
510
|
+
|
511
|
+
/* scale value */
|
512
|
+
v = rb_iv_get(instance, IVAR(ADDR_EXP_ATTR_SCALE));
|
513
|
+
if ( v == Qnil ) {
|
514
|
+
rb_str_buf_cat_ascii(str, "1");
|
515
|
+
} else {
|
516
|
+
rb_str_concat(str, rb_any_to_s(v));
|
517
|
+
}
|
518
|
+
|
519
|
+
/* subexpression end */
|
520
|
+
rb_str_buf_cat_ascii(str, ")");
|
521
|
+
needs_plus = 1;
|
522
|
+
}
|
523
|
+
|
524
|
+
val = rb_iv_get(instance, IVAR(ADDR_EXP_ATTR_DISP));
|
525
|
+
if ( val != Qnil ) {
|
526
|
+
if ( needs_plus ) {
|
527
|
+
rb_str_buf_cat_ascii(str, "+");
|
528
|
+
}
|
529
|
+
rb_str_concat( str, rb_funcall(val, symToS, 1, INT2NUM(16)) );
|
530
|
+
}
|
531
|
+
|
532
|
+
return str;
|
533
|
+
}
|
534
|
+
|
535
|
+
static void init_addrexpr_class( VALUE modOpdis ) {
|
536
|
+
clsAddrExprOp = rb_define_class_under(modOpdis,
|
537
|
+
"AddressExpressionOperand", clsOp);
|
538
|
+
rb_define_method(clsAddrExprOp, "to_s", cls_addrexpr_to_s, 0);
|
539
|
+
|
540
|
+
/* read-write attributes */
|
541
|
+
rb_define_attr(clsAddrExprOp, ADDR_EXP_ATTR_SHIFT, 1, 1);
|
542
|
+
rb_define_attr(clsAddrExprOp, ADDR_EXP_ATTR_SCALE, 1, 1);
|
543
|
+
rb_define_attr(clsAddrExprOp, ADDR_EXP_ATTR_INDEX, 1, 1);
|
544
|
+
rb_define_attr(clsAddrExprOp, ADDR_EXP_ATTR_BASE, 1, 1);
|
545
|
+
rb_define_attr(clsAddrExprOp, ADDR_EXP_ATTR_DISP, 1, 1);
|
546
|
+
|
547
|
+
/* constants */
|
548
|
+
rb_define_const(clsAddrExprOp, ADDR_EXP_SHIFT_LSL_NAME,
|
549
|
+
rb_str_new_cstr(ADDR_EXP_SHIFT_LSL));
|
550
|
+
rb_define_const(clsAddrExprOp, ADDR_EXP_SHIFT_LSR_NAME,
|
551
|
+
rb_str_new_cstr(ADDR_EXP_SHIFT_LSR));
|
552
|
+
rb_define_const(clsAddrExprOp, ADDR_EXP_SHIFT_ASL_NAME,
|
553
|
+
rb_str_new_cstr(ADDR_EXP_SHIFT_ASL));
|
554
|
+
rb_define_const(clsAddrExprOp, ADDR_EXP_SHIFT_ROR_NAME,
|
555
|
+
rb_str_new_cstr(ADDR_EXP_SHIFT_ROR));
|
556
|
+
rb_define_const(clsAddrExprOp, ADDR_EXP_SHIFT_RRX_NAME,
|
557
|
+
rb_str_new_cstr(ADDR_EXP_SHIFT_RRX));
|
558
|
+
}
|
559
|
+
|
560
|
+
/* ---------------------------------------------------------------------- */
|
561
|
+
/* Immediate Operand */
|
562
|
+
|
563
|
+
static VALUE cls_imm_to_s(VALUE instance) {
|
564
|
+
return rb_any_to_s(rb_iv_get(instance, IVAR(IMM_ATTR_VAL)));
|
565
|
+
}
|
566
|
+
|
567
|
+
static uint64_t imm_to_c( VALUE imm ) {
|
568
|
+
return NUM2ULL(rb_iv_get(imm, IVAR(IMM_ATTR_UNSIGNED)));
|
569
|
+
}
|
570
|
+
|
571
|
+
static VALUE imm_op_from_c( opdis_op_t * op ) {
|
572
|
+
VALUE args[1] = {Qnil};
|
573
|
+
VALUE var = rb_class_new_instance(0, args, clsImmOp);
|
574
|
+
if ( var == Qnil ) {
|
575
|
+
return var;
|
576
|
+
}
|
577
|
+
|
578
|
+
rb_iv_set(var, IVAR(IMM_ATTR_VMA),
|
579
|
+
ULL2NUM(op->value.immediate.vma) );
|
580
|
+
rb_iv_set(var, IVAR(IMM_ATTR_SIGNED),
|
581
|
+
LL2NUM(op->value.immediate.s) );
|
582
|
+
rb_iv_set(var, IVAR(IMM_ATTR_UNSIGNED),
|
583
|
+
ULL2NUM(op->value.immediate.u) );
|
584
|
+
rb_iv_set(var, IVAR(IMM_ATTR_VAL),
|
585
|
+
(op->flags & opdis_op_flag_signed) ?
|
586
|
+
LL2NUM(op->value.immediate.s) :
|
587
|
+
ULL2NUM(op->value.immediate.u) );
|
588
|
+
return var;
|
589
|
+
}
|
590
|
+
|
591
|
+
static void init_imm_class( VALUE modOpdis ) {
|
592
|
+
clsImmOp = rb_define_class_under(modOpdis, "ImmediateOperand", clsOp);
|
593
|
+
rb_define_singleton_method(clsImmOp, "to_s", cls_imm_to_s, 0);
|
594
|
+
|
595
|
+
rb_define_attr(clsImmOp, IMM_ATTR_VAL, 1, 1);
|
596
|
+
rb_define_attr(clsImmOp, IMM_ATTR_VMA, 1, 1);
|
597
|
+
rb_define_attr(clsImmOp, IMM_ATTR_SIGNED, 1, 1);
|
598
|
+
rb_define_attr(clsImmOp, IMM_ATTR_UNSIGNED, 1, 1);
|
599
|
+
}
|
600
|
+
|
601
|
+
/* ---------------------------------------------------------------------- */
|
602
|
+
/* Operand Factory */
|
603
|
+
|
604
|
+
static enum opdis_op_flag_t op_flags_code( VALUE op ) {
|
605
|
+
int i;
|
606
|
+
enum opdis_op_flag_t flags = opdis_op_flag_none;
|
607
|
+
struct RArray * ary = RARRAY( rb_iv_get(op, IVAR(OP_ATTR_FLAGS)) );
|
608
|
+
|
609
|
+
for ( i=0; i < RARRAY_LEN(ary); i++ ) {
|
610
|
+
VALUE val = RARRAY_PTR(ary)[i];
|
611
|
+
if (! strcmp(OP_FLAG_R, StringValueCStr(val)) ) {
|
612
|
+
flags |= opdis_op_flag_r;
|
613
|
+
} else if (! strcmp(OP_FLAG_W, StringValueCStr(val)) ) {
|
614
|
+
flags |= opdis_op_flag_w;
|
615
|
+
} else if (! strcmp(OP_FLAG_X, StringValueCStr(val)) ) {
|
616
|
+
flags |= opdis_op_flag_x;
|
617
|
+
} else if (! strcmp(OP_FLAG_SIGNED, StringValueCStr(val)) ) {
|
618
|
+
flags |= opdis_op_flag_signed;
|
619
|
+
} else if (! strcmp(OP_FLAG_ADDR, StringValueCStr(val)) ) {
|
620
|
+
flags |= opdis_op_flag_address;
|
621
|
+
} else if (! strcmp(OP_FLAG_IND, StringValueCStr(val)) ) {
|
622
|
+
flags |= opdis_op_flag_indirect;
|
623
|
+
}
|
624
|
+
}
|
625
|
+
|
626
|
+
return flags;
|
627
|
+
}
|
628
|
+
|
629
|
+
static void set_rb_op_flags( VALUE instance, enum opdis_op_flag_t val ) {
|
630
|
+
VALUE flags = rb_iv_get(instance, IVAR(OP_ATTR_FLAGS) );
|
631
|
+
|
632
|
+
if ( val & opdis_op_flag_r ) {
|
633
|
+
rb_ary_push(flags, rb_str_new_cstr(OP_FLAG_R) );
|
634
|
+
}
|
635
|
+
if ( val & opdis_op_flag_w ) {
|
636
|
+
rb_ary_push(flags, rb_str_new_cstr(OP_FLAG_W) );
|
637
|
+
}
|
638
|
+
if ( val & opdis_op_flag_x ) {
|
639
|
+
rb_ary_push(flags, rb_str_new_cstr(OP_FLAG_X) );
|
640
|
+
}
|
641
|
+
if ( val & opdis_op_flag_signed ) {
|
642
|
+
rb_ary_push(flags, rb_str_new_cstr(OP_FLAG_SIGNED) );
|
643
|
+
}
|
644
|
+
if ( val & opdis_op_flag_address ) {
|
645
|
+
rb_ary_push(flags, rb_str_new_cstr(OP_FLAG_ADDR) );
|
646
|
+
}
|
647
|
+
if ( val & opdis_op_flag_indirect ) {
|
648
|
+
rb_ary_push(flags, rb_str_new_cstr(OP_FLAG_IND) );
|
649
|
+
}
|
650
|
+
}
|
651
|
+
|
652
|
+
static void op_to_c( VALUE op, opdis_op_t * dest ) {
|
653
|
+
VALUE var;
|
654
|
+
|
655
|
+
if ( Qtrue == rb_obj_is_kind_of( op, clsImmOp) ) {
|
656
|
+
dest->category = opdis_op_cat_immediate;
|
657
|
+
dest->value.immediate.u = imm_to_c( op );
|
658
|
+
|
659
|
+
} else if ( Qtrue == rb_obj_is_kind_of( op, clsRegOp) ) {
|
660
|
+
dest->category = opdis_op_cat_register;
|
661
|
+
reg_to_c( op, &dest->value.reg );
|
662
|
+
|
663
|
+
} else if ( Qtrue == rb_obj_is_kind_of( op, clsAddrExprOp) ) {
|
664
|
+
dest->category = opdis_op_cat_expr;
|
665
|
+
addrexpr_to_c( op, &dest->value.expr );
|
666
|
+
|
667
|
+
} else if ( Qtrue == rb_obj_is_kind_of( op, clsAbsAddrOp) ) {
|
668
|
+
dest->category = opdis_op_cat_absolute;
|
669
|
+
absaddr_to_c( op, &dest->value.abs );
|
670
|
+
}
|
671
|
+
|
672
|
+
var = rb_iv_get(op, IVAR(GEN_ATTR_ASCII));
|
673
|
+
opdis_op_set_ascii(dest, StringValueCStr(var));
|
674
|
+
|
675
|
+
dest->data_size = (unsigned char) NUM2UINT(rb_iv_get(op,
|
676
|
+
IVAR(OP_ATTR_DATA_SZ)));
|
677
|
+
dest->flags = op_flags_code( op );
|
678
|
+
}
|
679
|
+
|
680
|
+
static VALUE op_from_c( opdis_op_t * op ) {
|
681
|
+
VALUE args[1] = {Qnil};
|
682
|
+
VALUE dest;
|
683
|
+
|
684
|
+
switch (op->category) {
|
685
|
+
case opdis_op_cat_register:
|
686
|
+
dest = reg_op_from_c(&op->value.reg); break;
|
687
|
+
case opdis_op_cat_immediate:
|
688
|
+
dest = imm_op_from_c(op); break;
|
689
|
+
case opdis_op_cat_absolute:
|
690
|
+
dest = absaddr_op_from_c(&op->value.abs); break;
|
691
|
+
case opdis_op_cat_expr:
|
692
|
+
dest = addrexpr_op_from_c(&op->value.expr); break;
|
693
|
+
case opdis_op_cat_unknown:
|
694
|
+
default:
|
695
|
+
dest = rb_class_new_instance(0, args, clsOp);
|
696
|
+
}
|
697
|
+
|
698
|
+
if ( dest == Qnil ) {
|
699
|
+
return dest;
|
700
|
+
}
|
701
|
+
|
702
|
+
rb_iv_set(dest, IVAR(GEN_ATTR_ASCII), rb_str_new_cstr(op->ascii));
|
703
|
+
rb_iv_set(dest, IVAR(OP_ATTR_DATA_SZ),
|
704
|
+
UINT2NUM((unsigned int) op->data_size));
|
705
|
+
set_rb_op_flags( dest, op->flags );
|
706
|
+
|
707
|
+
return dest;
|
708
|
+
}
|
709
|
+
|
710
|
+
/* ---------------------------------------------------------------------- */
|
711
|
+
/* Instruction Class */
|
712
|
+
|
713
|
+
static VALUE cls_insn_init(VALUE instance) {
|
714
|
+
rb_iv_set(instance, IVAR(INSN_ATTR_OPERANDS), rb_ary_new() );
|
715
|
+
rb_iv_set(instance, IVAR(INSN_ATTR_STATUS), rb_ary_new() );
|
716
|
+
|
717
|
+
return instance;
|
718
|
+
}
|
719
|
+
|
720
|
+
static void set_attr_if_alias( VALUE instance, const char * name, int idx,
|
721
|
+
opdis_op_t * a, opdis_op_t * b ) {
|
722
|
+
if ( a && b && a == b ) {
|
723
|
+
rb_iv_set(instance, name, INT2NUM(idx) );
|
724
|
+
}
|
725
|
+
}
|
726
|
+
|
727
|
+
|
728
|
+
static enum opdis_insn_cat_t insn_category_code( VALUE insn ) {
|
729
|
+
VALUE val = rb_iv_get(insn, IVAR(INSN_ATTR_CATEGORY));
|
730
|
+
if (! strcmp(INSN_CAT_CFLOW , StringValueCStr(val)) ) {
|
731
|
+
return opdis_insn_cat_cflow;
|
732
|
+
} else if (! strcmp(INSN_CAT_STACK , StringValueCStr(val)) ) {
|
733
|
+
return opdis_insn_cat_stack;
|
734
|
+
} else if (! strcmp(INSN_CAT_LOST , StringValueCStr(val)) ) {
|
735
|
+
return opdis_insn_cat_lost;
|
736
|
+
} else if (! strcmp(INSN_CAT_TEST , StringValueCStr(val)) ) {
|
737
|
+
return opdis_insn_cat_test;
|
738
|
+
} else if (! strcmp(INSN_CAT_MATH , StringValueCStr(val)) ) {
|
739
|
+
return opdis_insn_cat_math;
|
740
|
+
} else if (! strcmp(INSN_CAT_BIT , StringValueCStr(val)) ) {
|
741
|
+
return opdis_insn_cat_bit;
|
742
|
+
} else if (! strcmp(INSN_CAT_IO , StringValueCStr(val)) ) {
|
743
|
+
return opdis_insn_cat_io;
|
744
|
+
} else if (! strcmp(INSN_CAT_TRAP , StringValueCStr(val)) ) {
|
745
|
+
return opdis_insn_cat_trap;
|
746
|
+
} else if (! strcmp(INSN_CAT_PRIV , StringValueCStr(val)) ) {
|
747
|
+
return opdis_insn_cat_priv;
|
748
|
+
} else if (! strcmp(INSN_CAT_NOP , StringValueCStr(val)) ) {
|
749
|
+
return opdis_insn_cat_nop;
|
750
|
+
}
|
751
|
+
|
752
|
+
return opdis_insn_cat_unknown;
|
753
|
+
}
|
754
|
+
|
755
|
+
static enum opdis_insn_subset_t insn_isa_code( VALUE insn ) {
|
756
|
+
VALUE val = rb_iv_get(insn, IVAR(INSN_ATTR_ISA));
|
757
|
+
if (! strcmp(INSN_ISA_FPU , StringValueCStr(val)) ) {
|
758
|
+
return opdis_insn_subset_fpu;
|
759
|
+
} else if (! strcmp(INSN_ISA_GPU , StringValueCStr(val)) ) {
|
760
|
+
return opdis_insn_subset_gpu;
|
761
|
+
} else if (! strcmp(INSN_ISA_SIMD , StringValueCStr(val)) ) {
|
762
|
+
return opdis_insn_subset_simd;
|
763
|
+
} else if (! strcmp(INSN_ISA_VM , StringValueCStr(val)) ) {
|
764
|
+
return opdis_insn_subset_vm;
|
765
|
+
}
|
766
|
+
|
767
|
+
return opdis_insn_subset_gen;
|
768
|
+
}
|
769
|
+
|
770
|
+
static void insn_set_flags( opdis_insn_t * dest, VALUE insn ) {
|
771
|
+
int i;
|
772
|
+
struct RArray * ary = RARRAY( rb_iv_get(insn, IVAR(INSN_ATTR_FLAGS)) );
|
773
|
+
|
774
|
+
dest->flags.cflow = opdis_cflow_flag_none;
|
775
|
+
|
776
|
+
for ( i=0; i < RARRAY_LEN(ary); i++ ) {
|
777
|
+
VALUE val = RARRAY_PTR(ary)[i];
|
778
|
+
switch (dest->category) {
|
779
|
+
case opdis_insn_cat_cflow:
|
780
|
+
if (! strcmp(INSN_FLAG_CALL,
|
781
|
+
StringValueCStr(val)) ) {
|
782
|
+
dest->flags.cflow |=
|
783
|
+
opdis_cflow_flag_call;
|
784
|
+
} else if (! strcmp(INSN_FLAG_CALLCC,
|
785
|
+
StringValueCStr(val)) ) {
|
786
|
+
dest->flags.cflow |=
|
787
|
+
opdis_cflow_flag_callcc;
|
788
|
+
} else if (! strcmp(INSN_FLAG_JMP,
|
789
|
+
StringValueCStr(val)) ) {
|
790
|
+
dest->flags.cflow |=
|
791
|
+
opdis_cflow_flag_jmp;
|
792
|
+
} else if (! strcmp(INSN_FLAG_JMPCC,
|
793
|
+
StringValueCStr(val)) ) {
|
794
|
+
dest->flags.cflow |=
|
795
|
+
opdis_cflow_flag_jmpcc;
|
796
|
+
} else if (! strcmp(INSN_FLAG_RET,
|
797
|
+
StringValueCStr(val)) ) {
|
798
|
+
dest->flags.cflow |=
|
799
|
+
opdis_cflow_flag_ret;
|
800
|
+
}
|
801
|
+
break;
|
802
|
+
case opdis_insn_cat_stack:
|
803
|
+
if (! strcmp(INSN_FLAG_PUSH,
|
804
|
+
StringValueCStr(val)) ) {
|
805
|
+
dest->flags.stack |=
|
806
|
+
opdis_stack_flag_push;
|
807
|
+
} else if (! strcmp(INSN_FLAG_POP,
|
808
|
+
StringValueCStr(val)) ) {
|
809
|
+
dest->flags.stack |=
|
810
|
+
opdis_stack_flag_pop;
|
811
|
+
} else if (! strcmp(INSN_FLAG_FRAME,
|
812
|
+
StringValueCStr(val)) ) {
|
813
|
+
dest->flags.stack |=
|
814
|
+
opdis_stack_flag_frame;
|
815
|
+
} else if (! strcmp(INSN_FLAG_UNFRAME,
|
816
|
+
StringValueCStr(val)) ) {
|
817
|
+
dest->flags.stack |=
|
818
|
+
opdis_stack_flag_unframe;
|
819
|
+
}
|
820
|
+
break;
|
821
|
+
case opdis_insn_cat_bit:
|
822
|
+
if (! strcmp(INSN_FLAG_AND,
|
823
|
+
StringValueCStr(val)) ) {
|
824
|
+
dest->flags.bit |= opdis_bit_flag_and;
|
825
|
+
} else if (! strcmp(INSN_FLAG_OR,
|
826
|
+
StringValueCStr(val)) ) {
|
827
|
+
dest->flags.bit |= opdis_bit_flag_or;
|
828
|
+
} else if (! strcmp(INSN_FLAG_XOR,
|
829
|
+
StringValueCStr(val)) ) {
|
830
|
+
dest->flags.bit |= opdis_bit_flag_xor;
|
831
|
+
} else if (! strcmp(INSN_FLAG_NOT,
|
832
|
+
StringValueCStr(val)) ) {
|
833
|
+
dest->flags.bit |= opdis_bit_flag_not;
|
834
|
+
} else if (! strcmp(INSN_FLAG_LSL,
|
835
|
+
StringValueCStr(val)) ) {
|
836
|
+
dest->flags.bit |= opdis_bit_flag_lsl;
|
837
|
+
} else if (! strcmp(INSN_FLAG_LSR,
|
838
|
+
StringValueCStr(val)) ) {
|
839
|
+
dest->flags.bit |= opdis_bit_flag_lsr;
|
840
|
+
} else if (! strcmp(INSN_FLAG_ASL,
|
841
|
+
StringValueCStr(val)) ) {
|
842
|
+
dest->flags.bit |= opdis_bit_flag_asl;
|
843
|
+
} else if (! strcmp(INSN_FLAG_ASR,
|
844
|
+
StringValueCStr(val)) ) {
|
845
|
+
dest->flags.bit |= opdis_bit_flag_asr;
|
846
|
+
} else if (! strcmp(INSN_FLAG_ROL,
|
847
|
+
StringValueCStr(val)) ) {
|
848
|
+
dest->flags.bit |= opdis_bit_flag_rol;
|
849
|
+
} else if (! strcmp(INSN_FLAG_ROR,
|
850
|
+
StringValueCStr(val)) ) {
|
851
|
+
dest->flags.bit |= opdis_bit_flag_ror;
|
852
|
+
} else if (! strcmp(INSN_FLAG_RCL,
|
853
|
+
StringValueCStr(val)) ) {
|
854
|
+
dest->flags.bit |= opdis_bit_flag_rcl;
|
855
|
+
} else if (! strcmp(INSN_FLAG_RCR,
|
856
|
+
StringValueCStr(val)) ) {
|
857
|
+
dest->flags.bit |= opdis_bit_flag_rcr;
|
858
|
+
}
|
859
|
+
break;
|
860
|
+
case opdis_insn_cat_io:
|
861
|
+
if (! strcmp(INSN_FLAG_OUT,
|
862
|
+
StringValueCStr(val)) ) {
|
863
|
+
dest->flags.io |= opdis_io_flag_in;
|
864
|
+
} else if (! strcmp(INSN_FLAG_IN,
|
865
|
+
StringValueCStr(val)) ) {
|
866
|
+
dest->flags.io |= opdis_io_flag_out;
|
867
|
+
}
|
868
|
+
break;
|
869
|
+
default: break;
|
870
|
+
}
|
871
|
+
}
|
872
|
+
}
|
873
|
+
|
874
|
+
static enum opdis_insn_decode_t insn_status_code( VALUE instance ) {
|
875
|
+
int i;
|
876
|
+
enum opdis_insn_decode_t status = opdis_decode_invalid;
|
877
|
+
struct RArray * ary = RARRAY( rb_iv_get(instance,
|
878
|
+
IVAR(INSN_ATTR_STATUS)) );
|
879
|
+
|
880
|
+
for ( i=0; i < RARRAY_LEN(ary); i++ ) {
|
881
|
+
VALUE val = RARRAY_PTR(ary)[i];
|
882
|
+
if (! strcmp(INSN_DECODE_BASIC, StringValueCStr(val)) ) {
|
883
|
+
status |= opdis_decode_basic;
|
884
|
+
} else if (! strcmp(INSN_DECODE_MNEM, StringValueCStr(val)) ) {
|
885
|
+
status |= opdis_decode_mnem;
|
886
|
+
} else if (! strcmp(INSN_DECODE_OPS, StringValueCStr(val)) ) {
|
887
|
+
status |= opdis_decode_ops;
|
888
|
+
} else if (! strcmp(INSN_DECODE_MNEMFLG,
|
889
|
+
StringValueCStr(val)) ) {
|
890
|
+
status |= opdis_decode_mnem_flags;
|
891
|
+
} else if (! strcmp(INSN_DECODE_OPFLG,
|
892
|
+
StringValueCStr(val)) ) {
|
893
|
+
status |= opdis_decode_op_flags;
|
894
|
+
}
|
895
|
+
}
|
896
|
+
|
897
|
+
return status;
|
898
|
+
}
|
899
|
+
|
900
|
+
static void set_insn_status( VALUE instance, enum opdis_insn_decode_t val ) {
|
901
|
+
VALUE status = rb_iv_get(instance, IVAR(INSN_ATTR_STATUS) );
|
902
|
+
|
903
|
+
if ( val == opdis_decode_invalid ) {
|
904
|
+
rb_ary_push(status, rb_str_new_cstr( INSN_DECODE_INVALID) );
|
905
|
+
return;
|
906
|
+
}
|
907
|
+
|
908
|
+
if ( val & opdis_decode_basic ) {
|
909
|
+
rb_ary_push(status, rb_str_new_cstr( INSN_DECODE_BASIC) );
|
910
|
+
}
|
911
|
+
if ( val & opdis_decode_mnem ) {
|
912
|
+
rb_ary_push(status, rb_str_new_cstr( INSN_DECODE_MNEM) );
|
913
|
+
}
|
914
|
+
if ( val & opdis_decode_ops ) {
|
915
|
+
rb_ary_push(status, rb_str_new_cstr( INSN_DECODE_OPS) );
|
916
|
+
}
|
917
|
+
if ( val & opdis_decode_mnem_flags ) {
|
918
|
+
rb_ary_push(status, rb_str_new_cstr( INSN_DECODE_MNEMFLG) );
|
919
|
+
}
|
920
|
+
if ( val & opdis_decode_op_flags ) {
|
921
|
+
rb_ary_push(status, rb_str_new_cstr( INSN_DECODE_OPFLG) );
|
922
|
+
}
|
923
|
+
}
|
924
|
+
|
925
|
+
static void fill_ruby_insn( const opdis_insn_t * insn, VALUE dest ) {
|
926
|
+
int i;
|
927
|
+
char buf[128];
|
928
|
+
VALUE ops = rb_iv_get(dest, IVAR(INSN_ATTR_OPERANDS) );
|
929
|
+
|
930
|
+
set_insn_status( dest, insn->status );
|
931
|
+
|
932
|
+
rb_iv_set(dest, IVAR(GEN_ATTR_ASCII), rb_str_new_cstr(insn->ascii));
|
933
|
+
|
934
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_OFFSET), OFFT2NUM(insn->offset));
|
935
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_VMA), OFFT2NUM(insn->vma));
|
936
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_SIZE), UINT2NUM(insn->size));
|
937
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_BYTES),
|
938
|
+
rb_str_new((const char *) insn->bytes, insn->size ));
|
939
|
+
|
940
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_PREFIXES),
|
941
|
+
rb_str_split(rb_str_new_cstr(insn->prefixes), " "));
|
942
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_MNEMONIC),
|
943
|
+
rb_str_new_cstr(insn->mnemonic));
|
944
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_COMMENT),
|
945
|
+
rb_str_new_cstr(insn->comment));
|
946
|
+
|
947
|
+
buf[0] = '\0';
|
948
|
+
opdis_insn_cat_str( insn, buf, 128 );
|
949
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_CATEGORY), rb_str_new_cstr(buf));
|
950
|
+
|
951
|
+
buf[0] = '\0';
|
952
|
+
opdis_insn_isa_str( insn, buf, 128 );
|
953
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_ISA), rb_str_new_cstr(buf));
|
954
|
+
|
955
|
+
buf[0] = '\0';
|
956
|
+
opdis_insn_flags_str( insn, buf, 128, "|" );
|
957
|
+
rb_iv_set(dest, IVAR(INSN_ATTR_FLAGS),
|
958
|
+
rb_str_split(rb_str_new_cstr(buf), "|"));
|
959
|
+
|
960
|
+
rb_ary_clear(ops);
|
961
|
+
for ( i=0; i < insn->num_operands; i++ ) {
|
962
|
+
set_attr_if_alias( dest, IVAR(INSN_ATTR_TGT_IDX), i,
|
963
|
+
insn->operands[i], insn->target );
|
964
|
+
set_attr_if_alias( dest, IVAR(INSN_ATTR_DEST_IDX), i,
|
965
|
+
insn->operands[i], insn->dest );
|
966
|
+
set_attr_if_alias( dest, IVAR(INSN_ATTR_SRC_IDX), i,
|
967
|
+
insn->operands[i], insn->src );
|
968
|
+
|
969
|
+
rb_ary_push( ops, op_from_c(insn->operands[i]) );
|
970
|
+
}
|
971
|
+
}
|
972
|
+
|
973
|
+
static VALUE insn_from_c( const opdis_insn_t * insn ) {
|
974
|
+
VALUE args[1] = {Qnil};
|
975
|
+
VALUE var = rb_class_new_instance(0, args, clsInsn);
|
976
|
+
if ( var != Qnil ) {
|
977
|
+
fill_ruby_insn( insn, var );
|
978
|
+
}
|
979
|
+
return var;
|
980
|
+
}
|
981
|
+
|
982
|
+
static void insn_to_c( VALUE insn, opdis_insn_t * dest ) {
|
983
|
+
int i;
|
984
|
+
VALUE var;
|
985
|
+
struct RArray * ary;
|
986
|
+
|
987
|
+
dest->status = insn_status_code(insn);
|
988
|
+
|
989
|
+
var = rb_iv_get(insn, IVAR(GEN_ATTR_ASCII));
|
990
|
+
opdis_insn_set_ascii(dest, StringValueCStr(var));
|
991
|
+
|
992
|
+
var = rb_iv_get(insn, IVAR(INSN_ATTR_OFFSET));
|
993
|
+
dest->offset = (opdis_off_t) NUM2ULL(var);
|
994
|
+
|
995
|
+
var = rb_iv_get(insn, IVAR(INSN_ATTR_VMA));
|
996
|
+
dest->vma = (opdis_vma_t) NUM2ULL(var);
|
997
|
+
|
998
|
+
var = rb_iv_get(insn, IVAR(INSN_ATTR_SIZE));
|
999
|
+
dest->size = (opdis_off_t) NUM2ULL(var);
|
1000
|
+
|
1001
|
+
var = rb_iv_get(insn, IVAR(INSN_ATTR_BYTES));
|
1002
|
+
if (! dest->bytes ) {
|
1003
|
+
dest->bytes = calloc( 1, dest->size );
|
1004
|
+
}
|
1005
|
+
memcpy( dest->bytes, RSTRING_PTR(var), dest->size );
|
1006
|
+
|
1007
|
+
ary = RARRAY( rb_iv_get(insn, IVAR(INSN_ATTR_PREFIXES)) );
|
1008
|
+
for ( i=0; i < RARRAY_LEN(ary); i++ ) {
|
1009
|
+
VALUE val = RARRAY_PTR(ary)[i];
|
1010
|
+
opdis_insn_add_prefix(dest, StringValueCStr(val));
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
var = rb_iv_get(insn, IVAR(INSN_ATTR_MNEMONIC));
|
1014
|
+
opdis_insn_set_mnemonic(dest, StringValueCStr(var));
|
1015
|
+
|
1016
|
+
var = rb_iv_get(insn, IVAR(INSN_ATTR_COMMENT));
|
1017
|
+
opdis_insn_add_comment(dest, StringValueCStr(var));
|
1018
|
+
|
1019
|
+
dest->category = insn_category_code(insn);
|
1020
|
+
dest->isa = insn_isa_code(insn);
|
1021
|
+
|
1022
|
+
insn_set_flags(dest, insn);
|
1023
|
+
|
1024
|
+
ary = RARRAY( rb_iv_get(insn, IVAR(INSN_ATTR_OPERANDS)) );
|
1025
|
+
for ( i=0; i < RARRAY_LEN(ary); i++ ) {
|
1026
|
+
VALUE val = RARRAY_PTR(ary)[i];
|
1027
|
+
opdis_op_t * op = opdis_insn_next_avail_op(dest);
|
1028
|
+
if (! op ) {
|
1029
|
+
op = opdis_op_alloc();
|
1030
|
+
opdis_insn_add_operand(dest, op);
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
op_to_c( val, op );
|
1034
|
+
|
1035
|
+
if ( i == NUM2INT(rb_iv_get(insn, IVAR(INSN_ATTR_TGT_IDX))) ) {
|
1036
|
+
dest->target = op;
|
1037
|
+
}
|
1038
|
+
if ( i == NUM2INT(rb_iv_get(insn, IVAR(INSN_ATTR_DEST_IDX))) ) {
|
1039
|
+
dest->dest = op;
|
1040
|
+
}
|
1041
|
+
if ( i == NUM2INT(rb_iv_get(insn, IVAR(INSN_ATTR_SRC_IDX))) ) {
|
1042
|
+
dest->src = op;
|
1043
|
+
}
|
1044
|
+
}
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
static VALUE get_aliased_operand( VALUE instance, const char * alias ) {
|
1048
|
+
VALUE idx = rb_iv_get(instance, alias);
|
1049
|
+
VALUE ops = rb_iv_get(instance, IVAR(INSN_ATTR_OPERANDS) );
|
1050
|
+
|
1051
|
+
return (idx == Qnil) ? idx : rb_ary_entry(ops, NUM2LONG(idx));
|
1052
|
+
}
|
1053
|
+
|
1054
|
+
static VALUE cls_insn_tgt( VALUE instance ) {
|
1055
|
+
return get_aliased_operand(instance, IVAR(INSN_ATTR_TGT_IDX) );
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
static VALUE cls_insn_dest( VALUE instance ) {
|
1059
|
+
return get_aliased_operand(instance, IVAR(INSN_ATTR_DEST_IDX) );
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
static VALUE cls_insn_src( VALUE instance ) {
|
1063
|
+
return get_aliased_operand(instance, IVAR(INSN_ATTR_SRC_IDX) );
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
static int is_cflow_insn( VALUE instance ) {
|
1067
|
+
VALUE cat = rb_iv_get(instance, IVAR(INSN_ATTR_CATEGORY) );
|
1068
|
+
return (cat != Qnil && ! strcmp(INSN_CAT_CFLOW, StringValueCStr(cat))) ?
|
1069
|
+
1 : 0;
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
static int insn_has_flag( VALUE instance, const char * flg ) {
|
1073
|
+
VALUE flags = rb_iv_get(instance, IVAR(INSN_ATTR_FLAGS) );
|
1074
|
+
return (flags != Qnil && rb_ary_includes(flags, rb_str_new_cstr(flg))) ?
|
1075
|
+
1 : 0;
|
1076
|
+
}
|
1077
|
+
|
1078
|
+
static VALUE cls_insn_branch( VALUE instance ) {
|
1079
|
+
if ( is_cflow_insn(instance) &&
|
1080
|
+
(insn_has_flag(instance, INSN_FLAG_CALL) ||
|
1081
|
+
insn_has_flag(instance, INSN_FLAG_CALLCC) ||
|
1082
|
+
insn_has_flag(instance, INSN_FLAG_JMPCC) ||
|
1083
|
+
insn_has_flag(instance, INSN_FLAG_JMP)) ) {
|
1084
|
+
return Qtrue;
|
1085
|
+
}
|
1086
|
+
|
1087
|
+
return Qfalse;
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
static VALUE cls_insn_fallthrough( VALUE instance ) {
|
1091
|
+
if ( is_cflow_insn(instance) &&
|
1092
|
+
(insn_has_flag(instance, INSN_FLAG_RET) ||
|
1093
|
+
insn_has_flag(instance, INSN_FLAG_JMP)) ) {
|
1094
|
+
return Qfalse;
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
return Qtrue;
|
1098
|
+
}
|
1099
|
+
|
1100
|
+
static void define_insn_constants() {
|
1101
|
+
rb_define_const(clsInsn, INSN_DECODE_INVALID_NAME,
|
1102
|
+
rb_str_new_cstr(INSN_DECODE_INVALID));
|
1103
|
+
rb_define_const(clsInsn, INSN_DECODE_BASIC_NAME,
|
1104
|
+
rb_str_new_cstr(INSN_DECODE_BASIC));
|
1105
|
+
rb_define_const(clsInsn, INSN_DECODE_MNEM_NAME,
|
1106
|
+
rb_str_new_cstr(INSN_DECODE_MNEM));
|
1107
|
+
rb_define_const(clsInsn, INSN_DECODE_OPS_NAME,
|
1108
|
+
rb_str_new_cstr(INSN_DECODE_OPS));
|
1109
|
+
rb_define_const(clsInsn, INSN_DECODE_MNEMFLG_NAME,
|
1110
|
+
rb_str_new_cstr(INSN_DECODE_MNEMFLG));
|
1111
|
+
rb_define_const(clsInsn, INSN_DECODE_OPFLG_NAME,
|
1112
|
+
rb_str_new_cstr(INSN_DECODE_OPFLG));
|
1113
|
+
|
1114
|
+
rb_define_const(clsInsn, INSN_ISA_GEN_NAME,
|
1115
|
+
rb_str_new_cstr(INSN_ISA_GEN));
|
1116
|
+
rb_define_const(clsInsn, INSN_ISA_FPU_NAME,
|
1117
|
+
rb_str_new_cstr(INSN_ISA_FPU));
|
1118
|
+
rb_define_const(clsInsn, INSN_ISA_GPU_NAME,
|
1119
|
+
rb_str_new_cstr(INSN_ISA_GPU));
|
1120
|
+
rb_define_const(clsInsn, INSN_ISA_SIMD_NAME,
|
1121
|
+
rb_str_new_cstr(INSN_ISA_SIMD));
|
1122
|
+
rb_define_const(clsInsn, INSN_ISA_VM_NAME,
|
1123
|
+
rb_str_new_cstr(INSN_ISA_VM));
|
1124
|
+
|
1125
|
+
rb_define_const(clsInsn, INSN_CAT_CFLOW_NAME,
|
1126
|
+
rb_str_new_cstr(INSN_CAT_CFLOW));
|
1127
|
+
rb_define_const(clsInsn, INSN_CAT_STACK_NAME,
|
1128
|
+
rb_str_new_cstr(INSN_CAT_STACK));
|
1129
|
+
rb_define_const(clsInsn, INSN_CAT_LOST_NAME,
|
1130
|
+
rb_str_new_cstr(INSN_CAT_LOST));
|
1131
|
+
rb_define_const(clsInsn, INSN_CAT_TEST_NAME,
|
1132
|
+
rb_str_new_cstr(INSN_CAT_TEST));
|
1133
|
+
rb_define_const(clsInsn, INSN_CAT_MATH_NAME,
|
1134
|
+
rb_str_new_cstr(INSN_CAT_MATH));
|
1135
|
+
rb_define_const(clsInsn, INSN_CAT_BIT_NAME,
|
1136
|
+
rb_str_new_cstr(INSN_CAT_BIT));
|
1137
|
+
rb_define_const(clsInsn, INSN_CAT_IO_NAME,
|
1138
|
+
rb_str_new_cstr(INSN_CAT_IO));
|
1139
|
+
rb_define_const(clsInsn, INSN_CAT_TRAP_NAME,
|
1140
|
+
rb_str_new_cstr(INSN_CAT_TRAP));
|
1141
|
+
rb_define_const(clsInsn, INSN_CAT_PRIV_NAME,
|
1142
|
+
rb_str_new_cstr(INSN_CAT_PRIV));
|
1143
|
+
rb_define_const(clsInsn, INSN_CAT_NOP_NAME,
|
1144
|
+
rb_str_new_cstr(INSN_CAT_NOP));
|
1145
|
+
|
1146
|
+
rb_define_const(clsInsn, INSN_FLAG_CALL_NAME,
|
1147
|
+
rb_str_new_cstr(INSN_FLAG_CALL));
|
1148
|
+
rb_define_const(clsInsn, INSN_FLAG_CALLCC_NAME,
|
1149
|
+
rb_str_new_cstr(INSN_FLAG_CALLCC));
|
1150
|
+
rb_define_const(clsInsn, INSN_FLAG_JMP_NAME,
|
1151
|
+
rb_str_new_cstr(INSN_FLAG_JMP));
|
1152
|
+
rb_define_const(clsInsn, INSN_FLAG_JMPCC_NAME,
|
1153
|
+
rb_str_new_cstr(INSN_FLAG_JMPCC));
|
1154
|
+
rb_define_const(clsInsn, INSN_FLAG_RET_NAME,
|
1155
|
+
rb_str_new_cstr(INSN_FLAG_RET));
|
1156
|
+
rb_define_const(clsInsn, INSN_FLAG_PUSH_NAME,
|
1157
|
+
rb_str_new_cstr(INSN_FLAG_PUSH));
|
1158
|
+
rb_define_const(clsInsn, INSN_FLAG_POP_NAME,
|
1159
|
+
rb_str_new_cstr(INSN_FLAG_POP));
|
1160
|
+
rb_define_const(clsInsn, INSN_FLAG_FRAME_NAME,
|
1161
|
+
rb_str_new_cstr(INSN_FLAG_FRAME));
|
1162
|
+
rb_define_const(clsInsn, INSN_FLAG_UNFRAME_NAME,
|
1163
|
+
rb_str_new_cstr(INSN_FLAG_UNFRAME));
|
1164
|
+
rb_define_const(clsInsn, INSN_FLAG_AND_NAME,
|
1165
|
+
rb_str_new_cstr(INSN_FLAG_AND));
|
1166
|
+
rb_define_const(clsInsn, INSN_FLAG_OR_NAME,
|
1167
|
+
rb_str_new_cstr(INSN_FLAG_OR));
|
1168
|
+
rb_define_const(clsInsn, INSN_FLAG_XOR_NAME,
|
1169
|
+
rb_str_new_cstr(INSN_FLAG_XOR));
|
1170
|
+
rb_define_const(clsInsn, INSN_FLAG_NOT_NAME,
|
1171
|
+
rb_str_new_cstr(INSN_FLAG_NOT));
|
1172
|
+
rb_define_const(clsInsn, INSN_FLAG_LSL_NAME,
|
1173
|
+
rb_str_new_cstr(INSN_FLAG_LSL));
|
1174
|
+
rb_define_const(clsInsn, INSN_FLAG_LSR_NAME,
|
1175
|
+
rb_str_new_cstr(INSN_FLAG_LSR));
|
1176
|
+
rb_define_const(clsInsn, INSN_FLAG_ASL_NAME,
|
1177
|
+
rb_str_new_cstr(INSN_FLAG_ASL));
|
1178
|
+
rb_define_const(clsInsn, INSN_FLAG_ASR_NAME,
|
1179
|
+
rb_str_new_cstr(INSN_FLAG_ASR));
|
1180
|
+
rb_define_const(clsInsn, INSN_FLAG_ROL_NAME,
|
1181
|
+
rb_str_new_cstr(INSN_FLAG_ROL));
|
1182
|
+
rb_define_const(clsInsn, INSN_FLAG_ROR_NAME,
|
1183
|
+
rb_str_new_cstr(INSN_FLAG_ROR));
|
1184
|
+
rb_define_const(clsInsn, INSN_FLAG_RCL_NAME,
|
1185
|
+
rb_str_new_cstr(INSN_FLAG_RCL));
|
1186
|
+
rb_define_const(clsInsn, INSN_FLAG_RCR_NAME,
|
1187
|
+
rb_str_new_cstr(INSN_FLAG_RCR));
|
1188
|
+
rb_define_const(clsInsn, INSN_FLAG_IN_NAME,
|
1189
|
+
rb_str_new_cstr(INSN_FLAG_IN));
|
1190
|
+
rb_define_const(clsInsn, INSN_FLAG_OUT_NAME,
|
1191
|
+
rb_str_new_cstr(INSN_FLAG_OUT));
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
static void define_insn_attributes() {
|
1195
|
+
|
1196
|
+
/* read-write attributes */
|
1197
|
+
rb_define_attr(clsInsn, INSN_ATTR_STATUS, 1, 1);
|
1198
|
+
rb_define_attr(clsInsn, INSN_ATTR_PREFIXES, 1, 1);
|
1199
|
+
rb_define_attr(clsInsn, INSN_ATTR_MNEMONIC, 1, 1);
|
1200
|
+
rb_define_attr(clsInsn, INSN_ATTR_CATEGORY, 1, 1);
|
1201
|
+
rb_define_attr(clsInsn, INSN_ATTR_ISA, 1, 1);
|
1202
|
+
rb_define_attr(clsInsn, INSN_ATTR_FLAGS, 1, 1);
|
1203
|
+
rb_define_attr(clsInsn, INSN_ATTR_COMMENT, 1, 1);
|
1204
|
+
rb_define_attr(clsInsn, INSN_ATTR_OPERANDS, 1, 1);
|
1205
|
+
|
1206
|
+
/* private attributes */
|
1207
|
+
rb_define_attr(clsInsn, GEN_ATTR_ASCII, 1, 1);
|
1208
|
+
rb_define_attr(clsInsn, INSN_ATTR_TGT_IDX, 1, 1);
|
1209
|
+
rb_define_attr(clsInsn, INSN_ATTR_DEST_IDX, 1, 1);
|
1210
|
+
rb_define_attr(clsInsn, INSN_ATTR_SRC_IDX, 1, 1);
|
1211
|
+
|
1212
|
+
/* read-only attributes */
|
1213
|
+
rb_define_attr(clsInsn, INSN_ATTR_OFFSET, 1, 0);
|
1214
|
+
rb_define_attr(clsInsn, INSN_ATTR_VMA, 1, 0);
|
1215
|
+
rb_define_attr(clsInsn, INSN_ATTR_SIZE, 1, 0);
|
1216
|
+
rb_define_attr(clsInsn, INSN_ATTR_BYTES, 1, 0);
|
1217
|
+
|
1218
|
+
/* getters */
|
1219
|
+
rb_define_method(clsInsn, INSN_ATTR_TGT, cls_insn_tgt, 0);
|
1220
|
+
rb_define_method(clsInsn, INSN_ATTR_DEST, cls_insn_dest, 0);
|
1221
|
+
rb_define_method(clsInsn, INSN_ATTR_SRC, cls_insn_src, 0);
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
static void init_insn_class( VALUE modOpdis ) {
|
1225
|
+
clsInsn = rb_define_class_under(modOpdis, "Instruction", rb_cObject);
|
1226
|
+
rb_define_method(clsInsn, "initialize", cls_insn_init, 0);
|
1227
|
+
rb_define_method(clsInsn, "to_s", cls_generic_to_s, 0);
|
1228
|
+
rb_define_method(clsInsn, "branch?", cls_insn_branch, 0);
|
1229
|
+
rb_define_method(clsInsn, "fallthrough?", cls_insn_fallthrough, 0);
|
1230
|
+
|
1231
|
+
define_insn_attributes();
|
1232
|
+
define_insn_constants();
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
/* ---------------------------------------------------------------------- */
|
1236
|
+
/* Public API */
|
1237
|
+
|
1238
|
+
void Opdis_initModel( VALUE modOpdis ) {
|
1239
|
+
symToSym = rb_intern("to_sym");
|
1240
|
+
symToS = rb_intern("to_s");
|
1241
|
+
|
1242
|
+
init_insn_class(modOpdis);
|
1243
|
+
init_op_class(modOpdis);
|
1244
|
+
init_imm_class(modOpdis);
|
1245
|
+
init_absaddr_class(modOpdis);
|
1246
|
+
init_addrexpr_class(modOpdis);
|
1247
|
+
init_reg_class(modOpdis);
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
VALUE Opdis_insnFromC( const opdis_insn_t * insn ) {
|
1251
|
+
VALUE var = Qnil;
|
1252
|
+
if ( insn ) {
|
1253
|
+
var = insn_from_c(insn);
|
1254
|
+
}
|
1255
|
+
return var;
|
1256
|
+
}
|
1257
|
+
|
1258
|
+
int Opdis_insnFillFromC( const opdis_insn_t * insn, VALUE dest ) {
|
1259
|
+
if (insn == NULL || dest == Qnil) {
|
1260
|
+
return 0;
|
1261
|
+
}
|
1262
|
+
|
1263
|
+
fill_ruby_insn(insn, dest);
|
1264
|
+
return 1;
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
int Opdis_insnToC( VALUE insn, opdis_insn_t * c_insn ) {
|
1268
|
+
if (insn == Qnil || c_insn == NULL) {
|
1269
|
+
return 0;
|
1270
|
+
}
|
1271
|
+
|
1272
|
+
insn_to_c( insn, c_insn );
|
1273
|
+
|
1274
|
+
return 1;
|
1275
|
+
}
|