File: instr.h

package info (click to toggle)
bochs 2.7%2Bdfsg-4%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 21,940 kB
  • sloc: cpp: 250,055; ansic: 17,183; sh: 8,428; makefile: 4,786; yacc: 1,311; asm: 395; perl: 359; lex: 307; csh: 3
file content (420 lines) | stat: -rw-r--r-- 12,038 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
/////////////////////////////////////////////////////////////////////////
// $Id: instr.h 14086 2021-01-30 08:35:35Z sshwarts $
/////////////////////////////////////////////////////////////////////////
//
//   Copyright (c) 2016-2017 Stanislav Shwartsman
//          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////

#ifndef BX_INSTR_H
#define BX_INSTR_H

extern bx_address bx_asize_mask[];

const char *get_bx_opcode_name(Bit16u ia_opcode);
const char *get_intel_disasm_opcode_name(Bit16u ia_opcode);
const char *get_gas_disasm_opcode_name(Bit16u ia_opcode);

class BX_CPU_C;
class bxInstruction_c;

#ifndef BX_STANDALONE_DECODER

// <TAG-TYPE-EXECUTEPTR-START>
#if BX_USE_CPU_SMF
typedef void (BX_CPP_AttrRegparmN(1) *BxExecutePtr_tR)(bxInstruction_c *);
#else
typedef void (BX_CPU_C::*BxExecutePtr_tR)(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
#endif
// <TAG-TYPE-EXECUTEPTR-END>

#endif

// <TAG-CLASS-INSTRUCTION-START>
class bxInstruction_c {
public:

#ifndef BX_STANDALONE_DECODER
  // Function pointers; a function to resolve the modRM address
  // given the current state of the CPU and the instruction data,
  // and a function to execute the instruction after resolving
  // the memory address (if any).
  BxExecutePtr_tR execute1;

  union {
    BxExecutePtr_tR execute2;
    bxInstruction_c *next;
  } handlers;
#endif

  struct {
    // 15...0 opcode
    Bit16u ia_opcode;

    //  7...4 (unused)
    //  3...0 ilen (0..15)
    Bit8u ilen;

#define BX_LOCK_PREFIX_USED 1
    //  7...6 lockUsed, repUsed (0=none, 1=0xF0, 2=0xF2, 3=0xF3)
    //  5...5 extend8bit
    //  4...4 mod==c0 (modrm)
    //  3...3 os64
    //  2...2 os32
    //  1...1 as64
    //  0...0 as32
    Bit8u metaInfo1;
  } metaInfo;

  enum {
    BX_INSTR_METADATA_DST   = 0,
    BX_INSTR_METADATA_SRC1  = 1,
    BX_INSTR_METADATA_SRC2  = 2,
    BX_INSTR_METADATA_SRC3  = 3,
    BX_INSTR_METADATA_CET_SEGOVERRIDE = 3, // share src3
    BX_INSTR_METADATA_SEG   = 4,
    BX_INSTR_METADATA_BASE  = 5,
    BX_INSTR_METADATA_INDEX = 6,
    BX_INSTR_METADATA_SCALE = 7
  };

  // using 5-bit field for registers (16 regs in 64-bit, RIP, NIL)
  Bit8u metaData[8];

  union {
    // Form (longest case): [opcode+modrm+sib/displacement32/immediate32]
    struct {
      union {
        Bit32u Id;
        Bit16u Iw[2];
        // use Ib[3] as EVEX mask register
        // use Ib[2] as AVX attributes
        //     7..5 (unused)
        //     4..4 VEX.W
        //     3..3 Broadcast/RC/SAE control (EVEX.b)
        //     2..2 Zeroing/Merging mask (EVEX.z)
        //     1..0 Round control
        // use Ib[1] as AVX VL
        Bit8u  Ib[4];
      };
      union {
        Bit16u displ16u; // for 16-bit modrm forms
        Bit32u displ32u; // for 32-bit modrm forms

        Bit32u Id2;
        Bit16u Iw2[2];
        Bit8u  Ib2[4];
      };
    } modRMForm;

#if BX_SUPPORT_X86_64
    struct {
      Bit64u   Iq;  // for MOV Rx,imm64
    } IqForm;
#endif
  };

#ifdef BX_INSTR_STORE_OPCODE_BYTES
  Bit8u opcode_bytes[16];

  BX_CPP_INLINE const Bit8u* get_opcode_bytes(void) const {
    return opcode_bytes;
  }

  BX_CPP_INLINE void set_opcode_bytes(const Bit8u *opcode) {
    memcpy(opcode_bytes, opcode, ilen());
  }
#endif

#ifndef BX_STANDALONE_DECODER
  BX_CPP_INLINE BxExecutePtr_tR execute2(void) const {
    return handlers.execute2;
  }
#endif

  BX_CPP_INLINE unsigned seg(void) const {
    return metaData[BX_INSTR_METADATA_SEG];
  }
  BX_CPP_INLINE void setSeg(unsigned val) {
    metaData[BX_INSTR_METADATA_SEG] = val;
  }

#if BX_SUPPORT_CET
  BX_CPP_INLINE unsigned segOverrideCet(void) const {
    return metaData[BX_INSTR_METADATA_CET_SEGOVERRIDE];
  }
  BX_CPP_INLINE void setCetSegOverride(unsigned val) {
    metaData[BX_INSTR_METADATA_CET_SEGOVERRIDE] = val;
  }
#endif

  BX_CPP_INLINE void setFoo(unsigned foo) {
    // none of x87 instructions has immediate
    modRMForm.Iw[0] = foo;
  }
  BX_CPP_INLINE unsigned foo() const {
    return modRMForm.Iw[0];
  }
  BX_CPP_INLINE unsigned b1() const {
    return modRMForm.Iw[0] >> 8;
  }

  BX_CPP_INLINE void setSibScale(unsigned scale) {
    metaData[BX_INSTR_METADATA_SCALE] = scale;
  }
  BX_CPP_INLINE unsigned sibScale() const {
    return metaData[BX_INSTR_METADATA_SCALE];
  }
  BX_CPP_INLINE void setSibIndex(unsigned index) {
    metaData[BX_INSTR_METADATA_INDEX] = index;
  }
  BX_CPP_INLINE unsigned sibIndex() const {
    return metaData[BX_INSTR_METADATA_INDEX];
  }
  BX_CPP_INLINE void setSibBase(unsigned base) {
    metaData[BX_INSTR_METADATA_BASE] = base;
  }
  BX_CPP_INLINE unsigned sibBase() const {
    return metaData[BX_INSTR_METADATA_BASE];
  }
  BX_CPP_INLINE Bit32s displ32s() const { return (Bit32s) modRMForm.displ32u; }
  BX_CPP_INLINE Bit16s displ16s() const { return (Bit16s) modRMForm.displ16u; }
  BX_CPP_INLINE Bit32u Id() const  { return modRMForm.Id; }
  BX_CPP_INLINE Bit16u Iw() const  { return modRMForm.Iw[0]; }
  BX_CPP_INLINE Bit8u  Ib() const  { return modRMForm.Ib[0]; }
  BX_CPP_INLINE Bit16u Id2() const { return modRMForm.Id2; }
  BX_CPP_INLINE Bit16u Iw2() const { return modRMForm.Iw2[0]; }
  BX_CPP_INLINE Bit8u  Ib2() const { return modRMForm.Ib2[0]; }
#if BX_SUPPORT_X86_64
  BX_CPP_INLINE Bit64u Iq() const  { return IqForm.Iq; }
#endif

  // Info in the metaInfo field.
  // Note: the 'L' at the end of certain flags, means the value returned
  // is for Logical comparisons, eg if (i->os32L() && i->as32L()).  If you
  // want a bool value, use os32B() etc.  This makes for smaller
  // code, when a strict 0 or 1 is not necessary.
  BX_CPP_INLINE void init(unsigned os32, unsigned as32, unsigned os64, unsigned as64)
  {
    metaInfo.metaInfo1 = (os32<<2) | (os64<<3) | (as32<<0) | (as64<<1);
  }

  BX_CPP_INLINE unsigned os32L(void) const {
    return metaInfo.metaInfo1 & (1<<2);
  }
  BX_CPP_INLINE void setOs32B(unsigned bit) {
    metaInfo.metaInfo1 = (metaInfo.metaInfo1 & ~(1<<2)) | (bit<<2);
  }
  BX_CPP_INLINE void assertOs32(void) {
    metaInfo.metaInfo1 |= (1<<2);
  }

#if BX_SUPPORT_X86_64
  BX_CPP_INLINE unsigned os64L(void) const {
    return metaInfo.metaInfo1 & (1<<3);
  }
  BX_CPP_INLINE void assertOs64(void) {
    metaInfo.metaInfo1 |= (1<<3);
  }
#else
  BX_CPP_INLINE unsigned os64L(void) const { return 0; }
#endif
  BX_CPP_INLINE unsigned osize(void) const {
    return (metaInfo.metaInfo1 >> 2) & 0x3;
  }

  BX_CPP_INLINE unsigned as32L(void) const {
    return metaInfo.metaInfo1 & 0x1;
  }
  BX_CPP_INLINE void setAs32B(unsigned bit) {
    metaInfo.metaInfo1 = (metaInfo.metaInfo1 & ~0x1) | (bit);
  }

#if BX_SUPPORT_X86_64
  BX_CPP_INLINE unsigned as64L(void) const {
    return metaInfo.metaInfo1 & (1<<1);
  }
  BX_CPP_INLINE void clearAs64(void) {
    metaInfo.metaInfo1 &= ~(1<<1);
  }
#else
  BX_CPP_INLINE unsigned as64L(void) const { return 0; }
#endif

  BX_CPP_INLINE unsigned asize(void) const {
    return metaInfo.metaInfo1 & 0x3;
  }
  BX_CPP_INLINE bx_address asize_mask(void) const {
    return bx_asize_mask[asize()];
  }

#if BX_SUPPORT_X86_64
  BX_CPP_INLINE unsigned extend8bitL(void) const {
    return metaInfo.metaInfo1 & (1<<5);
  }
  BX_CPP_INLINE void assertExtend8bit(void) {
    metaInfo.metaInfo1 |= (1<<5);
  }
#endif

  BX_CPP_INLINE unsigned ilen(void) const {
    return metaInfo.ilen;
  }
  BX_CPP_INLINE void setILen(unsigned ilen) {
    metaInfo.ilen = ilen;
  }

  BX_CPP_INLINE unsigned getIaOpcode(void) const {
    return metaInfo.ia_opcode;
  }
  BX_CPP_INLINE void setIaOpcode(Bit16u op) {
    metaInfo.ia_opcode = op;
  }
  BX_CPP_INLINE const char* getIaOpcodeName(void) const {
    return get_bx_opcode_name(getIaOpcode());
  }
  BX_CPP_INLINE const char* getIaOpcodeNameShort(void) const {
    return get_bx_opcode_name(getIaOpcode()) + /*"BX_IA_"*/ 6;
  }

  BX_CPP_INLINE unsigned repUsedL(void) const {
    return metaInfo.metaInfo1 >> 7;
  }
  BX_CPP_INLINE unsigned lockRepUsedValue(void) const {
    return metaInfo.metaInfo1 >> 6;
  }
  BX_CPP_INLINE void setLockRepUsed(unsigned value) {
    metaInfo.metaInfo1 = (metaInfo.metaInfo1 & 0x3f) | (value << 6);
  }

  BX_CPP_INLINE void setLock(void) {
    setLockRepUsed(BX_LOCK_PREFIX_USED);
  }
  BX_CPP_INLINE bool getLock(void) const {
    return lockRepUsedValue() == BX_LOCK_PREFIX_USED;
  }

  BX_CPP_INLINE unsigned getVL(void) const {
#if BX_SUPPORT_AVX
    return modRMForm.Ib[1];
#else
    return 0;
#endif
  }
  BX_CPP_INLINE void setVL(unsigned value) {
    modRMForm.Ib[1] = value;
  }

#if BX_SUPPORT_AVX
  BX_CPP_INLINE void setVexW(unsigned bit) {
    modRMForm.Ib[2] = (modRMForm.Ib[2] & ~(1<<4)) | (bit<<4);
  } 
  BX_CPP_INLINE unsigned getVexW(void) const {
    return modRMForm.Ib[2] & (1 << 4);
  }
#else
  BX_CPP_INLINE unsigned getVexW(void) const { return 0; }
#endif

#if BX_SUPPORT_EVEX
  BX_CPP_INLINE void setOpmask(unsigned reg) {
    modRMForm.Ib[3] = reg;
  }
  BX_CPP_INLINE unsigned opmask(void) const {
    return modRMForm.Ib[3];
  }

  BX_CPP_INLINE void setEvexb(unsigned bit) {
    modRMForm.Ib[2] = (modRMForm.Ib[2] & ~(1<<3)) | (bit<<3);
  } 
  BX_CPP_INLINE unsigned getEvexb(void) const {
    return modRMForm.Ib[2] & (1 << 3);
  } 

  BX_CPP_INLINE void setZeroMasking(unsigned bit) {
    modRMForm.Ib[2] = (modRMForm.Ib[2] & ~(1<<2)) | (bit<<2);
  } 
  BX_CPP_INLINE unsigned isZeroMasking(void) const {
    return modRMForm.Ib[2] & (1 << 2);
  } 

  BX_CPP_INLINE void setRC(unsigned rc) {
    modRMForm.Ib[2] = (modRMForm.Ib[2] & ~0x3) | rc;
  } 
  BX_CPP_INLINE unsigned getRC(void) const {
    return modRMForm.Ib[2] & 0x3;
  } 
#endif

  BX_CPP_INLINE void setSrcReg(unsigned src, unsigned reg) {
    metaData[src] = reg;
  }
  BX_CPP_INLINE unsigned getSrcReg(unsigned src) const {
    return metaData[src];
  }

  BX_CPP_INLINE unsigned dst() const {
    return metaData[BX_INSTR_METADATA_DST];
  }
 
  BX_CPP_INLINE unsigned src1() const {
    return metaData[BX_INSTR_METADATA_SRC1];
  }
  BX_CPP_INLINE unsigned src2() const {
    return metaData[BX_INSTR_METADATA_SRC2];
  }
  BX_CPP_INLINE unsigned src3() const {
    return metaData[BX_INSTR_METADATA_SRC3];
  }

  BX_CPP_INLINE unsigned src() const { return src1(); }

  BX_CPP_INLINE unsigned modC0() const
  {
    // This is a cheaper way to test for modRM instructions where
    // the mod field is 0xc0.  FetchDecode flags this condition since
    // it is quite common to be tested for.
    return metaInfo.metaInfo1 & (1<<4);
  }
  BX_CPP_INLINE void assertModC0()
  {
    metaInfo.metaInfo1 |= (1<<4);
  }

#if BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS && BX_ENABLE_TRACE_LINKING && !defined(BX_STANDALONE_DECODER)
  BX_CPP_INLINE bxInstruction_c* getNextTrace(Bit32u currTraceLinkTimeStamp) {
    if (currTraceLinkTimeStamp > modRMForm.Id2) handlers.next = NULL;
    return handlers.next;
  }
  BX_CPP_INLINE void setNextTrace(bxInstruction_c* iptr, Bit32u traceLinkTimeStamp) {
    handlers.next = iptr;
    modRMForm.Id2 = traceLinkTimeStamp;
  }
#endif

};
// <TAG-CLASS-INSTRUCTION-END>

enum BxDisasmStyle {
  BX_DISASM_INTEL,
  BX_DISASM_GAS
};

extern char* disasm(const Bit8u *opcode, bool is_32, bool is_64, char *disbufptr, bxInstruction_c *i, bx_address cs_base, bx_address rip, BxDisasmStyle style = BX_DISASM_INTEL);

#endif