OSDN Git Service

am 73a09433: Merge "Minor code cleanup to address warnings found by Clang."
[android-x86/dalvik.git] / vm / compiler / codegen / x86 / libenc / enc_wrapper.cpp
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <assert.h>
19 #include <limits.h>
20 #include "enc_base.h"
21 #include "enc_wrapper.h"
22 #include "dec_base.h"
23 #include <cutils/log.h>
24
25 //#define PRINT_ENCODER_STREAM
26 bool dump_x86_inst = false;
27 //map_reg
28 const RegName map_of_regno_2_regname[] = {
29     RegName_EAX,    RegName_EBX,    RegName_ECX,    RegName_EDX,
30     RegName_EDI,    RegName_ESI,    RegName_ESP,    RegName_EBP,
31     RegName_XMM0,   RegName_XMM1,   RegName_XMM2,   RegName_XMM3,
32     RegName_XMM4,   RegName_XMM5,   RegName_XMM6,   RegName_XMM7,
33     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
34     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
35     RegName_Null,
36     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
37     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
38     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
39     RegName_Null,   RegName_Null,   //SCRATCH
40     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null
41 };
42
43 //getRegSize, getAliasReg:
44 //OpndSize, RegName, OpndExt: enum enc_defs.h
45 inline void add_r(EncoderBase::Operands & args, int physicalReg, OpndSize sz, OpndExt ext = OpndExt_None) {
46     RegName reg = map_of_regno_2_regname[physicalReg];
47     if (sz != getRegSize(reg)) {
48        reg = getAliasReg(reg, sz);
49     }
50     args.add(EncoderBase::Operand(reg, ext));
51 }
52 inline void add_m(EncoderBase::Operands & args, int baseReg, int disp, OpndSize sz, OpndExt ext = OpndExt_None) {
53     args.add(EncoderBase::Operand(sz,
54                                   map_of_regno_2_regname[baseReg],
55                                   RegName_Null, 0,
56                                   disp, ext));
57 }
58 inline void add_m_scale(EncoderBase::Operands & args, int baseReg, int indexReg, int scale,
59                         OpndSize sz, OpndExt ext = OpndExt_None) {
60     args.add(EncoderBase::Operand(sz,
61                                   map_of_regno_2_regname[baseReg],
62                                   map_of_regno_2_regname[indexReg], scale,
63                                   0, ext));
64 }
65 inline void add_m_disp_scale(EncoderBase::Operands & args, int baseReg, int disp, int indexReg, int scale,
66                         OpndSize sz, OpndExt ext = OpndExt_None) {
67     args.add(EncoderBase::Operand(sz,
68                                   map_of_regno_2_regname[baseReg],
69                                   map_of_regno_2_regname[indexReg], scale,
70                                   disp, ext));
71 }
72
73 inline void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
74     return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
75 }
76 inline void add_imm(EncoderBase::Operands & args, OpndSize sz, int value, bool is_signed) {
77     //assert(n_size != imm.get_size());
78     args.add(EncoderBase::Operand(sz, value,
79              is_signed ? OpndExt_Signed : OpndExt_Zero));
80 }
81
82 #define MAX_DECODED_STRING_LEN 1024
83 char tmpBuffer[MAX_DECODED_STRING_LEN];
84
85 void printOperand(const EncoderBase::Operand & opnd) {
86     unsigned int sz;
87     if(!dump_x86_inst) return;
88     sz = strlen(tmpBuffer);
89     if(opnd.size() != OpndSize_32) {
90         sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s ",
91                        getOpndSizeString(opnd.size()));
92     }
93     if(opnd.is_mem()) {
94         if(opnd.scale() != 0) {
95             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz,
96                            "%d(%s,%s,%d)", opnd.disp(),
97                            getRegNameString(opnd.base()),
98                            getRegNameString(opnd.index()), opnd.scale());
99         } else {
100             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%d(%s)",
101                            opnd.disp(), getRegNameString(opnd.base()));
102         }
103     }
104     if(opnd.is_imm()) {
105         sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "#%x",
106                        (int)opnd.imm());
107     }
108     if(opnd.is_reg()) {
109         sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s",
110                        getRegNameString(opnd.reg()));
111     }
112 }
113 //TODO: the order of operands
114 //to make the printout have the same order as assembly in .S
115 //I reverse the order here
116 void printDecoderInst(Inst & decInst) {
117     unsigned int sz;
118     if(!dump_x86_inst) return;
119     sz = strlen(tmpBuffer);
120     sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s ",
121                    EncoderBase::toStr(decInst.mn));
122     for(unsigned int k = 0; k < decInst.argc; k++) {
123         if(k > 0) {
124             sz = strlen(tmpBuffer);
125             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
126         }
127         printOperand(decInst.operands[decInst.argc-1-k]);
128     }
129     ALOGE("%s", tmpBuffer);
130 }
131 void printOperands(EncoderBase::Operands& opnds) {
132     unsigned int sz;
133     if(!dump_x86_inst) return;
134     for(unsigned int k = 0; k < opnds.count(); k++) {
135         if(k > 0) {
136             sz = strlen(tmpBuffer);
137             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
138         }
139         printOperand(opnds[opnds.count()-1-k]);
140     }
141 }
142 void printEncoderInst(Mnemonic m, EncoderBase::Operands& opnds) {
143     if(!dump_x86_inst) return;
144     snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- ENC %s ",
145              EncoderBase::toStr(m));
146     printOperands(opnds);
147     ALOGE("%s", tmpBuffer);
148 }
149 int decodeThenPrint(char* stream_start) {
150     if(!dump_x86_inst) return 0;
151     snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- INST @ %p: ",
152              stream_start);
153     Inst decInst;
154     unsigned numBytes = DecoderBase::decode(stream_start, &decInst);
155     printDecoderInst(decInst);
156     return numBytes;
157 }
158
159 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm(Mnemonic m, OpndSize size, int imm, char * stream) {
160     EncoderBase::Operands args;
161     //assert(imm.get_size() == size_32);
162     add_imm(args, size, imm, true/*is_signed*/);
163     char* stream_start = stream;
164     stream = (char *)EncoderBase::encode(stream, m, args);
165 #ifdef PRINT_ENCODER_STREAM
166     printEncoderInst(m, args);
167     decodeThenPrint(stream_start);
168 #endif
169     return stream;
170 }
171 extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_inst_size(char * stream) {
172     Inst decInst;
173     unsigned numBytes = DecoderBase::decode(stream, &decInst);
174     return numBytes;
175 }
176
177 extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_cur_operand_offset(int opnd_id)
178 {
179     return (unsigned)EncoderBase::getOpndLocation(opnd_id);
180 }
181
182 extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm(int imm, char * stream) {
183     Inst decInst;
184     unsigned numBytes = DecoderBase::decode(stream, &decInst);
185     EncoderBase::Operands args;
186     //assert(imm.get_size() == size_32);
187     add_imm(args, decInst.operands[0].size(), imm, true/*is_signed*/);
188     char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
189 #ifdef PRINT_ENCODER_STREAM
190     printEncoderInst(decInst.mn, args);
191     decodeThenPrint(stream);
192 #endif
193     return stream_next;
194 }
195 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem(Mnemonic m, OpndSize size,
196                int disp, int base_reg, bool isBasePhysical, char * stream) {
197     EncoderBase::Operands args;
198     add_m(args, base_reg, disp, size);
199     char* stream_start = stream;
200     stream = (char *)EncoderBase::encode(stream, m, args);
201 #ifdef PRINT_ENCODER_STREAM
202     printEncoderInst(m, args);
203     decodeThenPrint(stream_start);
204 #endif
205     return stream;
206 }
207 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg(Mnemonic m, OpndSize size,
208                int reg, bool isPhysical, LowOpndRegType type, char * stream) {
209     EncoderBase::Operands args;
210     if(m == Mnemonic_IDIV || m == Mnemonic_MUL || m == Mnemonic_IMUL) {
211       add_r(args, 0/*eax*/, size);
212       add_r(args, 3/*edx*/, size);
213     }
214     add_r(args, reg, size);
215     char* stream_start = stream;
216     stream = (char *)EncoderBase::encode(stream, m, args);
217 #ifdef PRINT_ENCODER_STREAM
218     printEncoderInst(m, args);
219     decodeThenPrint(stream_start);
220 #endif
221     return stream;
222 }
223 //both operands have same size
224 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_reg(Mnemonic m, OpndSize size,
225                    int reg, bool isPhysical,
226                    int reg2, bool isPhysical2, LowOpndRegType type, char * stream) {
227     if((m == Mnemonic_MOV || m == Mnemonic_MOVQ) && reg == reg2) return stream;
228     EncoderBase::Operands args;
229     add_r(args, reg2, size); //destination
230     if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL || m == Mnemonic_SAR)
231       add_r(args, reg, OpndSize_8);
232     else
233       add_r(args, reg, size);
234     char* stream_start = stream;
235     stream = (char *)EncoderBase::encode(stream, m, args);
236 #ifdef PRINT_ENCODER_STREAM
237     printEncoderInst(m, args);
238     decodeThenPrint(stream_start);
239 #endif
240     return stream;
241 }
242 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_reg(Mnemonic m, OpndSize size,
243                    int disp, int base_reg, bool isBasePhysical,
244                    int reg, bool isPhysical, LowOpndRegType type, char * stream) {
245     EncoderBase::Operands args;
246     add_r(args, reg, size);
247     add_m(args, base_reg, disp, size);
248     char* stream_start = stream;
249     stream = (char *)EncoderBase::encode(stream, m, args);
250 #ifdef PRINT_ENCODER_STREAM
251     printEncoderInst(m, args);
252     decodeThenPrint(stream_start);
253 #endif
254     return stream;
255 }
256 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_scale_reg(Mnemonic m, OpndSize size,
257                          int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
258                          int reg, bool isPhysical, LowOpndRegType type, char * stream) {
259     EncoderBase::Operands args;
260     add_r(args, reg, size);
261     add_m_scale(args, base_reg, index_reg, scale, size);
262     char* stream_start = stream;
263     stream = (char *)EncoderBase::encode(stream, m, args);
264 #ifdef PRINT_ENCODER_STREAM
265     printEncoderInst(m, args);
266     decodeThenPrint(stream_start);
267 #endif
268     return stream;
269 }
270 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_mem_scale(Mnemonic m, OpndSize size,
271                          int reg, bool isPhysical,
272                          int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
273                          LowOpndRegType type, char * stream) {
274     EncoderBase::Operands args;
275     add_m_scale(args, base_reg, index_reg, scale, size);
276     add_r(args, reg, size);
277     char* stream_start = stream;
278     stream = (char *)EncoderBase::encode(stream, m, args);
279 #ifdef PRINT_ENCODER_STREAM
280     printEncoderInst(m, args);
281     decodeThenPrint(stream_start);
282 #endif
283     return stream;
284 }
285 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_disp_scale_reg(Mnemonic m, OpndSize size,
286                          int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
287                          int reg, bool isPhysical, LowOpndRegType type, char * stream) {
288     EncoderBase::Operands args;
289     add_r(args, reg, size);
290     add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
291     char* stream_start = stream;
292     stream = (char *)EncoderBase::encode(stream, m, args);
293 #ifdef PRINT_ENCODER_STREAM
294     printEncoderInst(m, args);
295     decodeThenPrint(stream_start);
296 #endif
297     return stream;
298 }
299 extern "C" ENCODER_DECLARE_EXPORT char * encoder_movzs_mem_disp_scale_reg(Mnemonic m, OpndSize size,
300                          int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
301                          int reg, bool isPhysical, LowOpndRegType type, char * stream) {
302     EncoderBase::Operands args;
303     add_r(args, reg, OpndSize_32);
304     add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
305     char* stream_start = stream;
306     stream = (char *)EncoderBase::encode(stream, m, args);
307 #ifdef PRINT_ENCODER_STREAM
308     printEncoderInst(m, args);
309     decodeThenPrint(stream_start);
310 #endif
311     return stream;
312 }
313
314 extern "C" ENCODER_DECLARE_EXPORT char* encoder_reg_mem_disp_scale(Mnemonic m, OpndSize size,
315                          int reg, bool isPhysical,
316                          int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
317                          LowOpndRegType type, char* stream) {
318     EncoderBase::Operands args;
319     add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
320     add_r(args, reg, size);
321     char* stream_start = stream;
322     stream = (char *)EncoderBase::encode(stream, m, args);
323 #ifdef PRINT_ENCODER_STREAM
324     printEncoderInst(m, args);
325     decodeThenPrint(stream_start);
326 #endif
327     return stream;
328 }
329
330 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_mem(Mnemonic m, OpndSize size,
331                    int reg, bool isPhysical,
332                    int disp, int base_reg, bool isBasePhysical, LowOpndRegType type, char * stream) {
333     EncoderBase::Operands args;
334     add_m(args, base_reg, disp, size);
335     add_r(args, reg, size);
336     char* stream_start = stream;
337     stream = (char *)EncoderBase::encode(stream, m, args);
338 #ifdef PRINT_ENCODER_STREAM
339     printEncoderInst(m, args);
340     decodeThenPrint(stream_start);
341 #endif
342     return stream;
343 }
344 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_reg(Mnemonic m, OpndSize size,
345                    int imm, int reg, bool isPhysical, LowOpndRegType type, char * stream) {
346     EncoderBase::Operands args;
347     add_r(args, reg, size); //dst
348     if(m == Mnemonic_IMUL) add_r(args, reg, size); //src CHECK
349     if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
350        || m == Mnemonic_SAR || m == Mnemonic_ROR)  //fix for shift opcodes
351       add_imm(args, OpndSize_8, imm, true/*is_signed*/);
352     else
353       add_imm(args, size, imm, true/*is_signed*/);
354     char* stream_start = stream;
355     stream = (char *)EncoderBase::encode(stream, m, args);
356 #ifdef PRINT_ENCODER_STREAM
357     printEncoderInst(m, args);
358     decodeThenPrint(stream_start);
359 #endif
360     return stream;
361 }
362 extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm_rm(int imm, char * stream) {
363     Inst decInst;
364     unsigned numBytes = DecoderBase::decode(stream, &decInst);
365     EncoderBase::Operands args;
366     args.add(decInst.operands[0]);
367     add_imm(args, decInst.operands[1].size(), imm, true/*is_signed*/);
368     char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
369 #ifdef PRINT_ENCODER_STREAM
370     printEncoderInst(decInst.mn, args);
371     decodeThenPrint(stream);
372 #endif
373     return stream_next;
374 }
375 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_mem(Mnemonic m, OpndSize size,
376                    int imm,
377                    int disp, int base_reg, bool isBasePhysical, char * stream) {
378     EncoderBase::Operands args;
379     add_m(args, base_reg, disp, size);
380     if (m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
381         || m == Mnemonic_SAR || m == Mnemonic_ROR)
382         size = OpndSize_8;
383     add_imm(args, size, imm, true);
384     char* stream_start = stream;
385     stream = (char *)EncoderBase::encode(stream, m, args);
386 #ifdef PRINT_ENCODER_STREAM
387     printEncoderInst(m, args);
388     decodeThenPrint(stream_start);
389 #endif
390     return stream;
391 }
392 extern "C" ENCODER_DECLARE_EXPORT char * encoder_fp_mem(Mnemonic m, OpndSize size, int reg,
393                   int disp, int base_reg, bool isBasePhysical, char * stream) {
394     EncoderBase::Operands args;
395     add_m(args, base_reg, disp, size);
396     // a fake FP register as operand
397     add_fp(args, reg, size == OpndSize_64/*is_double*/);
398     char* stream_start = stream;
399     stream = (char *)EncoderBase::encode(stream, m, args);
400 #ifdef PRINT_ENCODER_STREAM
401     printEncoderInst(m, args);
402     decodeThenPrint(stream_start);
403 #endif
404     return stream;
405 }
406 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_fp(Mnemonic m, OpndSize size,
407                   int disp, int base_reg, bool isBasePhysical,
408                   int reg, char * stream) {
409     EncoderBase::Operands args;
410     // a fake FP register as operand
411     add_fp(args, reg, size == OpndSize_64/*is_double*/);
412     add_m(args, base_reg, disp, size);
413     char* stream_start = stream;
414     stream = (char *)EncoderBase::encode(stream, m, args);
415 #ifdef PRINT_ENCODER_STREAM
416     printEncoderInst(m, args);
417     decodeThenPrint(stream_start);
418 #endif
419     return stream;
420 }
421
422 extern "C" ENCODER_DECLARE_EXPORT char * encoder_return(char * stream) {
423     EncoderBase::Operands args;
424     char* stream_start = stream;
425     stream = (char *)EncoderBase::encode(stream, Mnemonic_RET, args);
426 #ifdef PRINT_ENCODER_STREAM
427     printEncoderInst(Mnemonic_RET, args);
428     decodeThenPrint(stream_start);
429 #endif
430     return stream;
431 }
432 extern "C" ENCODER_DECLARE_EXPORT char * encoder_compare_fp_stack(bool pop, int reg, bool isDouble, char * stream) {
433     //Mnemonic m = pop ? Mnemonic_FUCOMP : Mnemonic_FUCOM;
434     Mnemonic m = pop ? Mnemonic_FUCOMIP : Mnemonic_FUCOMI;
435     //a single operand or 2 operands?
436     //FST ST(i) has a single operand in encoder.inl?
437     EncoderBase::Operands args;
438     add_fp(args, reg, isDouble);
439     char* stream_start = stream;
440     stream = (char *)EncoderBase::encode(stream, m, args);
441 #ifdef PRINT_ENCODER_STREAM
442     printEncoderInst(m, args);
443     decodeThenPrint(stream_start);
444 #endif
445     return stream;
446 }
447 extern "C" ENCODER_DECLARE_EXPORT char * encoder_movez_mem_to_reg(OpndSize size,
448                       int disp, int base_reg, bool isBasePhysical,
449                       int reg, bool isPhysical, char * stream) {
450     EncoderBase::Operands args;
451     add_r(args, reg, OpndSize_32);
452     add_m(args, base_reg, disp, size);
453     char* stream_start = stream;
454     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
455 #ifdef PRINT_ENCODER_STREAM
456     printEncoderInst(Mnemonic_MOVZX, args);
457     decodeThenPrint(stream_start);
458 #endif
459     return stream;
460 }
461 extern "C" ENCODER_DECLARE_EXPORT char * encoder_moves_mem_to_reg(OpndSize size,
462                       int disp, int base_reg, bool isBasePhysical,
463                       int reg, bool isPhysical, char * stream) {
464     EncoderBase::Operands args;
465     add_r(args, reg, OpndSize_32);
466     add_m(args, base_reg, disp, size);
467     char* stream_start = stream;
468     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
469 #ifdef PRINT_ENCODER_STREAM
470     printEncoderInst(Mnemonic_MOVSX, args);
471     decodeThenPrint(stream_start);
472 #endif
473     return stream;
474 }
475 extern "C" ENCODER_DECLARE_EXPORT char * encoder_movez_reg_to_reg(OpndSize size,
476                       int reg, bool isPhysical, int reg2,
477                       bool isPhysical2, LowOpndRegType type, char * stream) {
478     EncoderBase::Operands args;
479     add_r(args, reg2, OpndSize_32); //destination
480     add_r(args, reg, size);
481     char* stream_start = stream;
482     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
483 #ifdef PRINT_ENCODER_STREAM
484     printEncoderInst(Mnemonic_MOVZX, args);
485     decodeThenPrint(stream_start);
486 #endif
487     return stream;
488 }
489 extern "C" ENCODER_DECLARE_EXPORT char * encoder_moves_reg_to_reg(OpndSize size,
490                       int reg, bool isPhysical,int reg2,
491                       bool isPhysical2, LowOpndRegType type, char * stream) {
492     EncoderBase::Operands args;
493     add_r(args, reg2, OpndSize_32); //destination
494     add_r(args, reg, size);
495     char* stream_start = stream;
496     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
497 #ifdef PRINT_ENCODER_STREAM
498     printEncoderInst(Mnemonic_MOVSX, args);
499     decodeThenPrint(stream_start);
500 #endif
501     return stream;
502 }
503
504 // Disassemble the operand "opnd" and put the readable format in "strbuf"
505 // up to a string length of "len".
506 unsigned int DisassembleOperandToBuf(const EncoderBase::Operand& opnd, char* strbuf, unsigned int len)
507 {
508     unsigned int sz = 0;
509     if(opnd.size() != OpndSize_32) {
510         sz += snprintf(&strbuf[sz], len-sz, "%s ",
511                        getOpndSizeString(opnd.size()));
512     }
513     if(opnd.is_mem()) {
514         if(opnd.scale() != 0) {
515             sz += snprintf(&strbuf[sz], len-sz, "%d(%s,%s,%d)", opnd.disp(),
516                            getRegNameString(opnd.base()),
517                            getRegNameString(opnd.index()), opnd.scale());
518         } else {
519             sz += snprintf(&strbuf[sz], len-sz, "%d(%s)",
520                            opnd.disp(), getRegNameString(opnd.base()));
521         }
522     } else if(opnd.is_imm()) {
523         sz += snprintf(&strbuf[sz], len-sz, "#%x", (int)opnd.imm());
524     } else if(opnd.is_reg()) {
525         sz += snprintf(&strbuf[sz], len-sz, "%s",
526                        getRegNameString(opnd.reg()));
527     }
528     return sz;
529 }
530
531 // Disassemble the instruction "decInst" and put the readable format
532 // in "strbuf" up to a string length of "len".
533 void DisassembleInstToBuf(Inst& decInst, char* strbuf, unsigned int len)
534 {
535     unsigned int sz = 0;
536     int k;
537     sz += snprintf(&strbuf[sz], len-sz, "%s ", EncoderBase::toStr(decInst.mn));
538     if (decInst.argc > 0) {
539         sz += DisassembleOperandToBuf(decInst.operands[decInst.argc-1],
540                                  &strbuf[sz], len-sz);
541         for(k = decInst.argc-2; k >= 0; k--) {
542             sz += snprintf(&strbuf[sz], len-sz, ", ");
543             sz += DisassembleOperandToBuf(decInst.operands[k], &strbuf[sz], len-sz);
544         }
545     }
546 }
547
548 // Disassmble the x86 instruction pointed to by code pointer "stream."
549 // Put the disassemble text in the "strbuf" up to string length "len".
550 // Return the code pointer after the disassemble x86 instruction.
551 extern "C" ENCODER_DECLARE_EXPORT
552 char* decoder_disassemble_instr(char* stream, char* strbuf, unsigned int len)
553 {
554     Inst decInst;
555     unsigned numBytes = DecoderBase::decode(stream, &decInst);
556     DisassembleInstToBuf(decInst, strbuf, len);
557     return (stream + numBytes);
558 }