2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * ncdis.c - disassemble using NaCl decoder.
45 #include "native_client/include/nacl_elf.h"
46 #include "native_client/ncv/ncfileutil.h"
47 #include "native_client/ncv/ncdecode.h"
48 #include "native_client/ncv/ncdisasmtab.h"
50 static const char *progname
;
52 void fatal(const char *fmt
, ...)
55 fprintf(stderr
, "%s: fatal error: ", progname
);
57 vfprintf(stderr
, fmt
, ap
);
63 /* later this will make decoding x87 instructions a bit more concise. */
64 static const char **kDisasmX87Op
[8] = { kDisasm87D8
,
73 /* disassembler stuff */
74 static const char *DisFmt(const struct NCDecoderState
*mstate
) {
75 static const uint8_t kWAITOp
= 0x9b;
76 uint8_t *opbyte
= &mstate
->inst
.maddr
[mstate
->inst
.prefixbytes
];
77 uint8_t pm
= mstate
->inst
.prefixmask
;
79 if (mstate
->opinfo
->insttype
== NACLi_X87
) {
80 if (opbyte
[0] != kWAITOp
) {
81 return kDisasmX87Op
[opbyte
[0]-0xd8][mstate
->inst
.mrm
];
84 if (mstate
->opinfo
->insttype
== NACLi_FCMOV
) {
85 return kDisasmX87Op
[opbyte
[0]-0xd8][mstate
->inst
.mrm
];
87 if (*opbyte
!= kTwoByteOpcodeByte1
) return kDisasm1ByteOp
[opbyte
[0]];
88 if (opbyte
[1] == 0x0f) return kDisasm0F0FOp
[opbyte
[mstate
->inst
.length
- 1]];
89 if (opbyte
[1] == 0x38) return kDisasm0F38Op
[opbyte
[2]];
90 if (opbyte
[1] == 0x3A) return kDisasm0F3AOp
[opbyte
[2]];
91 if (! (pm
& (kPrefixDATA16
| kPrefixREPNE
| kPrefixREP
))) {
92 return kDisasm0FXXOp
[opbyte
[1]];
94 if (pm
& kPrefixDATA16
) return kDisasm660FXXOp
[opbyte
[1]];
95 if (pm
& kPrefixREPNE
) return kDisasmF20FXXOp
[opbyte
[1]];
96 if (pm
& kPrefixREP
) return kDisasmF30FXXOp
[opbyte
[1]];
98 /* no update; should be invalid */
99 return "internal error";
102 static int ByteImmediate(const uint8_t* byte_array
) {
103 return (char) byte_array
[0];
106 static int WordImmediate(const uint8_t* byte_array
) {
107 return (short) (byte_array
[0] + (byte_array
[1] << 8));
110 static int DwordImmediate(const uint8_t* byte_array
) {
111 return (byte_array
[0] +
112 (byte_array
[1] << 8) +
113 (byte_array
[2] << 16) +
114 (byte_array
[3] << 24));
117 static const char* gp_regs
[] = {
118 "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"
121 static const char* mmx_regs
[] = {
122 "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7"
125 static const char* xmm_regs
[] = {
126 "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
129 static const char* seg_regs
[] = {
130 "%es", "%cs", "%ss", "%ds", "%fs", "%gs"
133 static void SibPrint(const struct NCDecoderState
*mstate
, uint32_t sib_offset
) {
134 uint8_t sib
= mstate
->inst
.maddr
[sib_offset
];
136 if (sib_ss(sib
) == 0) {
137 if (sib_base(sib
) == 5) {
138 const uint8_t* disp_addr
= mstate
->inst
.maddr
+ sib_offset
+ 1;
139 fprintf(stdout
, "[0x%x]", DwordImmediate(disp_addr
));
141 /* Has a base register */
142 if (sib_index(sib
) == 4) {
144 fprintf(stdout
, "[%s]", gp_regs
[sib_base(sib
)]);
146 fprintf(stdout
, "[%s + %s]",
147 gp_regs
[sib_base(sib
)],
148 gp_regs
[sib_index(sib
)]);
152 if (sib_index(sib
) == 4) {
154 fprintf(stdout
, "[%s]", gp_regs
[sib_base(sib
)]);
156 fprintf(stdout
, "[%s + %d * %s]",
157 gp_regs
[sib_base(sib
)],
159 gp_regs
[sib_index(sib
)]);
164 static void SegPrefixPrint(const struct NCDecoderState
*mstate
) {
165 uint8_t pm
= mstate
->inst
.prefixmask
;
166 if (pm
& kPrefixSEGCS
) {
167 fprintf(stdout
, "cs:");
168 } else if (pm
& kPrefixSEGSS
) {
169 fprintf(stdout
, "ss:");
170 } else if (pm
& kPrefixSEGFS
) {
171 fprintf(stdout
, "fs:");
172 } else if (pm
& kPrefixSEGGS
) {
173 fprintf(stdout
, "gs:");
177 static void RegMemPrint(const struct NCDecoderState
*mstate
,
178 const char* reg_names
[]) {
179 uint32_t sib_offset
=
180 mstate
->inst
.prefixbytes
+
182 mstate
->inst
.hasopbyte2
+
183 mstate
->inst
.hasopbyte3
+
185 const uint8_t* disp_addr
= mstate
->inst
.maddr
+
187 mstate
->inst
.hassibbyte
;
189 switch (modrm_mod(mstate
->inst
.mrm
)) {
191 SegPrefixPrint(mstate
);
192 if (4 == modrm_rm(mstate
->inst
.mrm
)) {
193 SibPrint(mstate
, sib_offset
);
194 } else if (5 == modrm_rm(mstate
->inst
.mrm
)) {
195 fprintf(stdout
, "[0x%x]", DwordImmediate(disp_addr
));
197 fprintf(stdout
, "[%s]", gp_regs
[modrm_rm(mstate
->inst
.mrm
)]);
202 SegPrefixPrint(mstate
);
203 fprintf(stdout
, "0x%x", ByteImmediate(disp_addr
));
204 if (4 == modrm_rm(mstate
->inst
.mrm
)) {
205 SibPrint(mstate
, sib_offset
);
207 fprintf(stdout
, "[%s]", gp_regs
[modrm_rm(mstate
->inst
.mrm
)]);
213 SegPrefixPrint(mstate
);
214 fprintf(stdout
, "0x%x", DwordImmediate(disp_addr
));
215 if (4 == modrm_rm(mstate
->inst
.mrm
)) {
216 SibPrint(mstate
, sib_offset
);
218 fprintf(stdout
, "[%s]", gp_regs
[modrm_rm(mstate
->inst
.mrm
)]);
223 fprintf(stdout
, "%s", reg_names
[modrm_rm(mstate
->inst
.mrm
)]);
228 static void InstFormat(const char* format
,
229 const struct NCDecoderState
*mstate
) {
231 char* fmt
= token_buf
;
234 strncpy(token_buf
, format
, sizeof(token_buf
));
237 char* token
= strtok(fmt
, " ,\n");
242 fprintf(stdout
, ", ");
243 } else if (pos
> 0) {
244 fprintf(stdout
, " ");
246 if (('$' == token
[0]) && !strncmp(token
, "$group", 6)) {
247 int mrm
= modrm_reg(mstate
->inst
.mrm
);
248 if (!strcmp(token
, "$group1")) {
249 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP1
][mrm
]);
250 } else if (!strcmp(token
, "$group2")) {
251 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP2
][mrm
]);
252 } else if (!strcmp(token
, "$group3")) {
253 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP3
][mrm
]);
254 } else if (!strcmp(token
, "$group4")) {
255 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP4
][mrm
]);
256 } else if (!strcmp(token
, "$group5")) {
257 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP5
][mrm
]);
258 } else if (!strcmp(token
, "$group6")) {
259 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP6
][mrm
]);
260 } else if (!strcmp(token
, "$group7")) {
261 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP7
][mrm
]);
262 } else if (!strcmp(token
, "$group8")) {
263 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP8
][mrm
]);
264 } else if (!strcmp(token
, "$group9")) {
265 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP9
][mrm
]);
266 } else if (!strcmp(token
, "$group10")) {
267 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP10
][mrm
]);
268 } else if (!strcmp(token
, "$group11")) {
269 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP11
][mrm
]);
270 } else if (!strcmp(token
, "$group12")) {
271 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP12
][mrm
]);
272 } else if (!strcmp(token
, "$group13")) {
273 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP13
][mrm
]);
274 } else if (!strcmp(token
, "$group14")) {
275 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP14
][mrm
]);
276 } else if (!strcmp(token
, "$group15")) {
277 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP15
][mrm
]);
278 } else if (!strcmp(token
, "$group16")) {
279 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP16
][mrm
]);
280 } else if (!strcmp(token
, "$group17")) {
281 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP17
][mrm
]);
282 } else if (!strcmp(token
, "$group1a")) {
283 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUP1A
][mrm
]);
284 } else if (!strcmp(token
, "$groupp")) {
285 fprintf(stdout
, "%s", kDisasmModRMOp
[GROUPP
][mrm
]);
287 fprintf(stdout
, "%s", token
);
289 } else if ('$' == token
[0]) {
290 /* Tokens starting with a $ but not $group need formatting */
293 fprintf(stdout
, "$A");
296 fprintf(stdout
, "%%cr%d", modrm_reg(mstate
->inst
.mrm
));
299 fprintf(stdout
, "%%dr%d", modrm_reg(mstate
->inst
.mrm
));
302 case 'M': /* mod should never be 3 for 'M' */
303 /* TODO: byte and word accesses */
304 RegMemPrint(mstate
, gp_regs
);
307 fprintf(stdout
, "eflags");
310 fprintf(stdout
, "%s", gp_regs
[modrm_reg(mstate
->inst
.mrm
)]);
314 const uint8_t* imm_addr
= mstate
->inst
.maddr
+
315 mstate
->inst
.prefixbytes
+
317 mstate
->inst
.hasopbyte2
+
318 mstate
->inst
.hasopbyte3
+
319 mstate
->opinfo
->hasmrmbyte
+
320 mstate
->inst
.hassibbyte
+
321 mstate
->inst
.dispbytes
;
322 if ('b' == token
[2]) {
323 fprintf(stdout
, "0x%x", ByteImmediate(imm_addr
));
324 } else if ('w' == token
[2]) {
325 fprintf(stdout
, "0x%x", WordImmediate(imm_addr
));
327 fprintf(stdout
, "0x%x", DwordImmediate(imm_addr
));
333 const uint8_t* imm_addr
= mstate
->inst
.maddr
+
334 mstate
->inst
.prefixbytes
+
336 mstate
->inst
.hasopbyte2
+
337 mstate
->inst
.hasopbyte3
+
338 mstate
->opinfo
->hasmrmbyte
+
339 mstate
->inst
.hassibbyte
+
340 mstate
->inst
.dispbytes
;
341 if ('b' == token
[2]) {
342 fprintf(stdout
, "0x%x",
343 mstate
->inst
.vaddr
+ mstate
->inst
.length
+
344 ByteImmediate(imm_addr
));
346 fprintf(stdout
, "0x%x",
347 mstate
->inst
.vaddr
+ mstate
->inst
.length
+
348 DwordImmediate(imm_addr
));
354 const uint8_t* imm_addr
= mstate
->inst
.maddr
+
355 mstate
->inst
.prefixbytes
+
357 mstate
->inst
.hasopbyte2
+
358 mstate
->inst
.hasopbyte3
;
359 fprintf(stdout
, "[0x%x]", DwordImmediate(imm_addr
));
363 if ('R' == token
[2]) {
364 fprintf(stdout
, "%%mm%d", modrm_rm(mstate
->inst
.mrm
));
366 fprintf(stdout
, "%%mm%d", modrm_reg(mstate
->inst
.mrm
));
370 RegMemPrint(mstate
, mmx_regs
);
373 fprintf(stdout
, "%s", gp_regs
[modrm_rm(mstate
->inst
.mrm
)]);
376 fprintf(stdout
, "%s", seg_regs
[modrm_reg(mstate
->inst
.mrm
)]);
379 if ('R' == token
[2]) {
380 fprintf(stdout
, "%%xmm%d", modrm_rm(mstate
->inst
.mrm
));
382 fprintf(stdout
, "%%xmm%d", modrm_reg(mstate
->inst
.mrm
));
386 RegMemPrint(mstate
, xmm_regs
);
389 fprintf(stdout
, "ds:[esi]");
392 fprintf(stdout
, "es:[edi]");
395 fprintf(stdout
, "token('%s')", token
);
399 /* Print the token as is */
400 fprintf(stdout
, "%s", token
);
407 static void PrintInst(const struct NCDecoderState
*mstate
) {
409 fprintf(stdout
, " %x:\t%02x", mstate
->inst
.vaddr
,
410 mstate
->inst
.maddr
[0]);
411 for (i
= 1; i
< mstate
->inst
.length
; i
++) {
412 fprintf(stdout
, " %02x", mstate
->inst
.maddr
[i
]);
414 for (i
= mstate
->inst
.length
; i
< 7; i
++) fprintf(stdout
, " ");
415 fprintf(stdout
, "\t");
416 InstFormat(DisFmt(mstate
), mstate
);
417 fprintf(stdout
, "\n");
420 int AnalyzeSections(ncfile
*ncf
) {
423 Elf32_Shdr
*shdr
= ncf
->sheaders
;
425 for (ii
= 0; ii
< ncf
->shnum
; ii
++) {
426 printf("section %d sh_addr %x offset %x flags %x\n",
427 ii
, (uint32_t)shdr
[ii
].sh_addr
,
428 (uint32_t)shdr
[ii
].sh_offset
, (uint32_t)shdr
[ii
].sh_flags
);
429 if ((shdr
[ii
].sh_flags
& SHF_EXECINSTR
) != SHF_EXECINSTR
)
431 printf("parsing section %d\n", ii
);
432 NCDecodeSegment(ncf
->data
+ (shdr
[ii
].sh_addr
- ncf
->vbase
),
433 shdr
[ii
].sh_addr
, shdr
[ii
].sh_size
, NULL
);
439 void AnalyzeCodeSegments(ncfile
*ncf
, const char *fname
) {
440 if (AnalyzeSections(ncf
) < 0) {
441 fprintf(stderr
, "%s: text validate failed\n", fname
);
445 static const char* GrockArgv(int argc
, const char *argv
[]) {
449 fprintf(stderr
, "Running %s unit tests\n", progname
);
455 int main(int argc
, const char *argv
[])
457 const char *loadname
= GrockArgv(argc
, argv
);
460 NCDecodeRegisterCallbacks(PrintInst
, NULL
, NULL
, NULL
);
461 if (loadname
== NULL
) {
462 extern void ncdecode_unittests();
464 ncdecode_unittests();
468 ncf
= nc_loadfile(loadname
);
470 fatal("nc_loadfile(%s): %s\n", strerror(errno
));
472 AnalyzeCodeSegments(ncf
, loadname
);