The ROme OpTimistic Simulator  2.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
disassemble.h
Go to the documentation of this file.
1 
42 #pragma once
43 
44 #if defined(__x86_64__)
45 
46 #include <stdint.h>
47 #include <stdbool.h>
48 
50 #define DATA_32 0x01
51 #define ADDR_32 0x02
53 #define DATA_64 0x04
55 #define ADDR_64 0x08
57 
58 
59 typedef struct insn_info_x86 {
60  unsigned long flags; // Insieme di flags contenente informazioni utili generiche riguardo l'istruzione
61  unsigned char insn[15]; // I byte dell'istruzione (15 è il limite massimo)
62  unsigned char opcode[2]; // L'opcode dell'istruzione
63  char mnemonic[16]; // Il nome dell'istruzione
64  unsigned long initial; // Posizione iniziale nel testo
65  unsigned long insn_size; // Lunghezza dell'istruzione
66  unsigned long addr; // Indirizzo puntato dall'istruzione, o 0x00
67  unsigned long span; // Quanto in memoria verrà riscritto/letto, o 0x00
68  bool has_index_register; // L'indirizzamento sfrutta un indice?
69  unsigned char ireg; // Quale registro contiene l'indice?
70  char ireg_mnem[8]; // Mnemonico del registro di indice
71  bool has_base_register; // L'indirizzamento sfrutta una base?
72  unsigned char breg; // Quale registro contiene la base?
73  char breg_mnem[8]; // Mnemonico del registro
74  bool has_scale; // L'indirizzamento utilizza una scala
75  unsigned long scale; // La scala
76  unsigned long disp_offset; // Lo spiazzamento del displacement dall'inizio del testo, o 0x00
77  int disp_size; // Dimensione in byte del displacement, o 0x00
78  long long disp; // Il valore dello spiazzamento
79  unsigned long immed_offset; // [SE] Lo spiazzamento dei dati immediati dall'inizio del testo, o 0x00
80  int immed_size; // [SE] La dimensione dei dati immediati, o 0x00
81  unsigned long long immed; // [SE] Il valore dei dati immediati
82  unsigned int opcode_size; // [DC] Dimensione dell'opcode per l'istruzione
83  int32_t jump_dest; // Dove punta la jmp
84  bool uses_rip;
85  unsigned char rex; // Il byte REX, o 0x00
86  unsigned char modrm; // Byte ModR/M o 0x00
87  unsigned char sib; // Byte SIB o 0x00
88  unsigned char sse_prefix; // Terzo byte dell'istruzione SSE/SSE2
89  unsigned char prefix[4]; // Prefissi all'istruzione o 0x00
90 
91  bool dest_is_reg; // [SE] Indica se la destinazione è un registro
92  unsigned char reg_dest; // [SE] Codice del registro destinazione (se esiste)
94 
95 // [FV] Flags contenenti informazioni utili sul comportamento o la classe delle funzioni
96 #define I_MEMRD 0x1 // Legge dalla memoria
97 #define I_MEMWR 0x2 // Scrive sulla memoria
98 #define I_CTRL 0x4 // Istruzioni della famiglia "test" e "control" che controllano valori di dati o singoli bit
99 #define I_JUMP 0x8 // Istruzioni della famiglia "jump", che modificano il flusso di esecuzione del processore
100 #define I_CALL 0x10 // Istruzione del tipo "call"
101 #define I_RET 0x20 // Istruzione del tipo "call"
102 #define I_CONDITIONAL 0x40 // Istruzione che viene eseguite se e solo se e' soddisfatta una condizione
103 #define I_STRING 0x80 // Opera su stringhe (e.g. movs, stos, cmps...)
104 #define I_ALU 0x100 // Esegue operazioni di tipo logico-aritmetico
105 #define I_FPU 0x200 // Utilizza la Floating Point Unit (FPU)
106 #define I_MMX 0x400 // Istruzione che utilizza i registri MMX
107 #define I_XMM 0x800 // Istruzione che utilizza i registri XMM
108 #define I_SSE 0x1000 // Istruzione SSE
109 #define I_SSE2 0x2000 // Istruzione SSE2
110 #define I_PUSHPOP 0x4000 // Istruzione di tipo "push" o di tipo "pop"
111 #define I_STACK 0x8000 // Se l'istruzione opera nello stack
112 #define I_JUMPIND 0x10000 // Indirect Branch
113 #define I_CALLIND 0x20000 // [SE] Indirect Call
114 #define I_MEMIND 0x40000 // [SE] Indirect memory address load (LEA)
115 
116 // [FV] Macro per il testing dei flags
117 #define IS_MEMRD(X) ((X)->flags & I_MEMRD)
118 #define IS_MEMWR(X) ((X)->flags & I_MEMWR)
119 #define IS_MEMIND(X) ((X)->flags & I_MEMIND)
120 #define IS_CTRL(X) ((X)->flags & I_CTRL)
121 #define IS_JUMP(X) ((X)->flags & I_JUMP)
122 #define IS_JUMPIND(X) ((X)->flags & I_JUMPIND)
123 #define IS_CALL(X) ((X)->flags & I_CALL)
124 #define IS_CALLIND(X) ((X)->flags & I_CALLIND)
125 #define IS_RET(X) ((X)->flags & I_RET)
126 #define IS_CONDITIONAL(X) ((X)->flags & I_CONDITIONAL)
127 #define IS_STRING(X) ((X)->flags & I_STRING)
128 #define IS_ALU(X) ((X)->flags & I_ALU)
129 #define IS_FPU(X) ((X)->flags & I_FPU)
130 #define IS_MMX(X) ((X)->flags & I_MMX)
131 #define IS_XMM(X) ((X)->flags & I_XMM)
132 #define IS_SSE(X) ((X)->flags & I_SSE)
133 #define IS_SSE2(X) ((X)->flags & I_SSE2)
134 #define IS_PUSHPOP(X) ((X)->flags & I_PUSHPOP)
135 #define IS_STACK(X) ((X)->flags & I_STACK)
136 
137 
138 // Strings to load macros from the configuration file
139 #define I_MEMRD_S "I_MEMRD"
140 #define I_MEMWR_S "I_MEMWR"
141 #define I_MEMIND_S "I_MEMIND"
142 #define I_CTRL_S "I_CTRL"
143 #define I_JUMP_S "I_JUMP"
144 #define I_JUMPIND_S "I_JUMPIND"
145 #define I_CALL_S "I_CALL"
146 #define I_CALLIND_S "I_CALLIND"
147 #define I_RET_S "I_RET"
148 #define I_CONDITIONAL_S "I_CONDITIONAL"
149 #define I_STRING_S "I_STRING"
150 #define I_ALU_S "I_ALU"
151 #define I_FPU_S "I_FPU"
152 #define I_MMX_S "I_MMX"
153 #define I_XMM_S "I_XMM"
154 #define I_SSE_S "I_SSE"
155 #define I_SSE2_S "I_SSE2"
156 #define I_PUSHPOP_S "I_PUSHPOP"
157 #define I_STACK_S "I_STACK"
158 
159 // Arch-Dependent Instruction Sets
160 #define UNRECOG_INSN 0
161 #define X86_INSN 7
162 
163 
164 #define A32(f) ((f) & ADDR_32) // Indirizzi a 32 bit?
165 #define D32(f) ((f) & DATA_32) // Dati a 32 bit?
166 #define A64(f) ((f) & ADDR_64) // Indirizzi a 64 bit?
167 #define D64(f) ((f) & DATA_64) // Dati a 64 bit?
168 
169 /* Test sui prefissi */
170 #define p_is_group1(p) (((p) == 0xf0) /* lock */ \
171  || ((p) == 0xf2) /* repne/repnz */ \
172  || ((p) == 0xf3)) /* rep/repe/repz */
173 
174 #define p_is_group2(p) (((p) == 0x2e) /* CS override/branch not taken */ \
175  || ((p) == 0x36) /* SS override */ \
176  || ((p) == 0x3e) /* DS override/branch taken */ \
177  || ((p) == 0x26) /* ES override */ \
178  || ((p) == 0x64) /* FS override */ \
179  || ((p) == 0x65)) /* GS override */
180 
181 #define p_is_group3(p) ((p) == 0x66) /* opsize override */
182 
183 #define p_is_group4(p) ((p) == 0x67) /* addr size override */
184 
185 #define is_prefix(o) (p_is_group1 (o) || p_is_group2 (o) \
186  || p_is_group3 (o) || p_is_group4 (o))
187 
188 #define is_sse_prefix(o) (((o) == 0xf2) || ((o) == 0xf3) || ((o) == 0x66))
189 
190 #define is_rex_prefix(r, mode64) (((r) >= 0x40 && (r) <= 0x4f ) && (mode64))
191 
192 
193 /* Recuperano i bit di interesse del byte REX (i primi 4 bit sono fissi e valgono 0100b) */
194 
195 #define REXW(r) (((r) & 0x08) >> 3)
196 #define REXR(r) (((r) & 0x04) >> 2)
197 #define REXX(r) (((r) & 0x02) >> 1)
198 #define REXB(r) (((r) & 0x01))
199 
200 
201 /* Test per le operazioni Jcc */
202 
203 // opcode nell'intervallo 70-7f,e3
204 #define is_jcc_insn(o) (((o) == 0xe3) || (((o) >= 0x70) && ((o) <= 0x7f)))
205 
206 // opcode nell'intervallo 80-8f (quando il primo byte è 0f)
207 #define is_esc_jcc_insn(o) (((o) >= 0x80) && ((o) <= 0x8f))
208 
209 
210 // Gli operandi dell'istruzione specificano se c'è o meno un byte ModR/M
211 #define has_modrm(addr) (((addr) == ADDR_C) \
212  || ((addr) == ADDR_D) \
213  || ((addr) == ADDR_E) \
214  || ((addr) == ADDR_G) \
215  || ((addr) == ADDR_M) \
216  || ((addr) == ADDR_P) \
217  || ((addr) == ADDR_Q) \
218  || ((addr) == ADDR_R) \
219  || ((addr) == ADDR_S) \
220  || ((addr) == ADDR_T) \
221  || ((addr) == ADDR_V) \
222  || ((addr) == ADDR_W))
223 
224 // È presente un byte SIB se il campo Mod non è 11b, il campo R/M è
225 // 100b e la modalità di indirizzamento è a 32 bit o 64 bit
226 #define has_sib(modrm, addr) ((((modrm) & 0x07) == 0x04) \
227  && (((addr) == SIZE_32) || (addr) == SIZE_64) \
228  && (((modrm) & 0xC0) != 0xC0))
229 
230 // Se il campo Mod è 01b, allora c'è uno spiazzamento di 1 byte. Se il campo
231 // Mod è 10b, e siamo in modalità di indirizzamento a 32/64 bit, allora c'è
232 // uno spiazzamento di 4 byte. Inoltre, se la modalità di indirizzamento è
233 // a 16 bit e il campo Mod è 10b, allora c'è uno spiazzamento di 2 byte.
234 // Se la modalità di indirizzamento è a 32 o 64 bit e sia il campo Mod è 00b sia
235 // il campo R/M è 101b, o il campo Mod è 10b, allora c'è uno spiazzamento
236 // di 4 byte. Altrimenti non c'è spiazzamento.
237 #define disp_size(modrm, addr) ((((modrm) & 0xC0) == 0x40) ? 1 \
238  : ((((addr) == SIZE_16) \
239  && ((((modrm) & 0xC7) == 0x06) \
240  || (((modrm) & 0xC0) == 0x80))) ? 2 \
241  : (((((addr) == SIZE_32) || (addr) == SIZE_64) \
242  && ((((modrm) & 0xC7) == 0x05) \
243  || (((modrm) & 0xC0) == 0x80))) ? 4\
244  : 0)))
245 
246 enum addr_method {
247  ADDR_0, /* Nessun metodo di indirizzamento */
248  ADDR_A, /* Indirizzamento diretto, nessun byte ModR/M */
249  ADDR_C, /* Il campo reg del byte ModR/M seleziona un registro di controllo */
250  ADDR_D, /* Il campo reg del byte ModR/M seleziona un registro di debug */
251  ADDR_E, /* Il byte ModR/M specifica l'operando: o un registro general purpose
252  o un offset per un indirizzo di memoria da un segment register
253  con un registro base, un registro d'indice, un fattore di scala
254  o spiazzamento */
255  ADDR_F, /* registro EFLAGS */
256  ADDR_G, /* Il campo reg del byte ModR/M seleziona un registro generale */
257  ADDR_I, /* Dati immediati */
258  ADDR_J, /* L'istruzione contiene un offset relativo, da (E)IP */
259  ADDR_M, /* Il byte ModR/M può riferirsi solo a memoria */
260  ADDR_N, /* [FV] Il campo R/M del byte ModR/M indica un registro MMX */
261  ADDR_O, /* Nessun byte ModR/M. L'op è codificata come word o dword o qword in 64bit */
262  ADDR_P, /* Il campo reg del byte ModR/M seleziona un registro packed qword MMX */
263  ADDR_Q, /* Il byte ModR/M specifica o un registro MMX o un indirizzo in memoria (scala, ecc...) */
264  ADDR_R, /* Il campo reg del byte ModR/M si può riferire solo a un registro generale */
265  ADDR_S, /* Il campo reg del byte ModR/M seleziona un segment register */
266  ADDR_T, /* Il campo reg del byte ModR/M seleziona un registro di test */
267  ADDR_U, // Alice: Il campo R/M del byte ModR/M seleziona un registro XMM
268  ADDR_V, /* Il campo reg del byte ModR/M seleziona un registro MMX */
269  ADDR_W, /* Il byte ModR/M seleziona un registro XMM o un indirizzo in memoria (scala, ecc...) */
270  ADDR_X, /* Indirizzo di memoria da DS:SI */
271  ADDR_Y, /* Indirizzo di memoria da ES:DI */
272 
273  /* Registri */
274  R_START,
275 
276  R_AL,
277  R_AH,
278  R_AX,
279  R_EAX,
280  R_RAX,
281 
282  R_BL,
283  R_BH,
284  R_BX,
285  R_EBX,
286  R_RBX,
287 
288  R_CL,
289  R_CH,
290  R_CX,
291  R_ECX,
292  R_RCX,
293 
294  R_DL,
295  R_DH,
296  R_DX,
297  R_EDX,
298  R_RDX,
299 
300  R_SIL,
301  R_SI,
302  R_ESI,
303  R_RSI,
304  R_DIL,
305  R_DI,
306  R_EDI,
307  R_RDI,
308  R_BP,
309  R_EBP,
310  R_SPL,
311  R_SP,
312  R_ESP,
313  R_RSP,
314 
315  /* segment registers */
316  R_CS,
317  R_DS,
318  R_SS,
319  R_ES,
320  R_FS,
321  R_GS,
322 
323  /* EFLAGS */
324  R_F,
325  R_EF,
326 
327  /* EIP */
328  R_IP,
329  R_EIP,
330  R_RIP,
331 
332  /* floating point registers */
333  R_ST0,
334  R_ST1,
335  R_ST2,
336  R_ST3,
337  R_ST4,
338  R_ST5,
339  R_ST6,
340  R_ST7,
341 
342  /* Extra registers in 64bit mode */
343  R_R8L,
344  R_R8W,
345  R_R8D,
346  R_R8,
347 
348  R_R9L,
349  R_R9W,
350  R_R9D,
351  R_R9,
352 
353  R_R10L,
354  R_R10W,
355  R_R10D,
356  R_R10,
357 
358  R_R11L,
359  R_R11W,
360  R_R11D,
361  R_R11,
362 
363  R_R12L,
364  R_R12W,
365  R_R12D,
366  R_R12,
367 
368  R_R13L,
369  R_R13W,
370  R_R13D,
371  R_R13,
372 
373  R_R14L,
374  R_R14W,
375  R_R14D,
376  R_R14,
377 
378  R_R15L,
379  R_R15W,
380  R_R15D,
381  R_R15,
382 
383 
384  /* MMX registers */
385  R_MM0,
386  R_MM1,
387  R_MM2,
388  R_MM3,
389  R_MM4,
390  R_MM5,
391  R_MM6,
392  R_MM7,
393 
394  /* SSE/SSE2 registers */
395  R_XMM0,
396  R_XMM1,
397  R_XMM2,
398  R_XMM3,
399  R_XMM4,
400  R_XMM5,
401  R_XMM6,
402  R_XMM7,
403  R_XMM8,
404  R_XMM9,
405  R_XMM10,
406  R_XMM11,
407  R_XMM12,
408  R_XMM13,
409  R_XMM14,
410  R_XMM15,
411 
412  R_END,
413 
414  /* Valore immediato interno all'istruzione (D0, D1) */
415  IMMED_1, /* il valore 1 */
416 };
417 
418 enum operand_type {
419  OP_0, /* nessun tipo */
420  OP_A, /* due oper da 1 word o 2 operandi dword in mem (dipende dall'attr opsize) */
421  OP_B, /* byte, indifferentemente dall'attrib opsize */
422  OP_C, /* byte o word, a seconda dell'attrib opsize */
423  OP_D, /* dword, indifferentemente dall'attributo opsize */
424  OP_DQ, /* dqword, indifferentemebre dall'attr opsize */
425  OP_P, /* puntatore di 32 o 48 bit a seconda dell'attributo opsize */
426  OP_PI, /* Registro MMX qword */
427  OP_PS, /* 128 bit packed single float [FV] o 256 bit */
428  OP_Q, /* qword, indifferentemente dall'att opsize */
429  OP_S, /* 6 byte pseudo-descriptor */
430  OP_SS, /* Elemento scalare di un packed single float a 128 bit */
431  OP_SI, /* registro dword (es: eax) */
432  OP_V, /* word o dword, a seconda dell'attributo opsize */
433  OP_W, /* word, indifferentemente dall'attributo opsize */
434  OP_PD, /* registri dqword o xmm [FV] 128 bit o 256 bit packed double-precision float */
435  OP_SD, /* registri qword o xmm */
436  OP_E, /* usato quando i registri sono codificati direttamente */
437  OP_Y, /* [FV] doubleword o quadword (in modalita' 64 bit), a seconda dell'attributo operand-size */
438  OP_FS, /* [FV] 14 o 24 byte in memoria, a seconda di operand-size (usato da istruzioni load/store FPU state) */
439  OP_FSR, /* [FV] 94 o 108 byte in memoria, a seconda di operand-size (usato da istruzioni FRSTOR/FSAVE FPU
440  * state piu' 80 bit registri FPU) */
441  OP_M80, /* 80 bit in memoria */
442  OP_M512byte /* 512 byte in memoria */
443 };
444 
445 enum op_size {
446  SIZE_8, //Alice
447  SIZE_16,
448  SIZE_32,
449  SIZE_64
450 };
451 
452 /* dimensione operando / indirizzo */
453 enum reg_size {
454  REG_SIZE_8, REG_SIZE_16, REG_SIZE_32, REG_SIZE_64, REG_SIZE_128
455 };
456 
457 
458 // Per tenere traccia dello stato dell'interpretazione
460  enum op_size opd_size; // Dimensione dell'operando corrente
461  enum op_size addr_size; // Dimensione dell'indirizzo corrente
462  unsigned char *text; // Sezione testo corrente (su cui si opera)
463  unsigned long pos; // Posizione corrente nel testo
464  unsigned char rex; // Il byte REX, o 0x00
465  bool mode64; // Stiamo eseguendo a 32 o a 64 bit?
466  unsigned char opcode[2]; // Opcode corrente
467  unsigned char modrm; // Byte ModR/M o 0x00
468  bool read_modrm; // Indica se il byte ModR/M è stato letto
469  unsigned char sib; // Byte SIB o 0x00
470  unsigned long disp_offset; // L'inizio del displacement o 0
471  int disp_size; // Dimensione in byte del displacement
472  unsigned long immed_offset; // L'inizio dei dati immediati o 0
473  int immed_size; // La dimensione dei dati immediati
474  enum addr_method addr[3]; // Codice per il metodo di indirizzamento
475  enum operand_type op[3]; // Codice per il tipo di operando
476  unsigned char prefix[4]; // Prefissi all'istruzione o 0x00
477  unsigned char sse_prefix; // Terzo byte dell'istruzione SSE/SSE2
478  unsigned long orig_pos; // Posizione iniziale nel testo
479  bool read_dest; // Indica se è stata analizzata la destinazione
480 
481  // [FV] Flag indicante se l'istruzione usi un indirizzamento RIP_Relative o meno
482  bool uses_rip;
483 
484  insn_info_x86 *instrument; // Struttura dati per gestire l'instrumentazione
485 };
486 
487 
488 struct _insn {
489  char *instruction; // Nome dell'istruzione (es: "mov")
490  enum addr_method addr_method[3]; // Metodo di indirizzamento (Appendice A di IA-32 SDM)
491  enum operand_type operand_type[3]; // Tipo corrispondete (sempre dall'appendice A)
492  void (*esc_function)(struct disassembly_state *); // Gestore dei byte addizionali dell'opcode
493  unsigned long flags; // Flag contenente info utili sull'istruzione (così come definiti in "instruction.h")
494 };
495 
496 typedef struct _insn insn, *insn_table;
497 
498 
499 extern void x86_disassemble_instruction(unsigned char *text, unsigned long *pos, insn_info_x86 *instrument, char flags);
500 
501 #endif /* defined(__x86_64__) */
502