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 : #ifndef NACL_TRUSTED_BUT_NOT_TCB
8 : #error("This file is not meant for use in the TCB")
9 : #endif
10 :
11 : #include "native_client/src/trusted/validator_x86/ncdis_segments.h"
12 :
13 : #include <string.h>
14 :
15 : #include "native_client/src/shared/platform/nacl_log.h"
16 : #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter.h"
17 : #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h"
18 : #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
19 : #include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"
20 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h"
21 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose.h"
22 : #include "native_client/src/trusted/validator/x86/nc_segment.h"
23 :
24 : /* Returns true if the disassemble flag is in the given flag set. */
25 0 : Bool NaClContainsDisasembleFlag(NaClDisassembleFlags flags,
26 0 : NaClDisassembleFlag flag) {
27 0 : return NaClHasBit(flags, NACL_DISASSEMBLE_FLAG(flag)) ? TRUE : FALSE;
28 : }
29 :
30 : static const char* kHardCodedMessage = "[hard coded]";
31 :
32 : /* Inspect the parsed instruction to print out the opcode sequence matched. */
33 610 : static void NaClInstPrintOpcodeSeq(struct Gio* gout,
34 610 : const NaClInstState* state) {
35 610 : size_t count = 0;
36 610 : if (state->num_opcode_bytes == 0) {
37 : /* Hard coded bytes sequence for instruction. */
38 38 : gprintf(gout, " %s", kHardCodedMessage);
39 38 : count = strlen(kHardCodedMessage) + 2;
40 38 : } else {
41 : /* Modeled instruction. Pull out parsed opcode bytes from parsed
42 : * instruction.
43 : */
44 572 : int i;
45 572 : gprintf(gout, " ");
46 572 : count = 1;
47 :
48 : /* Add prefix selector if applicable. */
49 572 : if (state->opcode_prefix) {
50 64 : gprintf(gout, " %02x", state->opcode_prefix);
51 64 : count += 3;
52 64 : }
53 :
54 : /* Add opcode bytes. */
55 2784 : for (i = 0; i < state->num_opcode_bytes; ++i) {
56 820 : gprintf(gout, " %02x", state->bytes.byte[state->num_prefix_bytes + i]);
57 820 : count += 3;
58 820 : }
59 572 : if (state->inst->flags & NACL_IFLAG(OpcodeInModRm)) {
60 156 : gprintf(gout, " / %d", modrm_opcode(state->modrm));
61 156 : count += 4;
62 572 : } else if (state->inst->flags & NACL_IFLAG(OpcodePlusR)) {
63 40 : gprintf(gout, " - r%d",
64 20 : NaClGetOpcodePlusR(state->inst->opcode_ext));
65 20 : count += 5;
66 20 : }
67 572 : if (state->inst->flags & NACL_IFLAG(OpcodeInModRmRm)) {
68 28 : gprintf(gout, " / %d", modrm_rm(state->modrm));
69 28 : count += 4;
70 28 : }
71 : /* Add opcode for 0f0f instructions, where the opcode is the last
72 : * byte of the instruction.
73 : */
74 1270 : if ((state->num_opcode_bytes >= 2) &&
75 : (0 == (state->inst->flags & NACL_IFLAG(Opcode0F0F))) &&
76 : (0x0F == state->bytes.byte[state->num_prefix_bytes]) &&
77 : (0x0F == state->bytes.byte[state->num_prefix_bytes + 1])) {
78 2 : gprintf(gout, " %02x", state->bytes.byte[state->bytes.length - 1]);
79 2 : count += 3;
80 2 : }
81 : }
82 14922 : while (count < 30) {
83 13702 : gprintf(gout, " ");
84 13702 : ++count;
85 13702 : }
86 610 : }
87 :
88 : /* Disassemble the code segment, using the given decoder tables.
89 : * Note: The decoder tables specified in the flags argument will
90 : * be ignored.
91 : *
92 : * Parameters:
93 : * mbase - Memory region containing code segment.
94 : * vbase - PC address associated with first byte of memory region.
95 : * size - Number of bytes in memory region.
96 : * flags - Flags to use when decoding.
97 : */
98 : static void NaClDisassembleSegmentUsingTables(
99 1589 : uint8_t* mbase, NaClPcAddress vbase,
100 1589 : NaClMemorySize size, NaClDisassembleFlags flags,
101 1589 : const struct NaClDecodeTables* decoder_tables) {
102 1589 : NaClSegment segment;
103 1589 : NaClInstIter* iter;
104 1589 : struct Gio* gout = NaClLogGetGio();
105 1589 : Bool print_internals =
106 : NaClHasBit(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleAddInternals));
107 1589 : NaClSegmentInitialize(mbase, vbase, size, &segment);
108 1589 : iter = NaClInstIterCreate(decoder_tables, &segment);
109 1589 : if (NULL == iter) {
110 0 : gprintf(gout, "Error: not enough memory\n");
111 0 : } else {
112 10190 : for (; NaClInstIterHasNext(iter); NaClInstIterAdvance(iter)) {
113 3506 : NaClInstState* state = NaClInstIterGetState(iter);
114 3506 : NaClInstStateInstPrint(gout, state);
115 3506 : if (print_internals) {
116 610 : NaClInstPrintOpcodeSeq(gout, state);
117 610 : NaClInstPrint(gout, state->decoder_tables, NaClInstStateInst(state));
118 610 : NaClExpVectorPrint(gout, state);
119 610 : }
120 3506 : }
121 1589 : NaClInstIterDestroy(iter);
122 : }
123 1589 : }
124 :
125 1589 : void NaClDisassembleSegment(uint8_t* mbase, NaClPcAddress vbase,
126 1589 : NaClMemorySize size, NaClDisassembleFlags flags) {
127 1589 : if (NaClHasBit(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleFull))) {
128 844 : if (NaClHasBit(flags,
129 : NACL_DISASSEMBLE_FLAG(NaClDisassembleValidatorDecoder))) {
130 0 : gprintf(NaClLogGetGio(),
131 : "Error: can't specify both full and validator disassembly,\n"
132 : " assuming full disassembly.\n");
133 0 : }
134 844 : NaClDisassembleSegmentUsingTables(mbase, vbase, size, flags,
135 : kNaClDecoderTables);
136 1589 : } else if (NaClHasBit
137 : (flags,
138 : NACL_DISASSEMBLE_FLAG(NaClDisassembleValidatorDecoder))) {
139 : if (64 == NACL_TARGET_SUBARCH) {
140 745 : NaClDisassembleSegmentUsingTables(mbase, vbase, size, flags,
141 : kNaClValDecoderTables);
142 : } else {
143 : NCDecodeSegment(mbase, vbase, size);
144 : }
145 745 : } else {
146 0 : gprintf(NaClLogGetGio(),
147 : "Error: No decoder tables specified, can't disassemble\n");
148 : }
149 1589 : }
|