OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 /* | |
8 * ncdecode_verbose.c - Print routines for validator that are | |
9 * not to be loaded into sel_ldr. | |
10 */ | |
11 | |
12 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose
.h" | |
13 | |
14 #include <stdio.h> | |
15 #include <stdlib.h> | |
16 #include <string.h> | |
17 | |
18 #include "native_client/src/shared/gio/gio.h" | |
19 #include "native_client/src/shared/platform/nacl_log.h" | |
20 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" | |
21 | |
22 #include "native_client/src/trusted/validator/x86/x86_insts_inl.c" | |
23 | |
24 #if NACL_TARGET_SUBARCH == 64 | |
25 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdisasmtab_
64.h" | |
26 #else | |
27 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdisasmtab_
32.h" | |
28 #endif | |
29 | |
30 /* To turn on debugging of instruction decoding, change value of | |
31 * DEBUGGING to 1. | |
32 */ | |
33 #define DEBUGGING 0 | |
34 | |
35 #include "native_client/src/shared/utils/debugging.h" | |
36 | |
37 /* The following are conditionally added since they only have meaning | |
38 * if we are processing 64-bit instructions. | |
39 */ | |
40 #if NACL_TARGET_SUBARCH == 64 | |
41 | |
42 /* Returns true if REX.W is defined in the REX prefix byte. */ | |
43 static INLINE uint8_t GetRexPrefixW(const NCDecoderInst* dinst) { | |
44 /* Note: the field rexprefix is non-zero only if a rexprefix was found. */ | |
45 return 0 != NaClRexW(dinst->inst.rexprefix); | |
46 } | |
47 | |
48 /* Returns true if REX.R is defined in the REX prefix byte. */ | |
49 static INLINE uint8_t GetRexPrefixR(const NCDecoderInst* dinst) { | |
50 /* Note: the field rexprefix is non-zero only if a rexprefix was found. */ | |
51 return 0 != NaClRexR(dinst->inst.rexprefix); | |
52 } | |
53 | |
54 #endif | |
55 | |
56 /* Returns the index into the general purpose registers based on the | |
57 * value in the modrm.rm field of the instruction (taking into account | |
58 * the REX prefix if it appears). | |
59 */ | |
60 static INLINE uint32_t state_modrm_reg(const NCDecoderInst* dinst) { | |
61 /* TODO(karl) This is no where near close to being correct. Currently, | |
62 * It only models r/m64 entry for instructions in the Intel documentation, | |
63 * which requires the W bit to be set (r/m32 entries do not use REX.w, | |
64 * and a different set of registers). | |
65 */ | |
66 uint32_t index = modrm_regInline(dinst->inst.mrm); | |
67 #if NACL_TARGET_SUBARCH == 64 | |
68 if (GetRexPrefixW(dinst) && GetRexPrefixR(dinst)) { | |
69 index += 8; | |
70 } | |
71 #endif | |
72 return index; | |
73 } | |
74 | |
75 /* Returns the index for the first instruction opcode byte. */ | |
76 static INLINE int NCOpcodeOffset(const NCDecoderInst* dinst) { | |
77 return dinst->inst.prefixbytes; | |
78 } | |
79 | |
80 /* Returns the index for the modrm byte. */ | |
81 static INLINE int NCMrmOffset(const NCDecoderInst* dinst) { | |
82 return NCOpcodeOffset(dinst) + dinst->inst.num_opbytes; | |
83 } | |
84 | |
85 /* Returns the index of the sib byte (if it has one). */ | |
86 static INLINE int NCSibOffset(const NCDecoderInst* dinst) { | |
87 /* Note: The sib byte follows the mrm byte. */ | |
88 return NCMrmOffset(dinst) + 1; | |
89 } | |
90 | |
91 /* Returns the beginning index for the displacement (if it has one). */ | |
92 static int NCDispOffset(const NCDecoderInst* dinst) { | |
93 if (dinst->opinfo->hasmrmbyte) { | |
94 if (dinst->inst.hassibbyte) { | |
95 return NCSibOffset(dinst) + 1; | |
96 } else { | |
97 return NCMrmOffset(dinst) + 1; | |
98 } | |
99 } else { | |
100 return NCOpcodeOffset(dinst) + dinst->inst.num_opbytes; | |
101 } | |
102 } | |
103 | |
104 /* Returns the beginning index for the immediate value. */ | |
105 static INLINE int NCImmedOffset(const NCDecoderInst* dinst) { | |
106 return NCDispOffset(dinst) + dinst->inst.dispbytes; | |
107 } | |
108 | |
109 /* later this will make decoding x87 instructions a bit more concise. */ | |
110 static const char** kDisasmX87Op[8] = {kDisasm87D8, | |
111 kDisasm87D9, | |
112 kDisasm87DA, | |
113 kDisasm87DB, | |
114 kDisasm87DC, | |
115 kDisasm87DD, | |
116 kDisasm87DE, | |
117 kDisasm87DF}; | |
118 | |
119 const char** kDummyUsesToAvoidCompilerWarning[] = {kDisasm660F38Op, | |
120 kDisasmF20F38Op, | |
121 kDisasm660F3AOp}; | |
122 | |
123 /* disassembler stuff */ | |
124 static const char* DisFmt(const NCDecoderInst *dinst) { | |
125 NCInstBytesPtr opbyte; | |
126 uint8_t opbyte0; | |
127 uint8_t opbyte1; | |
128 uint8_t pm = dinst->inst.opcode_prefixmask; | |
129 NCInstBytesPtrInitInc(&opbyte, &dinst->inst_bytes, NCOpcodeOffset(dinst)); | |
130 opbyte0 = NCInstBytesByte(&opbyte, 0); | |
131 | |
132 if (dinst->opinfo->insttype == NACLi_X87 || | |
133 dinst->opinfo->insttype == NACLi_X87_FSINCOS) { | |
134 if (opbyte0 != kWAITOp) { | |
135 return kDisasmX87Op[opbyte0 - kFirstX87Opcode][dinst->inst.mrm]; | |
136 } | |
137 } | |
138 if (dinst->opinfo->insttype == NACLi_FCMOV) { | |
139 return kDisasmX87Op[opbyte0 - kFirstX87Opcode][dinst->inst.mrm]; | |
140 } | |
141 if (dinst->opinfo->insttype == NACLi_NOP) return "nop"; | |
142 if (opbyte0 != kTwoByteOpcodeByte1) return kDisasm1ByteOp[opbyte0]; | |
143 opbyte1 = NCInstBytesByte(&opbyte, 1); | |
144 if (opbyte1 == 0x0f) { | |
145 return kDisasm0F0FOp[ | |
146 NCInstBytesByte(&opbyte, dinst->inst.bytes.length - 1)]; | |
147 } | |
148 if (opbyte1 == 0x38) { | |
149 return kDisasm0F38Op[NCInstBytesByte(&opbyte, 2)]; | |
150 } | |
151 if (opbyte1 == 0x3A) { | |
152 return kDisasm0F3AOp[NCInstBytesByte(&opbyte, 2)]; | |
153 } | |
154 if (! (pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP))) { | |
155 return kDisasm0FXXOp[opbyte1]; | |
156 } | |
157 if (pm & kPrefixDATA16) return kDisasm660FXXOp[opbyte1]; | |
158 if (pm & kPrefixREPNE) return kDisasmF20FXXOp[opbyte1]; | |
159 if (pm & kPrefixREP) return kDisasmF30FXXOp[opbyte1]; | |
160 | |
161 /* no update; should be invalid */ | |
162 return "internal error"; | |
163 } | |
164 | |
165 /* Returns the (sign extended) 32-bit integer immediate value. */ | |
166 static int32_t ImmedValue32(const NCDecoderInst* dinst) { | |
167 NCInstBytesPtr addr; | |
168 NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes, | |
169 NCImmedOffset(dinst)); | |
170 return NCInstBytesInt32(&addr, dinst->inst.immbytes); | |
171 } | |
172 | |
173 /* Returns the (sign extended) 64-bit integer immediate value. */ | |
174 static int64_t ImmedValue64(const NCDecoderInst* dinst) { | |
175 NCInstBytesPtr addr; | |
176 NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes, | |
177 NCImmedOffset(dinst)); | |
178 return NCInstBytesInt64(&addr, dinst->inst.immbytes); | |
179 } | |
180 | |
181 /* Returns the (sign extended) 32-bit integer displacement value. */ | |
182 static int32_t DispValue32(const NCDecoderInst* dinst) { | |
183 NCInstBytesPtr addr; | |
184 NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes, | |
185 NCDispOffset(dinst)); | |
186 return NCInstBytesInt32(&addr, dinst->inst.dispbytes); | |
187 } | |
188 | |
189 /* Defines the set of available general purpose registers. */ | |
190 static const char* gp_regs[] = { | |
191 #if NACL_TARGET_SUBARCH == 64 | |
192 /* TODO(karl) - Depending on whether the instruction uses r/m32 | |
193 * of r/m64 forms (according to the Intel document), the list of | |
194 * (16) registers is different. Currently, we are only handling | |
195 * the r/m64 case. | |
196 */ | |
197 "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", | |
198 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" | |
199 #else | |
200 "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" | |
201 #endif | |
202 }; | |
203 | |
204 | |
205 static const char* mmx_regs[] = { | |
206 "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" | |
207 }; | |
208 | |
209 static const char* xmm_regs[] = { | |
210 "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" | |
211 }; | |
212 | |
213 static const char* seg_regs[] = { | |
214 "%es", "%cs", "%ss", "%ds", "%fs", "%gs" | |
215 }; | |
216 | |
217 /* Print out the sib byte of the parsed instruction in the given decoder state | |
218 * to the given file. | |
219 */ | |
220 static void SibPrint(const NCDecoderInst* dinst, struct Gio* fp) { | |
221 uint8_t sib = NCInstBytesByte(&dinst->inst_bytes, NCSibOffset(dinst)); | |
222 | |
223 if (!dinst->inst.hassibbyte) { | |
224 /* This should not happen. */ | |
225 gprintf(fp, "?"); | |
226 } else if (sib_ss(sib) == 0) { | |
227 if (sib_base(sib) == 5) { | |
228 /* This code is JUST WRONG!. However, I am not fixing since | |
229 * the decoder printer is broken in so many other ways!. See tables | |
230 * 2-1 and 2-2 of "Intel 64 and IA-32 Architectures Software Developer's | |
231 * Manual" for details of what should be done (there are | |
232 * 3 cases, depending on the value of the mod field of the modrm | |
233 * byte). | |
234 * Note: While the changes here are not correct, they at least make | |
235 * sure that we process bytes that are actually in the instruction. | |
236 * That is, the code doesn't accidentally walk off the end of the | |
237 * parsed instruction. | |
238 */ | |
239 gprintf(fp, "[0x%x]", DispValue32(dinst)); | |
240 } else { | |
241 /* Has a base register */ | |
242 if (sib_index(sib) == 4) { | |
243 /* No index */ | |
244 gprintf(fp, "[%s]", gp_regs[sib_base(sib)]); | |
245 } else { | |
246 gprintf(fp, "[%s + %s]", | |
247 gp_regs[sib_base(sib)], | |
248 gp_regs[sib_index(sib)]); | |
249 } | |
250 } | |
251 } else { | |
252 if (sib_index(sib) == 4) { | |
253 /* No index */ | |
254 gprintf(fp, "[%s]", gp_regs[sib_base(sib)]); | |
255 } else { | |
256 gprintf(fp, "[%s + %d * %s]", | |
257 gp_regs[sib_base(sib)], | |
258 1 << sib_ss(sib), | |
259 gp_regs[sib_index(sib)]); | |
260 } | |
261 } | |
262 } | |
263 | |
264 static void SegPrefixPrint(const NCDecoderInst *dinst, struct Gio* fp) { | |
265 uint8_t pm = dinst->inst.prefixmask; | |
266 if (pm & kPrefixSEGCS) { | |
267 gprintf(fp, "cs:"); | |
268 } else if (pm & kPrefixSEGSS) { | |
269 gprintf(fp, "ss:"); | |
270 } else if (pm & kPrefixSEGFS) { | |
271 gprintf(fp, "fs:"); | |
272 } else if (pm & kPrefixSEGGS) { | |
273 gprintf(fp, "gs:"); | |
274 } | |
275 } | |
276 | |
277 /* Append that we don't bother to translate the instruction argument, | |
278 * since it is NaCl illegal. Used to handle cases where we don't implement | |
279 * 16-bit modrm effective addresses. | |
280 */ | |
281 static INLINE void NaClIllegalOp(struct Gio* fp) { | |
282 gprintf(fp, "*NaClIllegal*"); | |
283 } | |
284 | |
285 /* Print out the register (from the list of register names), | |
286 * that is referenced by the decoded instruction in the | |
287 * decoder state. If is_gp_regs is true, the register names | |
288 * correspond to general purpose register names. Otherwise, | |
289 * they are some other set, such as MMX or XMM. | |
290 */ | |
291 static void RegMemPrint(const NCDecoderInst *dinst, | |
292 const char* reg_names[], | |
293 const uint8_t is_gp_regs, | |
294 struct Gio* fp) { | |
295 DEBUG( printf( | |
296 "reg mem print: sib_offset = %d, " | |
297 "disp_offset = %d, mrm.mod = %02x\n", | |
298 NCSibOffset(dinst), (int) NCDispOffset(dinst), | |
299 modrm_modInline(dinst->inst.mrm)) ); | |
300 switch (modrm_modInline(dinst->inst.mrm)) { | |
301 case 0: | |
302 SegPrefixPrint(dinst, fp); | |
303 if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) { | |
304 NaClIllegalOp(fp); | |
305 } else { | |
306 if (4 == modrm_rmInline(dinst->inst.mrm)) { | |
307 SibPrint(dinst, fp); | |
308 } else if (5 == modrm_rmInline(dinst->inst.mrm)) { | |
309 gprintf(fp, "[0x%x]", DispValue32(dinst)); | |
310 } else { | |
311 gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
312 } | |
313 } | |
314 break; | |
315 case 1: | |
316 SegPrefixPrint(dinst, fp); | |
317 if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) { | |
318 NaClIllegalOp(fp); | |
319 } else { | |
320 gprintf(fp, "0x%x", DispValue32(dinst)); | |
321 if (4 == modrm_rmInline(dinst->inst.mrm)) { | |
322 SibPrint(dinst, fp); | |
323 } else { | |
324 gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
325 } | |
326 } | |
327 break; | |
328 case 2: | |
329 SegPrefixPrint(dinst, fp); | |
330 if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) { | |
331 NaClIllegalOp(fp); | |
332 } else { | |
333 gprintf(fp, "0x%x", DispValue32(dinst)); | |
334 if (4 == modrm_rmInline(dinst->inst.mrm)) { | |
335 SibPrint(dinst, fp); | |
336 } else { | |
337 gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
338 } | |
339 } | |
340 break; | |
341 case 3: | |
342 if (is_gp_regs) { | |
343 gprintf(fp, "%s", reg_names[state_modrm_reg(dinst)]); | |
344 } else { | |
345 gprintf(fp, "%s", reg_names[modrm_rmInline(dinst->inst.mrm)]); | |
346 } | |
347 break; | |
348 } | |
349 } | |
350 | |
351 /* Parses the group name in token. Returns NOGROUP(0) if unable to parse. */ | |
352 static NaClMRMGroups ParseGroupName(const char* token) { | |
353 if (!strncmp(token, "group", 5)) { | |
354 /* Matched group name prefix, recognize last two characters explicitly.*/ | |
355 const char* suffix = token + 5; | |
356 switch (strlen(suffix)) { | |
357 case 1: | |
358 switch (suffix[0]) { | |
359 case '1': | |
360 return GROUP1; | |
361 case '2': | |
362 return GROUP2; | |
363 case '3': | |
364 return GROUP3; | |
365 case '4': | |
366 return GROUP4; | |
367 case '5': | |
368 return GROUP5; | |
369 case '6': | |
370 return GROUP6; | |
371 case '7': | |
372 return GROUP7; | |
373 case '8': | |
374 return GROUP8; | |
375 case '9': | |
376 return GROUP9; | |
377 case 'p': | |
378 return GROUPP; | |
379 default: | |
380 break; | |
381 } | |
382 break; | |
383 case 2: | |
384 if (suffix[0] == '1') { | |
385 switch(suffix[1]) { | |
386 case '0': | |
387 return GROUP10; | |
388 case '1': | |
389 return GROUP11; | |
390 case '2': | |
391 return GROUP12; | |
392 case '3': | |
393 return GROUP13; | |
394 case '4': | |
395 return GROUP14; | |
396 case '5': | |
397 return GROUP15; | |
398 case '6': | |
399 return GROUP16; | |
400 case '7': | |
401 return GROUP17; | |
402 case 'a': | |
403 return GROUP1A; | |
404 default: | |
405 break; | |
406 } | |
407 } | |
408 break; | |
409 default: | |
410 break; | |
411 } | |
412 } | |
413 return 0; | |
414 } | |
415 | |
416 static void InstFormat(const char* format, | |
417 const NCDecoderInst *dinst, | |
418 struct Gio* fp) { | |
419 char token_buf[128]; | |
420 char* fmt = token_buf; | |
421 int pos = 0; | |
422 | |
423 strncpy(token_buf, format, sizeof(token_buf)); | |
424 | |
425 while (1) { | |
426 char* token = strtok(fmt, " ,\n"); | |
427 DEBUG( printf("\ntoken = '%s'\n", token) ); | |
428 if (NULL == token) { | |
429 break; | |
430 } | |
431 if (pos > 1) { | |
432 gprintf(fp, ", "); | |
433 } else if (pos > 0) { | |
434 gprintf(fp, " "); | |
435 } | |
436 if ('$' == token[0]) { | |
437 NaClMRMGroups group = ParseGroupName(token+1); | |
438 if (NOGROUP != group) { | |
439 int mrm = modrm_regInline(dinst->inst.mrm); | |
440 const char* opname = kDisasmModRMOp[group][mrm]; | |
441 DEBUG( printf("case: group %d, opname = %s\n", group, opname) ); | |
442 gprintf(fp, "%s", opname); | |
443 } else { | |
444 /* Tokens starting with a $ but not $group need formatting */ | |
445 DEBUG( printf("case: $ and not group\n") ); | |
446 switch (token[1]) { | |
447 case 'A': | |
448 gprintf(fp, "$A"); | |
449 break; | |
450 case 'C': | |
451 gprintf(fp, "%%cr%d", modrm_regInline(dinst->inst.mrm)); | |
452 break; | |
453 case 'D': | |
454 gprintf(fp, "%%dr%d", modrm_regInline(dinst->inst.mrm)); | |
455 break; | |
456 case 'E': | |
457 case 'M': /* mod should never be 3 for 'M' */ | |
458 /* TODO(sehr): byte and word accesses */ | |
459 RegMemPrint(dinst, gp_regs, 1, fp); | |
460 break; | |
461 case 'F': | |
462 gprintf(fp, "eflags"); | |
463 break; | |
464 case 'G': | |
465 gprintf(fp, "%s", gp_regs[modrm_regInline(dinst->inst.mrm)]); | |
466 break; | |
467 case 'I': | |
468 gprintf(fp, "0x%"NACL_PRIx64, ImmedValue64(dinst)); | |
469 break; | |
470 case 'J': | |
471 gprintf(fp, "0x%"NACL_PRIxNaClPcAddress, | |
472 NCPrintableInstructionAddress(dinst) | |
473 + dinst->inst.bytes.length | |
474 + ImmedValue32(dinst)); | |
475 break; | |
476 case 'O': | |
477 gprintf(fp, "[0x%"NACL_PRIx64"]", ImmedValue64(dinst)); | |
478 break; | |
479 case 'P': | |
480 if ('R' == token[2]) { | |
481 gprintf(fp, "%%mm%d", modrm_rmInline(dinst->inst.mrm)); | |
482 } else { | |
483 gprintf(fp, "%%mm%d", modrm_regInline(dinst->inst.mrm)); | |
484 } | |
485 break; | |
486 case 'Q': | |
487 RegMemPrint(dinst, mmx_regs, 0, fp); | |
488 break; | |
489 case 'R': | |
490 gprintf(fp, "%s", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
491 break; | |
492 case 'S': | |
493 gprintf(fp, "%s", seg_regs[modrm_regInline(dinst->inst.mrm)]); | |
494 break; | |
495 case 'V': | |
496 if ('R' == token[2]) { | |
497 gprintf(fp, "%%xmm%d", modrm_rmInline(dinst->inst.mrm)); | |
498 } else { | |
499 gprintf(fp, "%%xmm%d", modrm_regInline(dinst->inst.mrm)); | |
500 } | |
501 break; | |
502 case 'W': | |
503 RegMemPrint(dinst, xmm_regs, 0, fp); | |
504 break; | |
505 case 'X': | |
506 gprintf(fp, "ds:[esi]"); | |
507 break; | |
508 case 'Y': | |
509 gprintf(fp, "es:[edi]"); | |
510 break; | |
511 default: | |
512 gprintf(fp, "token('%s')", token); | |
513 break; | |
514 } | |
515 } | |
516 } else { | |
517 /* Print the token as is */ | |
518 gprintf(fp, "%s", token); | |
519 } | |
520 fmt = NULL; | |
521 ++pos; | |
522 } | |
523 } | |
524 | |
525 static void NCPrintInstTextUsingFormat(const char* format, | |
526 const NCDecoderInst *dinst, | |
527 struct Gio* fp) { | |
528 InstFormat(format, dinst, fp); | |
529 gprintf(fp, "\n"); | |
530 } | |
531 | |
532 void NCPrintInstWithoutHex(const NCDecoderInst *dinst, struct Gio* fp) { | |
533 DEBUG( printf("use format: %s\n", DisFmt(dinst)) ); | |
534 NCPrintInstTextUsingFormat(DisFmt(dinst), dinst, fp); | |
535 } | |
536 | |
537 void NCPrintInstWithHex(const NCDecoderInst *dinst, struct Gio *fp) { | |
538 int i; | |
539 DEBUG( printf("use format: %s\n", DisFmt(dinst)) ); | |
540 gprintf(fp, " %"NACL_PRIxNaClPcAddress":\t%02x", | |
541 NCPrintableInstructionAddress(dinst), | |
542 NCInstBytesByte(&dinst->inst_bytes, 0)); | |
543 for (i = 1; i < dinst->inst.bytes.length; i++) { | |
544 gprintf(fp, " %02x", NCInstBytesByte(&dinst->inst_bytes, i)); | |
545 } | |
546 for (i = dinst->inst.bytes.length; i < 7; i++) gprintf(fp, " "); | |
547 gprintf(fp, "\t"); | |
548 NCPrintInstWithoutHex(dinst, fp); | |
549 } | |
550 | |
551 static Bool PrintInstLogGio(const NCDecoderInst *dinst) { | |
552 NCPrintInstWithHex(dinst, NaClLogGetGio()); | |
553 return TRUE; | |
554 } | |
555 | |
556 /* Defines a buffer size big enough to hold an instruction. */ | |
557 #define MAX_INST_TEXT_SIZE 256 | |
558 | |
559 /* Defines an instruction print function. */ | |
560 typedef void (*inst_print_fn)(const struct NCDecoderInst* inst, | |
561 struct Gio *file); | |
562 | |
563 /* Print out the given instruction, using the given instruction print function, | |
564 * and return the printed text as a (malloc allocated) string. | |
565 */ | |
566 static char* InstToStringConvert(const NCDecoderInst* dinst, | |
567 inst_print_fn print_fn) { | |
568 /* Print to a memory buffer, and then duplicate. */ | |
569 struct GioMemoryFile filemem; | |
570 struct Gio *file = (struct Gio*) &filemem; | |
571 char buffer[MAX_INST_TEXT_SIZE]; | |
572 char* result; | |
573 | |
574 /* Note: Be sure to leave an extra byte to add the null character to | |
575 * the end of the string. | |
576 */ | |
577 GioMemoryFileCtor(&filemem, buffer, MAX_INST_TEXT_SIZE - 1); | |
578 print_fn(dinst, file); | |
579 buffer[filemem.curpos < MAX_INST_TEXT_SIZE | |
580 ? filemem.curpos : MAX_INST_TEXT_SIZE] ='\0'; | |
581 result = strdup(buffer); | |
582 GioMemoryFileDtor(file); | |
583 return result; | |
584 } | |
585 | |
586 char* NCInstWithHexToString(const NCDecoderInst* dinst) { | |
587 return InstToStringConvert(dinst, NCPrintInstWithHex); | |
588 } | |
589 | |
590 char* NCInstWithoutHexToString(const NCDecoderInst* dinst) { | |
591 return InstToStringConvert(dinst, NCPrintInstWithoutHex); | |
592 } | |
593 | |
594 void NCDecodeSegment(uint8_t* mbase, NaClPcAddress vbase, | |
595 NaClMemorySize size) { | |
596 NCDecoderInst inst; | |
597 NCDecoderState dstate; | |
598 NCDecoderStateConstruct(&dstate, mbase, vbase, size, &inst, 1); | |
599 NCDecoderStateSetErrorReporter(&dstate, &kNCVerboseErrorReporter); | |
600 /* TODO(karl): Fix this so that we don't need to override the | |
601 * action function. | |
602 */ | |
603 dstate.action_fn = PrintInstLogGio; | |
604 NCDecoderStateDecode(&dstate); | |
605 NCDecoderStateDestruct(&dstate); | |
606 } | |
607 | |
608 static void NCVerboseErrorPrintInst(NaClErrorReporter* self, | |
609 NCDecoderInst* dinst) { | |
610 PrintInstLogGio(dinst); | |
611 } | |
612 | |
613 NaClErrorReporter kNCVerboseErrorReporter = { | |
614 NCDecoderInstErrorReporter, | |
615 NaClVerboseErrorPrintf, | |
616 NaClVerboseErrorPrintfV, | |
617 (NaClPrintInst) NCVerboseErrorPrintInst | |
618 }; | |
OLD | NEW |